?

Log in

b0rg_tech's Journal
 
[Most Recent Entries] [Calendar View] [Friends]

Below are the 20 most recent journal entries recorded in b0rg_tech's LiveJournal:

[ << Previous 20 ]
Friday, July 17th, 2009
9:02 am
Caption contest: The pinball machine: Results
14:00 16.07.2009
Caption contest: The pinball machine: Results

It's been quite a while, but a winner in the caption contest has been selected and the prize finally reached its destination. (Mostly due to procrastination on my part. Don't blame the postal service.)

The winner is Scott from Australia with his entry

Only 5,000 more referrals until MULTIBALL

Even though it's kind of low-brow, it made me laugh spontaneously.

For his efforts, Scott wins a deluxe prize package consisting of

  • Exchange 2010 laptop skin
  • I'm a PC sticker and yoyo
  • Windows 7 stress ball
  • Assorted logo pens (Microsoft, Xbox 360, Microsoft Office)
  • TSA-approved Microsoft travel lock (so he can travel to our country should he be so inspired)
  • Miscellaneous historical items from the wayback drawer
    • Windows Me pen
    • Microsoft Bob lapel pin
    • Microsoft 20th anniversary kazoo
    • Temporary tattoos: Windows 2000, Windows 95, OLE (who knew they even had a logo!), Microsoft Visual Tools, MSN, Microsoft BackOffice.

Here's Scott's acceptance speech:

I'd like to thank all the letters that made the caption possible - the O, the N, the R, and especially the L - that little guy really pulled his weight. And thank you to the 1990's, for coming up with blogs, so that I could one day win a caption contest.

read more at The Old New Thing
9:02 am
Separating the metadata from the DIB pixels: Changing the raster operation
14:00 16.07.2009
Separating the metadata from the DIB pixels: Changing the raster operation

For a few days now, we've used the SetDIBitsToDevice function in conjunction with a precomputed BITMAPINFO to draw a DIB with an alternate color table without modifying the HBITMAP</a>.

The SetDIBitsToDevice function operates like a BitBlt with raster operation SRCCOPY. If you want another raster operation, you can use StretchDIBits, which has a final raster operation parameter. Despite its name, you don't have to stretch with StretchDIBits. Just pass a source and destination of equal size, and you've performed a NOP stretch, but you get the benefit of the raster operation.

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
 if (g_pvBits) {
    StretchDIBits(pps->hdc, 0, 0,
                      g_bmiGray.bmiHeader.biWidth,
                      g_bmiGray.bmiHeader.biHeight, 0, 0,
                      g_bmiGray.bmiHeader.biWidth,
                      g_bmiGray.bmiHeader.biHeight,
                      g_pvBits,
                     (BITMAPINFO*)&g_bmiGray, DIB_RGB_COLORS,
                      NOTSRCCOPY);
 }
}

I changed the call from SetDIBitsToDevice to StretchDIBits, setting the source and destination rectangles to the same size (so no actual stretching occurs), and specifying a raster operation of NOTSRCCOPY so the result on screen is a negative grayscale.

Some people may object to performing a stretch operation and requesting no stretching, but that's perfectly fine. At least in this case, GDI is not stupid. If you ask it to perform a stretch operation but pass parameters that don't do any stretching, it will optimize this to a non-stretching operation. You don't need to hand-optimize it. Instead of writing

if (cxSrc == cxDst && cySrc == cyDst) {
 BitBlt(hdc, xDst, yDst, cxDst, cyDst,
        hdcSrc, xSrc, ySrc, dwRop);
} else {
 StretchBlt(hdc, xDst, yDst, cxDst, cyDst,
            hdcSrc, xSrc, ySrc, cxSrc, cySrc, dwRop);
}

... just go straight to the StretchBlt:

StretchBlt(hdc, xDst, yDst, cxDst, cyDst,
           hdcSrc, xSrc, ySrc, cxSrc, cySrc, dwRop);

The StretchBlt function will convert the operation to a BitBlt if cxSrc == cxDst and cySrc == cyDst. You don't have to hand-optimize it. The GDI folks hand-optimized it for you.

(In fact, for a long time, the SetDIBitsToDevice function simply called StretchDIBits, saying that the input and output rectangles were the same size, and StretchDIBits detected the absence of stretching and used an optimized code path. Consequently, "optimizating" the code by calling SetDIBitsToDevice was actually a pessimization.) </pre>

Back to StretchDIBits. So far, we've been drawing the entire bitmap at the upper left corner of the destination device context. The last remaining feature of BitBlt is the ability to draw a rectangular chunk of a source bitmap at a destination location, so let's do that. We'll draw the bottom right corner of the bitmap in the bottom right corner of the window, with negative colors, and just to show we can, we'll also stretch it.

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
 if (g_pvBits) {
  RECT rc;
  GetClientRect(hwnd, &rc);
  int cxChunk = g_bmiGray.bmiHeader.biWidth / 2;
  int cyChunk = g_bmiGray.bmiHeader.biHeight / 2;
  StretchDIBits(pps->hdc, rc.right - cxChunk * 2,
                rc.bottom - cxChunk * 2,
                cxChunk * 2, cyChunk * 2,
                g_bmiGray.bmiHeader.biWidth - cxChunk,
                g_bmiGray.bmiHeader.biHeight - cyChunk,
                cxChunk, cyChunk,
                g_pvBits, (BITMAPINFO*)&g_bmiGray,
                DIB_RGB_COLORS, NOTSRCCOPY);
 }
}

So far, we've been operating on DIB pixels that are held inside a DIB section. But there's no requirement that the bits passed to StretchDIBits come from an actual DIB section. We'll look at the total disembodiment of DIBs next time, as well as looking at some unexpected consequences of all our game-playing.


read more at The Old New Thing
9:02 am
On gender differences in expectations of thinness, and the impact on guys who live in their parents'
14:00 15.07.2009
On gender differences in expectations of thinness, and the impact on guys who live in their parents' basement

At dinner a few years ago, one of my friends brought up a study (which I can't find, so who knows if it's actually true, but let's assume it's true for the sake of the story) that examined the effect of gender differences in expectations of thinness. One of the factors that the study considered was sexual orientation, and they found that homosexual men were, on average, thinner than their heterosexual brethren, and conversely that heterosexual women were thinner on average than their homosexual um, what's the female counterpart to "brethren"?

In other words, the conclusion of the study was that the pressure to be thin depends not so much on your own gender but rather on the gender of the person you're trying to attract. If you want to attract a man, you are more likely to be thin.

Like I said, whether what is now a thirdhand report of the study's conclusions is true isn't important to the story. It just served as a catalyst for this snippet of conversation that ensued.

Deborah: "I can see that. My friend Eleanor [not her real name] is a tall, beautiful Asian woman, and she says she won't date guys unless they have a bit of a pot belly."

