dilbert

Fiepke.nl

nixcraft

Slashdot

The Daily WTF

XKCD

Toothpaste for Dinner

Ars Tech

Google News

PBFComics

linux voice

SMBC

coindesk

MAGPIE php feed reader

Error'd: Perfectly Logical

"Outlook can't open an attachment because it claims that it was made in Outlook, which Outlook doesn't think is installed...or something," writes Gavin.

 

Mitch wrote, "So, the problems I'm having with activating Windows 10 is that I need to install Windows 10. Of course!"

 

"I don't expect 2018 to come around," writes Adam K., "Instead we'll all be transported back to 2014!"

 

"Here I thought that the world had gone mad, but then I remembered that I had a currency converter add-on installed," writes Shahim M.

 

John S. wrote, "It's good to know that the important notices are getting priority!"

 

Michael D. wrote, "It's all fun and games until someone tries to exit the conference room while someone else is quenching their thirst."

 

[Advertisement] Atalasoft?s imaging SDKs come with APIs & pre-built controls for web viewing, browser scanning, annotating, & OCR/barcode capture. Try it for 30 days with included support.

I Need More Space

Beach litter, Winterton Dunes - geograph.org.uk - 966905

Shawn W. was a newbie support tech at a small company. Just as he was beginning to familiarize himself with its operational quirks, he got a call from Jim: The Big Boss.

Dread seized Shawn. Aside from a handshake on Interview Day, the only "interaction" he'd had with Jim thus far was overhearing him tear into a different support rep about having to deal with "complicated computer crap" like changing passwords. No doubt, this call was bound to be a clinic in saintly patience.

"Tech Support," Shawn greeted. "How may—?"

"I'm out of space and I need more!" Jim barked over the line.

"Oh." Shawn mentally geared up for a memory or hard drive problem. "Did you get a warning or error mes—?"

"Just get up here and bring some more space with you!" Jim hung up.

"Oh, boy," Shawn muttered to himself.

Deciding that he was better off diagnosing the problem firsthand, Shawn trudged upstairs to Jim's office. To his pleasant surprise, he found it empty. He sank into the cushy executive-level chair. Jim hadn't been away long enough for any screensavers or lock screens to pop up, so Shawn had free rein to examine the machine.

There wasn't much to find. The only program running was a web browser, with a couple of tabs open to ESPN.com and an investment portfolio. The hardware itself was fairly new. CPU, memory, hard drive all looked fine.

"See, I'm out of space. Did you bring me more?"

Shawn glanced up to find Jim barreling toward him, steaming mug of coffee in hand. He braced himself as though facing down an oncoming freight train. "I'm not sure I see the problem yet. Can you show me what you were doing when you noticed you needed more space?"

Jim elbowed his way over to the mouse, closed the browser, then pointed to the monitor. "There! Can't you see I'm out of space?"

Indeed, Jim's desktop was full. So many shortcuts, documents, widgets, and other icons crowded the screen that the tropical desktop background was barely recognizable as such.

While staring at what resembled the aftermath of a Category 5 hurricane, Shawn debated his response. "OK, I see what you mean. Let's see if we can—"

"Can't you just get me more screen?" Jim pressed.

More screen? "You mean another monitor?" Shawn asked. "Well, yes, I could add a second monitor if you want one, but we could also organize your desktop a little and—"

"Good, get me one of those! Don't touch my icons!" Jim shooed Shawn away like so much lint. "Get out of my chair so I can get back to work."

A short while later, Shawn hooked up a second monitor to Jim's computer. This prompted a huge and unexpected grin from the boss. "I like you, you get things done. Those other guys would've taken a week to get me more space!"

Shawn nodded while stifling a snort. "Let me know if you need anything else."

Once Jim had left for the day, Shawn swung past the boss' office out of morbid curiosity. Jim had already scattered a few dozen shortcuts across his new real estate. Another lovely vacation destination was about to endure a serious littering problem.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

CodeSOD: A Lazy Cat

The innermost circle of Hell, as we all know, is trying to resolve printer driver issues for all eternity. Ben doesn’t work with the printers that we mere mortals deal with on a regular basis, though. He runs a printing press, three stories of spinning steel and plates and ink and rolls of paper that could crush a man.

Like most things, the press runs Linux- a highly customized, modified version of Linux. It’s a system that needs to be carefully configured, as “disaster recovery” has a slightly different meaning on this kind of heavy equipment. The documentation, while thorough and mostly clear, was obviously prepared by someone who speaks English as a second language. Thus, Ben wanted to check the shell scripts to better understand what they did.

The first thing he caught was that each script started with variable declarations like this:

GREP="/bin/grep"
CAT="/bin/cat"

In some cases, there were hundreds of such variable declarations, because presumably, someone doesn’t trust the path variable.

