And I’m so sad, like a good book

Recently, I’ve been reading Grimm Fairy Tales to get to sleep. Here’s a new story for you in their style. Like all fairy tales, half is new and two-thirds is borrowed.

“Pasalo and Shala”

There was a handsome and hardworking farm boy. Because his hair was bright as gold, he was called Pasalo (“gold-headed boy”). Pasalo woke one morning to hear beautiful singing. As he went to the road, he saw a pretty girl singing while she carried pails of milk to town. Pasalo went to her. Her name was Shala (“nightingale”), and her pails were heavy, and she sang to lighten the load. Pasalo carried her pails for her. After walking a mile or two, they fell in love, and Pasalo promised to marry Shala.

Whereupon an enchantress swooped down upon them, bearing a gilded bird cage. She had heard Shala singing too. The enchantress raised her dark cloak and turned Shala into a nightingale; and the enchantress stole the nightingale into her cage. The enchantress cursed Pasalo, and he was frozen as stone, and could not move. The enchantress flew away, and Pasalo collapsed, free of the curse.

“I will bring my love back,” thought Pasalo. He got his pitchfork and went to the great dark castle on the hill where the enchantress lived. Through the top window he could hear the nightingale singing in the gilded cage. A great gargoyle perched on top of the castle. Pasalo attacked it with the pitchfork. The gargoyle laughed, snapped the pitchfork easily between his teeth, and pressed Pasalo to the ground with one claw. The gargoyle said, “You may not enter the castle unless you show me the most beautiful thing in the world.” He let Pasalo up. Sad and beaten, Pasalo walked down the hill.

As Pasalo returned to his farm, he spied a wise old fox, fainted from pain and hunger. “The enchantress has injured me,” said the fox. “Heal me, and I will help you.” Pasalo fed the fox chicken and let him heal in his bed. When the fox was well, the fox bowed and said, “How may your love be returned?”

Pasalo said, “The gargoyle said, I may not enter the castle unless I show it the most beautiful thing in the world.”

“Ah,” said the fox. “It has never been done before, but it may be done yet. You must first find the place where water turns to air. Then, you must pass the unpassable door. There, you will find the most beautiful thing in the world.” Pasalo asked the fox what he meant, but the fox sprang out the window and ran away.

For many years, Pasalo searched for a place where water turns to air. He searched many countries, many towns and many forests, but he could find no such place. He endured many misfortunes, and his hair turned from gold to silver and then to gold again with the effort. At last, when he could go no further, he collapsed by the top of a waterfall. “I shall never find the place where the water turns to air,” said Pasalo.

Pasalo looked over the cliff, and found that he had walked all the way to the edge of the earth. Pasalo watched as the river drifted off the earth, and the water cascaded into infinite sky, and the river came to reform as clouds above the earth. “Is this the place the fox spoke of?” said Pasalo.

Pasalo was dry, so he put his face in the river to drink. As he did so, underneath the surface of the water, he could see clearly. Upside down, he saw an underground cave. He climbed through the water’s surface, pulled himself onto a ledge, and stood. Pasalo saw an underground passageway. A river flowed at his feet, the sun shone brightly through the river, and the light danced on the cavern ceiling.

“I can breathe in here,” said Pasalo, “and thus have I seen water turn to air!” Pasalo followed the river of light until he came to a small shore of sand before a great hewn wall. There was a single door in the wall. On the door, in red, were the following letters:

THE UNPASSABLE DOOR.

“Not unpassable for me,” said Pasalo, but though he beat, shoved and pried at the door, it would not move a bit. Pasalo slumped on the sand, dejected. As he sat on the sand, he could see a faint light under the door. Pasalo said, “If I might not pass through it, I might pass under it,” and dug sand from under the door. At last he removed enough that he could slide himself underneath the door.

When Pasalo emerged, he saw a vast and rich treasure room with every imaginable kind of wealth: rubies, emeralds and diamonds as big as porcupines, beds and sheets and linens spun of pure gold, encrusted crowns and swords and staves, each one more exquisite than the last. “Everything here is a wonder, and there are so many wonders here,” said Pasalo. “How can I possibly choose the most beautiful thing?” As he said this he spied a single tulip growing in a patch in the corner. A single droplet of dew sparkled from the center of the tulip. As Pasalo took the flower, a spell lifted and all the jewels and fineries were revealed as rocks and wood.