Me: "You do realize that you just instilled hope into the hearts of thousands of guys who live in their parents' basement?"

Sorry guys, I didn't ask for Eleanor's number.


read more at The Old New Thing
9:02 am
Separating the metadata from the DIB pixels: Precalculating the BITMAPINFO
14:00 15.07.2009
Separating the metadata from the DIB pixels: Precalculating the BITMAPINFO

Last time, we saw that you can use the SetDIBitsToDevice function to draw a DIB with an alternate color table without having to modify the HBITMAP</a>. In that version of the function, we selected the HBITMAP into a device context in preparation for drawing from it, but in fact that step isn't necessary for drawing. It was merely necessary to get the original color table so we could build our grayscale color table. If you don't care what the original colors are, then you can skip that step. And even if you care what the old colors are, and if you assume that the colors don't change, then you only need to ask once.

To demonstrate, that all the work of building the BITMAPINFO structure could have been done ahead of time, let's use this alternate version of our program:

HBITMAP g_hbm;
struct BITMAPINFO256 {
 BITMAPINFOHEADER bmiHeader;
   RGBQUAD bmiColors[256];
} g_bmiGray;
void *g_pvBits;

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 // change path as appropriate
 g_hbm = (HBITMAP)LoadImage(g_hinst,
                      TEXT("C:\\Windows\\Gone Fishing.bmp"),
                      IMAGE_BITMAP, 0, 0,
                      LR_CREATEDIBSECTION | LR_LOADFROMFILE);</font>
 if (g_hbm) {
  BITMAP bm;
  if (GetObject(g_hbm, sizeof(bm), &bm) == sizeof(bm) &&
                bm.bmBits != NULL &&
                bm.bmPlanes * bm.bmBitsPixel <= 8) {
   ZeroMemory(&g_bmiGray, sizeof(g_bmiGray));
   HDC hdc = CreateCompatibleDC(NULL);
   if (hdc) {
    HBITMAP hbmPrev = SelectBitmap(hdc, g_hbm);
    UINT cColors = GetDIBColorTable(hdc, 0, 256, g_bmiGray.bmiColors);
    for (UINT iColor = 0; iColor < cColors; iColor++) {
     BYTE b = (BYTE)((30 * g_bmiGray.bmiColors[iColor].rgbRed +
                      59 * g_bmiGray.bmiColors[iColor].rgbGreen +
                      11 * g_bmiGray.bmiColors[iColor].rgbBlue) / 100);
     g_bmiGray.bmiColors[iColor].rgbRed   = b;
     g_bmiGray.bmiColors[iColor].rgbGreen = b;
     g_bmiGray.bmiColors[iColor].rgbBlue  = b;
    }
    g_bmiGray.bmiHeader.biSize        = sizeof(g_bmiGray.bmiHeader);
    g_bmiGray.bmiHeader.biWidth       = bm.bmWidth;
    g_bmiGray.bmiHeader.biHeight      = bm.bmHeight;
    g_bmiGray.bmiHeader.biPlanes      = bm.bmPlanes;
    g_bmiGray.bmiHeader.biBitCount    = bm.bmBitsPixel;
    g_bmiGray.bmiHeader.biCompression = BI_RGB;
    g_bmiGray.bmiHeader.biClrUsed     = cColors;
    g_pvBits                          = bm.bmBits;
    DeleteDC(hdc);
   }
 }
 return TRUE;
}

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
 if (pvBits) {
    SetDIBitsToDevice(pps->hdc, 0, 0,
                  bmiGray.bmiHeader.biWidth,
                  bmiGray.bmiHeader.biHeight, 0, 0,
                  0, bmiGray.bmiHeader.biHeight,
                  pvBits,
                  (BITMAPINFO*)&bmiGray, DIB_RGB_COLORS);
 }
}

I moved the blue code moved from PaintContent to OnCreate to demonstrate that pretty much all of the work we used to do in PaintContent could have been done ahead of time. The only other thing we had to do was save the pointer to the bits so we could pass them to SetDIBitsToDevice. (Of course, that pointer becomes invalid once the controlling HBITMAP is destroyed, so be careful! In practice, you probably would be better off calling GetObject immediately before drawing to protect against the case that somebody deleted the bitmap out from under you.)

Next time, we'll look at another operation we can perform when we have a BITMAPINFO and a collection of pixels.

(Note that there are issues with this technique which will be taken up on Friday.)


read more at The Old New Thing
9:02 am
What happens to your restaurant tip?
14:00 14.07.2009
What happens to your restaurant tip?

Some time ago, the Seattle Times ran an article on how your restaurant tip gets divided up among the staff. A week later, they ran an entire article of responses to the original article, some from customers, but many from restaurant staff (both cooks and servers). And, now on a roll, the next week's food section looked at the sociology of splitting the bill with a sidebar looking at how hard it is for different types of restaurants.


read more at The Old New Thing
9:02 am
The fun and profit of manipulating the DIB color table can be done without having to modify it
14:00 14.07.2009
The fun and profit of manipulating the DIB color table can be done without having to modify it

If I were Michael Kaplan, I'd have a more clever title like I'm not touching you! or Look but don't touch or maybe Looking at a DIB through BITMAPINFO-colored glasses.

We saw some time ago that you can manipulate the DIB color table to perform wholesale color remapping. But in fact you can do this even without modifying the DIB color table, which is a handy trick if you want to do color remapping but you don't want to change the bitmap itself. For example, the bitmap is not one that under your control (so you shouldn't be modifying it), or the bitmap might be in use on multiple threads (so modifying it will result in race conditions).

Let's demonstrate this technique by converting the "Gone Fishing" bitmap to grayscale, but doing so without actually modifying the bitmap. As always, we start with our scratch program and make the following changes:

HBITMAP g_hbm;
</font>

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
 // change path as appropriate
 g_hbm = (HBITMAP)LoadImage(g_hinst,
                      TEXT("C:\\Windows\\Gone Fishing.bmp"),
                      IMAGE_BITMAP, 0, 0,
                      LR_CREATEDIBSECTION | LR_LOADFROMFILE);
 return TRUE;
}

