We're still on Summer Break here at The Daily WTF, which means it's time to bring back another classic. But in the mean time, please send in your stories so we'll have plenty to work with when we return next week.
Now what's particularly fun about Banking So Advanced is that it was originally published back on October 17, 2007... and is still relevant today. The article links have not changed and the "unique" code remains the same. Consider what that means in Internet Time: back then, Twitter was little more than a silly idea that most everyone found ridiculous. Okay, so clearly, not that much has changed in the past few years, but I should note that this online banking site is still optimized for "Netscape Navigator 4.75 or higher; Internet Explorer 5.0 or 6.0; and AOL 6, 7, or 8."
A while back, I wrote about US financial institutions, their failure to implement two-factor authentication, and the absurdity that has become Wish-It-Was Two Factor authentication. I thought that'd be the last I'd write about the topic, but when Steven King pointed me towards his bank, Synergy One. I couldn't resist a follow-up.
First and foremost, Synergy One seems to be a great, local institution. They invest in their community. They offer college scholarships. Heck, they even have student-run branches to encourage saving money while in high school. And this is exactly why it's such a shame that they've fallen prey to the Wish-It-Was Two-Factor placebo.
Being such a small institution, Synergy One does not develop their own banking software. They rely on Harland Financial Solutions, who provides "strength and industry leadership within each product" and boasts "over 7,000 clients" to make them "the number one choice for many financial institutions." With a reputation like that, it's no wonder so many banks look to Harland for their technology solutions.
Unfortunately, Harland's online banking product - Cavion® Internet Banking - is woefully inadequate. It does, however, sport several impressive-looking "multi-factor" authentication and security methods.
The first of these - that Synergy One and other unfortunate Harland end-users face - is the almighty CAPTCHA. A technology barely able to curb comment spam on blogs, Cavion® utilizes CAPTCHA as a "Security Code," claiming that it's an "extra security measure used to eliminate fraudsters from randomly selecting account numbers".
I suppose that makes sense. Surely, any fraudster bent on electronic bank fraud would be thwarted by a barely scrambled image that required off-the-shelf optical character recognition software to decode. On the bright side, the system did provide an audio CAPTCHA for accessibility. Granted, the text-to-speech engine sounds like it came from the early-90's, but hey, it's a start!
On the off chance someone might defeat that first bastion of security, Cavion® employs another fool-proof barrier: JavaScript. For those of you who missed their Code SOD today, following is the code that is used to fend off a SQL Injection (as seen on the Enrollment Page):
function isValidValue(stg,name) { var error=""; var rtn=""; stg = stg.toUpperCase(); if (stg.indexOf("DROP")>-1 || stg.indexOf("..")>-1 || stg.indexOf("NULL")>-1 || stg.indexOf("--")>-1) { error = true; } if (stg.indexOf("SELECT")>-1 || stg.indexOf("DELETE")>-1) { if (stg.indexOf("FROM")>-1) { error = true; } } if (stg.indexOf("UPDATE")>-1) { if (stg.indexOf("SET")>-1) { error = true; } } if (stg.indexOf("INSERT")>-1) { if (stg.indexOf("INTO")>-1) { error = true; } } if (error == true) { rtn="You have entered invalid data in your "+name+" \n Please do not use any of the following characters or words: 'SELECT FROM' 'DELETE FROM' 'UPDATE SET' 'INSERT INTO' DROP NULL .. -- \n "; } return rtn; }If those two security "factors" weren't enough, Cavion® even mandates that you use an onscreen keyboard to type in certain fields:
That's right! You fraudsters have no chance of getting in-- Oh, wait...
... gee, I can't imagine how any would find that difficult to use!
Unfortunately, things go a bit downhill from there.
When you sign up as a customer and enroll in their online banking (something which I think I'll have to pass on), you're required to select and answer a few of those ridiculous "security" questions. Curiously, one of the questions had a rather odd disclaimer:
Steven, who shared these screenshots with me, thought nothing of it. Green was more to his taste, anyway. But when it came time to selecting another question, it became pretty clear why RED was not a valid option.
I guess you're just out of luck if you grew up on 9th, love pie, and just can't get enough CSI (or, god forbid, ER). Your money will be so secure that you won't even be able to figure out what answers you need to type in to access it.
Sadly, Synergy One is one of many that subscribed to this preposterous online banking system. Several others -- San Antonio City Employees FCU, Hudson Valley FCU, Missoula FCU, SRP FCU, and so many more -- have been suckered into Cavion® and its related products. And it just keeps spreading.
So what can we, as security conscious IT professionals, do about this growing Wish-It-Was-Two-Factor Authentication dilemma? Complain. Loudly. A sincere letter sent to a bank Vice President that uses Harland’s - or any other embarrassingly deficient banking software - will certainly plant the seeds of doubt that their system isn't as advanced as they were told. And maybe, just maybe, it will make them wonder, how exactly is preventing "RED" more secure?!
Working as a DBA in academia, Paul received a notice that a certain newly migrated user schema, specifically the one used by the enrollment tracking system, had swelled to 281 tables and was growing. This had struck Paul as being very strange since the tracking system wasn't all that complicated.
When a student is registering for a class, and want to know if there's room left, they need two pieces of information - the Course ID and the Semester Number.
Course IDs are found by simply looking up the course in the Course Catalog. However, the semesters (or terms), denoted by a 4-digit number, can be a little tricky for new students. The first digit denotes the century (2 for the 21st century), the second and third digits are the specific year (08 for 2008, 09 for 2009, and so on) and the last digit denotes the month the term begins (1 for spring term, 6 for the summer term, and 9 for the fall term). Therefore, if you are looking for classes for the Spring 2009 Term use 2091 or if you are looking for Summer 08 classes use 2086, and for Fall 2010 use 2109.
The student enters the Course and Semester code and they get back a count of spaces left in the class.
Thinking that the system should really be, tops, five tables in all, Paul couldn't figure where all the tables were coming from, that is until he checked the layout and found a very creative way of storing data in a database.
Each table was in the format ██_Enroll_hours_<term>_<week> each for enrollment going back in history several years.
Karsten wrote, "seeing the whole undergound train shut down and reboot during the ride was a bit scary."
"I just bashed a few keys at random when doing a Google search to check my connectivity," writes Ben, "it looks like the Dartington College of Arts (a real school, I should note!) is really making the most of their Google sponsorship and selling themselves well."
"I guess it did certainly take 'a while' for the scan to run," J. Pablo Fernández wrote, "but I'm surprised it advises me to immediately scan again."
"This came up at the local A&P grocery store," Chris R notes, "I'm sure glad I'm a Bonus Club member!"
"Hopefully I am able to make it to a Best Buy store before 123," wrote Cav, "I don't want my coupons to expire! Although, to their credit, they have known about this since 1."
"Check out our great free books," Ben Horton writes, "there only $4.47 each!"
[Someone.Frgt.To.Fill.Ths.In] (from Paul Schnei)
It's the summer break for The Daily WTF! Please send in your own stories so we'll have some fun ones to share when we return. In the mean time, here’s a fun classic. "The Pie T Department" was originally published on August 8, 2007.
Many years ago, Dan B. worked at a large accounting firm that had several small, satellite offices spread throughout the world. The offices shared data -- mostly email -- via a dial-up based file synch operation that would run several times throughout the day. Since these offices were so small, they didn't need IT support on staff; instead, they'd rely on the IT staff at the central office for help.
The file synching had been going well for months, but the process began failing when attempting to synch with one of the Australian offices. Dan tried to diagnose the problem on his end, but determined that it had to be a problem with the remote server in Australia. It was going completely offline every few days and had to be manually restarted. Unable to convince his boss that a trip to the outback was needed, he had no choice but to work with the office's secretary, Sydney, to fix the problem.
For a few weeks, on and off, Dan walked Sydney through all of the common diagnostic steps. Having all but ruled out software issues, Dan started thinking that the problem could be with the server overheating.
Dan: Is there an air conditioner running in the server room?
Sydney: Yes. Well, I mean, not in the cupboard, but there's air conditioning in the room.
Dan: "The cupboard?"
Sydney: Yeah, the cupboard in the kitchenette.
Dan: Oh. That could be an issue... are there any vents or fans on the cupboard?
Sydney: Well, no. But Boyd usually leaves the cupboard doors open.
Dan: Hmm... it could still get hot in there...
Sydney: It doesn't get too hot, though, it works perfect for the pies.
Dan: "The pies?"
Sydney: Yeah, the monitor gets pretty hot, so Boyd and some of the other folks use it to warm up their meat pies in the morning.
Dan: ...
Sydney: I'm sorry... are you... crying?
As it turned out, warming up lunch on the server was part of the problem. The other problem was the type of lunch: while scones and bagels were perfectly safe, the meat pies ended up tripping fat down the back of the server into the PSU, tripping it off until it was restarted manually.
Fortunately, Dan was able to offered simple solution: use the microwave instead.
Varg's colleague had an awfully difficult problem challenge to solve: remove the language parameter ("lang") from a query string.
Well, difficult for Varg's colleague. Though most of us would apply some substring finesse, this particular developer hammered away with a brute force approach.
Dim MyPage As String = Request.Url.ToString MyPage = Replace(MyPage, "&lang=en", "") MyPage = Replace(MyPage, "&lang=gr", "") MyPage = Replace(MyPage, "&lang=EN", "") MyPage = Replace(MyPage, "&lang=GR", "") MyPage = Replace(MyPage, "&lang=En", "") MyPage = Replace(MyPage, "&lang=Gr", "") MyPage = Replace(MyPage, "&lang=eN", "") MyPage = Replace(MyPage, "&lang=gR", "") MyPage = Replace(MyPage, "&LANG=EN", "") MyPage = Replace(MyPage, "&LANG=GR", "") MyPage = Replace(MyPage, "?lang=en", "") MyPage = Replace(MyPage, "?lang=gr", "") MyPage = Replace(MyPage, "?lang=EN", "") MyPage = Replace(MyPage, "?lang=GR", "") MyPage = Replace(MyPage, "?lang=En", "") MyPage = Replace(MyPage, "?lang=Gr", "") MyPage = Replace(MyPage, "?lang=eN", "") MyPage = Replace(MyPage, "?lang=gR", "") MyPage = Replace(MyPage, "?LANG=EN", "") MyPage = Replace(MyPage, "?LANG=GR", "")Upon seeing this solution, Varg replied to his coworker, "this doesn't seem to cover the '?LaNg=en' and '&lANg=gr' scenarios." I'll let you guess how the code was updated to include those.
It's the summer break for The Daily WTF! We're working on some fun new stories now, but in the mean time, here’s a fun classic. "Anything You Can Do Lyle Can Do Better" was originally published on May 21, 2008.
If Lyle could be summed up in one word, it'd be "competitive." If he could be summed up in three words, it'd be "ultra-competitive jackass." If you had $21.00 on you, Lyle would make it a point to have $21.50. If you estimated that a task would take you twelve hours, it'd take Lyle eleven hours and 45 minutes. If a distant relative died, somehow two of Lyle's distant relatives died. He was the kind of guy that would play basketball against a nine year old to win, then he'd make fun of the kid for losing, then he'd make fun of the kid for crying. If a stranger asked Lyle what time it was, he treated it as a challenge.
Lyle was two levels above James W. in the company hierarchy (or, as Lyle would probably call it, "winning"). James reported to Rob, who reported to Lyle. Another team of the same size reported to Lyle as well. James and one of his colleagues knew about Lyle's obsession with winning and exploited it at every opportunity, usually teasing him to the point that he'd leave them alone. As is the case with most bullies being called out on their bullpucky, Lyle got defensive and eventually stopped visiting James during the day.
Clearly, there were problems with the team (and not with Lyle), so he had to take action. I'm better at team building than anyone else, Lyle reasoned. Time for a team-building exercise!
And he knew just the place, too: Lazer Zone X-Treme 2000!! It was the ideal environment for IT office team building — screaming children, sticky arcade cabinets, blaring nu-metal — paradise within just a few miles of the office. He sent emails to his two teams inviting them to play laser tag.
Everyone carpooled to LZXT2K (Lyle got there first), and stood in line waiting to sign in (Lyle signed in first). The teams in the laser tag game were the same as the teams in the office, with Lyle joining the team opposite James. They entered their names, put on their vests, and began the first of two games.
While James was skeptical of laser tag for team building, he had to admit that it was a good time and that everyone enjoyed the friendly competition. Everyone except Lyle, that is. Whenever he was hit, he'd throw up his arms and complain that he shot first and his gun wasn't working. Whenever he landed a hit, he'd laugh and praise himself loudly in third person. "How are you so awesome, Lyle? I don't know, Lyle, I just can't help it!"
The first match was neck-and-neck throughout, until James's team barely pulled ahead at the end. While everyone else was laughing and comparing score sheets after the game, Lyle sat in the corner scowling at his sheet.
"OK, tough guys," Lyle said, rising from his seat and crushing his score sheet in a clenched fist, "how about for the next game the losing team has to sing the 'I'm a Little Teapot' song here in the lobby!"
James rolled his eyes, realizing that it must've taken Lyle tremendous strength of will to not be howling profanities at his team. Everyone agreed to the wager before the second game began.
Five minutes into the game, James was getting the sense that something was amiss. Lyle's team had more than three times the score of James's team, and James could hardly land a shot on anyone! At one point, James had snuck up behind someone on the opposite team, and from three feet away couldn't get their vest to register a shot.
It was a laser tag massacre — James's team had lost by over 1,000 points by the end. And Lyle couldn't have been happier. "OK, let's hear it," he insisted with a toothy smile.
"Just one second," James said loudly enough for all to hear. He went over to the kid running the system to do some detective work.
"So... 'Skippy,'" James began, reading the kid's nametag. "I'm curious — is there a way to turn off all the vests on one team?"
Skippy immediately broke eye contact, looking down at his desk. After a pause, he sheepishly replied "yeah..."
"And did that guy over there ask you to turn off the vests for his team?"
"Y... yeah... He asked me to turn all of them off except one."
"Thanks." James excused himself and returned to the group.
Lyle still had a huge smile on his face. "Ah, so the losers came back! Have you got something you'd like to say, or perhaps, sing for us?"
James shot a disgusted look at Lyle, and after a brief, awkward silence, the teams returned to their cars. Lyle got back to the office first.
A few days later, Lyle sat James down to take him to task for figuring out his subterfuge. James was surprised that he was the one being admonished. "It's just that I didn't want my team feeling bad about losing twice," Lyle explained.
"No one would have felt bad," James explained. "Everyone was having a good time! Nobody was talking trash or trying to make one team feel bad." Well, except you, James thought.
Hopefully the next team-building exercise, a small company picnic, won't be sabotaged by Lyle.
"This one had me so confused it made me ponder my existence," writes Jack M.,"and I remain subscribed to the list."
"If their ad is any indication of how I should be writing web code," wrote Kevin, "then I don't wanna be right!"
"So where exactly is the FIFA World Cup being held this year?" Michael Wood writes, "South Afmerica??"
The below, submitted anonymously, is either meant to give the viewer an impression of Hertz's worldwide presence or the web developer haphazardly chose a list of "countries".
"I was reinstalling the HTC sync application on my computer," wrote Jeff, "but apparently it has been using, or is being used...or something. I think."
"Found this in my local Morrisons," Gareth writes, "where it seems they pass the negative savings onto the customer."
"I've always known that Flash is bloated and stinks," wrote Chas., "now I know why."
Reality Support (from Stuart Whelan)
Many, many years ago I used to be on-call support for the local hospital and emergency department. The IT system consisted of Wyse serial terminals connected to a Sun system running RealityDB. The software was PMS, the Patient Management System, and I dealt with PMS every day, all day.
I should note, RealityDB had the best error message I have ever seen in my career: “Reality is corrupted”. And also my favorite confirmation message: “Are you sure you wish to destroy Reality?”
Anyway, most of the on-call support calls consisted of telling the users to check the contrast and brightness, press enter 3 times, press Control-Q, then turn the terminal off and on again. But two calls really stood out through the haze.
One was on a Friday night, and came in while my friends and I were indulging in our weekly “rent the worst movie you can find.” When then the pager beeped, I wrenched myself back into reality and went to the nearest payphone.
The number went through to the Cardio Department. Specifically, a concerned doctor: his “terminal” was telling him that “someone was performing an illegal operation.”
I really wanted to tell him to get an orderly and go check all the ID’s of the people in the operating room, but I didn't. It was one of these new fangled Windows 95 machines, which he was using for the first time.
The second call I remember happened in the middle of the afternoon. It was someone from ICU (Intensive Care Unit) with the usual problem description “PMS is not working.” I ran through the usual list: contrast, brightness, enter three times, control Q, switch it off, and switch it on. And then, all of a sudden, I heard the alarms start blaring over the phone. And then the shouting. The phone went dead.
I found out later that someone had moved the terminal from the white power outlet to the red one. Although the outlets are more protected these days, back then, the color red was the only indicator that the outlet was exclusively for life support equipment.
Apparently, the terminal tripped a breaker, or blew a fuse, or something (I never got a straight story), and all the life support equipment attached the circuit stopped. Nobody died, but the nursing staff were kept very busy with hand-held respirators for a while.
Telephatic Support (from Matt Westwood)
I’ve had the pleasure of working tech support for a company that had a large employ of slightly less than sophisticated computer users with slightly less than understandable accents. The first time I received a call like this, I was surprised.
"Hello, Matt here."
"It's Bubba, Ah've got a prahblem with mah prohgram."
"Which program would that be, Bubba?"
"THIS ONE HERE ON MAH SCREEN IN FRONT OF ME, OF COURSE!!!"
I had since learned to ask different questions.
New Thing Support (from Joakim)
I recently took a call from someone who was having trouble with his new computer: his Internet Explorer got a new “thing” showing that he hadn't seen before. He couldn’t quite describe it, aside from calling it “weird” and having all sorts of “computery symbols” and what not.
My first thought was that it was an error message, but it turned out that wasn’t the case. I figured it was a toolbar, so I guided him to open the browser, and click an empty area so he could uncheck whatever new toolbar he got. That didn’t help the problem one bit, and I had still had idea what he was talking about, so I figured a screenshot was in order.
After a grueling thirty-minute exercise of locating the Print Screen PRT SC key, loading Paint, pasting, saving, and then emailing, I waited another few minutes for the rather large attachment to show up. When I opened the attachment, this is what I saw.
My palm immediately and instinctively went to my forehead.
I'd love to hear your tech support stories; go ahead and send them to me!
"I found this interesting tidbit while making some changes to a .NET application," Tim Kowalski writes.
"Although the original developer claims to 'spend 9/10ths on the rule and not the exception', I would argue it's more like 5/10ths on the excuse, 4/10ths on the rule, and 1/10th avoiding the exception."
catch (Exception ex) { CommonLoggerHelper.DumpException(ex); // Typically I like to minimize the amount of // code I wrap in a try/catch statement. However // honestly, I'm feeling that there are a couple // of potential problems that could arise in my // implementation of the code and I want there to // be *some* thought about what should happen here // if the worst-case-scenario actually happens. // Actually, what I'm about to say mimics many of // the comments I made in the questions.aspx.cs // file. // I have two potential problems ... 1st, if the // web server is reset while my user is on the last // quiz question ready to click the "Finish" button // then all his answers will be lost. 2nd, if the // database connection is lost (or other database // malladies occur) then all the user's answers will // be lost. Yes, yes, yes ... I could construct // some elaborate schemes to ensure this doesn't // happen, but that would require I back-up several // steps and re-do some things about the application. // Since this is simply a tutorial application // I'll just bring these potential issues to your // attention and move on. // This does remind me of a great programmer quote: // "Nine tenths of programming is handling the exceion, // not the rule." I fear too often in my own work // I spend 9/10ths on the rule and not the exception. // To make a long story short, I'm going to take // the easy way out and just redirect the user to // the default.aspx page if there is any trouble. // Yes, makes me feel a little dirty, but due to // time constraints I must move on... Response.Redirect("default.aspx"); }Amit checked his latest code in and turned to more interesting work. It didn't take much to be more interesting than writing a CSV parser. That was kid's stuff, really. With the low-hanging fruit out of the way, Amit could focus on the more mission critical aspects that were on tight deadlines. He had designed the module with a little extra polish; it was generic and should be easy to modify in the future. That was a smart decision, as a few days later the requirements changed. The application also needed to be able to handle pipe (|) separated values data. Since Amit was tied up on more important work, his manager stopped by to ask a few questions.
"How difficult do you think this would be?" John asked.
"It's really easy. There's a constant, DATA_SEPARATOR, someone could turn that into a variable expression. From there, it's just a matter of making the module configurable," Amit explained.
"So, you think Tony could handle it?"
A first year CS student should be able to make the change in a few minutes, and then spend maybe a few hours running some test data through to make sure it behaved properly and the mapping file for the conversion worked. "He should be able to," Amit said, diplomatically.
There was a vast field between "incompetent" and "incompetent enough to get fired", and Tony frolicked in that field among the Lilies of Wasted Effort and the Butterflies of Uselessness. He was the sort of person that could only survive in a large company where his dead-weight was barely noticable among the bueraucratic morass. Amit's statement was literally true: Tony, a senior developer, should have been able to make these changes. Could he, on the other hand?
Minutes later, Amit's inbox dinged. Tony's email complained, "It's not working. :("
Amit replied with simple instructions:Find the line that reads #define DATA_SEPARATOR ',' and change it to #define DATA_SEPARATOR '|'. We can worry about configuration later, but that should let you get started on testing your column mappings.
A few hours later, Tony swept into Amit's office on the black wings of the Angel of Vexation. "It's still not working," he whinged. "Can you take a look?"
Amit took a look. The obvious problem was that, instead of changing the DATA_SEPARATOR definition, Tony had merely added a second one, labeled DATA_SEPARATOR_TWO. "It was giving me a compiler warning," Tony explained.
Amit took the path of least resistance and fixed the declarations, and then gave it a run to see what happened. The application failed on parsing and complained, "Content in column 0 too large; check input data and mapping file."
"Well," Amit asked Tony, "did you check the input and mapping files?"
"No," Tony said. "But they're definitely good, I just converted one of our test CSVs to PSV."
"Well, maybe the conversion tool screwed up," Amit suggested. "What did you use?"
"Conversion tool?"
Amit opened the PSV file Tony had "converted", and saw that the file was chock full of commas, not pipes. Tony had simply changed the file extension. "That doesn't work?" Tony asked. "Then why do they let you change the file extension? What's the point of that? They shouldn't even put a feature in if it doesn't work."
"Do you think," Amit grumbled, "that if we changed the extension to .mp3, it would play on your iPod?"
"Oh, I don't have an iPod. But my Zen could definitely play it. No DRM, you know."
"We need to make sure that the new PL/SQL version that runs on Oracle will work exactly as it does on SQL Server," stated the directive given to Andy by his supervisor.
Andy had been tasked to port over a T-SQL function which, when passed valid string, would convert it into a data format that could then be returned back to the calling application and submitted to a label printer to produce a bar code.
Though experienced as an Oracle Developer by position, and coming into the task with zero SQL Server experience, Andy found that his task didn't seem nearly as difficult as he had imagined. The code was very well commented and the formatting of the T-SQL logic was close enough to the style of PL/SQL that he was most familiar with that he soon felt right at home and was able to get straight to work.
Things were going long quite smoothly until he hit part of function responsible for data validation - the section of the code that ensured the passed value to convert into barcode data format was a whole number.
While @QuickCounter <= @Length BEGIN Set @CheckDigit = Null Begin Try Set @CheckDigit = Cast (Substring(@barcodeValueSequence, @QuickCounter, 1) as Int) End Try Begin Catch If @CheckDigit is null Begin Select 'Non-Numeric Sequence Provided' Return End End Catch Set @QuickCounter = @QuickCounter + 1 ENDThough Andy's level of T-SQL experience didn't extend much further beyond that of the code that he was handed, Andy had a strong feeling that there was something fishy about how this particular piece code behaved and, after a little research, his hunch was confirmed. Rather than evaluate the entire value stored in the barcodeValueSequence variable as a single value, the logic would step through the string and evaluate if each character could be converted to an integer, character by character, for the entire length of the string. While this approach didn't seem to be much of a performance hog, this approach bothered him. Andy knew there must be a better way and had to pursue it, if for no other reason than to make his conversion to PL/SQL task easier.
So, after a little more research, Andy discovered SQL Server's built in 'ISNUMERIC' function which could, as the name implies, evaluate the entire string and determine if the value is a number and could replace the While...BEGIN...END block with a single line of code.
Quite pleased with the fruits of his research, Andy figured that he would share his findings to his manager, however, the reply wasn't entirely as he had hoped.
"This is a great catch! Thanks for thinking outside of the box on this one, but I do have to ask one favor of you," replied Andy's boss,"for now, I'll need you to replicate the validation logic in your new procedure."
"We just can't run the risk of the new Oracle code behaving any differently than the SQL Server version does."
"I'm not sure if that means he's the problem," Chris F. wrote, "or we need to get him to fix the problem."
"Perhaps the download would have succeeded," wrote Chris Scholfield, "if the telegram was sung instead of read."
"This is an error message from the China Airlines Dynasty Flyer registration page," Matt M. writes.
"The page count is kind of depressing," writes Kyle, "considering how much effort went into writing the document."
"While using pgAdmin III, a GUI for PostgreSQL Databases, I received the following," Jeremy Sweetman wrote,"Something tells me that's a little high."
"I sure hope that the font shortage doesn't hurt business at FedEx Kinko's," notes David.
"Now, being a native Texan, this is how 'I' feel," Brian writes, "Apparently, some web developers agree."
"I found this job through an internet posting like I'm sure many thousands of other job seekers," writes Rich S., "but it's nice to see that a job site is willing to reach out to the individual."
It takes ambition and funding to build the "best datacenter in the world". Bi-located on the East and West coast, with multiple fat pipes, doubly-redudant power generation, armed security guards, and a Network Operations Center with giant plasma screens scrolling network statuses that are monitored by a 24/7 staff always looking busy, such a datacenter would serve only the highest-end clients. It takes one more key ingredient though: timing. Building a high-end datacenter in the middle of the deepest recession in decades isn't the recipe for success. Only a handful of clients ever moved in, and they were moving back out when the datacenter decided to shut down operations for good. Nearly everyone had been laid off, which left Ryan as the lone IT guy.
It was a lonely, and slightly creepy, position. Day after day, he sat alone in an abandoned office building, with only the security guard for company. During those weeks, his mind wandered, inventing noises where there were none, inventing strange interpretations for the noises that were there. He kept his sanity and balanced his time between building walkthroughs, marathon Minesweeper sessions, and browsing IT humor sites to remind himself that things could be far worse than drawing a check to warm a chair.
His cellphone beeped at him. An SMS alert proclaimed that a server had gone down. It wasn't DNS or something important, so he ignored it and continued trying to set a new record on Expert mode. A few minutes later, his cellphone bleeped again. And again. DNS and something important were down.
His record attempt abandoned, the sluggishness of the past few weeks of boredom fell away. Ryan bolted for the server room. He threw open the door and a wave of heat flashed past him. He expected smoke and flames. Instead he saw overheating servers and a thermostat that registered 110ºF. To make matters worse, he could feel hot air blasting into the room from the vents. The heat was on.
Obviously, the thermostat was broken, so Ryan did the logical thing and turned it off. He waited for the HVAC system to notice and turn off the heat. And waited. The vents continued belching hot air into the room. Unsure how to fix the heat, Ryan decided to solve the hottest problem first. He fetched the never-before-used emergency air-conditioner. Minutes later, it sat, still partially cocooned in shrink wrap, angrily battling it out with the building's rogue HVAC system. The temperature dropped to a more manageable 85º.
Ryan called the security desk, which had monitors for the HVAC system. "According to this," the guard said, "the Server Room zone is 64º in a zone for 68º, and the thermostat is still active. So, heat is still running to bring it up to 68º. Are you sure you turned it off?"
Ryan double checked, just to be safe, and then for good measure, he started sanity checking the other thermostats in the building. He walked from room to room, and it wasn't until he reached the Network Operations Center that he noticed something was off. Despite being an admin, he never spent much time in the NOC. Like many a NOC, it had been built for form, not function, as something that the sales-guy could show off to potential clients and put in brochures. The real work happened in the cube-farm down the hall.
After a brief tracing of cables and sensors, Ryan pieced together what happened. Because the NOC room has been empty since the recent layoffs, the presence of human heat no longer kept the room warm. Normally, that wouldn't be a problem, except for the fact that the HVAC guys behind the "world class datacenter" placed the NOC and server room in the same heating/cooling zone. The sensor was in the NOC room, and the vents were in the server room. Before the layoffs, the NOC was staffed 24/7, and the presence of human heat always kept the ambient temperature above 68º, thus keeping the A/C blowing all the time in the server room. With no humans in the NOC, the HVAC system started pumping heat into the server room.
As a quick fix, Ryan "tweaked" the shared zone to 50 degrees, and the vents once again flooded the room with cold air. A few weeks later, he collected his final paycheck and happily pulled the breaker to the server room, leaving the problem to whoever might buy the remains of their "world class datacenter".
"We have an old codebase where strings are used as a swiss army knife," writes Jimmi Hested, "almost everything that goes in or out of a function is ends with a .ToString(), even it's already a string... and sometimes even if it already ends with .ToString()."
"Here is a bit of code from our web front-end. Not only is there a try/catch (just to make sure everything works), but the original developer felt a string was way better than a bool." try { // Check that a valid scheme has been selected if (scheme.SelectedValue.Length == 5) { // Extract the start and end time from the selected scheme int tempStartTime = Convert.ToInt32(scheme.SelectedValue.Substring(0,2)); int tempEndTime = Convert.ToInt32(scheme.SelectedValue.Substring(3,2)); // Find out which days to show/saves string tempMonday = "false"; string tempTuesday = "false"; string tempWednesday = "false"; string tempThursday = "false"; string tempFriday = "false"; string tempSaturday = "false"; string tempSunday = "false"; if (mondayCheckBox.Checked) tempMonday = "true"; if (tuesdayCheckBox.Checked) tempTuesday = "true"; if (wednesdayCheckBox.Checked) tempWednesday = "true"; if (thursdayCheckBox.Checked) tempThursday = "true"; if (fridayCheckBox.Checked) tempFriday = "true"; if (saturdayCheckBox.Checked) tempSaturday = "true"; if (sundayCheckBox.Checked) tempSunday = "true"; // Save the new settings webservice.UpdateSettings(tempStartTime, tempEndTime, tempMonday, tempTuesday, tempWednesday, tempThursday, tempFriday, tempSaturday, tempSunday, pType.SelectedValue); label.Text = GetString("SettingsUpdated"); } } catch { }
Jimmi added, "it's also worth noting the fact that the datatype to store the true/false values is nvarchar(5). What could possibly go wrong?"
Beep. .... Beep. .... Beep. .... Peter stared aimlessly at the heart monitor above his wife’s hospital bed, watching the green lines zig... then zag. Then zig... then zag. It was calmingly hypnotic, especially after five long hours of sitting by her side in the cardiac unit, waiting around for test results.
Suddenly, the steady pace of beeps increased and Peter snapped out of his daze. Looking around, he spotted the culprit: the doctor was in route and was making his way towards the bed. “I just wanted to let you know that we’re still waiting on the final enzyme analysis,” the doctor said as he flipped through papers on his clipboard, “the first tests were… hmm… inconclusive. So, it shouldn’t be much longer.”
This might have brought Peter’s and his wife’s hopes up, except for the fact that the doctor said the exact same thing forty-five minutes ago. And forty-five minutes before that. Suspecting it might be at least another forty-five minutes, Peter got up and headed towards the vending area. He had hoped a Reese’s Cup might assuage the fact that his wife was sitting in the hospital and showing all the signs of a heart attack at the young age of 37.
As he reached down to grab the peanut butter cups from the candy machine, his cell phone rang. Instinctually, he reached towards his hip, flipped open the phone, and put it towards his ear, answering with “this is Peter speaking.”
“So how’d it go?” the voice on the other end questioned.
“Wait,” Peter was completely blindsided and had no idea why he picked up the phone, “I’m sorry, who is this?”
“It’s Deborah Franks,” she said questioningly, “you know, the recruiter? You interviewed my candidate today? I was curious how it went?”
“Look, Deborah,” Peter responded, “now’s just… uhhh… not a good time. I’m actually at the hospital right now, and we think my wife has had a heart attack. How about we table this until Monday, assuming her condition improves?”
“Okay… but surely you can tell me how you feel about the candidate? I mean, he’ll want to know when things are going to happen.”
“Quite frankly,” Peter said, annoyed, “this is the last thing on my mind right now. I’ve been at the hospital all day, and we still need to figure what to do about our kids in day care. Your candidate can wait.”
“But it’s a Friday,” she insisted, “and I hate leaving these go all weekend. It’s not like I’m asking for a decision, just a hint as to how things went and when you’ll decide.”
“We will not discuss this now. I have to go be with my wife.”
Deborah scoffed, “you know, you’re being very rude you know, not answering any of my questions!”
By that point, Peter hung up his phone and walked back to his wife’s hospital bed. In the few minutes he was away, the nurse had carted over an EKG machine and was running yet another test. “Hmmm,” she said in a concerned voice, “we’re still seeing some abnormalities. Now that’s not necessarily bad, but it’s inconclusive. We’ll have to see what the doctor says, but you may want to plan for an overnight stay.”
Not knowing how long she’d be at the hospital, Peter kissed his wife goodbye and headed towards their car so that he could go home and pick up some overnight essentials. As he walked through the parking lot, his phone rang again. More cognizant of the situation, he first looked at the Caller-ID to see who was calling him: it was the in-laws, which was good news, because they might be able to pick up the kids from day care. Peter answered with a more casual greeting.
“Uh, hello?” the caller responded, “this is Jeremy Franks, Director of Finance. Hey listen, did you receive a call from our recruiter, asking about one of her candidates?”
Peter looked down at the phone again. Whoops. The in-laws phone number ends with 7634, not 7364. Not exactly sure why a director of his company was calling him – nor wanting to jeopardize his relationship with a director – he responded affirmatively.
“You gonna hire the candidate or not?” the director abruptly asked.
“I don’t know,” Peter answered, “probably not. Why do you ask?”
“Huh? Probably not? Then why didn’t you tell my wife then!?”
And then it clicked. Deborah Franks. Jeremy Franks. Clearly, he had upset the wife of a director. “Sir,” he played defensive, “I told Deborah that I was in the hospital with my wife, who may have just had a heart attack. It didn’t seem like the approp–”
“You upset my wife,” Jeremy cut him off, “she’s eight months pregnant!”
“I uh… well, I told her it could wait until Monday, given the situate–”
“She told me that you didn’t answer any of her questions!”
“No, I didn’t,” Peter explained, “and the fact of her pregnancy was irrelevant to me, as I do not know your wife and you didn’t mention it the single time. Did I mention my wife is–”
“Don’t get smart with me,” the director barked, “do I need to remind you that I’m a director of this company, and you’ve only been here three months?”
“You just have,” Peter said, and then hung up. He almost immediately regretted doing that, as getting sacked might put his family’s health insurance at risk. Still, he had more important things to worry about, and he just wanted to focus on getting through weekend.
Fast forward two dreadfully long days, and Peter returned to work to face the wrath of a scored director. To his surprise, he faced something else: in his inbox was a letter of apology from his boss, along with a note from the CEO. Apparently, Jeremy’s outrage and blatant nepotism didn’t sit too well with the CEO, and as a result, Jeremy “was moved out of the company.”
As for Peter’s wife, she made a full recovery. And rumor has it that Jeremy found his way to a tech start-up with a role at the “bookkeeper” level instead of the “director” level.
Everyone responds to new requirements on already-behind-schedule projects in a different way. Many people feel anger, and try to find an innocuous way to show it. Others, realizing this might finally be their chance to shine, take it as a challenge with a smile. Still others, like Gary's colleague Steve, find a way to fulfill the requirements without actually fulfilling the requirements.
With less than a week remaining till the deadline of a 4-month-long project, Gary and Steve's boss demanded everyone write Unit test code. Gary spent hour upon unpaid overtime hour adding as many unit tests as he could come up with, while Steve left by 5pm each day. Their boss also asked them to set up a nightly script to perform the unit tests automatically. Each night Steve's test set would always come back with 100% successful results.
A few weeks after launch, Gary asked Steve how he managed to build so many unit tests in such a short amount of time.
Steve responded, "Oh, I read a book on unit testing months ago, and it really prepared me to write tests in no time at all."
Still not convinced how Steve managed to achieve this goal so easily, Gary opened up one of Steve's unit test files only to discover this:
public class TransactionProcessorTest {
private boolean state = false;
public void init() {
state = true;
}
@Test
public void testInit() {
TransactionProcessorTest = new TransactionProcessorTest();
Assert.assertEquals(false, t.state);
t.init();
Assert.assertEquals(true, t.state);
}
}
Gary realized the code had indeed tested something, that Steve knew nothing about unit testing.
When Sally graduated from college, she had aspirations of finding a career in project management. And much to her delight, she landed a great position with a large, internationally-based consulting firm. In addition to billing out fresh college graduates at obscenely high rates, the company developed obscenely expensive software for large enterprises.
With the vast majority of the firm’s software development being performed at the other end of the world, they relied heavily on teams at the client’s site to define application requirements and act as the “face” for the offshore developers. Sally was hired to work on these types of teams and, and to her, it seemed like a perfect fit.
Soon after being brought on, Sally was given a thorough “onshoring” training course at the company’s US headquarters. Basically, it was everything one needed to know to be a highly-paid consultant: proper protocol for communicating between the various groups, the importance of good documentation, and a crash course in project management best practices. Everything was a little bit rushed, but the instructors explained that everything was simply an overview – the real training would be learned on the job.
On the last day of training, Sally expected to receive her first assignment, but instead she returned home without any further direction. Naturally concerned, Sally called the HR representative who had hired her and asked when she might expect to be assigned to a client.
“Oh, that’s because you’ve been temporarily benched,” explained her HR rep, “Don’t worry though, really it should only be a week, tops!” The rep further explained that while on the bench, she would receive a full salary with benefits, and to think of it as a “paid vacation, minus the vacation part.” Sally was told to take advantage of the time to hone her skills and read up on some of the technologies that the company works with.
At first, it was complete bliss: getting paid to sleep in past 10am, getting paid to eat corn flakes, getting paid to watch Jerry Springer, and then getting paid to read “SAP Best Practices” at the local Starbucks. After the week had passed, Sally gave her rep a ring just to make sure that everything was ok and when she might expect her next assignment.
“We’re working on it!” replied the cheery HR rep, “Things are kind of in a holding pattern ...recession, dontchaknow!” she chuckled under her breath.
Sally asked when she might want to touch base again but she received a curt, and almost cliché, “Don’t call us, we’ll call you.”
Skip ahead a year later when Sally’s phone rings - it was the HR department of the company that she had received a steady stream of paychecks for the past 11 months and 22 days.
Turns out that a position at a client site had finally materialized...in Seattle...some thousand miles away.
Starting Monday.
Such a sudden and radical move wasn’t something that Sally had expected, but at this point, any opportunity seemed better than baking an anniversary cake for her time sitting on the bench. So, after some quick negotiations of the wheres and whens, Sally packed her things, boarded a flight, and booked a nice hotel room nearby the client site where she could stay.
It wasn’t too long before Sally realized that something was seriously amiss. As it turned out, some requirement was mistranslated by someone, and the client didn’t actually need an off-shore liaison. No, they needed a mid-level experienced VB developer.
Of course, since both the client and the consulting firm turn around as fast as a battleship, it took two full months for the mess to be sorted out. All the while, Sally did exactly what she had done for the past year: nothing. The only difference was she had to continue living out of a hotel and report to the client’s site every day.
Eventually, Sally was finally told to return home and await a new assignment. The HR rep promised her that they had a new, tentative assignment that was “right around the corner.” To this day, Sally is still waiting for that assignment and, of course, continuing to receive paychecks. But this time, she’s spending her bench time brushing up on her job interviewing skills.
Brian's company needs to track financial information indexed by 100 digit routing numbers. Now, obviously, not all of those digits are significant, so if a user enters "123", the application needs to be smart enough to pad out the other 97 digits with leading zeros. Sane people might think this should be implemented as a one-line call to a built-in method. The more DIY among us might waste time building up a for loop. And, of course, a LISP fan would simply torture future coders with recursion and parentheses.
Then there's this approach that Brian found:
function ZeroFill(Data) { var length = Data.length; var NewData; if (length >= 100) { NewData = Data.substring(0,length); } if (length == 99) { NewData = "0" + Data.substring(length-99,length); } if (length == 98) { NewData = "00" + Data.substring(length-98,length); } if (length == 97) { NewData = "000" + Data.substring(length-97,length); } /* ... SNIPPED FOR REALLY LONG AND REPETITIVE CODE ... */ if (length == 2) { NewData = "000000000000000000000000" + "00000000000000000" + "0000000000000000" + "0000000000000000" + "0000000000000000000000000" + Data.substring(length-2,length); } if (length == 1) { NewData = "0000000000000000000000000" + "00000000000000000" + "0000000000000000" + "0000000000000000" + "0000000000000000000000000" + Data.substring(length-1,length); } return NewData; } dp.SyntaxHighlighter.ClipboardSwf = 'http://img.thedailywtf.com/images/mark/dp.SyntaxHighlighter/Scripts/clipboard.swf'; dp.SyntaxHighlighter.HighlightAll('code');"None of our customers' web servers are online!" was not the kind of thing Ryan wanted to hear in the morning. Nor was it the kind of question Ryan wanted to hear from the 15 different department heads and administrators all shouting on the conference call that morning. Luckily (for everyone but Ryan), Ted from Net Operations was on the call. Ted was one of those hands-off system administrators who found that it was far easier to delegate work to someone else and leave early for a bar.
After 10 minutes of bickering, Ted announced that he had found the root cause of the problem: Ryan. He announced to the group that Ryan, in his ignorance and naivety, had deleted all of the customers' web servers from production. In shocked realization that today might be his last day on the job, Ryan was unable to speak at first, but one detail gnawed at him - throughout it all, he had followed the steps that Ted had given him to the letter. Ryan needed answers - if Ted said that he did indeed wreck the Production environment then it was Ted who would show him.
The Training ProcessIt all started about four weeks before that fateful morning. Ryan had been working at Initech for three months as a junior developer and was eager to learn all facets of the development process, including setting up a web server. Ryan's boss asked him to work with Ted to set up a new test server as part of the training process. Ted sent Ryan an e-mail with a link to a virtual clone of the production server he had created, along with a copy of a Visio diagram showing the configuration of all the servers across the domain.
Ryan's primary role as a developer left him with an hour or two each day to work on the test server. Ryan struggled with server configuration and despite trying a dozen different options; the test server would simply not talk to the other computers on the network properly. He sent numerous e-mails to Ted asking for assistance but rarely received a response. On rare occasions when Ted did respond, he often just resent the first e-mail that he had sent to Ryan with the same instructions and Visio diagram. Ryan also tried calling Ted and stopping by his desk, but Ted always seemed to be 'elsewhere'.
Finally, Ryan cornered Ted by the water cooler one day and begged for his help in setting up the test server. Ted instructed Ryan to clear out the old directories on the test server and reinstall IIS since they probably contained old data from the production clone.
Assigning Blame"I'm looking at the logs right now.", explained Ted while tapping on his monitor, obviously annoyed, "You were the last one on production and it was working just fine before you logged in."
Ryan shook his head in disbelief, "That's just not possible, I mean. It must have been someone else using my login."
"Look again!"
Ted pointed out that unless Ryan wasn't at his desk at 2:52pm the previous afternoon or the logs showing Ryan's workstation name and network id as being responsible were lying, it was indeed him.
Ryan couldn't deny it - he was at his desk the entire afternoon.
Ted chided, "Logging into a production server is strictly forbidden! You do not know our systems well enough. This isn't some college dorm room computer! All production requests need to go through me."
"But I'm telling you, there's no way I could have been on the production server, I logged into the test server, just like your documents showed, see?" and with that, Ryan thrusted out Ted's own documentation.
Suddenly Ted realized what had happened. Ted had given Ryan production server information instead of the test server he was supposed to be working on. To add insult to injury, Ryan had carefully compared the Visio diagram against the server information Ted had sent him not realizing that the Visio diagram, too, was out of date. At this point, Ted changed his tone and in a follow-up message to the group managed to talk his way out of trouble.
Ted stated that it wasn't Ryan's direct fault but rather it was a fault of his inexperience. He argued, "We can solve this in the future by more developer education. Since I don't have time in my busy schedule for training, perhaps one of the other operators can train him..."
Shortly thereafter, a backup of the server was loaded onto production and all was back to normal. In the end, Ryan's boss agreed with Ted's assessment and that it was a good learning experience. Ryan also learned to double check anything Ted told him with other members of the Net Operations team - not that Ted and Ryan spoke much after this, as Ted was rarely at his desk.
Consider "0010000000100000". It's a string filled with nothing but "1" and "0" characters. Now, unless such a string is part of some classroom assignment where the goal is to programmatically convert Based 2 to Base 10 — or, perhaps, existing in some highly-limited and/or perverted language like MUMPS — there is never a good reason for it to exist in a program.
Because there are so many more appropriate data types — a boolean array, an integer bitmask, or even an integer array, just to name a few — a "boolean string" is a canary in the coalmine. If it's in an application's codebase, then chances are, there's something seriously wrong with that code. If, perchance, such a string is found in a VARCHAR column in some database, then something isn't just seriously wrong, the application is nothing short of an epic disaster.
Unfortunately, Jani Chaushev knows this fact all to well. In the application he was tasked with maintaining, there are several such columns, each filled with rows of data like this.
001000000010000000000000000000001001000000000000000000000000000000000010000000000 000000000000000000000000000000001010000000000000000000000000000000000000000000000 101000000010000000000001000000001001000000000000011110000000000000000010000000000 000000000001100000000000000000001010000000000000000001111000000000000000000000001Fortunately, there's a perfectly sane way of querying for these rows. I'm kidding, of course. The rows are retrieved with a convoluted RegEx-based query.
SELECT * FROM `redcated_table_name` WHERE `extras` REGEXP '^[0-1]{25}[1]{1}[0-1]{55}$' OR `extras` REGEXP '^[0-1]{26}[1]{1}[0-1]{54}$' OR `extras` REGEXP '^[0-1]{27}[1]{1}[0-1]{53}$' OR `extras` REGEXP '^[0-1]{28}[1]{1}[0-1]{52}$' OR `extras` REGEXP '^[0-1]{29}[1]{1}[0-1]{51}$' OR `extras` REGEXP '^[0-1]{30}[1]{1}[0-1]{50}$' OR `extras` REGEXP '^[0-1]{31}[1]{1}[0-1]{49}$' OR `extras` REGEXP '^[0-1]{36}[1]{1}[0-1]{44}$' OR `extras` REGEXP '^[0-1]{37}[1]{1}[0-1]{43}$' OR `extras` REGEXP '^[0-1]{38}[1]{1}[0-1]{42}$' OR `extras` REGEXP '^[0-1]{39}[1]{1}[0-1]{41}$' OR `extras` REGEXP '^[0-1]{40}[1]{1}[0-1]{40}$' OR `extras` REGEXP '^[0-1]{41}[1]{1}[0-1]{39}$' OR `extras`='1'And it only gets worse. This convoluted query for convoluted data is generated by even more convoluted code.
$sql = ''; $sql_sess = ''; if(isset($_POST['search_act']) && $_POST['search_act']== 1) { if ( isset($_POST['show_extras']) || isset($_POST['show_extras_x']) || isset($_POST['show_extras_y']) ) { for($i=1;$i<=81;$i++) { if(isset($_POST['extra'.$i]) && $_POST['extra'.$i]==1) { //if (in_array($i, array(1,2,3,4,5,6,7,8,9,10,11,12,13,14))) if (in_array($i, array(77,78,79,80,81))) { $iii=0; //for($ii=77;$ii<82;$ii++) for($ii=1;$ii<15;$ii++) { if($_POST['extra'.$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($ii-1) ."}[1]{1}[0-1]{".($i-$ii-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{" .($i-1)."}[1]{1}[0-1]{" .(81-$i)."}$' OR"; } } else if($i==15 or $i==16 or $i==17 or $i==18 or $i==19 or $i==20){ $iii=0; for($ii=21;$ii<25;$ii++) { if($_POST['extra'.$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{" .($i-1)."}[1]{1}[0-1]{".($ii-$i-1) ."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{" .($i-1)."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else if($i==43 or $i==44 or $i==45){ $iii=0; for($ii=46;$ii<47;$ii++) { if($_POST['extra'.$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{" .($i-1)."}[1]{1}[0-1]{".($ii-$i-1) ."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{" .($i-1)."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else if($i==47 or $i==48 or $i==49){ $iii=0; for($ii=50;$ii<52;$ii++) { if($_POST['extra'.$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".($ii-$i-1)."}[1]{1}[0-1]{" .(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else if($i==52 or $i==53){ $iii=0; for($ii=54;$ii<56;$ii++) { if($_POST['extra'.$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".($ii-$i-1) ."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else if($i==56 or $i==57){ $iii=0; for($ii=58;$ii<60;$ii++) { if($_POST['extra'.$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".($ii-$i-1) ."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else{ //if($i!=21 and $i!=22 and $i!=23 and $i!=24 and // $i!=46 and $i!=50 and $i!=51 and $i!=54 and // $i!=55 and $i!=58 and $i!=59 and $i!=77 and // $i!=78 and $i!=79 and $i!=80 and $i!=81) if($i!=21 and $i!=22 and $i!=23 and $i!=24 and $i!=46 and $i!=50 and $i!=51 and $i!=54 and $i!=55 and $i!=58 and $i!=59 && !in_array($i, array(1,2,3,4,5,6,7,8,9,10,11,12,13,14))) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } $sql_sess .= "1"; } else { $sql_sess .= "0"; } } $_SESSION['sql'] = '0'.$sql_sess; } if (isset($_POST['show_all']) || isset($_POST['show_all_x']) || isset($_POST['show_all_y'])) { $sql = ""; $sql_sess = str_pad("0", 81, "0", STR_PAD_RIGHT); $_SESSION['sql'] = $sql_sess; } } else { $sql_sess = str_split($_SESSION['sql']); $isnul = 'T'; for($i=1;$i<=81;$i++) { if(isset($sql_sess[$i]) && $sql_sess[$i]==1) { $isnul = 'F'; //if (in_array($i, array(1,2,3,4,5,6,7,8,9,10,11,12,13,14))) if (in_array($i, array(77,78,79,80,81))) { $iii=0; //for($ii=77;$ii<82;$ii++) for($ii=1;$ii<15;$ii++) { if($sql_sess[$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($ii-1) ."}[1]{1}[0-1]{".($i-$ii-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1) ."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else if($i==15 or $i==16 or $i==17 or $i==18 or $i==19 or $i==20){ $iii=0; for($ii=21;$ii<25;$ii++) { if($sql_sess[$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .($ii-$i-1)."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .(81-$i)."}$' OR"; } } else if($i==43 or $i==44 or $i==45){ $iii=0; for($ii=46;$ii<47;$ii++) { if($sql_sess[$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .($ii-$i-1)."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .(81-$i)."}$' OR"; } } else if($i==47 or $i==48 or $i==49){ $iii=0; for($ii=50;$ii<52;$ii++) { if($sql_sess[$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .($ii-$i-1)."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .(81-$i)."}$' OR"; } } else if($i==52 or $i==53){ $iii=0; for($ii=54;$ii<56;$ii++) { if($sql_sess[$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .($ii-$i-1)."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .(81-$i)."}$' OR"; } } else if($i==56 or $i==57){ $iii=0; for($ii=58;$ii<60;$ii++) { if($sql_sess[$ii]==1) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{" .($ii-$i-1)."}[1]{1}[0-1]{".(81-$ii)."}$' OR"; $iii++; } } if($iii==0) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } else{ //if($i!=21 and $i!=22 and $i!=23 and $i!=24 and // $i!=46 and $i!=50 and $i!=51 and $i!=54 and // $i!=55 and $i!=58 and $i!=59 and $i!=77 and // $i!=78 and $i!=79 and $i!=80 and $i!=81 ) if($i!=21 and $i!=22 and $i!=23 and $i!=24 and $i!=46 and $i!=50 and $i!=51 and $i!=54 and $i!=55 and $i!=58 and $i!=59 && !in_array($i, array(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) ) { $sql .= " `extras` REGEXP '^[0-1]{".($i-1)."}[1]{1}[0-1]{".(81-$i)."}$' OR"; } } } } if($isnul=='T') { $sql_sess = '00000000000000000000000000000000000000000'. '0000000000000000000000000000000000000000'; } } if($sql_sess!='0000000000000000000000000000000000000000'. '00000000000000000000000000000000000000000') { $sql = $sql." `extras`='1'"; //$sql .= " 1"; } else{ $sql = "1"; } $ProductsController = new ProductsController; $arr = $ProductsController->getProducts($dbo, $sql, $_GET); $smarty->assign('results_tpl', 1); if(count($arr['catalog_arr'])>0) { $smarty->assign('catalog_arr', $arr['catalog_arr']); }