Now, it’s funny we bring up cat, as a common need in these scripts is to send a file to STDOUT. You’d think that cat is just the tool for the job, but you’d be mistaken. You need a shell function called cat_file:

# function send an file to STDOUT
#
# Usage: cat_file <Filename>
#

function cat_file ()
{
        local temp
        local error
        error=0
        if [ $# -ne 1 ]; then
                temp=""
                error=1
        else
                if [ -e ${1} ]; then
                        temp="`${CAT} ${1}`"
                else
                        temp=""
                        error=1
                fi
        fi
        echo "${temp}"
        return $((error))
}

This ‘belt and suspenders’ around cat ensures that you called it with parameters, that the parameters exist, and failing that, it? well? fails. Much like cat would, naturally. This gives you the great advantage, however, that instead of writing code like this:

dev="`cat /proc/dev/net | grep eth`"

You can instead write code like this:

dev="`cat_file /proc/dev/net | ${GREP} eth`"

Much better, yes?

[Advertisement] BuildMaster integrates with an ever-growing list of tools to automate and facilitate everything from continuous integration to database change scripts to production deployments. Interested? Learn more about BuildMaster!

The CMS From Hell

Hortus Deliciarum - Hell

Contracting can be really hit or miss. Sometimes, you're given a desk and equipment and treated just like an employee, except better paid and exempt from team-building exercises. Sometimes, however, you're isolated in your home office, never speaking to anyone, working on tedious, boring crap they can't convince their normal staff to do.

Eric was contracted to perform basic website updating tasks for a government agency. Most of the work consisted of receiving documents, uploading them to the server, and adding them to a page. There were 4 document categories, each one organized by year. Dull as dishwater, but easy.

The site was hosted by a third party in a shared hosting environment. It ran on a CMS produced by another party. WTFCMS was used in many high-profile sites, so the agency figured it had to be good. Eric was given login credentials and—in the way of techies given boring tasks everywhere—immediately began automating the task at hand.

Step 1 of this automation was to get a list of articles with their IDs. Eric was pleased to discover that the browser-based interface for the CMS used a JSON request to get the list of pages. With the help of good old jq, he soon had that running in a BASH shell script. To get the list of children for an article, he passed the article's ID to the getChildren endpoint.

Usually, in a heirarchy like this, there's some magic number that means "root element." Eric tried sending a series of likely candidates, like 0, -1, MAX_INT, and MIN_INT. It turned out to be -1 ... but he also got a valid list when he passed in 0.

Curious, he thought to himself. This appears to be a list of articles ... and hey, here's the ones I got for this site. These others ...? No way.

Sure enough, passing in a parent ID of 0 had gotten Eric some sort of super-root: every article across every site in the entire CMS system. Vulnerability number 1.

Step 2 was to take the ID list and get the article data so he could associate the new file with it. This wasn't nearly as simple. There was no good way to get the text of the article from the JSON interface; the CMS populated the articles server-side.

Eric was in too deep to stop now, though. He wrote a scraper for the edit page, using an XML parser to handle the HTML form that held the article text. Once he had the text, he compared it by hand to the POST request sent from his Firefox instance to ensure he had the right data.

And he did ... mostly. Turns out, the form was manipulated by on-page Javascript before being submitted: fields were disabled or enabled, date/time formats were tweaked, and the like. Eric threw together some more scripting to get the job done, but now he wasn't sure if he would hit an edge case or somehow break the database if he ran it. Still, he soldiered on.

Step 3 was to upload the files so they could be linked to the article. With Firebug open, Eric went about adding an upload.

Now, WTFCMS seemed to offer the usual flow: enter a name, select a file, and click Upload to both upload the file and save it as the given name. When he got to step 2, however, the file was uploaded immediately—but he still had to click the Upload button to "save" it.

What happens if I click Cancel? Eric wondered. No, never mind, I don't want to know. What does the POST look like?

It was a mess of garbage. Eric was able to find the file he uploaded, and the name he'd given it ... and also a bunch of server-side information the user shouldn't be privvy to, let alone be able to tamper with. Things like, say, the directory on the server where the file should be saved. Vulnerability number 2.

The response to the POST contained, unexpectedly, HTML. That HTML contained an iframe. The iframe contained an iframe. iframe2 contained iframe3; iframe3 contained a form. In that form were two fields: a submit button, reading "Upload", and a hidden form field containing the path of the uploaded file. In theory, he could change that to read anything on the server. Now he had both read and write access to any arbitrary destination in the CMS, maybe even on the server itself. Vulnerability number 3.

It was at this point that Eric gave up on his script altogether. This is the kind of task that Selenium IDE is perfect for. He just kept his head down, hoped that the server had some kind of validation to prevent curious techies like himself from actually exploiting any of these potential vulnerabilities, and served out the rest of his contract.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

Representative Line: Highly Functional

For a brief period of time, say, about 3–4 years ago, if you wanted to sound really smart, you’d bring up “functional programming”. Name-dropping LISP or even better, Haskell during an interview marked you as a cut above the hoi polloi. Even I, surly and too smart for this, fell into the trap of calling JavaScript “LISP with curly braces”, just because it had closures.

Still, functional programming features have percolated through other languages because they work. They’re another tool for the job, and like any tool, when used by the inexpert, someone might lose a finger. Or perhaps someone should lose a finger, if only as a warning to others.

For example, what if you wanted to execute a loop 100 times in JavaScript? You could use a crummy old for loop, but that’s not functional. The functional solution comes from an anonymous submitter:

Array.apply(null, {length: 99}).map(Number.call, Number).forEach(function (element, index) {
// do some more crazy stuff
});

This is actually an amazing abuse of JavaScript’s faculties, and I thought I saw the worst depredations one could visit on JavaScript while working with Angular code. When I first read this line, my initial reaction was, “oh, that’s not so bad.” Then I tried to trace through its logic. Then I realized, no, this is actually really bad. Not just extraneous arrays bad, but full abused of JavaScript bad. Like call Language Protective Services bad. This is easier to explain if you look at it backwards.

forEach applies a function to each element in the array, supplying the element and the index of that element.

Number.call invokes the Number function, used to convert things into numbers (shocking, I know), but it allows you to supply the this against which the function is executed. map takes a callback function, and supplies an array item for the currentValue, the index, and the whole array as parameters. map also allows you to specify what this is, for the callback itself- which they set to be Number- the function they’re calling.

So, remember, map expects a callback in the form f(currentValue, index, array). We’re supplying a function: call(thisValue, numberToConvert). So, the end result of map in this function is that we’re going to emit an array with each element equal to its own index, which makes the forEach look a bit silly.

Finally, at the front, we call Array.apply, which is mostly the same as Array.call, with a difference in how arguments get passed. This allows the developer to deftly avoid writing new Array(99), which would have the same result, but would look offensively object-oriented.

[Advertisement] High availability, Load-balanced or Basic – design your own Universal Package Manager, allow the enterprise to scale as you grow. Download and see for yourself!

Error'd: @TitleOfErrord

"I asked my son, @Firstname, and he is indeed rather @Emotion about going to @ThemePark!" wrote Chris @LASTNAME.

 

"I think Google assumes there is only one exit on the highway," writes Balaprasanna S.

 

Axel C. writes, "So what you're saying here is that something went wrong?"

 

"Hmmmm...YMMV, but that's not quite the company that I would want to follow," wrote Rob H.

 

"You know, I also confuse San Francisco with San Jose all the time. I mean, they just sound so much alike!" writes Mike S.

 

Mike G. writes, "Sure, it's a little avant garde, but I hear this film was nominated for an award."

 

[Advertisement] Otter enables DevOps best practices by providing a visual, dynamic, and intuitive UI that shows, at-a-glance, the configuration state of all your servers. Find out more and download today!

CodeSOD: Classic WTF: Hacker Proof Booleans

We continue our summer break with a classic case of outsmarting oneself in the stupidest way. Original -- Remy

"Years ago, long before I'd actually started programming, I spent my time learning about computers and data concepts by messing around with, believe it or not, cheat devices for video games," wrote Rena K., "The one I used primarily provided a RAM editor and some other tools which allowed me to tool around with the internal game files and I even get into muddling around with the game data all in the interest of seeing what would happen."

"As such, by the time my inflated hacker ego and I got into programming professionally, I was already pretty familiar with basic things like data types and binary. I was feeling pretty darn L33T."

"However, this mindset lead to me thinking that someone could potentially 'steal my program' by replacing my name with theirs in a hex editor and claiming to have made it themselves. (Which wasn't unheard of in the little game hacking communities I was in...) So I used the h4x0r sk1llz I'd picked up to make my program hacker-proof."

"Of course I knew full well how boolean variables worked, but I'd read somewhere that in VB6, boolean types were actually integers. From this, I concluded that it was technically possible that a boolean variable could hold a value that was neither true or false. Of course there was no way to do this from within VB, so that could only mean someone was monkeying around with something they shouldn't. I needed a way to detect this."

if var = true then
    doThings()
else if var = false then
    doOtherThings()
else
    MsgBox("omfg haxor alert")
    End --terminate program
end if

"I kept up adding the above to my code for years until I grew up enough to realize that it didn't do a darn thing. For the record though, nobody ever managed to 'steal my program'."


Do you have any confessions you'd like to make? Send them on in.

[Advertisement] Infrastructure as Code built from the start with first-class Windows functionality and an intuitive, visual user interface. Download Otter today!

Classic WTF: The Accidental Hire

At least we get a summer break, I suppose. Not like over at Doghouse Insurance. Original -- Remy

Doghouse Insurance (as we'll call them) was not a pleasant place to work. Despite being a very successful player in their industry, the atmosphere inside Doghouse was filled with a constant, frenzied panic. If Joe Developer didn't delay his upcoming vacation and put in those weekend hours, he might risk the timely delivery of his team's module, which might risk delaying the entire project, which might risk the company's earnings potential, which might risk the collapse of the global economy. And that's just for the Employee Password Change Webpage project; I can't even begin to fathom the overarching devastation that would ensue from a delayed critical project.

To make matters worse, the primary business application that poor souls like Vinny maintained was a complete nightmare. It was developed during the company's "database simplification" era and consisted of hundreds of different "virtual attribute tables" stuffed into four real tables; it was a classic case of The Inner-Platform Effect. But amidst all this gloom and despair was an upbeat fellow named Chris who accidentally became a part of the Doghouse Insurance team.

Chris interviewed with Doghouse Insurance back in 2002 for a developer position on the Data Warehouse team. With the large pool of available candidates at the time, Chris didn't make the cut and the opening was awarded to someone else. However, Doghouse never communicated this to him and instead offered him a job.

It was an awkward first day; Chris showed up and no one knew what to do with him. They obviously couldn't immediately fire him (it would risk a lawsuit, which might risk a -- oh, you know the drill) and, since all teams were short-staffed, they couldn't increase the headcount on one team because that would be unfair to all of the other managers. After a few weeks, it was finally decided: Chris would be the Source Control Guy.

Doghouse Insurance didn't really have a need for a Source Control Guy and Chris didn't really have any experience being a Source Control Guy. It was a perfect match. After a few months, Chris figured out how to manage Doghouse's Source Control System and became responsible for the entirety of SCS-related tasks: adding new users, reseting forgotten passwords, creating new repositories, and -- well -- that was pretty much it.

While everyone else stressed out and practically killed themselves over deadlines, Chris mostly sat around all day, waiting for that occasional "I forgot my source control password" email. He never gloated nor complained and instead made himself available to listen to his coworker's grievances and tales of woe. Chris would offer up whatever advice he could and would generally lighten the mood of anyone who stopped by his desk for a chat. His cubicle became the sole oasis of sanity in the frantic world of Doghouse Insurance.

Although Vinny is no longer at Doghouse Insurance (he actually left after following Chris' advice), he still does keep in touch with Chris. And Vinny is happy to report that, should you ever find yourself unfortunate enough to work at Doghouse Insurance, you can still find Chris there, managing the Source Control System and eager to chat about the insanity that is Doghouse.

[Advertisement] Scale your release pipelines, creating secure, reliable, reusable deployments with one click. Download and learn more today!

CodeSOD: Classic WTF: It's Like Calling Assert

We continue our summer vacation with this gem- a unique way to interact with structured exception handling, to be sure. Original. --Remy

When we go from language to language and platform to platform, a whole lot of “little things” change about how we write code: typing, syntax, error handling, etc. Good developers try to adapt to a new language by reading the documentation, asking experienced colleagues, and trying to follow best practices. “Certain Developers,” however, try to make the language adapt to their way of doing things.

Adrien Kunysz discovered this following code written by a “Certain Developer” who wasn’t a fan of the try...catch…finally approach called for in .NET Java development and exception handling.

   /**
    * Like calling assert(false) in C.
    */
   protected final void BUG (String msg) {
       Exception e = null;
       try { throw new Exception (); } catch (Exception c) { e = c; }
       logger.fatal (msg, e);
       System.exit (1);
   }

And I’m sure that, by commenting “Like calling assert(false) in C,” the author doesn’t mean assert.h, but means my_assert.h. After all, who is C – or any other language – to tell him how errors should be handled?

UPDATE: Fixed Typos and language. I swear, at 7:00AM this looked fine to me...

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

Classic WTF: Server Room Fans and More Server Room Fun

The Daily WTF is taking a short summer break this week, and as the temperatures around here are edging up towards "Oh God I Want to Die" degrees Fahrenheit, I thought it'd be great to kick off this week of classic articles with some broiling hot server room hijinks. -- Remy

"It's that time of year again," Robert Rossegger wrote, "you know, when the underpowered air conditioner just can't cope with the non-winter weather? Fortunately, we have a solution for that... and all we need to do is just keep an extra eye on people walking near the (completely ajar) server room door."

 

"For as long as anyone can remember," Mike E wrote, "the fax machine in one particular office was a bit spotty whenever it was wet out. After having the telco test the lines from the DMARC to the office, I replaced the hardware, looked for water leaks all along the run, and found precisely nothing. The telco disavowed all responsibility, so the best solution I could offer was to tell the users affected by this to look out the window and, if raining, go to another fax machine."

"One day, we had the telco out adding a T1 and they had the cap off of the vault where our cables come in to the building. Being curious by nature, I wandered over when nobody was around and wound up taking this picture. After emailing same to the district manager of the telco, suddenly we had the truck out for an extra day (accompanied by one very sullen technician) and the fax machine worked perfectly from then on."

 

"I found this when I came back in to work after some time off," writes Sam Nicholson, "that drive is actually earmarked for 'off-site backup'. Also, this is what passes for a server rack at this particular software company. Yes, it's made of wood."

 

"Some people use 'proper electrical wiring'," writes Mike, "others use 'extension cords'. We, on the other hand, apparently do this."

 

"I was staying at a hotel in Manhattan and somehow took a wrong turn and wound up in the stairwell," wrote Dan, "not only is all their equipment in a public place (without even a door), it's mostly hanging from cables in several places."

 

"I spotted this in China," writes Matt, "This poor switch was bolted to a column in the middle of some metal shop about 4m above ground. There were many more curious things, but I decided to keep a low profile and stop taking pictures."

 

[Advertisement] Infrastructure as Code built from the start with first-class Windows functionality and an intuitive, visual user interface. Download Otter today!

Error'd: Know Your Bits!

"I know software can't always be perfect, but things like this make me want to shut down my PC and say that's enough computering for the day," writes Timothy W.

 

Richard S. wrote, "I suppose you don't really need an email body when you have everything you need in the subject."

 

"I recently inherited a project from a contractor that left the project," writes Michael H., "I have never seen code quite like his, and that is NOT a compliment."

 

Bruce C. writes, "The fact that this won't ship to NZ is kind of immaterial - the REAL question is do I feel like spending $10.95 for new or can I settle for used at a discount?"

 

"I'm sure their product is great, but I don't want to be an early adopter if I can help it," writes Jaime A.

 

"To be fair, the email did catch my attention," wrote Philip G.

 

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

The Gassed Pump

“Staff augmentation,” was a fancy way of saying, “hey, contractors get more per hour, but we don’t have to provide benefits so they are cheaper,” but Stuart T was happy to get more per hour, and even happier to know that he’d be on to his next gig within a few months. That was how he ended up working for a national chain of gas-station/convenience stores. His job was to build a “new mobile experience for customer loyalty” (aka, wrapping their website up as an app that can also interact with QR codes).

At least, that’s what he was working on before Miranda stormed into his cube. “Stuart, we need your help. ProdTrack is down, and I can’t fix it, because I’ve got to be at a mandatory meeting in ten minutes.”

A close-up of a gas pump

ProdTrack was their inventory system that powered their point-of-sale terminals. For it to be down company wide was a big problem, and essentially rendered most of their stores inoperable. “Geeze, what mandatory meeting is more important than that?”

“The annual team-building exercise,” Miranda said, using a string of profanity for punctuation. “They’ve got a ‘no excuses’ policy, so I have to go, ‘or else’, but we also need to get this fixed.”

Miranda knew exactly what was wrong. ProdTrack could only support 14 product categories. But one store- store number 924- had decided that they needed 15. So they added a 15th category to the database, threw a few products into the category, and crossed their fingers. Now, all the stores were crashing.

“You’ll need to look at the StoreSQLUpdates and the StoreSQLUpdateStatements tables,” Miranda said. “And probably dig into the ProductDataPump.exe app. Just do a quick fix- we’re releasing an update supports any number of categories in three weeks or so, we just need to hold this together till then.”

With that starting point, Stuart started digging in. First, he puzzled over the tables Miranda had mentioned. StoreSQLUpdates looked like this:

IDSTATEMENTSTATEMENT_ORDER
145938DELETE FROM SupplierInfo90
148939INSERT INTO ProductInfo VALUES(12348, 3, 6)112

Was this an audit tables? What was StoreSQLUpdateStatements then?

IDSTATEMENT
168597INSERT INTO StoreSQLUpdates(statement, statement_order) VALUES (‘DELETE FROM SupplierInfo’, 90)
168598INSERT INTO StoreSQLUpdates(statement, statement_order) VALUES (‘INSERT INTO ProductInfo VALUES(12348, 3, 6)’, 112)

Stuart stared at his screen, and started asking questions. Not questions about what he was looking at, but questions about the life choices that had brought him to this point, questions about whether it was really that bad an idea to start drinking at work, and questions about the true nature of madness- if the world was mad, and he was the only sane person left, didn’t that make him the most insane person of all?

He hoped the mandatory team building exercise was the worst experience of Miranda’s life, as he sent her a quick, “WTF?” email message. She obviously still had her cellphone handy, as she replied minutes later:

Oh, yeah, that’s for data-sync. Retail locations have flaky internet, and keep a local copy of the data. That’s what’s blowing up. Check ProductDataPump.exe.

Stuart did. ProductDataPump.exe was a VB.Net program in a single file, with one beautifully named method, RunIt, that contained nearly 2,000 lines of code. Some saintly soul had done him the favor of including a page of documentation at the top of the method, and it started with an apology, then explained the data flow.

Here’s what actually happened: a central database at corporate powered ProdTrack. When any data changed there, those changes got logged into StoreSQLUpdateStatements. A program called ProductDataShift.exe scanned that table, and when new rows appeared, it executed the statements in StoreSQLUpdateStatements (which placed the actual DML commands into StoreSQLUpdates).

Once an hour, ProductDataPump.exe would run. It would attempt to connect to each retail location. If it could, it would read the contents of the central StoreSQLUpdates and the local StoreSQLUpdates, sorting by the order column, and through a bit of faith and luck, would hopefully synchronize the two databases.

Buried in the 2,000 line method, at about line 1,751, was a block that actually executed the statements:

If bolUseSQL Then
    For Each sTmp As String In sProductsTableSQL
        sTmp = sTmp.Trim()
        If sTmp <> "" Then
            SQLUpdatesSQL(lngIDSQL, sTmp, dbQR5)
        End If
    Next sTmp
End If

Once he was done screaming at the insanity of the entire process, Stuart looked at the way product categories worked. Store 924 didn’t carry anything in the ALCOHOL category, due to state Blue Laws, but had added a PRODUCE category. None of the other stores had a PRODUCE category (if they carried any produce, they just put it in PREPARED_FOODS). Fixing the glitch that caused the application to crash when it had too many categories would take weeks, at least- and Miranda already told him a fix was coming. All he had to do was keep it from crashing until then.

Into the StoreSQLUpdates table, he added a DELETE statement that would delete every category that contained zero items. That would fix the immediate problem, but when the ProductDataPump.exe ran, it would just copy the broken categories back around. So Stuart patched the program with the worst fix he ever came up with.

If bolUseSQL Then
    For Each sTmp As String In sProductsTableSQL
        sTmp = sTmp.Trim()
        If sTmp <> "" Then
            If nStoreNumber = 924 And sTmp.Contains("ALCOHOL") Then
                Continue For
            ElseIf nStoreNumber <> 924 And sTmp.Contains("PRODUCE") Then
                Continue For
            Else
                SQLUpdatesSQL(lngIDSQL, sTmp, dbQR5)
            End If
        End If
    Next sTmp
End If
[Advertisement] Application Release Automation – build complex release pipelines all managed from one central dashboard, accessibility for the whole team. Download and learn more today!

CodeSOD: A Promise of Timing

Asynchronous programming is hard, and there’s never been a perfect way to solve that problem. One of the most widely used solutions is the “promise” or “future”. We wrap the asynchronous process up in a, well, promise of a future result. “Someday, there will be data here, I hope.” The real beauty of promises comes from their composability- “getData promises to fetch some records, and then the calling method can promise to display them.”

Of course, it’s still asynchronous, and when an application has multiple asynchronous processes happening at the same time, “weird behavior” can happen, thanks to timing issues. Keith W encountered one of those timing related Heisenbugs, and became immediately suspicious about how it was getting invoked:

this.disableUI("Loading form...");
this.init(workflowId, ordinal).done(() => this.enableUI("Form loaded!"));

init isn’t passing data to the next promise in the chain. So what actually happens in the init method?

public init(workflowId: string, ordinal: number): JQueryPromise<any> {
  var self = this;

  var promise = $.Deferred<boolean>();

  $.when(
    $.ajax({
      type: "GET",
      url: getEndpoint("work", "GetFormInputForm"),
      data: { id: workflowId, ordinal: ordinal },
      contentType: "application/json",
      success(result) {
        if (result) {
          var formType = result.FormType || Forms.FormType.Standard;
          self.formMetaDataExcludingValues = result;
          var customForm = new Forms.CustomForm(formType, Forms.FormEditorMode.DataInput, result);
          self.CustomForm(customForm);
          self.flatControlList = customForm.flattenControls();
          ko.utils.arrayForEach(self.flatControlList, (cnt) => {
            var row = { name: cnt.name(), value: {}, displayText: "", required: cnt.required() };
            if (cnt instanceof Forms.SelectControl) {
              row.value = cnt.values();
            } else if (cnt instanceof Forms.ContactControl || cnt instanceof Forms.OrganisationControl) {
              row.displayText = cnt.displayName();
              row.value = cnt.value();
            } else if (cnt instanceof Forms.SequenceControl) {
              row.value = "";
            } else if (cnt instanceof Forms.AssetControl) {
              row.value = cnt.value();
              row.displayText = row.value ? cnt.displayName() : null;
            } else if (cnt instanceof Forms.CategoryControl) {
              row.value = cnt.cachedValue;
            } else {
              row.value = cnt.value();
            }

            self.defaultValues.push(new ControlValue(row));
          });
        }
      }
    })
  ).done(() => {
    $.ajax({
      type: "GET",
      url: url,
      data: { id: workflowId, ordinal: ordinal, numberOfInstances: self.NoOfInstances() },
      contentType: "application/json",
      success(result) {
        if (result) {
          var formType = result.FormType || Forms.FormType.Standard;
          if (!multiple) {
            self.CurrentInstanceNo(1);

            // store a blank form control values
            self.saveCurrentFormValues().done(() => self.applyKoBinding().done(() => {
              console.info("Data Saved Once.");
            }));
          } else {
            self.Forms([]);
            self.CurrentInstanceNo(self.NoOfInstances());
            self.saveAllFormValues(result).done(() => self.applyKoBinding().done(() => {
              console.info("Data Saved for all.");
            }));
          }
        }
      }
    })
  })

  promise.resolve(true);
  return promise;
}

This code is awful at first glance. It’s complicated spaghetti code, with all sorts of stateful logic that manipulates properties of the owning object. That’s your impression at first glance, but it’s actually worse.

Let’s highlight the important parts:

public init(workflowId: string, ordinal: number): JQueryPromise<any> {
  var promise = $.Deferred<boolean>();

  //big pile of asynchronous garbage

  promise.resolve(true);
  return promise;
}

Yes, this init method returns a promise, but that promise isn’t contingent on any other promises being made, here. promise.resolve(true) essentially renders this promise synchronous, not asynchronous. Instead of waiting for all the pending requests to complete, it immediately claims to have succeeded and fulfilled its promise.

No wonder there’s a?
?
?
?
?
?
?
?
? timing issue.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

The Insurance Plan

When designing a new feature of an application, among other things, you always want to decide how it will be used. Is it single threaded or will it need to happen in parallel. Will only one user do it at a time, or does it need to support asynchronous access. Will every user want to do it in the same way, or will they each want something just a little different.

In Sewer Ants, ants in a Sewer

Charlie C. worked for a modestly sized financial startup that had gained some traction. The company had grown to about 100 people. They had garnered about 300 customers, and they were building software that would solve a problem that was causing regulators all manner of headaches.

The system essentially provided the ability for customers to swap bond insurance contracts. These swaps could be between any two, three or four parties, depending upon the type of transaction. One day, one of the customers asked the CEO if they could implement an approval workflow. Specifically, before letting some low level trader execute a swap, it would be routed to a group with approval authority. If approved, the transaction would be routed to the other party. If not, it would be rejected back to the initiator.

The CEO asked the development manager who came to Charlie and told him to just hard code some flags in the main transaction record, and check for them as special cases at every relevant place in the code. Charlie knew that if one customer wanted it, that most (if not all) of them would want it. Accordingly, he explained as much and said he would make it table driven.

"Won't that take longer to build?" the boss inquired.

"Of course it will take longer, but it's a whole lot more supportable than special-casing the code all over, and corrupting the main transaction record," Charlie replied. With 300 customers and transactions involving 2, 3 or 4 parties, there were almost 8 billion permutations; even a tiny fraction of customers requesting special handling would make it absolutely unsupportable. "Think of it like? insurance."

The manager insisted on the hard coding, but Charlie ignored him, knowing all too well the consequences of listening to his boss.

A few months later, the work was done. On the very last day of work, as Charlie was doing some final cleanup, his boss walked over with the CEO in tow. They were both in a bit of a panic. "Another customer has asked for special workflow processing, but in a slightly different way. How much time will it take to add the additional workflow logic?"

Charlie looked at his boss, laughed, and said "About thirty minutes."

"But it took months this time!"

"And this is why I don't listen to you." Charlie went on to explain that it would take about a half hour to create the relevant groups, users and flags to simulate the new workflow, and that he would try to start the servers, queue managers and 16 copies of their application (one for each user in the scenario) on his PC to demonstrate that it would perform the required routing.

At the appointed time, both CEO and development manager returned and watched as Charlie made his machine groan through the motions to perform the desired flow processing. While it was busy thrashing, he used the opportunity to point out that they had no demo environment, that the developer workstations were simply not powerful enough to perform these sorts of demos, and he apologized for taking so much of their time. As the CEO listened to the hard disk grinding away, he agreed and offered to let them buy more powerful developer workstations.

After about an hour of going through all the different scenarios, the CEO was pleased, thanked Charlie for his time and told him to put in an order for the workstations the next day. Then they walked away.

Later that day, the development manager was transferred to manage another team and someone else was put in charge of Charlie's project. Shortly thereafter, Charlie grabbed the other developers and put together specs for their dream machines, which were ordered the next day.

Over the next year, configurations for more than a thousand different special case workflows were added, and not a single byte of code had to change.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

CodeSOD: Variation on a Theme

If you’re not already aware, the Daily WTF is open source. We went the route of building our own CMS mostly because our application needs are pretty light. We don’t need themes, we don’t need WYSIWYG editors, we don’t need asset uploads. Also, with home-grown code, we know what’s in it, what it does, and any problems in the code are our own.

Which brings us to WordPress, land of the themes. There’s a cottage industry around building WordPress themes, and it’s a busy enough space that there are specialists in developing themes for specific industries. Alessandro ended up doing some work in the real estate business, tweaking a WP theme to change the way certain images would get displayed in a slide show.

$pic1 = get_field('pic_1');
$pic2 = get_field('pic_2');
$pic3 = get_field('pic_3');
$pic4 = get_field('pic_4');
$pic5 = get_field('pic_5');
$pic6 = get_field('pic_6');
$pic7 = get_field('pic_7');
$pic8 = get_field('pic_8');
$pic9 = get_field('pic_9');
$pic10 = get_field('pic_10');

if ($pic1!=""){
  if (strpos($pic1,'php') === false) {
  if (strpos($pic1,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic1); } else {
  if (strpos($pic1,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic1); } else {
  $pic1r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic1);
  echo '<li><a href="'.$pic1r.'" class="lbp_primary"><img src="'.$pic1r.'" /></a></li>';
  }
  }
  }
}
if ($pic2!=""){
  if (strpos($pic2,'php') === false) {
  if (strpos($pic2,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic2); } else {
  if (strpos($pic2,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic2); } else {
  $pic2r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic2);
  echo '<li><a href="'.$pic2r.'" class="lbp_primary"><img src="'.$pic2r.'" /></a></li>';
  }
  }
  }
}
if ($pic3!=""){
  if (strpos($pic3,'php') === false) {
  if (strpos($pic3,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic3); } else {
  if (strpos($pic3,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic3); } else {
  $pic3r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic3);
  echo '<li><a href="'.$pic3r.'" class="lbp_primary"><img src="'.$pic3r.'" /></a></li>';
  }
  }
  }
}
if ($pic4!=""){
  if (strpos($pic4,'php') === false) {
  if (strpos($pic4,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic4); } else {
  if (strpos($pic4,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic4); } else {
  $pic4r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic4);
  echo '<li><a href="'.$pic4r.'" class="lbp_primary"><img src="'.$pic4r.'" /></a></li>';
  }
  }
  }
}
if ($pic5!=""){
  if (strpos($pic5,'php') === false) {
  if (strpos($pic5,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic5); } else {
  if (strpos($pic5,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic5); } else {
  $pic5r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic5);
  echo '<li><a href="'.$pic5r.'" class="lbp_primary"><img src="'.$pic5r.'" /></a></li>';
  }
  }
  }
}
if ($pic6!=""){
  if (strpos($pic6,'php') === false) {
  if (strpos($pic6,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic6); } else {
  if (strpos($pic6,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic6); } else {
  $pic6r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic6);
  echo '<li><a href="'.$pic6r.'" class="lbp_primary"><img src="'.$pic6r.'" /></a></li>';
  }
  }
  }
}
if ($pic7!=""){
  if (strpos($pic7,'php') === false) {
  if (strpos($pic7,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic7); } else {
  if (strpos($pic7,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic7); } else {
  $pic7r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic7);
  echo '<li><a href="'.$pic7r.'" class="lbp_primary"><img src="'.$pic7r.'" /></a></li>';
  }
  }
  }
}
if ($pic8!=""){
  if (strpos($pic8,'php') === false) {
  if (strpos($pic8,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic8); } else {
  if (strpos($pic8,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic8); } else {
  $pic8r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic8);
  echo '<li><a href="'.$pic8r.'" class="lbp_primary"><img src="'.$pic8r.'" /></a></li>';
  }
  }
  }
}
if ($pic9!=""){
  if (strpos($pic9,'php') === false) {
  if (strpos($pic9,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic9); } else {
  if (strpos($pic9,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic9); } else {
  $pic9r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic9);

      if( file_exists( $pic9 ) ) {
        echo '<li><a href="'.$pic9r.'" class="lbp_primary"><img src="'.$pic9r.'" /></a></li>';
      }
  }
  }
  }
}
if ($pic10!=""){
  if (strpos($pic10,'php') === false) {
  if (strpos($pic10,'floorplan')) { $floor =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic10); } else {
  if (strpos($pic10,'EPC')) { $epc =  str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic10); } else {
  $pic10r = str_replace("[HIDDEN-URL]","/wp-content/uploads/",$pic10);
  echo '<li><a href="'.$pic10r.'" class="lbp_primary"><img src="'.$pic10r.'" /></a></li>';
  }
  }
  }
}

As you can see, the loop was unrolled for performance, and the extraneous tab characters were removed to keep the filesize down. It's easy to add or remove images from the slide-show, by doing a simple copy/paste action. This is some top-shelf code here.

[Advertisement] Atalasoft?s imaging SDKs come with APIs & pre-built controls for web viewing, browser scanning, annotating, & OCR/barcode capture. Try it for 30 days with included support.