void
OnDestroy(HWND hwnd)
{
 if (g_hbm) DeleteObject(g_hbm);
 PostQuitMessage(0);
}

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
 if (g_hbm) {
  BITMAP bm;
  if (GetObject(g_hbm, sizeof(bm), &bm) == sizeof(bm) &&
                bm.bmBits != NULL &&
                bm.bmPlanes * bm.bmBitsPixel <= 8) {
   struct BITMAPINFO256 {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[256];
   } bmiGray;
   ZeroMemory(&bmiGray, sizeof(bmiGray));
   HDC hdc = CreateCompatibleDC(NULL);
   if (hdc) {
    HBITMAP hbmPrev = SelectBitmap(hdc, g_hbm);
    UINT cColors = GetDIBColorTable(hdc, 0, 256, bmiGray.bmiColors);
    for (UINT iColor = 0; iColor < cColors; iColor++) {
     BYTE b = (BYTE)((30 * bmiGray.bmiColors[iColor].rgbRed +
                      59 * bmiGray.bmiColors[iColor].rgbGreen +
                      11 * bmiGray.bmiColors[iColor].rgbBlue) / 100);
     bmiGray.bmiColors[iColor].rgbRed   = b;
     bmiGray.bmiColors[iColor].rgbGreen = b;
     bmiGray.bmiColors[iColor].rgbBlue  = b;
    }
    bmiGray.bmiHeader.biSize        = sizeof(bmiGray.bmiHeader);
    bmiGray.bmiHeader.biWidth       = bm.bmWidth;
    bmiGray.bmiHeader.biHeight      = bm.bmHeight;
    bmiGray.bmiHeader.biPlanes      = bm.bmPlanes;
    bmiGray.bmiHeader.biBitCount    = bm.bmBitsPixel;
    bmiGray.bmiHeader.biCompression = BI_RGB;
    bmiGray.bmiHeader.biClrUsed     = cColors;
    SetDIBitsToDevice(pps->hdc, 0, 0,
                      bmiGray.bmiHeader.biWidth,
                      bmiGray.bmiHeader.biHeight, 0, 0,
                      0, bmiGray.bmiHeader.biHeight,
                      bm.bmBits,
                     (BITMAPINFO*)&bmiGray, DIB_RGB_COLORS);

    BitBlt(pps->hdc, bm.bmWidth, 0, bm.bmWidth, bm.bmHeight,
           hdc, 0, 0, SRCCOPY);
    SelectBitmap(hdc, hbmPrev);
    DeleteDC(hdc);
   }
  }
 }
 return TRUE;
}

Things start off innocently enough, loading the bitmap into a DIB section for use during painting.

We do our work at paint time. First, we confirm that we indeed have a DIB section and that it is 8bbp or lower, because bitmaps at higher than 8bpp do not use color tables.

We then select the bitmap into a DC so we can call GetDIBColorTable to get its current color table. (This is the only step that requires the bitmap to be selected into a device context.) We then edit the color table to convert each color to its grayscale equivalent.

Finally, we fill in the BITMAPINFO structure with the description of the bitmap bits, and then we call SetDIBitsToDevice to send the pixels to the destination DC.

Just for good measure, we also BitBlt the original unmodified bitmap, to prove that the original bitmap is intact and unchanged.

This mini-program is really just a stepping stone to other things you can do with this technique of separating the metadata (the BITMAPINFO) from the pixels. We'll continue our investigations tomorrow.

(Before you all run out and use this technique everywhere you can imagine, wait for the remarks in Friday's installment.)


read more at The Old New Thing
9:02 am
Failed follow-up: The case of the dubious dental work
14:00 13.07.2009
Failed follow-up: The case of the dubious dental work

I've been waiting for an opportunity to do a follow-up on this story, but the trail appears to have gone cold. Here's the story as we know it so far:

In 2004, a woman (who had previously run unsuccessfully for a city council position) files a $6,370 claim for dental work against McDonald's, claiming that she injured her teeth biting into a cherry pie. Less than three months later, she files a $6,006 claim against McDonald's for dental work resulting from biting into a piece of bone in a cheeseburger patty. The insurance company investigates and determines that both claims were false: The dentist who allegedly performed the dental work (coincidentally: her employer, where she had access to billing documents) says he performed no dental work on her.

It so happens that the year before, the woman had pled guilty to first-degree theft in which she had purchased property with her employer's money as well as embezzled $27,000 in cash. (Coincidentally, in that case, she also worked in a dentist office as an office manager.)

My frustration is that I haven't found any coverage of what the result of the insurance fraud charges were. There are quite a number of cases involving the defendant over the past five years, but I think 07-1-06399-1 is the relevant one here, since the arraignment date matches the news article date to within a few weeks.

The hearing was continued to October 9, 2007, then delayed one more day, at which point the defendant pled guilty, and a statement to that effect was filed the next day. In November, a felony judgment and sentence was handed down (case 07-9-33438-1) consisting of $500 plus restitution. Jail time or home detention doesn't appear to be recorded into the case history, so I don't know the full extent of the sentence.


read more at The Old New Thing
9:02 am
Speculation on how a mishandled 13-character string can result in a blue screen
14:00 13.07.2009
Speculation on how a mishandled 13-character string can result in a blue screen

Commenter nolan reminisces about an old Windows 95 bug in the networking layer that crashed if a string was exactly 13 characters long. "So for the past 10 years or so, I've been wondering exactly how one could write code with that bug. Any bug that weird has to have a great story behind it."

I don't know what the story behind it is, but if after ten years you still can't imagine how such a bug could be possible, you don't have a very active imagination.

SomeFunction(char *hostname)
{
 char tmpbuffer[13]; // most host names are less than this size
 char *buffer;
 if (strlen(hostname) > sizeof(tmpbuffer)) {
   buffer = strdup(hostname);
   if (!buffer) return some error;
 } else {
   buffer = strcpy(tmpbuffer, hostname);
 }
 ... do stuff with buffer ...
 if (buffer != tmpbuffer) free(buffer);
}

If the host name is exactly 13 characters, then this code overflows the buffer by one character, corrupting the stack. A crash is hardly surprising at this point.


read more at The Old New Thing
Wednesday, July 15th, 2009
1:22 am
Vault 5.0 Beta 2
18:05 06.07.2009
Vault 5.0 Beta 2

Last week's beta 2 release means that the long-awaited version 5.0 of SourceGear Vault is coming soon.  This includes the regular edition of Vault as well as the "much more better" edition which has integrated bug-tracking.  (The latter product is actually called SourceGear Fortress and carries the version number 2.0, but its heart is still Vault.)

This release has numerous improvements, but for now I want to highlight one new feature which we call "VSS Handoff".  Basically, Handoff is a simpler and faster way of importing a SourceSafe database.  Instead of converting all your old history, Vault simply wraps your VSS database and makes it part of your Vault repository.  After that, all new checkins will go into the regular Vault database.  For history operations which need to access stuff that happened before the Handoff, the VSS database is seamlessly referenced.  The transition from SourceSafe can't get more painless than this.

Bottom line:  If you are still using SourceSafe, Vault 5 will remove your last excuse.

In fact, shortly after Vault 5 is released, I plan to go on a world tour.  If you are still clinging to SourceSafe, I will visit your office.  I will taunt you mercilessly and suggest an MRI to confirm that there is nothing between your ears but bone.  And I will drench you with my new Super Soaker Max Infusion Flash Flood Water Blaster

And I will be morally justified.  You've been given many opportunities to switch to any one of several dozen competent version control tools.  And yet, it's 2009 and you're still using SourceSafe.  Surely you didn't expect this to end well?

BTW, for more details about Vault 5, check out the recent blog entries by Jeremy or Paul:-)


