<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4107175839454033511</id><updated>2012-02-16T01:47:16.160-07:00</updated><category term='parcon'/><title type='text'>javawizard</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://me.opengroove.org/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default?start-index=26&amp;max-results=25'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>44</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-6688528571417630718</id><published>2011-06-24T22:08:00.002-06:00</published><updated>2011-06-24T22:08:30.562-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='parcon'/><title type='text'>Parcon has its own blog</title><content type='html'>I decided to create a blog dedicated to Parcon, so all Parcon-related posts will now be showing up on that blog. It's located at &lt;a href="http://blog.parcon.opengroove.org"&gt;blog.parcon.opengroove.org&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-6688528571417630718?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/6688528571417630718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=6688528571417630718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6688528571417630718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6688528571417630718'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2011/06/parcon-has-its-own-blog.html' title='Parcon has its own blog'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-7379966280369300107</id><published>2011-06-16T23:53:00.012-06:00</published><updated>2011-06-20T15:03:19.102-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='parcon'/><title type='text'>PyParsing examples in Parcon</title><content type='html'>A lot of people at #python have encouraged me to port some of PyParsing's examples to Parcon, so I've decided to write up a blog post with some of those examples. Some of them parse the same input but produce output that's slightly different from what the corresponding PyParsing example produces; such differences are noted accordingly.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;Let's start with PyParsing's &lt;a href="http://pyparsing.wikispaces.com/"&gt;hello, world&lt;/a&gt; example first:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from parcon import alpha_word&lt;br /&gt;greet = alpha_word + "," + alpha_word + "!"&lt;br /&gt;hello = "Hello, World!"&lt;br /&gt;print hello, "-&gt;", greet.parse_string(hello)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This prints:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Hello, World! -&gt; ('Hello', 'World')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The main difference between the PyParsing version and the Parcon version is that the result doesn't contain the "," and the "!". In my experience, the output of literals in the grammar is typically ignored, so Parcon by default discards literal values. If the value of a literal is important, SignificantLiteral("...") should be used instead; changing "," to SignificantLiteral(",") and "!" to SignificantLiteral("!") would have made the Parcon example follow PyParsing's behavior.&lt;br /&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;Now let's try another one. This one is Chemical Formulas, the second example on &lt;a href="http://pyparsing.wikispaces.com/Examples"&gt;this page&lt;/a&gt;. It doesn't include the atomic weight calculator at present, but I'll add this in at some point. Here's the parser:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from parcon import *&lt;br /&gt;element = Word(lower_chars, init_chars=upper_chars)&lt;br /&gt;integer = Word(digit_chars)[int]&lt;br /&gt;element_ref = element + Optional(integer, 1)&lt;br /&gt;chemical_formula = +element_ref&lt;br /&gt;# Examples:&lt;br /&gt;print chemical_formula.parse_string("H2O") # [('H', 2), ('O', 1)]&lt;br /&gt;print chemical_formula.parse_string("H2SO4") # [('H', 2), ('S', 1), ('O', 4)]&lt;br /&gt;print chemical_formula.parse_string("NaCl") # [('Na', 1), ('Cl', 1)]&lt;br /&gt;print chemical_formula.parse_string("Au") # [('Au', 1)]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;The last example I'm providing in this post is wordsToNum, the fourth example on the same page that chemicalFormula appeared on. It takes a human-readable number specification like "twelve thousand three hundred forty five" and parses it into the representative number (12345, in that case).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;from operator import mul&lt;br /&gt;from functools import partial&lt;br /&gt;# This part is copied from the PyParsing version of wordsToNum, with&lt;br /&gt;# some newlines removed&lt;br /&gt;unitDefinitions = [&lt;br /&gt;    ("zero",       0), ("oh",         0), ("zip",        0), ("zilch",      0),&lt;br /&gt;    ("nada",       0), ("bupkis",     0), ("one",        1), ("two",        2),&lt;br /&gt;    ("three",      3), ("four",       4), ("five",       5), ("six",        6),&lt;br /&gt;    ("seven",      7), ("eight",      8), ("nine",       9), ("ten",       10),&lt;br /&gt;    ("eleven",    11), ("twelve",    12), ("thirteen",  13), ("fourteen",  14),&lt;br /&gt;    ("fifteen",   15), ("sixteen",   16), ("seventeen", 17), ("eighteen",  18),&lt;br /&gt;    ("nineteen",  19)]&lt;br /&gt;tensDefinitions = [&lt;br /&gt;    ("twenty",  20), ("thirty",  30), ("forty",   40),&lt;br /&gt;    ("fourty",  40), # for the spelling-challenged...&lt;br /&gt;    ("fifty",   50), ("sixty",   60), ("seventy", 70), ("eighty",  80),&lt;br /&gt;    ("ninety",  90)]&lt;br /&gt;majorDefinitions = [&lt;br /&gt;    ("thousand",    int(1e3)), ("million",     int(1e6)), ("billion",     int(1e9)),&lt;br /&gt;    ("trillion",    int(1e12)),("quadrillion", int(1e15)),("quintillion", int(1e18))]&lt;br /&gt;# Now we get into the Parcon-specific code.&lt;br /&gt;def make(text, number):&lt;br /&gt;    return AnyCase(text)[lambda x: number]&lt;br /&gt;&lt;br /&gt;unit = Longest(*[make(t, n) for t, n in unitDefinitions])&lt;br /&gt;ten = Longest(*[make(t, n) for t, n in tensDefinitions])&lt;br /&gt;mag = Longest(*[make(t, n) for t, n in majorDefinitions])&lt;br /&gt;product = partial(reduce, mul)&lt;br /&gt;section = (Optional(unit[lambda t: t*100] + "hundred") + -ten + -unit)[flatten][sum]&lt;br /&gt;number = ((section + mag)[product][...] + Optional(section, 0))[flatten][sum]&lt;br /&gt;number = Exact(number, Whitespace() | "-" | "and")&lt;br /&gt;# Some examples (all of which return the corresponding int value):&lt;br /&gt;print number.parse_string("zero")&lt;br /&gt;print number.parse_string("one")&lt;br /&gt;print number.parse_string("five")&lt;br /&gt;print number.parse_string("ten")&lt;br /&gt;print number.parse_string("seventeen")&lt;br /&gt;print number.parse_string("twenty")&lt;br /&gt;print number.parse_string("twenty one")&lt;br /&gt;print number.parse_string("fifty five")&lt;br /&gt;print number.parse_string("one hundred")&lt;br /&gt;print number.parse_string("one hundred three")&lt;br /&gt;print number.parse_string("two hundred ten")&lt;br /&gt;print number.parse_string("six hundred forty two")&lt;br /&gt;print number.parse_string("eight hundred fifty")&lt;br /&gt;print number.parse_string("one thousand")&lt;br /&gt;print number.parse_string("one thousand one")&lt;br /&gt;print number.parse_string("one thousand five")&lt;br /&gt;print number.parse_string("one thousand thirty")&lt;br /&gt;print number.parse_string("one thousand forty two")&lt;br /&gt;print number.parse_string("one thousand one hundred")&lt;br /&gt;print number.parse_string("one thousand one hundred fifty nine")&lt;br /&gt;print number.parse_string("five thousand one hundred fifty nine")&lt;br /&gt;print number.parse_string("twenty thousand one hundred fifty nine")&lt;br /&gt;print number.parse_string("forty one thousand one hundred fifty nine")&lt;br /&gt;print number.parse_string("two hundred forty one thousand one hundred fifty nine")&lt;br /&gt;print number.parse_string("one million")&lt;br /&gt;print number.parse_string("one million two hundred forty one thousand one hundred fifty nine")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr/&gt;&lt;br /&gt;That's it for this post!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-7379966280369300107?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/7379966280369300107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=7379966280369300107' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7379966280369300107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7379966280369300107'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2011/06/pyparsing-examples-in-parcon.html' title='PyParsing examples in Parcon'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-3573396392833884307</id><published>2011-06-16T04:54:00.004-06:00</published><updated>2011-06-20T01:20:29.566-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='parcon'/><title type='text'>Parcon: a new parser combinator library</title><content type='html'>Parcon is a Python parser combinator library I'm working on. I've released it on PyPI &lt;a href="http://pypi.python.org/pypi?:action=search&amp;term=parcon"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;(I've also released Pargen, a formatter combinator library, as a submodule of Parcon, but I'll write a separate blog post on Pargen later.)&lt;br /&gt;&lt;br /&gt;I wrote Parcon to improve on some things that I think PyParsing does wrong. One of those things is PyParsing's lack of, in my opinion, useful error messages. For example, let's consider a grammar that parses an open parenthesis, any number of "a" or "b", and a close parenthesis. This looks like this in PyParsing:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;expr = "(" + ZeroOrMore(Literal("a") | "b") + ")"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Simple enough. If you call expr.parseString("(abbab)"), it returns just fine. If, however, you call expr.parseString("(a"), you get an exception with a message something like this:&lt;br /&gt;&lt;br /&gt;Expected ")" (at char 2), (line:1, col:3)&lt;br /&gt;&lt;br /&gt;This message omits information: "a", "b", or ")" would all be valid characters here, but only ")" is shown. The corresponding Parcon grammar:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;expr = "(" + ZeroOrMore(SignificantLiteral("a") | SignificantLiteral("b")) + ")"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;provides a more informative error message when expr.parseString("(a") is called:&lt;br /&gt;&lt;br /&gt;At position 2: expected one of "a", "b", ")"&lt;br /&gt;&lt;br /&gt;This includes all possible options, not just the last one.&lt;br /&gt;&lt;br /&gt;This shortcoming of PyParsing becomes more obvious when parsing grammars consisting of a number of alternatives, each of which start with a particular string. PyParsing will only provide the last such expected string, while Parcon will provide all of them.&lt;br /&gt;&lt;br /&gt;Four other shortcomings in PyParsing that Parcon improves on:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;In PyParsing, parsers are mutable: parse actions can be added to them and so on. This makes it hard to reuse parsers reliably: a parse action might be added to a parser by one piece of code with others not realizing it. PyParsing provides a copy function to get around this, but this requires using copy on any parser that might possibly be reused, which is especially tedious in libraries consisting simply of sets of predefined parsers.&lt;br/&gt;&lt;br /&gt;Parcon obviates this by making parsers immutable, with the sole exception of Forward. Parse actions, in particular, are created using the Transform parser, which is constructed as Transform(parser, function); it passes the result of the specified parser through the specified function, returning the result of that function. parser[function] is shorthand for this, so parser[function] is the rough equivalent of pyparsing_parser.addParseAction(function), except that the original parser isn't modified by this in any way.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PyParsing's Literal, by default, does not suppress itself. From my experience writing parsers, suppressed literals are quite a bit more common than significant literals. Parcon's Literal is suppressed by default; SignificantLiteral is Parcon's non-suppressed alternative.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PyParsing can automatically parse out whitespace from within a grammar. This, however, doesn't account for when comments and such need to be automatically removed. Parcon allows a whitespace parser to be specified when calling parseString; this parser will be applied between every other parser in the grammar, and its results will be discarded. (This parser defaults to Whitespace(), a Parcon parser that parses carriage returns, newlines, spaces, and tabs, if it isn't specified.)&lt;br/&gt;&lt;br /&gt;Of course, this could have the result of removing, for example, spaces in string literals being parsed by a Parcon grammar. Parcon provides a parser called Exact to prevent this: Exact(parser) is a parser that acts exactly like the parser it's created with, except that it sets the whitespace parser to Invalid() (a parser that never matches anything) while parsing the parser it was constructed with.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PyParsing does not provide any sort of monadic Bind parser, which would be needed to parse, for example, a binary protocol packet consisting of a certain number of bytes representing the length of the packet, followed by that many bytes consisting of the packet's data. (Yes, Parcon can parse binary data just as well as it can parse textual data.) Parcon provides both Bind and Return parsers, which, together, make Parcon a monadic parser combinator library. This opens up numerous possibilities for grammars that can be written using Parcon.&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If these features sound cool to you, open a terminal, type &lt;tt&gt;pip install parcon&lt;/tt&gt;, and give it a whirl! Documentation and examples are provided &lt;a href="http://www.opengroove.org/parcon/"&gt;here&lt;/a&gt;. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-3573396392833884307?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/3573396392833884307/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=3573396392833884307' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3573396392833884307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3573396392833884307'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2011/06/parcon-new-parser-combinator-library.html' title='Parcon: a new parser combinator library'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-4091715304615358253</id><published>2011-02-17T10:30:00.001-07:00</published><updated>2011-02-17T10:30:02.172-07:00</updated><title type='text'>A QR Code for Dessert.</title><content type='html'>What?&lt;br /&gt;&lt;br /&gt;No, really.&lt;br /&gt;&lt;br /&gt;I decided to take a leaf from &lt;a href="http://en.wikipedia.org/wiki/File:QR_Waffle.jpg"&gt;NYC Resistor&lt;/a&gt; and create an edible QR code. The one thing I don't like about theirs is that, while edible, it certainly wouldn't taste the best. I wanted to make one that would actually taste good.&lt;br /&gt;&lt;br /&gt;6 hours of work later, I had finished my task. I made it out of graham crackers, chocolate chips, and marshmallows, with a thin layer of frosting on each graham cracker. The only problem was, I just didn't have the heart to eat it after putting that much effort into it. My dad suggested gluing it to a piece of cardboard and taking it to work to hang up at my desk, which is what I'm planning on doing at present.&lt;br /&gt;&lt;br /&gt;The code is actually scannable (and results in a URL that redirects to this blog post). I'll post pictures soon.&lt;br /&gt;&lt;br /&gt;My next idea: QR fruit snacks. A single snack would be in a package, and it'd have some message (a joke, perhaps) encoded on it. Expect to see this on the market in ten years.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-4091715304615358253?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/4091715304615358253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=4091715304615358253' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/4091715304615358253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/4091715304615358253'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2011/02/qr-code-for-dessert.html' title='A QR Code for Dessert.'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-8485837978806185149</id><published>2011-01-28T02:19:00.002-07:00</published><updated>2011-01-28T02:24:33.330-07:00</updated><title type='text'>XKB and groups</title><content type='html'>This is really short because of the time, but I just found out that Gnome's keyboard switcher uses XKB's notion of groups internally. If you have USA as your first preference and United Kingdom as your second preference, it maps UK in as Group 2.&lt;br /&gt;&lt;br /&gt;This messes stuff up if you've doctored up your own custom symbol file that uses multiple groups. I just spent a good day trying to figure out why this didn't work, and it turns out it's because of that.&lt;br /&gt;&lt;br /&gt;The moral of the story is: keyboards added in Gnome's keyboard switcher (System → Preferences → Keyboard → Layouts) will get mapped in as groups and override any groups you have in your symbols file, so make sure and use only one layout, or modify your symbol file to use, say, groups one and four, instead.&lt;br /&gt;&lt;br /&gt;I'll write a post on how to configure the control key to switch groups tomorrow or something. And a post on how to actually add new symbols to a keyboard. There seems to be a lack of XKB documentation out there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-8485837978806185149?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/8485837978806185149/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=8485837978806185149' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/8485837978806185149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/8485837978806185149'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2011/01/xkb-and-groups.html' title='XKB and groups'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-1949581521834493456</id><published>2011-01-22T23:32:00.000-07:00</published><updated>2011-01-22T23:32:19.392-07:00</updated><title type='text'>Threading, locks, and Tkinter's after_idle</title><content type='html'>I've been getting into Tkinter lately. It's one of the few Python widget toolkits that works on PythonCE. It's actually quite nice. The UIs are not the most friendly, and there are some other things I don't particularly like about Tkinter, but all-in-all, it's been fairly good. (I still like GTK+ better, but it doesn't run on PythonCE, and thus far my applications have all needed to run on my Pocket PC.)&lt;br /&gt;&lt;br /&gt;So, I was going along, happily writing and testing, when I hit a slight problem. That slight problem came in the form of an application that just seemed to up and hang for no apparent reason. And when I say hang, I mean the entire Tkinter main loop froze up. What?&lt;br /&gt;&lt;br /&gt;I started sprinkling print statements throughout my code to try and find where the freeze-up was occurring, and I eventually found it: it was on an attempt to acquire a lock. Aha! Deadlock! Not the most unusual thing ever. The only problem was, there didn't seem to be any other code that could block after having acquired this lock, and I wasn't using any other locks in my application.&lt;br /&gt;&lt;br /&gt;The reason I'm posting about this is because of what ended up being the cause of this. The code that was deadlocking was code bring run on Tkinter's main loop due to a call to tk.after_idle. It turns out that a call to after_idle outside of the event loop itself will block until the currently-running event, if any, finishes. External code was obtaining this lock and then trying to use after_idle. Because the event that would then proceed to attempt to acquire the lock itself was already running, after_idle would block. The event itself would then block.&lt;br /&gt;&lt;br /&gt;The solution I'm going to implement is to have a queue of events and a function that runs itself on the event loop 5 or so times every second, processing all the events in the queue. This isn't optimal, but it's the simplest solution I can see at present.&lt;br /&gt;&lt;br /&gt;So, the moral of the story is: after_idle doesn't just run its argument when the main loop is idle; it blocks completely until the main loop is idle. So be careful if you're using locks, and when in doubt, use your own queue and a periodic task that runs events in the queue.&lt;br /&gt;&lt;br /&gt;I also apologize for sounding like a dope in this post. I'm rather more tired than I usually am for some reason...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-1949581521834493456?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/1949581521834493456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=1949581521834493456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/1949581521834493456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/1949581521834493456'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2011/01/threading-locks-and-tkinters-afteridle.html' title='Threading, locks, and Tkinter&apos;s after_idle'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-3161248233270244508</id><published>2010-03-21T23:41:00.011-06:00</published><updated>2010-03-22T00:39:54.946-06:00</updated><title type='text'>Mathematical Hugs</title><content type='html'>I was at the FIRST robotics competition at the Huntsman Center up at the University of Utah with the rest of my team last Friday. We ended up not doing so well in the competition, but hey, it was way fun, and that's the main thing that counts.&lt;br /&gt;&lt;br /&gt;This is our first year competing as a team. Most teams have adult mentors that help them out; we managed to get 25 members for our team with all of zero mentors helping us. Because of that, we got an award at the Awards Ceremony Friday night. No-one on our team really thought we were going to get an award, though, so they all stayed in the pit. Only three people on my team (Morgan, Forrest, and I) went to the ceremony.&lt;br /&gt;&lt;br /&gt;So, we ended up getting the Rookie Inspiration Award, which was pretty cool. The three of us went down to claim the award and high-five the judges, and the three of us hugged before receiving the award.&lt;br /&gt;&lt;br /&gt;Now, me being the nerd that I am, I got thinking about that today. For three people to hug each other exactly once, you need three hugs. We'll number our people 1, 2, and 3. You need a hug between 1 and 2, a hug between 1 and 3, and a hug between 2 and 3. Makes sense.&lt;br /&gt;&lt;br /&gt;In fact, the formula for computing this ends up being 1+2+3+...+n, or (n&lt;sup&gt;2&lt;/sup&gt;+n)/2, where &lt;i&gt;n+1&lt;/i&gt; is the number of people that want to hug.&lt;br /&gt;&lt;br /&gt;So, because a single person generally can only hug one other person at the same time (meaning three people can't all hug each other at the exact same time for all intents and purposes concerned here), it takes three &lt;i&gt;units of time&lt;/i&gt;, a &lt;i&gt;unit of time&lt;/i&gt; being defined as the approximate time it takes two people to hug (which is obviously subjective and depends on how long they hug and other factors I'm not going to account for), for those three people to hug each other exactly once.&lt;br /&gt;&lt;br /&gt;So, I started thinking to myself, let's say more people from our team had shown up at the ceremony. Let's say four people had shown up. In order for each of the four people to hug each of the other four people exactly once, 6 hugs need to take place: 1-2, 1-3, 1-4, 2-3, 2-4, and 3-4. Since there are four people, only two hugs can take place over the course of a single unit of time. It would seem likely, then, that all 6 hugs could be completed in three units of time.&lt;br /&gt;&lt;br /&gt;So then I thought about how those people would hug depend on where they're standing. Let's imagine them standing in an approximate square, like this (click on the image to view a larger version):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0011.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0011.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1, 2, 3, and 4 are our people. We have three time periods, each a unit of time long, that we're looking at here: A, B, and C. The dotted lines represent a hug that occurs during that time period. As indicated by the image, during time period A, 1 and 3 hug, and 2 and 4 hug. During time period B, 1 and 2 hug, and 3 and 4 hug. During time period C, 1 and 4 hug, and 2 and 3 hug.&lt;br /&gt;&lt;br /&gt;There's just one problem: it's somewhat difficult for 1 and 4 to hug at the same time as 2 and 3 hug without having one of them walk around the other, since they would both be hugging through the center of the image (where the two C lines cross), which obviously wouldn't work. So this arrangement for completing all six hugs isn't going to work.&lt;br /&gt;&lt;br /&gt;That seems to necessitate at least some sort of movement on the part of the people involved in order to complete all of the hugs within three units of time. For example, just before time period 3, 2 and 4 could switch places with each other, and then the C lines would parallel the existing B lines and there wouldn't be a conflict. But then the people involved have to remember which time period they're supposed to switch at and who's supposed to switch. What if there was a directed cycle graph involving some of the people that would cause all of the hugs to be carried out in three time periods if the people move one vertex down the directed cycle graph before every time period? That would seem to be simpler.&lt;br /&gt;&lt;br /&gt;I set about finding such a directed cycle graph for the four person problem. In less than a minute I had found one that works. Not surprising, really, as there aren't many possible graphs when you only have four vertices.&lt;br /&gt;&lt;br /&gt;So, the graph I found is this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0012.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0012.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The dotted lines are the hugs that take place, and the arrows form the edges of the directed cycle graph. Three units of time need to elapse for each person to hug each other person, as established before. Between each time period, however, the people that are on the directed cycle graph (which is everyone except 4) move one edge down the graph. So 2 moves to where 3 is, 3 moves to where 1 is, and 1 moves to where 2 is.&lt;br /&gt;&lt;br /&gt;So, as shown on the graph, 1 and 2 hug and 3 and 4 hug during the first time period.&lt;br /&gt;&lt;br /&gt;Each person then moves down the graph by one position, so that the arrangement of people looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0013.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0013.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now 3 and 1 hug and 2 and 4 hug. This same process takes place once more, so now the arrangement of people looks like this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0014.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0014.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now 2 and 3 hug and 1 and 4 hug.&lt;br /&gt;&lt;br /&gt;So, here's the list of all of the hugs that needed to have taken place in order for all of the people to have hugged each other exactly once:&lt;ul&gt;&lt;li&gt;1 and 2 (took place in time period 1)&lt;/li&gt;&lt;li&gt;1 and 3 (took place in time period 2)&lt;/li&gt;&lt;li&gt;1 and 4 (took place in time period 3)&lt;/li&gt;&lt;li&gt;2 and 3 (took place in time period 3)&lt;/li&gt;&lt;li&gt;2 and 4 (took place in time period 2)&lt;/li&gt;&lt;li&gt;3 and 4 (took place in time period 1)&lt;/li&gt;&lt;/ul&gt;This directed cycle graph therefore solves our problem. So what if six people had shown up to the Awards Ceremony instead of just four?&lt;br /&gt;&lt;br /&gt;Before we move on to the problem of six people, I'd like to point out an interesting fact: both the three-person puzzle and the four-person puzzle have the same minimum time period requirement (three) despite the fact that the three-person puzzle only involves three hugs whereas the four-person puzzle involves six hugs. As I'll show either later in this post or in a future post, this is not a coincidence; Every odd-numbered group requires exactly the same number of steps to hug as the next even-numbered group above it, and this stems from the fact that the directed cycle graphs for these end up being almost identical.&lt;br /&gt;&lt;br /&gt;Now, on to the six-person version of the puzzle. We'll assume the people are standing in a circle. The vertices representing the people therefore form a hexagon. After a few minutes of trial and error, I found a graph that works for our hexagonal group of people:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0015.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0015.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As per the formula given above, 15 hugs are necessary in order for all six people to hug exactly once. Since we have six people, three hugs can take place concurrently, so we need a total of 5 units of time to complete all of the hugs. Each of those will obviously have a different arrangement people. Here are the five time periods for the directed cycle graph given above:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0016.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0016.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0017.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0017.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0018.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0018.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0019.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0019.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.opengroove.org/math-hugs/scan0020.png"&gt;&lt;img src="http://www.opengroove.org/math-hugs/scan0020.png" width="100px" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Cool, huh.&lt;br /&gt;&lt;br /&gt;So I made the mistake of trying to explain this whole puzzle to my mom. It took me quite a bit to explain it to her so that she could understand, and the only comment I could get out of her after that was that I should get some people together and actually try it and then post a video of it on the blog post. If you can't already tell, my mom is quite mathematically disinclined.&lt;br /&gt;&lt;br /&gt;Anyway, that's it for tonight. I will, however, mention that graphs for odd numbers look quite a bit different than graphs for even numbers. I'm working on some such graphs in my notebook; I'll post a followup entry with them in a few days.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-3161248233270244508?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/3161248233270244508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=3161248233270244508' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3161248233270244508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3161248233270244508'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/03/mathematical-hugs.html' title='Mathematical Hugs'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-7699630927377669235</id><published>2010-02-27T23:15:00.004-07:00</published><updated>2010-02-27T23:17:11.777-07:00</updated><title type='text'>JZBot now supports Facebook!</title><content type='html'>I finally got Facebook support for JZBot/Marlen working!!! If you have a facebook account, add Marlen as a friend and start chatting. Marlen's Facebook profile is &lt;a href="http://facebook.com/marlenjackson"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-7699630927377669235?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/7699630927377669235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=7699630927377669235' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7699630927377669235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7699630927377669235'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/02/jzbot-now-supports-facebook.html' title='JZBot now supports Facebook!'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-5878824424787007258</id><published>2010-02-17T16:40:00.002-07:00</published><updated>2010-02-17T16:42:58.298-07:00</updated><title type='text'>JZBot now supports XMPP/GMail</title><content type='html'>As usual with my posts, this is probably 2 weeks late, but JZBot now supports XMPP (and therefore GMail Chat)!!! Add multimarlen@opengroove.org as a contact and send "hi" in a chat message to him, or "lart Alex". multimarlen will automatically let you chat with him when he's online.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-5878824424787007258?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/5878824424787007258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=5878824424787007258' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/5878824424787007258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/5878824424787007258'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/02/jzbot-now-supports-xmppgmail.html' title='JZBot now supports XMPP/GMail'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-2242560177734597636</id><published>2010-02-17T16:05:00.001-07:00</published><updated>2010-02-17T16:06:25.753-07:00</updated><title type='text'>Another awesome ThinkGeek shirt</title><content type='html'>&lt;a href="http://www.thinkgeek.com/a69c/"&gt;This shirt&lt;/a&gt; is now my favorite ThinkGeek shirt ever.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-2242560177734597636?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/2242560177734597636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=2242560177734597636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/2242560177734597636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/2242560177734597636'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/02/another-awesome-thinkgeek-shirt.html' title='Another awesome ThinkGeek shirt'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-7316044807345356593</id><published>2010-02-08T18:38:00.003-07:00</published><updated>2010-02-08T18:41:45.952-07:00</updated><title type='text'>Gummy Heart</title><content type='html'>While browsing ThinkGeek for other random valentines stuff (see my last blog post), I came across another of their new products, a &lt;a href="http://www.thinkgeek.com/caffeine/wacky-edibles/d19a/"&gt;gummy heart&lt;/a&gt;. And by "heart", I mean it looks like a real human heart, not like a stereotypical valentine's heart. Sheer awesomeness, except for the one fact that it's caffeinated (I hope I'm not the only one out there that gets major headaches from caffeine).&lt;br /&gt;&lt;br /&gt;But yeah, that's my only real gripe against ThinkGeek, is that almost all of their foodstuff is caffeinated to the point that it would be more against the Word of Wisdom than coffee would. I hope they start to sell uncaffeinated versions of some of their products, although knowing ThinkGeek, they won't anytime soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-7316044807345356593?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/7316044807345356593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=7316044807345356593' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7316044807345356593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7316044807345356593'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/02/gummy-heart.html' title='Gummy Heart'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-7176361974560631494</id><published>2010-02-01T21:28:00.005-07:00</published><updated>2010-02-08T18:43:35.048-07:00</updated><title type='text'>How to date a geek guy</title><content type='html'>Just ran across this while searching for some excerpts from ThinkGeek's latest book, &lt;a href="http://www.thinkgeek.com/ac84/"&gt;A Girl's Guide to Dating a Geek&lt;/a&gt; (although this ended up not being an except specifically from the book):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://penguinpetes.com/b2evo/index.php?title=one_for_the_ladies_how_to_date_a_geek_gu&amp;amp;more=1&amp;amp;c=1&amp;amp;tb=1&amp;amp;pb=1"&gt;http://penguinpetes.com/b2evo/index.php?title=one_for_the_ladies_how_to_date_a_geek_gu&amp;amp;more=1&amp;amp;c=1&amp;amp;tb=1&amp;amp;pb=1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is one of the more awesome posts I've seen on the internet, cause it's totally true (especially #2 and somewhat #5). I'm tempted to add this under some title to my "You know you're a geek when..." page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-7176361974560631494?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/7176361974560631494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=7176361974560631494' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7176361974560631494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7176361974560631494'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/02/how-to-date-geek-guy.html' title='How to date a geek guy'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-7457796732937102470</id><published>2010-01-27T15:33:00.004-07:00</published><updated>2010-02-02T22:38:24.456-07:00</updated><title type='text'>JZBot now supports BZFlag</title><content type='html'>This is about a week late, but JZBot can now connect to &lt;a href="http://bzflag.org"&gt;BZFlag&lt;/a&gt; servers. If you're a bzflag server owner and want a bot at your server for some random reason, you can download JZBot at &lt;a href="http://jzbot.googlecode.com"&gt;http://jzbot.googlecode.com&lt;/a&gt;. Or join irc.freenode.net #jzbot and ask for help.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-7457796732937102470?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/7457796732937102470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=7457796732937102470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7457796732937102470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7457796732937102470'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/01/jzbot-now-supports-bzflag.html' title='JZBot now supports BZFlag'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-9054164227546498395</id><published>2010-01-23T01:48:00.003-07:00</published><updated>2010-01-23T01:51:12.951-07:00</updated><title type='text'>Geeky to the Max</title><content type='html'>From &lt;a href="http://dudle.us/2010/01/23/geeky-to-the-max/"&gt;MrDudle's blog&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&amp;lt;C0BALT&gt; I also use OCR from MSPaint when I’m really getting serious about coding.&lt;br /&gt;&amp;lt;Limp_Trizkit&gt; oh, when i’m really serious, i pull out my screwdriver and some magnets&lt;br /&gt;&amp;lt;Limp_Trizkit&gt; and take apart the hard drive with my code&lt;br /&gt;&amp;lt;Limp_Trizkit&gt; then use the magnets to flip the bits by hand&lt;br /&gt;&amp;lt;Limp_Trizkit&gt; then reassemble the drive and compile&lt;br /&gt;&amp;lt;C0BALT&gt; I never thought of that!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-9054164227546498395?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/9054164227546498395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=9054164227546498395' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/9054164227546498395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/9054164227546498395'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/01/geeky-to-max.html' title='Geeky to the Max'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-7778897824289324774</id><published>2010-01-15T19:35:00.001-07:00</published><updated>2010-01-15T19:36:49.547-07:00</updated><title type='text'>You know you're a geek when...</title><content type='html'>I'm working on a list of "You know you're a geek when..." phrases &lt;a href="http://sites.google.com/a/opengroove.org/javawizard/you-know-you-are-a-geek-when"&gt;here&lt;/a&gt;. I'll be adding to it periodically, so keep checking it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-7778897824289324774?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/7778897824289324774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=7778897824289324774' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7778897824289324774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/7778897824289324774'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/01/you-know-youre-geek-when.html' title='You know you&apos;re a geek when...'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-8673988568673979671</id><published>2010-01-06T02:17:00.003-07:00</published><updated>2010-01-06T02:18:37.385-07:00</updated><title type='text'>Fact interpreter in Python</title><content type='html'>On request of another guy involved in JZBot, I ported JZBot's Fact interpreter to Python. It's available in the JZBot Subversion repository at &lt;a href="http://jwutils.googlecode.com/svn/trunk/projects/jzbot2-python/fact-parser/"&gt;http://jwutils.googlecode.com/svn/trunk/projects/jzbot2-python/fact-parser/&lt;/a&gt;. src/test.py under that directory is a Python script demonstrating how to use the interpreter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-8673988568673979671?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/8673988568673979671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=8673988568673979671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/8673988568673979671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/8673988568673979671'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/01/fact-interpreter-in-python.html' title='Fact interpreter in Python'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-6340628662841049158</id><published>2010-01-01T22:56:00.004-07:00</published><updated>2010-01-01T23:09:30.227-07:00</updated><title type='text'>libusbJava.so</title><content type='html'>For some reason, &lt;a href="http://libusbjava.sf.net/"&gt;libusbJava&lt;/a&gt; did &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; want to compile on my linux s&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;ystem. It consistently issued warnings that some "libusbpp.so" (which I still have yet to figure out what the heck it is) was missing. I did some googling, and eventually managed to compile it by hand using this command:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;g++ -shared -Wl,-soname,libusbJava.so -I/usr/lib -I/usr/lib/jvm/java-6-sun-1.6.0.16/include -I/usr/lib/jvm/java-6-sun-1.6.0.16/include/linux -shared LibusbJava.cpp -olibusbJava.so.0.2.4 /usr/lib/libusb.a&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Note that the &lt;span style="font-family:courier new;"&gt;/usr/lib/jvm/java-6-sun-1.6.0.16&lt;/span&gt; paths are specific to whatever version of java you're using.&lt;br /&gt;&lt;br /&gt;Anyway, with that taking upwards of an hour to do, I figured I'd post a pre-built binary for anyone that's looking for one. This was built on Ubuntu 9.04 against libusb-0.1-4 (Synaptic reports its version number to be 2:0.1.12-13; I'm not knowledgable enough to know the difference between the two), so I won't make any guarantees as to whether it will work properly on your system. You can download the binary &lt;a href="http://sites.google.com/a/opengroove.org/javawizard/files-1/libusbJava.so.0.2.4"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-6340628662841049158?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/6340628662841049158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=6340628662841049158' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6340628662841049158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6340628662841049158'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2010/01/libusbjavaso.html' title='libusbJava.so'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-3272737704205528608</id><published>2009-11-28T19:35:00.003-07:00</published><updated>2009-11-28T20:30:52.835-07:00</updated><title type='text'>SuperTunnel</title><content type='html'>Due to some problems I encountered while using GNU HttpTunnel (namely that HttpTunnel would get packets in the wrong order when I was trying to forward ports over SSH over HttpTunnel and cause SSH to disconnect with a failed MAC error), I decided to write an alternative. My dad's work firewalls all outbound traffic besides HTTP and HTTPS, which greatly inconvienences me when I go to work with him as I can't upload new versions of &lt;a href="http://evaluationportal.com/"&gt;Evaluation Portal&lt;/a&gt; or &lt;a href="http://jzbot.googlecode.com/"&gt;JZBot&lt;/a&gt; to my web server.&lt;br /&gt;&lt;br /&gt;Anyway, the alternative is called &lt;a href="http://supertunnel.googlecode.com/"&gt;SuperTunnel&lt;/a&gt;. There are three main differences between SuperTunnel and HttpTunnel:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;HttpTunnel has a tendency to get packets out of order when processing high-volume traffic. This caused SSH to repeatedly crash when I would use it to forward ports over HttpTunnel. SuperTunnel does not do this; I've verified that it works when both downloading and uploading data as fast as SuperTunnel will send and receive it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;HttpTunnel only allows one socket connection to be active at a time. SuperTunnel allows up to 200 concurrent connections, and in the future that limit will be specified by a configuration file.&lt;/li&gt;&lt;li&gt;HttpTunnel uses requests that are long-lived in the sense that a single request will be opened and data streamed down through it as data is received by the server. Since this causes problems with buffering proxies, SuperTunnel instead follows an approach where a single connection will only be used once to receive data. Once even a single byte is received, the connection ends and a new one is made. SuperTunnel waits one second between receive connections so that an excessive number of connections aren't made with each one holding only a couple of bytes.&lt;/li&gt;&lt;/ul&gt;Instructions are present at &lt;a href="http://supertunnel.googlecode.com/"&gt;http://supertunnel.googlecode.com&lt;/a&gt; on how to download SuperTunnel. Currently, you'll have to check out the Subversion repository SuperTunnel is stored in. I plan on making a direct download available soon. You'll also need your own server to run SuperTunnel on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-3272737704205528608?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/3272737704205528608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=3272737704205528608' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3272737704205528608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3272737704205528608'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/11/supertunnel.html' title='SuperTunnel'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-6594816878533958526</id><published>2009-11-07T17:20:00.001-07:00</published><updated>2009-11-07T17:22:02.521-07:00</updated><title type='text'>Wave Othello Gadget</title><content type='html'>A few days ago, I spent a day and wrote a Google Wave Othello gadget. The gadget's URL is &lt;a href="http://trivergia.com/wavyothello/gadget/jw.othello.client.OthelloGadget.gadget.xml"&gt;http://trivergia.com/wavyothello/gadget/jw.othello.client.OthelloGadget.gadget.xml&lt;/a&gt;. Add it to a wave, play a game with a friend, and add a comment to this post and let me know how it went or if there are any new features you'd like.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-6594816878533958526?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/6594816878533958526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=6594816878533958526' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6594816878533958526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6594816878533958526'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/11/wave-othello-gadget.html' title='Wave Othello Gadget'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-837899018207205977</id><published>2009-10-17T00:57:00.005-06:00</published><updated>2009-10-17T01:24:07.252-06:00</updated><title type='text'>Single-file IRC server</title><content type='html'>Those of you that know what IRC is are probably already thinking I'm off my rocker, given the title of this post. And I probably am. I decided to try my hand at writing an IRC server in a single Java file. I've got it to the point that people can connect to it, join channels, set the channel topic, send messages (and receive them) at channels, send private messages, and change nicks, so I figured I'd blog about it and include a link to it if anyone wants to use it. It's not intended to become a production IRC server; I'm mostly writing it so that I can test out an IRC bot that I'm writing when I don't have an internet connection.&lt;br /&gt;&lt;br /&gt;Anyway, &lt;a href="http://jwutils.googlecode.com/svn/trunk/projects/jircs/src/Connection.java"&gt;here&lt;/a&gt;'s the source code for the server. Download it, compile it with "javac Connection.java", and then run it with "java Connection &amp;lt;hostname&gt;", replacing &amp;lt;hostname&gt; with your computer's hostname. If you're not sure what your computer's hostname is, just use &lt;span style="font-style: italic;"&gt;localhost&lt;/span&gt; as the hostname. Then, open your favorite IRC client, connect to "127.0.0.1:6667", and join any channel you want. You can switch nicks, set the channel's topic (even though you're not a channel op), and other users can connect, join channels, and chat with you. Sending messages directly between users also works. Modes do not, however (channels always act as if they are mode +nt, no matter what you set their mode to be, but anyone can change the topic even though the channels have +t present). I'm hoping to add more functionality to this server soon.&lt;span style="display: block;" id="formatbar_Buttons"&gt;&lt;span class="on down" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;img src="http://www.blogger.com/img/blank.gif" alt="Link" class="gl_link" border="0" /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-837899018207205977?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/837899018207205977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=837899018207205977' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/837899018207205977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/837899018207205977'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/10/single-file-irc-server.html' title='Single-file IRC server'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-3054193334570127875</id><published>2009-10-17T00:51:00.002-06:00</published><updated>2009-10-17T00:57:19.824-06:00</updated><title type='text'>Java Proxy instance throws a NullPointerException</title><content type='html'>This is something I just found out, and I figured I'd blog about it for those that might come across this in the future.&lt;br /&gt;&lt;br /&gt;I'm writing some code in a project (JZBot specifically, &lt;a href="http://jzbot.googlecode.com"&gt;http://jzbot.googlecode.com&lt;/a&gt;) that uses java.lang.reflect.Proxy. At one point, I was calling a method on a proxy instance, and it was throwing a NullPointerException. The weird thing about this was that the NullPointerException was being thrown from within the proxy instance itself, not from the InvocationHandler that it is supposed to call. Other methods on the proxy worked, indicating that there wasn't some error with the invocation handler somehow being set to null.&lt;br /&gt;&lt;br /&gt;Eventually, I found the problem: I had declared the method on the interface that the proxy implemented to return a boolean, but the invocation handler was returning null. The auto-unboxing that was being done by the proxy instance internally was messing things up. I changed the method's return type to void (which is what it should have been), and everything worked.&lt;br /&gt;&lt;br /&gt;This is yet another example of where to watch out for autoboxing and unboxing. Admittedly, it would be more helpful if the NPE had a message stating something like, for example, "null can't be unboxed to a boolean", which would most likely have saved me quite a bit of time. Oh well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-3054193334570127875?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/3054193334570127875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=3054193334570127875' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3054193334570127875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/3054193334570127875'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/10/java-proxy-instance-throws.html' title='Java Proxy instance throws a NullPointerException'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-4355946306383459478</id><published>2009-09-10T19:26:00.004-06:00</published><updated>2009-09-10T19:34:13.815-06:00</updated><title type='text'>Airplane problem simulator</title><content type='html'>I just got back from a party where a friend of mine told me the classic "Airplane seating problem", and the resulting answer. The answer was somewhat hard for me to believe, so, since I had brought my laptop, I pulled it out and spent 10 minutes writing this program to simulate the airplane problem. It turns out that the answer he had told me is correct. I'll be darned.&lt;br /&gt;&lt;br /&gt;Anyway, here's the program, written in Java. Paste it into a file called PlaneSim.java, run "javac PlaneSim.java" and then "java PlaneSim" to run it. The javadoc at the beginning of the program explains what the airplane problem is, in case you haven't heard of it before.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;import java.util.Random;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * There's a common puzzle that goes something like this: There's a plane that&lt;br /&gt; * has 100 seats in it. Each person has a ticket that assigns them to a&lt;br /&gt; * particular seat. However, the first person doesn't follow his ticket, instead&lt;br /&gt; * choosing a random seat to sit in. Each successive person tries to sit in the&lt;br /&gt; * seat listed on their ticket. If that seat is already taken, they choose a&lt;br /&gt; * random vacant seat to sit in. This goes on until all 100 passengers have been&lt;br /&gt; * seated. What is the chance that the last person will be in his correct seat?&lt;br /&gt; * The puzzle's correct answer is 0.5 (IE he's in his correct seat about half of&lt;br /&gt; * the time on average). This program simulates the airplane problem several&lt;br /&gt; * thousand times to verify this answer, and it does, indeed, verify that 0.5 is&lt;br /&gt; * the correct answer.&lt;br /&gt; * &lt;br /&gt; * @author Alexander Boyd&lt;br /&gt; * &lt;br /&gt; */&lt;br /&gt;public class PlaneSim&lt;br /&gt;{&lt;br /&gt;    private static int seatcount;&lt;br /&gt;    &lt;br /&gt;    /**&lt;br /&gt;     * @param args&lt;br /&gt;     */&lt;br /&gt;    public static void main(String[] args)&lt;br /&gt;    {&lt;br /&gt;        seatcount = 100;&lt;br /&gt;        // Run 100,000 simulations&lt;br /&gt;        int simcount = 100000;&lt;br /&gt;        int correctTimes = 0;&lt;br /&gt;        for (int i = 0; i &lt; simcount; i++)&lt;br /&gt;        {&lt;br /&gt;            correctTimes += ((sim() == (seatcount - 1)) ? 1 : 0);&lt;br /&gt;        }&lt;br /&gt;        System.out.println("Simulation count: " + simcount);&lt;br /&gt;        System.out.println("Last person was in correct seat " + correctTimes&lt;br /&gt;                + " times");&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static int sim()&lt;br /&gt;    {&lt;br /&gt;        int[] seats = new int[seatcount];&lt;br /&gt;        // Change all seats to be empty&lt;br /&gt;        for (int i = 0; i &lt; seats.length; i++)&lt;br /&gt;        {&lt;br /&gt;            seats[i] = -1;&lt;br /&gt;        }&lt;br /&gt;        // Run the simulation&lt;br /&gt;        for (int i = 0; i &lt; seatcount; i++)&lt;br /&gt;        {&lt;br /&gt;            if (i == 0)&lt;br /&gt;            {&lt;br /&gt;                // First person, so random seat&lt;br /&gt;                seats[random()] = 0;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                // Put this person in their seat if it's empty&lt;br /&gt;                if (seats[i] == -1)&lt;br /&gt;                {&lt;br /&gt;                    seats[i] = i;&lt;br /&gt;                }&lt;br /&gt;                // If it's not empty, randomly place this person until we get an&lt;br /&gt;                // empty seat to put them in.&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    int randomIndex = random();&lt;br /&gt;                    while (seats[randomIndex] != -1)&lt;br /&gt;                        randomIndex = random();&lt;br /&gt;                    seats[randomIndex] = i;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        // Simulation is done. Now see who's in the last seat.&lt;br /&gt;        return seats[seatcount - 1];&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private static Random random = new Random();&lt;br /&gt;    &lt;br /&gt;    public static int random()&lt;br /&gt;    {&lt;br /&gt;        return random.nextInt(seatcount);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-4355946306383459478?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/4355946306383459478/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=4355946306383459478' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/4355946306383459478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/4355946306383459478'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/09/airplane-problem-simulator.html' title='Airplane problem simulator'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-8617010309342255578</id><published>2009-09-04T14:23:00.002-06:00</published><updated>2009-09-04T14:28:17.206-06:00</updated><title type='text'>Natural bee repellant</title><content type='html'>This is a new discovery made by my mom that I figured might be helpful  to other people. In our yard, we grow spearmint. I don't remember exactly why she tried using it against bees, but placing a cutting of spearmint on our picnic table has proved to be a very effective bee repellant. Like I mean one day we were getting swarmed with meatbees while eating outside, so we put a cutting of spearmint on the table, and we didn't see a single bee after that. So if you want to get rid of bees, plant spearmint and use cuttings of it whenever you eat outdoors.&lt;br /&gt;&lt;br /&gt;And if you're going to plant some spearmint, I should probably tell you that it's extremely agressive in terms of spreading by root. So plant it in a pot for best results.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-8617010309342255578?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/8617010309342255578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=8617010309342255578' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/8617010309342255578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/8617010309342255578'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/09/natural-bee-repellant.html' title='Natural bee repellant'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-6843073948767712045</id><published>2009-08-07T10:19:00.001-06:00</published><updated>2009-08-07T10:20:42.458-06:00</updated><title type='text'>A test blog post</title><content type='html'>I'm posting this with a GNOME applet to see if it works. So everyone can pretty much ignore this post.&lt;br /&gt;&lt;br /&gt;UPDATE: it appears to work, except that it doesn't place the title correctly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-6843073948767712045?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/6843073948767712045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=6843073948767712045' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6843073948767712045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/6843073948767712045'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/08/test-blog-post.html' title='A test blog post'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4107175839454033511.post-9056974162565987658</id><published>2009-07-07T11:48:00.003-06:00</published><updated>2009-07-07T11:59:19.784-06:00</updated><title type='text'>Chinese Firebox</title><content type='html'>This one is my dad's brainchild. He came up with the design for it a couple of years ago, and we've built one at my grandma's every 4th/24th that we're there since. Here's a video:&lt;br /&gt;&lt;object height="265" width="320"&gt;&lt;param name="movie" value="http://www.youtube-nocookie.com/v/BF9tdjpBq3A&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube-nocookie.com/v/BF9tdjpBq3A&amp;amp;hl=en&amp;amp;fs=1&amp;amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="265" width="320"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Cool, huh. The whole thing is made with the contents of 24 crackle bombs (the little green round things about the size of a smoke bomb). It takes its name from the fact that the actual firework, once built, looks like a miniature take-out box from a Chinese restaurant. I'll post instructions on how to make one, along with some pictures of the actual firework, sometime in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4107175839454033511-9056974162565987658?l=me.opengroove.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://me.opengroove.org/feeds/9056974162565987658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4107175839454033511&amp;postID=9056974162565987658' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/9056974162565987658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4107175839454033511/posts/default/9056974162565987658'/><link rel='alternate' type='text/html' href='http://me.opengroove.org/2009/07/chinese-firebox.html' title='Chinese Firebox'/><author><name>Alex Boyd</name><uri>http://www.blogger.com/profile/07059716142223945493</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
