CodeSOD: Elliptical Curveball |
Why is it that you hear people saying, dont roll your own crypto? It cant be that bad, right? I mean, if the code gives the correct outputs when given the correct inputs?
Everything in cryptography depends upon high quality random numbers, and lots of them. People get into semi-informed flamewars about what entropy means, government agencies sneak backdoors into algorithms, performance matters, secrecy matters, and unpredictability matters. The standard which defines four randomness generators is NIST Special Publication 80090. One of the four raised suspicions because it (Dual_EC_DRBG) was three times slower than any of the others.
Joe… well, Joe sends us his own code, which fixed this. He made one of the others slower. Using MySQL stored procedures. Just bear in mind, with the below, that its still cleaner, more comprehensible, and generally saner than OpenSSL.
--
-- prng_nistctr_sp
-- Implements the NIST SP 800-90 CTR_DRBG cryptographic random number generator standard
-- with MySQL AES_ENCRYPT() as the block cipher (256 bit seed, 128 bit output)
--
DELIMITER //
DROP FUNCTION prng.make_128bit_block//
CREATE DEFINER = 'prng'@'localhost'
FUNCTION prng.make_128bit_block (p_h BIGINT UNSIGNED, p_l BIGINT UNSIGNED)
RETURNS TEXT
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
RETURN UNHEX( CONCAT(LPAD(HEX(p_h),16,'0'),LPAD(HEX(p_l),16,'0')) );
END;
//
DROP PROCEDURE prng.inc_128bit_value//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.inc_128bit_value (INOUT p_h BIGINT UNSIGNED, INOUT p_l BIGINT UNSIGNED)
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
IF p_l < 18446744073709551615 THEN
SET p_l = p_l + 1;
ELSE
SET p_l = 0;
IF p_h < 18446744073709551615 THEN
SET p_h = p_h + 1;
ELSE
SET p_h = 0;
END IF;
END IF;
END;
//
DROP PROCEDURE prng.nistctr_block_encrypt//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.nistctr_block_encrypt (p_vh BIGINT UNSIGNED, p_vl BIGINT UNSIGNED, p_kh BIGINT UNSIGNED, p_kl BIGINT UNSIGNED, OUT o_h BIGINT UNSIGNED, OUT o_l BIGINT UNSIGNED)
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE hexblock TEXT;
SET hexblock = HEX( AES_ENCRYPT(prng.make_128bit_block(p_vh, p_vl), prng.make_128bit_block(p_kh, p_kl)) );
SET o_h = CONV( SUBSTR(hexblock, 1, 16), 16, 10);
SET o_l = CONV( SUBSTR(hexblock, 17, 16), 16, 10);
END;
//
DROP PROCEDURE prng.nistctr_update//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.nistctr_update (INOUT p_vh BIGINT UNSIGNED, INOUT p_vl BIGINT UNSIGNED, INOUT p_kh BIGINT UNSIGNED, INOUT p_kl BIGINT UNSIGNED, IN p_dah BIGINT UNSIGNED, IN p_dal BIGINT UNSIGNED, IN p_dbh BIGINT UNSIGNED, IN p_dbl BIGINT UNSIGNED)
LANGUAGE SQL
CONTAINS SQL
NOT DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE tah,tal,tbh,tbl BIGINT UNSIGNED DEFAULT 0;
CALL prng.inc_128bit_value(p_vh, p_vl);
CALL prng.nistctr_block_encrypt(p_vh, p_vl, p_kh, p_kl, tah, tal);
CALL prng.inc_128bit_value(p_vh, p_vl);
CALL prng.nistctr_block_encrypt(p_vh, p_vl, p_kh, p_kl, tbh, tbl);
SET tah = tah ^ p_dah; SET tal = tal ^ p_dal;
SET tbh = tbh ^ p_dbh; SET tbl = tbl ^ p_dbl;
SET p_kh = tah; SET p_kl = tal;
SET p_vh = tbh; SET p_vl = tbl;
END;
//
DROP PROCEDURE prng.nistctr_instantiate//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.nistctr_instantiate (INOUT p_vh BIGINT UNSIGNED, INOUT p_vl BIGINT UNSIGNED, INOUT p_kh BIGINT UNSIGNED, INOUT p_kl BIGINT UNSIGNED, IN p_dah BIGINT UNSIGNED, IN p_dal BIGINT UNSIGNED, IN p_dbh BIGINT UNSIGNED, IN p_dbl BIGINT UNSIGNED)
LANGUAGE SQL
MODIFIES SQL DATA
NOT DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
SET p_kh = 0; SET p_kl = 0;
SET p_vh = 0; SET p_vl = 0;
CALL prng.nistctr_update(p_vh, p_vl, p_kh, p_kl, p_dah, p_dal, p_dbh, p_dbl);
END;
//
DROP PROCEDURE prng.nistctr_reseed//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.nistctr_reseed (INOUT p_vh BIGINT UNSIGNED, INOUT p_vl BIGINT UNSIGNED, INOUT p_kh BIGINT UNSIGNED, INOUT p_kl BIGINT UNSIGNED, IN p_dah BIGINT UNSIGNED, IN p_dal BIGINT UNSIGNED, IN p_dbh BIGINT UNSIGNED, IN p_dbl BIGINT UNSIGNED)
LANGUAGE SQL
MODIFIES SQL DATA
NOT DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
CALL prng.nistctr_update(p_vh, p_vl, p_kh, p_kl, p_dah, p_dal, p_dbh, p_dbl);
END;
//
DROP PROCEDURE prng.nistctr_generate//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.nistctr_generate (INOUT p_vh BIGINT UNSIGNED, INOUT p_vl BIGINT UNSIGNED, INOUT p_kh BIGINT UNSIGNED, INOUT p_kl BIGINT UNSIGNED, OUT o_h BIGINT UNSIGNED, OUT o_l BIGINT UNSIGNED, IN p_dah BIGINT UNSIGNED, IN p_dal BIGINT UNSIGNED, IN p_dbh BIGINT UNSIGNED, IN p_dbl BIGINT UNSIGNED)
LANGUAGE SQL
MODIFIES SQL DATA
NOT DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
SET o_h = NULL; SET o_l = NULL;
IF p_dal IS NULL THEN SET p_dal = 0; END IF;
IF p_dbh IS NULL THEN SET p_dbh = 0; END IF;
IF p_dbl IS NULL THEN SET p_dbl = 0; END IF;
IF p_dah IS NULL THEN
SET p_dah = 0;
ELSE
CALL prng.nistctr_update(p_vh, p_vl, p_kh, p_kl, p_dah, p_dal, p_dbh, p_dbl);
END IF;
CALL prng.inc_128bit_value(p_vh, p_vl);
CALL prng.nistctr_block_encrypt(p_vh, p_vl, p_kh, p_kl, o_h, o_l);
CALL prng.nistctr_update(p_vh, p_vl, p_kh, p_kl, p_dah, p_dal, p_dbh, p_dbl);
END;
//
DROP FUNCTION arosystem.hex_prng_generate_block//
CREATE DEFINER = 'prng'@'localhost'
FUNCTION arosystem.hex_prng_generate_block ()
RETURNS TEXT
MODIFIES SQL DATA
NOT DETERMINISTIC
SQL SECURITY DEFINER
BEGIN
DECLARE nvh,nvl,nkh,nkl BIGINT UNSIGNED DEFAULT 0;
DECLARE oh,ol BIGINT UNSIGNED DEFAULT NULL;
SELECT vh,vl,kh,kl INTO nvh,nvl,nkh,nkl FROM prng.prng_nistctr_state WHERE usable = TRUE LIMIT 1;
CALL prng.nistctr_generate(nvh,nvl,nkh,nkl,oh,ol,NULL,NULL,NULL,NULL);
UPDATE prng.prng_nistctr_state SET vh=nvh,vl=nvl,kh=nkh,kl=nkl, reseed_counter = reseed_counter + 1;
RETURN HEX( prng.make_128bit_block(oh,ol) );
END;
//
DROP PROCEDURE prng.prng_init_hex//
CREATE DEFINER = 'prng'@'localhost'
PROCEDURE prng.prng_init_hex (hexseed TEXT)
MODIFIES SQL DATA
NOT DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE nvh,nvl,nkh,nkl BIGINT UNSIGNED DEFAULT 0;
DECLARE dah,dal,dbh,dbl BIGINT UNSIGNED DEFAULT 0;
SET hexseed = LPAD(hexseed, 64, '0');
SET dah = CONV( SUBSTR(hexseed, 1, 16), 16, 10);
SET dal = CONV( SUBSTR(hexseed, 17, 16), 16, 10);
SET dbh = CONV( SUBSTR(hexseed, 33, 16), 16, 10);
SET dbl = CONV( SUBSTR(hexseed, 49, 16), 16, 10);
CALL prng.nistctr_instantiate(nvh,nvl,nkh,nkl,dah,dal,dbh,dbl);
UPDATE prng.prng_nistctr_state SET vh=nvh,vl=nvl,kh=nkh,kl=nkl, usable = TRUE, reseed_counter = 1;
END;
//
Joe at least imbued a certain something into the dance of bouncing in and out of hex representations; safely passing around the strings, and splitting the 128-bit values into 64-bit chunks, then recombining later. Even the modulo arithmetic, implemented by comparison to a hard-coded representation of 2^641, before either adding 1 or setting it to 0.
Yet, in the razzle-dazzle of the dance, certain teensy things may have slipped from Joes attention. Is that seed the required minimum size? What happens in the presence of concurrency? Oops- looks like two concurrent callerts to hex_prng_generate_block can get the same entropy, making the same updates to the state. Better hope this isnt being used for keying material to protect against eavesdropping, or an attacker can get the same keys by simply talking at the same time. And how is this initialized for the very first time?
Just because it looks like it works, returning good values, in good conditions, isnt enough for crypto. Enjoy Joes masterpiece. It might wake you up better than that cup of coffee as you follow along, but please, dont try this at home.
[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an
impressively-featured free edition, too!
|
Метки: CodeSOD |
Error'd: Online Shopping Magic |
"Wow! Every time I tapped 'See more products', the number more than doubled," writes Stephanie F.
Steve L. wrote, "I wonder. Will my order number get upgraded to a full integer once it has been shipped?"
"The loyalty program for the local chocolate shop wants to know your birthday and then gives you 12 free form fields to tell them what you think about having birthdays in each month of the year," wrote Rupert M.
"[%%PERSONAL_PRONOUN%%] feel so special," writes James C.
"It’s nice to know that my laptop will have the latest and greatest BIOS. Totally worth the extra time to boot up this morning," writes James B.
Quentin G. wrote, "Only the devil himself would name an update like this...Or an intern. Or a psychopath."
"An appropriate error considering the file's contents," Chris wrote.
"So, is this ColdFusion giving me my first warning?" Jack T. writes.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
|
Метки: Error'd |
CodeSOD: Hang On… |
Once upon a time, there was a small logistics company that did most of their software development in house. In the early 2000s, they decided to get ahead of the curve, and started building software to work on mobile devices. At the time, it was risky and uncertain, but over the next few decades, the idea of using commodity mobile phones to run their warehouse management software saved the company piles of money.
They grew so big that they cut the company into two parts- Inilogic, the big giant logistics company, and Initech, which made their mobile phone software. In the split, some developers went to Initech, while a few- like Mr. A- stayed with Inilogic.
Mr. A happened to be sitting in on a presentation where reps from Initech were showing off their cutting edge new feature: now users would be able to actually place calls from inside the application. Unfortunately, the demo didnt work. While the developers scrambled to figure out why, he saw this bit of code flash on the projector:
// Make sure phone hangs up
try {
phone.hangup();
phone.hangup();
phone.hangup();
}
catch (Exception e) {}
Two years later, the phone call functionality still doesnt work.
[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 Cable Outage |
New Year's Eve is a wonderful day. Not only a time of rejoicing—meeting and partying with friends and strangers alike to celebrate making it through yet another year—but also a time of change. Between new resolutions and yesteryear's memoirs, it's the best moment to move our lives in a different, exciting, and surprising direction.
For Mitch, however, that was not the case. Working for a cable TV company had taught him that when your superior called in the early evening on your day off, it meant one thing and one thing only.
"Hi, Boss," he sighed. "How bad is it?"
"Bad." The boss didn't sound too excited himself. "HBO and Showtime are down. People will want our heads on pikes if we don't bring them back up ASAP. So, I know I shouldn't be bothering you, but I've tried everyone and—"
"No, it's okay," Mitch said. "Just give me twenty minutes to get to the office. I think I know what the problem is, it shouldn't take long."
"You're a lifesaver," the boss said with relief. "We'll talk about compensation when you're back. See you, and good luck."
Mitch left the house and started his car in surprisingly high spirits. The receivers at the office had their bad moods. All he needed to do was flick a reset switch, and the channels would be broadcasting again. Given holiday overtime was six times his normal hourly salary, he felt like he'd gotten the better end of the deal.
Two hours later found Mitch kicking himself for his optimism.
He'd tried resetting the receivers. He'd tried replacing them with spares. He'd checked and rechecked all the cables and connections, went through the whole troubleshooting list twice—all for naught. Not only were the two premium channels still not broadcasting, but along the way, another three channels had gone down, one by one.
Think, Mitch, think! he urged himself. Huddled in front of a laptop, he tried to connect to one of the failing devices over the local network, but it was just as unmoved by his pings as by his pleas. There was nothing visibly wrong with the network configuration, and other devices plugged into the same ports worked just fine, but the dead receivers stubbornly refused to work no matter what tricks he used.
Mitch had no choice but to move to the next step in the troubleshooting protocol. With trembling hands, he dialed the device vendor's helpdesk number.
"Thank you for calling Initrode Systems, my name is Nathaniel. How can I help you?"
A New Year's miracle! The monotone voice on the other side filled Mitch with hope. He'd never expected to connect to a living soul so quickly, on a holiday at that.
"Hello, my name is Mitch. I'm having a problem with my equipment ..." He explained his troubles in detail, noting every symptom he'd witnessed.
"I see," Nathaniel said. "Have you tried turning the device off and on again?"
The lengthy conversation left Mitch no wiser. He went through the motions, only to hear that "the only suggestion" Initrode Systems had for him was to replace his router. Mitch couldn't fathom how a router would have anything to do with not being able to connect to devices on the same network. Nevertheless, he grumbled a thank-you to Nathaniel and hung up.
One thing he'd noticed during the troubleshooting gauntlet was that right after turning on, the devices would work for a few seconds, and only then suddenly drop dead. That gave him a glimmer of an idea. He dug out a dusty Ethernet hub, switched up a few cables, and started capturing packets from the whole network, trying to find a pattern.
As burst upon burst of network traffic appeared on Mitch's monitor, he finally started smiling. There was a pattern to this madness. He picked up the phone and called Paul, his colleague from IT.
"Mitch! Hey there, buddy, what's up? Celebrating the New Year already?"
"No way, how could I start without you?" Mitch joked. "Listen, Paul, sorry for the interruption, but I have a bit of a situation here at work. Think you could spare a few minutes?"
"Oh. I thought you were on vacation?"
"I was."
"Well, shoot," Paul said. "I'll do my best."
Mitch recapped the outage situation, then segued into his latest findings. "A few seconds after booting, some of our receivers try to send an SNMP trap to some IP, then the ICMP Destination Unreachable message pipes in and they just die. They don't work, they don't respond to pings, they don't generate any traffic."
"Huh." Paul muttered something under his breath. "That's an odd response, but it's not wrong. Maybe there's a bug in the firmware? Have you called the vendor?"
Mitch suppressed a flare of anger. "They've been as helpful as you'd expect."
"Of course. And to think we're paying for that support ... Anyway, what was that IP?" Paul asked.
After dictating the address, Mitch heard faint typing for a few seconds. Finally, Paul picked up again.
"Well, I don't think I can help you. The IP is for a router at our other office. I can't remote in there, and you probably won't be able to get in today either."
Mitch sighed, at the end of his rope. There's one more thing I can try, he thought. "But you can remote to the router in here, right?"
"I can," Paul said.
"Can you add that IP as its secondary interface? Maybe it will play nicer with the trap?"
"That ..." Paul paused for a while. "Hey, that might actually work. Let me try."
After a few minutes, Paul told Mitch to try resetting the receivers again. He flicked the switch and went back to his laptop, crossing his fingers.
There's the trap ... there's the response ...
"Bingo!" he exclaimed as the packets started to flow again and the receiver showed up as operational.
"Woo-hoo, we saved the New Year!" Paul cried, jubilant.
"It seems so, everything looks OK here. Thanks a lot, man."
"Not a problem. Now hurry up and get out of there, you can still catch the ball drop on TV!"
"If I don't get drunk before then. See you next year!"
Mitch hung up and started packing his things. Looking through the window at the first fireworks set off by impatient celebrators, he knew what his first New Year's resolution would be: Never underestimate any problem.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
|
Метки: Feature Articles |
CodeSOD: Databases Done Fresh |
Nobody knew how Carl kept his job. Some said he was the boss' boss' nephew, or perhaps knew some dirt on the CEO. Some said he had been threatened with termination before, but his lawyer had advised the company it was cheaper to keep him than to get rid of him. Whatever the case, Carl's eccentricities were legendary.
Seeing Carl's footprints on the SVN logs for his project, Paul decided to brave the trip to his cubicle for an explanation of some rationale that eluded his understanding.
Carl's cube was in a back corner, almost forgotten, half-hidden behind the coffee station—just as Carl liked it. He'd built a top to his cube out of cardboard, to keep the area dark despite the flourescant lights. Tinfoil was wrapped around the signs, to counter the "EF rays" that set off his "electrosensitivity." The air smelled faintly of roses and cough drops.
As Paul knocked, Carl turned, taking off a large pair of noise-cancelling headphones before removing the earbuds nestled underneath. "What brings you to my abode?" he asked, with a wide grin that probably was meant to be casual but instead came off as just a little manic.
"I had some questions about your commit, ah, revision 512?"
Paul tried to keep his tone light, but a shadow passed over Carl's face, and his fingers began to twist against each other, fidgeting.
"Ah, yes. Five twelve. Five hundred and twelve. Five hundred and ten and two. A bad number, very bad."
Paul blinked. "... Right. It's just, I don't understand what you were trying to do here?" Tentatively, he held out the printout for Carl to see:
String[] columns = row.split(",", -1);
String field1 = columns[0];
String field2 = columns[1];
String field3 = columns[2];
String field4 = columns[3];
String field5 = columns[4];
String field6 = columns[5];
String field7 = columns[6];
String field8 = columns[7];
//String field9Old = columns[8];
String field9 = columns[8];
String field10 = columns[9];
String field11 = columns[10];
//String field13Old = columns[12];
sql = "insert into tableName(field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, field11) " +
"values (?,?,?,?,?,?,?,?,?,?,?)";
dao.executeSql(sql, new String[]{field1,field2,field3,field4,field5,field6,field7,field8,field9,field10,field11});
Carl nodded, far too many times for Paul's comfort. "Yes, yes. Very bad. You see, the array was too old. Unusable. Data integrity lost."
"Too ... old?" asked Paul, hesitantly.
"Yes. The data, it was stale, you see. Only fresh data can go into the database. Otherwise it attracts ants."
"... Right. Ants. Got it. Thanks." Paul began to back away, hoping only to extract himself safely.
"Be careful of the EF rays!" Carl replied far too cheerily as he put his earbuds back in his ears.
Technically it's not hurting much, Paul thought desperately to himself as he returned to the lit portion of the office. Maybe he won't notice if I wait a week before ripping it back out? Or a month or two ...?
Still, he couldn't get one last lingering doubt out of his mind: Whatever happened to the old field12?
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
|
Метки: CodeSOD |
Classic WTF: Who Needs Connectivity? I Have Service! |
Today is traditionally the day in which Americans go into debt to sate the appetite of their economy. Let's go back to a simpler time- 2013- with this classic WTF about dial-up Internet service. Originally written by Kirby F.
Jim worked in the IT department of a university and one of his many jobs was maintaining the dial-up system.
Yes, that's right. Dial-up.
Back in the 90's the university promised all their faculty members that when they retired they would get free dial-up internet service, forever. Retired people tend to be pretty set in their ways, so Jim wasn't surprised that they still had users in 2010. But nothing could have prepared him for the call he was about to receive.
When the phone rang, Jim only said "hello" and was immediately greeted by an angry woman shouting "My dial-up isn't working!"
Although Jim was the right person to handle such a problem, he was a bit startled. Despite the fact that his phone number wasn't published anywhere this person had somehow managed to completely bypass the help desk and call him directly. Since he hadn't identified himself as being in the IT department, Jim told the caller "Sorry, you've got the wrong person. You need to call someone else."
He had barely gotten the words out when the caller launched into a tirade like nothing he had ever heard before. "My name is Mary B. I used to be head of the Music Department, and I was assistant provost, and I just had dinner with the university president last night and . . . ." on and on, barely pausing to take a breath, finally ending with "John said I should call you directly whenever I have a problem because you're the only person there with any sense".
Jim was flattered by the compliment, but, wait a minute. John? As in university president John Smith? His boss's boss's boss? Holy crap, this is real! Jim knew he had no choice but to start working on her problem.
"OK. In order to make sure I get this right, could you please spell your username for me."
"Sure, M-A-R-Y-B"
Jim checked everything he could think of -- server logs, connectivity between the modems and server -- but the entire system seemed to be working fine. Not only were there no failed login attempts in any of the logs, there was no record of any recent logins by Mary. The use of real-names in user ID's fell out of favor in the late 90's ...maybe she just doesn't use the system very often?
Jim told Mary to hold on while he tried to log in to his account to see if anyone else was affected or only her. "So you singled me out to break my account?" Mary asked, sounding very irritated.
"No, that's not it at all", Jim tried to explain, but Mary didn't want to hear it.
"John said you were smart and I just want my dial-up to work."
After quite a bit of digging and fumbling around, all the while giving Mary vague assurances that he was doing something helpful, Jim managed to find and boot up his old laptop that had a modem so he could try dialing into the system himself. It had been a while since he had done this but eventually, he heard the sound of a successful 56k connection.
Jim was able to successfully connect to his account and the logs showed everything working perfectly. "When was the last time you were able to connect?" Jim asked. But Mary didn't answer. Instead she insisted that he play the "internet noise" again, but louder this time so she could hold the phone up to her computer and she wouldn't proceed any farther until he tried it, "just to be sure".
Wait. Did she say that her computer wasn't making "internet noises" anymore? So Jim had her check all the wires, but everything seemed to be connected properly. Then Jim asked if she had a phone she could plug into the wall jack to make sure there was a dial tone.
"I don't know what good that would do", Mary said, "my daughter bought us cell phones and we cancelled the phone line last week."
There was a long pause as Jim just didn't know what else to say. Finally Mary broke the silence. "Well, I guess my husband was right".
Jim knew he would regret asking the next question, but his curiosity got the best of him.
"Right about what?"
"He said whenever we have a problem I should just call a random number at the university and yell until I find someone who will help me. He says it's way better than AOL's support."
Jim was confused. "I don't know how AOL could possibly help you with our dial-up, and, as a retired faculty member you can just call our help desk any time you want."
"Oh, I just told you that so you would help me. I'm not even sure where the university is."
As Jim hung up, he was sure about one thing. He really hated Mary and he wasn't the least bit ashamed of it.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
http://thedailywtf.com/articles/classic-wtf-who-needs-connectivity-i-have-service
|
Метки: Feature Articles |
Representative Line: Be Thankful for Good Requirements |
In the US, todays the Thanksgiving holiday. As I learned from A Charlie Brown Thanksgiving, its supposed to be about friendship, family, and being grateful for what you have. In common practice, its more about gorging yourself.
While I was perusing our inbox, I saw that Matthew sent me a flow chart that represented a set of requirements from his sales team. Immediately upon opening it, I said, Thank goodness I dont have to work on this.
So, today, whether you celebrate the orgy of American excess or not, celebrate this fact. Youve never been handed a requirements document this bad. I hope.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
http://thedailywtf.com/articles/be-thankful-for-good-requirements
|
Метки: Representative Line |
CodeSOD: Mid-Stream Switch |
Submitter James writes: "I'm working on a project that has as one of its components a Microsoft App for Excel 2013. My team lead wrote most of the app up to this point, and I'm adding features. While exploring her code, I ran into this little gem (in JavaScript):"
function ClearData() {
var spn = document.getElementById("spntest");
spn.innerHTML = "";
var def = $.Deferred();
var arBlankMiddle = new Array();
var arNull = new Array();
arNull.push(0);
spn.innerHTML = "";
for (var i = 1; i <= 50; i++) {
arBlankMiddle.push([0]);
}
spn.innerHTML = "";
var arBlank = new Array();
// arBlank.push(arBlankMiddle);
arBlank = [[""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""], [""]];
spn.innerHTML = "";
$.when(writeData("A1:A50", arBlank), writeData("B1:B50", arBlank), writeData("C1:C50", arBlank), writeData("D1:D50", arBlank), writeData("E1:E50", arBlank), writeData("F1:F50", arBlank), writeData("G1:G50", arBlank), writeData("H1:H50", arBlank), writeData("I1:I50", arBlank), writeData("J1:J50", arBlank), writeData("K1:K50", arBlank), writeData("L1:L50", arBlank), writeData("M1:M50", arBlank), writeData("N1:N50", arBlank)).done(function (res1, res2, res3, res4, res5, res6, res7, res8, res9, res10, res11, res12, res13, res14) {
spn.innerHTML = "";
def.resolve();
});
//$.when(writeData("A1:A50", arBlank)).done(function (res1) {
// def.resolve();
//});
return def.promise();
}
James explains: "writeData() is a function that writes to Excel given the specified range and data. So it looks like she started with an iterative approach, but in the middle switched to a non-iterative one, but left the half-finished iterative code in. I'm speechless."
[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!
|
Метки: CodeSOD |
The Guru and The Code |
A logistics company isnt the kind of company that invests heavily in IT, no matter how vital IT is for their business. Thats why Rich spent several years as the only developer. Most of his code was built to pick up data from one siloed turn-key system and dump it into a different one, or to integrate two in-house developed applications. On a bad day, he had to touch up the VBA macros in home-grown Excel spreadsheet someone in accounting had hacked together and had suddenly become business critical.
Practically overnight, the logistics company hit an inflection point in its growth curve, and suddenly they were exploding. Revenue quintupled, new SBUs were created from thin air, and headcounts expanded accordingly. This, sadly, left Rich drowning in the flood of new requests. I need help, he told his management.
We dont have room for more IT hires, but we can bring on some contractors, was the reply.
And thus appeared Lunch Room Guy. Lunch Room Guy was the new contractor from Initech. With the rapid expansion, they didnt have any office space for contractors, so Lunch Room Guy was so named because that was where he sat. He immediately proved his utility by learning how to work the newfangled and overly complicated coffee machine. He was cheerful, enthusiastic and friendly. Eager to prove he was a good team player, he even went so far as to train others on how to use those coffee machines during his lunch hour.
The only problem with Lunch Room Guy was that he didnt have all that much experience. Well, he admitted, Ive only got a few years experience with .NET, but my boss is a total guru. I can call on him anytime I get stuck, so itll be fine.
A guru! How exciting! Based on the Initechs track record, based on Lunch Room Guys enthusiastic demeanor, and based on their confidence in his Guru, Rich handed off a set of simple requirements for processing some XML-based data, and a little advice. Weve been using XLinq- Linq to XML- for doing XML processing. It works very well, but your boss is the Guru, so if he has other ideas, let me know.
Requirements went in, and… something came out. Something that became known around the company as The Code. The Guru and Lunch Room Guy worked hard and communicated well. The users were kept in the loop, testing proceeded well, and the product got released into production without any issues. For the first few months, everything was smooth. The developer team kept growing to keep up with the business needs, and Lunch Room Guy was joined by Conference Room Gal #0, Conference Room Gal #1, and Broom Closet Jake.
As the company grew, the number of XML files hitting The Code also grew, and thats when everything started to blow up. Invalid XML was coming out of The Code, or sometimes the data was just incomplete. The users were angry, the CIO was furious, and Lunch Room Guy and his Guru were busy on other projects, which meant Rich had to take a look at the code.
The first thing he noticed was that there was absolutely no logging at all. There was nothing that gave him a clue to how many files were processed, or how long the processing took, or if any errors occurred. Rich quickly added some timestamps to the process, and discovered that it was taking well over two hours to process the XML files- which was a problem, since the downstream job that consumed the XML ran every hour.
Rich dug deeper into the code, and found mysterious enumerated types declared like so:
Public Enum TableType1
'table name here
LOADSCHEDULE
ARCHIVESCHEDULE
REVIEWSCHEDULE
End Enum
Public Enum Columns
ScheduleId
HeaderId
SchedNum
ShipWithRef
End Enum
Lunch Room Guys code was starting to smell like a week old bologna sandwich. Especially when, a few lines later, Rich found this gem:
Public ReadOnly Property TableType() As String
Get
Return _TableType.ToString
End Get
End Property
Public Sub SetTableType(ByVal TableType As GLEAN.Tables.HEADER.TableType1)
_TableType = TableType
End Sub
Get the table type as a string, but set it using an Enum? That kind of mysterious logic could only make sense to the mind of a Guru. A little further down in the same file, Rich found more of the Gurus handiwork…
Public Property Items(ByVal ColumnName As Columns) As Object
Get
Select Case ColumnName
Case Columns.DAddress1
Return _DAddress1
Case Columns.DAddress2
Return _DAddress2
Case Columns.DCity
Return _DCity
Case Columns.DCountry
Return _DCountry
'snip 28 more cases
End Select
End Get
Set(ByVal value As Object)
Try
Select Case ColumnName
Case Columns.ScheduleId
_ScheduleId = CInt(value)
Case Columns.HeaderId
_HeaderId = CInt(value)
Case Columns.SchedNum
_SchedNum = CInt(value)
Case Columns.ShipWithRef
If value.ToString.Length > 30 Then
_ShipWithRef = value.ToString.Substring(1, 30)
Else
_ShipWithRef = value.ToString
End If
If _ShipWithRef.Trim = "" Then
_ShipWithRef = ""
End If
' snip 28 more cases
End Select
Catch ex As Exception
End Try
End Set
End Property
This coding style was replicated throughout the entire project. The constructor (well, actually the Create method, as the code didnt use constructors) took 32 parameters. Pretty much every operation ran through a 32-branch Select/Case statement to decided what, exactly, to do. Exceptions were always caught and ignored. And this class represented just one section of the XML file- an XML file that was divided into 10 sections, each of which were backed with a database table ranging from 1040 columns.
Rich sought out Lunch Room Guy for an explanation of what this garbage was.
Oh, the Guru did all of the design and architecture, he said. Its a really genius pattern, because its like using a database, but without actually using a database. It runs in memory, so its lightning fast! Ive learned so much from the Guru.
Rich blinked and backed away slowly. Lunch Room Guy wasnt the only one who had learned from the Guru. Rich had learned two things. First, code reviews were not optional. Second, that there were times when the only option was to completely junk the existing code. Rich applied both of those lessons, and over the course of one long weekend, reimplemented his own solution. With a review from Conference Room Gal #2 and Broom Closet Jake, he released it into production.
Its less than one-hundredth the number of lines of code, it runs in seconds, not hours, produces copious logging data, and has been chugging away with little more than minor changes ever since. To this day, even though Rich and his co-workers have moved on to other jobs and projects, they connect over social media and routinely discuss The Code, Lunch Room Guy, and what it truly means to be a Guru.
[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an
impressively-featured free edition, too!
|
Метки: Feature Articles |
CodeSOD: Confession: The Coin-Flip Hash |
There are certain problems in computing that you generally shouldnt tackle unless youre planning to make it your lifes work. Dont write your own date handling logic. Dont write your own encryption. If you do, youll probably screw it up, so use something developed by someone who knows what they are doing.
Handling passwords is a subset of encryption, in many ways. Samuel sends this to us as a confession- he hopes to unburden himself of his sins. Its bad enough that hes passing passwords in the clear, but he goes a step farther:
if(isset($_POST["pass"])){
$r=rand(0,1);
if( ($r==0 && md5($_POST["pass"])=="7e843964cca0fe3c3adc1d3f8605554b") || ($r==1 && sha1($_POST["pass"])=="92f5d9410b62c8a35da15d64cacce9db13d15277") ){
//render successful login content, set cookie
}else{
//render login error
}
}else{
//render "no password" error
}
If the user has supplied a password, this utterly bizarre logic will flip a coin. Based on the flip, it will compare the hash of the input password using either MD5 or SHA1, and for bonus points, the hashes are hard-coded in, which I guess solves the problem of storing them someplace.
One of Samuels co-workers spotted this, saw his name on the commit, and asked him, What were you thinking?
Samuel could only answer, I wasnt.
[Advertisement] Use NuGet or npm? Check out ProGet, the easy-to-use package repository that lets you host and manage your own personal or enterprise-wide NuGet feeds and npm repositories. It's got an
impressively-featured free edition, too!
http://thedailywtf.com/articles/confession-the-coin-flip-hash
|
Метки: CodeSOD |
Error'd: End User Experience May Vary by Region |
"I guess eight of the ports are English-only," Andrew G. wrote.
"So, this means that nothing is expiring...right?" wrote Chris.
Steve L. wrote, "Hey AT&T! The 'Trim' function in JavaScript would work GREAT here."
"Um, can I opt out of the sale on this power meter?" wrote Scott.
"VS2010 was gracious enough to perform 916061759 more tasks than I wanted," wrote John A.
"You're welcome...I guess," writes Andrew.
"I don't think of this as an error so much as a reminder for some certain someone who, you know, might forget to insert their memory card," Alex G. wrote.
"This mobile TV was set up for people to watch World Cup matches outside Birmingham's Bullring centre, but it looks like it isn't quite ready for the opening match yet," writes Stuart D.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
http://thedailywtf.com/articles/end-user-experience-may-vary-by-region
|
Метки: Error'd |
CodeSOD: The Cleaner |
In software development, there are people who get the unenviable task of being the cleaner. Somebody makes a mess, and the cleaner comes in to take care of it. And that brings us to Tina.
Tina was brought in as a cleaner. There was an application that was a mess , and the powers-that-be wanted it taken care of. Tina took a look, and she noticed that there were a lot of round trips to the database. In fact, after profiling, it almost looked like every query ran at least twice. She saw code following this pattern everywhere:
if (!IsTableEmpty("users")) {
results = GetTableData("users");
}
Or, worse:
if (!IsTableEmpty("users") && !IsTableEmpty("orders") && !IsTableEmpty("line_items")) {
users = GetTableData("user");
orders = GetTableData("orders");
lines = GetTableData("lines");
for (int i = 0; i < users.count; i++) {
for (int j = 0; j < orders.count; j++) {
for (int k = 0; k < lines.count; k++) {
//manually join all the records together
//with a giant block of conditionals
}
}
}
}
With that sort of logic, Tina knew exactly how this particular application needed to be taken care of, but she was curious. Curiousity, of course, isnt a good trait in a cleaner. Dont ask questions. Dont poke your nose where it doesnt belong. But she just had to know- how was IsTableEmpty implemented?
private bool IsTableEmpty(string s){
SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM "+s,"server=****;database=****;User ID=****;Password=****");
DataSet ds = new DataSet();
adapter.Fill(ds);
int count=0;
foreach(DataRow row in ds.Tables[0].Rows){
count+=1;
}
if(count>0)
return false;
return true;
}
[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!
|
Метки: CodeSOD |
The Enterprise Axe |
If a piece of software is described in any way, shape or form with the word enterprise its a piece of garbage.
-Remys Law of Enterprise Software
Enterprise software products live in an uncomfortable space. They need to fulfill the needs of a business, without being specific to any one business. Theyre a one-size fits all solution, and companies like Oracle or SAP compete on their feature-set and the customizability of their inner platform.
Maciek recently had his own horrifying encounter with Microsofts own Enterprise Resource Planning tool, Dynamics AX. Dynamics AX is a monster glued together out of the left-over parts of every product Microsoft makes. It integrates with SharePoint, Office, Project Server, and of course SQL Server and SQL Server Reporting Services (SSRS), because a tool like this is not useful without some sort of reporting system. Its extensible through both .NET and COM. Its a mess thats been featured before.
Dynamics AX first entered Macieks life when his end-users complained that one of the Accounts Receivable reports was incorrect. Specifically, they needed the Invoice Date field to be color coded. If the invoice went out to a customer on a Monday, the field should be green, but if it went out the second Thursday of the month, it should be red, but black if it was any other day, except for Wednesdays, which should always be yellow unless they fall on an odd numbered calendar day or its a leap year. Maciek didnt ask the users why this particular insane business rule existed, because they wouldnt have explained it to him anyway. One specific user- Vlad- had a vision of what the report was supposed to look like, and that Maciek was responsible for fulfilling that vision.
Maciek dug into Dynamics AX and opened up the report in Business Intelligence Development Studio- Microsofts tool for editing SSRS reports. The report itself was a canned report, developed by Microsoft and bundled with Dynamics AX. Since naming things is one of the hard problems in computer science, whoever actually developed the report didnt bother trying to solve it. Every single field in the report was named textbox45 or textbox94. Since every field used a customized expression to control what was actually displayed, Maciek couldnt actually tell which field was the Invoice Date without examining the properties of hundreds of fields.
It took hours to find the field, and then Maciek carefully built a formatting expression that met Vlads vision. He ran the report with a few different sets of parameters, confirmed the output, then he sent sample reports to Vlad. Can you confirm these reports are correct? If they are, I can roll the changes out to AX.
A week went by with no reply from Vlad. Maciek moved on to other tasks. Another week went by. Maciek started to forget about Vlad entirely. Then, suddenly, a message with a subject line of REPORTS ARE BROKEN!!!!! arrived in Macieks inbox.
Why isnt this working? Vlads email demanded. I went to AX and ran the report and the invoice date field isnt color coded correctly. FIX IT.
I didnt put the changes in production yet, Maciek replied. I need you to confirm that the sample reports I sent are correct.
I DONT CARE, Vlad replied, I JUST WANT THE REPORTS FIXED.
This email exchange ballooned into a series of CCs and BCCs. Six levels of management swooped in to solve this crisis, and they solved it by dragging Maciek through twelve hours of meetings. Eventually, Vlad sent a follow up email. Was there something I was supposed to look at? Could you resend? Finally, Maciek was able to get the changes validated and released to production. He thought that would be the end of it.
A month later, Vlad sent another email with the subject, THE REPORTS ARE BROKEN!!!!! Specifically, the AR invoice report, which Maciek was the last person to touch, just printed out an error code and didnt generate data.
As the expert, Maciek verified the error in production, and then pulled up the report in BIDS to see if he could debug the problem. When he ran the report from BIDS, even against production data, it worked fine. It printed out 3,000 records just fine. Since it worked on his machine, that meant the problem had to be somewhere in Dynamics AX. AX didnt just run reports, but it had hooks where X++ (AXs platform-specific programming language) could interact with the report lifecycle.
Maciek grabbed a machete and plunged into the thicket of Microsofts X++ code. There, he found this:
///
/// Provides the opportunity for validation prior to running the report.
///
protected container preRunValidate()
{
// Record count is a good proxy for overall time on this
// report. However, each record requires a significant amount
// of processing and costly balance queries, so the limits
// are set significantly lower for this report than other
// reports. 100 records will take around 10 seconds to process
// and 2500 records will take around 15 minutes to process.
#define.WarningLimit(100)
#define.ErrorLimit(2500)
Query countQuery = this.getFirstQuery();
int recordCount;
recordCount = QueryRun::getQueryRowCount(countQuery);
if (recordCount > #ErrorLimit)
{
// Processing over the error limit should take around 20 minutes, so even
// with some error possible due to overlap in counting this still
// means the report will timeout on a machine with low volume and
// no load.
validateResult = [SrsReportPreRunState::Error];
}
else if (recordCount > #WarningLimit)
{
// Processing up to the warning limit should take around 10 seconds
validateResult = [SrsReportPreRunState::Warning];
}
return validateResult;
}
Note, this code executes after the query has been run against the database. If the query returns more than 2,500 records, this method sets an error code. From the comments, Maciek determined that the original developer believed that rendering a row on the report was neither CPU nor IO bound, but instead was a function of time. Maciek didnt believe that, and even if it were true, Vlad wouldnt mind waiting longer for the report to run if he got the results he wanted, but with that error limit set, increasing the timeout wouldnt do anything.
On a whim, Maciek decided to live dangerously, and disabled the error limit check. Thus far, the report continues to run just fine.
[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!
|
Метки: Feature Articles |
CodeSOD: A Hardware Switch |
Michele S. had recently worked on code for an engine-controlled device. Since the device had physically-moving parts operated by servos, the software had to be careful to not move anything out of bounds because it could actually break a physical piece of equipment.
Michele had written the low-level function which sets the position of a component.
void PlcPart::set_target_position (uint16_t parPosition) {
using boost::algorithm::clamp;
const uint16_t min_pos = m_set_base_position;
const uint16_t max_pos = min_pos + m_movement_range;
vaeAssertRelease(parPosition >= min_pos and parPosition <= max_pos);
m_target_position = clamp(parPosition, min_pos, max_pos);
}
It validates that the requested position is in a suitable range, asserts if its out-of-range, and then clamps it to the accepted range. It prevents physical damage to the hardware and safely notifies the programmer if they try to exceed the boundaries.
At some point, Michele discovered that the unit tests started having issues. Apparently, someone was annoyed at the assertion messages and took it upon himself to correct this. But, instead of fixing the root cause (calling set_target_position with bad values), he modified the function itself to look like this:
void PlcPart::set_target_position (uint16_t parPosition) {
using boost::algorithm::clamp;
const uint16_t min_pos = m_set_base_position;
const uint16_t max_pos = min_pos + m_movement_range;
if (parPosition > max_pos)
parPosition = max_pos;
vaeAssertRelease(parPosition >= min_pos and parPosition <= max_pos);
m_target_position = clamp(parPosition, min_pos, max_pos);
}
Assertions avoided! (Well, half of them anyway.)
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
|
Метки: CodeSOD |
Quality Overhaul |
"Hey, did you see the email? They're remaking our website!"
"No way, Dave. You're kidding." Cody rushed to his PC and opened the latest company newsletter. After three years of working at IniVenture, he found the news hard to believe. Despite many pleas from the employees, management had never dared to touch that relic of late 90s web design, opting to spend their time and money on more lucrative ventures instead.
"'Over the next few months,'" he read aloud with Dave peeking over his shoulder, "'we'll be cooperating with Victory Design, an award-winning web design and development agency, to bring IniVenture even closer to the world of Internet and modern technology.'"
"As if we were anywhere close to that now," Dave groaned, then took to hunting the usual bull. "Let's see: 'latest technologies,' 'brand synergy,' 'your feedback matters,' blah blah blah ... " He smirked. "Well, I don't know about you, but I can't wait to see the revamp. It's going to be a beautiful disaster."
Months passed without any news about the new website. Some employees sent their suggestions and offered help, only to be met with a standardized response and no follow-up. The newsletter didn't offer many updates either, other than the occasional reassurance that the project was "right on track" and would be completed "shortly." Reading between the lines, it seemed the revamp had either been shoved aside or canned.
Until one day, Cody ended up paying a visit to the IT department.
"Hi, Jen," he greeted the mousy girl tapping at the keyboard. "Can you hook me up with a clean laptop? We have a new guy starting in a few days."
"Uh, yeah, sure, but it'll have to wait a while," she said, not lifting her eyes from the monitor. "I'm just deploying the new website, so ..."
"Oh, it's done already?" Cody asked, surprised. "Is it any good?"
"I ... don't know, really," Jen answered. "I didn't even have time to look at it. The moment the PM got the first version from the designers, she forwarded it to me and told me to put it on a public server immediately."
"Wait, seriously?" Cody's eyes went wide. "Aren't you guys going to, um, test it or anything?"
"I tried to explain, and the other company did too, but ... well, let's just say I got my orders." Jen shrugged and went back to hacking at the keyboard.
"Well, good luck then."
Cody sneaked out of the room and went back to his desk. Wow, what a mess, he thought. It's probably going to be down for at least a week, maybe more.
But he turned out to be wrong. Just an hour later, his browser opened to the new, sleek, and remodelled IniVenture home page.
Except the more he dug into it, the more problems he found. Some links lead to 404 pages, others went into infinite redirect loops. A few images and captions were missing. And to top it off, most projects and clients were just test data left over by the developers, all of them located in "SAMPLE City, SAMPLE State, US".
Trying not to laugh, Cody clicked the "Employee Survey" link to let management know about the issues. The page promised that every employee who offered his feedback would be entered into a drawing to win a new iPhone. He answered the questions eagerly but honestly, describing his findings in detail. Then, when the last field of the form asked him to provide his name and email for the sweepstake, something dawned on him ...
"Hey, did you see the email? Guess who's the lucky guy with the new iPhone?"
"What, did I win?" Dave ran to Cody's desk and peeked over his shoulder. Trying not to laugh, Cody pulled up the latest company newsletter.
"'The new website proved to be an amazing success. We'd like to thank everyone for their efforts, and we'd like to thank over 17,000 of our employees for taking the time to voice their feedback.'"
"Wait, what?!" Dave cried. "We don't even have a tenth of—"
"Read on." Cody buried his face in his hands to contain the laughing fit.
"'The lucky winner of a new iPhone 6S is Mr. Bruce Wayne, who can contact our corporate offices at Gotham City to ...'" Dave shook his head. "Great. Now we have Batman working for us?"
"Either that, or someone failed to make sure that the employee survey was for employees only!" Giggling like a madman, Cody closed the email client.
It wasn't until the following month that management figured out the problems with the website. They ended up taking it down for a month of maintenance, then silently replaced it with the old version.
And as far as everybody at IniVenture knows, the Dark Knight never showed up to collect his iPhone.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
|
Метки: Feature Articles |
Error'd: Who Stole the Search Box?! |
"Why, thank you, Microsoft, I do need assistance with... wait a minute!" Steve L. writes.
"It's like you could click OK, but the app really doesn't want you to," wrote Miroslaw
"So, according to IBM's site, addresses only required for the US or Canada, so why am I being asked to enter it for Australia? WTF!," wrote Chris.
Mark writes, "I'm with you, Tundra, I blame my parents for a lot of things too."
"OneDrive is so great that it already has my future photos available," Tim N. wrote.
"I can't say for sure, but I think the analysis shows that either I have some bad code on my hands or my machine sucks," writes James D.
Kelly B. writes, "I went to get my stuff off the printer at work but it appeared to have passed."
"Dublin, Ireland near Los Angeles?! Heck, that isn't even close to Dublin, California!" wrote Catherine H.
[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!
|
Метки: Error'd |
Your Recommended Virus |
In the early 2000s, Fernando was the Network Operations Manager for a wireless ISP known for its comprehensive customer support. They had techs who’d install the necessary gear, and consultants who’d arrive onsite to reconfigure computers, routers, firewalls, and everything else, until the customer was completely up and running. A small team of developers could even custom-build any small software apps a customer might ask for.
The service was well loved. In fact, it was so thorough and helpful that after the initial install hiccups were soothed, Fernando and his support team almost never heard from customers again.
“We’re too good!” a sales manager complained during one of the most surreal meetings of Fernando’s career. “We’re hurting our own business! There’s gotta be a way for us to drive up service calls!”
“Ethically,” another sales-beast added quietly.
“Right, ethically. What can we do?”
Brainstorming commenced. A set number of service calls that the customer had to pay for upfront, whether or not they were ever used? Quarterly “check-ins” built into everyone’s service contracts (at a price, of course)?
“Hang on, this is still about helping our customers, right? Or at least it should be,” Fernando said. “What’s one thing that everyone needs help with, all the time? Security. New threats pop up all the time. Why don’t we set up a listserv that we can use to recommend security updates and best practices? That way, we’re staying in touch with the users with good advice—and we can encourage them to call us for help with implementing that stuff.”
It was a fantastic suggestion. The sales managers were happy. The top-level execs were happy. And since it had been Fernando’s big idea, he had the privilege of implementing it. He set up a Majordomo list-server, configured to accept postings from his email address only, then carried out his plan to great success. Customers received highlights from Bugtraq and other relevant sources, generated steady business, and were protected from many nasty problems.
Everyone was thrilled.
It took a full two years before the storm clouds surfaced, but surface they did. Bafflingly, Fernando received an email from the listserv that he hadn’t sent. He opened it, and slowly realized what he was looking at. A Windows virus from some customer's site had replied to one of his emails, and had used his email address as the forged sender. His list-server had then dutifully forwarded it to the entire distribution list.
Horror shot through him. Not two seconds later, the phone rang.
“Hi Fernando, it’s Brian. Listen, I just got your email. What do you need me to do with this here?”
“I’m sorry, it was a mistake,” Fernando gunned out, heart pounding. “Please go ahead and delete that.”
He was hardly off the first call when the next one came in. While he was on the line, he watched emails pile up in his inbox.
I don't understand what you mean by this.
Am I supposed to install this?
Can you have one of your guys come out and install this for me?
Fernando shook with terror. Sweat beaded at the nape of his neck. Hundreds of customers could potentially infect and torpedo their own operations, all because the Network Operations Manager in charge of security emails had just sent out a virus.
The next free moment on the phone, he called his receptionist. “Hold all my calls for the next few minutes, please.”
Before he heard any acknowledgement, he dropped the phone back into its cradle and began drafting a clarification email to explain the whole mess. Please disregard—
“Hey, what was that weird file you sent out?” A coworker leaned lazily past his office door. “Looks kinda suspicious to me.”
“I’m aware of that.” Fernando struggled not to curse or yell. “We’ll talk later.”
Once he’d sent out the email, he firewalled the majordomo process to only accept email from localhost. Then he sat back, closed his eyes, and prayed.
His quick action made more of a difference than any divine intervention. Fernando never heard any reports of customer systems getting infected from that incident.
Disturbingly, he also never figured out whose machine had sent the original.
[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!
|
Метки: Feature Articles |
CodeSOD: Confession: rect.Contains(point) |
A few years ago, Josip M decided to try his hand at building games using C# and the XNA framework. He started implementing the classic board game, Nine Mens Morris, but like most side projects, he lost interest and mostly forgot about it…
…until a few months ago, when he started cleaning up his hard drive, and found the code again. Then he remembered why he lost interest and abandoned the project:
if (Mouse.GetState().LeftButton == ButtonState.Pressed && PositionPhase == true)
{
#region Positions
// First line
if (Mouse.GetState().X > ((int)(175 * GraphicScale)) && Mouse.GetState().X < ((int)(325 * GraphicScale)) && Mouse.GetState().Y > ((int)(175 * GraphicScale)) && Mouse.GetState().Y < ((int)(325 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[0, 0] == '\0') { FigurePlacement[0, 0] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(175 * GraphicScale)) && Mouse.GetState().X < ((int)(325 * GraphicScale)) && Mouse.GetState().Y > ((int)(175 * GraphicScale)) && Mouse.GetState().Y < ((int)(325 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[0, 0] == '\0') { FigurePlacement[0, 0] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(175 * GraphicScale)) && Mouse.GetState().Y < ((int)(325 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[3, 0] == '\0') { FigurePlacement[3, 0] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(175 * GraphicScale)) && Mouse.GetState().Y < ((int)(325 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[3, 0] == '\0') { FigurePlacement[3, 0] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1675 * GraphicScale)) && Mouse.GetState().X < ((int)(1825 * GraphicScale)) && Mouse.GetState().Y > ((int)(175 * GraphicScale)) && Mouse.GetState().Y < ((int)(325 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[6, 0] == '\0') { FigurePlacement[6, 0] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1675 * GraphicScale)) && Mouse.GetState().X < ((int)(1825 * GraphicScale)) && Mouse.GetState().Y > ((int)(175 * GraphicScale)) && Mouse.GetState().Y < ((int)(325 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[6, 0] == '\0') { FigurePlacement[6, 0] = '2'; ++FigureCount2; PlayerTurn = 1; }
// Second line
else if (Mouse.GetState().X > ((int)(375 * GraphicScale)) && Mouse.GetState().X < ((int)(525 * GraphicScale)) && Mouse.GetState().Y > ((int)(375 * GraphicScale)) && Mouse.GetState().Y < ((int)(525 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[1, 1] == '\0') { FigurePlacement[1, 1] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(375 * GraphicScale)) && Mouse.GetState().X < ((int)(525 * GraphicScale)) && Mouse.GetState().Y > ((int)(375 * GraphicScale)) && Mouse.GetState().Y < ((int)(525 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[1, 1] == '\0') { FigurePlacement[1, 1] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(375 * GraphicScale)) && Mouse.GetState().Y < ((int)(525 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[3, 1] == '\0') { FigurePlacement[3, 1] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(375 * GraphicScale)) && Mouse.GetState().Y < ((int)(525 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[3, 1] == '\0') { FigurePlacement[3, 1] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1475 * GraphicScale)) && Mouse.GetState().X < ((int)(1625 * GraphicScale)) && Mouse.GetState().Y > ((int)(375 * GraphicScale)) && Mouse.GetState().Y < ((int)(525 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[5, 1] == '\0') { FigurePlacement[5, 1] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1475 * GraphicScale)) && Mouse.GetState().X < ((int)(1625 * GraphicScale)) && Mouse.GetState().Y > ((int)(375 * GraphicScale)) && Mouse.GetState().Y < ((int)(525 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[5, 1] == '\0') { FigurePlacement[5, 1] = '2'; ++FigureCount2; PlayerTurn = 1; }
// Third line
else if (Mouse.GetState().X > ((int)(575 * GraphicScale)) && Mouse.GetState().X < ((int)(725 * GraphicScale)) && Mouse.GetState().Y > ((int)(575 * GraphicScale)) && Mouse.GetState().Y < ((int)(725 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[2, 2] == '\0') { FigurePlacement[2, 2] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(575 * GraphicScale)) && Mouse.GetState().X < ((int)(725 * GraphicScale)) && Mouse.GetState().Y > ((int)(575 * GraphicScale)) && Mouse.GetState().Y < ((int)(725 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[2, 2] == '\0') { FigurePlacement[2, 2] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(575 * GraphicScale)) && Mouse.GetState().Y < ((int)(725 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[3, 2] == '\0') { FigurePlacement[3, 2] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(575 * GraphicScale)) && Mouse.GetState().Y < ((int)(725 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[3, 2] == '\0') { FigurePlacement[3, 2] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1275 * GraphicScale)) && Mouse.GetState().X < ((int)(1425 * GraphicScale)) && Mouse.GetState().Y > ((int)(575 * GraphicScale)) && Mouse.GetState().Y < ((int)(725 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[4, 2] == '\0') { FigurePlacement[4, 2] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1275 * GraphicScale)) && Mouse.GetState().X < ((int)(1425 * GraphicScale)) && Mouse.GetState().Y > ((int)(575 * GraphicScale)) && Mouse.GetState().Y < ((int)(725 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[4, 2] == '\0') { FigurePlacement[4, 2] = '2'; ++FigureCount2; PlayerTurn = 1; }
// 4th line
else if (Mouse.GetState().X > ((int)(175 * GraphicScale)) && Mouse.GetState().X < ((int)(325 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[0, 3] == '\0') { FigurePlacement[0, 3] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(175 * GraphicScale)) && Mouse.GetState().X < ((int)(325 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[0, 3] == '\0') { FigurePlacement[0, 3] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(375 * GraphicScale)) && Mouse.GetState().X < ((int)(525 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[1, 3] == '\0') { FigurePlacement[1, 3] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(375 * GraphicScale)) && Mouse.GetState().X < ((int)(525 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[1, 3] == '\0') { FigurePlacement[1, 3] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(575 * GraphicScale)) && Mouse.GetState().X < ((int)(725 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[2, 3] == '\0') { FigurePlacement[2, 3] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(575 * GraphicScale)) && Mouse.GetState().X < ((int)(725 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[2, 3] == '\0') { FigurePlacement[2, 3] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1275 * GraphicScale)) && Mouse.GetState().X < ((int)(1425 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[4, 3] == '\0') { FigurePlacement[4, 3] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1275 * GraphicScale)) && Mouse.GetState().X < ((int)(1425 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[4, 3] == '\0') { FigurePlacement[4, 3] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1475 * GraphicScale)) && Mouse.GetState().X < ((int)(1625 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[5, 3] == '\0') { FigurePlacement[5, 3] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1475 * GraphicScale)) && Mouse.GetState().X < ((int)(1625 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[5, 3] == '\0') { FigurePlacement[5, 3] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1675 * GraphicScale)) && Mouse.GetState().X < ((int)(1825 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[6, 3] == '\0') { FigurePlacement[6, 3] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1675 * GraphicScale)) && Mouse.GetState().X < ((int)(1825 * GraphicScale)) && Mouse.GetState().Y > ((int)(925 * GraphicScale)) && Mouse.GetState().Y < ((int)(1075 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[6, 3] == '\0') { FigurePlacement[6, 3] = '2'; ++FigureCount2; PlayerTurn = 1; }
// 5th line
else if (Mouse.GetState().X > ((int)(575 * GraphicScale)) && Mouse.GetState().X < ((int)(725 * GraphicScale)) && Mouse.GetState().Y > ((int)(1275 * GraphicScale)) && Mouse.GetState().Y < ((int)(1425 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[2, 4] == '\0') { FigurePlacement[2, 4] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(575 * GraphicScale)) && Mouse.GetState().X < ((int)(725 * GraphicScale)) && Mouse.GetState().Y > ((int)(1275 * GraphicScale)) && Mouse.GetState().Y < ((int)(1425 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[2, 4] == '\0') { FigurePlacement[2, 4] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(1275 * GraphicScale)) && Mouse.GetState().Y < ((int)(1425 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[3, 4] == '\0') { FigurePlacement[3, 4] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(1275 * GraphicScale)) && Mouse.GetState().Y < ((int)(1425 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[3, 4] == '\0') { FigurePlacement[3, 4] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1275 * GraphicScale)) && Mouse.GetState().X < ((int)(1425 * GraphicScale)) && Mouse.GetState().Y > ((int)(1275 * GraphicScale)) && Mouse.GetState().Y < ((int)(1425 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[4, 4] == '\0') { FigurePlacement[4, 4] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1275 * GraphicScale)) && Mouse.GetState().X < ((int)(1425 * GraphicScale)) && Mouse.GetState().Y > ((int)(1275 * GraphicScale)) && Mouse.GetState().Y < ((int)(1425 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[4, 4] == '\0') { FigurePlacement[4, 4] = '2'; ++FigureCount2; PlayerTurn = 1; }
// 6th line
else if (Mouse.GetState().X > ((int)(375 * GraphicScale)) && Mouse.GetState().X < ((int)(525 * GraphicScale)) && Mouse.GetState().Y > ((int)(1475 * GraphicScale)) && Mouse.GetState().Y < ((int)(1625 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[1, 5] == '\0') { FigurePlacement[1, 5] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(375 * GraphicScale)) && Mouse.GetState().X < ((int)(525 * GraphicScale)) && Mouse.GetState().Y > ((int)(1475 * GraphicScale)) && Mouse.GetState().Y < ((int)(1625 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[1, 5] == '\0') { FigurePlacement[1, 5] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(1475 * GraphicScale)) && Mouse.GetState().Y < ((int)(1625 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[3, 5] == '\0') { FigurePlacement[3, 5] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(1475 * GraphicScale)) && Mouse.GetState().Y < ((int)(1625 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[3, 5] == '\0') { FigurePlacement[3, 5] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1475 * GraphicScale)) && Mouse.GetState().X < ((int)(1625 * GraphicScale)) && Mouse.GetState().Y > ((int)(1475 * GraphicScale)) && Mouse.GetState().Y < ((int)(1625 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[5, 5] == '\0') { FigurePlacement[5, 5] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1475 * GraphicScale)) && Mouse.GetState().X < ((int)(1625 * GraphicScale)) && Mouse.GetState().Y > ((int)(1475 * GraphicScale)) && Mouse.GetState().Y < ((int)(1625 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[5, 5] == '\0') { FigurePlacement[5, 5] = '2'; ++FigureCount2; PlayerTurn = 1; }
// Last line
else if (Mouse.GetState().X > ((int)(175 * GraphicScale)) && Mouse.GetState().X < ((int)(325 * GraphicScale)) && Mouse.GetState().Y > ((int)(1675 * GraphicScale)) && Mouse.GetState().Y < ((int)(1825 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[0, 6] == '\0') { FigurePlacement[0, 6] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(175 * GraphicScale)) && Mouse.GetState().X < ((int)(325 * GraphicScale)) && Mouse.GetState().Y > ((int)(1675 * GraphicScale)) && Mouse.GetState().Y < ((int)(1825 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[0, 6] == '\0') { FigurePlacement[0, 6] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(1675 * GraphicScale)) && Mouse.GetState().Y < ((int)(1825 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[3, 6] == '\0') { FigurePlacement[3, 6] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(925 * GraphicScale)) && Mouse.GetState().X < ((int)(1075 * GraphicScale)) && Mouse.GetState().Y > ((int)(1675 * GraphicScale)) && Mouse.GetState().Y < ((int)(1825 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[3, 6] == '\0') { FigurePlacement[3, 6] = '2'; ++FigureCount2; PlayerTurn = 1; }
else if (Mouse.GetState().X > ((int)(1675 * GraphicScale)) && Mouse.GetState().X < ((int)(1825 * GraphicScale)) && Mouse.GetState().Y > ((int)(1675 * GraphicScale)) && Mouse.GetState().Y < ((int)(1825 * GraphicScale)) && PlayerTurn == 1 && FigurePlacement[6, 6] == '\0') { FigurePlacement[6, 6] = '1'; ++FigureCount1; PlayerTurn = 2; }
else if (Mouse.GetState().X > ((int)(1675 * GraphicScale)) && Mouse.GetState().X < ((int)(1825 * GraphicScale)) && Mouse.GetState().Y > ((int)(1675 * GraphicScale)) && Mouse.GetState().Y < ((int)(1825 * GraphicScale)) && PlayerTurn == 2 && FigurePlacement[6, 6] == '\0') { FigurePlacement[6, 6] = '2'; ++FigureCount2; PlayerTurn = 1; }
Its worth noting that XNA has a Rectangle structure and a Contains method which would have greatly simplified this code. At least Josip learned from the error of his ways.
[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!
http://thedailywtf.com/articles/confession-rect-contains-point
|
Метки: CodeSOD |
Single-User Mode |
It was a common occurrence for Jaroslaw F.s brother, Andrzej, to call him for help. Andrzej worked as a data-entry specialist for the Polish Ministry of Employment, while Jaroslaw was part of the ministrys IT department and moonlighted as a Python programmer.
One day, Jaroslaw answered another call from Andrzej. No sane person can do this job, Andrzej started. There just arent enough hours in the day.
Hours in the day? You enter data and run reports using web software. Its not that difficult.
No, you dont understand. The ministrys starting a new labor force program, and Im in charge of the data entry. But there are too many records to enter by hand.
Andrzej, Im really tired of this, Jaroslaw said. Im going to write you a script to help with your work, and in exchange you dont call me at work for six months. Deal?
Jaroslaw had never actually seen the software Andrzej used to enter data. Just getting to Andrzejs department required signing an authorization form at the front office, then a half-hour wait until his supervisor gave the go-ahead. But Jaroslaw knew writing the script for his brother wouldnt take very long.
Andrzej showed Jaroslaw to his desk and opened a browser. The web application looked current circa 1998, as if someone mocked up a Windows GUI in Internet Explorer 4. There were rows and rows of grey tabular data, text set in black Tahoma. Next to each cell was a button marked Edit.
You press the button to edit each cell, which takes a few seconds to load, Andrzej said, demonstrating. Each cell, and every row, must be entered one at a time
Surely theres a bulk import somewhere. Jaroslaw scrolled down the page, looking through buttons labelled Income Report and Demographic Report. There was nothing marked that looked remotely like a bulk import feature. How long does it normally take you to enter a row?
Five minutes. I usually get about 10 records an hour. There are 400 records, and my boss needs them done by the end of Sunday. That left five days. I still have reports to run while I do this. Thats why I need your help.
Okay, Jaroslaw said, cant you get someone to help you with this? Five people entering data would mean itd get done in a day.
Even if we had that many people to spare, there cant be more than one person entering data at a time. The system would crash.
Jaroslaw chuckled. Oh, come on. No web application forces a single user to enter data.
A year ago, we tried using two people at a time, Andrzej whispered. A whole dataset was corrupted. It set back the departments mandate by six months, and my last supervisor was fired because of it. My new supervisor wont tolerate any further delays.
A CRUD-like web interface, with no parallel data entry allowed, it seemed deliberately designed to make one persons life miserable & and that person was Andrzej.
Its a good thing I work in IT, Jaroslaw said. Because what you need is a tailor-made import script, and Im the one who can write it for you.
First, Jaroslaw installed Python on Andrzejs computer. If Jaroslaw were about to exploit the ministrys applications, he wanted to use a language he was familiar with. Next, he entered a few sample rows from the dataset Andrzej was burdened with. He logged every HTTP request the web application made, making a list of calls his script would need to make. Finally, he converted the Excel file the data came in to .csv so his script could consume it. It was tedious, but not as tedious as Andrzejs burden.
Let the script run overnight, Jaroslaw said. If anyone asks, tell them I did this on my own initiative. It should be done by morning.
The next morning, Andrzej himself went to see Jaroslaw in the IT department. He looked relieved. You just saved me four days of manual data entry.
You can use it on other datasets, Jaroslaw said. Just convert the files to .csv and pass in the filename as an argument from the command line. And make sure no one else is entering data while its running.
Thanks, Andrzej said. So, call you in six months?
Jaroslaw shook his head. This ones on me. I had no idea what torture they put you through until you showed 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!
|
Метки: Feature Articles |
Announcements: Bonus WTF: Karmic Cascade |
Our sponsors at Infragistics have a special treat over on their blog: an extra feature for today. It's a story of teamwork and "teamwork", and of course- disaster.
A worldwide leader in user experience, Infragistics helps developers build amazing applications. More than a million developers trust Infragistics for enterprise-ready user interface toolsets that deliver high-performance applications for Web, Windows and mobile applications. Their Indigo Studio is a design tool for rapid, interactive prototyping.
[Advertisement]
Scout is the best way to monitor your critical server infrastructure. With over 90 open source plugins, robust alerting, beautiful dashboards and a 5 minute install - Scout saves youvaluable engineering time. Try the server monitoring you'll M today.Your first 30 days are free on us. Learn more at Scout.
|
Метки: Announcements |