James Tauber's Blog
Welcome to my blog. It's a haphazard collection of thoughts on various interests of mine as well as updates on projects. If you're interested in any of blogging, personal information management, Python, Django, XML, RDF, software development, Web 2.0, open source, free-market economics, Mac OS X, web architecture, REST, music theory, record producing, filmmaking, linguistics, the Greek New Testament, pure mathematics or general relativity, there's a chance you may find something of interest.
Metrics Provide An Inner Product
Another post for the Poincaré Project.
We've already seen that a one-form is a linear function from a vector to a (for our purposes) real number. On a manifold, one-forms correspond to stack-type vectors being applied to arrow-type vectors by counting how many "stacks" the arrow passes through.
In the previous post Metrics As Mappings Between Arrows and Stacks, we saw that a metric is an extra bit of structure that describes how to map between arrow-type vectors and stack-type vectors.
So, in summary:
- a metric tells you how to go from an arrow-type vector to a stack-type vector
- a stack-type vector can be applied to another arrow-type vector to get a real number
These two facts can be combined to let you take two arrow-type vectors and get a real number out of them.
This has parallels with currying in functional programming.
Recall that if a function "add" takes two integers and returns an integer, it can be viewed as a function that takes one integer and returns a function that takes one integer and returns an integer.
add :: Int -> Int -> Int
Now, a one-form is a function that takes a vector and returns a real. In other words:
Vector -> Real
So it is easy to see that if you curry a real-valued function that takes two vectors you get:
Vector -> Vector -> Real
In other words, a function taking two vectors to a real is equivalent to a function from a vector to a one-form.
So if you have a metric that can convert between vectors and one-forms (or, in the context of a manifold, between arrows and stacks) then you also have a function from two vectors to a real.
Such a function is called an inner product or dot product. Often the notion of an inner product is defined first, before one-forms are introduced (if at all). In fact, some texts will define a metric to be an inner product. It is best for our purposes, though, to think of the metric's fundamental purpose as being converting between arrows and stacks (and back again) and the inner product as being an extra concept we get for free.
by jtauber : Created on May 11, 2008 : Last modified May 11, 2008 : Categories poincare_project : 0 comments (permalink)
Introducing Pinax
In the post Reusable Django Apps and Introducing Tabula Rasa I mentioned my project to create an out-of-the-box Django-based website with everything but the domain-specific functionality.
At the time I was calling it Tabula Rasa but now I've settled on the Greek word Pinax, proposed by Orestis Markou.
So far it's just my new django-email-confirmation app tied together with password change and reset, login/logout, with the beginnings of a tab-style UI. There's a ton more I want to refactor out of my existing websites to put into it as well as adding support for OpenID and the stuff I'm starting to do for django-friends.
Even if one doesn't use Pinax as the starting point of a website, I'm hoping it will prove very useful for another goal, namely a "host" project to develop and tryout reusable apps.
The initial code is available at http://code.google.com/p/django-hotclub/ under /trunk/projects/pinax and there is a running instance for you to try out at:
http://pinax.hotcluboffrance.com
by jtauber : Created on May 10, 2008 : Last modified May 10, 2008 : Categories django pinax : 4 comments (permalink)
Elite Oolite
When I lived in Brunei in the mid-80s, a neighbour had a BBC Micro and I would go over there to play the space trading game Elite. The hidden-line wireframe graphics and massive procedurally-generated universe seemed amazing to me at the time and it was definitely the kind of software I aspired to one day write myself. At the time, I taught myself trigonometry to do 3D graphics but never got to hidden line removal :-)
I was aware of various Elite clones over the years, but the other day I stumbled across Oolite, an open-source Mac OS X version with modern OpenGL graphics. Simply amazing and just as addictive as I remember the original being. It also seems to be highly pluggable, with numerous extensions available to add both to the UI and gameplay.
by jtauber : Created on May 9, 2008 : Last modified May 9, 2008 : Categories games : 0 comments (permalink)
LOTRO on VMware Fusion
I've hardly played Lord of the Rings Online at all the last six months and not at all the last three.
My only copy of Windows is a VMware Fusion instance and LOTRO doesn't work on VMware Fusion. That is...until now.
I was excited to hear that the new VMware Fusion 2.0 beta 1 supported pixel shaders in DirectX 9 and I wondered if that meant LOTRO would work. I downloaded the beta, which JUST WORKED with my existing VM (which wasn't even shut down). I spent an hour or so updating LOTRO but my first attempt to start the game failed.
The error message was different, though. Instead of being about the graphics adapter it was a complaint about a Game Error 127. A Google search revealed this post and so I tried making the config change they suggested there.
And BINGO! I can now run Lord of the Rings Online on VMware Fusion!
I haven't tweaked the settings yet to see if it's playable but I'm hopeful.
VMware, you are amazing!
UPDATE: I played LOTRO for a little bit tonight. I had to turn sound off as it was too jittery. Graphics were fine, though, on Low detail and low resolution. The mouse look problem mentioned in the comments was easily fixed by just going to options and changing the mouse look sensitivity.
by jtauber : Created on May 6, 2008 : Last modified May 6, 2008 : Categories os_x lotro : 4 comments (permalink)
Reusable Django Apps And Introducing Tabula Rasa
The excellent 42 Topics blog has a post entitled Popularizing Django — Or Reusable apps considered harmful which makes (or attempts to make) the case for packaged apps over reusable apps.
He raises some good points, although of course the packaged apps he's talking about still use reusable apps so he's not actually talking about there being a problem with reusable apps per se, just that there should be packaged apps as well.
I mentioned the django-hotclub group in a comment on that post as I'd really like the discussion to take place there.
I also, in that comment, mention something I'm working on tentatively called Tabula Rasa. (I'm toying with a Greek name rather than Latin but something tells me people are more comfortable with tabula rather than grammateion)
Basically, the goal of Tabula Rasa is an out-of-the-box Django-based website with everything but the domain-specific functionality.
So far it's just my new django-email-confirmation app tied together with password change and reset, login/logout, with the beginnings of a tab-style UI. There's a ton more I want to refactor out of my existing websites to put into it as well as adding support for OpenID and the stuff I'm starting to do for django-friends.
Even if one doesn't use Tabula Rasa as the starting point of a website, I'm hoping it will prove very useful for another goal, namely a "host" project to develop and tryout reusable apps.
One of the challenges I know I've always had with writing or trying out reusable apps is the need for a project to provide the scaffolding.
So Tabula Rasa will hopefully serve that dual purpose.
UPDATE: I've decided to switch to the Greek word pinax suggested below by Orestis Markou.
UPDATE 2: Now see Introducing Pinax.
by jtauber : Created on May 6, 2008 : Last modified May 9, 2008 : Categories django : 9 comments (permalink)
Metrics As Mappings Between Arrows and Stacks
Another post for the Poincaré Project.
Back in Coordinate Systems and Metrics we saw that a metric for a coordinate system tells us the "distance travelled as proportion of coordinate change". Then in the following post, Metrics in Two or More Dimensions:
Imagine that you're at a particular point on a two-dimensional manifold. If you head off in a particular direction from that point at a particular rate, your coordinates will change. The metric tells you, from a given point, the rate of change of each of your coordinates given travel in a particular direction at a particular rate.
Those two posts express two sides of the same coin: in one I said the metric tells us the rate of change of position given the rate of change of coordinates and in the other I said the metric tells us the rate of change of coordinates given a rate of change of position.
A rate of change of position is, as we've seen, an arrow-vector. A rate of change of a particular coordinate is, as we've also seen, a stack-vector in the dual space.
In fact, one can view a metric as being a mapping between arrow-vectors and stack-vectors. You can use it, along with some calculus if the metric is different at different points, to calculate distances (as described in Coordinate Systems and Metrics). It can also be used to calculate the length of a vector or the angle between two vectors (concepts which don't exist without a metric).
A metric ties those length and angle notions to the coordinate system and, in so doing, actually defines the coordinate system.
Finally, a metric has within it, all the information necessary to describe the curvature of a manifold. It is ultimately this function that makes it relevant to both the General Theory of Relativity and the Poincaré Conjecture.
We will explore each of these in due course. The main takeaway at this point is that a metric is a mapping between arrow-vectors and stack-vectors.
by jtauber : Created on May 4, 2008 : Last modified May 4, 2008 : Categories poincare_project : 0 comments (permalink)
Factoring Out Common Args To Zipped Generators
I'm playing around with some additive synthesis in Python.
I've implemented an oscillator as a generator that takes a number of parameters. It is then possible to mix multiple oscillators using zip (or better, itertools.izip) over them and doing a (weighted) sum.
However, I wanted to be able to factor out common arguments to the oscillators so I didn't have to specify the frequency of each one individually.
I knew functools.partial would be part of the solution but it took me a while to work out how to combine its use with generators and itertools.izip.
Here is a simplified progression of what I came up with.
Phase 1
Rather than use oscillators, let's just imagine with have a generator that works a lot like xrange:
def gen1(start, stop, step):
n = start
while n <= stop:
yield n
n += step
then we can combine multiple generators and, say, sum the corresponding elements like this:
for x in zip(gen1(10, 20, 2), gen1(10, 25, 3)): print sum(x),
Phase 2
Let's abstract this into a function that takes generators as arguments (and uses itertools.izip)
def mixer1(*generators):
return (sum(x) for x in izip(*generators))
for x in mixer1(gen1(10, 20, 2), gen1(10, 25, 3)): print x,
mixer1 is similar to my mixer (although without weighting)
Phase 3
But now say we wanted to factor out the common start parameter. First we need a partial version of function gen1:
gen2 = lambda **kwargs: partial(gen1, **kwargs)
This allows one to say
partial_gen = gen2(stop=20, step=2)
and then later call
partial_gen(start=10)
to get the generator.
But what we now need is a new version of the mixer that takes the extra keyword args and passes them in to each partial function to turn them back into generators:
def mixer2(*generators, **kwargs):
return mixer1(*[gen(**kwargs) for gen in generators])
and now we can say:
for x in mixer2(gen2(stop=20, step=2), gen2(stop=25, step=3), start=10): print x,
Phase 4
Here's the final version:
gen2 = lambda **kwargs: partial(gen1, **kwargs)def mixer3(*generators, **kwargs): return (sum(x) for x in izip(*[gen(**kwargs) for gen in generators]))
The real thing is a little more involved because of the weighted summing, etc but the hard parts are shown.
by jtauber : Created on May 2, 2008 : Last modified May 3, 2008 : Categories python : 1 comment (permalink)
Moiré Waves
I was playing around with some additive synthesis in Python, generating various basic waveforms and checking them visually, in Soundtrack Pro.
The moiré pattern of the waveforms in one test file was interesting:
That's actually 220 cycles of a sine wave, followed by the same for a sawtooth, square and triangle waveform.
by jtauber : Created on May 1, 2008 : Last modified May 1, 2008 : 2 comments (permalink)
Grammar Rules
One downside to having a background in linguistics is that one is more sensitive to various so-called grammar rules that people regurgitate from their school years.
The majority of linguists probably view these rules the way a doctor would view the four humours. But a more fundamental issue is not that some of the theories have been superseded but that their perpetuation reveals a very unscientific approach to language. It is as if these people are viewing rules of grammar like they would road rules—human inventions that one may disagree with, but which are still, in some sense, what is "correct"—rather than, say, laws of physics that attempt to model observations.
This means that when confronted with data that doesn't match the rules, such people will say the data is wrong ("that isn't correct English") rather than ever consider that maybe it's their rules that need refinement.
Now it is certainly the case that people make mistakes when they speak (and that can be a revealing study in itself) and there is such a thing as good English usage (see the last paragraph) but most linguists focus on modeling the tacit intuitions native speakers have about their language which are very often at odds with the "rules of grammar" learnt at school.
Let me give an example. A common misconception is that English has cases that work in a similar way to Latin. I suspect the origins of this stem from attempts to model English after Latin as if Latin was somehow a better language.
It is easy to see on the surface there might be evidence for a nominative/accusative case distinction in English pronouns. Native speakers will say "I gave the book to him. He gave the money to me." with the intuition that switching "I" and "me" or "he" and "him" would be incorrect. This is a valid observation that a linguist would want to capture in some kind of descriptive rule.
However, when asked "who is it?" native speakers will almost always answer "it's me" rather than "?it's I".
I've had people try to tell me that the latter is "more correct" although they don't say it themselves. If they don't say it, as competent speakers of English, what is their claim to it being correct? Because their high school English teacher told them? Because Latin would use the nominative here?
If you ask a group of people "who wants to sit in the front?" they are far more likely to answer "me" than "?I". And yet they would say "I do" rather than "*me do". If you accuse someone you are probably more likely to say "it was him" not "?it was he". So what's going on doesn't just involve using the nominative case for the subject and accusative case for the object.
The massive 1,800+ page Cambridge Grammar of the English Language gives more great examples "nobody can do it but her/*she", "the only one who objected was me/?I" and (showing photos) "this one here is me/*I at the age of 12".
Things become even more complex in the case of conjunctions. The Cambridge Grammar gives the example of "they invited my partner and I to lunch". They point out that examples like this "are regularly used by a significant proportion of speakers of Standard English, and not generally thought by ordinary speakers to be non-standard". They go on to argue against the prescriptivist use of analogy with "they invited me/*I to lunch" to justify why the use of "I" is incorrect.
The worst kinds of rules are ones that sound almost like superstitions: don't use passives, don't use adverbs, don't split infinitives, don't end sentences with a preposition, don't start a sentence with "however" etc. They may help one adopt a particular style of writing, but they certainly aren't rules of grammar in any scientific sense and are, in most cases, completely arbitrary.
Some of the usage guides these rules are found in are better than others. Strunk and White is full of these arbitrary superstitions. In fact, Professor Geoffrey Pullum, the co-editor of the previously mentioned Cambridge Grammar of the English Language describes Strunk and White as a "horrid little notebook of nonsense" and instead recommends Merriam-Webster's Concise Dictionary of English Usage which I own and agree is much more useful for evidence-based guidelines on subtle differences in usage between words.
by jtauber : Created on May 1, 2008 : Last modified May 1, 2008 : Categories linguistics linguistic_observations : 12 comments (permalink)
UPS Invents Time Travel
and who is BERT in Provo?
by jtauber : Created on April 30, 2008 : Last modified April 30, 2008 : 2 comments (permalink)
Why Colour Correction Only Needs Two Sliders
Duncan Davidson (who I still think of as James) asked on Twitter:
Color Temp works on the Blue/Yellow axis. Tint on the Green/Magenta. No need to tweak Red/Cyan?
I responded there but decided to here as well as I've talked about colour theory before.
The basic answer is that you only need two axes because colour (disregarding brightness/luminance) is two-dimensional. Red, Green and Blue form a triangle in that two-dimensional space (with Cyan, Magenta and Yellow being on the opposite edges respectively).
Basic linear algebra tells us that, in an n-dimensional space, you only need n vectors to form a basis (actually, that's the definition of dimensionality) so you can adjust any point in two-dimensional colour space by translating it by a linear combination of any two, non-parallel vectors. Incidentally, Hue and Saturation would be almost polar coordinates on this space.
Because one form of colour modification is colour temperature, it makes sense to roughly make one of the axes the yellow-blue direction. I think the magenta-green axes is largely arbitrary. Any other axis would have done fine.
Note I say "roughly" the first time in that previous paragraph because the black-body colours aren't a straight line in standard colour models.
Hmm, that makes me wonder if colour correction sliders represent rectilinear bases at all.
UPDATE (2008-05-04): According to a reply in the Reddit thread, the slides aren't rectilinear but are based on the black-body colours. The so-called "tint" is presumably then orthogonal to black-body line (the Planckian locus)
by jtauber : Created on April 29, 2008 : Last modified May 5, 2008 : Categories photography : 10 comments (permalink)
Auto-Scrolling in jQuery
I mentioned in my previous post New Site Look that, inspired by 37 Signals, I wanted to auto-scroll pages in my website in two circumstances:
- when there is an error in an Add Comment form, scroll down to the error message
- when the user expands the Add Comment form, scroll to put the form in view
Here's the fragment of my Django template that achieves both of these with jQuery:
<script type="text/javascript" src="/static/jquery.js"></script>
<script type="text/javascript">
function scrollTo(selector) {
var targetOffset = $(selector).offset().top;
$('html,body').animate({scrollTop: targetOffset}, 500);
}
$(document).ready(function() {
$('#add_comment_toggle').click(function() {
$('form.add_comment').slideToggle();
scrollTo('form.add_comment');
return false;
});
{% if comment_error %}
$('form.add_comment').show();
scrollTo('.comment_error');
{% endif %}
});
</script>
The only bit of Django, for those who don't know it, is the {% if ... %} which only includes that Javascript if a comment_error exists.
The scrollTo function scrolls to the element whose selector is given. Notice how, if a comment_error exists, I make sure the form is showing first, then call scrollTo.
Also, in my code for toggling the Add Comment form, I call the function to scroll to the form.
by jtauber : Created on April 28, 2008 : Last modified April 28, 2008 : Categories django web_design javascript jquery : 6 comments (permalink)
New Site Look
If you read this in a feed reader, you might want to go to my actual site to see what I'm talking about :-)
Usually, when I rewrite the underlying code behind jtauber.com, I do a redesign of the look as well. In the 14 years that jtauber.com has been around, it's probably had around 10 different looks. The last change took place when I wrote Leonardo in 2003.
When I ported Leonardo to Django I really should have changed the look, in keeping with tradition, but I didn't. I decided this weekend to do some code clean up and add a couple of new features and ended up doing a completely new look as well. I also switched from Django 0.96.1 to Django trunk (including qs-rf), although I don't make use of any of the new features yet.
Here's a brief list of what I did change:
- changed colour from the green I've had for the last five years to a purple more like what I had in 2002 but with lickable gradient site title
- went from a two-column to three-column layout so I'd have a place to put some Web 2.0 goodies on every page
- added my photo to the home page :-)
- added Twitter updates
- added links to my Facebook and LinkedIn profiles
- added an overflow property to pre so code examples don't overlap the right column
- fixed an annoying bug where if you got the maths question wrong your comment would get forgotten
- made add comment form initially hidden and available only via a toggle
- inspired by this video at 37 Signals, I added some auto-scrolling to the add comment form—when there is an error in submission, the page automatically scrolls to the errors; and when you toggle the comment form open, it automatically scrolls so the form is fully in view.
Had to trigger hasLayout in IE6 to get it to work there. Fortunately, I'd had that issue previously with Quisition so knew what to do. Thank goodness for VMware Fusion to enable me to check the site on IE6.
I quite like the new look, especially in comparison to the old look. I'm more than a little chuffed at getting the autoscrolling working too :-)
by jtauber : Created on April 27, 2008 : Last modified April 27, 2008 : Categories django this_site web_design : 4 comments (permalink)
django-email-confirmation
This simple django app is for cases where you don't want to require an email address to signup on your website but you do still want to ask for an email address and be able to confirm it for use in optional parts of your website.
A user can have zero or more email addresses linked to them. The user does not have to provide an email address on signup but, if they do, they are emailed with a link they must click on to confirm that the email address is theirs. A confirmation email can be resent at any time.
As of r22, what's on the trunk here should be usable but I welcome feedback on how to make it better. The source contains a working project that shows all the features of the app as well as providing useful code for your own project.
This code is based in part on django-registration and is essentially a replacement for it where your requirements are different.
http://code.google.com/p/django-email-confirmation/
by jtauber : Created on April 27, 2008 : Last modified April 27, 2008 : Categories django : 0 comments (permalink)
Barry and Frank
Continuing on from the previous Barry and Frank story...
Colin comes up to Barry and Frank and says "I've just tossed this coin 100 times and recorded the result each time in this notebook. What is the probability that toss number 37 was tails?". Frank thought for a moment and asked "can we study the notebook?" "Sure," Colin said.
Frank took the notebook and looked through it before declaring "well, 40 out of 100 tosses were tails, so the probability of toss number 37 having been tails is 0.4".
"I agree," said Barry, somewhat to the surprise of Frank. But Barry then took the notebook, turned to the appropriate entry and said "oh, the probability just changed to 1"
by jtauber : Created on April 17, 2008 : Last modified April 17, 2008 : Categories mathematics : 1 comment (permalink)
Probability Thought of the Day
If I ever taught probability and statistics, this is the problem I'd put on the board the first lecture:
Colin comes up to Barry and Frank and says, "hey guys! I have a coin here which is biased but I won't tell you which way or by how much. What's the probability of the next toss being tails?". Barry replied, "given what we know, it is 0.5". Frank looked astonished. "How can you say 0.5? Given the coin is biased, that's the one probability we know it can't be." Who is right, Barry or Frank?
UPDATE: corrected "a tail" to "tails".
UPDATE 2: Eliezer Yudkowsky has a great post on exactly this scenario. He's way smarter than I, so go read him :-)
by jtauber : Created on April 13, 2008 : Last modified April 13, 2008 : Categories mathematics : 21 comments (permalink)
History
via James Bennett and Bill de hÓra:
$ history | awk '{print $2}' | sort | uniq -c | sort -rn | head
120 cd
111 ls
78 python
73 svn
17 mate
14 less
11 rm
11 mv
7 mkdir
5 ssh
No surprises there at all :-)
by jtauber : Created on April 10, 2008 : Last modified April 10, 2008 : 0 comments (permalink)
More About Twitter
On my previous entry about Twitter, Nelson commented:
I still don't really get what Twitter is... would it be useful to me?
I could describe Twitter as to blogging what IM is to email but that's not enough.
I admit that I didn't get Twitter at first. For months I just thought it wasn't my kind of thing.
Then something changed.
For me Facebook status was the gateway drug. Once I got interested in what people were doing, thinking, and responding to in their Facebook status, Twitter started to make more sense.
The other thing that changed was I built a critical mass of interesting people to follow. Some of them were people I only vaguely know but who I knew had interesting things to say. Some I confess are just fly-on-the-wall eavesdropping.
But the two most interesting categories are the friends who I can keep more in touch with about day-to-day stuff and the acquaintances (or strangers) with common interests who I strike up spontaneous conversations with.
Here is fun example last week. Someone mentioned that Game Neverending (GNE) was back. So I went and checked it out. It closed down a couple of hours later so I never would have known about it in time if not for Twitter. Later on in the week, I twittered that I'd like to write a GNE-clone in Django. As well as a number of people asking me what GNE was, I also had a reply from a guy I met at PyCon saying he'd love to be involved. So we worked on it together over the weekend (see my post about it. All this happened because of Twitter.
To build the critical mass of people to follow (what I did, anyway):
- if you're on Facebook, see which of your friends are twittering and start following them
- import your contacts (I did this via gmail even though I don't use gmail) to see other friends who twitter
- look at who your friends are following and start following some of those people
- look to see who your followers are replying to and start following them
- if someone follows you, check them out and, if they're not spam, follow them
The other thing that helped me get into it was finding a client app. I've used Twitterific and Twhirl and like both a lot.
Incidentally, I twittered that I was writing this post and immediately received a number of suggestions and links (thanks @moof and @epoz)
Suggested blog posts on this topic included:
- Nearly a million users, and no spam or trolls by Russell Beattie
- On Twitter by Tim Bray
I'll also twitter with a link to this post for people to add their comments to.
Will it be useful to you? If you like finding out what friends are up to; if you like learning about new things going on from smart people with common interests; if you like making serendipitous connections based on overheard conversations, then Twitter will be useful to you.
Hope this helps!
P.S. If you follow a lot of people, never be afraid to just ignore the river of tweets when you're busy (or sleeping). I generally don't look at Twitter at work, for example, and only rarely ever go back to skim what I missed.
UPDATE: Definitely watch the short video http://www.commoncraft.com/Twitter that David recommends below!
by jtauber : Created on April 7, 2008 : Last modified April 7, 2008 : 6 comments (permalink)
Game Neverending in Django
In the early hours of April 2nd I heard via Twitter that Game Neverending, the online game that never launched but which gave rise to Flickr, had come back. I played it for about an hour and loved it but then had to go to work. When I got home, the game had been shut down again—I guess it was just an April Fool's joke.
Digging around I found the GNE museum which had a fair amount of information about the game mechanics. It occurred to me that it would be fairly straightforward to implement most of the concepts as a Django-based website.
So yesterday, I started django-mmo at Google Code Project Hosting. So far I've implemented the basic location system and support for some aspects of game items (player inventory, picking up and dropping, spawning but not the making system yet). I haven't paid any attention yet to UI (sort of looks like Web pages did in 1993) and the whole thing so far is played in a kind of "God-mode" where you can control any player. In a way, the UI is just there for testing the model at the moment.
But I'm making good progress. The initial goal is parity with GNE (or at least what I can glean from GNE museum) and then I can think about ways of extending it.
UPDATE (2008-04-13): Making and chat are now implemented. The UI is getting close to parity too.
by jtauber : Created on April 6, 2008 : Last modified April 14, 2008 : Categories python django games : 1 comment (permalink)
Twittering
I've been using Twitter a lot lately. My page is http://twitter.com/jtauber if you'd like to follow me.
I've also set up a Twitter account for Quisition and over the weekend plan to hook up notifications so that @quisition will tweet when there are new announcements and new packs.
And speaking of Quisition, I've created a Facebook page where I'll also post updates.
by jtauber : Created on April 4, 2008 : Last modified April 4, 2008 : 1 comment (permalink)