“All my treasures are vanished,” said Pasalo, “but at least I have this.” Pasalo went back under the impassable door, through the river of light at the edge of the world, and over many many miles to the dark castle on the hill.

The gargoyle glowered at him. “You may not enter the castle unless you show me the most beautiful thing in the world.”

Pasalo showed the beautiful tulip with the droplet of dew. The gargoyle laughed and said, “I tell you to show me the most beautiful thing in the world, and you show me a simple common flower?”

Pasalo said, “No. I have travelled far and wide over many years, and I have seen the edge of the earth. I have traversed the place where water turns to air, and passed the impassable door. I have rejected every earthly treasure to find this tulip and bring it here, but not to you. Please give it to Shala the nightingale on my behalf, and tell her that I love her, and always will.” Whereupon the gargoyle bowed deeply and permitted Pasalo to enter.

Pasalo ran to the top window. He saw the dark enchantress dangle the gilded cage out of the window with one arm, with Shala the nightingale therein. “If you come at me, I’ll dash your nightingale to the rocks below,” said the enchantress, “and that will be the end of your true love.” Whereupon, from outside the window, the gargoyle seized the cage and the enchantress’s arm with it, and pulled them both outside the window. The enchantress swang from the teeth of the gargoyle. The gargoyle gave a small chomp, and the enchantress (less one arm) fell twenty stories to the sharp rocks below. As she died, the sun lifted, and roses climbed the walls of the castle.

Pasalo despaired of Shala the nightingale in the jaws of the gargoyle, when the gargoyle placed his great head in the window and smiled. Through his teeth stepped Shala. The curse was lifted, and she was as beautiful as the day when Pasalo first saw her. They were married and lived happily in the castle with the great gargoyle guarding them; the last I heard, the three live there still.

There’s no leaving here; ask, I’m an ear

There?s a great deal of existing rendering code built on old versions of Microsoft’s Foundation Class (MFC) model. In the old object model, you had a single CFrameWnd, a single CDocument, and one or more CView classes that were owned by the CFrameWnd class. These objects share message routing responsibilities with one another, and a great deal of code has been written with these assumptions.

Fast forward twenty or so years, and these old assumptions, upon which most of MFC was originally architected, are incompatible with the complexity of modern user interface design, and even a good deal of modern-day MFC itself. There can be multiple documents, controls floating and tabbed which may or may not be children of the CFrameWnd.

The funky new display and interface features like CDockablePane and CMFCToolBar don’t know anything about the CView class, and they don’t inherit from CView. It’s hard to upgrade an older application written based on the old MFC document-view model to dockable panes.

It?s a bit of work, but here’s one way to accomplish this without relying on proprietary libraries. The basic strategy we use is to change the old CView-based classes to be a subclass of CDockablePane, and then make the new class support enough of the major CView features in order to handle update rendering, commands, OLE drag and drop, and user-interface updates via the old interfaces in your old class.

In order to convert your own subclass of CView into a CDockablePane subclass, here’s what you need to do:

1. Create a new subclass of CDockablePane (we’ll call it CYourDockablePane) from which all your old CViews will inherit.
2. Implement update message handling and OLE support from your CYourDockablePane subclass.
3. Subclass COleDropTarget into a new class which we’ll call CYourOleDropTarget in order to handle OLE drag-and-drop in the manner that CView does.
4. Add features to your C*FrameWnd* class to support window updating and command message routing to the new panes.

 


 

YourDockablePane.h:

//------------------------------------------------------------------
#pragma once

#include "YourOleDropTarget.h"

class CYourDockablePane : public CDockablePane
{
	DECLARE_DYNCREATE(CYourDockablePane)

public:
	CYourDockablePane();
	virtual ~CYourDockablePane();

