sixtyPercent: Cochlear Implants, Aviation, Technlology, and Philosophy 2005
Two Flying Books: 'Solo' and 'Cannibal Queen'
Somehow I recently found the time to read a couple more books on flying: Clyde Edgerton's Solo: My Adventures In The Air, and Stephen Coonts' The Cannibal Queen.
Both authors are ex-fighter pilots with Vietnam War experience; both are successful authors of fiction; and these two books represent something of a departure into auto-biographical writing. Given these similarities, it seems reasonable to lump together a quick review of each into a single blog posting.
I wanted to like Cannibal Queen more than I did. I'm very fond of the "setting off on a flight of discovery" genre -- two great examples of which are Mariana Gosnell's Zero Three Bravo and Rinker Buck's Flight Of Passage. In Coonts' variation on this theme, he sets of with his teenage son in an open cockpit biplane, and eventually flies to all fourty-eight states in the continental US. The book mixes excellent descriptions of the flying with somewhat forced philosophical pronouncements. There are a few nice moments of non-flying -- such as when Coonts' visits his hometown, but mostly you'd want to read this book for the flying.
Solo describes in a fair amount of (never boring) detail Edgerton's training as a pilot -- from student pilot in a Piper Cherokee 140 to a fighter pilot for the US Air Force in an F-4. Edgerton spends most of the book describing the training and related experiences, and always made me feel as if I were along for the ride. His description of primary flight instruction mirrored my own in many ways, and once this connection was established in the first few chapters I was hooked. I finished the book in one sitting. Only at the end does he venture in some depth about how the flying and war experiences influenced his life. That part was enjoyable too -- perhaps because Edgerton focuses on how his flying shaped him, rather than taking Coonts approach of trying to relate it to the human condition in general.
Solo felt like a book that wanted to be written -- Cannibal Queen felt more like a contractual obligation. The latter does have nicer pictures though :-) .
by David Creemer : 2005/12/30 : Categories flying books : 0 trackbacks : 0 comments (permalink)
Looking back on our Cochlear Implant Journey
Looking back on my blog entries and other CI Pages on this site, I notice that I've never really talked about some of our experiences from birth to now that may be of interest to others.
Our kids were lucky enough to be born at Lucille Packard Children's Hospital, where there is a newborn hearing screening program. We essentially knew right away that Brendan was deaf (technically a profound hearing loss) and he was wearing hearing aids at nine weeks old. I have only one complaint about that whole process, and it's more like a wish: I wish we had received a "congratulations, you have a deaf child -- now here's the 10 steps to follow and people to call in the Bay Area" pamphlet. The staff at the hospital tried to help, but their program was not that mature at the time.
But we soon identified most of the Bay Area's deaf education resources, and dove headfirst in to the various Sign / Oral / Total Communication / etc. debates. We evaluated our options and pushed forward. Before too long we were pretty sure that he was not getting any benefit from the hearing aids and we knew we needed a plan B. This turned out to be a cochlear implant, and on his first birthday, Brendan had CI surgery done by Dr. Roberson of California Ear Institute.
On his implant activation a few weeks later, we knew right away that he could hear something. Though he was hearing right away, it was more than two years before he could really talk.
Over those two years we knew he obviously was hearing and responding, so we kept "pouring language into him." He attended an oral deaf education school and we focused our lives on his success. Eventually he began to talk, and rapidly increased his expressive vocabulary. We used to keep a list of words he could say, but that quickly became a futile effort. By the time he entered kindergarten at age five, there wasn't even a question of a vocabulary deficiency. At the end of kindergarten his vocabulary was beyond what one would expect to see for someone ending the first grade.
Brendan's speech is indistinguishable from his peers (and often better -- probably due to working on it), and his hearing is amazing. Though he doesn't hear as well as his peers, he uses no extra assistive devices and participates in all class activities, including music. He can talk on the telephone (with either implant), whisper, and sing. Many people we meet simply do not believe he's deaf.
I can only guess as the sources of Brendan's success with his Cochlear Implants. Much of the credit goes to the device manufacturer, surgeon, and habilitation team of course. We (his parents) worked hard to find the best options we could, and then continued to focus on what it takes to get to a successful outcome. And of course I think Brendan himself deserves a lot of credit -- he's cheerfully accepted every challenge in front of him, and that's made all of our tasks much more pleasant.
by David Creemer : 2005/12/28 : Categories cochlear_implants (permalink)
Nucleus Freedom BTE Cochlear Implant Speech Processor
Brendan uses bilateral cochlear implants to hear. We have now had about half a year of experience with the new Freedom BTE. As I discuss on the in-depth Cochlear Implants page, I'm very please with the results. His hearing on the new (left) side is excellent -- he can even talk on the phone with just the new processor, and is beginning to show some localization abilities.
Adults I've spoken to about this processor report that it's physically more comfortable to wear than the "old" 3G processor, which is great. As a parent responsible for the day to day operation of the device, I do feel that the "UI" of the basic functions has taken a step backward. By far the most common thing Brendan does with the processor is turn it on or off -- typically four times a day -- everything else is a far distant second. On the 3G, there's a physical switch that can be operated by feel.
One the Freedom, however, one must first push the top button, and then observe the tiny LCD to be sure to have cleared the H3 (coil off) error code. Then you push and hold the same button until the device turns off. If you push and hold for too short of a time, you've just changed the default program, and then have to cycle through the three other programs to get back. If you push and hold before you clear the H3 error code, then nothing happens and you've wasted your time. It's impossible to do by feel alone.
The 3G switch might have been less reliable (don't know), and probably physically harder to integrate into a small package, but it's sure easy to use.
by David Creemer : 2005/12/21 : Categories cochlear_implants (permalink)
Towards a Fully-Implantable Cochlear Implant
Several companies seem to be working on fully-implantable cochlear implants. Med-El -- one of the three major cochlear implant manufacturers, already has an implantable hearing aid on the market, so I guess they are at least researching it. (See http://www.symphonix.com).
Also, Envoy Medical of Minneapolis has a product which from their description also looks like a fully implanted cochlear implant. Since they have no track record with external implants (as far as I can tell) I am a bit concerned about their ability to produce a competitive product. I hope they are working with an established implant company or at least have hired a bunch of experienced implant scientists.
Either way the progress is exciting. When we made the decision to get a cochlear implant for our son, we recognized the like all technology, these products would get much better very quickly. The rigors of medical certification slow the pace of advancement down a bit -- with good reason I suppose, but in general the any given CI seems "out of date" within a two or three years. No matter -- Brendan hears perfectly well, we can manage the system, and have even developed ways of handling situations like talking in the pool.
The most frequently asked question about a fully implanted CI or hearing aid seems to be "where does the microphone go?". Silly question! Where's the microphone in your ear? Built right in, of course! The technical challenges seems to be finding a way to interface the implanted processor with the eardrum and / or middle ear bones. The results must be acceptable enough for Vibrant/Med-El to ship a hearing aid based on this technology.
The other issue is battery life -- most rechargeable batteries have a useful life of a limited number of cycles. Assuming something like one day of use per charge, and 1000 cycles, that means one would need to replace the battery after three years. Surgery every three years doesn't sound fun, but I can see other possibilities. Perhaps an external battery can be used some of the time (especially if it looks / works much like an existing CI processor). This sort of approach might double the life of the internal battery, and surgery every six years doesn't seem too bad. Battery technology doesn't seem to advance quite as fast as CI's, but perhaps the first battery might last six years, and the replacement might be good for twelve. That doesn't seem too bad.
So would we upgrade? Nope. Our results are way better than I had hoped, and someday soon Brendan will be old enough to make his own decisions on these matters. It's also one of the reasons we decided on bilateral implants. Someday he may want to "upgrade" without running the risk of losing all sound.
by David Creemer : 2005/12/19 : Categories cochlear_implants : 0 trackbacks (permalink)
Doonesbury on Creationism
This Doonesbury strip hits the nail right on the head in the Creationism debate.
Frankly, I have a lot of respect for strict, young-Earth literal creationists -- many seem to have a very internally consistent view. But the rest of us are just a bunch of theological wimps (in my unlearned opinion).
"I like creationism but I'm happy to benefit from modern science and medicine...". Bzzzzt. No picking and choosing allowed! And remember, if you wear that 50-50 wool/cotton blend sweater your sweet old grandmother gave you, you're in big trouble too. (Really -- look it up, Leviticus 19:19).
by David Creemer : 2005/12/18 : Categories rants (permalink)
Narnia and Syriana
I found myself with a bit of extra time this weekend, so I decided to treat myself to two currently-in-the-theatre movies, instead of the usual after-the-kids-are-asleep DVD's.
On Saturday I saw the Chronicles of Narnia: The Lion, The Witch, and the Wardrobe, which is sadly, well -- crap. The graphics are great of course, and like the marketing campaign must have cost a lot of money. What wasn't good was essentially everything else. The acting was weak, the script not so good, the direction was shaky, and frankly I'm not sure who the target audience is supposed to be. Like many people, I read C.S. Lewis' books as a kid, but the movie couldn't transport me back to the enjoyable fantasy adventures I remember. The film is certainly too violent for young kids, and too poorly done for adults, so all that's left is the 10-12-ish year old crowd.
The comparison between this and the Lord of the Rings movies is inevitable and probably proper. Peter Jackson (Rings) obviously loved and studied Tolkein's stories. The most hard-core of Tolkein fans may not forgive him for leaving out a favorite scene or character (e.g. Tom Bombadil) but I he certainly got many of the important parts across, while never forgetting to tell his own great story (especially in the Extended Edition DVDs). The same cannot be said of Andrew Adamson's Narnia adaptation. When the film's Aslan refers to the "deep magic", not only did I not get what he was talking about, but I got the impression the writers didn't either.
Oh well. Syriana on the other hand is a really good film. I'm in no position to comment on how close the film comes to portraying the "true" reality of its topic, but it sure left me believing they hit the mark right on. Like its spiritual predecessor Traffic, Syriana takes you into a world most of us know nothing about but with which we are all intimately connected (petro-politics in this case). Stephen Gaghan tells the story of high-intrigue and geopolitics through the personal lives of a half-dozen peope -- all with quite different perspectives, but of course all in some way linked. Educational without being preachy, Syriana is an excellent antidote to the usual "feel-good" movies of the season. It's the kind of film I will be thinking about for many weeks.
by David Creemer : 2005/12/18 : Categories film : 0 trackbacks : 3 comments (permalink)
Blocking Junk Fax Spam with Asterisk
We have a fax machine in our master bedroom (don't ask), and eventually the fax spammers got ahold of the phone number. Pretty soon the middle of the night beeps and noises became intolerable, and I began to look around for a solution. Junkbusters has tons of great advice for taking legal action against the criminals sending this crap, but I don't have the time to do this, unlike, say Steve Kirsch.
Looking for a quick technical solution (ok so everything looks like a nail to me), I developed a simple, but pretty effective approach using Asterisk. Asterisk is a telephony server that I already run in our home, handling things like long-distance least-cost routing, and so on basically I'm using it as a IP-PBX. It's also wonderfully programmable, and has a decent 3rd party soft fax addition.
Now when we get a fax call, Asterisk picks up the line and check for caller-ID. If available, and the number isn't in a blacklist (or is in the whitelist), then the fax goes to our fax machine. If there's no caller-ID, then Asterisk plays the special information tone (SIT), then the fax goes to the soft fax, and then emailed to me (where it's usually deleted).
The SIT or "Tele-zapper" tones is the sound one gets before the familiar "we're sorry, that number..." when something is wrong with a call (at least in North America). This may help remove our phone number from the junk faxer's lists.
The results are quite good though not perfect. We've gone from about 1 fax per night, down to about 1 every couple of months.
by David Creemer : 2005/12/15 : Categories technology : 0 trackbacks : 0 comments (permalink)
Beatles Mashups and Other iPod Filler
I've been actively seeking out and listening to more mashups recently. I was introduced to The Grey Album by a friend, and that began my quest to learn a bit more and find other underground treasures.
Recently I stumbled into CCC's Revolved -- a mashup of The Beatles Revolver album with a variety of other artists.
In a way it reminds me of a well done Saturday Night Live skit an excellent concept, well executed, but with something unknown missing. The best tracks to my mind are "Got To Get You In The Mood" which combines The Beatles "Got To Get You Into My Life" with Glenn Miller's "In The Mood", and "Close To No One", mixing The Beatles "For No One" with The Cure's "Close To Me". The Beatles seem to be a popular target for mashups -- perhaps due to DJ Dangermouse's "success" with the Grey Album, and perhaps just simply due to their popularity.
But even better than those is CCC's non-Beatles mash of "Stand By Me," featuring The Police's "Every Breath You Take" and of course Ben E King's "Stand By Me". The technical quality is great, and it's fun to watch the cognitive dissonance expressed in the faces of unsuspecting friends as the song plays out. It may not be a masterpiece like "99 Problems," but there's room for a lot of variety on a 60 GB iPod.
by David Creemer : 2005/12/15 : Categories music : 0 trackbacks : 0 comments (permalink)
Autism and Headwinds
There's a funny thing about flying small planes it always seems like no matter where or when I fly, I'm fighting a bit of a headwind. There's a logical explanation for this of course. If I fly due east at 100 knots, and the wind is from the east at 10 knots, then I will progress over the ground at 90 knots. But it's a bit more subtle if the wind is from the south. Assuming I still want to fly east, I'll need to point the plane just a tiny bit south perhaps to a heading of 095 degrees to counteract the wind's desire to push me off course. The result is I lose a tiny bit of forward speed, and just like that a crosswind turns into a headwind. Generalize that example a bit and you can see that in flying, more than half the time one faces a headwind.
A couple of years ago we discovered that our deaf son is also autistic. He is what one might call "high functioning" so it's not always obvious that something is a bit off especially at a very young age. But there are many things that are obviously not quite right. So we are facing yet another challenge just as felt like we were out of the woods with the first one. (See my discussion on Cochlear Implants to learn about how Brendan deals with deafness).
Not long after we received an "official" autism diagnosis, we began to notice other things. One day, I spilled an alphabet puzzle onto a table to play with Brendan. 26 pieces, each shaped differently and painted like an animal on one side. About half landed right-side up, and half upside-down. Brendan turned to me and said "where's the N?". I said "I don't know," and began flipping the pieces looking for the "N", which ultimately wasn't there. It turns out it was on the carpet.
Puzzled, I tried a different test. I flipped the pieces all upside down, took one out, and asked "what's missing?" You can see where this is going he could quickly tell which piece was missing, with just a glance at the collection of upside down pieces. Months later, he got a gift of three similar puzzles which were much like the original letter puzzle. It consisted of uppercase and lowercase letters, and numbers 1 - 25 so 77 pieces in all. I can pull out any piece, hold it up to him with the letter facing me (so he only sees the piece shape and color), and 9 times out of 10 he can identify the piece.
His memory seems endless and nearly perfect -- recalling calendars, lists, books, dates of events, and so on. He is also puzzlingly imperfect -- he can't or won't recall some things that seem obvious to me. He knows the names of all the kids in his class (in alphabetical order), but has trouble recognizing them especially out of context. He can usually remember the color key to any of the dozens of color-by-numbers he's done, but is only just now having real conversations.
He truly has some amazing gifts, not just despite of his challenges, but probably because of them.
I'm flying "uphill" again, fighting a headwind -- there always seems to be a headwind. But crap I'm flying! It's an amazing thing to see the sun light up the Sierra on a clear afternoon while flying down the California coast. At a few thousand feet in the air, I have a beautiful view of the mountains, but am still close enough to the sea below to appreciate the waves breaking on the cliffs. If the wind were at my back, I'd only land sooner.
by David Creemer : 2005/12/14 : Categories life flying autism : 0 trackbacks : 0 comments (permalink)
More on My Struggles With Missing Sync
Have I mentioned before that Missing Sync for Palm OS Version 5 is the worst application I have ever had the misfortune of owning? Oh yes, I have.
Here's another example why. At least twice a sync (which I almost never do, because it takes about 30 minutes), I see a dialog box like this:
Does anyone who doesn't work for Mark/Space know what this means? ... because I sure as crap don't.
So why haven't I uninstalled this yet? I'm too lazy / fearful of the extrication process and I know that I'll have to spend days cleaning up the three years worth of duplicated events in my wife's calendar to do it right. Actually, Missing Sync didn't create just duplicate events -- it seems to me to have created duplicate-duplicates for each and every un-timed repeating events. This software makes my wife mad at me.
by David Creemer : 2005/12/13 : Categories technology : 0 trackbacks : 3 comments (permalink)
Leonardo, Stolen Ideas and Cuban Cigars
My friends are updating their websites. Jason has seen the light and installed Leonardo (which power's this wiki-blog), and he's already made some nice additions, some of which are represented on this website. http://www.mischievous.org/blog is no longer so boring.
Also, Philip Haine has launched his interesting blog http://www.stealthisidea.com. Therein he vents many of the great ideas that seem to regularly pop out of his head, and encourages others to take them and run. I say "therein" because he also seems to be able to use words like philosophically, henceforth, and catharsis without blushing, so I feel the need to engage in some pseudointellectual appendification, perhaps to address feelings of inadequacy, or perhaps to continue the one-upmanshipizing.
Anyway, I like Phil's concept -- giving away ideas, so here's my...
Idea of the week
It's illegal to import Cuban cigars into the US, under the Trading With The Enemy Act. Reading the text, it seems like it's pretty much illegal to import just about anything from Cuba. However there are specific exceptions for "publications, artwork, or other informational materials".
Seemingly unrelated, is this news from "New Scientist" magazine of edible, vegatable and fruit based ink cartridges for ink-jet printers.
So here's my idea, which I won't do and I don't encourage anyone else to do: import cured Cuban tobacco leaves with the Constitution of the United States printed on the leaves. To my mind this fully qualifies under the law as a publication, informational material, and probably even a work of art. When the leaves come to the US, read them and put them on the wall as art. Of course, I can't find a law that says it's illegal to roll up a nice painting or book and smoke it...
And remember, IANAL.
by David Creemer : 2005/12/12 : Categories life ideas (permalink)
Building Scalable Web Applications With Python and PostgreSQL
During the workday, I work as a part of a tiny team building the MerchantCircle web application. Our application is built entirely in Python, XHTML, Javascript, and PostgreSQL. Someday we hope our site will be home to millions of users, but right now we're just getting going.
We started designing and building this application before the current crop of "hot" Python web application frameworks (TurboGears, Django, and Subway among others) hit the streets. It's very cool to see such rapid work and great thinking out loud about the various approaches to building these frameworks and the applications they support. Since we started before these tools were public, we built our own system. Since we're not crazy, we built it out of many of the same parts used by other frameworks: CherryPy, SQLObject, FormEncode, Cheetah Templates, memcached, Lighttpd and of course Linux.
But I'm in more of a "heads down, get it done" sort of role, and while I greatly enjoy learning about these systems and perhaps contributing a tiny bit to them, I mostly need to focus on our application. Fortunately, the Python language and the philosophy of the library and tools has made integrating all of these tools relatively easy. This "philosophy" isn't new I suppose -- the Python library tends to be composed of lots of little pieces that generally do one or two things very well, and that reminds me of the Unix way. When we needed wiki formatters or RSS parsers or soundex libraries, high quality implementations were almost always available.
Since nice frameworks like TurboGears and Django weren't yet available, we had to work through some issues of integration and scaling when combining all of these pieces. If I were starting now, this wouldn't be the case. In any event, as I said in my first sentence -- I spend my days building the application. I don't spend my time figuring out hot to validate form input or read data from the database or set cache control headers.
So how do you build scalable, Python based, Postgres-backed web applications? Come back in a year and I'm sure I'll know by then :-) In the mean time, I'll post more in-depth articles over the next days and weeks as to what we're doing, and here's a few things that our team has learned so far;
- Start with a solid base, such as from Django, my current favorite. As fun as it may be (for some) to write the next great web application framework, that's usually not the main point of the exercise.
- Think about database schema and queries all of the time. Spend a lot of time reducing database hits. We learned how to log queries taking longer then 500ms, and we study the logs. But don't worry to much about exotic, clustered databases, etc. It's amazing how many users can be handled by one (nice) box. Don't be afraid of stored procedures, pl-pgsql, triggers, and so on -- in fact embrace them and push as much as is reasonable to the DB layer.
- Don't be afraid of schema evolution -- worse is better. Develop good practices for migrating schema and data and then keep developing.
- Use lighttpd and squid, and aggressively cache static content and dynamic pages (as possible). Lighttpd is awesome.
- Design and build the middle layer (the application server) to be federated. SQLObject in particular can get in the way here if you're not careful -- watch out for cache inconsistencies.
- Log everything and watch the logs all the time.
by David Creemer : 2005/12/09 : Categories technology python : 0 trackbacks : 0 comments (permalink)
Hybrid Car Ownership Update
I've owned two Hybrid Cars first a Honda Insight, then a Honda Civic Hybrid when I needed more room for kids :-). Since it has now been about five years since I started down this road, I felt it was time for a bit of an updated.
The first thing most people want to know is how is the mileage? There's been much said about these cars not living up to EPA estimates, but I'm happy to say that in my case at least both cars seem to hit their marks. My Insight consistently got 55 MPG, +/5 depending on use. This Civic Hybrid isn't quite as efficient, though it still turns in a respectable 40-45 MPG tank after tank.
Happily, I don't have a lot of tankfuls of data. Both cars were/are daily commuters, but I wind up filling my tank only about once a month. Even with gas prices at $3/gallon, I'm just not spending much on fuel. California car insurance rates seem generally high, but both cars are small and safe, and my rates seem to compare quite reasonably with "traditional" cars.
Finally there's reliability. I've had two problems one with each car in five years. The Civic Hybrid needed an alignment and new tires after three years (blame the bad roads I guess). The Insight was rear-ended while I was on the way to trade the car in (really no kidding). After spending two weeks at the car repair shop, it seemed good as new. So nothing I can blame on the cars.
In addition I've recently added the California carpool lane stickers, so I can now travel alone in diamond lanes, which feels odd at first, but trust me -- you adapt quickly!
So let's see -- Two reliable, not lemon cars; cheap vehicles to operate, and insure; environmentally friendly; carpool lane access -- oh and I also got a $2000 federal tax deduction and a $1000 state rebate check (twice -- once for each car).
Summary: couldn't be much happier.
by David Creemer : 2005/12/08 : Categories life : 0 trackbacks : 0 comments (permalink)
Update on Bangkok Inside Out
Here's an update on what's going on with my cousin's book, Bangkok Inside Out.They (Daniel and his co-author Guy) have responded to the Thai government's de-facto banning, by issuing this press release
The book hasn't been officially banned, but either way the government's argument seems a bit silly to me. As a "foreigner" who knows nothing about Thai culture, my reaction to reading about this is "seems like challenging place to do business."
I've archived PDFs of further coverage of this story from the Wall Street Journal, the South China Morning Post, the Singapore Strait Times, Farang Magazine, and the International Herald Tribune.
by David Creemer : 2005/12/02 : Categories life books : 0 trackbacks : 2 comments (permalink)
Banned in Bangkok
I've just learned that my cousin's excellent book, Bangkok Inside Out, has been banned in Thailand. This is a real shame, as the book is essentially a love-letter to the city.
This is Daniel's second book in what I hope is a series. The first, Jakarta Inside Out covers the culture of that city in much the same way, and is (still) available in Indonesia and worldwide.
Both books feature awesome pictures and great prose -- typically one-topic per page -- on day-to-day real life cultural aspects of these cities. Most of the material taps into the true goings on of the people of Jakarta and Bangkok -- the kind of stuff you only learn from living there for years (as Daniel and his co-author have).
by David Creemer : 2005/11/22 : Categories life books : 0 trackbacks : 0 comments (permalink)
MissingSync Version 5
I've spent eight hours over the last two days struggling with Mark/Space's Missing Sync for Palm OS on my wife's Mac.
I upgraded from version four for primarily two reasons: I wanted the new memo application which has the ability to search across all notes (which it should have had from the beginning IMHO), and I was eager to benefit from its use of Mac OS X's sync framework. I use iSync and the OS X/Tiger sync framework to sync with .Mac and with my Nokia 6600 smart phone with excellent results.
Unfortunately, I personally have had hours of trouble with Missing Sync version 5. My wife has a lot of data in here calendar -- but not over the top a lot. My first attempts at syncing just failed outright after 20 minutes or so of waiting. I read a bit on the support mailing list, and taking some advice from there, purged all of her data more than two years old. I cleaned all of the data from her Treo -- and tried again, being sure to check "Desktop overwrites handheld". That seemed to result in one good sync, but examining the data resulted in duplicated untimed events. Lots of duplicated untimed events. Actually not duplicated -- quadrupled -- two years worth. One sync actually asked me to manually resolve more than 5000 conflicts (and no, the "resolve similar conflicts like this" check box didn't help).
After two days I have had not one good sync.
I will be removing this program, and asking for a refund.
by David Creemer : 2005/11/08 : Categories technology : 0 trackbacks : 0 comments (permalink)
Bad Science
Ben Goldacre's Bad Science column for the Guardian is one of the most refreshing journalistic undertakings I've seen in a while. Perhaps it's a bit of evil fun to watch him make fun of humanities graduate "science reporters", but he doesn't seem to do so without good reason.
I have similar complaints about technology writers -- many (but not all) don't really seem to understand their topic. When I happen to be very familiar with a given topic, I often find an article lacking or even incorrect. Perhaps this is why I find myself spending more time reading blogs than "official" news sources...
2005/10/31 : Categories technology life : 0 trackbacks : 0 comments (permalink)
Integrating CherryPy and Routes
Here's a very simplistic example of integrating CherryPy and Routes for URL mapping.
The basic approach is to place the Routes Mapper at the root of the CherryPy object publisher as a catch-all method. It then takes over URL to object dispatching.
This examples uses CherryPy 2.0, but 2.1 should be even simpler. I'm not entirely sure what to do about the CherryPy "default" method -- the example below doesn't quite get it right.
from cherrypy.lib import httptools from cherrypy.cperror import NotFound from cherrypy import cpg import re base_re = re.compile( r'^(?P[a-zA-Z]+)://(?P .*)' ) class RouteRoot: def default( self, *args, **kwargs ): base = cpg.request.base d = base_re.match( base ).groupdict() host = d[ 'host' ] proto = d[ 'protocol' ] path = cpg.request.path con = request_config() con.mapper = m # the Routes Mapper object con.host = host con.protocol = proto con.redirect = httptools.redirect con.mapper_dict = m.match( path ) if con.mapper_dict: c = con.mapper_dict.pop( 'controller' ) controller = controllers[c] action = con.mapper_dict.pop( 'action', 'index' ) try: meth = controller.__getattribute__( action ) except AttributeError: try: meth = controller.__getattribute__( 'default' ) except AttributeError: raise NotFound( path ) kwargs.update( con.mapper_dict ) print meth, kwargs return meth( **kwargs ) raise NotFound( path ) default.exposed = True cpg.root = RouteRoot() *** highlight file error ***
by David Creemer : 2005/10/01 : Categories python (permalink)
SQLObject and Memcached, part 1
Last week I attended the BayPIGgies monthly meeting and heard Ben Bangert's excellent introduction to SQLObject & FormEncode. I'm using both of these tools at work, so it's good to learn of other folk's experience with these tools.
First an apology -- some in the group asked why SQLObject reads back a row after inserting it (on object creation), since nobody seemed to have the answer, I speculated that it was to read back the ID. Wrong -- the id is fetched before the row is created (next item in the DB sequence). My next guess is that the row is read back in case the database executed a trigger, or had some default values that it applied to the row. In this case, the in-memory values would be incorrect, or not filled in if the row is not read back.
Another question came up on how to keep multiple processes synchronized with each other with SQLObject. The short answer is that it's not easy. SQLObject is aggressive about caching objects, even when told not too -- this is apparently to preserve object identity -- i.e. two fetches of the same row yield the exact same Python object. Makes sense to me.
Even so, I've been experimenting with approaches to solving the multi-process problem with SQLObject. One standard approach is to have database based triggers update a serial number associated with each row in tables that are shared between processes. Then before every use of the object, check to see if your serial number matches -- if not, re-sync and try again.
Below is some code I wrote to do that, but instead of adding a serial number column, it just caches the serial number in memcached. To use this class, update the memcached servers list, and then re-parent the shared class to use this class instead of SQLObject as the base.
The solution isn't perfect, as documented below. There is still a small but real race condition, and I love to hear solutions to reducing or eliminating that. However the results are nice for non-critical data. For example, multiple federated web applications can use this technique to keep seldom changing user data up to date.
This post is entitled part 1 because I have another, more invasive solution that I'll post in a little while. I've hacked up SQLObject's cache to always and ONLY use a memcached-based cache for object storage. This has some pluses and some minuses -- you would definitely not want to use this for a single process application, and object identity suffers (see above). I'll post that once the code works a bit better.
# SharedObject -- a SQLObject subclass where instances are shared by multiple
# processes. This implementation isn't perfect (see below), but generally works
# ok. It uses memcached to track object serial numbers, and patches some SQLObject
# methods to catch reads / writes. Any read or write checks the serial number of
# the object from memcached, and refreshes the object if it's out of date.
#
# THIS CODE HAS (at least one) RACE CONDITION. Since the read - update - write
# cycle does not happen within the scope of a "transaction", the object in question
# could have changed after we test to see if our copy if up to date.
# This could obviously lead to bad results. You have been warned.
#
# David Creemer -- 17-Sep-2005 -- Placed in the public domain. NO WARRANTY.
#
import sqlobject
import memcache
# set the memcache client list -- customize this as appropriate
mc = memcache.Client( [ '127.0.0.1:11211' ] )
class UnfreshObject(Exception): pass
class DeletedObject(Exception): pass
class SharedObject( sqlobject.SQLObject ):
def _key( self ):
return self.__class__.__name__ + str(self.id)
def _use( self ):
# call this when using the object for reading. This will ensure
# we have the latest data by checking the memcached serial number
if not hasattr( self, '_serial'):
self._serial = 0
k = self._key()
s = mc.get( k )
if s:
if s == "DEL":
raise DeletedObject()
if s > self._serial:
# we're out of date -- sync to db
self.sync()
self._serial = s
else:
# first time we are called
mc.set( k, 0 )
def _change( self ):
# call then when you have changed an object
# NOTE THAT THIS METHOD HAS A RACE CONDITION. The object could have been changed
# after the test to see if we're up to date.
if not hasattr( self, '_serial'):
self._serial = 0
k = self._key()
s = mc.get( k )
if s and s == "DEL":
raise DeletedObject()
s += 1
mc.set( k, s )
self._serial += 1
if self._serial != s:
raise UnfreshObject()
def __getattribute__( self, name ):
if name in ['name','val']:
self._use()
return sqlobject.SQLObject.__getattribute__( self, name )
def set(self, **kw):
try:
self._change()
except UnfreshObject:
self._use()
return sqlobject.SQLObject.set( self, **kw )
def _SO_setValue(self, name, value, from_python, to_python):
try:
self._change()
except UnfreshObject:
print "*"
self._use()
return sqlobject.SQLObject._SO_setValue( self, name, value, from_python, to_python )
def destroySelf( self ):
# if the object is destroyed, leave a marker in the cache for a day
mc.set( self._key(), "DEL", 60*60*24 )
return sqlobject.SQLObject.destroySelf( self )
***
highlight file error
***
by David Creemer : 2005/09/18 : Categories python (permalink)
Mischievous
A work colleague of mine has put up a funny website -- http://www.mischievous.org/blog. It's funny because there is absolutely nothing there but google ad words. This posting is a test to see if we can influence his page rank.
by David Creemer : 2005/08/25 : Categories humor : 0 trackbacks : 0 comments (permalink)
NPREM
NPREM is the near-dreaming sleep state experienced after the alarm clock-radio turns on. Usually experienced around 6:20 AM or so, with the radio tuned to NPR's Morning Edition, and always involving an in-depth, 10-minute or so long story. Usually reported by Linda Wertheimer or Scott Simon, but not always.
by David Creemer : 2005/08/05 : Categories humor : 0 trackbacks : 0 comments (permalink)
The Grey Album
I got ahold of The Grey Album by DJ Dangermouse, and I think it's very good. This album is a mashup of the Beatles "The White Album" and Jay-Z's "The Black Album". I already own the former and will now buy the latter.
What makes this music even more interesting is that it's apparently illegal to distribute, as the source music is used without permission. This is understandable but unfortuante -- it's a new, creative work of art that deserves to be appreciated (IMHO). Ironically, EMI's supression of the work has of course made it more popular -- I would probably not have heard of it if it wasn't for the controversy. (The so-called Streisand Effect).
by David Creemer : 2005/07/15 : Categories music (permalink)
Experimental website online
I've brought online a new python-based experimental business directory and local coupons website working with some friends. The database is mostly empty now, but it does contain data for some of
Palo Alto, CA, San Francisco, CA, Renton, WA, Chicago, IL, Fairhope, AL, Germantown, TN, and Dallas, TX.
This site is using technologies like:
- squid for reverse proxy caching
- pound for load balancing
- cherrypy is the python-based web application server
- cheetah provides the python-based XHTML page template generation
- sqlobject is the python-based database Object-Relational Mapper
- postgresql handles the database duties
- lighttpd handles the front end web interface
all on linux. In other words, it's all free software. Pretty amazing stuff all around.
by David Creemer : 2005/07/13 : Categories technology python : 0 trackbacks : 0 comments (permalink)
Admiral?
I saw this article on BBC today. It turns out the head of Bolivia's armed forces is Admiral Luis Aranda. Admiral? Bolivia? What am I missing?
by David Creemer : 2005/05/26 : Categories humor : 0 trackbacks : 0 comments (permalink)
Waiting for the Doctor
I had a second visit to SOAR (Sports Orthopedic and Rehabilitation) this week to check on my back, which had been in quite a lot of pain. A friend had recommend this clinic, and Dr. Joel Saal in particular. After arriving early, checking in, and then going to an exam room, I then waited 40 minutes in a windowless, magazine-less tiny room for the doctor to arrive. Outside I heard things like "Is Dr. Saal here yet?" "Tell him to go right to room #2 when he gets here", etc.
Normally I wouldn't use this forum to complain about this sort of thing. Except this is a private clinic which can manage their patient load; and this was the second time the same thing happened; and when I asked if a 40 minute wait (past the scheduled appointment time) was acceptable, three nurses all grimaced and noded their heads with sad looks on their faces, saying "did you tell Dr. Saal? You should tell him." Apparently this is normal, patients are complaining, and it's not getting through to the right person. At one point, one of the staff mentioned that they didn't know what to do about this problem.
A long time ago, I read (or at least skimmed) Gallwey's The Inner Game of Tennis. I think I remember one lesson from that book (but it could have been another) about just relaxing and observing a single important factor, rather than thinking carefully through the task and trying to get all of the sub-details right. I think a follow-on book discussed this exact situation -- patients complaining about long waits (past the appointment time) at a medical office. The "solution" proposed was simple: just write down the amount of time each and every patients is made to wait. Eventually the problem took care of itself. I hope SOAR can apply this or some other lesson, but on my next visit, I'll be sure to bring a book!
by David Creemer : 2005/05/10 : Categories life : 0 trackbacks : 3 comments (permalink)
Multi-computer-monitor setup
I'm faced with a bit of an embarrasment of riches -- I have two nice machines on my desk at work, as well as a fantastic Dell 2005FP 20" LCD panel. One computer is an IBM Thinkpad T43p, the other is an Apple iBook. The iBook is my personal computer, and I generally bring it everywhere with me and find it the most comfortable to use. The Thinkpad runs Ubuntu Linux 5.04, and is used for developement and system administration tasks. Though Mac OS X is "just" UNIX under the hood, I find the package management and system administration of Debian-style Linux to be more in sync with the way I develop and manage systems and web applications. Yes, I know that there are things like Fink to superimpose package management onto Mac OS X, but it's not the same as having an OS built around apt-get.
In any event, I need to fluidly move back and forth between these two environments. There are of serveral solutions to this, and I tried most -- two sets of keyboards and mice, KVM switches, VNC, x2vnc and so on, but I finally settled for the time being on NX / FreeNX, setup mostly as described here. NX is essentailly a terminal services implementation from NoMachine available also in open source form. So now my Thinkpad runs more or less closed -- just booted to the Linux console. My iBook connects to the 20" LCD panel and (with the help of this excellent hack) has a huge Mac OS X desktop. The NX client runs essentially full-screen on the 20" LCD and I have one keyboard and mouse to run it all. This seems the best of both worlds -- I can continue to "live" in Mac OS X which my fingers have memorized and which manages multiple monitors exceptionally well. If I move the mouse to the NX client window, I'm instantly "in" my Ubuntu GNOME desktop, happily developing away. The performance of NX is really very, very good.
To complete it all, I needed a good USB keyboard and mouse. The mouse part was easy -- it seems there are lots of decent models to choose from. But the keyboard aisle at my local Fry's is a distaster -- 30 different models, all junk. Most have crappy keys and 30 extra buttons, switches, levers, dials and wheels for "controlling the Internet and Music" bla bla. I just want that feels good and doesn't cost a lot! The a funny thing happened -- I went to the "Apple" section, and found the $29 Apple keyboard which was exactly right.
If this setup continues to work as well as I hope, I'll pass the Thinkpad along to a coworker, and substitue a beefier desktop PC for the Ubuntu developement host and NX server.
by David Creemer : 2005/05/04 : Categories technology : 0 trackbacks : 3 comments (permalink)
Setting Up Shop
I'm at a new (tiny) startup now, and decided that since I'm in charge of the technology (more or less), I try to start things out right.
We're relying heavily on open source software both for our internal IT infrastructure, and for components of the product we're building. I've been a fan and user of Debian Linux for a long time -- it's stable and easy to maintain. However as many have noted, the current stable release of Debian (Woody) is getting a bit long in the tooth. Sarge will be here real-soon-now, but in the mean time I can't wait.
So like many others in this situation, I was drawn to Ubuntu and haven't looked back. We've install the 5.04 Hoary release on three workstantions and two servers so far with excellent results.
Adapting the directions from this Howto and this one too was straightforward, and without too much trouble we now have LDAP-based single sign on for network accounts, file serving, wiki and subversion authorization, and email. Very nice!
Having done all this on commodity PC class server hardware, and also having worked for a while in Apple's Mac OS X Server engineering group, I can say that all this would have been much easier under Mac OS X Server -- the GUI administration tools are very well done, but to be fair I suppose I should compare with Red Hat or SuSE's commercial offerings.
There were a couple of annoyances along the way. Ubuntu doesn't seem to have an Apache2 mod_auth_ldap available. I could have just built it, but I also wanted to learn a bit about the Python LDAP module. One apt-get later, and I had mod_python and python-ldap installed, and wrote a 20-line script to do Apache2 LDAP authentication:
from mod_python import apache
import ldap
def authenhandler(req):
pw = req.get_basic_auth_pw()
user = req.user
# open connection to server -- change as necessary
l = ldap.open( '127.0.0.1' )
base = 'ou=People,dc=example,dc=com'
try:
# attempt to auth bind to the server
l.simple_bind_s( 'uid=' + user + ',' + base, pw )
return apache.OK
except ldap.LDAPError:
return apache.HTTP_UNAUTHORIZED
***
highlight file error
***
After acquiring, installing, and configuring PC's and laptops running Ubuntu Linux, Windows XP Pro, and Mac OS X, I find myself using Ubuntu for my servers and development platform, and my Apple iBook for everything else. Though Mac OS X is UNIX at its core, I find it easier to develop on a platform very close to our production environment. The iBook G4 12" however is just a heck of a great personal computer. It's tough, light, very functional, and Mac OS X is dream to use. My old 15" Aluminum Powerbook had a great screen and other nifty features, but it seems fragile by comparison.
by David Creemer : 2005/05/02 : Categories technology python : 0 trackbacks : 1 comment (permalink)
Separated at Birth?
While browsing through my image gallery dug up this photo of a 1930's Aeronca C3, taken at the massive Oshkosh fly-in a couple of years ago.
I've always felt that this airplane bears a strong resemblance to Droopy Dog, but maybe that's just me...
![]() |
by David Creemer : 2005/02/21 : Categories flying (permalink)
Python Geo Programming
I found this free database of US ZIPcodes with city name, state, and latitude, longitude information. With a bit more searching, I also found these databases of US 2000 Census infomration by ZIPcode. All this information looked like a good opportunity for some Python geographic programming fun
Unfortunately, the census data is in DBase format. Fortunately, there are a couple of ways to convert this data to something useful to me. I found a Python DBase file reader, and used it plus some simple Python DB API code to populate a SQLite database with the information.
I've also been playing with SQLObject recently, which is a very nice Python Object/Relational Mapping system (ORM). It generally just does its job well, and stays out of the way the rest of the time. This fits well with my programming philosophy of simple tools that do one job. Python is excellent at both creating these simple tools, and integrating them together. So I created this simple class:
from sqlobject import *
import math
#
# The following formulas are adapted from the Aviation Formulary
# http://williams.best.vwh.net/avform.htm
#
nauticalMilePerLat = 60.00721
nauticalMilePerLongitude = 60.10793
rad = math.pi / 180.0
milesPerNauticalMile = 1.15078
def calcDistance(lat1, lon1, lat2, lon2):
"""
Caclulate distance between two lat lons in NM
"""
yDistance = (lat2 - lat1) * nauticalMilePerLat
xDistance = (math.cos(lat1 * rad) + math.cos(lat2 * rad)) * (lon2 - lon1) * (nauticalMilePerLongitude / 2)
distance = math.sqrt( yDistance**2 + xDistance**2 )
return distance * milesPerNauticalMile
def milesBox( lat, lon, radius ):
"""
Returns two lat/lon pairs as (lat1, lon2, lat2, lon2) which define a box that exactly surrounds
a circle of radius of the given amount in miles.
"""
latRange = radius / ( milesPerNauticalMile * 60.0 )
lonRange = radius / ( math.cos(lat * rad) * milesPerNauticalMile * 60.0)
return ( lat - latRange, lon - lonRange, lat + latRange, lon + lonRange )
#
# Zipcode persistent information class
#
class Zipcode( SQLObject ):
"""
A collection of information about a US ZIP code. Database key is the 5 digit zipcode itself,
as an integer. For some zipcodes, no city name is given.
"""
_connection = 'sqlite:///tmp/zipdb.db'
_idName = 'zip'
# 'zip' is the ID column
city = StringCol( default = 'UNKNOWN' )
state = StringCol( length = 2 )
latitude = FloatCol()
longitude = FloatCol()
population = IntCol( default = 0 )
area = FloatCol( default = 0.0 ) # in square miles
def distance( self, zip ):
"""
Return the great circle distance between self and the given zipcode.
"""
return calcDistance( self.latitude, self.longitude,
zip.latitude, zip.longitude )
def nearby( self, radius = 10.0 ):
"""
Return a list (generator) of all zipcodes within the radius (in miles) of self --
more or less -- see milesBox doc for true definition.
"""
(lat1,lon1,lat2,lon2) = milesBox( self.latitude, self.longitude, radius )
return Zipcode.select( AND (
AND( Zipcode.q.latitude >= lat1,
Zipcode.q.latitude <= lat2 ),
AND( Zipcode.q.longitude >= lon1,
Zipcode.q.longitude <= lon2 ) ) )
***
highlight file error
***
With the class built, we can start to have some fun:
% python >>> from zipcode import Zipcode >>> # Southern-most named town in Wyoming >>> [z for z in Zipcode.select( Zipcode.q.state == 'WY', orderBy='latitude' )][0].city 'Jelm' >>> # distance from Dallas to San Francisco -- note precision is only to 4 decimal places >>> Zipcode.get( 94114 ).distance( Zipcode.get( 75248 ) ) 1482.3659983019043 >>> # cities within 20 miles of Palo Alto, CA >>> import sets >>> sets.Set([x.city for x in Zipcode.get( 94306 ).nearby( 20.0 )]) Set(['Millbrae', 'Santa Clara', 'Los Gatos', 'Union City', 'San Leandro', 'San Gregorio', 'Newark', 'Pacifica', 'San Francisco', 'Loma Mar', 'San Mateo', 'Hayward', 'San Carlos', 'Half Moon Bay', 'Pleasanton', 'Burlingame', 'Mountain View', 'Stanford', 'Fremont', 'San Lorenzo', 'Los Altos', 'La Honda', 'Menlo Park', 'Saratoga', 'San Jose', 'Portola Valley', 'Milpitas', 'Campbell', 'Atherton', 'Sunnyvale', 'Palo Alto', 'Alviso', 'Pescadero', 'Redwood City', 'San Bruno', 'Cupertino', 'Daly City', 'Boulder Creek', 'Brisbane', 'Belmont', 'Castro Valley', 'South San Francisco', 'Sunol']) *** highlight file error ***
by David Creemer : 2005/01/12 : Categories python : 0 trackbacks : 5 comments (permalink)
