Content tagged Programming

An Emulator Design Pattern

posted on 2012-06-22 17:49:15

Going into this project, I knew almost nothing about emulation. I still know very little. But I was tired of seeing emulators written in C and Java for performance or portability that wound up looking like a big switch statement sooner or later. My 6502 emulator is ANSL CL and should run anywhere that sbcl, clisp, ccl, or any other fine Common Lisp implementation will run. Granted, if a totally new processor architecture comes out, it's probably easier to cross-compile/port a 6502 in C than the CL compiler hosting cl-6502 but I digress. I wanted to write a fast, high-level emulator. The closest thing I found to an emulator design that I liked was py65 but even that was a bit less abstract than I would've hoped.


I'm still searching for ways to improve the core abstractions that I have (and no doubt there are many hardcore low-level hackers that would be disgusted by my work) but I'm enjoying the process and here are some preliminary thoughts...


Addressing modes!


 

Addressing modes, addressing modes, addressing modes. This is the biggest difference between assembly language and the languages I use day to day. Hence, it's a crucial abstraction to get correct. For the first time, Common Lisp's notion of "generalized places" has been a real boon. There were two nuances to addressing modes that I found I really needed to account for.



  • Some modes access CPU registers, others RAM. (This mostly just effects the way I need to use setf.)



  • Most opcodes use the byte /at/ an address rather than the address, but sometimes an opcode *does* need the address.




To solve these issues and abstract some code patterns, I wrote a macro called defaddress. It defines a method on the CPU that returns the address computed by the mode /and/ generates a setf function that sets the register in the CPU struct or the byte in memory based on a cpu-reg keyarg to the macro. Finally, to solve the issue that we most often want the byte, opcodes are defined as either being :raw or not (the default). If they're not, instead of passing the mode symbol to be funcalled, we pass a lambda that gets the byte at the address computed by the mode. So far, concerns seem nicely separated. Time will tell if I've struck on the right design here.


Opcodes


 
Opcodes in cl-6502 are really mnemonics, a set of opcodes that encode the same language primitive but for different addressing modes. As long as the foundation of addressing modes as funcallables is there to support the opcodes, you can write any opcode cleanly with a single body of code shared across all addressing modes. This has made me deeply happy as it seems to me to be _THE RIGHT THING_.



