Tuesday, January 09, 2007

 

My Luck Day - 3 No Trump!

I play bridge with some friends of mine. Recently, I got dealt a hand which had more high card points in it than I had ever seen: 26. Later that evening, I got another strong hand of 25 points! The proper opening bid for these situations is 3 no trump.

This got me to wondering what the probability of getting a hand like this would be (assuming the cards were shuffled properly). So, I wrote a quick and dirty Python program to simulate large number of hands and count the occurrences of the possible initial high card points. On the following graph, the x axis is the high card count, while the y axis is the percentage of times that count occurs. Note that this data is from a simulation, and is not exact.



The specific probability of 26 points is about 0.011842% or 1 in 8,444 hands. The chances for 25 points is about 1 in 3,703 hands.

It is interesting to note that in the 10 million hands I generated, not one of them had 33 points or more. Maybe next time I'll get one of those :-)

Here is the code I used:

import random

a = []
for i in range(0,4):
for j in range(0,4):
a.append(j + 1)
for j in range(0,9):
a.append(0)

d = []
for i in range(0,41):
d.append(0)

for c in xrange(1,9999999):
random.shuffle(a)
s = sum(a[0:13])
d[s] += 1

if c % 10000 == 0:
print c
for i in xrange(0,41):
print '%2d: %f %d' % (i, 100.0 * d[i] / c, d[i])

Saturday, October 07, 2006

 

Gonna Fly Now

I recently saw this video of a man who built a video camera into an RC airplane and flew it around while looking at the live feed from his camera, transmitted via wireless. He also installed gyros on his video goggles which control the pan and tilt of the camera. This gives him the ability to "look around" while flying, greatly enhancing the experience.

Of course I had to build one for myself. And, I decided to photo-document the process.

Update: I've replaced the original video with a different one, as the old one seems to have been removed. Also, I've not had much time to fly my plane. I've had two flights, one without the video equipment, and one with it, but the video recorder's battery flaked on me and I could not make a recording. Funny how having kids takes aways from one's hobbies :-)

Wednesday, August 23, 2006

 

Rodentia non Grata

And Now for Something Completely Different.

Recently, during the winter months, we've had problems with rats crawling into our Toyota Highlander at night to take advantage of the warm engine. This, I don't mind. However, I did mind them gnawing the fuel injector lines which caused the engine to perform rather badly. At about $300 a pop to replace the lines, I was not amused.

So, this little guy is the fourth victim in my hunt to reduce the rat population around my house:



What's interesting about this common, however gruesome, scene is that this rat was caught by backing up into a trap.

My, patent not pending, device is two rat traps fixed to a board. It is common for the bait on the trigger to be licked clean by a rat without triggering the trap. By having two traps close together, one gets a better chance at getting a rat.

There are other advantages as well. The board adds mass to the whole configuration, so when a trap is triggered, instead of the trap getting flung about, it stays put. Also, because of the extra mass, the trap closes faster and twitches less before closing, giving the rat less notice of his impending doom. Also, setting the trap is easier and safer because one can hold the board instead of the trap itself.

Sunday, July 09, 2006

 

IE Trident Easter Eggs

I created the Trident easter eggs in IE 4 and IE5.

The IE 4 one is a sinusoidal animation of the names of the people who worked on Trident. I used the letter spacing property to perform the animation, and when the names collapse, I replace the name with the next name. I think it is a pretty cool effect. If you click once on the "<TRIDENT>" tags and the center name, I made my name display instead of cycling through the other names. An Easter egg in side an Easter egg :-)

The IE 5 one is a gravitational simulation where the names of the people who worked on the product are the gravity wells and a collection of colored dots orbit the names. I had to play around with how much friction to simulate, as early on, the dots tended to fly away to infinity! Again, I hid my own Easter egg in side the Easter egg. In the top left part of the window are some NBSP's where the cursor will turn from an arrow to a caret. Clicking on this will cause only my name to appear.

After IE 5.0, the pointy haired managers at Microsoft decided that Easter eggs comprised a security thread (or at least they thought corporate customers had this thought) and eggs were removed from the product. Turds.

Speaking of Easter eggs. The project that turned into Trident, called Forms^3 (Forms cubed) also has an Easter egg in which you can find my name. This one was created by Terry Lucas. Forms^3 is a forms editing and runtime package which exists in the Microsoft Office products. It exists in Excel 2002, but I'm not sure if it is in later versions. Perhaps someone can check them out.

You get to the Forms^3 Easter egg by starting the Visual Basic for Applications tool.

  1. From the "Tools" menu, click on the "Macro" sub menu and then on the "Visual Basic Editor" item. This is usually bound to "Alt-F11".
  2. Then, in the editor, click on the "Insert" menu and insert a new "UserForm". This brings up a canvas onto which you can drop controls.
  3. Create a list box by dragging the listbox icon from the toolbar onto the canvas.
  4. Then, modify the "RowSource" property of the list box to have the value "Alchemy_Forms^3". The list box will now be populated with the first names of all the people on the Forms^3 team.
  5. You can then set the "ColumnCount" to be 3 to see the last names and the role each individual had on the team: dev, test, etc. You may need to make the list box larger to show this additional information.
  6. You can activate the control by clicking on it at which point you will be able to scroll through all the names.