read more at Eric.Weblog()
Tuesday, July 14th, 2009
4:43 pm
The Words You Wear

The Words You Wear

In business, words are like fashion. You try a word on because important people around you are saying it and getting results, but you may not actually know what it means.

Every group in the company has their own unique set of words and every group uses these words to verbally define who they are, what they know, and what they own. These words, these phrases, have value when everyone is in agreement as to what they mean, but used outside of your part of the organization, their value decreases, especially the closer you get to engineering.

The engineering burden is that when it comes to the product, we know how it works. Everyone else outside of engineering has vastly less working knowledge of the product; they don't need that depth for their job. The engineers know the intricate details of the system, the people who built it, and what it is capable of.

This is why, when fashionable words show up in our day, we grind our teeth. We're cynical because we don't trust fashionable words. They sound important, but over the years we've found they obfuscate our product's capabilities, they portray our development process as trivial, and they create productivity destroying expectations elsewhere in the building.

I'm guilty of using these words. I've written about them before, but they still stand out in my day. They hang in the air sounding like buzzing rather than communication.

This is not what you think you're saying, but this is what we're hearing:

  • Actionable -- A label applied to an idea or plan to make it sound achievable.
  • Alignment -- "I've yet to convince people that I am correct."
  • Best Practices -- A phrase used to convince you to do something different that assumes you don't actually want to know why it's a better approach.
  • Business Critical -- "You are fired if this fails." (See also: Mission Critical.)
  • Capacity -- How MBAs measure your productivity. I'm not kidding.
  • Cross-functional -- A hyphenated word everyone starts using when they decide to not fail alone.
  • Executive Summary -- A brief assessment given to executives. If this summary were shown to those who actually do the work, they would giggle.
  • Future Proofing -- Architecting a product so that it accounts for things that don't yet exist and can't be predicted.
  • Key Takeaways -- The three bullets of information you actually needed in that two-hour meeting.
  • Heads-up -- "You're screwed."
  • Initiative -- A new process designed by someone who doesn't understand the old process.
  • Lock-in -- Designing a product to be both indispensable to your customer while also screwing them.
  • Milestones -- Magically created dates that mean nothing, but give executives the impression that progress is being made.
  • Mission Critical -- "We are out of business if this fails." (See also: Business Critical.)
  • Offline -- A tactic to delay a decision until they can say no in private. "Let's take this offline."
  • Organic -- An adjective used to attempt to avoid actual planning. "We're using an organic process."
  • Paradigm -- A model you need in your head to explain something very complex to someone else.
  • Social Media -- Two words used to kill newspapers.
  • Sanity Check -- The meeting just before the meeting when you explain that things are going badly.
  • Silver Bullet -- The last ditch strategy to beat up another company who is currently kicking the shit out of you.
  • Socialization -- The process by which an idea that no one wants to do is forced on others.
  • Solution -- "I don't know what your product does."
  • Stretch Goal -- Engineering speak for "if it makes you feel better that we might get this done, that's cool, but there is no way this is happening."
  • Taking One for the Team -- Announcing that you're doing something exceptional after you've fucked up.
  • Thought Leadership -- The act of talking rather than doing.

Cutting edge fashion looks freakish to me. When I see a model walking down the runway wearing a black and white geometric monstrosity, I wonder, "How does anyone make money doing this?" These aren't the designs that end up in your local department stores. They've traveled through many different designers who have watered them down and made them palatable versions of the cutting edge.

New ideas, like fashion, have to start somewhere. When Jordan in Marketing lays down an energetic thirty minutes of incomprehensible marketing buzz-speak, I take a deep breath and attempt to hear his enthusiasm rather than his seemingly meaningless words. I remind myself of the time I walked to his office and threw down twenty minutes of arcane engineering reality and he gave me the benefit of the doubt. He clarified and we found a comfortable place to communicate.


read more at Rands In Repose
1:22 pm
Secured Debugging
13:00 14.07.2009
Secured Debugging

In 1968, when David Foskey finally had the opportunity to stand face-to-face with a Honeywell 8200, his expression was nothing short of awestruck. Technically, the 8200 didn’t have a face, it had a window that overlooked a room. And not just any room, but a room the size of a freakin' basketball court. In fact, Honeywell recommended that no less than six thousand square feet be dedicated to the 8200; any less and the sorters, collators, processors, storage devices, and computer operators would be a bit too cramped.

For David, his enthrallment wasn’t just about the sheer size – to reiterate, a freakin' basketball court – or the mainframe’s raw computer power – over 400,000 operations per second and 1,048,576 bytes1 of memory. It was also the fact that a Honeywell 82002 played a memorable role as war planning, Latvian army controlling, deviously plotting supercomputer in a recent Harry Palmer spy movie, Billion Dollar Brain. And not only that, but the Honeywell 8200 that David peered into was owned and operated by the Department of Defense.

Snapping Out of It

“Okay freshy,” the jarring voice belonging to David’s new boss bellowed, “this officially concludes our little tour.” His boss abruptly drew the curtain on the window overlooking the Honeywell 8200 and quietly added, “now don’t tell anyone I showed you the 8200…. unsecured.”

David wasn’t exactly sure what “unsecured” meant, but he was used to hearing it. As a recently hired software support engineer for the Department of Defense, he had to jump through all sorts of hoops just to get the “peon” clearance level. At that level, he was granted access to work at his desk and, after following proper sign-out procedures, use the restroom.

Just about everything else – even telling another peon your telephone extension number – was expressly forbidden. After all, if you knew enough phone extensions, you could better guess the number of people in the building and gauge its communication capacity. And in those trying cold war times, anyone could be enemy.

Day to Day

As a software support engineer, David’s day-to-day responsibilities weren’t all that different than what they’d be today. The Department of Defense had many large systems and programs, and like any large custom-built software, it was rife with bugs and “features”. When a program crashed or produced unexpected output, David would analyze the core dump, read the code, look at the data, and debug it until it worked.

At least, that was the “best case scenario”. For security reasons, software support engineers weren’t allowed to see actual live data. Nor did they have access to all of the program code. And core dumps… since they might contain sensitive data, they were scrubbed before ever being printed out. But aside from that, programmers could debug to their hearts’ content. Well, so as long as they did so with paper and pencil. And they shredded everything afterwards.

It took a little while, but David got used to it. He was among eight other software engineers, all of whom had similar peon security clearance. For his first several weeks, David worked at his desk and never had a chance to lay eyes on the majestic Honeywell 8200. That is, until he experienced the first development emergency.