	// These are needed to get around OnUpdate()?s protected status
	virtual BOOL ReceiveNotification(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
	virtual void OnUpdate( CView *pSender, LPARAM lHint, CObject *pHint );

	// Simulate CView OLE drag and drop effects
	virtual DROPEFFECT	OnDragEnter( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point );
	virtual void		OnDragLeave( void );
	virtual DROPEFFECT	OnDragOver( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point );
	virtual DROPEFFECT	OnDropEx( COleDataObject *pDataObject, DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point );
	virtual DROPEFFECT	OnDragScroll( DWORD dwKeyState, CPoint point);
	virtual BOOL        OnDrop( COleDataObject* pDataObject,	DROPEFFECT dropEffect, CPoint point);

protected:
	DECLARE_MESSAGE_MAP()

	// View classes know how to do this
	virtual CYourDocument *GetDocument(void) const;
	CYourOleDropTarget	m_OleDropTarget;

public:

};



YourDockablePane.cpp:
/---------------------------------------------------------------------
// YourDockablePane.cpp : implementation file

#include "stdafx.h"
#include "YourDockablePane.h"

IMPLEMENT_DYNCREATE(CYourDockablePane, CDockablePane)

CYourDockablePane::CYourDockablePane()
{

}

CYourDockablePane::~CYourDockablePane()
{
}


BEGIN_MESSAGE_MAP(CYourDockablePane, CDockablePane)
END_MESSAGE_MAP()

CYourDocument * CYourDockablePane::GetDocument( void ) const
{
	CDocTemplate* pDocTemplate;
	POSITION pos;
	pos = AfxGetApp()->GetFirstDocTemplatePosition();
	pDocTemplate = AfxGetApp()->GetNextDocTemplate(pos);
	pos = pDocTemplate->GetFirstDocPosition();
	return (CYourDocument*) pDocTemplate->GetNextDoc(pos);
}

BOOL CYourDockablePane::ReceiveNotification( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
	return OnNotify( wParam, lParam, pResult );
}

DROPEFFECT CYourDockablePane::OnDragEnter( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point )
{
	return DROPEFFECT_NONE;
}

void CYourDockablePane::OnDragLeave( void )
{

}

DROPEFFECT CYourDockablePane::OnDragOver( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point )
{
	return DROPEFFECT_NONE;
}

DROPEFFECT CYourDockablePane::OnDropEx( COleDataObject *pDataObject, DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point )
{
	return DROPEFFECT_NONE;
}

DROPEFFECT CYourDockablePane::OnDragScroll( DWORD dwKeyState, CPoint point )
{
	return DROPEFFECT_NONE;
}

BOOL CYourDockablePane::OnDrop( COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point )
{
	return false;
}

void CYourDockablePane::OnUpdate( CView *pSender, LPARAM lHint, CObject *pHint )
{

}



YourOleDropTarget.h:
/------------------------------------------------------------------------
#pragma once

class CYourDockablePane;

// CYourOleDropTarget command target

class CYourOleDropTarget : public COleDropTarget
{
	DECLARE_DYNAMIC(CYourOleDropTarget)

public:
	CYourOleDropTarget();
	virtual ~CYourOleDropTarget();
	BOOL Register(CWnd* pWnd);

protected:
	CYourDockablePane *m_pPane;
	DECLARE_MESSAGE_MAP()
public:
	virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
		DWORD dwKeyState, CPoint point);
	virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
		DWORD dwKeyState, CPoint point);
	virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
		DROPEFFECT dropEffect, CPoint point);
	virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject,
		DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point);
	virtual void OnDragLeave(CWnd* pWnd);
	virtual DROPEFFECT OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
		CPoint point);

};



YourOleDropTarget.cpp:
/--------------------------------------------------------------
// YourOleDropTarget.cpp : implementation file
//

#include "stdafx.h"
#include "YourDockablePane.h"
#include "YourOleDropTarget.h"

// CYourOleDropTarget

IMPLEMENT_DYNAMIC(CYourOleDropTarget, COleDropTarget)


CYourOleDropTarget::CYourOleDropTarget() :
	m_pPane( NULL )
{
}

CYourOleDropTarget::~CYourOleDropTarget()
{
}

BEGIN_MESSAGE_MAP(CYourOleDropTarget, COleDropTarget)
END_MESSAGE_MAP()

BOOL CYourOleDropTarget::Register( CWnd* pWnd )
{
	m_pPane = dynamic_cast< CYourDockablePane * >( pWnd );
	return COleDropTarget::Register( pWnd );
}


