Monday, February 01, 2010
Yet another Bill Watterson interview found!
Ah, the life of a newspaper cartoonist—how I miss the groupies, drugs and trashed hotel rooms!
But since my “rock star” days, the public attention has faded a lot. In Pop Culture Time, the 1990s were eons ago. There are occasional flare-ups of weirdness, but mostly I just go about my quiet life and do my best to ignore the rest. I'm proud of the strip, enormously grateful for its success, and truly flattered that people still read it, but I wrote “Calvin and Hobbes” in my 30s, and I'm many miles from there.
Via Hacker News, Bill Watterson, creator of beloved 'Calvin and Hobbes' comic strip looks back with no regrets | Living - cleveland.com - cleveland.com
It's not the best Bill Watterson interview (a much better interview was done by Andrews McMeel Publishing) but that answer is just great.
The reason for even linking to this is that any interview with Bill Watterson is a very rare event. Heck, even pictures of the artist are very rare and so far, I think this is the only picture I've seen of him:
Quite the recluse, that Mr. Watterson.
He's also famous of not allowing any Calvin and Hobbes merchandising, although it does appear he relunctantly gave his endorsement for a new product coming out in July:
Wednesday, February 03, 2010
Perhaps an 80M script isn't that excessive …
Around three months ago, I found a bug in Lua (and yes, it's silly to run an 80M script, but then, I tend to do silly things with programs). I reported the error to the Lua mailing list, and a few days later it was posted as a known bug with a one line patch to fix it.
And yes, I just got around to retesting Lua (with a version that has every patch applied, including the patch for the bug I found) with my 80M script:
[spc]lucy:/tmp/lua>time lua -i show.lua Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio > dofile("default.lua") > os.exit() real 0m10.964s user 0m5.880s sys 0m0.376s [spc]lucy:/tmp/lua>
Much better.
Lua just in time
Playing around with Lua is fun, but I've been hearing some good things about LuaJIT, a “just in time” compiler for Lua for the x86 platform (written by a single guy, no less!). Even more amazing, it's literally a drop in replacement for Lua (both the command line interpreter and library).
Okay, I'm willing to give this a try. I download, compile and install it. I then decide to test it using jumble program I wrote in Lua. All I need to do is change one line:
#!/usr/local/bin/lua
to read:
#!/usr/local/bin/luajit
and rerun the program.
version | time in seconds |
---|---|
pure Lua | 7.74 |
pure LuaJIT | 3.57 |
Lua + C | 2.06 |
LuaJIT + C | 1.70 |
LuaJIT easily trounces the Lua interpreter without any code changes (other than specifying a different “interpreter”). The versions with C use a C function to sort the letters in the word and while LuaJIT was faster than the Lua + C version, the very fact that I didn't have to modify any code is fantastic! LuaJIT used the very same C code as the Lua version—no changes or recompilations required!
Very neat!
I just relinked my Lua daemon against LuaJIT, just to test it out, and yes, it worked without any changes. I could even reload the scripts on the fly. And incredibly, it's only about 50% bigger than Lua itself.
LuaJIT is one sweet piece of technology.
I can't remember the last time I used a printer …
I hate printers.
All I wanted to do was print out a 13 page file using both sides of the paper. It was easy enough to select the odd pages, then the even pages in the printer software. The hard part? Knowing which way to orientate the papers for printing on the second side.
It took me four attempts to get it correct.
Sigh.
So much for saving paper …
Saturday, February 06, 2010
Thinking outside the dusty box
My computer has a rather odd cutout in the front that tends to accumulate dust:
I've noticed recently that it's accumulated a metric buttload of dust (the shot above is after I've removed quite a bit of it, as shown below). Even Mark remarked how dusty it was in there.
So, the problem: how to go about dusting the thing. It was a thick blanket of dust, and I headed into the garage of Chez Boca thinking I might find a vacuum with a nozzle attachment that would fit in there when I came across the perfect solution:
The Lint Roller!
It's really just a very wide roll of masking tape with the sticky side out. The method is easy: just remove the outer sheet (it's about 6″×4″) and apply it to the dust.
A few lint sheets later and the computer is now dust free.
Sunday, February 07, 2010
Heaven forbid he ever try to climb a tree (not like it's easy to climb palm trees … )
I'm beginning to think child safety is getting way out of hand. I was driving home from resolving a customer issue (nothing major—just needed to reset a port on a switch—thank you ever so much, Monopolistic Phone Company), driving down the street towards Chez Boca when I saw a kid, maybe four or five years old, wandering about, on foot, close to home (easily within 50′ of the front door), wearing a bicycle helmet! There was no sign of any type of pedal-powered vehicle in the vicinity, although his mother was nearby, sitting on the front lawn watching out for the little kid.
He was wearing a bicycle helmet while walking!
Around his age, I was flying headfirst into ditches on my bicycle sans helmet and the only lasting affect is an inability to spell sertain words correctly. Well, that, and a tendency to say “that” instead of “who.”
He was wearing a bicycle helmet while walking, people!
Then again, I should be amazed he was let outside at all …
Insanity
- From
- Mark Grosberg <XXXXXXXXXXXXXXXXX>
- To
- Sean Conner <sean@conman.org>
- Subject
- Re: Password updated
- Date
- Tue, 5 Jan 2010 11:24:10 -0500 (EST)
On Tue, 5 Jan 2010, Sean Conner wrote:
What's the cookie2 header for?
I'm so glad you asked. This is almost so good it may cause you to blog about it (actually I figured by the time we were done discussing the insanity of cookies you may have had an insightful blog post anyhow).
I guess after the third cookie spec they figured they kinda sucked at this so they built in an escape. So after much re-re-re-reading of the RFC I think what happens is if you have received a cookie with a
$Version
that you don't understand you are supposed to just send back aSet-Cookie2:
header with$Version="version_this_thing_understands"
It's for future expandability so when we have 10 cookies specs clients and servers will “just work” (at this point I think we both know that statement is about as truthful as “the check is in the mail.”).
Well Mark (and yes, I know, it's been a month), the cookie specs are a paragon of clarity compared to the laughable mess that is syslog protocol specification. Had I been aware of the “informational nature” of RFC-3164 I might not have even started my own homebrew syslogd replacement (network stuff in C, high level logic in Lua).
How loose is the spec?
A program that wishes to use syslog()
may select a
“facility” the message will be logged under—think of “facility” as a
subsystem, like “mail” or “cron” (under Unix, cron
runs
scheduled tasks on a periodic nature) or “auth” (authorization, or login
credentials). Also, each message has a priority (kind of), one of
“debug”, “info”, “notice”, “warn”, “err”, “crit” (for critical
errors), “alert” (even more critical errors) and “emerg” (basically, the
machine is on fire, abandon all hope, etc.). The program using
syslog()
can also tag each message, usually with its name, and
the message itself has no real structure, originally being meant for human
consumption.
Now, the syslog protocol, which is used to send the messages to a program
that handles these messages, usually named syslogd
under Unix,
is a text based protocol, and a full RFC-3164 message would look something like:
<87>Feb 07 04:30:00 brevard crond: (root) CMD (run-parts /etc/cron.hourly)
You have the facility and priority (as a single number) in angle brackets, immediately followed by the timestamp, a space and then the name of the machine sending the message, a space and the tag (usually the name of the program on the machine sending the message), a colon, then the message.
And technically, every field is optional! Which makes parsing this a technical challenge. Not only that, but since there never really was a spec, it's easy to find ambiguous messages, such as:
<14>Jan 14 05:53:37 gconfd (spc-25469): Received signal 15, shutting down cleanly
which (per the spec) was sent from the program “(spc-25469)” on machine
“gconfd”. Funny thing is, I have no machine called “gconfd” but there
does exist a program called gconfd
that runs on my machine,
running as me, with a process ID of 25496 (fancy that).
I don't even want to talk about /Applications/Windows Media
Player/Windows Media
Player.app/Contents/MacOS/WindowsMediaPlayer
.
It gets even worse. RFC-3164 makes a point in saying that the following is a legal syslog message that has to be processed:
Use the BFG!
Just writing the code to parse this mess took the majority of time, as I kept coming across syslog messages that really weren't.
To work my way out of this mess, if I don't find a proper facility/priority field, I log the raw message (using facility “user” and level “notice”, which is what RFC 3164 says to use in the absence of such information). If there's no timestamp, okay, but if there is one but it's malformed, I log the raw message. I then check for an IP or IPv6 address, as I feel that's really the only sane value to use, then everything else up to a ':' is accepted as the tag value (more or less).
Is it perfect?
No.
But so far, it covers everything I've personally encountered. It will
misparse (which is a testcase I pulled from rsyslogd
), but not crash, on
seeing:
<130> [ERROR] host.example.net 2008-09-23 11-40-22 PST iapp_socket_task.c 399: iappSocketTask: iappRecvPkt returned error
Garbage in, garbage out (also, stuff like this can be checked in the Lua code, as the raw message is available in addition to the parsed message).
Cookies? Insane? Not really. Not when compared to the syslog protocol.
More than you care to know about syslog
So I've been learning more than I ever wanted to about the syslog protocol. There's the non-spec that is RFC-3164 that is optimistic in terms of the protocol. Then there's the cleaned-up spec that no one is using that is RFC-5424 (which is quite nice, if a bit over-engineered).
RFC-3164 documents the use of UDP as the transport protocol for the syslog protocol, reading that RFC one gets the impression that one should never actually use UDP as the transport mechanism, least some cracker intercept or change the messages, or worse yet—you lose some packets and get nailed in an Sarbanes—Oxley audit (or even worse still—an ISO-9000 audit—the horror! The horror!).
Well, you could try running the syslog protocol over TCP, but even that isn't good enough for some people, claiming that you can still lose logging information under certain circumstances. No, for reliability you need to add a layer of framing over TCP and wrap the syslog protocol in XML and call it a day.
So far, the only syslog program I've found that even pays RFC-3195 lip service is rsyslogd
, and
even then, it's receive only and uses its own framing layer over TCP for sending.
I personally haven't seen an issue with using UDP for the syslog protocol. Not only do I relay syslog messages to a centralized server (my desktop box at Chez Boca, so I can watch the stuff in real time) but copies are kept locally (just in case). Also, there have been times when a TCP version (yes, even if I was using RFC 3195 or the lighter RELP) would have failed (at one point, our upstream provider upgraded a firewall that filtered out TCP traffic routed asymetrically and guess what? Our traffic was routed asymetrically; UDP traffic was unaffected and thus in that case, we were able to isolate the issue faster). Even the design of SNMP centered around UDP simply because it was “fire and forget” and thus on a congested network, there was a greater chance of UDP traffic of making it out and accepted than TCP traffic (which requires an acknowledgment that might never make it back).
But in looking over these, I'm struck that a reliable syslog protocol doesn't use SCTP, which has the reliability, ordering and (most importantly, congestion control) of TCP with the message-based semantics of UDP. Heck, for “reliability” SCTP has one feature that neither TCP nor UDP have: either peer can change the IP address used for the session.
For now, I'll just stick with UDP.
Tuesday, February 09, 2010
Syslogintr—a syslogd replacement in C and Lua
So, why did I decide to write my own syslogd
? Well, it was
started as something to do while at Bunny's mom's house. I was curious as
to the actual protocol used by syslogd
because it's always
bugged me that the files written by syslogd
bear no information
about the facility or priority a message originally had. Sure, you can
filter by the facility and priority, but the resulting files lose
that information.
It was after reading RFC-3164 that I realized it might be possible to filter on more than just the facility and priority. Have Lua handle the logic of log analyzation and I had what I thought was a fun little project.
Heh. Little did I know.
Anyway, it's been in use for a little over three months (and 140 commits
to the source repository) and I must say, I'm finding it very
useful. Sure, I could have written a Lua script to parse the log files that
the traditional syslogd
writes, but I'm just cutting out the
middleman filesystem.
So the C code accepts, parses and hands a well-structured block of information to the Lua code, and it's the Lua code where all the features are implemented.
The information to Lua is passed in a table (which is Lua for an associative array, or hash table) with the following fields:
name | type | comments |
---|---|---|
name | type | comments |
version | number | This is the version of the syslog protocol, of which there are two—the documented version 1 which I haven't seen in the wild yet, and the conventional version which I've internally labelled as “version 0”. I currently only support version 0, so this field (as of this writing) is always 0. |
_RAW | string | This is the actual raw message as received. It was intended as a debugging aid, but I keep it enabled as it is useful when you get the odd message. |
remote | boolean | true if the message
came in over the network, false if it was generated
locally on the machine. I use this as a quick test. |
host | string | This is really the source of the
message. For a remote syslog message, this will contain the
IPv4 or
IPv6 address.
For messages generated locally, this will be the “local socket”
(formerly known as “Unix sockets”) the message was written to
(which on most systems is /dev/log ). |
relay | string | Usually this will be the same as
the host field, but when syslog messages are being
relayed, this is the intermediate system that relayed the message
on. If system A generated a message to B, and B relayed it to C,
then the host field will contain “A”, but the
relay field will contain “B”. If, however, it goes A
→ B → C → D, then host will contain
“A” and relay will have “C” (in other words—the
relay field will only contain the last relay
machine). |
port | number | The UDP port number the syslog message was sent from. If the message was sent locally, this will be -1. |
timestamp | number | This is the timestamp the
message as it was received on the accepting host. This value is
suitable for use in the Lua functions os.date() and
os.difftime() . |
logtimestamp | number | This is the timestamp as
found in the syslog message (if there was one). Otherwise, it will
be the same as timestamp . |
program | string | This is really the tag portion,
but since it's mostly the name of the program that generated the
syslog message, that's what I called this field. If it wasn't
given, the value of this field will be “”' (an empty string, not
nil ). |
pid | number | The process ID of the program that
sent the message. Most Unix syslogd implementations
have this as part of the tag, and if found, is set here. Otherwise,
it will be 0. |
facility | string | The facility, which will be one
of the following:
|
level | string | This is the priority of the
message, but the term “priority” never made much sense, so I call
it “level.” This will be one of eight values:
|
msg | string | The actual message, or basically, whatever is left after parsing everything else. This is pretty much a free-format string. |
This table is passed to a function called “log()” to handle however. On my development system, this function is simply:
function log(msg) writelog(msg) sshd(msg) end
writelog()
just logs the message to a single huge logfile
(that records the host
, program
,
facility
, level
and msg
fields).
It's the sshd()
function that's interesting:
if blocked == nil then blocked = {} end function sshd(msg) if msg.remote == true then return end if msg.program ~= "sshd" then return end if msg.facility ~= "auth2" then return end if msg.level ~= "info" then return end local ip = string.match(msg.msg,"^Failed password for .* from ::ffff:([%d%.]+) .*"); if ip == nil then return end I_log("debug","Found IP:" .. ip) if blocked[ip] == nil then blocked[ip] = 1 else blocked[ip] = blocked[ip] + 1 end if blocked[ip] == 5 then local cmd = "iptables --table filter --append INPUT --source " .. ip .. " --proto tcp --dport 22 --jump REJECT" I_log("debug","Command to block: " .. cmd) os.execute(cmd) I_log("info","Blocked " .. ip .. " from SSH") table.insert(blocked,{ ip = ip , when = msg.timestamp} ) end end
This checks for local messages from sshd
and if it finds
five (or more) consecutive failed attempts, adds the IP address of the
offending party to the firewall, and logs the attempt (via
I_log()
). Nothing that a lot of intrusion scripts don't
already do, but this is in the syslog daemon, not another process reading
this second hand through a file (and without the issues that come up with
log rotation).
Now, in order to keep the firewall from filling up, I added yet another feature—the ability to periodically run a Lua function. So, elsewhere in the script I have:
alarm("60m") function alarm_handler() I_log("debug","Alarm clock"); if #blocked == 0 then I_log("debug","Alarm clock---snooze button!") return end local now = os.time() I_log("debug",string.format("About to remove blocks (%d left)",#blocked)) while #blocked > 0 do if now - blocked[1].when < 3600 then return end local ip = blocked[1].ip I_log("info","Removing IP block: " .. ip) blocked[ip] = nil table.remove(blocked,1) os.execute("iptables --table filter -D INPUT 1") end end
alarm()
informs the C code to call the function
alarm_handler()
every 60 minutes (if you give
alarm()
a numeric value, it takes that as a number of seconds
between calling the function, if a string, it expects a numeric value
followed immediately by “m” for minutes, “h” for hours (so I could have
specified “1h” in this case) and “d” for days). The function
alarm_handler()
then removes the blocks one at a time (once per
hour) which is long enough for the scanner to move on.
Now, you may have noticed this bit of odd code:
if blocked == nil then blocked = {} end
One feature of the C code is that if it receives a SIGUSR1
,
the Lua script will be reloaded. This is to ensure that if there is any
IP blocks defined, I don't lose
any when the script is reloaded (and yes, that is a handy feature—change
the Lua code a bit, and have the daemon reload the script without having to
restart the entire daemon).
Along those lines, if the C code receives a SIGHUP
, calls
the Lua function reload_signal()
, which allows the script the
ability to close and reopen any logfiles it might be using (thus being
compatible with the current syslogd
behavior) which is useful
for rotating the logs and what not.
I'm also running this on my own server (brevard.conman.org
,
which runs this blog) and also one of our monitoring servers at The Company
(this one not only runs Nagios, Cacti and
snmptrapd
, but all our routers send their syslog information to
this server). The Lua code I have running on the monitoring server not only
keeps logging in the same files as the old syslogd
(in the same
format as well), but also this little bit of code:
function check_ospf(msg) if msg.facility ~= 'local1' then return end if string.match(msg.msg,".*(OSPF%-5%-ADJCHG.*Neighbor Down).*") then send_emergency_email("sean@conman.org",msg) send_emergency_email("XXXXXXXXXXXXXXXXX",msg) elseif string.match(msg.msg,".*(OSPF%-5%-ADJCHG.*LOADING to FULL).*") then send_okay_email("sean@conman.org",msg) send_okay_email("XXXXXXXXXXXXXXXXX",msg) end end
If the routing on our network changes, I get email notification of the
event. I also have some code that processes the logs from Postfix. Postfix
generates “thin
entries,” five entries per email (from various subsystems) when what I
really want logged are “fat entries” (which summarize the status of the
email in one log line). So, I wrote some code to catch all five lines per
email, and then just log a one line summary, thus changing a bunch of “thin
entries” to one “fat entry” (what I really want to do is send all mail
related logs on all our servers to one central location, so we no longer
have to check two or three servers everytime one of our customers complains
about email being “too slow” but that's for another show
entry).
The Lua code on my personal server also does the Postfix “thin-to-fat” conversion, but it also logs the webserver status every hour (just because I can).
And if you're wondering why I've blathered on and on about a piece of code I've yet to release, it's because I've yet to write any documentation on the darned thing, and I figure this would be a decent first pass at some documentation. And maybe to gauge interest in the project.
Wednesday, February 10, 2010
Notes on logging
This is interesting: Facebook wrote their own logging system instead of using syslog. Their system only has two pieces of informtion—a catagory and the message. No facilities, no priorities or levels. I think in Facebook's case, they log everything so there's no need for individual priorities or levels (the argument here is: you're going to log everything eventually anyway, so simplify the process).
Another note: when your configuration file is too complex (or in other words—an ad-hoc declarative language) perhaps it's time to give up and just use a scripting language for configuration (I skipped straight to using a scripting language for configuration/logic).
More notes on logging
I mentioned yesterday about logging
all mail related logs to a central server. While we don't have a
complicated email setup (unlike, say, Negiyo), we still have several email
severs and we get enough tickets about slow or lost email that it's a pain
having to slog through one or two servers piecing everything together. What
I would like is, given a Message-ID
(which is (supposed to be)
a globally unique identifier for an email) or an email address, to make a
query in one location and get something like:
message-id = <YzNCeWFXNW5RSE53Y21sdVoyUmxkeTVqYjIwPQo=@mx3oc.com> from = gandalf@example.net to = sean@example.com [rhohan-isp.example.org] [gondor.example.net] Feb 10 22:46:56 [gondor.example.net] [spamfirewall.example.com] Feb 10 22:46:57 [spamfirewall.com] [compmailserv.example.com] Feb 10 22:47:02 [compmailserv.example.com] [workstation.example.com] Feb 10 22:47:06 [workstation.example.com] mbox of sean Feb 10 22:47:06
As an example, you see the Message-ID
, who sent the email,
who received it, and the five other lines can be read as: machine X sent
email to machine Y at such-n-such a time,” with the last one showing local
delivery of the email to a mailbox.
Anyway, that's what I would like to build. And I can almost do it. Sendmail (which at
The Company we use on our legacy systems), Postfix (which we use for new servers)
and Exim (which we use
on one server because it has a feature that's needed by a program
that runs on that one server) all log a bunch of messages as email works
through their respective systems. Each one uses an internal unique ID,
but they at least log the Message-ID
at some point, so
I can map the respective MTAs internal IDs to a globally unique ID.
The odd-man out though, is our spam firewall, which is used by a
significant portion of our customers. But, given that our spam firewall is
OpenSource™ I suppose I can modify the source code to emit a
Message-ID
, but the problem there is if (or when) we
upgrade—I would have to patch the code again (or, convince the Powers That
Be to accept the patch).
I would also like to convert as many software packages to log via
syslog
, and while most, like PostgreSQL and even Apache, can be
configured as such, there are a few holdouts (I'm looking at you,
MySQL) that can't.
Wednesday, February 17, 2010
Dragons and Thunderstorms
Four months ago I attended a Drupal users group and I was underwhelmed since the group was mainly web developers, not programmers. So of course I found myself at a Ruby users group (so close that Wlofie and I walked there).
I went not because I'm terribly interested in Ruby (although getting a feel for the language certainly won't hurt) but because an old friend from college, Steve Smith had organized the meeting and I thought it might be nice to drop in and say hello.
It turned out that this group was more aligned with my interests than the Drupal users group. The first presentation was on distributed Ruby, which had a unique feature—if the local side could not marshall an object to send to the remote side, it basically signaled the other side to make a remote call back to do the actual processing, so neither side could really claim to be the client nor the server—both sides could act the role. It's a bit baroque for my tastes, but still, an interesting solution to a problem with remote procedure calls.
The second presentation wasn't a presentation as it was a discussion on design patterns in Ruby, which lead to a digression through the source code for Rails 3.0 and a few coding techniques that several of the more knowledgeable Ruby programmers in the room didn't realize were possible in Ruby (and a whole new way to write ravioli code—wow).
And oddly enough, they were interested in some of the projects I've done in Lua. So it's definitely a users group I can see going to again.
Friday, February 19, 2010
Glutton for punishment
Four months ago I attended a Drupal users group and I was underwhelmed, so I'm finding myself in a rather odd position—I'm giving a technical talk about Drupal at the 2010 Florida Drupal Camp tomorrow (Saturday—at <shudder> 10:00 am! Oh bother!) about the work I've done on “Project: DoogieHowser.”
I'm not sure what prompted me to volunteer for the presentation, other than misery loving company and a chance to rant about the sheer silliness of the project (or maybe just the guilty feeling from writing about that Drupal users group a few months back), but hey, I get a free trip to Orlando and other than the unholy earliness of the presentation, it shouldn't be that bad.
And besides, what could possibly go wrong with Smirk and me being out of town at the same time?
I should know better than that
“Oh, Sean,” said Smirk. “You know better than that!”
“I know, I know.”
Sigh.
Bunny warned me about asking what possibly could go wrong. Bunny and I encountered heavy traffic leaving the Boca Raton area, and I-4 was almost, but not quite, a parking lot at 7:30 pm.
But even that wasn't the issue. Nope. At 11:00 pm Smirk knocks on the hotel door. Apparently, one of our customers decided that tonight was the perfect night to rework their entire network and needed our help.
Head, meet desk.
Saturday, February 20, 2010
Notes from a hotel room from the middle of the night while listening to a heated discussion in Spanish
The Quality Inn room is very nice, but there were several men in a very heated discussion, outside as we were trying to sleep. Bunny called the front desk to complain, and was informed by the sole employee onsite at the time that the police were being called in to mediate the heated discussion.
Sigh.
An hour later, the very heated discussion was resolved, but that still left a bunch of people entering and leaving various rooms and making sure that their doors were closed shut.
I think things quieted down by 3:00 am, giving me a full three hours before the wakeup call.
Le sigh.
Just a quick note from a conference
Of course I'm blogging from the conference. Why do you ask?
My perspective on presentations
I managed to get through my presentation about “Project: DoogieHowser” although my presentation was a bit shorter than I expected it to be. But it appeared to go well with the audience.
Smirk has been recording all the sessions with the goal of putting up the videos at Drupal Maestro (where you'll be able to see my presentation, but not from my perspective).
And if that wasn't bad enough, I volunteered to do yet another
presentation, this time about Git, since there was an open session and one
of the suggestions for a topic was git
. Since I use
git
, I figured I could do a quick rundown on how to use it.
A realization
While I was underwhelmed by the Drupal users group, I am not underwhelmed here at the 2010 Florida Drupal Camp.
But then again, I'm sitting through the Special Topics track, which have the more technical talks at the conference. Everybody has been very nice (obviously, they haven't read that post) and the catered lunch was quite good. I'm actually glad I came to this thing.
Now, to prepare for my git
presentation …
It is over
The git
presentation was well received, as I briefly covered some basic git
commands like git init
, git add filenames…
and git commit
, along with a few different workflows one can do with git
.
After that, a two-plus hour dinner at Macaroni Grill, dinner for 60.
Now, I crash.
Monday, February 22, 2010
Souvenir from a conference
I crashed hard, mainly because, I caught yet another cold (second this year so far—or perhaps a continuation of the first, it's hard to say). Snotty nose, tired, sneezing, the whole nine yards.
I really hate being sick.
Tuesday, February 23, 2010
Crawler Town
For my friends who are into Lego, I give you:
Crawler Town (link via kisrael.com)
Now, back to my regularly being sick …
Wednesday, February 24, 2010
Noooooooooooooooooooooooooooo!
or