A Serious Emergency

”Listen up, freshies,” David’s boss announced one morning, “we have a serious emergency with ALDV-IN-8862! This has to be addressed now, so drop everything and prepare to work on this.”

For the DoD, you’d think that a “serious emergency” would involve armed conflict, hostile state actions, or at the very least, a death or a maiming. But in this case, the issue was that ALDV-IN-8862 was crashing halfway through an automated inventory reconciliation. As boring as it sounded, fixing it would be incredibly exciting because it’d mean a trip to the Honeywell 8200 and the opportunity to work on some real, live programs.

A few hours later, David’s boss asked for few a volunteers to visit the 8200. To his surprise, David actually volunteered; a few others were volunteered by drawing the short straws. On the brisk walk to the 8200, David’s boss casually mentioned “by the time we get there, they should be done securing the room.”

With everything seemingly secure and secured, David wasn’t sure what meant and decided to wait to see for himself. When they arrived, David’s boss peeled back the curtain on the overlooking window. “They’re about done,” he said, “I’m sure they’ll let us in any minute now.”

David snuck a glance through the window and quickly realized what “secured” meant. The computer operators who were normally responsible for mounting and unmounting tapes were running around with handcarts and dollies, moving hard drives and other refrigerator-sized devices out of the room.

Fifteen minutes later, David and his team were permitted in the room and were told to go to work. The room was notably emptier, but none of that mattered: David would finally get the chance to sit down and debug a Honeywell 8200. As he sat at the console, the operators handed him and each of the other programmers an inch-thick stack of green-bar paper.

On the paper was printed a core dump; like other core dumps they received, there was a fair amount of sensitive information cut out. And, like other times, it was literally cut out: the operator had taken a pair of scissors and snipped wherever a sensitive buffer was printed.

Six hours later, the programmers came to a conclusion: there is no way the software is broken, it must be bad data coming from one of the I/O devices. They recommended that the hardware engineers start their diagnostics. Of course, for security reasons, the groups weren’t allowed to interact, so the room had to once again be secured for the hardware team.

After a few days and endless core dump printouts, David’s team was absolutely certain it was a hardware problem and the hardware team was absolutely certain it was a software problem. Fortunately for both, the problem went away… which meant it was probably a date problem, somewhere. As the days turned to weeks, weeks turned to months, and the pile of unsolved core dumps grew to be tens of thousands of pages, David came to realize something. The Honeywell 8200 wasn’t all that impressive anymore. He even felt relieved when he drew the long straw and wasn’t volunteered to go visit the mainframe.


[1] Technically, the 8200 (and the earlier 200) series mainframes used 6-bit “characters” instead of 8-bit bytes; so that’d be 6,291,456 usable bits, which would be the equivalent of 786,432 bytes. Kinda. Go read the manual if you want to learn more.

[2] Okay, while we’re doing footnotes, it was the technically the 200 that starred in Billion Dollar Brain; but they were basically the same thing, except that the 8200 was even more awesome.




Brought to you by the Non-WTF Job Board:





read more at The Daily WTF
1:22 pm
CodeSOD: Synchronization by Modal
13:00 13.07.2009
CodeSOD: Synchronization by Modal

Bryan D recently started a new contract with a large company that was developing a rich client application with all the latest buzzword technologies: WCF, WPF, BDD, etc. He was brought on to clean up the code and help figure out why the middle tier wasn’t so “middle”. It actually lived in the UI.

The middle tier seemed pretty straight forward: it was a collection of classes that were designed to be exposed as webservices and then called by the UI. Each service class implemented an abstract Interface that had a pretty straightforward set of method.

public interface IFindCustomerService
{
    ... snip ...

    IList<ICustomer> ExecuteFindCustomers(string surname);
}

Many of the implementation classes, however had modal dialog window contained within. Figuring that to be the cause of the tight coupling between layers, Bryan ripped out the dialogs from the middle tier and watched with horror as the application crashed and burned.

The problem was that all of the methods on the service were returning null. Digging further Bryan learned that, although the methods appeared synchronous, they used asynchronous calls... and modal dialogs to hold everything together.

public class FindCustomerService : IFindCustomerService
{
    private ProgressDialog progressDialog;

    ... snip ...

    public IList<ICustomer> ExecuteFindCustomers(string surname)
    {
        dataProxy.OnAsyncCompleted += OnFindCustomerCompleted;
        dataProxy.BeginFindCustomers(surname);
        progressDialog.ShowDialog();    // this call blocks ...
        
        return Customers;
    }

    private void OnFindCustomersCompleted(object sender, EventArgs e)
    {
        Customers = dataProxy.EndFindCustomers();
        progressDialog.Close();        // ... until this call closes the dialog
        dataProxy.OnAsyncCompleted -= OnFindCustomersCompleted;
    }
}

So, instead of the UI presenting the user with a "please wait..." dialog when a service was called, it relied on the service to display the dialog to the user. Needless to say, the code has since been substantially restructured...




Brought to you by the Non-WTF Job Board:





read more at The Daily WTF
1:22 pm
Sponsor Appreciation, Flushing Logic, Estmate Problems, and More
13:00 10.07.2009
Sponsor Appreciation, Flushing Logic, Estmate Problems, and More

Please show your support for The Daily WTF by checking out the companies that have been kind enough to sponsor us. And, in doing so, I’m sure you’ll find some pretty cool products and services built by like-minded developers and IT professionals.

 

Microsoft/web   Microsoft/web - We teamed up with Microsoft/web to answer a burning question: with the dizzying array of languages, frameworks, tools, and technologies, what do you think about web development? It's all finished! Just let us know if you'd like a copy!
 

Decent Diversions

Comic Reader Mobi   Comic Reader Mobi - I'm not a big comic book guy myself,but Comic Reader Mobi looks like a good way to start. Simply tap any of the text bubbles to magnify; the app automatically detects the size of the text bubble and magnifies that text alone. You can also magnify a small area without expanding the entire page. It is an extremely handy feature that allows you to see the whole page and read the text without zooming in and out.

Cool Tools

Splunk   Splunk - Search, navigate, alert and report on all your IT data in real time. Logs, configurations, messages, traps and alerts, script, code, metrics and more. If a machine can generate it -- Splunk can eat it.
Caretta   Caretta Software - makers of GUI Design Studio, a specialized software prototyping and User Interface design tool for Desktop, Mobile and Web Applications. Quick and Easy to use, with No Coding! Why not give the 30-day trial a shot?
TechSmith   TechSmith - the world’s leading provider of screen capture and recording software for individual and professional use. Personally, I can't live without SnagIt, and am quickly getting addicted to Camtasia. The Jing project is also pretty interesting for instant sharing.
SlickEdit   SlickEdit - makers of that very-impressive code editor and some pretty neat Eclipse and VisualStudio.NET tools and add-ins, some of which (Gadgets) are free. Check out this short video highlighting just one of SlickEdit's Visual Studio integration features.
Software Verification   Software Verification - software engineering tools for memory leak detection, code coverage, performance profiling, thread lock contention analysis and thread deadlock detection, flow tracing and application replay on the Windows Vista, 2003, XP, 2000 and NT platforms.
 