// CYourOleDropTarget message handlers

DROPEFFECT CYourOleDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
	return m_pPane->OnDragEnter( pDataObject, dwKeyState, point);
}

void CYourOleDropTarget::OnDragLeave(CWnd* pWnd)
{
	m_pPane->OnDragLeave();
}

DROPEFFECT CYourOleDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
	return m_pPane->OnDragOver( pDataObject, dwKeyState, point);
}

DROPEFFECT CYourOleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point)
{
	return m_pPane->OnDragScroll( dwKeyState, point);
}

BOOL CYourOleDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
	return m_pPane->OnDrop( pDataObject, dropEffect, point);
}

DROPEFFECT CYourOleDropTarget::OnDropEx( CWnd *pWnd, 
							COleDataObject* pDataObject,
							DROPEFFECT dropDefault,
							DROPEFFECT dropList,
							CPoint point 
							)
{
	DROPEFFECT effect;
	
	effect = m_pPane->OnDropEx( pDataObject, dropDefault, dropList, point );

	if ( effect == DROPEFFECT_NONE )
		return m_pPane->OnDrop( pDataObject, dropDefault, point );

	return effect;
}



Add this snippet to the definition file (the .h file) of your application?s CFrameWnd or CFrameWndEx subclass:
. . .
		typedef list< CPane *> CYourPanes;
		typedef CYourPanes::iterator  CYourPaneIter;

		typedef list< CYourDockablePane *> CYourDockablePanes;
		typedef CYourDockablePanes::iterator CYourDockablePanesIter;

		CYourPanes			m_Panes;
		CYourDockablePanes 	m_YourDockablePanes;

Add this to the implementation file (the .cpp file) of your application's CFrameWnd or CFrameWndEx subclass, changing the CYourFrameWnd class name to the name of your frame window subclass:
void CYourFrameWnd::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint )
{
	for ( CYourDockablePanesIter it = m_YourDockablePanes.begin(); 
		it != m_YourDockablePanes.end(); it++ )
       {
		(*it)->OnUpdate( pSender, lHint, pHint );
	}
}
BOOL CYourFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
	/* We intercept all the commands sent to the frame here, and give all 
	 * our child panes first crack at handling them.
	 */
	for ( CYourPaneIter it = m_Panes.begin(); it != m_Panes.end(); it++ )
	{
         	if ( (*it)->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ))
			return true;
	}

	return CFrameWndEx::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
BOOL CYourFrameWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	for ( CYourDockablePanesIter it = m_YourDockablePanes.begin(); it != m_YourDockablePanes.end(); it++ )
	{
		if ( (*it)->ReceiveNotification( wParam, lParam, pResult ) )
			return true;
	}

	return CFrameWndEx::OnNotify(wParam, lParam, pResult);
}
At this point, you should search through your old CView class to find any references to a COleDropTarget. These references should be changed to refer to the m_OleDropTarget member that you put within the CYourDockablePane class.

A couple final things you need to do: inform your main frame class about the locations of your CYourDockablePane-derived classes, as well as your toolbars and other non-view features, which are generally children of the CPane class.

Wherever you instantiate and call Create() on your CYourDockablePane descendant, add it to your list of CYourDockablePanes:

  m_YourDockablePanes.push_back( &yourNewlyCreatedDockablePane );

And wherever you instantiate and Create() toolbars or other things that need to process commands or UI updates, including your dockable panes, add them to the list of CPanes as well:

  m_Panes.push_back( &yourNewlyCreatedControlOrPane );

This basic strategy can be used to convert old CView-based classes into any modern control-based user interface architecture, or merely to have your classes derive from CWnd directly.

There may be other side effects of this class conversion that I’ve not considered. Please feel free to modify the above code to your specific situation.

Information and code from this blog entry may be reused and redistributed under the following license.

Creative Commons License
There’s no leaving here; ask, I’m an ear by John Byrd is licensed under a Creative Commons Attribution 3.0 United States License.
Based on a work at www.johnbyrd.org.

One night in Bangkok makes a hard man humble

My thoughts this morning go out to my brother, who has been sent to Afghanistan for a month. Part of the troop surge there. He’s going in a support role, in order to provide some equipment and weapons training, so he’s not expected to see combat; however, I’m still thinking of him. He’s a large fellow and at least as smart as me.