The implementation of defopcode is a bit hairy, particularly the EVAL-WHEN block to make sure metadata about the opcodes gets set in the *opcodes* array at load-time, but the supporting defins macro is fairly clean. The important thing is that opcode definitions wind up looking marvelous. For example, here's ASL and BCC:

    (defopcode asl (:docs "Arithmetic Shift Left" :raw t)
((#x06 5 2 'zero-page)
(#x0a 2 1 'accumulator)
(#x0e 6 3 'absolute)
(#x16 6 2 'zero-page-x)
(#x1e 7 3 'absolute-x))
(update-flags (funcall mode cpu) '(:carry))
(let ((result (wrap-byte (ash (funcall mode cpu) 1))))
(update-flags result)
(funcall setf-form result)))

(defopcode bcc (:docs "Branch on Carry Clear" :track-pc nil)
((#x90 2 2 'relative))
(branch-if (lambda () (zerop (status-bit :carry cpu))) cpu))

ASL defines 5 methods here each with a different addressing mode but sharing the same body. They update flags in the status register as expected, increment the program counter properly, and put metadata in *opcodes* to aid with dispatch and disassembly. Not bad, eh?


Objects, Functions, Macros, Whatever!


 
So far, I've mostly just used objects (read: CLOS) to define some conditions, two core methods on the CPU (step and execute), and the instructions themselves. The CPU itself is defined as a Struct rather than a Class. All the instructions are methods EQL-specialized on the opcode and the opcode alone which should make dispatch pretty speedy. The methods reference the *cpu* global directly and since Common Lisp has /usable global variables/ that look up the most recent binding in the current thread on reference, I should be able to run many instances safely in different threads on a single core. Just do something like...

    (make-thread :foo (lambda ()
      (let ((*ram* (make-array (expt 2 16) :element-type '(unsigned-byte 8))
            (*cpu* (make-cpu))))
        &body))) ;; and we're off to the races!

What's next?


 

I have a bunch of potential ideas for what's next. I want to extend this work towards full NES emulation in the browser. There isn't a formal ordering of priorities or milestones yet (cause this is kind of an art project), but coming up with a sane, RESTful API to sit on top of cl-6502 is probably the next step. Hopefully I'll get some time to hack on that this weekend.

  • cl-6502: An assembler! Unit tests + bug fixing.

  • famiclon: An NES emulator backend built on romreader and cl-6502. Video, Sound. Input?
  • Qeng-Ho: Hunchentoot+ST-JSON, REST API wrapping cl-6502+famiclon, No persistence! Multiple CPUs! Internal private API for now.

  • Pham-Nuwen: Clojure+Clojurescript@Deepclouds.net. Persistence! Nice web interface. Graphics w/canvas! Etc...

  • cl-z80: DO THAT SHIT! (how hard could it be? just another 8bit thing. see emu-docs.org)

On Interactive Retrocomputing

posted on 2012-06-18 04:27:59

Lately, I've been working on an emulator for the MOS 6502 processor in Common Lisp that I've been boring enough to name cl-6502. The emulator is basically finished as is the disassembler. There are also pretty solid docs. An assembler should be added soon and hopefully a helper utility or two and unit tests. But why do this? Well, for a couple of reasons.

1) I never did enough Systems Programming. I never did any assembly in college and wrote an absolute paucity of C (granted, that's my fault). I never learned enough about the inner working of Operating Systems or how to exploit memory hierarchies. I want to know more about how the machine works at a low level. Writing an emulator in a high-level language isn't a great way to do that but I wanted to anyway. Writing some assembly programs to run on this emulator might help though and I hope to do some of that later.

2) I was curious how concise, extensible, and performant an emulator could be written with Common Lisp. Most emulators are written in C/C++ for performance reasons. There are a few in Java (for portability?) or Javascript for what we now call portability but even these are not terribly high-level from a design perspective. I don't have all the answers to this question yet but I'm excited by some of the work I've done so far. In particular, writing macros for Addressing Modes and Opcodes has been quite helpful and I expect CLOS's :before, :after, and :around methods to go a long way where extensibility is concerned. I'm hoping the EQL-specialized methods, SBCL, and perhaps some shrewd profiling can lead to good performance. Also, 45 lines of code for a 6502 disassembler doesn't seem bad to me. :P

3) ICU64/Frodo Redpill. I'm not wild about static types and I tend to write tests after the fact because I view programs as clay until they're ready to be fired in the kiln. Roly Perera's work on self-explaning computation interests me a lot as does Chris Granger's work on Light Table. Rapid feedback loops are important. Maintaining flow is important. As far as I'm concerned, all emulators should strive towards the sort of "peek/poke the machine" experience that ICW/Frodo Redpill offers. Games are a very easy way to get people to engage with computers. Everybody likes games. And lots of folks at some point in wondering about programming, ponder how much is involved in changing something about a game they like. With a system like ICU/Frodo Redpill they could literally /see/ the answer. Add an integrated editor and you're in pretty interesting territory. Feel like changing something about the "hardware"? Feel like having breakpoints and step debuggers pop up on arbitrary memory accesses or instruction executions? You got it. But ICU64/Frodo Redpill has this all locked down on desktops. Why not do as much as possible with HTML5, <canvas>, and Clojurescript? I'm not going to be the guy to come up with the next Mother of all Demos ... but I hope to make something cool. And if I'm really lucky, I'll have something interesting to play with online by Strange Loop on September 23rd. I've already got a 6502 emulator. What's next?

A tentative Strange Loop 2012 Schedule

posted on 2012-06-17 00:30:57

Strange Loop has posted their schedule for 2012 and my company has been kind enough to send me. Without further ado, here's my current thought on which talks I'll attend. I just can't wait for September. :)

;; Sunday, September 23 (Emerging Languages Preconf)
-- 7:30 flight? ZOMG WHAT WAS I THINKING?!?
09:30 Jeremy Ashkenas - Symbiotic Languages: Transpiling into Javascript
10:30 Ostap Cherkashin - Bandicoot: code reuse for the relational model
11:30 Hakan Raberg - Clever, Classless and Free?
12:40 Michael Fogus - The Reemergence of Datalog
13:20 Brian McKenna - Roy
14:40 David Herman - Rust
15:50 James Noble - Grace: an open source educational OO language
16:30 Jose Valim - Elixir: Modern Programming for the Erlang VM
17:10 David Pollak - Visi: Cultured & Distributed

-- STRAAAAANNNGE LOOOOP
;; Monday, September 24
09:00 Michael Stonebraker - In-Memory Databases
10:00 Dustin Getz - Monad Examples for normal people, in Python and Clojure
11:00 Pieter Hintjens - Software Architecture using ZeroMQ
-- (or Functional Design Patterns - Stuart Sierra)
12:20 Neil Milstead - Augmented Reality and CV
13:00 Craig Kersteins - Postgres Demystified
14:00 Neha Narula - Executing Queries on a Sharded Database
-- (or Clojurescript by David Nolen)
15:30 Scott Vokes - Data Structures: The Code That Isn't There
-- (or Lessons from Erlang by Garrett Smith, Types vs Testing by Paul Snively and Amanda Laucher) GAAH
16:30 Rich Hickey - The Database as a Value
17:30 Lars Bak - Pushing the Limits of Web Browsers
20:00 Matthew Taylor - Humanity 2.0

;; Tuesday, September 25
09:00 Jeff Hawkins - Computing Like the Brain
10:00 Chris Granger - Behind the Mirror
11:00 Nathan Marz - Runaway complexity in Big Data...and a plan to stop it
12:20 Carlton Mills - Computer Architecture of the 1960s
13:00 Oleg Kiselyov - Guess lazily! Making a program guess and guess well
14:00 Cliff Moon - The Audubon Society for Partial Failures
15:30 Ola Bini - Expressing Abstraction, Abstracting Expression
-- (or Building visual, data-driven UIs with ClojureScript)
16:30 Bret Victor - ?
-- And then I'm out because of my 7:30 flight. Sorry Brendan Eich!

 

10 Great Hacking Albums

posted on 2012-06-06 18:23:52

My posts on this blog have leaned away from technical content for the last year, tending towards the introspective and music or poetry. I'm hoping to start shifting back in the other direction for a little bit and plan to write about my latest personal hacking project soon. In the interim, here are 10 favorite albums to write code to off the top of my head. I will note at the outset that I prefer ambient and instrumental music for hacking. Ambient stuff in particular seems to naturally encourage a state of "flow" for me. Also, here's a link to some C2 wiki discussion on flow as it relates to programming. Also, as long as we're throwing out great hacking music I might as well shill the mixtapes I've been working on the last two months. :) All three are pretty solid. And there's a one hour extended mix that mashes together I/Omega and Lost Without a Traceback that isn't on soundcloud. Ping me if you're interested. There are some track changeups and much improved transitions in the I./Omega half.

Hackerjams:
Tim Hecker - Harmony in Ultraviolet
Tim Hecker - An Imaginary Country
Tim Hecker - Ravedeath, 1972
Fennesz - Venice
Fennesz - Black Sea
Fuck Buttons - Tarot Sport
Rustie - Glass Swords
Araabmuzik - Electronic Dream
Four Tet - There Is Love In You
Amon Tobin - Supermodified

(Honorable Mentions: Tycho - Dive, Washed Out - Life of Leisure)

If you were to proceed through the above albums in sequence, you'd start with some fantastic downtempo ambient/noise stuff with Hecker and Fennesz, shift into uptempo "noisetronica" with the Fuck Buttons, transition into the over the top and in your face Rustie, ride those dancey vocals and synths into Araabmuzik, and then start winding down with the more midtempo vocals of There Is Love In You and the outstanding groove of Supermodified.

On Data Loss

posted on 2011-10-27 21:02:24

I've been meaning to blog more and have a more long-form, personal post in the works. Hopefully I'll get that out tonight. I don't reflect as much through writing as I used to and I miss that. Anyway, something interesting just happened at work. We have a beloved IRC bot at my office named olga. One of our favorite features of olga is that she'll write a haiku for us on demand. More precisely, we can give her a phrase that is five or seven syllables and she'll remember it. When we ask her to construct a haiku she picks two random 5-syllable phrases and a random 7-syllable phrase. The most impressive invocation of olga haiku I've seen to date is: "What we do in life / Is there a step I'm missing? / Inexorably". I wish *I'd* fucking written that. It's gorgeous.

So...I inadvertently deleted all of olga's sevens. Someone was asking for an example of how to *remove* an entry and I posted an example that apparently matched a perl regex to nuke the universe. So I trust perl even less now and I've never even actually used it. The fiasco resulted in this delightful github commit fixing the vulnerability. We modify olga's haiku database a few dozen times a day conservatively. It's like a collective cultural store for our exceedingly delightful and nerdy hackers. After the chaos and laughter subsided, a coworker and I grepped through our irc logs of the past few months searching for matches to the "haiku add.*sevens" pattern. We'll probably be able to restore things decently enough. There are server admins with still more extensive logs we may be able to get access to...but that's not what's interesting about this to me. What's interesting about this to me...is the emotional response we had to the whole event which made me think that data loss with computers in modern times can be somewhat akin to a phantom limb sensation.

Think about it. You have *no* idea how much data you have and, if you're a quirky statistical outlier archivist-type like me, only a vague idea of what the most important and recent elements in that dataset are. You probably don't even know *where* your data is. It's on Google's servers, Amazon's servers, your phone, your PC (possibly several) and maybe even your personal server. Even if you're not a hacker/computer type, you've got data coming out of your ears. In modern society, effectively *EVERYONE* is an information packrat. And the question is, what cognitive and emotional burden does that sort of behavior result in?

The most interesting part to me is that I suspect many cases of data loss aren't troublesome unless you're aware of them. We have *so much* data that unless you're sure an operation accidentally deleted data you didn't intend to lose, you might never miss it. How big is olga's 7-phrase dataset? I have no idea. But I honestly expect it's in the high hundreds if not thousands of phrases. If we lost 100 of them...would we ever notice? Doubtful. But *knowing* that a bunch of data was accidentally lost feels like losing property except for the fact that it's hard to assess just what value that property had, what measures can or should be taken to ameliorate the event, what meaning the loss really has.

This has funny implications for SciFi authors as well. The idea of memory diamond or some sort of storage medium for someone to record their entire life (lifelogging) is predicated on the fact that no data would ever be lost...because at that scale, you simply don't know what is important and what can be lost because the *value* of the data is context-sensitive, especially temporally. Moments of nostalgia make it impossible to say, "Scrap this, lose that", and if you don't know what data has been lost then the whole thing is suspect. And don't laugh *too* hard, between Steve Mann, the MIT Media Lab and folks at Yale and elsewhere there's a decent amount of research towards making lifelogging possible. Anyway, I just wanted to get some of these thoughts down. It's definitely been another fun day at the office. :)

Editor's Note: Discussions with a coworker have reminded me of two things:
1) We really are likely statistical outliers much more than this post suggests. I tried to hint at this possibility with the archivist bit but it's never the less important to reinforce.
2) People obviously know the difference between important data and unimportant data. This interesting phantom limb-like effect really seems to come out with tons of miscellaneous, less important data (IRC logs, browsing history, etc) that you keep because you can rather than essential information or emotionally substantive data (photos, videos, MP3s, certain emails, etc).

Random Updates

posted on 2011-04-01 22:25:45

The last 2 months have flown by. My time as an undergrad is coming swiftly (and happily) to an end and I'm finalizing my plans for after graduation. I said Paktahn 0.9.4 would be out by the end of February and wound up being two weeks late on that. Paktahn 0.9.4.8 is out now and my users seem to be pretty happy. At the end of the day, it's all about customer service. There were a number of bugfix/point releases to 0.9.4 due to the libalpm C library that paktahn has long used having some API changes in version 6 that needed accomodating. I found a regression in libalpm though which was pretty fun.

I seem to be staring at a lot more C code this semester than usual. Aside from paktahn, one of my classes has me working on the cl-opencv library which is a set of FFI bindings to Intel's OpenCV computer vision library. This semester has been the first time I've used CL's FFI and the CFFI library and in spite of some hiccups it's been a lot of fun. It certainly opens up a new world of possibilities being able to reuse all the C code that's already been written. I remember looking into /usr/include/ one day recently, seeing gobs of C header files and feeling joy. It almost makes me want to write and compile some C myself. ... Almost. ;) Unfortunately I have more than enough lisp software to keep me busy for a spell and I hope to have more to say on that subject very soon.

Other than school I've been enjoying skateboarding, as usual, and eating lots of Sushi. And my latest musical kick, as I'm sure some of you were wondering, is Childish Gambino. Gambino is the alias of Donald Glover who you may also know as Troy from the delightfully funny TV show Community and as a former staff writer on 30 Rock. His EP and last album, Culdesac, are available on his website for free. The guy is crazy prolific. That's all for now...

A Common Lisp Web Development Primer, Part 3

posted on 2010-11-22 04:24:03

Disclaimer: What? You haven't already read the first two parts? Feel free to go ahead and do that. The same disclaimers apply. (require 'cl-wdp-part1 'cl-wdp-part2)

Today's Topics


The main topics we'll be covering are Weblocks widgets, forms and views along with a brief example of creating a presentation to use jQueryUI's Datepicker. There will also be a brief aside on what to do after an emergency reboot or power outage relating to cl-prevalence and trivial-timers. By the end the clockwork site will be fully functional.

Form-widgets, Widgets and Views


The User Guide has pretty nice expository summaries of Widgets and Views. The bottom line is that Widgets are what Weblocks pages are composed of and views are different ways to render those widgets. A macro called defwidget is used to construct widgets which are just new classes which inherit from the widget-metaclass. Don't worry if you don't know what that means. Essentially, you define widgets for the data you care about working with and then you define views to render that data, whether as a form for editing, a table for comparing multiple items or some other representation.

Leslie has been working on some new form-widget code intended to remove some of the sharp edges of the current system. As this site is basically just a form it made sense for me to try to use this new code (and Leslie wanted me to help him bang on it). Consequently, one thing you'll need to do is add (load "/path/to/weblocks/contrib/lpolzer/form-widget.lisp") to your init.lisp file that runs on startup. It should be placed after weblocks is loaded and before the loading of clockwork.

Last time we defined a reminder class with slots for the data we really care about: a list of emails, a title and summary and timestamps for when to send that message and when the event itself occurs. However, it won't do to ask our users to input timestamps or to tell us the "email" for their cell phone's SMS gateway. To that end, we'll define a view to gather the information we really need to construct the timestamps and other parts of the reminder. We need to know whether they want to be notified by email, text message or both. We'll need the corresponding contact info, including their cell carrier if they want to be notified by text message. We'll also need to note the event date, timezone and time as well as how long before the event they'd like to be reminded and a message and title. I've also thrown in a "honeypot" field. In theory, spam bots will indiscriminately fill it so we won't get any bogus submissions because the form won't validate. Maybe later we'll replace this with reCaptchas.

So let's get to it and define a view for our form in a new file src/forms.lisp. Insert the following code:

(in-package :clockwork)

(defview reminder-form-view (:type form :caption "Schedule an Event Reminder..."
:buttons '((:submit . "Submit")) :persistp nil)
(send-as :present-as (dropdown :choices '(("An email and a text." . :both)
("Just an e-mail." . :email)
("Just a text." . :text))
:welcome-name "How to send it")
:requiredp t)
(email :satisfies 'valid-email)
(cell-number :satisfies 'valid-cell-number)
(cell-carrier :present-as (dropdown :choices *sms-gateways*))
(event-date :present-as (calendar) :requiredp t)
(event-hour :present-as (dropdown :choices *hour-choices*)
:requiredp t)
(event-minute :present-as (dropdown :choices '(("00" . 0)
("15" . 15)
("30" . 30)
("45" . 45)))
:requiredp t)
(timezone :present-as (dropdown :choices *timezones*)
:requiredp t)
(remind-me :present-as (dropdown :choices '(("At the event" . 0)
("5 minutes before" . 300)
("10 minutes before" . 600)
("15 minutes before" . 900)
("30 minutes before" . 1800)
("45 minutes before" . 2700)
("1 hour before" . 3600)
("2 hours before" . 7200)
("1 day before" . 86400)
("2 days before" . 172800)
("1 week before" . 604800)
("2 weeks before" . 1209600)))
:requiredp t)
(subject :requiredp t)
(summary :present-as (textarea :rows 5))
(honeypot :label "Leave this blank" :satisfies #'null))

(defparameter *timezones*
'(("UTC-12:00 (Eniwetok, Kwajalein)" . -43200)
("UTC-11:00 (Midway Island, Samoa)" . -39600)
("UTC-10:00 (Hawaii)" . -36000)
("UTC-09:00 (Alaska)" . -32400)
("UTC-08:00 (Pacific Time)" . -28800)
("UTC-07:00 (Mountain Time)" . -25200)
("UTC-06:00 (Central Time)" . -21600)
("UTC-05:00 (Eastern Time)" . -18000)
("UTC-04:00 (Atlantic Time, Caracas)" . -14400)
("UTC-03:30 (Newfoundland)" . -12600)
("UTC-03:00 (Brazil, Buenos Aires, Georgetown)" . -10800)
("UTC-02:00 (Mid-Atlantic)" . -7200)
("UTC-01:00 (Azores, Cape Verde Islands)" . -3600)
("UTC+00:00 (Lisbon, London, Casablanca)" . 0)
("UTC+01:00 (Berlin, Brussels, Copenhagen, Madrid, Paris)" . 3600)
("UTC+02:00 (Kaliningrad, South Africa)" . 7200)
("UTC+03:00 (Baghdad, Moscow, Riyadh, St. Petersburg)" . 10800)
("UTC+03:30 (Tehran)" . 12600)
("UTC+04:00 (Abu Dhabi, Baku, Muscat, Tbilisi)" . 14400)
("UTC+04:30 (Kabul)" . 16200)
("UTC+05:00 (Ekaterinburg, Islamabad, Karachi, Tashkent)" . 18000)
("UTC+05:30 (Bombay, Calcutta, Madras, New Delhi)" . 19800)
("UTC+05:45 (Kathmandu)" . 20700)
("UTC+06:00 (Almaty, Colombo, Dhaka)" . 21600)
("UTC+07:00 (Bangkok, Hanoi, Jakarta)" . 25200)
("UTC+08:00 (Beijing, Hong Kong, Perth, Singapore)" . 28800)
("UTC+09:00 (Osaka, Seoul, Sapporo, Tokyo, Yakutsk)" . 32400)
("UTC+09:30 (Adelaide, Darwin)" . 34200)
("UTC+10:00 (Eastern Australia, Guam, Vladivostok)" . 36000)
("UTC+11:00 (Magadan, New Caledonia, Solomon Islands)" . 39600)
("UTC+12:00 (Auckland, Fiji, Kamchatka, Wellington)". 43200)))

(defparameter *hour-choices*
(loop for i from 0 to 23
collecting `(,(format nil "~d" i) . ,i)))

So here we're defining a view called reminder-form-view and passing in a list of arguments *about* the view as well as a list of fields in the view. In the list of arguments about the view we note that it's a form and we don't want to persist the form contents directly. We use a variety of keywords in the list of form fields to get the behavior we want including :present-as, :requiredp, :satisfies and :label. Present-as allows us to make something a dropdown or any other defined presentation. Note that some presentations do take arguments. Dropdown in particular takes a list of dotted pairs representing the Dropdown choice and it's corresponding value. Requiredp does what you'd expect and marks a form field as required. Satisfies takes a lambda or the name of a function which will validate the field's data. By default, the view will "humanize" the field names and use those humanized names as labels. If you want a different label for some reason, you can achieve that with the :label keyword.

Now we have a form that takes all the data we need to construct a reminder but we still need to validate the emails and cell phone numbers. Additionally, we'll need to write helper functions to construct the email list and timestamps that the reminder's emails and timestamp slots will be set to. Consequently, add this code to the bottom of the file:


(defun valid-email (user-input)
"Ensure that there is an @ and a . and input not containing @s before and after each."
(or (cl-ppcre:scan "^[^@]+@[^@]+\\.[^@]+$" user-input)
(values nil "Your email must have an @, a . and text before and after both.")))

(defun valid-cell-number (user-input)
"Ensure that only numbers are given and there are at least 10."
(or (cl-ppcre:scan "^[0-9]{10,}$" user-input)
(values nil "Your number must have only numbers and at least 10 of them.")))

(defun get-emails (form-data)
(with-form-values (send-as email cell-number cell-carrier) form-data
(let ((sms-mail (concatenate 'string cell-number "@" cell-carrier)))
;; this was an ecase with keywords but weblocks converts
;; the keywords to strings somewhere in form submission
(cond ((string= send-as "BOTH") (list email sms-mail))
((string= send-as "EMAIL") (list email))
((string= send-as "TEXT") (list sms-mail))))))

(defun get-timestamps (form-data)
(with-form-values (event-date event-hour event-minute
remind-me timezone) form-data
(let* ((hour (parse-integer event-hour))
(minute (parse-integer event-minute))
(reminder-time-period (parse-integer remind-me))
(timezone (parse-integer timezone))
(datestring (split-sequence #\- event-date))
(day (parse-integer (first datestring)))
(month (parse-integer (second datestring)))
(year (parse-integer (third datestring)))
(event-time (encode-timestamp 0 0 minute hour day month year :offset timezone)))
(list event-time
(timestamp- event-time reminder-time-period :sec)))))


The validation functions are ORs with the function testing the input as the first clause and a VALUES form returning nil (a failed submission) and an appropriate error message as the second. The helper functions use the with-form-values macro to grab the relevant fields of the form and construct the resulting slot. Get-timestamps is rather nasty but we're essentially just grabbing all those fields pertaining to the time, parsing the integers from them and passing those on to the appropriate timestamp functions in the local-time library.

A Calendar Presentation


It would certainly be better to have a nice calendar than have users enter dates as strings and then try to validate them and God forbid we roll our own given the number of Javascript calendars already out there. Since it's fairly well established I opted for the jQueryUI Datepicker. Previously to use Javascript libraries you needed to download them and place them in your Weblocks project's pub/script folder but thanks to a quick patch by Leslie Polzer remote dependencies are now also supported. In case you didn't read the previous article, when you first start a project with (wop:make-app 'name "/path/to/app") weblocks generates a defwebapp form and a basic package for that app along with setting up a store and some basic resources. To include the jQuery code on our page we'll modify our defwebapp form in clockwork.lisp like so:

(defwebapp clockwork
:prefix "/"
:description "Fire-and-Forget Event Reminders"
:init-user-session 'clockwork::init-user-session
:autostart nil ;; have to start the app manually
:ignore-default-dependencies nil ;; accept the defaults
:hostnames '("clockwork.redlinernotes.com")
:dependencies '((:stylesheet "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/themes/ui-darkness/jquery-ui.css")
(:script "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js")
(:script "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js")
(:javascript-code "var $jquery = jQuery.noConflict();"))
:debug t)


First let's note that this will include these dependencies in the "HEAD" of every page. If you want to have per-widget dependencies Weblocks does support that by (if I'm not mistaken) defining a widget-public-dependencies method specialized on that widget. Since we only have one page in this app anyway we'll just list them here. We've done that by adding entries to the dependencies list that use Google's CDN to supply the minified jQuery and jQueryUI libraries along with a stylesheet for the jQueryUI stuff. We added the :hostnames argument which specifies that requests to any host besides those listed are to be ignored. This is particularly helpful if you're running multiple webapps off of one server but want them to share a Lisp image and port rather than fire up separate Hunchentoot servers for each one. Additionally, we're inlining the js code that calls jQuery.noConflict() in the header because Weblocks uses prototype and scriptaculous out of the box and jQuery will happily steal the $ global variable from Prototype which causes all sorts of havoc. While there is interest in removing the prototype and scriptaculous dependencies it hasn't happened yet. It would be greatly appreciated if any developer felt like taking a little time to tackle this.

So now that we've included the JS code, let's write a presentation. The presentation lets us add the code :present-as (calendar) to a slot in our View and have it render as a calendar. This presentation will be a little different as we're using Leslie's new form-widget code. A more traditional coverage of presentations can be found in this blog post. Create a new file in the src directory called calendar.lisp and insert the following code:

(in-package :clockwork)

;; calendar presentation
(defclass calendar-presentation (input-presentation)
())

;; calendar form-widget code
(define-widget calendar-field-widget (field-widget)
()
(:default-initargs :parser (lambda (raw-value)
(values t raw-value))))

(defmethod field-presentation->field-widget-class ((presentation calendar-presentation))
'calendar-field-widget)

(defmethod render-field-contents ((form form-widget) (field calendar-field-widget))
(with-html
(:input :type "hidden" :name (name-of field) :value (datestring))
(:div :id "datepicker"
(send-script '($jquery (lambda ()
(ps:chain ($jquery "#datepicker")
(datepicker (ps:create date-format "dd-mm-yy"
min-date 0
on-select (lambda (date inst)
(ps:chain ($jquery "[name=event-date]")
(val date))))))))))))

(defun datestring ()
(subseq (format-timestring nil (now) :format '((:day 2) "-" (:month 2) "-" :year)) 0 10))


So what's going on here? First we define a calendar-presentation class and a calendar-field-widget class along with a simple method to map the presentation onto the widget-class. Then we write the bulk of the code, a render-field-contents method which generates the HTML and Javascript. We'll use a hidden input field with a name equal to the field in the view that gets initialized to today's date. That will be followed by a div containing the Javascript code for the datepicker written with Parenscript (indentation suggestions welcome) which sets the hidden input field whenever a date is selected.

Putting it all together...


Now that we have all the pieces we need we can hook them together. You'll note that a src/init-session.lisp file already exists and contains a defun for init-user-session. This function sets up the widget tree and creates a new session when users visit the site. Remove the old definition and insert the following into the file:

(defun init-user-session (root)
(setf (widget-children root)
(make-reminder-form)))

(defun make-reminder-form ()
(let ((reminder-form (make-instance 'form-widget :on-success 'submit-reminder-form)))
(form-widget-initialize-from-view reminder-form 'reminder-form-view)
reminder-form))

We're just defining a separate function (make-reminder-form) to create our form instance here rather than defining it inline in the init-user-session code. Make-reminder-form itself creates an instance of the form-widget class which runs a function called submit-reminder-form when the form is successfully submitted (i.e. passes validation, etc). Note that we have not yet defined submit-reminder-form. Because the form is really based on a view and not a widget or class we want to persist we'll use form-widget-initialize-from-view in conjunction with the reminder-form-view we defined earlier. Note that you may need to restart the webapp after redefining the init-user-session function. Run (restart-webapp 'clockwork) and check the homepage. You should now have a nice form complete with jQuery Datepicker. But of course, nothing useful happens on submission. Time to fix that by going ahead and defining submit-reminder-form. Open src/init-session.lisp back up and insert the following:


(defun submit-reminder-form (widget)
(let ((new-reminder (create-reminder widget)))
(schedule new-reminder)
(persist-object *clockwork-store* new-reminder))
(reset-form-widget widget))

(defun create-reminder (form-data)
(with-form-values (subject summary) form-data
(let ((timestamps (get-timestamps form-data)))
(make-instance 'reminder
:emails (get-emails form-data)
:title subject
:summary summary
:timestamp (first timestamps)
:at (second timestamps)))))

Note that I wrote this in a way that's fairly natural to Lisp. I wrote submit-reminder-form in what almost resembles pseudocode and ensured it expressed my intent before worrying about writing a helper function to make that possible. So submit-reminder-form creates a new-reminder by passing the widget to create-reminder, schedules and saves that new-reminder in the Prevalence store and then resets the form. To make this possible, create-reminder uses with-form-values to scrape out the subject and summary from the form, then we grab the timestamps and emails using the functions we wrote for that earlier and instantiate the reminder object accordingly. At last the site is fully functional for sending email or text message reminders!

Recovering from Failure


We haven't covered what to do in case of an emergency reboot or other failure. Since everything is persisted by prevalence on submission the *clockwork-store* will still have our reminders. All we have to worry about is ensuring that all the timers get rescheduled. This is so simple it hurts. Reopen src/reminder.lisp and add the following code to the bottom of the file:

(defun recover-reminders ()
"A function to reschedule reminders after a reboot. Based on testing,
any that expired during the reboot will be sent when the schedule method is called.
Better late than never, right?"
(mapcar #'schedule (find-persistent-objects *clockwork-store* 'reminder)))


Calling (recover-reminders) will schedule all the reminders in the store and whether Linux, SBCL or trivial-timers is to thank, a timer that's scheduled in the past will trigger immediately so you don't have to worry about some being lost during the reboot itself. Just add #:recover-reminders to the export list in the clockwork defpackage in clockwork.lisp and then call it after you load clockwork in your init.lisp file that runs when the server starts. Here's my init.lisp as an example.

Next time...


At this point we've seen a tiny bit of the Store API and the default Prevalence store and learned a little about widgets and views. We still need to cover actions and navigation/dispatchers and it wouldn't hurt to demonstrate user registration and authentication as well as use of a SQL backend. Sooner or later we'll get around to all of those things.

Right now I'm working on a postmodern backend for weblocks and may also work on styling, polish, error handling and potentially a new feature or two for clockwork. Based on what gets done, the next article will either cover the beginning of a new project or continued improvements to clockwork.

A Common Lisp Web Development Primer, Part 2

posted on 2010-11-16 03:19:24

Disclaimer: This blog will not teach you Common Lisp. That is a (mostly) solved problem. See Peter Seibel's Practical Common Lisp and Peter Norvig's PAIP. Other oft-recommended texts include Keene's OOP in CLOS, PG's On Lisp and Kiczales et al's The Art of the Metaobject Protocol. This blog will also not teach you good style, I'm too young for that. It hopefully demonstrates non-atrocious style though. I'm learning web development as I go, so don't count on expert understanding there either.
Disclaimer Pt. 2: For the foreseeable future all these projects will be weblocks-based. If that's not your cup of tea you can check out the RESTAS docs and examplesFelideon's blog on UCWAdam Petersen's slightly bitrotted sans framework article or "defect" to Clojure and look at all the Compojure stuff and maybe Sandbar.

Introduction


It's taken far longer than I hoped to get this second article off the ground. For those of you who missed Part 1, look here and if you'd rather see code than this article's commentary, the code is available on github. It's worth noting that Part 1 was originally written with clbuild in mind but has since been updated with instructions for quicklisp also. Part 2 details the construction of Clockwork, a simple clone of the now defunct yourli.st, an email reminder service. Clockwork allows you to schedule a reminder and brief note which is sent to you by email or text message at the predetermined time. Right now international numbers aren't supported but I'd be happy to see patches.

Future Plans


There's still a good amount of stuff in the TODO and I have further projects in mind after this. Part of the reason this article was so long in coming is that I've been helping Leslie by testing out his new form-widget library. The other reasons are that I have school and (until recently) was working plus I'm learning web development as I go. The next article will go into polishing this application and will likely be much more Javascript and CSS than Lisp. I'm working on getting a postmodern backend written, tested and merged into Weblocks right now. Once that's done I plan to continue this series by developing a RESTful blog that can import entries from Wordpress and maybe crosspost to livejournal as that should prove more interesting...but like Linus' said, "Talk is cheap, show me the code".

Resources, Libraries and Project Skeleton


Weblocks docs are not in an ideal state and hopefully this blog series will help that some. Four things worth being aware of for a beginner are the Google group, the TINAA-generated docs, the User Manual and User Guide. As usual, googling specific concepts will lead you to blog entries and mailing list posts that may or may not be out of date.

We'll begin by using weblocks helper to create a project skeleton by evaluating (wop:make-app 'clockwork "/home/redline/projects/"). If you've been following along since Part 1, you'll also want to push that path onto the ASDF central registry so you can use quicklisp to load the clockwork system in your server init file (~/webapps/init.lisp). (push "/home/redline/projects/clockwork/" asdf:*central-registry*) will do the trick. Then add a (ql:quickload '(clockwork)) line at the bottom of the file followed by (clockwork:start-clockwork :port 4242). At this point, you should be able to reboot the server and run screen -dRR or similar to get a screen session with emacs and an sbcl instance with clockwork and swank running. They'll be in different windows which you can switch to with C-a (control-a) and the window number. Numbers start at 0. Enough of that, this isn't a GNU Screen tutorial. Go to the emacs instance and run M-x slime-connect making sure to change the port to that specified in the init file. At this point, you're connected to SLIME and can evaluate (in-package :clockwork) and finally get hacking! You should also be able to reach clockwork in the browser at localhost:4242 but there's not much there yet...

To begin with, you'll need some libraries to send emails and schedule reminders to be sent in the future. SBCL provides a Timers facility which we could use for this but it's usually worth doing a little extra work to write portable Common Lisp. To this end we'll use the trivial-timers library as a wrapper and cl-smtp for emails. We'd also like to handle timezones and time arithmetic properly so we'll use the local-time library for that. We'll also be doing some minor string handling which split-sequence winds up being an easy solution for so grab that too. Add those to the :depends-on clause in clockwork.asd in the project directory and then run (ql:quickload 'clockwork) at the REPL. Quicklisp will download and load the new libraries for you. It's that easy. Finally, add :local-time to the :use clause of the defpackage in clockwork.lisp and import the split-sequence symbol from the split-sequence package.

Data and Weblocks Stores


By default Weblocks defines a cl-prevalence backend ("store") which persists data to the "data/" directory in the clockwork project folder. The store itself is defined in conf/stores.lisp and that's where you would go to define additional stores if you wanted them. Weblocks has a special variable, *default-store*, and DEFSTORE sets that variable after defining a store so the last store defined in stores.lisp will act as the default. Weblocks also supports elephant and clsql but for now, we'll focus on other aspects of the framework and delve more into the Store API in a later article. If you're curious now though the Store API is clearly defined and documented.

The only data we really care about is the reminders our users will generate. For our purposes, a reminder consists of some number of recipients, a title, a summary of the event it's reminding you of, the time of the event and how far before the event you'd like to be reminded. A class definition falls out of this rather naturally and we'll add an id slot so prevalence will know how to store it. Create a src/reminder.lisp file, insert the following and add the file to the :components clause of clockwork.asd.


(in-package :clockwork)

(defclass reminder ()
((id :reader reminder-id) ;; all classes to be persisted with cl-prevalence need an id slot
(emails :reader reminder-emails
:initarg :emails
:type list)
(title :reader reminder-title
:initarg :title
:type string)
(timestamp :reader reminder-timestamp
:initarg :timestamp
:type timestamp)
(summary :reader reminder-summary
:initarg :summary
:type string)
(at :reader reminder-at
:initarg :at
:type timestamp)))

Now that we have a rough idea of what data we care about, lets look at how to send messages.

Emails and Text Messaging


Text messaging is actually quite simple to support thanks to the SMS gateways run by the major carriers. SMS gateways allow us to send an email to an address which represents a phone number. This is then converted to a text message and forwarded on to the recipient's cell phone free of charge. The downside to this is that it's carrier specific so you have to know the cell carrier of the recipient. It would be nicer to just take a number and figure out what carrier services it but Local Number Portability, among other things, makes this tricky. Whitepages.com has an API for looking this up but their information was out of date for my cell phone and they had a 200 request per API key per day limit. Twilio and Data24-7 offer for-pay APIs but for this example app I'll be staying free and cheap. I'll be coldly forcing my users to select their carrier from a dropdown if they want SMS support.

Since we don't know whether our users really care about their privacy or what kind of data they'll be putting in these reminders, we'll do the responsible thing and send the emails via Encrypted SMTP. I'll be using a gmail account I registered for the service since Google provides free, encrypted SMTP on all their accounts. Let's write a quick helper macro for using it. Create a src/messaging.lisp file, insert the following and add it to the :components clause of clockwork.asd.


(in-package :clockwork)

(defparameter *mail-server* "smtp.gmail.com")

(defmacro with-encrypted-smtp ((&key to subject style
(from "cl.ockwork.webdev@gmail.com"))
&body body)
`(cl-smtp:send-email ,*mail-server* ,from ,to ,subject
(if (eql ,style :html)
(with-html ,@body) ;; TODO: make a nicer render style
,@body)
;; it's worth noting send-email takes a :cc argument
:ssl :tls
:authentication '(,*smtp-user* ,*smtp-pass*)
,@(when (eql style :html)
'(:extra-headers
'(("Content-type"
"text/html; charset=\"iso-8859-1\""))))))

Note that we haven't defined *smtp-user* or *smtp-pass* yet. There are two questions you should be asking. Why a macro and what is it doing? The why is debatable in this case. I wanted the syntax to jump out at me and read a certain way when I use the encrypted SMTP. That's all. The what is fairly straightforward. The macro is syntactically similar to with-open-file and others. It takes keyword arguments for the recipient, sender (with a default value), subject and style of the message along with a message as the body and then sends an email via encrypted SMTP (and cl-smtp's send-email function) with the credentials provided. If the style is :html, it goes to the trouble of specifying a few additional headers.

Since we haven't defined the user and pass, let's do that now. Create a conf/config.lisp file, insert the following and add it to your clockwork.asd.

(in-package :clockwork)

(defparameter *smtp-user* "yourusername@gmail.com")
(defparameter *smtp-pass* "yourpassword")

Obviously, you don't want this puppy in source control. Consequently, I committed it before I filled in the user and pass values then ran git update-index --assume-unchanged conf/config.lisp which tells git to ignore all future changes to the file. Be forewarned, that command might be reversible but I don't know how. Go ahead and add in your username and password, reload the system at the REPL with (ql:quickload 'clockwork) and test it out. You should be able to send yourself an email. Now let's add some helpers for SMS. Return to the src/messaging.lisp file and we'll add a variable defining a mapping of Carriers to SMS Gateway servers and a function for determining if an email address belongs to one of the listed SMS gateways. Add the following code to the bottom of the file.

(defparameter *sms-gateways*
;; list is derived from http://en.wikipedia.org/wiki/List_of_SMS_gateways
'(("AT&T/Cingular" . "txt.att.net")
("Alltel" . "text.wireless.alltel.com")
("Boost Mobile" . "myboostmobile.com")
("Cincinatti Wireless" . "gocbw.com")
("MetroPCS" . "mymetropcs.com")
("Sprint/PCS" . "messaging.sprintpcs.com")
("Sprint/Nextel" ."page.nextel.com")
("T-Mobile" . "tmomail.net")
("US Cellular" . "email.uscc.net")
("Verizon" . "vtext.com")
("Virgin Mobile" . "vmobl.com")))

(defun sms-mail-p (email)
(let ((domain (second (split-sequence #\@ email))))
(member domain *sms-gateways* :key #'cdr :test #'equal)))


A Few Reminder Methods


We still need methods to send a reminder, delete it when we're through with it and schedule it to be sent at a later time. Let's create those now. Since users aren't required to register to send a reminder, we'll put off letting them delete reminders from the system for now. When they submit the reminder form, a reminder will be instantiated, persisted and scheduled for later sending and deletion. We'd like to offer the user the ability to send reminders by email, text message or both so we'll assume that a list of emails are stored in the emails slot of the reminder and loop through each one, sending it with the macro we defined earlier. Then we'll use Weblocks Store API to delete the object from the datastore. Add the following code to the end of src/reminder.lisp.

(defgeneric send-and-delete (reminder)
(:documentation "Send the user their reminder as requested and then remove it from the datastore."))

(defmethod send-and-delete ((reminder reminder))
(loop for email in (reminder-emails reminder) do
(with-encrypted-smtp (:to email :subject (reminder-title reminder)
:style (if (sms-mail-p email)
:plain
:html))
(reminder-summary reminder)))
(delete-persistent-object-by-id *default-store* 'reminder (reminder-id reminder)))


Finally, we'd like to schedule the reminder to be sent at a later date. Assuming that the timezone differences are handled beforehand and that the reminder's at slot contains a timestamp for when the message should be sent according to the server's timezone, the local-time and trivial-timer libraries make defining a schedule method pretty easy. We'll just use the local-time library and a let to compute the seconds from the present until the time to send the reminder, make a timer whose function calls send-and-delete on the reminder and schedule it with a delay of the number of seconds computed. The only tricky bit is to pass :thread t to make-timer so that each timer is triggered in a new thread. If this isn't done, the timer will try to interrupt an arbitrary thread to run it's function which, put plainly, is unreliable. Another alternative would be to have a dedicated thread for sending reminders and pass that as the argument to :thread but we'll take the easy way out this time. Add the following code to the end of reminder.lisp. Here are links to my versions of the files: messaging, reminder.


(defgeneric schedule (reminder)
(:documentation "Schedule the reminder to be sent at the time the user requested."))

(defmethod schedule ((reminder reminder))
(let ((secs-until-reminder (round (timestamp-difference (reminder-at reminder) (now)))))
(trivial-timers:schedule-timer
(trivial-timers:make-timer (lambda ()
(send-and-delete reminder)) :thread t)
secs-until-reminder)))


Next Time...


This article got long. It may be too high-level for some, too low-level for others and too wordy for everybody. In addition, this isn't the most thrilling software ever constructed. Next time we'll get into more Weblocks specifics and work on the frontend to get the form and a jQuery calendar up and going. Please let me know if there are questions I can answer, things you'd like covered in more depth or other thoughts on how to improve this series. Thanks for reading.

The Spirit of Lisp (some young kid's impression)

posted on 2010-11-12 20:13:28

Disclaimer: I am not speaking for the CL community. Hell, depending on who you ask there *is* no Common Lisp community. If you're an old hat lisper, this article will probably make you groan, scratch your beard, kick something and mumble something like "Lisp just smells funny, News at 11". I'm posting it because I haven't put the words down before and the thoughts bring me joy. But *this is not news*. Because news is at 11. If you're a not-yet (common) lisper who has some interest in the language, my hope is that if you show up on #lisp or otherwise begin investigating or playing with lisp, you'll arrive with a slightly more informed perspective.

I recently read something on Zach Beane aka xach's blog that made me quite happy. He was posting about this year's International Lisp Conference and discussed (among other things) the low attendance this year and some possible causes of that. But then he went on to write this wonderful bit,

"I really like getting together in space and time with other Lispers. An ideal future Lisp conference for me, personally, would ... attract hundreds of cheerful and enthusiastic Lisp nerds...Navel-gazing and nostalgia would be at a minimum. People would talk about what they're doing today and what exciting things they plan for the future. Everyone would get together at dinner and swap stories about Lisp, life, and whatever else came to mind.

I know people are doing fun stuff with Lisp because I talk to them every day about it online. It would be pretty special to talk to them for a few days about it face-to-face."


...which in part led me to tweet the following just because I thought it embodied some things I really love about the lisp community:

"(loop (awhen (build-something) (release it))) ;; Wake up #lisp ers. Your time is now. This message brought to you in part by #quicklisp"


Nikodemus Siivola nailed this too at some point with the quote, "Schemer: “Buddha is small, clean, and serious.” Lispnik: “Buddha is big, has hairy armpits, and laughs.” Scott Fahlman's statement that "Common Lisp is politics, not art." seems similarly indicative of this in some ways also.

There are two things I'm really trying to get at. One is agnosticism, a very serious take on multi-paradigm, "you want it, you got it" programming. Opinionated languages are great as are languages or communities that are pursuing other goals, be they some abstract notion of elegance, minimalism or anything else. But...Common Lisp *is* a programmer amplifier. It subscribes to no preordained or predefined notion of what elegance is.[1] Hell, a recent article talked about 3 different kinds of languages you need to know and I might add an unopinionated language and an opinionated language to that list. Whatever the opinions you ought to see the difference.



My other point is the more important one, the emphasis both in the language and community on practicality, productivity and getting things done. People often show up on lisp.reddit or the #lisp channel on Freenode/IRC and ask if Lisp can has monads or Lisp does functional programming or if people have built big things with it and so on *before* trying to learn lisp or using it.[2] Almost always the first response is "Why are you asking that? Why does it matter? Why do you want to know?". This tends to dissatisfy the visitors whose real agenda, in my humble opinion, is usually to ensure they study the thing that will "make them good" or get them furthest ahead of the curve. Why waste your time with "the wrong language"?


Generally, the whole conversation devolves. The parties are coming from totally different points of inquiry. But whether the visitors are "flamed so hard they die" or gently dealt with until agreements are reached things end pretty quickly and everyone goes on about their day. Paul Snively calls lisp the "cockroach of programming languages" and I'm not sure if he means Common Lisp or just the Lisp family genes. But when people ask if lisp is dead or "shouldn't I just use/study language X?" I'm relieved and pleased that we're too busy having fun and building things to worry about it. Who cares what language wins tomorrow? This language works today, we're using it and when we see other languages with something we need, we grab it.

To me this is something refreshing about the lisp community that isn't internally or externally recognized quite enough. Which isn't to say that we should go around beating our chests and talking about what rock stars or great programmers we are. I'm certainly not one. I remain a wet behind the ears programmer. I'm not writing as much code as I should and as a consequence still have little useful stuff to release. But I've been privileged to watch and try to help Will Halliburton with a lisp-powered startup and work with Leslie Polzer on Weblocks and Paktahn.

Really it's most likely that there's so much more noise than signal regarding "lisp" and often so little clarity as to whether scheme, lisp or genetically 'lispy' languages are being discussed on online forums that the public image about Common Lisp is horribly out of whack. Hell, I've said terrible, stupid, ridiculous things about Common Lisp in the past. Why? I hadn't seen the community, I hadn't seen the language, I didn't understand *what* it was. And maybe we can't change that or it's just not worth the effort. The people who have heard something from x, who heard it from y, who heard it from z will keep repeating old wives' tales forever. But here's my attempt at getting down why this language is in no danger of dying anytime soon:

We're all just having fun building things. And if that sounds like something you'd like to do, please come in, visit #lisp and ask us questions. Message me personally if you want, I'm on freenode as redline6561. I promise the water is fine. Just don't ask if this is the right way to use your time. Figure that out in advance. As far as I'm concerned, between great open source implementations like SBCL and CCL, great editing solutions like SLIME for emacs, Slimv for vim and the new Textmate bundle and easy access to libraries through quicklisp, there's never been a better time.

[1] This certainly is not to say that you can't use or practice other languages notions of elegance in lisp. Drew Crampsie aka drewc has been perfectly happy working on a monadic web request dispatcher of late and Francois Rene Rideau aka fare happily does Purely Functional Programming in CL and came up with an "Interface Passing Style" which simulates the parametric polymorphism of Haskell's type classes.



[2]If you're doing that, you're missing the point. Part of the reason that happens is surely the endless blog articles and old reddit comments which endorse SICP and "learning lisp" as a way to expand your mind and reach some ersatz programming enlightenment. Part of it is that you might just be getting started in programming and looking for ways to skip to the end. And that's understandable, I've been there myself. But remember the words of Norvig and Nostrademons.

CL Web Primer Progress Report

posted on 2010-11-07 21:20:29

Wow. It's been way too long since I've written about this. Naturally, software takes longer than expected. I also helped Leslie test features that were in beta so migrating to those and working out their kinks slowed things down a little.

But long story short, the next entry in the CL Web Primer series should be coming very soon. 7 days at the latest. If you just want to read the code, it's at http://github.com/redline6561/clockwork.

Defining a jQueryUI Datepicker presentation, 38 lines.
Defining a simple text messaging system, 37 lines.
Defining a reminder class and methods to schedule the reminder to be sent, send it and delete it, 47 lines.
Defining a form for users to fill out, a list of timezones and validation functions to ensure the input is good, 109 lines.
Putting it all together, 27 lines.
Learning about web programming (I know, giving myself too much credit there...) with Common Lisp and Weblocks? Priceless.

The site is still quite ugly and needs a lot of work and a few more features but at least it's functional now.
Until next time...

A Common Lisp Web Development Primer, Part 1

posted on 2010-09-19 19:57:54

Disclaimer Pt.1: There are many people smarter and more qualified than me when it comes to CL web development. Thankfully, this article is covering basics and my knowledge should be sufficient. Correct me where wrong, of course.
Disclaimer Pt.2: This article will deal more with config files, programming environment setup and the CL web dev landscape with a follow up article to introduce a specific framework, examples, etc.
Edit of Nov 12, 2010: This article has been updated to reflect modern Common Lisp best practices (i.e. Quicklisp).

The Hardware


The first thing to talk about is where our application will be served. This was recently discussed on lisp.reddit. Unlike languages like PHP, Perl, Ruby or Python, shared hosting is not prevalent for lisp though tech.coop is a notable exception. In general, a VPS or similar setup will be required. I've heard good things about people using Slicehost, Linode and ThrustVPS. Personally, I use Linode's smallest instance for $20 a month and have been quite happy with it. I've run hunchentoot, lighttpd, postgres and mysql on it simultaneously without issue but that wasn't under significant load. I'm also aware of at least one startup using Lisp on top of Amazon's EC2. Heck, you may have a server you'd like to run out of your home. For our purposes, I will assume you have a reliable internet-facing Linux box and root access.

The Linux Distro and Programs


Any Linux distribution should be suitable for lisp web server duties. Personally, I would lean towards Archlinux as their default install is quite lean and they keep very recent versions of SBCL(1.0.42), CMUCL(20a) and others packaged. There's even a CCL AUR package (Archwiki AUR article) maintained by Leslie Polzer. Whatever distribution you wind up using to follow along with this series I recommend you also install screen, emacs, sbcl and lighttpd with your package manager. You should also grab the VCS pentafecta of darcs, git, mercurial, subversion and cvs.

Setting up Emacs and SLIME


Note that there are many other, probably better, Emacs+SLIME tutorials out there. Since the original writing of this article, Quicklisp has become the dominant method for acquiring Common Lisp libraries. Instructions for its use are here and the clbuild instructions are maintained below for posterity. First grab quicklisp with curl -O http://beta.quicklisp.org/quicklisp.lisp then load and install it by running sbcl --load quicklisp.lisp, followed by evaluating (quicklisp-quickstart:install), (ql:add-to-init-file) and (ql:quickload "quicklisp-slime-helper"). Finally, add (setq inferior-lisp-program "sbcl") and (load (expand-file-name "~/quicklisp/slime-helper.el")) to your ~/.emacs.

Alternate clbuild instructions
The first thing to do is grab clbuild. At least until quicklisp is released, clbuild will remain the easiest way to get all the necessary lisp libraries to get cranking on web development in linux. I like to keep clbuild in ~/builds but place it where you like. Download it with darcs get http://common-lisp.net/project/clbuild/clbuild. Then cd into the clbuild directory and make it executable by running chmod +x clbuild. I'd also add the directory to your path in .bashrc or add an alias like alias clbuild='/home/redline/builds/clbuild/clbuild'.


With that done, it's time to start grabbing libraries. First, get SLIME by running clbuild update slime. Then you'll want to run clbuild slime-configuration and stick that in your ~/.emacs file, taking care to change the (setq inferior-lisp-program "/home/.../.../clbuild/clbuild lisp") to (setq inferior-lisp-program "sbcl") or "/usr/bin/sbcl" or whatever is appropriate.
End clbuild-specifics


At this point you should be able to ssh into your development server, run emacs -nw (for no-window-system/terminal mode) and then type M-x (alt-x) slime and enter to get to a lisp prompt.

Getting the Lisp Libraries


After talking with Leslie a bit, I'll be using weblocks-dev over weblocks-stable. Weblocks-dev use is encouraged over stable at this time. Quicklisp uses weblocks-dev already and makes this insanely easy, just evaluate (ql:quickload 'weblocks). Done.

clbuild specifics
If you'd like to use weblocks-dev, open /path/to/your/clbuild/wnpp-projects in your favorite text editor and change the following:
1) Find elephant and change it's darcs repo from blah/blah/blah/elephant to blah/blah/blah/elephant-1.0
2) Find weblocks and change it's hg repo from http://www.bitbucket.org/skypher/weblocks-stable/ to http://www.bitbucket.org/S11001001/weblocks-dev/
3) Find cl-prevalence and change it's repo to cl-prevalence get_hg http://www.bitbucket.org/skypher/cl-prevalence/
Then run clbuild update weblocks and, if prompted about whether or not to download dependencies, enter 'y'. Let it work it's most excellent magic.
End clbuild-specifics



The Framework Selection


There are a multitude of ways to do web development in Common Lisp. There are web servers such as Araneida and Portable Allegroserve (both effectively unmaintained), Hunchentoot (which is dominant in the way *Ediware* often is), Apache with mod_lisp, relatively obscure or undocumented combination server/frameworks like Antiweb, Symbolicweb/SW-HTTP and Teepeedee2 and frameworks like Weblocks, UCW and RESTAS.

I wanted something relatively commonly used and well-documented but I wanted a framework as opposed to just using libraries like CL-WHO, Parenscript and Postmodern on top of hunchentoot. Since UCW already has a blog series and I've worked with Leslie on Paktahn a while, Weblocks was a natural choice for me.

The App Setup


I already run a wordpress blog and some other stuff on a lighttpd server on my Linode. Consequently, it made sense to just map a subdomain to my lisp experiments and leave the rest alone. To do this with lighttpd, add the following to /etc/lighttpd/lighttpd.conf:
$HTTP["host"] =~ "testbed.redlinernotes.com" {
proxy.server = ( "/" => ( ( "host" => "127.0.0.1",
"port" => 4242 ) ) )
}

Now you wouldn't want your webapp to not restart if you had to reboot the server would you? Of course you wouldn't. I've taken a cue from Xach and daemonized it via screen as follows:
Open /etc/rc.local in your favorite text editor and insert a line similar to su redline -c 'screen -d -m -S screenslime -c /home/redline/webapps/screenrc'. This will ensure that the redline user starts a screen instance in detached mode with the name "screenslime" when the system boots that will use /home/redline/webapps/screenrc as it's configuration. If you don't know what any of that means, don't worry. It means screen is cool and you want it.

Now, you should add something like the following to whatever file you listed as your screenrc:
chdir /home/redline/projects

screen emacs -nw
screen sbcl --userinit /home/redline/.sbclrc --load /home/redline/webapps/init.lisp

This will ensure screen defaults to the /home/redline/webapps directory, starts an emacs instance in no-window-systems mode in screen window 0 and starts sbcl loading your .sbclrc and a lisp init script for your webapp(s) in screen window 1.

Next, we need to actually write the init file for your webapp. For now, it will be quite simple as I'm just playing with weblocks. In the next article, we'll build something (probably un) interesting. In your init.lisp file (or whatever you called it) insert something like:
(ql:quickload '(weblocks swank))

(setf swank-loader::*contribs* '(swank-c-p-c swank-arglists
swank-fuzzy swank-fancy-inspector
swank-package-fu))
(swank-loader::loadup)
(swank:create-server :dont-close t
:port 4010
:coding-system "utf-8-unix")

This will ensure weblocks loads and swank serves on port 4010 so that we can use SLIME to connect and work on the running system. Note that you could've also put (load "/path/to/my/.sbclrc") or inlined the following as the first line(s) in your init file and avoided the --userinit portion of the sbcl invocation in screenrc. My .sbclrc simply points sbcl to the clbuild libraries like so:
(require 'asdf)
(setf asdf:*central-registry* '("/home/redline/clbuild/systems" *default-pathname-defaults*))

Unless you're using clbuild, you won't need this in your .sbclrc but if you are it's important that you do this so that sbcl can find the lisp libraries we downloaded with clbuild. If you don't, it'll be looking in ~/.sbcl/systems.

Finally, I would also add a bash alias to your ~/.bashrc to get you right back to where you were with screen+SLIME. Mine is alias webslime='screen -dR'. I also added stty -ixon to my .bashrc as detailed in my last post because screen was capturing keystrokes I wanted sent to emacs. Xach pointed out that this could be toggled in screen with C-a C-f but I preferred having it as a default.

See, now that was mostly painless, wasn't it? Next time I'll cover the basics of weblocks and develop a simple starter application. Or if I'm feeling particularly lazy, maybe I'll just walk us through the simple-blog example-app. Cheers.

A short update and emacs/screen note

posted on 2010-09-14 14:00:14

In short, I'm busy but life has been really good lately. I've been learning new skateboarding tricks (fakie backside 180 kickflips FTW), the weather is good, music is good, the 20 hour a week job has been good and classes have been...well, pretty easy so far. Plus I've been busy socially. Having a car and not being broke may have something to do with that.

Moving on, I've been playing with weblocks a lot the last few days. I've got a nice little setup that I look forward to posting about here at some point but I was getting frustrated by my screen session hanging whenever I tried to search or save in emacs. The common denominator there is C-s and it turns out that C-s and C-q stop and resume output on a terminal. This is well covered under a Flow Control section in the screen manpages. The best solution seems to be to disable flow control and if you can't do that, tell emacs to switch some keybindings around to deal with it.

The two options I noticed for disabling flow control were running "stty -ixon" and adding it to your .bashrc or adding "defflow off" to your .screenrc. Zach Beane was kind enough to comment and note that you can also use C-a C-f in screen to toggle the control flow setting between on, off and auto (which he normally prefers). As the .screenrc entry will be specific to screen while the other will affect all shell usage, I'd prefer to stick to the .screenrc method but it didn't seem to work so I'm using the bash trick as well. That's all for now. Hope this helps somebody one day. Cheers, folks.

Why Computer Science?

posted on 2010-07-18 01:56:03

It's bedtime here but I couldn't help but post this quote by kragensitaker from reddit. I've always meant to get around to writing an explanation of why I think Computer Science is a lovely discipline. This addresses it in a very different way than I was hoping to but absolutely merits posting here.
Well, a thousand years ago, geometry was the field holding those special secrets. Computers are just the automation and generalization of geometry. Everything except that generalization of geometry (now known as "mathematics") is contingent on the physical universe we happen to inhabit.

The most remarkable thing about all of this is that apparently that physical universe can be simulated, analyzed, and even predicted with mathematics. So, too, with all the universes we can imagine. And of course this is much easier to do with automated mathematics.

So a computer is not just a machine; it's not just a machine that imitates other machines; it's not just a machine with a universe in it; it's a machine with all possible universes in it.

Of course, this is not somehow discontinuous with the multi-millennium discipline of geometry, or for that matter writing and arithmetic. It's merely the current step.
That's part of what makes it such an extraordinary field, to me, and makes the bullshit worthwhile.

There's also, though, the human side. Computers are not merely simulators; they are also communicators, through which we can diffuse universal access to human knowledge. This is an educational and liberal achievement unparalleled in human history. The dream of Diderot is less and less a dream and more and more a reality. And thus even PHP is forgiven.

Clojure/Slime on Arch (and maybe elsewhere)...

posted on 2010-05-22 13:00:56

This is just a quick configuration post.  On Archlinux, clojure, clojure-contrib and swank-clojure-git packages are already available from the AUR. I'm a big fan of Common Lisp and use it for most of my programming, so I wanted to be able to use any of the 3 common lisp implementations installed from distro packages along with SBCL git built with clbuild or clojure without much fuss. Though there are a fair number of articles on clojure/emacs/slime setup and still more a google search away, I found it a bit of a pain to get things going the way I wanted.

I can't vouch for whether or not this will work for non-Arch users but if you have clojure and swank-clojure installed then aside from changing paths or setting environment variables this ought to work for you. (Let me know if I'm wrong, of course.)

I've got my lisp implementations defined as follows:
(setq slime-lisp-implementations
'((ccl ("ccl64"))
(ecl ("ecl"))
(sbcl ("sbcl"))
(sbcl-git ("/home/redline/builds/clbuild-dev/clbuild" "lisp"))))
(setq slime-default-lisp 'sbcl-git))

If that looks completely alien to you or you don't already have some additional code in your .emacs for SLIME setup, you're in the wrong place. You probably just want an easy Emacs starter kit for clojure. Or, alternately, to look at my full .emacs file.

And the following big chunk to get swank-clojure and the rest set up:
(add-to-list 'load-path "/usr/share/emacs/site-lisp/clojure-mode")
(require 'clojure-mode)
(add-to-list 'load-path "/usr/share/emacs/site-lisp/swank-clojure")
(require 'swank-clojure)
(add-hook 'clojure-mode-hook
'(lambda ()
(define-key clojure-mode-map "\C-c\C-e" 'lisp-eval-last-sexp)
(define-key clojure-mode-map "\C-x\C-e" 'lisp-eval-last-sexp)))
(eval-after-load "slime"
`(progn
(require 'assoc)
(setq swank-clojure-classpath
(list "/usr/share/clojure/clojure.jar"
"/usr/share/clojure/clojure-contrib.jar"
"/usr/share/emacs/site-lisp/swank-clojure/src"))
(aput 'slime-lisp-implementations 'clojure
(list (swank-clojure-cmd) :init 'swank-clojure-init))))

At this point, you should be able to start Emacs and then do M- - M- x slime, followed by enter and either the word clojure or one of your lisp implementations. Alternately, you could just do M-x slime and get sbcl-git. See? Not so bad after all.

Paktahn 0.9 is out!

posted on 2010-05-18 18:16:40

Well, it's been a long spell since the last paktahn release. There are reasons for it but I'm just glad we got the release out.

The "big feature" of the release is AUR updates which I am happy to have implemented. I wouldn't have been able to get it done if versioning support hadn't been kicked off by Wei Hu (wh5a) a while back though. At any rate, AUR Updates are in as is support for the .tar.xz format which Arch has adopted for packages going forward.

Beyond that we have a new contributor to the project, Justin Caratzas, that I've enjoyed working with and hope to work with more in the future. Justin fixed a bug in how AUR packages were installed regarding whether or not they were installed as dependencies.

I should have more time to hack on paktahn this semester than last semester so hopefully there won't be a commit gap for 2 months like there was before. I'm already looking at features for 1.0 and my biggest priority is reworking the command-line option handling using astine's unix-options and then extending paktahn to support pacman's -Syu, -Sy and -Su. Then I wouldn't ever need to call down to "regular old" pacman. Other than that it might be nice to get support for Paktahn on CCL or ECL and a test suite written. CCL support is complete save catching Ctrl+C and offering restarts as appropriate. There isn't exactly a clear path to implementing said support...

Anyway, if you're a user and you find a bug or want a feature, head for the issues page and let us know about it!

LIMIT and OFFSET in Postmodern

posted on 2010-04-25 17:58:09

I've been using the Postmodern library in Common Lisp to access PostgresQL databases of late and it's been a pretty good experience.

That said, I had a little trouble using LIMIT and OFFSET to get DAO objects and wanted to put an example online in case anyone else has trouble with this. Future Postmoderners, May Google protect you.

You'll want to use query-dao instead of select-dao and wrap the limit around a select statement. It winds up looking something like this:

(query-dao 'card
(:limit (:select (:distinct 'name) :from 'card) 10 0))


In this example, we're selecting the first 10 rows (that are distinct by name) from the card table. Obviously, you could use '* instead of (:distinct 'name) to select from all rows.

That's not much of a post but here it is. Once I'm through finals I'll try to start posting a bit more regularly. Then again, I'll be moving once in May and once in June so we'll see what happens.

A Brief, "Postmodern" Shout-out

posted on 2010-04-12 01:11:48

Things have been crazy lately but I'm not here to give a full update. I will say that there's been good with the bad, family, friends and supporters all the while and that the bad is mostly the usual bureaucratic and financial troubles that are just a part of life. I'm trying to post more regularly. Today is a brief programming post.

This semester I've been taking a database course and we're building a small, silly webapp as the final project. The course uses SQL+PHP and I asked my professor if he wouldn't mind if I used SQL+Common Lisp. He accepted and so I've been using the Postmodern library for Common Lisp to talk to my Postgresql database. Postmodern has been really nice to use so far but there's one thing that I had a little trouble with that I'd like to document here.

Generally, if you're writing classes in Lisp you're using CLOS and an example might be something like this:
(defclass user ()
((username
:initarg :username :reader :username)
(password
:initarg :password :reader :password)
(salt
:initarg :salt :reader :salt)
(email
:initarg :email :reader :email)
(first-name
:initarg :first-name :reader :first-name)
(last-name
:initarg :last-name :reader :last-name)
(zip
:initarg :zip :reader :zip)))

Postmodern has a nice method for interacting with the database via class definitions that it coins "Database Access Objects". Note that DAOs neither are nor attempt to be a full ORM solution, a very sane decision in my humble and inexperienced opinion. Anyway, to make a normal class into a DAO class is easy, just do this:
(defclass user ()
((username
:col-type string
:initarg :username :reader :username)
(password
:col-type string
:initarg :password :reader :password)
(salt
:col-type string
:initarg :salt :reader :salt)
(email
:col-type string
:initarg :email :reader :email)
(first-name
:col-type string
:initarg :first-name :reader :first-name)
(last-name
:col-type string
:initarg :last-name :reader :last-name)
(zip
:col-type integer
:initarg :zip :reader :zip))
(:metaclass dao-class)
(:keys username))

All you have to do is add col-types to each slot so the system knows what type is stored in the database rows, list the components of the primary key and declare it a member of the dao-class metaclass. With that done, you can easily work with CLOS objects and fairly seamlessly select, update, delete or instantiate+insert them into the database. Creating the table itself can be done as follows: (execute (dao-table-definition 'user)). However, this is really intended as a shortcut for cases where you have a simple table definition. Say you wanted to allowed users to own collections of things, maybe collectible cards, and track those in the database as well. You ought to have foreign key constraints on the database so that collections couldn't be owned by users that didn't exist or consist of cards that didn't exist or were made up.

In the case where foreign key constraints are desired or other more complex checks should be made, the preferred method is to write a deftable definition in addition to the class and then create the table with (create-table 'class) or (create-all-tables) if you have several tables. This would make for nasty code duplication since you'd still need a dao-object class to interact with the tables as nicely as possible. Thankfully, there's a macro to clear the situation up and import the simple parts from your dao-class specification. A possible deftable for the collection class might look like this:
(deftable collection
(!dao-def) ;; Import the existing info from the dao-class definition.
(!foreign 'user 'username) ;; Ensure that the username that owns the collection exists in our user table.
;; Ensure that each card in a collection has a name and edition corresponding to a card in our database.
(!foreign 'card '(card-name card-edition)
'(name edition)))

Of course, if your tables are already created and you just want to access them or you want to create them at the psql prompt, you don't care about any of this. Hmm...I guess that's supposed to go at the top. Anyway, a more careful and thorough reading of the documentation would've shown me this but examples are nice and here one is in case anyone googles around for it like I did. As far as I can tell, this is the preferred current approach for table creation. Corrections welcome and thanks to Marijn Haverbeke for writing postmodern. It's been wonderful so far.

Paktahn 0.8.2 and other news...

posted on 2010-01-14 04:36:33

The last week has been thoroughly insane in ways both good and bad. As a gift, I had my thoroughly aged Nokia 6010 replaced by a shiny new Nexus One. Much as I would've liked an N900 they aren't subsidized by any carrier and so will remain out of my price range. I've also switched service to T-Mobile and thus far been quite satisfied. Then again, coming from a phone without a data plan I have no way of evaluating the 3G I'm getting.

The holidays were good. I have a skateboard again so when the weather clears up I can get back to enjoying that.  Time with mom was really good as was some peace and quiet and time to reflect. I took the opportunity to discover some new music as I usually do and also to read two novels by Vernor Vinge that I thoroughly enjoyed: A Fire Upon the Deep and A Deepness in the Sky. Careful, those wiki links have spoilers. As for the music, I've considered compiling a top 5 favorite albums of 2009 list but haven't gotten around to it. Besides, last.fm should tell you most of that. I will say I've been deeply enjoying Jon Hopkins, Ametsub and Minus the Bear this week. It's kind of an odd mix.

Moving on, I got back into code last Tuesday after a long holiday absence. I really needed the break to recharge. 2009 was a full year. I spent the bulk of the second half of last week and the weekend writing code, reading code or screwing around with configuration files...which are all things I enjoy a good bit. Over the break I had fooled around with a new window manager (StumpWM in lieu of XMonad) and started using clbuild instead of asdf-install. I also spent a little time adding a lot of projects to clbuild in case I felt like playing with them. In the course of all this fiddling, I made a fresh archlinux install in a new partition with essentially nothing but Lisp and C compilers, a tiling window manager, Chromium, Emacs and a music player. To some degree, I'm fleshing it out still. It's a dumb diversion but every now and then I just have to rip my system up a little. It's hard to explain.

On Sunday, after 3 months of work Leslie and I finally made the Paktahn 0.8.2 release. For all intents and purposes, the wait was worth it. A lot of new features and fixed bugs are present but there is still so much on my Paktahn.todo list. And of course there are bugs to fix. It's hard to explain why I'm so invested in Paktahn. Part of it is the work I've put in to date, part of it is how pleasant it's been working with Leslie and how much I've learned. Another large part is that there is great joy in having written some part of my day to day software and having a (relatively) deep understanding of it. It's kind of silly because AUR Helpers are a dime a dozen (or two dozen) but I'm still having fun.

The Paktahn release was not without some drama though. Almost immediately after the release I started having odd issues building paktahn with sbcl. The resulting executable would exit as soon as you ran it complaining of a fatal error and a lost gc invariant. Not what you want to see. The bad thing was the error was intermittent and I couldn't isolate the cause. I had issues with it in my old archlinux install as well as the new one, with old and current checkouts of my code and with a checkout of Leslie's tree. I'm pretty sure I tried it with a fresh, recompiled sbcl and also tried removing all fasls and recompiling. I got very confused in the course of all that trying to figure out what happened. I should've been taking notes. At this juncture, it builds fine again and I can't get it to act up. :( Ah, well. At least I can get back to developing. It certainly gives me some impetus to finish the CCL port I started Dec 28th.

So on to school this semester. I'm interning at a company called Kloudshare and have begun work on open sourcing a portion of their code. It's good fun and I hope to have more to share on that note very shortly. The administrative person I spoke with before break failed to get the internship registered in SPSU's system though so I spent a good deal of Tuesday getting that worked out with her. Then I had the unpleasant experience of learning that online courses are *substantially* more expensive than offline ones. Apparently, the state doesn't subsidize them because they can be taken advantage of by anyone or something like that. In my case, I was just trying to avoid an hour and a half commute both ways and try to find more time to code. I guess you really can't have it all. Now I have to jump through more financial aid hoops. Joy.

Soon I hope to have some code to show here. Maybe I'll spend 10 minutes and just throw my dotfiles up on github for the hell of it tomorrow. Other than that...I miss long form writing, poetry, essays...but my focus is elsewhere. Plus I'm tired. The rest will have to wait for another day.

Git For Dummies...

posted on 2009-10-22 19:53:02

A friend asked me for a simple tutorial. So here one is. Also, just because I can:

My workflow roughly looks like:

Start or clone git repository: [git clone $URL] OR [mkdir project; cd project; git init]
Make some changes: HACK HACK HACK, ensure the files are tracked: [git add $FILES]
Review my changes: [git status], [git diff]
Uh oh, a choice!: if (I like these changes)
then [git commit] // ideally, your $EDITOR environment variable is set to the editor you like.
else [git checkout -- $FILES] // yes, the dashes should literally be there. this reverts the files to the last commit's state.
Repeat.


I didn't cover pushing and pulling (collaborating) or branching above (working on separate features simultaneously).
Let's do that now:

Get a list of branches and show the current branch: [git branch]
Start a new branch to work on: [git branch $NAME]
Switch to a different branch: [git checkout $NAME]
Delete a branch you don't want anymore or are finished with: [git branch -d $NAME]
Merge changes from one branch into another branch: [git merge $SENDER $RECIPIENT] // Branch recipient gets senders changes.
List tracked repos (online, github, etc): [git remote]
Track a friends repo (or one online, github, etc): [git remote add $URL]
Send your changes to a repo you have write access to: [git push $REMOTE $NAME] /* remote can be a url or one of your remotes.
name is a branch on your machine. note that master is a branch. */
Retrieve and merge in a friends changes: [git pull $REMOTE $NAME]

There are a bunch of blog tutorials. The best way to find them is to go to programming.reddit.com and search for "git tutorial" or "git intro".

Other than that, there are two free git books I know of:
Pro Git - http://progit.org/book/
The Git Community Book - http://book.git-scm.com/

Keep It Together

posted on 2009-10-06 15:25:26

So, the last time I really posted a personal update I didn't have many good things to say. I was a bit depressed. But I seem to have climbed out of that hole. Midterms are mostly over and I have a much better feel for my classes with them behind me. The only one I haven't taken is the American Government midterm which I'll take tomorrow at 3pm. A decent amount of stress is off now that they're out of the way. I'm still a bit overextended. I'm pulled in many directions by a desire to do many things but I might as well be honest. I like it that way.

Particularly, I'm trying to contribute to two different pieces of Open Source Software. One is Mixalot, a suite of Common Lisp libraries for interfacing with Linux's ALSA sound sytem and playback of MP3 files. The other is Paktahn, a package management wrapper for Arch Linux which is meant to replace Yaourt. Paktahn is also written in Common Lisp. Notice a trend? I want to use Mixalot to work with Ogg Vorbis (*.ogg) files which it doesn't support. I told Andy Hefner I'd like to try and contribute some libvorbisfile bindings which would let Mixalot work with that file format. Unfortunately, that involves interfacing with C code which I don't know much about. It's definitely an order of magnitude harder than most things I've worked on before. Plus I've had exams...so I haven't gotten much done on that front yet. Leslie Polzer is writing Paktahn and he pointed me in the direction of a fairly straightforward, well-defined problem that needed solving. I got around to working on that and have made pretty good progress. With a little more work it may even make it upstream for the next release. That's wicked fun!

I've wanted to write a blog post on Lisp for a little while but couldn't narrow down what about Lisp to focus on. Lately I had been looking at mailing lists, documentation and source code repos for a lot of Common Lisp libraries. Perhaps what shocked me most was the realization that Lisp has plenty of work to go around for silly noobs like myself. There are all sorts of trivial little tasks all over the place that maintainers are too busy solving real problems to fix. And that's awesome! I can be very helpful probably to a wide number of different projects. Now, I don't know a lot and I don't have time to "help" near as much as I'd like...but I can still learn something and be of use. And I'm pretty happy about that. So Common Lisp: Have fun on the fringe, benefit from learning a non-standard language with some awesome features, be useful and get mentored by some smart folks. What's not to love? I'll try to post something more thoughtful about this later. But for now, all I have to say is that this is a really good thing and I can't wait to see where it takes me.

For now though, it's back to studying.

Scripting with SBCL

posted on 2009-09-09 17:40:14

Over the labor day weekend, I had fun. I avoided dreary schoolwork, I played guitar, I hung out with cool people, I celebated my second anniversary with a lovely lady, I wrote code.

One bit of code I worked on is a script to read in AT&T call logs and figure out the 5 people you call most often. As you might guess, this can be useful for people contemplating switching to T-Mobile (say, for an upcoming piece of hardware designed for their 3G network). In short, the script is run from the command prompt with ./myfaves.lisp and prints out the 5 people you've talked to the most based on your call logs and the total percentage of your minutes those calls account for. The call logs this script processes can be downloaded from wireless.att.com. Login to your wireless.att.com account, go to "Bill & Payments". Under "Wireless Statement Summary" click the "Call Details" tab and finally scroll down a bit and click "Download Call Details". Using the dropdown box, select each month then click CSV format and submit. Put all those files in the same directory and then execute the following lisp script from that directory.


#!/usr/bin/sbcl --script
(declaim (sb-ext:muffle-conditions style-warning))

(eval-when (:compile-toplevel :load-toplevel :execute)
(let ((*standard-output* (make-broadcast-stream))
(*error-output* (make-broadcast-stream)))
(require 'asdf)
(require 'split-sequence)
(require 'osicat)
(require 'cl-containers)))

(defpackage :my-faves
(:use :common-lisp :cl-containers :osicat)
(:import-from split-sequence split-sequence))

(in-package :my-faves)

;; ATT CSV info
;; call logs start on line 24, entries on every other line (evens)
;; voice calls final line starts with "Totals"
;; 5th comma-entry is number, 7th is duration in minutes

(defparameter *months* nil)
(defparameter *results* (make-array 6 :fill-pointer 0))
(defparameter *call-log* (make-container 'sorted-list-container
:test #'equal
:key #'car
:sorter #'string<))

(defun init ()
(loop for path in (list-directory (truename ".")) do
(let* ((pathstr (native-namestring path))
(ext (subseq pathstr (- (length pathstr) 3))))
(when (string= "csv" ext)
(push path *months*)))))

(defun find-faves ()
(loop for file in *months* do
(load-calls file))
(analyze-data)
(print-results))

(defun load-calls (path)
(catch 'load-calls
(with-open-file (in path)
(loop for i from 1 to 23 do
(read-line in nil))
(loop for line = (read-line in nil) do
(parse-call line)))))

(defun parse-call (csv-line)
(cond ((string= "" csv-line))
((finished-voice csv-line) (throw 'load-calls 'done))
(t (let* ((split-line (split-sequence #\, csv-line))
(number (fifth split-line))
(minutes (parse-integer (seventh split-line))))
(insert-call-sorted number minutes)))))

(defun finished-voice (csv-line)
(string= "Totals" (subseq csv-line 0 6)))

(defun insert-call-sorted (number minutes)
(let ((present (search-for-item *call-log* number :key #'car)))
(if present
(incf (cdr (search-for-item *call-log* number :key #'car)) minutes)
(insert-item *call-log* (cons number minutes)))))

(defun analyze-data ()
(ensure-sorted *call-log*)
(sort-elements *call-log* #'> :key #'cdr)
(loop for number from 0 to 4 do
(vector-push (item-at *call-log* number) *results*))
(let ((total-free (loop for i from 0 to 4 summing (cdr (aref *results* i))))
(total-mins (reduce-elements *call-log* #'+ :key #'cdr)))
(setf (aref *results* 5) (round (* 100 (/ total-free total-mins))))))

(defun print-results ()
(format t "AT&T -> T-Mobile myFaves Recommendations:~%")
(format t "-----------------------------------------~%")
(format t "According to our analysis of your call logs, these are your 5 most frequently dialed numbers.~%")
(format t "-----------------------------------------~%~%")
(loop for i from 0 to 4 do
(format t "~A whom you spoke to for ~A minutes.~%~%" (car (aref *results* i)) (cdr (aref *results* i))))
(format t "These numbers should be your myFaves as they accounted for ~A% of your total minutes.~%" (aref *results* 5)))

(init)
(find-faves)


I'm sure it's not the prettiest, lispiest code out there but it could be an awful lot worse. Also, sbcl emitted style-warnings when the script was run. This behavior surprised me a little bit. After all, if I'm running the script I have little need for the style-warnings. After some digging, I learned enough to write this patch for the program which suppressed the undesirable output. I hope to submit a patch to the SBCL manual in the next week or so that notes this may be desired as nothing on the current page regarding sbcl --script would indicate that any output from the compiler would appear.

Better than TV

posted on 2009-06-01 17:06:02

Here are a few video lectures I've enjoyed that simply never could have made it to Television. Too much of a niche audience I suppose. They'll go from most comprehensible to non-nerds/programmers to incomprehensible to non-nerds/programmers. Soon I'll post up something actually productive or cool. For now, it's all school.

I still really like Giles Bowkett's RubyFringe presentation from last year. It really starts in after the musical presentation of the first seven minutes. It's good fun even if you don't program and you can see a glimmer of why programmer's would be interested in what it is they do.

I also fervently love "The Graphing Calculator Story" which I read in text somewhere before stumbling across this video.

Finally, I watched Zed Shaw's CUSEC talk last night and was forced to conclude that I both like Zed Shaw and very much like his talk.

Now, when you need a break, watch something.

Tab Terminator

posted on 2009-05-28 15:01:32

So, my browser is getting full again and I feel like clearing out the backlog. Prepare yourselves for a linkpost! Also, I'll try to arrange links by progressive nerdiness or some such.

NOTE: I've been terrible at keeping up with other people's blogs. If you're a friend of mine and I haven't read/commented in a while, I'm sincerely sorry. I'll be trying to catch up soon. Also, if you haven't heard about the underground sensation tearing up comedy clubs everywhere, his name is Justin Morgan and I'd keep your eyes peeled for him.

I've been hearing about a few albums that might be good and that I should check out as a consequence. They follow:
Doves - Kingdom of Rust
White Rabbits - It's Frightening
Night Control - Death Control
Danger Mouse and SparkleHorse - Dark Night of the Soul

It's occurred to me recently that I really kind of need a phone and I'm ready to take the fancy smartphone leap. I did a quick survey of the competition yesterday and narrowed my choices down to 4 models, none of which are released yet and one of which isn't even official. Don't ask me about all that. I'm sure we'll discuss this later. Here they are: Palm Pre, Samsung I7500, Nokia N97, and the Nokia N900 (because Rover is a very stupid name for a phone). Hopefully some official word about the N900 will break soon.

Okay, so there's an awesome site about Literate Programs here. If you're looking for some code to read it's probably not a bad place to start.

There was recently a great discussion on proggit about most used emacs commands. That's some handy stuff to keep track of. Between that and the emacs-fu blog I referenced two posts back I'll be learning a good while.

Considering that it's old news, there's still a fair amount of hollering about MIT switching from Scheme and SICP to Python and continuing debate on the value of SICP. Indeed, it's not the holy bible and grauenwolf is getting a too many downvotes. He makes a number of very good points. I haven't taken time to read through the whole thread (should I?) but psnively seems to have the right idea to me, as usual.

O'Reilly Radar put up a pretty good article on the things HTML5 will enable and the resulting scramble to the finish by a lot of big players.

There was a good discussion on the Haskell reddit about making -Wall the default for GHC, I chimed in because there didn't seem to be enough discussion to suit my tastes and though I'm an idiot I'd at least learn something. Learn I did and I'm wondering if this bug is one of those referenced in response to my comment.

Other random Haskell stuff: Recommendations to learn monads after functors, monoids, etc from Conal Elliott, a curious DSL from Sir Kiselyov, a neat package of adaptive datatypes from Dons, an interesting article on benchmarking EC2 with GHC compile times (which would be more relevant if I was trying to put off buying a computer or looking into working remotely) and some Haskell responding to Factor that I wish I could read.

Three last things: I found this cool programming problems blog that offers small, fun puzzles like Project Euler. It's called Programming Praxis. There's a really neat paper that's over my head called Types are Calling Conventions which makes a little sense but I wish it made more. And lastly, some thinking on the productivity boost of Object Oriented Languages that harkened back to some things Wren Thorton wrote and so on. Later!

Lisp is Lovable

posted on 2009-05-27 15:59:11

I'm about to run to class but I thought I'd throw up a Lisp solution I coded to the Funny Words problem which I worked through in Haskell earlier. I used sb-ext:save-lisp-and-die thanks to a helpful guide to dump a core image and used unix's time command to time it. The output of time ./funnyWords.core english-words.txt was as follows:
real 0m4.053s
user 0m3.913s
sys 0m0.057s

That's significantly shorter than the corresponding Haskell time and I wonder why. This code is a lot more imperative but I'm curious exactly where the speedups are. By the way, LOOP is awesome. As for the differences, I'll spend time sorting it out when I have time later. NOTE: solrize posted an improvement to my Haskell code that made it run in umm...half a second? Less? The main speedup seemed to be coming from using Data.Map and using the sort of each word as the key during insertion. That way, you get isAnagram for free, among other things. If you have thoughts on this code or the earlier Haskell code, where the differences lie or how to make them lispier or haskellier please let me know! :) Here's the code:

;; how to find words like cosmicomics:
;; words which can be split into anagrams by the middle letter
;; PRESENTLY ASSUME THAT ALL WORDS ARE LOWERCASE! how can we type/test for this?

(defparameter *dict* nil)
(defparameter *results* nil)
(defparameter *file* nil)

(defun main ()
(let ((*file* (or (second *posix-argv*)
*file*)))
(funny-words *file*))
1)

(defun funny-words (wordlist)
(let ((result nil))
(with-open-file (in wordlist)
(loop for word = (read-line in nil) while word do
(push word result)))
(setf *dict* result))
(mapcar #'partial-find *dict*))
;; (concat-map #'partial-find *dict*))

(defun is-anagram (word1 word2)
(string= (sort (copy-seq word1) #'char-lessp)
(sort (copy-seq word2) #'char-lessp)))

(defun has-joiner (word1 word2)
(let ((strlen (- (length word1) 1)))
(char= (elt word1 strlen) (elt word2 0))))

(defun is-funny-word (word1 word2)
(and (has-joiner word1 word2)
(is-anagram word1 word2)
(not (string= word1 word2))))

(defun build-word (word1 word2)
(concatenate 'string word1 (subseq word2 1)))

(defun same-length (word lst)
(loop for item in lst
when (= (length word) (length item))
collecting item))

(defun partial-find (word)
(loop for item in (same-length word *dict*)
when (is-funny-word item word)
do (let ((answer (build-word item word)))
(push answer *results*)
(print answer))))

;;(defun concat-map (f lst)
;; (loop for item in lst appending (funcall f item)))

The Week After

posted on 2009-05-26 14:18:37

I want to thank everyone who commented or sent messages for their love and support over the past week. It's been most appreciated. Things are slowly returning to normal. I wrote something substantial about Dad last night but I'm going to hold off on posting it for a bit. I want to make sure it's of the right quality. There was a write-up in the AJC, in print and online, which is alright but the obituary by Dad's college roommate (which is unfortunately not online) hits the mark much better I think. That or Mom's tributes to him on Caringbridge.

Quick (but serious) pop quiz, Compare and contrast these two quotes. They may be my two favorites. Tell me what they make you think in terms of their different approach to the benefits and drawbacks of the advance of human knowledge. I think the dichotomy between them pretty neatly encapsulates my scattered thoughts and feelings about human progress.

Civilization advances by extending the number of important operations which we can perform without thinking about them. - Alfred North Whitehead

We are living now, not in the delicious intoxication induced by the early successes of science, but in a rather grisly morning-after, when it has become apparent that what triumphant science has done hitherto is to improve the means for achieving unimproved or actually deteriorated ends. - Aldous Huxley

I'm mostly enjoying my summer courses, particularly Data Structures. It's given me an excuse to relearn pointers and learn how to actually use gcc/g++ and makefiles. I'm still a long way from being any good or knowing what the hell I'm doing though. C'est la vie. The Sixteenth Edition of the Haskell Communities and Activities report is out, in PDF and HTML. I was mostly excited to see a progress report on the Glasgow Haskell Compiler which is some top notch technology if ever there was any. Just look at the stuff they're working on! I've been poking around the Computer Language Benchmarks game recently, too. Gotta love SBCL and GHC.

There are a few pieces of software I'm anticipating a release of. Here they are with links to the blockers for each: Firefox 3.5 because I live in it, Chromium's (Google Chrome) Linux Beta and Songbird which I don't really use but track with some interest. I'm also looking forward to a new Pitivi release (which should happen today, actually) and GHC 6.12 but that's months out still. Emacs 23 should also be fun because emacs releases are so punctuated but it's a pain to find a release schedule anywhere or even a list of blockers! GEEZ! Outside of software, I'm really looking forward to Peter Seibel's book Coders at Work which appears to be reaching it's endgame.

Speaking of Emacs I've been spending a bit more time in that incredible editor trying to become more proficient and found the Emacs-Fu blog to help immensely. There was also a guide to using the extension that ships with Mercurial that I found pretty helpful in getting off the ground quickly. I'll wrap this up by posting three songs I enjoyed listening to this morning.

Max Richter - Horizon Variations
Found at skreemr.com


Andrew Bird - Anonanimal
Found at skreemr.com


School Of Seven Bells - Iamundernodisguise
Found at skreemr.com

Playing with Haskell

posted on 2009-05-03 04:47:39

Before I start running my mouth without thinking, some disclaimers:
1) This has no business showing up on reddit. It's a journal entry from a dumb kid who played for a few hours. I'm acutely aware of it. Also, there would be no post (no code) at all if cgibbard (Cale) in #haskell hadn't been so damn helpful. Thanks also goes out to olsner, ski, yitz and Twey.
2) This post is completely programming related for readers of my blog who aren't interested in that.

I've been increasingly enamored with Haskell recently. Back in March I picked up Real World Haskell and read through 3 chapters stopping short of finishing the last 3 exercises in Chapter 3 one day over spring break. School and real life caught up with me unfortunately and I've just now had time to sit down with Haskell again. I've been following the language pretty heavily since February and read a number of Dons blogs on things like writing simple unix tools. That's proof enough of disclaimer #1.

Looking back over some of the RWH stuff, I stumbled upon mention of a book by Italo Calvino called Cosmicomics. Cosmicomics is just a cool word. I decided to see how many words like it I could generate. That is, how many words could I generate that are anagrams smushed together by a shared letter. Naturally, I decided it'd be fun to try to do it in Haskell.

The resulting code is 39 lines, 35 removing comments. It is quite readable as far as I'm concerned and as I mentioned, I'm an idiot. The code compiles to a nice, native linux binary that takes up 684k on my machine (ArchLinux x86_64, GHC 6.10.2, etc). It reads in a 6750 word dictionary file with a word on each line and certainly does more computation than is necessary to get the desired result: a printed list of words like cosmicomics. It executes in just over 17 seconds. Fast enough for me. Here's the code:

-- how to find words like "cosmicomics":
-- words which can be split into anagrams by the middle letter
-- PRESENTLY ASSUME THAT ALL WORDS ARE LOWERCASE! I should probably unit test or type for this.

import Data.List (sort)
import System.Environment (getArgs)

main = do
[f] <- getArgs
inFile <- readFile f
let dict = filter (not . null) (lines inFile)
printFunnies (filter notSameWord (findFunnies dict))

isAnagram :: String -> String -> Bool
isAnagram word1 word2 = sort word1 == sort word2

hasJoiner :: String -> String -> Bool
hasJoiner word1 word2 = last word1 == head word2

isFunnyWord :: String -> String -> Bool
isFunnyWord word1 word2
| isAnagram word1 word2 && hasJoiner word1 word2 = True
| otherwise = False

notSameWord :: (String, String) -> Bool
notSameWord (word1, word2) = word1 /= word2

sameLength :: String -> [String] -> [String]
sameLength word xs = filter (\x -> length x == length word) xs

printFunnies :: [(String, String)] -> IO [()]
printFunnies xs = mapM (\(x,y) -> putStrLn (x ++ tail y)) xs

partialFind :: [String] -> String -> [(String, String)]
partialFind dict word = [(word,w) | w <- sameLength word dict, isFunnyWord word w]

findFunnies :: [String] -> [(String, String)]
findFunnies xs = concatMap (partialFind xs) xs


Note from the future: Accidentally navigated away from this page, Wordpress lost the last 600 words\40 minutes of work. Future posts will be written in Emacs.

I found the tricky parts of the problem to be findFunnies, partialFind and printFunnies. findFunnies I was actually on the right track about, I was just using map instead of concatMap. I'd bumped into concatMap earlier while looking at a different problem but it slipped my mind until Cale said, "Hey, you actually want concatMap here". Remember when I said I was dumb? partialFind may have been the trickiest and there are two reasons for that. One, I'd completely forgotten about list comprehensions. Clever, right? Even if I'd remembered them I had no idea you could test predicates while you built the list. Again, thanks Cale. Then it was working but I wanted to format the results differently and introduced two non-exhaustive pattern matches trying to do it so it was back to hastle #haskell. I was soon talking with Cale again. Finally, I realized you had to get the type system to accept the IO being done in printFunnies but I was using map as I didn't know something like mapM existed. Even had I known, I doubt I would've been able to throw together the lamba function it's being passed. Cale gave me a working version with forM and I found my way from there.

I came to Haskell from SBCL (Common Lisp) which I had come to from Scheme (PLT/MIT/Chicken, take your pick). I feel like a lot of my thoughts on Haskell are deeply colored by that trajectory so take the following with a few nice big grains of salt. Now then, for three random thoughts on Haskell from one of those fools who plays way too much with languages instead of getting better by actually getting things done.

It's really nice that Haskell actually has a dominant implementation, GHC, as well as a good package manager, Cabal. Consequently, all the libraries I've encountered on Hackage are easily installable and compatible with GHC. Conversely, I can't say if any require GHC extensions or are compatible with HUGS. That said, everything seems pretty up to date and I haven't even had to think about installing something from version control. Having easily installable bindings to a major cross platform toolkit like GTK or QT and Curses is pretty essential in my opinion. Don't even get me started on the awesomeness that is Hoogle and Hayoo.

Haskell is the first language that's made me see types can actually be useful. To be fair, before this I'd only programmed in Lisp, Scheme, Python and C. A trivial amount of each, at that, so you can see why I wasn't thrilled by static typing. To be fair, I did get a good number of compiler errors over typing problems in my code but they were always helpful. I'm not decidedly on either side of the fence with regards to typing and my gut says that both lend themselves better to certain problems (see the ease of multiple arity functions in Lisp and Scheme, for example) but at least now I can see the issue from both sides.

Haskell is also the first language with non-lispy syntax that I actually like. Dons posted an article called On Syntax a while back proclaiming the superiority of Haskell's syntax but did a bit of a disservice by using a trivial example. Haskell's syntax gets a fair bit more complicated doing anything non-trivial though the code remains concise by consequence. That said, it's far from unreadable and I hope that it'll become more natural as I spend more time writing code. While I found Python's syntax pretty tolerable, Haskell's use of Pattern Matching and Guards really puts it over the top. Lisp has been said to have no-syntax which certainly makes it easier (read: feasible) to use macros, not that it's merely a matter of syntax. I don't even want to think about Template Haskell. I remember reading something along the lines of "Lisp's no-syntax as syntax is certainly flexible but it doesn't lend itself to expressing anything in a very elegant way so much as expressing nothing in a very inelegant way". At least now I can vaguely understand why people could think Perl's syntax was a good idea.

Ironically, an article got posted on the Haskell subreddit earlier regarding Haskell's syntax and difficulty reading it. I thought Nostrademons comment was pretty thoughtful and it largely sums up my issues, particularly points 2 and 3. Maybe if I'm lucky I'll encounter point 1 as I code more in the coming months. Most importantly, none of these issues (syntax, typing or anything else) are dealbreakers. If you want to learn Lisp or Haskell you absolutely can and the main reason for that is the exceedingly helpful communities that surround them. When you can jump into a chatroom, mention a problem you're having and instantly get advice from some much smarter and more experienced folks there's no reason not to dive in and play around. More and more, I'm convinced that languages make it or break it based in large part on their communities and I promise Haskell and Lisp both have damn good ones.

If you're interested in learning Haskell, these are some of the best resources I've found on the web so far (excluding #haskell, of course):
Books:
Real World Haskell - A book available in paperback and readable free online.
Learn You a Haskell - A freely readable online book.
Haskell Wikibook - Community edited online Haskell book.
Docs:
The GHC Standard Library
and User Manual
Any packages docs on Hackage. Just click any of the links under "Modules".
Wiki:
The Haskell Wiki is phenomenal and has stacks of articles on everything from style and idioms to tutorials.
Search Engines: Search the libraries for a function by either name or type!
Hayoo
Hoogle

Finally, here's the output of time funnyWords english-words.txt behind a cut:

All Over Everywhere

posted on 2009-04-02 20:31:30

This week has ended up being pretty nice, if off the wall. Teresa and I were getting locked into an apartment over at the Aventine at Ashford. I'm also beginning to dig into Financial Aid applications for 2009-2010 and preparing for all the schoolwork I've got to do in April. Oh, and before I beat you with them I might as well warn you that this is another linkpost.

I'm planning on doing some hacking with a friend this weekend and was looking at data structures on Wikipedia, primarily Radix Trees and Tries(Prefix Trees).

Looking at which languages had libraries already, I found that Haskell's ByteString-Trie was written by a fellow named wren ng thorton. I chased a few links and stumbled on wren's livejournal where I read my favorite thing since the Minimal Social Compact. I may not be smart enough to follow every thread in there but I'm smart enough to know that his thoughts resonate and I wish wren the best of success. I really enjoyed Objects are a Big Pile of Fail too but for different reasons.

Speaking of Haskell, Conal Elliott's blog hosted a really good discussion on what portability means in terms of semantics, GHC 6.10.2 was released and the Haskell-Platform Mailing List put out a call for volunteers to help Duncan and Dons et al help get it out the door. You can say a lot of things about that language but you can't say it doesn't have momentum. Mmmm.

That other language I'm fond of has had some fun developments recently. It's not a huge deal necessarily but there's an interesting article by Slava Pestov on implementing a SmallTalk front end to Factor's VM. That's good fun.

Yesterday was eventful. I fixed some drywall and got a book in the mail. I'm rather excited about it. Its called The Elements of Computing Systems and between the book and companion web site (see: study plan), you'll build a computer from top to bottom out of NAND gates. A minimal Operating System implemented in a High Level Language, implemented on a VM, implemented on an Assembler, implemented on Machine Code, implemented on a specific Computer Architecture, implemented from Chips and Gates on whatever substrate proves suitable. Beneath that, of course, is Physics.

Also, it's been a long time since I was regularly checking Anandtech but when Anand keeps kicking out awesome articles about SSDs and the development of breakthrough graphics products I've gotta keep checking in for more. Keep it up, Anand! He's also managed to turn me into an OCZ Vertex fanboy.

Last but not least, it's important that somebody tell the Music Industry (and the Content Industry as a whole, actually) to bug off but I'm not sure that Charlie Nesson would be my first choice for the job. That said, it's important that somebody is trying to do it and I at least appreciate his goal of turning Copyright into a matter which people actually think about. We'll see what happens.

Endless Blather

posted on 2009-03-26 02:55:34

This post has everything.

It seems like a lot has happened in the past day or two. I'm all wrapped up preparing for a test tomorrow but there are other interesting things afoot. Teresa turned 20 today and there's going to be a party in her honor on Sunday. Kernel 2.6.29 has been released, it turns out cpufrequtils was never really doing anything and Skate 2 finally got a patch enabling custom soundtracks. EA Blackbox, even though you're two months late I'll take back some of those mean things I said. Speaking of games, someone finally wrote a Fei Long Guide for SFIV. It should hold some good lessons but I think I've got a lot of it down by this point.

I've got the webserver setup to play around with weblocks, leftparen and happstack. Hopefully one day I'll actually spend some time on that. It would be nice if weblocks was asdf-installable. I don't know. Maybe I'll just prototype GUIs in Chicken Scheme, Common Lisp and Python. QT seems to be the cross-platform GUI toolkit of choice. It's the only one with recent bindings for all three languages.

Oh, before I forget, if you're interested in the best general write-up on SSDs I've yet seen you should read this article from Anandtech. Generally I prefer the stuff at Arstechnica but I've yet to see anyone with an article this thorough and excellent on SSDs. Well done, guys. Speaking of which, OCZ Vertex 120GB are under $400. OCZ, you've earned my faith by this one. I'll choose you guys when I have cash to blow via pricegrabber.

There are endless good recipes on the Pioneer Woman's website. I had an abundance of Chicken, I check under Entrees->Chicken and find Braised Chicken and Parmesan Crusted Chicken. I've tried the Parmesan Crusted Chicken and the Braised Chicken. The Parmesan Crusted Chicken was pretty fantastic. Braised Chicken was tasty but I didn't like it as much.

The arguments about concurrent and parallel programming are ongoing. GHC is planning a new release for Autumn. I really hope the Haskell Platform is off the ground by then. Also, if you use Xmonad there's a good guide to Urgency Hooks here. Open Source development is still being thoughtfully explored. See, The Free as in Beer Economy and Freesouls.

The International Lisp Conference '09 has been going on and different people have said different things about it. Andy Wingo seems to have some decent writeups. Sadly, some of the things he say make me think of what Paul Snively said in his Road To Lisp survey (which I realize is likely quite dated), "My own thinking is that Lisp is the cockroach of programming languages: it'll be the only one left after the apocalypse. Not bad for a dead language." Maybe in a few decades I can hope I don't suffer the bias of echo chambers. Maybe not.

Last but not least I'll just note that I'm really enjoying Elbow tonight while doing math. Really enjoying it.

Elbow - Weather To Fly
Found at skreemr.com

Trouble Man

posted on 2009-03-24 13:28:12

It's a Marvin Gaye morning. I love the song Trouble Man. If I could sing it like Marvin some days I would just walk around singing it.

Marvin Gaye - Trouble Man
Found at skreemr.com


How can you be against that? While we're on Marvin Gaye here's a version of Inner City Blues with a little surprise if you get to the end.

Marvin Gaye - Inner City Blues (Make Me Wanna Holler)
Found at skreemr.com


Last thought, does anybody else wish there was a version of House for programmers in which "Dr. House" told everybody to just shove their Gang of Four and Design Patterns, think about the problem and actually do the job right? (Note: This does not mean unstructured programming or something. Mostly just anti-kneejerk-OO. He's a cynic looking for simple and obvious solutions, not a curmudgeon.)

It might be fun, I might be wrong...

posted on 2009-03-19 00:50:28

I've done a very poor job adhering to my schedule today. I'm still in the spring break mentality and not really wanting to work. I worked hard Monday and Tuesday. I'm not sure what happened today. At any rate, I need to remember to make myself write some Lisp, Haskell, or Python for fun this weekend. I should also probably write some C# for school.

Three quick things I stumbled on today that made me happy:
Joe Marshall continuing to talk about his history with lisp, how he found it, etc.

lib6502 by Ian Piumarta. I keep hearing that the 6502 had a really nice ISA and I'm considering whether an eventual fun project (like 5 or more years out) might be to write a basic lisp or scheme interpreter targeting the 6502. Maybe I could get away with working on it some in an Architecture or Programming Language Concepts course. Somehow it sounds tricky/crazy. Could I write one in 5 months? I'm still an idiot. Maybe I won't be in a year or so.

Last, there's some interesting guitar modeling software for PC...and articles about how to emulate other people's guitar setups, including John Mayer. Now, that may sound ridiculous...but here's something else that makes me happy that not many people know. John Mayer can play the everloving shit out of his guitar. There are a lot of little Stevie-isms in there. As in the late great Stevie Ray Vaughan, whom I dearly love. Is there anyone besides Mayer that's keeping the SRV style alive today that I should know about?

I'm still more interested in sampling than being a guitarist myself but I like to noodle now and again. Speaking of which, go back and listen to the first Gorillaz album. Great, right? :)

Brick by Brick

posted on 2009-03-10 19:34:08

So spring break is finally here and I've gotten nothing done the past...5 days. I threw a small get together on Friday, went to a friend's stand up show on Saturday, saw the Watchmen on Sunday, and saw the same friend yesterday to watch Synecdoche, NY...which reminded me that I just don't get Charlie Kaufman films. The Kaufman films amaze me they're just incomprehensible. I can't infer the meaning to his metaphors, usually.

That's not all I've done these past few days but you get the picture. Worse (or better) still, my social schedule is booked. I'm already hanging out with people Tuesday night, Wednesday night, Friday night and Saturday night. It's ridiculous. I'm never going to get my math homework done. Anyway, where was I?

The more I think about it the more interested I am in writing or composing music of my own and there's no question that I want to do it digitally. I may even write my own software tools to do it but that's way down the line. A lot of the trouble is I don't know how to get started making music on a machine at all. Or off one. It's sort of this big, ominous thing for me. I don't think of myself as being that creative or talented anyway but I don't care. I'm going to try it. I'm still sampling things occasionally. I just need to find some piece of software to help me string it all together.

I've been at least a little productive. I've cranked through the first few chapters of Real World Haskell and would like to keep a one chapter a day pace. The code is browsable on the new server's mercurial repo. One good thing has occurred to me these past few days. Spring break isn't wildly different than my normal schedule. Sure, I don't have homework or Tuesday or Thursday classes but I don't think that's holding me back from being truly productive or learning things I want. If I just invent the right structure for myself I think I can do still more than I'm doing now. It's something worth thinking about.

After all, there's so much out there to study. I'm interested in picking up some Category Theory from a (djvu) copy of Conceptual Mathematics I found out on the interwebs. I'll probably buy a copy at some point, I have a problem when it comes to books. Anyway, aside from that there is tons of great free material out on the web. Herbert Wilf's Generatingfunctionology and A=B are both available free online and there is an interesting text on the Basic Concepts of Mathematics and one on Modern Algebra, and another on proofs that I may work on. Beyond that, there's tons of free material on Haskell and Lisp so I have no reason to be bored. Oh, and as always Brian and Robert over at Enfranchised Mind are always putting out good articles.

Last but not least, BT wrote the entire song that follows in the CSound programming language. Granted, it took him 6 months and hundreds of pages of code but still...


















BT - All That Makes Us Human Contin
Found at skreemr.com

My .hgignore

posted on 2009-01-14 23:25:29

Before I forget it or fail to version it somewhere I want to post the contents of my .hgignore file. You may or may not find it useful if you're a mercurial user but it's really for me. :)

syntax: glob
*.elc
*.orig
*~
\#*
.DS_Store
unversioned/*
.hgrc
.hgignore

Mercurially Me

posted on 2008-10-23 05:34:39

Something non-techy for starters, Don Gerz has posted three separate entries about Alan Moore's Watchmen in the last week. In two days, actually. And (perhaps due to my prodding) Kris Osterhage threw up a post mentioning his Watchmen experience among other things. It's fun. Maybe I should try to re-read it and write a nice essay before the movie comes out in March.

I haven't been getting quite enough done lately but what else is new. I have been learning some good things and as always there's good stuff coming down the pipe. I've banged out the features I thought my version of hangman was most lacking, a real word-list\dictionary and a fix for a bug I may not have mentioned. If a letter occurred more than once in a word (i.e. "o" in "cook") and was guessed only the first instance of the letter would show up. Those fixes are committed and I'm moving on to things like the cleanup suggestions Xach made and then who knows.

Finishing PCL is probably next on the priority list. I took some crappy notes which I keep telling myself to turn into a "Common Lisp for Schemers" series of articles but I haven't gotten around to it. Maybe because I'll just embarass myself but that's what the internet is for so I'll probably do it anyway. I've also been wanting to finish the Picture Language stuff in SICP 2.2. But whenever I try to load the SICP module in DrScheme my CPU utilisation goes through the roof and it just sits there for a while. Personally, I'm not one for waiting as this seems to happen with any module on PLaneT. It's probably just me though and I'm willing to look into it more later. There are some .scm files for MIT-Scheme on the SICP site and I'm still considering what to do.

Also, I've been peeking at Scheme implementations again. I'm still fond of the massive concurrency option of Gambit/Termite and I like DrScheme for it's strong community and many good features...but my heavens, Chicken Scheme is armed to the teeth with eggs. Is it even for real? That looks like fun to me. Implementation surfing is a dangerous distraction when you should be writing code though. I'll worry more about scheme implementations when I bang out a x86_64 edition of RedLinux before college starts (hopefully in the Spring). I'll write more about that tomorrow but I've been worrying about my upgrade path for a while now and going back to school has brought some of those issues back to the front for me. My laptop positively refuses to get on a secured wireless network. Now, that's probably something to fix with a usb wifi card or something but the battery life is also under an hour. I'll just say I've been thinking about it a lot and come to some conclusions.

Additionally, OOPSLA and Lisp50 just wrapped up. I really wanted to go but I wouldn't have been much more than a fanboy at this point and my funds were limited. Hopefully videos of a few talks and more blogging on the conference will trickle out. The clatter about clojure continues to grow too. It's something worth keeping an eye on no doubt.

Last but not least, more mercurial fun tonight. What you didn't guess from the title? I found two good sources on Mercurial today. The first was a general mercurial guide and the other dealt with emacs integration. On to some quick tips.

Let's assume you forgot to setup your username in .hgrc and you've just fired off the old add-commit. You haven't pushed (and we'll assume no one had the ability to pull) yet so no one has to know about your silly mistake and crazy machine name. Just run hg rollback to eliminate that last commit but be forewarned that you can't rollback a rollback. For simpler cases where you've added, removed or something similar but haven't committed yet just use hg revert. You can also use hg revert filename to undo changes to a particular file.

Also, I'm enjoying using mercurial.el in emacs. Just drop mercurial.el into your emacs/site-lisp directory and (require 'mercurial) into your .emacs file. C-c h s does hg-status and C-c h c will start a commit but allow you to unmark any files you don't want to commit before doing so. C-c h a is hg-add and C-c h U is hg revert, C-x v u being for the current file only. C-c h < works as hg-pull and C-c h u is hg-update. Finally, C-c h > is hg-push. There you have it folks. Mercurial in a paragraph. I'm a bit tired so that's all for tonight. See you tomorrow.

Quick Mercurial Tip

posted on 2008-10-17 19:20:36

I hadn't actually looked into ignoring files with Mercurial until today. You can set up a file in the root of your repository called .hgignore that will make your life a bit easier. Mercurial will read that file (which is a list of patterns in glob or regexp format) and will ignore any files that match those patterns when it does it's versioning work. So, want to ignore anything under the unversioned directory, mercurial configuration files and any temporary files? Here you go:


syntax: glob

unversioned/*
.hgrc
.hgignore
*~
\#*
*.elc
.DS_Store


Also, there are some great mercurial articles here. I'm also playing around with Zach Beane's ZS3 library. Nice stuff. Also nice is his Common Lisp small project guide. That's damn handy. Unfortunately, all I'm using S3 for at the moment is to store RedLinux (695mb iso) and drakma currently requires loading the full file in memory to upload it with PUT. I guess I'll be keeping an eye on Edi Weitz then. More later...

Hangman's Hope

posted on 2008-10-17 08:02:04

The last week has been really, really hard. Mostly because I've been confronted with something I hoped wouldn't have to happen: The necessity of returning to academia. I've applied to a few more jobs and we'll see what happens there. I got turned down by King & Spalding in a letter today and am going to call tomorrow and ask why. I'm really just not getting enough done on my own to justify being out of school. I'm not learning enough. Perhaps I do need the structure. I'm disappointed but I have to re-evaluate based on my experience. State changes and given my present state I'm looking at returning to SPSU in the Spring or Fall of next of year. There's some notion of transferring to GA Tech as well but I'm not sure what I think about that.

One nice thing about SPSU would be that I'd at least have the spare time to continue pursuing LISP and other personal studies. It's also worth noting that a significant motivation in this year off was to at least get the fundamental concepts of programming down some before being buried in the specifics of the monstrous languages used to instruct most Freshman in Computer Science these days (i.e. Java; pythonistas at Tech, you're lucky).

Anyway, tonight I was frustrated with the fact that I hadn't written any code in a long time and I hadn't written a real program of my own in an even longer time. For one reason or another, implementing Hangman in Common Lisp seemed like a good idea. Now, I'm not claiming that hangman is ever any great feat...except maybe if you write it in BrainFuck. Nor is it any great feat to write it in under a hundred lines. Worse still is that it lacks any ASCII art. That said, I did this in a few hours, found it pretty fun and think it came out fairly readable and concise in the end. After all, how couldn't it? It's hangman.


;; Hangman
;; Brit Butler
;; v.01
;; Feature Ideas: ASCII hangman. Eliminate explicit elt references and other hackish
;; stuff, especially show-letter. Import dictionary in place of *word-list*.

(defparameter *word-list* '("cookies" "kittens" "fairies"
"unicorns" "words" "linux"
"lisp" "music" "songs"
"sex" "love" "fun"
"code" "cease" "and"
"desist" "read" "print"
"eval" "loop" "macro"))

(defparameter *turn-count* '())
(defparameter *letters-picked* '())
(defparameter *word-in-progress* '())
(defparameter *solved-word* '())

(defun hangman ()
(setf *turn-count* 7)
(setf *letters-picked* '())
(select-game-type)
(work-on-word))

(defun select-game-type ()
(if (y-or-n-p "Would you prefer to have a word chosen at random?")
(set-the-words (elt *word-list* (random (length *word-list*))))
(set-the-words (string-downcase (read-prompt "Please input your desired word: ")))))

(defun set-the-words (word-of-the-run)
(setf *solved-word* word-of-the-run)
(setf *word-in-progress* (make-array (length word-of-the-run)
:initial-element #\- :element-type 'character))
(format t "~a~%" *word-in-progress*))

(defun read-prompt (query-string)
(format *query-io* query-string)
(read-line *query-io*))

(defun check-letter (letter)
(if (already-picked? letter)
(format t "You already picked that goofball! Try again...~%")
(push letter *letters-picked*))
(cond ((is-in-word? letter) (show-letter letter))
((not (is-in-word? letter)) (decf *turn-count*)
(format t "Nope. Not in there. ~a turns left.~%" *turn-count*))))

(defun is-in-word? (letter &key (start 0))
(position letter *solved-word* :start start))

(defun already-picked? (letter)
(position letter *letters-picked*))

(defun show-letter (letter)
(setf (elt *word-in-progress* (is-in-word? letter)) letter)
(format t "~a~%" *word-in-progress*))

(defun pick-a-letter (&key (message "Pick a letter please: "))
(let ((rtn (read-prompt message)))
(if (> (length rtn) 1)
(pick-a-letter
:message "We only need ONE letter thank you very much. Try again: ")
(check-letter (elt rtn 0)))))

(defun work-on-word ()
(pick-a-letter)
(word-finished?))

(defun word-finished? ()
(if (= *turn-count* 0)
(game-over)
(if (string= *solved-word* *word-in-progress*)
(play-again? "Congratulations.")
(work-on-word))))

(defun game-over ()
(format t "Sorry. The word was ~a.~%" *solved-word*)
(play-again? "You're all out of turns. Game over."))

(defun play-again? (message)
(format t "~a~%" message)
(if (y-or-n-p "Would you like to play again?")
(hangman)
(format t "Thanks for playing!~%")))

Another Emacs/Slime Cheatsheet

posted on 2008-10-12 05:37:04

I've been picking up more and more Emacs and SLIME while working my way through Practical Common Lisp over the last week or two. I'm really happy with it as a work environment at this point but have tons left to learn. I haven't even written any elisp code to script it. Of course, I haven't had a need yet. I'll get there and I'll update this as I learn new things. I'll just note that I'm also quite attached to ArchLinux as my distro and, increasingly, Xmonad as my window manager. It's the first time I've felt really settled on an Operating System/environment since moving to Linux. Maybe ever. I'm pretty happy about it and aside from using RedLinux as a way to see what I like, I've posted all the config files here. Before the cheatsheet here's a quick Linux tip on killing processes I found. Try passing -1 or -9 to kill along with the PID. Try -1 first then -9 if all else fails. On to the cheatsheet.

EDIT: Yes, it's ugly. Piss off. I miss monospaced fonts already, I'm grumpy, I'm tired, it's 1:40 am and I haven't been up this late in forever. I'll fix it later. ;-P


;;Emacs Cheatsheet:

; C-7                         Undo.
; C-8                         Backspace.
; C-s                          I-search forward.
; C-v                          Page-down
; M-v                         Page-up
; M-<                        Beginning of document/file.
; M->                        End of document/file.
; C-l                          Center screen on cursor.
; C-n                         Next-line/Down-arrow
; C-p                         Previous-line/Up-arrow
; M-f                         Forward a word
; M-b                         Backward a word
; M-bksp                    Delete previous word.
; C-k                         Send a line to the kill ring. Cut.
; C-y                         Place a line from the kill ring. Paste.
; C-x C-f                    Find (or create) a file and open it in the buffer.
; C-x C-s                    Save the file in the buffer.
; C-x b                       Switches to a buffer. Type for a specific buffer or hit enter to go with the default (last buffer).
; C-x o                       Moves the cursor between windows.
; C-x 0                       Closes the current window if other windows exist. (Kill this window.)
; C-x 1                       Makes the current window the only window. (Kill all other windows.)
; C-h t                       Start the emacs tutorial.
; C-h k                       Prompts for a keystroke and tells what command it invokes.
; C-h w                      Prompts for a command and describes the keystroke it's bound to.
; C-h b                       Displays a list of bindings to various commands.
; C-u num command   Repeats the given command num times.

;; Slime Cheatsheet:


; M-p                                  Is the up arrow for the slime repl.
; C-c C-c                             Sends an s-expression to slime.
; C-c C-k                             Compile and load the file represented by the current buffer.
; C-C C-L                             Load a file in slime, defaults to the file in the current buffer.
; C-c C-z                              Pulls up the repl in a frame and moves the cursor there.
; C-c RET                             Runs macroexpansion.
; , quit                                 Kills the running inferior-lisp and closes all the SLIME buffers.
; q                                       Leave the debugger and return to the repl.
; M-x Slime-inspect               Run the inspector.
; M-x Slime-profile-package   Run the profiler.
; M-x Slime-profile-report      Check the profiler results.
; M-x Slime-profile-reset        Reset the profiler.

Less fun, More funk

posted on 2008-09-15 17:21:18

9 months into "the real world" I'm a bit perplexed. With all this talk of industry and full-time jobs, I for some reason expected that "the real world" would expect you to be industrious. Apparently, I am mistaken and while you'd want to end up at a job that challenges, drives and energizes you it is by no means a necessity. I've been thinking about this a lot and at some point will write more and possibly even wrap up that emerging philosophy series of posts. Particularly because I've been having lots of discussions that concern economics and/or politics lately and there seem to be some tenuous strands between those things. I go back and forth on what we need to do about the majority of people that accept and have no issue with the status quo, or at least lack the drive, energy or determination to get outside, above or beyond it. I would say that's probably 90% of us and am pretty sure I am in that category myself at present. It certainly seems unreasonable to demand the peak of human achievement from everyone and highly questionable whether people would universally like being at the peak of their potential achievement, or near it. I'll try to elaborate on those thoughts enough for them to be coherent in the near future.

Found some good reading\watching this morning though I sometimes wonder when\how\if I'll get to all of it. One good thing is the S3 2008 conference (unrelated to Amazon's S3 architecture ) which includes video footage of a presentation on the Lively Kernel . That's pretty cool stuff and I hope I get a chance to watch it tonight. Also there was a paper co-authored by Pascal Costanza on Reflection in Programming Languages , specifically Lisp. I've read the first few pages and though some of it is over my head I think I can stumble my way through it. I really am hoping to get around to reading this paper by David Wiley titled Online Self-Organizing Social Systems: The Decentralized Future of Online Learning . Will referred it to me and it looks quite good. I'm even tempted to read some Dijkstra .

I'm interested in getting some of the piano work of Ravel, Satie, and Debussy. I have Debussy's Children's Corner and like that. Then again, maybe I just need more Masashi Hamauzu.

A final thought: Why are 90% of the good technical lectures on the web in RM format which I must tediously rip to download an offline copy? No, I do not trust your site to stay up with the content I want forever. Even if you're google or wikipedia. Thanks, Peter.

Eat Food, Sleep, Have Visions

posted on 2008-09-12 16:19:27

Wow. What a day. I've been managing to keep fairly busy lately but also enjoying myself a good deal. So what's in store today? A word about music, a bit about games, some programming thoughts (on Factor and Common Lisp) and a mention of RedLinux.

Music: Four Tet has been making me really happy for the past 24-48 hours. I've known and liked Four Tet for a few years now but I think just how good he is at what he's doing only hit me recently. Two tracks did the trick for me and both are off his album Everything is Ecstatic. One is titled 'Smile Around The Face' and the other is titled 'And Then Patterns'. I'm posting a streaming link to 'Smile Around The Face' because it's awesome. There's a pretty interesting list of his 9 most influential records here and some interviews here and here that I may read later. As a sidenote, I'm jealous of all those NCF kids and their Walls. I want to throw a wall. If I did though I'd probably be silly/lame and try to sneak this track in...

Four Tet - Smile Around The Face
Found at skreemr.com


Games: I've been saying that one of my favorite things about the new game consoles is the downloadable games. Xbox 360 and PS3 seem particularly strong in this category to me though the Wii has old mainstays from Nintendo lore to prop it up. I've already mentioned echochrome and everyday shooter here in the past and they're both quite good but I don't think I've mentioned Super Stardust HD. It has been and continues to be simply delightful. Some video tips on the game were recently released as a free downloaded on the PSN and convinced me to pick up the $4.99 single player expansion pack. They also released a free patch for the game so that you could play music off the PS3 hard drive once that functionality was possible through firmware updates. If anyone who has worked on the game is reading this: Excellent, excellent work guys. Really. This is how to build a title and continually improve it, create community, etc. I look forward to your future releases.

Languages: I'm going to separate my blathering here into sub-ramblings based upon the language concerned. First up, Common Lisp. I've been having some fun working with a friend to get a simple Gmail scraper/wrapper API developed in Common Lisp that would allow me to connect to accounts grab and compose messages, etc. We were relying on a CL library named mel-base to achieve this. I've been doing development locally and in the process gotten a bit more familiar with SBCL, SLIME and ASDF-Install. I've definitely come around to the idea that there is a place for both Common Lisp and Scheme which I, in misguided form, derided some time back. There are certainly pros and cons to each. At any rate, the combination of ASDF-Install, SBCL and SLIME is pretty great. That said, I realized after a bit of tinkering that mel-base lacks SSL support even here in 2008. That means it won't work with most (if not all) of today's web-based e-mail services which require SSL to encrypt the connection to the server (you know, so people can't steal your password and e-mails). I'm quite surprised it isn't there by now but assume the maintainer has been busy. Luckily, there is a CL library for SSL called CL+SSL, appropriately. I'm very tempted to find a way to patch SSL support (with a dependency on CL+SSL, of course) into the POP3, IMAP and SMTP folders in mel-base and contribute the patch upstream for the next release. I have no idea what I'd be doing really and I'm fairly intimidated but it seems like a good start and a reasonable place to help and try my hand. There are some other people who have pursued this though that I should get in touch with first to make sure no patches are already in circulation for SSL. Next up, Factor. I've been interested in stack-based languages since I first learned of them and still am quite intent on learning Forth in the near future. Possibly as my first non-lisp language. I stumbled into some blog entries by Phil Dawes on why he likes Factor and has enjoyed learning it. He also has an excellent post digging down into the versatility and usefulness of the compiler. Speaking of which, the Planet Factor blog offers some of the clearest insight into the development and internals of a programming language I've ever read, particularly one as young as Factor. Keep an eye on this one. You've got one more year, Slava. I want my 1.0.

RedLinux and Logos: I'm solidifying "plans" for the v.08 update to RedLinux. You can catch a glimpse at the changelog. I also have some logo designs (Thanks, Neil!) for the lambdabang, I just need to decide on size and color. Once I get a logo for RedLinux, I'll start working on the web page for it and get the ISOs up. End of September? We just might be able to do that.

An Update

posted on 2008-09-05 20:07:29

Wow. So I started a post on Friday (I think, maybe Tuesday) but I must not have saved or finished it. It's not sitting in my drafts folder. Anyway, I've been a bit up and down lately but I'm really glad Fall is starting. It may be my favorite season. I dig the cooler weather. I got my wisdom teeth out yesterday morning and that went smoother than I expected. I miss chewing food but other than that have no real complaints. I haven't needed much of the hydrocodone (basically vicodin) they gave me and haven't been sleepy or incoherent much either. In fact, I've been up since 8am today and really enjoyed catching up on e-mails and little things like that. Ah, vacations.

Newsflash: Cooking is really fun. I've cooked a little ever since moving into the house and meant to move on to more advanced dishes but really stuck to basics (pasta, pizzas, burgers + dogs, sauteed chicken) for the first month or two. Recently though I found some food blogs and have been trying to cook real meals. I started this monday with made from scratch blueberry muffins and filet mignon and mashed potatoes for dinner. It was wicked good. In the upcoming weeks I'm hoping to pick up fried chicken and empanadas. Tonight I may just try to figure out french onion soup. :-)

So, the next two months are huge. September there are three major Linux Conferences (X Developers Summit, Linux Plumbers Conference and the Kernel Development Summit) going on and a fourth in Atlanta. The one in Atlanta (Atlanta Linux Fest 2008) is on Saturday, September the 20th and I couldn't be more excited. It's from 11am-6pm over on Northside Pkwy and I signed up as soon as I heard about it. Plus I just got my wisdom teeth out. October there are lots of Linux Distribution releases (particularly Ubuntu and Fedora) and a number of awesome games coming out for PS3 including LittleBigPlanet, Fallout 3 and Bioshock. I'd really like to get the custom ArchLinux derivative I've developed over the summer out by October, too. Even if that just means putting the ISO on megauploads and creating a page for it on my site.


Beyond that, I'm just trying to get back into programming. I haven't moved as quickly as I'd like but I am having fun. I'm really tempted to try to learn about Factor, a concatenative language (like Forth) developed by Slava Pestov. It looks really cool but I can't quite afford to get sidetracked at the moment. If you're interested in what it's like trying to write a modern programming language though they've got a great blog and Slava has made some great posts on the Compiler Architecture lately. My big programming focus at the moment though is trying to do some hacking for a startup in NYC. I got contacted by one of their developers and think I can learn a lot from them though how much I'll be able to help is still up for debate. At the moment, I'm mostly writing glue code for Common Lisp libraries but I'm really enjoying it. It's also made me realize just how crucial libraries and the way they're handled by a language is. I can't believe they managed to leave module systems out of the RnRS for so long! I can also see why Common Lisp opted for multiple namespaces but I'm still not sure I like it. And I definitely just don't like the syntax for funtion calls after being used to Scheme. Ah, well. There is no perfect language.


Feel free to swing by the house if you want to help me learn to cook or see me looking like a chipmunk.

Programming in the Debugger

posted on 2008-08-13 19:57:40

There's a quote I recalled reading on the internet and wanted to send to a friend recently but I couldn't find it. I stumbled across it today over on Lambda the Ultimate and am archiving it here due to awesomeness. Lambda the Ultimate is a fantastic community centered around programming languages and there are many great discussions worth reading. This discussion starts off with the aforementioned quote which I'll excerpt here and goes on to discuss dynamism in languages, specifically as it relates to interactivity versus a specific typing discipline. Ready for the awesome quote? Good.

By way of Luke Gorrie over on Lambda the Ultimate:
By way of Joe Marshall in comp.lang.lisp:
Here's an anecdote I heard once about Minsky.  He was showing a
student how to use ITS to write a program. ITS was an unusual
operating system in that the `shell' was the DDT debugger. You ran
programs by loading them into memory and jumping to the entry point.
But you can also just start writing assembly code directly into memory
from the DDT prompt. Minsky started with the null program.
Obviously, it needs an entry point, so he defined a label for that.
He then told the debugger to jump to that label. This immediately
raised an error of there being no code at the jump target. So he
wrote a few lines of code and restarted the jump instruction. This
time it succeeded and the first few instructions were executed. When
the debugger again halted, he looked at the register contents and
wrote a few more lines. Again proceeding from where he left off he
watched the program run the few more instructions. He developed the
entire program by 'debugging' the null program.

Top 5 Hackers

posted on 2008-07-14 16:18:53

I got sort of preoccupied this weekend with the question of who my Top 5 Hackers are. They're not necessarily supposed to be the world's best hackers. Rather, they're programmers who I respect both technically and individually. There are plenty of people doing great work on interesting things and that wasn't the primary motivation behind this list. I'm not going to go too deeply into my reasoning or try to order the list in any particular way. I'll just lay it on you. I'm sure it will change some over time.

Aaron Swartz
John Carmack
Justin Frankel
Linus Torvalds
Luke Gorrie

Topping off the day

posted on 2008-04-22 04:59:45

Okay, so today has been pretty excellent. I've really gotten a good bit done. I fixed my problem with MIT-Scheme on Hardy by just compiling a new version from source, I figured out how to get Emacs to behave like edwin when evaluating s-expressions (at least with MIT-Scheme) and I tidied up the first two SICP entries with 1.3 left for tomorrow. Finally, I installed a revision control server and moved all my code into it.


I'm really pleased about it because I've been meaning to do it forever. You may remember me babbling on about "git". That was what I initially intended to use as my RCS but I settled on mercurial and I'm quite taken with it. At any rate, to see the fruits of my labor just navigate to the new code section of my website. You can see the two different changesets I've uploaded so far and browse through the files by clicking the "manifest" button at the top, then going to books, then sicp, then chapter01. I'll do a more thorough writeup tomorrow. Hope your days were as joyful and productive.

Emacs and MIT-Scheme on Hardy

posted on 2008-04-21 17:55:30

Okay, quick update. The feature I'm missing from edwin has a name and that name is "Scheme Interaction Mode". This feature is provided in Emacs by using xscheme.el. Just replace (require 'quack) with (require 'xscheme) in your .emacs file. Unfortunately, xscheme only works with MIT-Scheme so as far as I can tell there isn't a general purpose Scheme Interaction Mode for Emacs that works across Schemes. I'll dig around more about that. In the mean time, I got MIT-Scheme to work on Hardy by compiling from the portable C on their website as described here. It took over an hour though. It's not a solution I'm too pleased about and half makes me want to downgrade to Gutsy or switch to a distro that has support for MIT-Scheme altogether. At any rate, more on all this down the line.

Quick Emacs Question

posted on 2008-04-21 04:01:58

Dear Interwebs,

I've gotten rather accustomed to Edwin as I've worked my way through SICP. Eventually I'll want to use a different scheme so I'll have to switch to Emacs. I've been working on that lately but there's one thing holding me back that I can't find a solution to anywhere. I've got quack installed and really like the edwin behavior of C-x C-e. That is, when I evaluate an S-Expression I want it to be evaluated on a REPL in the background and the resulting value or error information dumped into the text editing buffer. I do not want a REPL to show up with that information in a new frame. Please, Emacs folk: Help.

Spontaneous Monday Linkpost

posted on 2008-03-03 17:52:17

Bookshelf Jealousy

I need to try OpenBox and build a trim install from the ground up again. Maybe with Gentoo this time? Or should I stick to Arch of Foresight?

I continue to hear good things about Barack Obama. Staggering amounts of good things. It's not that Marc Andreesen is saying this. It's that everyone who's had contact with the guy is saying this. Also, he's big on civil liberties. Maybe from lecturing on Constitutional Law at University of Chicago. Hopefully that means he'll handle these fiascos a little better than the current administration. It wouldn't be too hard.

I really want to hear a good comparison of bzr and git and I'm not convinced I've heard one yet. It seems to be very "Linus made Git!" vs "Yeah but mere mortals can use Bzr!". Please guys can we elevate the sophistication in this debate?

Luis Villa comes up with some great ideas and this is one of them. Also, I may finally have to try greasemonkey because adding pictures to my posts continually sounds like a better and better idea. Well, at least some of my posts. While we're on Luis though, I take RSS feed reading seriously but I don't get near 800 feeds a day. I'd be interested in hearing what he settles on.

I'm wondering if I should start contributing to Ubuntu's Weekly Newsletter. It'd be a chance to do some volunteer work for a community I do care about and I have been thinking that down the road I might like to do some freelance writing so it wouldn't be a bad way to get a feel. What can I say? Ben inspired me.

I'm glad people are thinking about the future. This article from worldchanging appears particularly promising. Anyone have any formal responses to this? I'm going to work on mine along with an update of the Secondhand Standards essay.

Also, I'm not personally a Nine Inch Nails fan but it is pretty cool that they've released their latest album as CC'd work and I kind of hope Radiohead does that with their next album...

Personally, I share sogrady's taste in laptops and while I'm not in the market right now I am wildly optimistic about grabbing one of these in a year or so off craigslist or something.

I'm trying to really get into emacs. I want to settle on an editor and really learn it. Since I'm learning Scheme for the next year or so Emacs seems like an insanely reasonable place to start. Making it pretty seems like a good idea though.

Finally, this guy is totally awesome and I hope I can come up with a project as cool as this after my self-education.

Future Projects…

posted on 2008-03-02 22:08:29

I'm looking to make a "You might be an Oglethorpe Kid if..." list. Any suggestions?

I was driving to Oglethorpe Friday night and after seeing a license plate ("ADD 7018" I think...) I had this interesting idea for a function:

1. Takes an integer (i.e. 7018) as it's single argument.

2. Converts it to a list of integers (i.e. {7, 0, 1, 8}).

3. Adds the head of the list to the concatenated integer of the tail (i.e. 7 + 018).

4. Repeat until it's a 1 digit value and return that value.

So, on the first run you'd wind up with 025, then 25, then 7. Notice anything interesting? That's the first integer in the list. I'd like to write another function that runs the first million numbers through this function and then outputs the results in a nice readable table. That'd be interesting.

Anyway, in other news if you check I've updated the frontpage on my site to be a bit more accurate with regards to my current activities. I also started categorizing all my old blog entries back in January and I'm done so now everything is tagged and you can pull up stuff by topic. Say if you wanted to read all my bad poetry for example. Or my crazy essays, all my rants involving Linux, or posts with Pictures, etc. Of course, the search function always works too.

I watched Lecture 2-a of the SICP Lectures last night. The first half hour made sense but the half hour after that was more like the sound of my brain melting. I'm going to try a few of the problems and see how it goes. I also might work on some goofy playlists. If you've got some goofy playlist\artist\song you've been rocking out to recently post it in the comments. Alright, wish me luck.

Pascal’s Triangle

posted on 2008-02-07 03:25:28

A little over two weeks ago I came up against Exercise 1.12 in the venerable Structure and Interpretation of Computer Programs.


The exercise wants you to write a recursive program to compute elements of Pascal's Triangle.


This exercise has pretty much infuriated me and it's all my own fault. Upon first hearing the problem statement I got it in my head that the function should look something like "(define (pas n)...)". I always think of number series being described in terms of a single argument (i.e. the 12th element) so it seemed natural to me that the pascal's triangle function should be computed in this way even though it is not, in some sense, a traditional series.


After a while, I cracked and read the precursor text (but not the code) to Eli Bendersky's solution and noticing that he defined the function with two arguments (for columns and rows) arrived fairly quickly with that insight at what seems to be the more or less standard solution. I have had this much completed for a week but gotten stalled trying to figure out the problem of a pascal function that takes one argument.


As of today I've solved the problem though and hoped to share my results here. First, the throwaway code that ended up being good for nothing!



(define (is-one? element)
(define (is-one-iter ones count flag)
(cond ((< element 5) #t)
((= ones element) #t)
((> ones element) #f)
((= flag 1) (is-one-iter (+ ones 1) count (- flag 1)))
(else (is-one-iter (+ ones count) (+ count 1) (+ flag 1)))))
(is-one-iter 4 2 0))
;Value: is-one?

That code tests to see whether a given element equals one and it does take a single argument which is nice. I couldn't figure out a way to use it to compute the actual elements though.


After a little bit of experimenting I stumbled on this number sequence (OEIS #A080956) which when put in the following procedure would allow me to compute n from a given column and row.


EDIT: Corrected dyslexic mistake in my code (I'd replaced all instances of col with row and vice versa). See comments.



(define (n-from-rowcol row col)
(define (f x)
(- (/ (* (+ x 1) (- 2 x)) 2)))
(+ row col (f (- row 1))))
;Value: n-from-rowcol

Now all I had to do was find a way to reverse the function to give me the inputs if I gave it the output. I actually stumbled upon another number sequence (OEIS #A000124, also known as the Lazy Caterer's Sequence) which when put into the following procedure returns the correct column and row for a given element. At last, working code:



(define (pascal n)
(define (pas col row)
(cond ((= col 1) 1)
((= row 1) 1)
((= col row) 1)
(else (+ (pas (- col 1) row)
(pas (- col 1) (- row 1))))))
(define (colrow-from-n)
(define (col-iter count)
(define (f x)
(- (/ (+ (square x) x 2) 2) x))
(cond ((> (f count) n) (pas (- count 1) (- n (- (f (- count 1)) 1))))
((= (f count) n) (pas (f count) 1))
(else (col-iter (+ count 1)))))
(col-iter 1))
(colrow-from-n))
;Value: pascal

Any insights into cleaner code, better algorithms, or comparisons between the two number series are welcomed.

Still Kicking

posted on 2008-01-30 19:26:42

Okay. So, I didn't get the week 2 recap posted last Friday and I'm not getting it posted today either. Before you folks go judging me and deciding I turned into a lazy bum I thought I should make some note of progress.

As I've mentioned, SICP isn't going as fast as I hoped but I won't skip a thing. If my schedule goes out the window so be it but this book is getting finished. Of course, hopefully I can conform somewhat to the schedule as well. There will be an update this weekend even if I'm not through section 1.2.

In the meantime, I thought that I'd post up something I've been working on during my lunch hour. Namely, Project Euler code. Project Euler is a website that has about 180 Programming Problems of escalating difficult. I've only devoted one lunch hour to it so far but it's been fun and I'd love to get through a quarter to half the problems this year.

The challenge for me I think will come from the math side as well as the programming and some of these I just won't be able to solve for a while. Better to challenge myself from both ends, right? The code's hidden behind a cut for those who don't want their eyes scarred by this programming nonsense. Also, I'll be improving these as I discover better programming formalisms. I'm also solving each problem in both C and Scheme. I want to solve each problem from two paradigms (or more) if possible.

An Escher Videogame and other nerdities

posted on 2008-01-22 17:22:47

One of the games I'm most excited about coming out this year is called echochrome. It's coming out for Playstation 3 and the PSP. No US release date has been announced but it will land in Japan on March 19th. While I normally don't bother with writing about games, this one's special. It's one of the most novel concepts for a game I've seen in years. In short: you rotate a scene featuring an Impossible Object such that an automated walking man can navigate it. It's a perspective-based puzzle game. Here look:


Also, everybody is writing about CS Education lately which is awesome considering I've been thinking about it so much. Just look at all this mess:

The Enfranchised Mind article (which may be the best of the bunch) and associated reddit comments

Raganwald' No Disrespect article and associated reddit comments

and Mark Guzdial's take and associated reddit comments


It may sound like a cop-out but I think Abelson and Sussman had this right all along. We're so hopelessly early in the existence of Computer Science as a discipline that we don't have a clue what it really is yet. And when you don't know what something is, it's pretty hard to know how to present it. Or steer it's course. That's all for now.


Finally, a paper got thrown on LTU about a dependently typed version of Scheme. Very intriguing.

Software in the Real World

posted on 2008-01-10 19:28:55

I'm a bit perturbed at the moment and I'm having a hard time figuring out why but it seems to happen to me after reading Spolsky articles and their associated reddit comments. That was the last time I remember having this same sense, at any rate. The sense that I might call "Computer Science scares the shit out of me". Either that or "the real world scares the shit out of me".

But on to the Spolsky article. I read Spolsky's article "The Perils of Java Schools" and the comments from when it was posted on reddit. The article is about what it sounds like it is. Joel thinks that schools have dumbed down their CS programs by teaching Java instead of a functional language like LISP or Scheme or a low level language like C. The commenters then get into arguments about Joel being stupid, what the ONE TRUE WAY to teach Computer Science and/or programming is, the reason one set of skills or another is valuable in industry, the difference in industry's goals and academia's, and anything else they see fit to mention.

The argument in comments on these articles is often in fact a mere miscommunication. One side advocates that a good (or great) programmer is found by a seeking out those that are technically adept with things like tail-call recursion and functional programming or low-level bit-hackery and such. The other side advocates finding those that have good design principles and an understanding of architecture/best practices.

The missed point seems to be that the first side (to my thinking) presumes that their conditions ipso facto create the candidate argued for by the second side. That is, the first side thinks if someone understands tail-call recursive functions and pointers than they must have some sense of design to go with their knowledge of abstractions and that this, consequently, makes them good engineers. The second side is missing this fact and arguing that design skill is more important than technical ability. Both are large components though. I do not think Spolsky would advocate hiring programmers who had technical ability but little design skill or design skill and best practices but little technical ability.

After reading these articles however I have to step back and remember that we're talking about Computer Science or Programming both of which ultimately have in mind the creation of software or in Sussman's words a description of a process. That description (software) is supposed to automate work, to create value. And THAT is the scary part.

Computer Science scares me a little because I wonder if I have the necessary chops (and desire) to become a good programmer. It's also scary because it will take me a while to even figure out the answer to that question, probably longer than I'd like. Real life on the other hand scares me a lot more for an entirely different reason that I'll explain by way of confession.

I confess that I have an intense urge to read reddit and I find it very hard to resist. It borders on compulsion. The reason is this: I think I'm lazy. In fact, it's even more than that. I think I'm not going to make it out there. You know, in the real world. There are a few reasons for this. One, it's painted as scary and brutal by a lot of people. Two, and this is the bit about me being lazy, I think the real world is bullshit. Or at least mostly bullshit. It's people trying to find ways to stay busy so they can make money so they can eat and do things they actually care about. This next bit is important so I want to state it carefully:

It's not that I don't think that there aren't people out there getting things done that actually need doing. It's that I think that 90% of human labor is about maintaining the status quo, that maintaining the status quo is a huge waste of time if not for the fact you'd starve otherwise, and that the little last bit that actually creates new value and advances the state of things seems like accident or luck as often as the product of hard work. Moreover, there's no guarantee no matter who you are that you won't just get bad luck and get screwed. THAT is what's scary.

It's scary because I don't want to hate my job and just try to do what's necessary to make it. It's scary because I'd like to be in that little 10% and there is no guaranteed way to get there. And it's scary because the very fact of it is implicitly anti-hope or anti-progress. "90% of the world is about maintaining the world. Good luck."

I read reddit not because I want to avoid my other duties but because I wildly want to believe that somewhere on there I will find the guidance I need to not be a 90% human being. I want to be good at something, produce value, not fear starvation or unemployment, and love my craft. So far, I believe programming to be my best bet. Hopefully, this year off from college will bear that out one way or another.

Random Quote Post

posted on 2007-11-24 19:07:55

I've been stumbling across these this morning and find them all quite provocative. What do you think?

"As Navrozov explains, the word "power" in Russian means "possession" and is a cognate to the English word "wield." Since in a democracy public opinion is power and universities are the source of all legitimate opinion, they can be said in a sense to possess and wield our minds. So no one at a university should be surprised to smell the marmoset, not even in an innocent little department called "computer science," but I knew the stench from childhood and to say I was shocked would be an understatement." - Unqualified Reservations

"Of course, in a sense, anything you do with in a computer can be described as "mathematics." The point is not whether or not programming is math. The point is what notation is most effective for expressing programs. Choosing the best notation is the entire problem of programming language design, and this problem is neither mathematical nor scientific. A programming language is a user interface for programmers, and if you can reduce UI design to math, science, or any formal process, call Apple, not me." - Unqualified Reservations

Quick Quote

posted on 2007-10-04 03:05:03

This is a really good essay on complexity in software appropriately entitled Why Software Is Hard.

(The difference is that the overruns on a physical construction project are bounded. You never get to the point where you have to hammer in a nail and discover that the nail will take an estimated six months of research and development, with a high level of uncertainty. But software is fractal in complexity. If you're doing top-down design, you produce a specification that stops at some level of granularity. And you always risk discovering, come implementation time, that the module or class that was the lowest level of your specification hides untold worlds of complexity that will take as much development effort as you'd budgeted for the rest of the project combined. The only way to avoid that is to have your design go all the way down to specifying individual lines of code, in which case you aren't designing at all, you're just programming.

Fred Brooks said it twenty years ago in "No Silver Bullet" better than I can today: "The complexity of software is an essential property, not an accidental one. Hence, descriptions of a software entity that abstract away its complexity often abstract away its essence.")

I also found an interesting opinion piece/writeup on Inheritance.

More later. It's sleepy time.

Quotes on Programmers

posted on 2007-09-14 14:40:13

"15 years of experience interviewing programmers has convinced me that the best programmers all have an easy aptitude for dealing with multiple levels of abstraction simultaneously." - Joel Spolsky, The Guerilla Guide to Interviewing v3.0

"As Lyle Ramshaw, a former graduate student of Knuth's, points out, "Don claims that one of the skills that you need to be a computer scientist is the ability to work with multiple levels of abstraction simultaneously. When you're working at one level, you try and ignore the details of what's happening at the lower levels. But when you're debugging a computer program and you get some mysterious error message, it could be a failure in any of the levels below you, so you can't afford to be too compartmentalized." - Salon.com Article on The Art of Programming

"The key to being a good hacker may be to work on what you like. When I think about the great hackers I know, one thing they have in common is the extreme difficulty of making them work on anything they don't want to. I don't know if this is cause or effect; it may be both." - Paul Graham, Great Hackers

Fun stuff that maybe relates...or I've just been reading anyway:
Why You Need A Degree For Big Companies (parody)
News From The Front (Why the College you go to doesn't matter)
How To Do What You Love

Fifth Tuesday Quotables

posted on 2007-06-13 05:40:00

Dear Friends:
Sorry if I've been bad about responding to comments or e-mails for the past 24 hours or so. Today's been very busy. In fact, after this quick break to keep up my summer blog series I'm going to get back to working on something so that our servers at work will finally go up tomorrow. I'd also like to thank everyone for the tremendous response and support I got on my "Real World" post. It really did mean a lot.

"As a thirteen-year-old kid, I didn't have much more experience of the world than what I saw immediately around me. The warped little world we lived in was, I thought, the world. The world seemed cruel and boring, and I'm not sure which was worse." - Paul Graham

"As far as I can tell, the concept of the hormone-crazed teenager is coeval with suburbia. I don't think this is a coincidence. I think teenagers are driven crazy by the life they're made to lead. Teenage apprentices in the Renaissance were working dogs. Teenagers now are neurotic lapdogs. Their craziness is the craziness of the idle everywhere." - Paul Graham

"To the popular press, "hacker" means someone who breaks into computers. Among programmers it means a good programmer. But the two meanings are connected. To programmers, "hacker" connotes mastery in the most literal sense: someone who can make a computer do what he wants—whether the computer wants to or not. To add to the confusion, the noun "hack" also has two senses. It can be either a compliment or an insult. It's called a hack when you do something in an ugly way. But when you do something so clever that you somehow beat the system, that's also called a hack. The word is used more often in the former than the latter sense, probably because ugly solutions are more common than brilliant ones. Believe it or not, the two senses of "hack" are also connected. Ugly and imaginative solutions have something in common: they both break the rules. And there is a gradual continuum between rule breaking that's merely ugly (using duct tape to attach something to your bike) and rule breaking that is brilliantly imaginative (discarding Euclidean space)." - Paul Graham

"It says a great deal about our work that we use the same word for a brilliant or a horribly cheesy solution. When we cook one up we're not always 100% sure which kind it is. But as long as it has the right sort of wrongness, that's a promising sign. It's odd that people think of programming as precise and methodical. Computers are precise and methodical. Hacking is something you do with a gleeful laugh." - Paul Graham

Unless otherwise credited all material Creative Commons License by Brit Butler