This Easter egg uses some of the data binding technology Terry was working on at the time.

Sunday, July 02, 2006

 

Code Karma

I've recently been writing client side Java Script for an HTML user interface I've been building at work, and I ran into an issue with Internet Explorer which I was at least partially responsible for 10 years ago! Let me explain what it is, why it is and an effective way to work around it.

I was attempting to dynamically replace a number of rows in a table with a different set of rows. I was using the innerHTML property of an element which takes a string, parses it as HTML and replaces the contents of that element with the new HTML. In this case, I try to replace the contents of a TBODY with a new set of rows:

  <table>
<tbody id="rows">
<tr>....
<tr>....
...
</tbody>
</table>


var tb = document.getElementsByName('rows')[0];
tb.innerHTML = "<tr>......";


This works just fine in Firefox. The new rows replace the old and the display updates. However, in Internet Explorer, one gets a script error stating that there was a runtime error!

At first, I thought that IE was not capable of performing the redraw for modified tables with innerHTML, but then I remembered that I was responsible for this limitation! How many developers get to deal with the consequences of their decisions about products at a later date? Probably not many. Let me describe how this came to be.

About 10 years ago, I was part of the Trident team. Trident was responsible for implementing the parsing, rendering and object model for the next version of IE, after 3.0. Also known as mshtml.dll. I was a developer responsible for the in-memory representation of the HTML and the dynamic manipulation of that HTML.

One of the things I did during this time was invent the method innerHTML, along with innerText, outerHTML, outerText and the lesser known insertAdjacentHTML and insertAdjacentText methods. These were methods which took HTML or raw text and replaced/inserted that new content into the document.

Now, Microsoft documents this as not applicable to table elements. Why? They don't say. However, I remembered why.

When one sets the innerHTML property of an element, the string containing the HTML is run through the parser. Now, HTML parsers are not simple, straightforward parsers like XML parsers. The HTML parser (implemented brilliantly by David Bau) takes arbitrary text and, usually, produces an HTML tree of elements. For example, parsing a file containing only "Foo" will result in the tree:
  <HTML><HEAD></HEAD>
<BODY>Foo</BODY></HTML>

You can see this for yourself by running the following through IE (Firefox won't work, as they did not implement outerHTML):
Foo<script>alert(document.body.parentNode.outerHTML)</script>

Now, parsing something like "<tr><td>Foo" where there is no TABLE tag preceding the TR causes the parser to ignore the TR tag altogether. This was probably done by the IE parser for backwards compatibility with the Netscape browser of the time. In fact, much of the complexity of the parser is influenced by backwards compatibility.

So, attempting to set the innerHTML of a TBODY with "<tr>..." would result in setting the contents of the TBODY with "Foo". This is not terribly "valid" or displayable HTML. In order to get that TR created, you need to precede it with a TABLE tag. However, attempting to set the contents of the TBODY with "<table><tr>..." makes even less sense because injecting a TABLE directly in a TBODY is also meaningless.

What this all calls for is what I used to call "Contextual HTML Parsing". This is a mode of parsing where a branch of an existing HTML tree was to "seed" the parser with a context with which the parser would then interpret a string to parse. Thus, if the branch of tags were (from the bottom) TBODY, TABLE, BODY, HTML and one were to parse "<tr>...", the "Contextual HTML Parser" would know that creating a TR was okay because its immediate parent would implicitly be a TBODY, a valid container for a TR.

Nifty concept, this contextual parsing. The problem was that we never had enough time to implement such a feature. And, in order to deal with attempts to modify tables in such a manner, I prohibited the modification of tables with innerHTML and other methods.

An alternative to all this would have been to "hack" something up. For example, I could have checked to see if the innerHTML of a TBODY was being set to something which began with a "<tr>". Under these circumstances I could have prepended a "<table>" to the string, and then plucked the TR's out of the resulting tree and replaced the contents of the TBODY with them.

Sounds simple enough until you have to consider all the variations. Like, what if the string to be parsed looks like "<!-- new rows --><tr>...". Pretty soon you start doing all the work the real parser has to do.

So instead of hacking up something very incomplete and possibly erroneous in many cases, I left the modifications of tables with innerHTML out of the product. It would have been fun to modify the parser to deal with non textual context!

I wonder how Firefox implemented this. Perhaps I'll find the time to look at the code sometime....

The workaround for this is actually not all that bad. What I did was to insert a SPAN tag into my original page with the visibility style set to hidden. When I wanted to replace the rows, I would set the innerHTML of this span with something like "<table><tbody><tr>...". Because the span is not visible, this does not cause the page to redraw. Then, I would use the DOM method replaceChild of elements to remove the old TBODY and replace it with the newly parsed TBODY. This resulted in the table changing and being redrawn correctly!
  <table>
<tbody id="tb">
<tr>....
<tr>....
...
</tbody>
</table>
<span id=temp style='visibility:hidden'></span>


var temp = document.getElementsByName('temp')[0];
temp.innerHTML = '<table><tbody><tr><td>New Row';
var tb = document.getElementsByName('tb')[0];
tb.parentNode.replaceChild(temp.firstChild.firstChild, tb);


You can see this in action here.

This page is powered by Blogger. Isn't yours?