Great Components

Mindfusion   MindFusion - a great source for flow-charting and diagramming components for a variety of platforms including .NET, WPF, ActiveX and Swing
div elements   Divelements - developers of WinForms, WPF, and Silverlight controls. Easily integrate the Office 2007 Ribbon Interface, Dockable Windows, and several other interfaces. All products are available with a 30-day trial.
Atlassian   Atlassian - the folks behind JIRA (which, in turn inspired Manual JIRA) wanted to let you know that they're not a "follow the rules" software company who realizes that there is no single recipe for practicing agile development. They were once hungry for practical tips, so they thought they should share their agile story.
 

Solid Hosting

go grid   Go Grid - the first multi-tier, cloud computing platform that allows you to manage your cloud hosting infrastructure completely on demand through an intuitive, web interface. Get powerful dedicated resources on a cloud computing architecture that you can buy as you need instead of deploying servers and building complex load balanced networks. Get a $50 credit when signing up!
Cushy CMS   Cushy CMS - a hosted CMS built from the ground up with ease of use in mind. It's incredibly simple to use: no PHP or ASP required. If you can add CSS classes to HTML tags then you can implement CushyCMS. And best of all, it's free. Spend a few minutes and try it out!
SoftLayer   SoftLayer - serious hosting provider with datacenters in three cities (Dallas, Seattle, DC) that has plans designed to scale from a single, dedicated server to your own virtual data center (complete with racks and all)

And now, back to our regularly, completely off-topic scheduled program.

 

Maxim K spotted this waterless flushing urinal in Botany Bay National Park, Kurnell, NSW.

 

"If they're standing behind it," Rick Xaver writes, "they're doing it wrong."

 

"I spotted this near Dayton, OH," writes Roberto Sanchez, "Incidentally, the same typo appeared on the driver's door, but traffic was moving a little too quickly for me to be able to manage a second picture."

 

"I am part of the emergency response division here at work," N.A. wrote, "while planning for outbreaks, plagues, and bioterrorist attacks, we tested out some of the body bags. This one was terrible and, once the heat got to it, the bag started to stretch and give. Out of curiosity, I checked the tag and was surpried at the company's web address."

 

"I found this from my (exam-board approved) IT textbook while revising for an upcoming AS exam," Ross Masters, "Thankfully I had alternate notes for this section."

 

Carl Witthoft was excited: "Boy did I strike it rich with this investment account!"

 

"You can use the internet all day for free," David Kowis wrote, "or pay $2.95 for 15 minutes ($0.25 for each additional minute). What a deal!"

 

"Water flakes?" Sam wondered, "so.... the fish food is snow?"

 

"Assuming an eight character password," Bob notes, "they've reduced the key-space by 15 orders of magnitude. Brute-forcing my password would take a few hours on a quad-core."

 

"Apparently," writes Kevin, "there was just no way they could say 'closed'?"

 

"I tried to check hours of my apartment management office," Konstantin wrote, you can not argue with a logic like that."

 

"I got a phone call one afternoon, and this wa the called id information," Rhyss writes, "Needless to say, I decided not to pick it up."

 

"This is the sign outside of our wiring closet," BMP wrote, "it also doubles as the men’s bathroom."

 

"Caution!", Hae Yu warns, "Don't Smoking!"

 




Brought to you by the Non-WTF Job Board:





read more at The Daily WTF
1:22 pm
Slow, Difficult to Code, and Buggy
13:00 09.07.2009
Slow, Difficult to Code, and Buggy

Back in 2006, Steve worked as a developer at mid-sized financial services firm. Like many organizations with central IT operations, departments within Steve’s company had the option to “buy” application development services from IT, or use an outside vendor for their business software needs, provided that the vendor’s software met IT’s security and technical requirements.

Generally, getting IT’s approval was easy: the purchaser just needed to set up a meeting between the vendor and an “integration services” developer on Steve’s team, and then wait a few days for approval. But every now and then – such as when the HR department hired GlobalComp to build a web portal – things get a bit tricky.

The GlobalComp Review

After the GlobalComp sales rep gave his spiel about how wonderful and innovative their web portal technology was, Steve opened with a softball question. “Is it secure?”

“Of course it’s secure,” the rep said, “we at GlobalComp take security very seriously. In fact, our pages are delivered over Secure Socket Lay—”

“Wait a sec,” Steve, who had been playing around with the web portal during the presentation, cut him off. “I think I just broke into your admin console.”

Red-faced in embarrassment, the GlobalComp rep stumbled through an apology. It was clear that the developers had never anticipated someone typing ' OR ''=' in the password field, and Steve thought it’d be a good idea to do a code review to see what else they had missed. The rep hesitantly agreed and set up another meeting.

A Code Tour

Before Steve was permitted to even talk to a developer at GlobalComp, they had him sign a lengthy Non-Disclosure Agreement. As an added security measure, Steve could only review the code while the immaculately-dressed Dave, GlobalComp’s lead developer, watched him. “You’d be surprised,” Dave said in a serious tone, “there are a lot people who would steal our software ideas.”

Steve’s first port of call was login.asp. But it wasn’t the security snafus or the Microsoft FrontPage meta-tags that caught his eye. Not only were they using Access, but they had come up with a rather interesting way of caching huge amounts (400K+) of user-specific information. They used the ASP Session object.

<%
set conn=Server.CreateObject("ADODB.Connection")
conn.Provider="Microsoft.Jet.OLEDB.4.0"
conn.Open "c:\inetpub\wwwroot\database.mdb"
set rs = Server.CreateObject("ADODB.recordset")
rs.Open "SELECT * FROM Users WHERE Username = '" _
    & Username & "' AND Password = '" & Password & "'", conn
do until rs.EOF
session(“USERNAME”) = rs.Fields(“username”).value
session(“COMPANY”) = rs.Fields(“company”).value
session(“LOCATION”) = rs.Fields(“location”).value
session(“ADDRESS1”) = rs.Fields(“address1”).value
session(“ADDRESS2”) = rs.Fields(“address2”).value
session(“ADDRESS3”) = rs.Fields(“address3”).value
session(“ADDRESS4”) = rs.Fields(“address4”).value
session("HTML_BLOCK_1") = rs.Fields("html1").value
…180 columns later…
session(“YET_ANOTHER_FIELD”) = Rs.Fields(“yet_another_field”).value
Rs.MoveNext
loop
rs.close
conn.close
%>