A couple weeks ago I joined the Screen Actors’ Guild. I’m hoping I can leverage some of the Ambassador’s Day work into a new agent.

I just wrote the world’s youngest chess playing program, Superpawn. Superpawn plays like a smart young child. It plays a mostly legal game of chess, though it doesn’t understand concepts like castling and the fifty move rule. Superpawn loves to get the queen out early and parade her around the board. It is trivially Winboard compatible. Once Superpawn survives the epd2wb test suite, I’ll probably release it with a CC0 license.

When my wife was a little girl, she used to play chess with her older and somewhat more serious sister. At a certain point in the game, Amanda would grab a pawn and scream “SUPERPAWN!” and fly it around the board, knocking all the pieces over.

Me used to be a angry young man

With thanks and respect to my father, my company now has a small office at 2102 Business Center Drive in Irvine. I’ve spent the last few weeks launching the company. I spent Christmas break moving in the computers and the printer and the Ikea furniture. I even hired a part-time employee with a flurry of W-2s and I-9s to manage some accounts.

I was worried that I’d turn into a porn-surfing late-sleeping slug when self-employed, but it’s been just the opposite. I am happy to report that I work just as hard for myself as for The Man — twelve-hour days in many cases, and I don’t feel that I’ve worked that hard at the end of the day.

It’s an exciting time, and I’m glad to be alive so I can live it. I am physically tired, but I wake up every morning now excited to go into work.


View Larger Map

<%image(20100106-Photo_010110_005.jpg|1280|1024|Me hiding me head in the sand)%>

The sky is blue, and all the leaves are green

For those of you who are not familiar: for the past three years I’ve been working as a contractor at a large video game development house. The company has been laying off a bunch of people, and yesterday they decided that I should be on that list as well. I feel ambivalent about this. The timing was awkward, but I feel like my product is at the point where I can begin licensing it on a larger scale, so this has the potential to be a blessing in disguise. At least, I’m going to try to keep a positive attitude, and try to focus on rounding up new business. Those of you who know me know that I’m the most sardonic human being in this hemisphere, so positivity does not come naturally to me; but middleware is one of those few industries that does well in an economic downturn, and the product we’ve developed is actually better than the competition, so I do have a good chance of actually turning a profit soon.

Obligatory joke: Titles of musicals that will write themselves:

“Bleeding In The Rain”
“Jesus Christ Porno Star”
“Annie Get Your Machete”
“An American In Paris Hilton”
“Blow Me Kate”
“Oklahomo”

Jesus don’t want me for a sunbeam

She had a particular set of music that she wanted at the funeral. “Memories” from Cats, and “Don’t Cry For Me Argentina” from Evita. Big, loud, brassy numbers. Laptop was down, but I figured out how to burn the CDs on Dad’s laptop. My Harvard computer science degree came in handy for my stepmother’s funeral.

I could handle the service, no problem. Standard Catholic mass. Lots of cookie-cutter sisters pressed like Whitman white chocolates into the front row, all sobbing delicately into Kleenex. Sit-stand-kneel, sing number 865 from the hymnal. I even took communion with the bunch of them, and did not burst into flames. I ate the body of Christ and thought of zombies.

There was a gullet-stuffing potluck after the funeral. Even after everyone had eaten all the Sam’s Club Value Cashews and cole slaw and four-cheese sandwiches and Vienna sausages on plastic toothpicks, even then, there were two party trays of fatty ham and roast-beef sandwiches left over. Somehow the trays came to my dad’s house. I tried to throw them away, but my brother and my father reacted violently. “You so much as make a move to throw out that party tray, and I’ll break your neck,” snarled my brother. He kept it for a day, ate one sandwich from it, and threw it away himself. Something about West Virginia and wasted food. I’ll explain it to you someday. If you lived here, you would already understand.

Flew to West Virginia a week ago, again. Death tours back east running into tens of thousands of dollars.

Dad is sad. I was ready for much worse; I was expecting full-on drinking binges and self-loathing and suicidality, like when we were kids. He’s focusing on helping others instead. He just got elected into an officer position down at the local AA branch. He laughs now and then.

