Forgot your password?
typodupeerror
The Almighty Buck Games

Integer Overflow Bug Leads To Diablo III Gold Duping 160

Posted by Soulskill
from the many-foreheads-were-slapped dept.
Nerval's Lobster writes "Online economies come with their own issues. Case in point is the Auction House for Diablo III, a massively multiplayer game in which players can pay for items in either in-game gold or real-world dollars. Thanks to a bug in the game's latest patch, players could generate massive amounts of virtual gold with little effort, which threatened to throw the in-game economy seriously out of whack. Diablo series publisher Blizzard took corrective steps, but the bug has already attracted a fair share of buzz on gaming and tech-news forums. 'We're still in the process of auditing Auction House and gold trade transactions,' read Blizzard's note on the Battle.net forums. 'We realize this is an inconvenience for many of our players, and we sincerely apologize for the interruption of the service. We hope to have everything back up as soon as possible.' Blizzard was unable to offer an ETA for when the Auction House would come back. 'We'll continue to provide updates in this thread as they become available.' Diablo's gold issue brings up (however tangentially) some broader issues with virtual currencies, namely the bugs and workarounds that can throw an entire micro-economy out of whack. But then again, 'real world' markets have their own software-related problems: witness Wall Street's periodic 'flash crashes' (caused, many believe, by the rise of ultra-high-speed computer trading)." It seems likely the gold duping was due to a simple integer overflow bug. A late change added to the patch allowed users to sell gold on the Real Money Auction House in stacks of 10 million rather than stacks of 1 million. On the RMAH, there exists both a cap ($250) and a floor ($0.25) for the value of auctions. With stacks of 1 million and a floor of $0.25, a seller could only enter 1 billion gold (1,000 stacks) while staying under the $250 cap. When the gold stack size increased, the value of gold dropped significantly. At $0.39 per 10 million, a user could enter values of up to 6.4 billion gold at a time. Unfortunately, the RMAH wasn't designed to handle gold numbers above 2^31, or 2,147,483,648 gold. Creating the auction wouldn't remove enough gold, but canceling it would return the full amount.
This discussion has been archived. No new comments can be posted.

Integer Overflow Bug Leads To Diablo III Gold Duping