“I can’t help but notice that this is in ASP,” Steve said to Dave. “I’m curious: why not .NET? Do you have a lot of ASP libraries that you’re reusing?”

“It’s 2006,” Dave snapped back, “not 2015. Everyone knows that .NET hasn’t really taken off yet. It’s slow, difficult to code, and very buggy. Maybe in a few years we’ll consider it, but until then, ASP is far more quicker and powerful.”

Steve quizzically raised an eyebrow, “all right. But can you elaborate on what you’re doing with the session over here?”

Dave smiled. “There are many clever things we developed to optimize the performance of the product. This is just one example.” v“For optimization,” Steve commented, “wouldn’t it have made sense to go with SQL Server? This portal is meant to be used by thousands of users across the country. Do you think Access is up to the job?”

“What’s wrong with Access?” Dave defensively questioned. “When I was at Accenture, we used it all the time?”

“Ummm,” Steve responded, “you’re telling me that Accenture routinely passes over databases like Oracle and SQL Server, and chooses instead to deploy their solutions using Microsoft Access?”

“Yep,” Dave nodded, “they certainly do!”

The Final Verdict

After spending a couple hours with Dave, Steve had learned more than enough to write his review report. “In light of the numerous performance, security, and data-integrity issues,” the executive summary read, “we do not approve GlobalComp’s web portal software for use in our production environments.”

It was the first time that that Steve, or anyone else in his department, had ever given a non-approval for vendor software. They felt relieved that they had successfully acted as the gatekeeper of bad software.

This was also the first time that Steve learned the consequence of rejecting a vendor. The HR department huffed, puffed, and angrily protested to the CTO. The CTO then overrode the rejection and GlobalComp’s software was purchased anyway. C’est la vie.

 


Slow, Difficult to Code, and Buggy was originally published in Alex's DevDisasters column in the May, 2009 issue of Visual Studio Magazine. VSM is a free magazine for software architects, senior developers and development managers that includes practical, proven, unbiased how-to articles readers can put to use immediately.




Brought to you by the Non-WTF Job Board:





read more at The Daily WTF
1:22 pm
Error'd: Planning for the Past
13:00 08.07.2009
Error'd: Planning for the Past

"I was very grateful for the letter Virgin sent out the day after they were here," Magnus Therning "That sure helped us planning."

 

"I discovered this super-secret, crazy-awesome, ultra-Beta Gmail Labs feature that somehow bends spacetime and lets you send an email to the future!" Danny V writes, "I was all excited until I received an email from my Past Self; it was the exact message that I had sent to my Future Self a few minutes prior."

 

"Weird," Matt write, "while I am an unregistered visitor, I'm pretty sure I'm not Internal Only. But I will say, I thought I had a higher Tookie value."

 

Jeremy Fry received this from his mortgage provider.

 

Chris Wade notes, "BricsCAD has a setting for every computer-related emotion."

 

"When there's something straaaange in your render app," Mike M sings, "who you gonna call? Pro-GRAM-mers!"

 

"Generate fewer messages?" Mark Christian ponders, "perhaps you could have started with that one?"

 

"The Planning Portal is the site we have to fill in to apply for planning permission," write Chris Wade, "Number Null, Null Road is becoming a bit overdeveloped."

 

"I'm new to Twitter," Denilson Figueiredo de Sá write, "and I don't know exactly what to expect from it. Apparently, the feeling is mutual."

 

"I needed to check the EULA for XP Professional Edition," Jenk write, "to say it's a bit vague is an understatement."

 




Brought to you by the Non-WTF Job Board:





read more at The Daily WTF
12:41 am
Iterator Blocks, Part Two: Why no ref or out parameters?
13:35 13.07.2009
Iterator Blocks, Part Two: Why no ref or out parameters?

A long and detailed discussion of how exactly we implement iterator blocks would take me quite a while, and would duplicate work that has been done well by others already. I encourage you to start with Raymond’s series, which is a pretty gentle introduction: part 1, part 2, part 3. If you want a more detailed look at how this particular sausage is made, Jon’s article is quite in-depth.

To make a long story short, we implement iterators by:

  • Spitting a class that implements the relevant interfaces.
  • Hoisting locals of the iterator block to become fields of the class.
  • Rewriting the iterator block as the “MoveNext” method of the class.
  • Tracking the point where the last yield happened in the MoveNext method, and branching to that point directly using a switched “goto” when MoveNext is called.
  • Moving the logic in “finally” blocks (or equivalents, like the auto-generated finally blocks associated with lock statements and using statements) into the Dispose method, to ensure that stuff gets cleaned up when the iteration is completed or abandoned.

This is not the only implementation strategy we could have pursued. As I said last time, we could have implemented full-blown continuations and built the whole thing out of them; any conceivable control flow can be built out of continuations. But getting continuations right requires a lot of support from the framework, and would be very expensive. We can get by with less, so we do.

Similarly, we could have built this out of “coroutine fibers”. A fiber is like a thread in that it has its own stack, but the code on the fiber itself decides when the fiber is done running. Again, this is a strategy – implement coroutines – that I mentioned last time which we rejected as too costly and difficult to get right in the CLR. Again, we can get by with less, so we do.

But this choice of a feasible, cost-effective implementation strategy then drives restrictions back into the design space; we have to lose some generality in order to make this strategy work.

The first thing that we lose is the ability to have iterator blocks be in methods which take ref or out parameters. In order to preserve the values of local variables and formal parameters across calls to MoveNext, we hoist the locals and parameters into fields of a compiler-generated class.

As I discussed earlier, the CLR designers had an implementation goal of being able to take advantage of the performance characteristics of the system stack. What happens when you store a reference in a field? The reference could be to something on the stack, but the field could live longer than the thing on the stack. The designers of the CLR were faced with three choices:

  • Build a system which is as fragile and horrid as unmanaged C code, a language in which accidentally storing a reference to something with too-short lifetime is a frequent source of awful crashing bugs and data corruptions.
  • Disallow (*) taking references to locals; any local taken as a reference must be hoisted to become a field on a garbage-collected reference type. Safe, but slow.
  • Disallow storing references in fields.

The CLR designers chose the third option. Which means that our choice of hoisting parameters to fields immediately runs into a problem; we have no safe way of storing references to other variables in a field. The reference could be to something on the stack, but the iterator could live longer than the variable that is on the stack. A confluence of implementation choices has now driven an unfortunate and seemingly arbitrary restriction into the design. We lose a bit of generality in order to gain simplicity of implementation and higher performance in common cases.

Now think about that decision from the perspective of the larger goal of the feature. Remember, the feature is not “make any possible method into an iterator block”. The feature is “make it easier to write code that enumerates the members of a collection”. An “out” or “ref” parameter exists solely to enable a method to mutate an outside variable and therefore pass back information to the caller when the method terminates.