E-mail says more layoffs at work. They fired fifteen people; do you think I could maybe re-do the schedule while I have down time? [Redacted.] Dad is worried about what he will eat. I taught him how to cook a steak, how to dice an onion, how to bake fish, and how to roast croutons.

House looks the same. Lots of leaves. You people in California don’t know leaves, and you don’t know sky. You should come visit, and you will see sky.

The sisters left, in a gossiping, nattering bunch and I was left with my brother, my father, and my Appalachian stoicism. I was actually doing fine until tonight, when I had to disassemble the pictures from the collage back into a photo album. That’s when it hit me. Death in the family. Sixth in three years.

Goddammit!

How straightforward the game when one has trust in one’s player

There exist many variants on the basic rules of chess. Many of these variants introduce a larger board or new pieces or movement rules in order to make the game more complex. Personally, I have a hard time keeping straight the additional rules of the variants, and so they seem less fun to me. In the words of Trip Hawkins, great games are simple, hot and deep.

Cathouse is my contribution to the world of chess variants. In Cathouse, many queens scratch at one another to gain the attention of the king.

The only valid pieces in Cathouse are pawns, queens, and kings. Initial setup for the Cathouse board is as follows:

20091017-Cathouse

In the initial setup, your pieces are placed on the opponent’s side of the board. You have your king on the eighth rank, with pawns on the fifth, sixth and seventh rank.

Move and capture rules are the same as for FIDE chess: pawns may move forward exactly one square into an empty space, or they may capture on adjacent front diagonals. Kings may move and capture to any open adjacent square.

When a pawn reaches the eighth rank, it is immediately exchanged for a queen. This means that each player may theoretically promote up to three queens on the board. (Pawns may only promote to queens.) If you don’t have so many queens laying around with your chess board, just turns your rooks onto their heads and pretend they’re queens.

Queens move as in FIDE chess: they slide along rows, columns or diagonals in rays until they are stopped by a piece of their own color, or until they capture an opposing piece.

The game ends according to FIDE chess rules. Checkmate, stalemate, draw, and three-move repetition endings are all possible.

For a piece layout this simple, the game is surprisingly well-balanced. Computer analysis suggests that white has an opening advantage of only about half a pawn, the same as in traditional FIDE chess. Each player must try to generate their own queens while simultaneously preventing the opponent from doing so. Space control and tempo seem to be key in Cathouse.

It’s spring time for Hitler in Germany

Dad called a couple weeks ago. Rachel, my stepmother, has had cancer for some years now. They just decided to transition her into hospice care. We rejiggered our vacation plans and traveled to Charleston, West Virginia three days ago instead. As with all cancers, no one really knows anything.

People come and go in Dad’s house, some of whom I don’t know. Rachel’s Catholic; a priest came in.

We’ve been on the road a lot. Charleston, West Virginia to Fishersville, Virginia where we will spend the night tonight. My mother made food. Lots of food. It’s what she does. We’re watching The Producers (new school) on TV while I write this.

I snapped at my wife the other day. I regret having done that.

My family looks old to me. I assume I look old to them.

I’m quiet, mostly because I’m tired. I feel physically drained, and I find it difficult to hold a coherent train of thought. I suppose I’m growing a little too set in my ways.

Spam spam spam spam spam spam spam spam

So the Yahoo porn spam bot keeps contacting me. Rather than ignore it, I thought I’d try to get it to tell me a little more about its internal structure, so that someone with more time than me can r00t it. Here’s what I found out.

The bot has a canned script. If a human responds to its IMs, and it doesn’t see a keyword, then it continues with its canned script. Once the script ends, the conversation terminates.

Known interesting keywords follow. The bot searches this keyword list in this order, and the earliest match is returned as a response. The bot is case-insensitive. The bot will continue to chat you indefinitely if you include one or more of the following words in your response.

web / http://tinyurl.com/SEXYMISSES [or whatever the porn URL du jour is]
site / http://tinyurl.com/SEXYMISSES [or whatever the porn URL du jour is]
shit / what’s wrong?
fake / the only thing fake here is your toupet!
spam / nah, I am a vegetarian… no spam for me! haha
bot / whats a bot? im 100% all real and natural, from tits to ass!