Comments Filter:
  • Limit checking (Score:5, Insightful)

    by girlintraining (1395911) on Wednesday May 08, 2013 @06:05PM (#43669547)

    And this class, is why we use explicit type casting and do sanity checks (checking limits) prior to processing. Now, if you'll look on your screens, you'll see another example of this. Here is a failed mission to Mars, caused because the wrong unit of measurement was put into the computer, a problem caused by the lack of the human brain's compiler to make use of any data type except 'variant' and 'object'... So, what have we learned?

    • That Ada prevails in all things?
      • Re: (Score:2, Insightful)

        by solidraven (1633185)
        Yep, Ada and the closely related VHDL are both a success story for a very good reason. Yet a lot of people seem to hate both due to how strictly they enforce their rules. But Ada always wins when reliability is a must.
      • by djlowe (41723) *
        Hi,

        That Ada prevails in all things?

        Well, I suspect that you're being snarky, but you have a point. Sort of, in the sense that "If we can't trust the programmers to write good code, always, then we can force them to use a language that at least forestalls the worst of their blunders."

        The real issue, of course, is NOT technical, at the programmer/developer level, for such a project. It's administrative, in the sense that, regardless of the chosen programming language, bad code that would allow this should NE

        • That's basically it, yes. If I had my radical hat on, I might even go so far as to say this is yet more evidence that C (or, in this case C++) is not suitable for non-high-performance application-layer programming... but I dunno, it's getting pretty late.
    • Re: (Score:2, Funny)

      by Anonymous Coward

      tat puters' is hard.

    • Re: (Score:2, Interesting)

      by Anonymous Coward

      So, what have we learned?

      That C is scaryscary and we're too lazy to do type checking, so we'll keep using the trendy, make-money-now languages, treating this as an outlier that won't happen to us, since we're so smart?

    • by TubeSteak (669689) on Wednesday May 08, 2013 @06:21PM (#43669729) Journal

      So, what have we learned?

      That 2^31 gold ought to be enough for anybody?

      • Re: (Score:3, Informative)

        That 2^31 gold ought to be enough for anybody?

        Gryfindor loses 50 points.

      • by Culture20 (968837)
        Yes. I hate games where gold is weightless. How does someone carry around that much gold?
    • by Anonymous Coward

      So, what have we learned?

      That next time when we launch something headed to Mars, we should duct tape you to it, with a sign that reads:

      if (ego > INT_MAX)
      airsupply = INT_MAX+1; // Just to make sure there's enough to make it back

      Let us know what Mars is like, and take some pretty pictures while there. Try not to upset the rovers too much, once their clock overflows they get quite moody.

    • Re:Limit checking (Score:5, Insightful)

      by Austerity Empowers (669817) on Wednesday May 08, 2013 @07:07PM (#43670205)

      So, what have we learned?

      Gamers gonna game, and real money auction houses are a bad idea...

      • [...] real money auction houses are a bad idea...

        Some of us knew this a long, long time ago. I have to admit, I'm feeling terribly smug right now.

    • by Jesus_666 (702802) on Wednesday May 08, 2013 @07:56PM (#43670639)

      So, what have we learned?

      To always use 64-bit numbers, duh.

    • Re:Limit checking (Score:4, Informative)

      by broken_chaos (1188549) on Wednesday May 08, 2013 @11:02PM (#43671685)

      One bug, which I reported about WoW two years ago, shows an integer underflow on a character statistics page under certain conditions. It still hasn't been fixed. Minor? Yeah, but give a bit of a pattern.

    • by DiEx-15 (959602)

      ... So, what have we learned?

      That Blizzard did a piss poor job in bug checking? That they didn't do enough QA assurance and brought this problem onto itself?

      Nah... It ain't that. It is the PLAYERS that did all the wrongdoing!

  • by Revek (133289) on Wednesday May 08, 2013 @06:19PM (#43669711) Homepage

    I remember the day when you could strip the gear off anyone playing a multiplayer game with the trainer. I usually used it on jerks who came in collecting ears. If someone came in you could quickly look at their inventory and if they had several ears you could clear out their inventory and gear. They wouldn't know visually until they tried to hit you at which time they would be completely naked. It was really fun when they re-spawned and came back to loot their body and you started dropping some of the ears they collected on the ground.

  • by Anonymous Coward

    What a beginner's mistake. I wonder what the rationale was for not using a 64-bit integer; "It's wasteful!"

    • Re: (Score:2, Insightful)

      by Anonymous Coward

      It's simple really...

      They elected to buy 2 newbie programmers for the price of 1 experienced one! And the new guys will work all night! It's win-win!

  • How quaint. I can't remember the last time I saw one of those (except where deliberately created for loop counters etc.).
    • by gl4ss (559668)

      How quaint. I can't remember the last time I saw one of those (except where deliberately created for loop counters etc.).

      well, this serves more as an example of how fucked up the game economics already were in D3, because the problem came up from having to increase stack sizing from 1 to 10 million.

      I mean, wtf, is diablo 3 set in zimbabwe?

      • by imsabbel (611519)

        Its a game where money is not really "destroyed", but created everytime a monster is killed. OF COURSE it has inflation.

        • There is one way it is destroyed, death and tax on broken equipment. But this is so low, it effectively isn't.
  • What could Blizzard do? Performing a roll-back would wipe all progress obtained by players for the patch day, which would result in a lot of bad PR. But leaving the economy as-is will devalue all items in the game (and Diablo III is all about getting items).

    In the end, Blizzard has not done a roll-back, but instead banned anyone who duped, and refunded anyone who spent real money. The bug was temporarily fixed by reverting the patch note which caused the entire mess.

    Why would rolling back 1 day of gameplay be such a disastrous event?

    • Re:Bad PR? (Score:5, Insightful)

      by gl4ss (559668) on Wednesday May 08, 2013 @07:05PM (#43670183) Homepage Journal

      What could Blizzard do? Performing a roll-back would wipe all progress obtained by players for the patch day, which would result in a lot of bad PR. But leaving the economy as-is will devalue all items in the game (and Diablo III is all about getting items).

      In the end, Blizzard has not done a roll-back, but instead banned anyone who duped, and refunded anyone who spent real money. The bug was temporarily fixed by reverting the patch note which caused the entire mess.

      Why would rolling back 1 day of gameplay be such a disastrous event?

      why? because people spent actual money and made actual money?

    • Rolling back millions of players most of whom haven't even heard of the dupe? Or ban the handful of people who were involved in the dupe and revert any transaction they had with other people? Seems like an easy choice.
    • by Hentes (2461350)

      IIs that even possible? Are they keeping backups of the game state for every single day?

      • by seebs (15766)

        So far as I know, most online games have a transaction store, so they can roll back to any second they want.

    • by Lakitu (136170)

      uh, are you kidding?

      It's because people paid for a game, were force-fed always-online-even-for-single-player, and then may have spent hours playing on the day in question.

      How is that not disastrous?

    • Why would rolling back 1 day of gameplay be such a disastrous event?

      So you wouldn't mind paying $250 for an item, and then lose the item due to Blizzard rolling back?

  • Confused (Score:4, Insightful)

    by Murdoch5 (1563847) on Wednesday May 08, 2013 @07:03PM (#43670163)
    Why are they using a signed int for the gold amount? If the lowest gold amount is 0 then you should use an unsigned int which would double the possible value. Although in either case a simple if statement could of prevented this entire issue.
    • Lazy programers with no foresight.

      It is same reason people "assumed" a 32-bit IP address would be enough instead of just using 64-bit from the beginning.

      There is never time to do it right, but there is always time to do it over!

      • by Murdoch5 (1563847)
        well I can see the logic for IPV4 when it came out, I mean at the time 4 billion IP's was unthinkable. But as for lazy programming, I completely agree.
      • by AmiMoJo (196126) *

        I think to be fair if most of us were developing a military network in the 60s/70s we might think that 16.7 million addresses is enough. The real blunder was assigning millions and millions to companies and institutions that didn't need them, but again when there is no management structure and no money to set one up and it's a research project anyway...

        The biggest failure has been our inability to do anything about it. My ISP hasn't even heard of IPv6 and they are one of the largest.

        • by tlhIngan (30335)

          I think to be fair if most of us were developing a military network in the 60s/70s we might think that 16.7 million addresses is enough. The real blunder was assigning millions and millions to companies and institutions that didn't need them, but again when there is no management structure and no money to set one up and it's a research project anyway...

          The biggest failure has been our inability to do anything about it. My ISP hasn't even heard of IPv6 and they are one of the largest.

          Well, back then, we used

      • by Teckla (630646)

        Lazy programers with no foresight.

        Yes, it couldn't possibly have been the result of time pressure the developer was under...

    • by Shennan (7821)

      In general, it's a good idea to used signed ints whenever possible.

      Here are the only 2 reasons I see for unsigned ints:
      - matching hardware or wire spec
      - You need the extra range afforded, and don't need negative numbers.

      And the reasons for using signed integers otherwise:
      - It prevents other overflow and comparison problems. Ie, fixes other dumb coding issues like "if (my_gold - your_gold > 0)" becomes a bug when the gold types are unsigned.

      • by Murdoch5 (1563847)
        I completely disagree, unless you have a reason to support numbers less then 0 you should always go with unsigned. Also depending on the language unsigned int's are safer and have standardized behaviour imposed, for instance in C an unsigned int must behave in a very predictable manor well a signed int doesn't have the same restrictions.
        • Re:Confused (Score:5, Informative)

          by Anonymous Coward on Wednesday May 08, 2013 @07:48PM (#43670569)

          You couldn't be more wrong. Signed ints are usually the best way to go in C/C++.

          >in C an unsigned int must behave in a very predictable manor

          "unsigned int x = -3;" generates no compile errors or warnings.

          If you don't believe me, listen to the creator of C++ (Bjarne Stroustrup):

          "The unsigned integer types are ideal for uses that treat storage as a bit array. Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea. Attempts to ensure that some values are positive by declaring variables unsigned will typically be defeated by the implicit conversion rules."

          • by c++0xFF (1758032)

            Too bad you're an AC. This post is spot-on.

            Mixing signed and unsigned values can result in unexpected behavior. Trust me, don't mix them if you can avoid it.

            You get a bit of a larger upper range (2x more, not all that much really), while introducing a whole new set of problems at the bottom end (what if you underfow?).

            Avoid unsigned unless there's a good reason to use it. There are definitely good reasons -- it's a pain that Java got rid of unsigned! -- but avoid in general. Don't just use unsigned if y

          • Re:Confused (Score:5, Interesting)

            by flargleblarg (685368) on Wednesday May 08, 2013 @09:42PM (#43671337)

            You couldn't be more wrong. Signed ints are usually the best way to go in C/C++.

            Actually, he's not wrong at all. He said signed integers don't behave in a very predictable manner, and he's right. Signed integers have undefined (actually, to be more precise, implementation-defined) behavior for mod and div of negative values. You cannot be sure whether -4 / 3 is -1 or -2, without knowing how your compiler implements it. Some round toward zero, others toward negative infinity. Recent drafts of C++ are trying to fix this.

          • by Old Wolf (56093)

            "unsigned int x = -3;" generates no compile errors or warnings.

            This supports the point of the poster you were referring to. The code is correct, predictable, and generates no warnings.

            If you don't believe me, listen to the creator of C++

            C and C++ are different languages. The implicit conversion rules and the promotion rules are different in C++ to C. In C, unsigned types always promote to unsigned types. But in C++, unsigned types may promote to signed ones, if the value fits in the signed range.

          • by AmiMoJo (196126) *

            "unsigned int x = -3;" generates no compile errors or warnings.

            Yes, but it always generates the same binary value, the same number. It is 100% consistent, where as, for example, the result of dividing a negative signed int is compiler dependent.

      • by Old Wolf (56093)

        In general, it's a good idea to used signed ints whenever possible.

        Says who?

        In C, signed ints have a whole lot of problems associated with representation and overflow. But unsigned ints have well-defined behaviour in every circumstance. They wrap around in case of overflow or an out-of-range assignment. You can safely test, set and reset individual bits.

        With signed ints, you can raise a signal (triggering a signal handler, or aborting the program if there is no handler) if there is overflow or underflow. Using '^', '|' or '&' on signed values can trap due to creating

    • by Hentes (2461350)

      The summary is wrong, they used an unsigned int and the overflow occured at 2^32.

      • by Murdoch5 (1563847)
        Okay fair enough, however this would of still worked
        if( gold_max 2^32 ){ /* DO STUFF */ } else { /* DO OTHER STUFF */ }. It really is a very simple check.
    • Re:Confused (Score:5, Insightful)

      by c++0xFF (1758032) on Wednesday May 08, 2013 @07:52PM (#43670611)

      Integer underflow. Imagine a situation where a player has 100 gold and a bug in the code subtracts 101 gold for whatever reason. If you use a 32-bit unsigned integer, that player now has 4,294,967,295 gold. A 64-bit unsigned is even worse, of course.

      A simple if statement would catch this as well, right? But think of how often you do addition and subtraction (and everything else) throughout your code! Do you put an if around each one? Can you handle the error situation in each case? How do you ensure that you found every addition and subtraction, including future changes?

      A better solution is to make a Money class with well-defined operations, and throw an exception if you try to exceed the boundaries. Sounds easy ... but it has to be flexible enough to handle all situations (the class has to be used for all intermediate values -- it's no good to resort to an int, where problems might come back) while still being robust. ("I know, I'll use a class!" ... now you have two problems. "I know, I'll use exceptions!" ... now you have three.)

      This is not an easy problem to solve for non-trivial software, which is why bugs like this come up periodically.

      • by Murdoch5 (1563847)
        Fair enough! I didn't really consider the under flow case.
      • A simple if statement would catch this as well, right? But think of how often you do addition and subtraction (and everything else) throughout your code! Do you put an if around each one?

        I use a program to automatically put a try-catch-finally statement around every line of code including my try-catch statements. When I'm contracting, no one can read my code so they'll have to hire me to fix or update anything. When I'm a permanent employee, then the number of lines of code I generate grows significantly so the bosses think I'm a great and productive programmer. Profit!

      • Re:Confused (Score:4, Funny)

        by ShakaUVM (157947) on Thursday May 09, 2013 @04:53AM (#43672935) Homepage Journal

        Baldur's Gate stored various things as unsigned shorts, IIRC.

        There was a monster called the nishruu that would drain charges off your magic items. So after one combat, I found I now had a charged magic item with 32,000-ish charges on it.

        Since the gold value of magic items was proportional to the number of charges remaining, I sold it and never needed to worry about money again in the game.

      • I mainly program in Java, so my natural reaction was using BigInteger. [oracle.com] I'm pretty sure someone already made something like that for C++ too [stackoverflow.com]

  • Luls. (Score:4, Informative)

    by neminem (561346) <{neminem} {at} {gmail.com}> on Wednesday May 08, 2013 @07:15PM (#43670283) Homepage

    Basically this exact thing happened to Kingdom of Loathing... like 9 years ago... at a time when that game was basically still in beta, and was basically the work of two people, neither of whom would actually have called themselves "programmers" at the time... as opposed to the work of a giant team of professionals releasing a triple-A title... that is mega hilarious.

    (Black Sunday: August 8th, 2004, someone discovers that using a particular item, "meat vortex", which under normal circumstances subtracts a handful of the game's currency from your inventory, if you had 0 meat would instead wrap around and give you max meat minus a few, because the game was storing meat in an unsigned int. Fun times!)

    • by Rhys (96510)

      Those who froget the past are doomed to repeat it: Asheron's call had a similar issue back in 99-2000 era.

      • Normally I don't point out spelling errors, but yours is two funny. froget. Can I haz your Froget Legs? Some reason you made me think of EQ, who did the spell them? Froglets? I forget.
    • Re:Luls. (Score:4, Interesting)

      by ais523 (1172701) <ais523(524\)(525)x)@bham.ac.uk> on Thursday May 09, 2013 @04:57AM (#43672947)
      What's probably more interesting was their fix for the problem. Instead of trying to do any sort of rollback (although they did find people with impossibly high currency amounts and reduce them to saner values), they put a large amount of very expensive trophy items for sale which didn't do anything useful, in the hope that people would put their newfound wealth to an amusing trivial cause.
  • by BenJeremy (181303) on Wednesday May 08, 2013 @07:42PM (#43670523)

    I discovered a bug with the gold in Pirates! while watching somebody play on my roommate's Mac (we were stationed in Okinawa on Camp Kinser)... he went into port with damage, and while he did not have enough money, it offered to repair his damaged ships for more money than he had.

    Needless to say, the underflow was done to a UINT16 used to track gold (in 10-gold increments), so you'd end up with around 655350 gold after the transaction. That kept your crews happy, and let you buy lots of things.

    I also enjoyed the mental image of 1200 pirates hanging off a sloop after I sold off my fleet.

    We put in ungodly hours into that game.

  • by Anonymous Coward

    Diablo III is not an MMO. You are capped at what, 4 people in a game at once? A massively multiplayer online game allows a lot more than that.

  • by Anonymous Coward

    If they had used actual bitcoins instead of simulated fiat gold, their simulated economy wouldn't be having simulated inflation.

  • by The_Revelation (688580) on Wednesday May 08, 2013 @08:40PM (#43670955) Homepage
    ... is that Blizzard have often touted the very reason the game carries an always connected requirement is so that they can ensure the economy works correctly and to limit exploits through 3rd party applications. It seems rather clear, however, that the 1st party application is the only one you need to exploit the system. And, as usual, the question must be asked "does this make the game more fun?".

    As I see it, this has been Blizzard's only metric for success with Diablo 3, not profitability, as we will see later. They claimed that by breaking the existing mould, they were providing a 'more fun' experience. So, the question then becomes, does the AH or RMAH make the game more fun? Interestingly, Blizzard don't appear to be packaging these components with the Playstation 3 edition. Is that because it turns out all of the changes to Diablo 3 were 'not fun', or is it because Playstation 3 users don't deserve 'as much fun', or is playing with a controller rather than a mouse and keyboard 'so much more fun' that their combination with the AH/RMAH turned into a 'fun overload' that had to be dialled back in order not to blow our puny little minds?

    It also asks another important question about the business model. Is always-on net requirements 'more fun', particularly when they don't add anything to play beyond what a direct/lan connection might provide. When you try to enumerate the pros/cons, you see something like:
    Pros: Everyone uses the latest version all the time if they want to play
    Everyone playing has to have a working key

    Cons: Internet Connection must be working to play
    Need a server farm in every retail country so that paying customers can play (well, they don't even now, and charge people in those countries more money per copy so that they can have a game that they don't have local server access play)
    Servers have to be working in order to play
    User account has to be working in order to play
    If we rolled out a dodgy patch, everyone will be broken at once
    We have to know the product life-cycle prior to release in order to cost all of our servers' TCO correctly.
    We have to keep talking to everyone to make sure the game is working to their expectations and forever hear about shortcomings

    Economically, I don't understand how game companies are able to turn a profit on a title with those kinds of restrictions and ongoing costs. As a small example, lets say one of your servers can host 200 users at a time, but the server cost $20k, thats $100 per concurrent user before you turn the thing on. Maybe it can host 2000 users at a time, sure but thats still $10 per concurrent user before you turn it on or pay any support personnel, or for space on the floor. Surely, over the life of your product, you would be operating a negative margin without some sort of subscription service. I have read other places that, while you can't place a cost on piracy, you can place a cost and a metric on product returns. Diablo 3 is one of the few games I've ever returned, it was unusable for the first week, and is still, in most parts of the world (outside the US/EU/ASIA) mostly unplayable. Despite that, the parts of the game that were modified to provide 'more fun' actually provided, for me, a fan of the Diablo franchise, 'a lot less fun'.

    So, to say that another way, by insisting on Always-Connected, Blizzard not only have to pay a bunch of additional ongoing expenses to run (apparently) necessary infrastructure, its also alienating their core user-base which must be very costly to their bottom line. I don't understand how this course of action renders any kind of net commercial advantage.
    • Economically, I don't understand how game companies are able to turn a profit on a title with those kinds of restrictions and ongoing costs. As a small example, lets say one of your servers can host 200 users at a time, but the server cost $20k, thats $100 per concurrent user before you turn the thing on. Maybe it can host 2000 users at a time, sure but thats still $10 per concurrent user before you turn it on or pay any support personnel, or for space on the floor. Surely, over the life of your product, you would be operating a negative margin without some sort of subscription service.

      They do it by selling hundreds of millions of copies worldwide and assume that not every user will log in simultaneously 24/7, and that some users will abandon the game shortly after purchase. Oversubscription leads to higher profit margins at the cost of release day meltdowns.

  • by Anonymous Coward

    We duped our gold the way God intended: by pulling an item out of our belt as we picked it up.

    Kids these days....

    • by Culture20 (968837)
      Yeah, well; nothing beats "examine butterfly; sell butterfly".
      It works because the examine butterfly implicitly takes the butterfly out of the goblet for the rest of the command string (so that the examine functions), but you can sell it in the same command string. The butterfly's value doubles every time it escapes from the display case, but you have to avoid the overflow because they used a signed int for zorkmids.
  • by Eightbitgnosis (1571875) on Wednesday May 08, 2013 @08:58PM (#43671069) Homepage
    Diablo 3 was a bad game that had a garbage economy before this event, and it's still a bad game that has a garbage economy after
    • Re: (Score:1, Insightful)

      by Anonymous Coward

      You couldn't handle Inferno huh?

  • you should check your H1-B's more carefully.
  • In the very old game, Mordor, you could create a dummy character and trade negative 1 million gold to the. They get negative, you get positive. Then you delete them. This is just barely one step past that (and at least 15 years past that, lol)
  • I'm not sure how this is a big deal?

    After all, pretty soon the only other person still playing is going to know what's going on.

  • There's only one answer to every problem, that's create more money! There wasn't a bug in the servers, Blizzard just consulted with the FED.

  • by SD-Arcadia (1146999) on Thursday May 09, 2013 @08:27AM (#43673677) Homepage
    The "game" part is just packaging around the pointless grind and universal trade at the auction house. No one does anything for fun after the first time they get through the quests. The game mechanics and itemization are utterly boring and without character. There is not a single aspect of skill involved either. You spend most of your time staring at your skill cooldowns and life-mana pool because the terrain and monsters don't really matter. It's rote repetition and an utter waste of time. Worst purchase I ever made. I'd much MUCH rather have a Diablo 2 expansion with new content and a higher resolution support than this PoS.
  • 2^31 = 2,147,483,648 = $21,474,836.48 when counted in pennies. I once worked for a software company where a call came into the support desk from one of our customers accounting departments. Once their sales reached a certain point, their books were suddenly off by exactly that amount (minus 1 cent). While everybody else was scratching their heads about the missing 21 million dollars, I recognized the number, and knew exactly what the problem was. They were storing the number as a 32 bit signed int wh

The trouble with opportunity is that it always comes disguised as hard work. -- Herbert V. Prochnow

Working...