Why would you want to do that in a method whose sole purpose is to produce the sequence of values stored in a collection? What would the meaning of mutations to the variable even be if the iterator block mutates the variable multiple times as the iterator is running? Normally that kind of thing is not visible (modulo goofy multithreading scenarios) until the method is done, but an iterator block returns control to its caller many times before its done.

This seems like a scenario which is uncommon, strange and hard to implement. And furthermore, there are ways to achieve mutation of outer variables during iteration without passing in a ref to a variable; you could pass in an Action delegate. Instead of this illegal program:

IEnumerable<int> Frob(out string s)
{
  yield return 1;
  s = "goodbye";
}
void Grob()
{
  string s = "hello";
  foreach(int i in Frob(out s)) …
}

you can always do the equivalent thing with this legal program:

IEnumerable<int> Frob(Action<string> setter)
{
  yield return 1;
  setter("goodbye");
}
void Grob()
{
  string s = "hello";
  foreach(int i in Frob(x=>{s=x;})) …
}

Since making the more general feature work given our implementation constraints is (1) hard or impossible, (2) clearly a corner case, not a mainline scenario, and (3) has a possible workaround, it’s a no-brainer to put a restriction on the design and disallow ref and out parameters.

Next time, why no yield in a finally block?

***********

(*) Or, weaker, make it allowed but unverifiable. That is pretty much the same thing from the compiler implementers perspective; we try to never generate unverifiable code unless it is specifically marked “unsafe”.


read more at Fabulous Adventures In Coding
Saturday, July 11th, 2009
5:43 pm
MS-DOS also allowed spaces in file names, although vanishingly few programs knew how to access them
14:00 09.07.2009
MS-DOS also allowed spaces in file names, although vanishingly few programs knew how to access them

A little-known fact about MS-DOS is that it allowed spaces in file names. Sure, you were limited to 8.3, but a file called "LOOK AT.ME" was legal in MS-DOS, and you could indeed create such a file. Good luck finding programs that didn't treat you as insane when you asked for that file, though.

Although the file system supported files with spaces, practically no programs supported them. Command line tools saw the space as the end of the file name. You couldn't quote the file name because no command line tool supported quotation marks to protect spaces. After all, if you believed that spaces were illegal characters in file names, you wouldn't write extra code to allow people to specify a file name with spaces in them!

The only program in common use that I remember supporting spaces in file names was GW-BASIC. If you were naive enough to create a file in GW-BASIC with a space in its name, you found yourself in a pretty nasty world of hurt once you escaped GW-BASIC back to the real world. The easiest way to delete such a file was to go back into GW-BASIC and delete it from there.


read more at The Old New Thing
5:43 pm
Up and down often substitute for compass directions, but you have to know when you've taken it too f
14:00 08.07.2009
Up and down often substitute for compass directions, but you have to know when you've taken it too far

The official curriculum for seventh grade students in the state of Washington includes Washington history and geography. My friend the seventh grade teacher typically includes as part of this curriculum an assignment wherein each student is assigned one of the state's counties on which to produce a brief report.

It is common to substitute up and down for north and south when speaking informally, but it is also important to know when you've taken the substitution too far. One student's report on Pierce County began with the following sentence:

Pierce County is at the bottom of Puget Sound.

read more at The Old New Thing
5:43 pm
Attack of the rogue feature: Oh no, where did my Explorer icon labels go?
14:00 08.07.2009
Attack of the rogue feature: Oh no, where did my Explorer icon labels go?

A customer reported that on Windows Vista, if you hold down the shift key and repeatedly click the View button in the command bar of an Explorer window, you will eventually reach a state where all the labels under the icons have disappeared! Where did they go, and how do I get them back?

Congratulations, you stumbled across a rogue feature.

One of the developers who worked on Windows XP decided to add a cute shortcut: Holding down the shift key when switching to Thumbnail mode will cause the labels to disappear. (At least, that was the intent of the rogue feature, but it so happens that as a side effect, the hold the shift key to remove labels shortcut also takes effect during certain other operations, because the shift key test was made in a shared worker function.)

Great, now that they're gone, how do you get them back? The way to restore item labels in Windows XP was to repeat the operation and hold the shift key when switching into Thumbnail mode. But wait, Windows Vista doesn't have an explicit Thumbnail mode any more. Since the hold the shift key to hide the labels feature was a rogue feature, nobody knew that the Thumbnail menu item was secretly being overloaded as an escape hatch!

Okay, here's how you get the labels back: Right-click in the background of the folder and select Customize This folder. From the customization dialog, change the template to Pictures and Videos, then OK. Now go back to the Explorer folder window and right-click in the background of the folder a second time, then go to the View submenu. (Alternatively, type Alt+V.) There will be a new Hide File Names option: Uncheck it. (If it's already unchecked, then check it, and then uncheck it again.) If you want, you can go back and uncustomize the folder so it has the All files template again.

The customer support people are probably relieved to learn that this rogue feature no longer exists in Windows 7.


read more at The Old New Thing
5:43 pm
More musings on the peculiar linguistic status of languages acquired in childhood
14:00 07.07.2009
More musings on the peculiar linguistic status of languages acquired in childhood

As I noted yesterday, languages which I acquired as a child occupy a different part of my brain from languages I acquired as an adult. If you speak to me in a childhood-acquired language, the information goes directly into my brain via some sort of low-level connection, and I barely even recognize what language it is you're speaking. On the other hand, if you speak to me in a language I acquired as an adult, it requires a conscious effort to process the information. (I don't have to translate what you speak before I can understand it, but the act of understanding requires a bit more effort.)

I got to experience this phenomenon with my Chinese-speaking nieces. If you spent time in their home, you'll hear three languages spoken. The adults speak to each other in their local Chinese dialect, they speak with the children in the regional Chinese dialect, and of course there's English. (The adults also speak Mandarin Chinese but you don't hear it often in the house.)

Since none of the Chinese dialects I know overlap with the dialects spoken by the children, my conversations with the nieces are in English. Over time, I started learning the regional dialect, and whenever possible, I would use it when speaking with the children. (I.e., when what I wanted to say had nonzero intersection with what I knew how to say.)

But even when I spoke with the nieces in Chinese, they always responded in English.

One day, I asked one of the nieces a simple question in Chinese, something like "Do you want to drink some water?" She looked at me and said, "大姑丈講中文!" I give her sentence in the original Chinese because it is ambiguous. I interpreted it to mean, "Uncle, speak Chinese!" And I was confused, because, well, I was speaking Chinese.

It was later explained to me that my niece meant the other interpretation of the sentence, which is "Uncle is speaking Chinese!" In other words, she was expressing surprise that I was speaking Chinese. I'd been doing this for months, but this was the first time she noticed.


read more at The Old New Thing
[ << Previous 20 ]
About LiveJournal.com