(archive 'newLISPer)

October 18, 2006

Noodling around

Filed under: newLISP — newlisper @ 17:35
Tags:

Just noodling around today. Then I shall be away for a few weeks. But all I have to say is: noodles.

Would you like some source with that, sir?


#!/usr/bin/newlisp

(set 'buffer "")
(define (ps str)
 (write-line str buffer))
(define (render)
 (write-file
  (string (env "HOME") "/Desktop/noname.ps")
   (append [text]%!PS-Adobe-3.1
%%Creator: newLISP
[/text] buffer "showpage" "\r\n"))
 (exec (string "open "(env "HOME") "/Desktop/noname.ps")))

(seed (date-value)) ; randomnessity

(ps (format {gsave 0.7 setgray /Eurostile findfont
   600 scalefont setfont
   30 20 moveto (Q) show
   grestore}))

(ps (format {1 setlinecap
   10 setlinewidth
   %f %f %f setrgbcolor} 0.6 0.6 0.8))

(for (c 1 70)
 (map set '(x1 y1 x2 y2) (random (random 50 30) 300 4)) ; start and end
 (map set '(b1x b1y b2x b2y)
  (random (random 40 120) (random 60 350) 4)) ; bulgy
 (ps { newpath })
 (ps (format {1 setlinecap
  11 setlinewidth
  %f %f %f setrgbcolor} 0.7 0.7 (random 0.6 0.1))) ; back
 (ps (format {%f %f moveto} x1 y1))
 (ps (format {%f %f %f %f %f %f curveto stroke} b1x b1y b2x b2y x2 y2))
 (ps (format {1 setlinecap 9 setlinewidth %f %f %f  setrgbcolor}
  0.8 0.8 0.5)) ; middle
 (ps (format {%f %f moveto} x1 y1))
 (ps (format {%f %f %f %f %f %f curveto stroke}
  b1x b1y b2x b2y x2 y2))
 (ps (format {1 setlinecap
  8 setlinewidth %f %f %f setrgbcolor} 0.95 0.95
   (random 0.8 0.1))) ; front
 (ps (format {%f %f moveto} x1 y1))
 (ps (format {%f %f %f %f %f %f curveto stroke}
  b1x b1y b2x b2y x2 y2)))
(render)
(exit)

October 16, 2006

Lutz's Ninth

Filed under: newLISP — newlisper @ 09:52
Tags:

newLISP release 9.0 has been released, and no doubt there will be much loud rejoicing among newLISP users (which you will hear if you listen closely – the web is very noisy). There are new functions, enhancements in others, speed increases, and bug fixes. The documentation gleams in the sunlight, buffed to perfection by a team of Oregonian wordsmiths. Of course, most of us have probably been downloading the development versions, so will already be using some of the new goodies.

A last minute arrival is the ref-all function. This returns a list of every occurrence of an item in a nested list. Now I don’t usually carry around big nested lists with me, so when I require one I usually turn to my iTunes library. It’s a big XML file, but that doesn’t stop us –

(xml-type-tags nil nil nil nil)
(set 'itunes-data
    (xml-parse
        (read-file "/Users/me/Music/iTunes/iTunes Music Library.xml")
        (+ 1 2 4 8 16)))

turning it into a nested list. Now we’ll see if I’ve got any classical music in there:

(map
    (fn (i) (println (last (first (rest (member '(key "Name")
        (itunes-data (chop (chop i)))))))))
    (ref-all "Classical" itunes-data))

OK, this isn’t the most elegant code you’ve ever seen (‘chop chop’ ‽ ‘last-first-rest-member’ ‽), but the key point is that ref-all is giving me the address of every reference to the word “Classical” in my iTunes library. I don’t have to hack my way through the XML undergrowth. Output is a list of evocative titles:

...
Toccatina Op. 36
Symphony No. 2: Movement I
Symphony No. 2: Movement II
Symphony No. 2: Movement III
Interlude [Orphee - Act II, Scene 5]
Concerto for Saxophone Quartet and Orchestra: Movement I
Concerto for Saxophone Quartet and Orchestra: Movement II
Concerto for Saxophone Quartet and Orchestra: Movement III
Concerto for Saxophone Quartet and Orchestra: Movement IV
Koyaanisqatsi
Organic
Cloudscape
Resource
Vessels
Pruit Igoe
The Grid
...

But ref-all‘s economy tempted me into trying to write a one-line RSS headline newsreader, a reprehensible practice that I hope won’t encourage the playing of newLISP golf. In fact I could only get it down to three lines:

(xml-type-tags nil nil nil nil)
(set 'sxml-data (xml-parse (get-url {http://www.alh.net/newlisp/phpbb/rss.php}) (+ 1 2 4 8 16)))
(map (fn (i) (println (last (sxml-data (chop i))))) (ref-all 'title sxml-data))

newLISP Fan Club
newLISP newS :: RE: newLISP v.9.0 release
newLISP newS :: RE: newLISP v.9.0 release
newLISP newS :: RE: newLISP v.9.0 release
newLISP newS :: newLISP v.9.0 release
newLISP and/or Whatever Else :: RE: Dynamic list values
newLISP and/or Whatever Else :: RE: Dynamic list values
newLISP and/or Whatever Else :: Dynamic list values
newLISP newS :: RE: pre-release newLISP 9.0.0
newLISP newS :: RE: pre-release newLISP 9.0.0
newLISP newS :: RE: pre-release newLISP 9.0.0
newLISP newS :: RE: pre-release newLISP 9.0.0
newLISP for Win :: RE: newlisp.DLL possible?
newLISP newS :: RE: pre-release newLISP 9.0.0
newLISP for *n?x :: RE: Perhaps a dumb question
newLISP newS :: RE: pre-release newLISP 9.0.0

This is not perhaps the best way to say thank you to Lutz for another cool version of newLISP. Here’s a better way: thank you!

October 4, 2006

Agents and daemons

Filed under: newLISP — newlisper @ 08:58
Tags:

As I wrote that title, I thought for one moment that I was going to start another parody of Dan Brown (his “Angels and Demons” thriller hasn’t yet been turned into a blockbuster movie, but I think it’s in the pipeline). But no, I stopped myself just in time. In fact I’ve been trying to develop a small utility for my own purposes, and I ended up reading a technical note from Apple about agents and daemons, which had a section wonderfully entitled Daemonomicon.

Apple’s note explains the difference between agents (background applications that work on behalf of a specific user) and daemons (programs that operate system-wide, not directly for the benefit of a user). So I ended up writing an agent rather than a daemon. A pity really, because I like the idea of conjuring up Unix daemons.

I think (but I’m not much of an expert) that newLISP is a good language for writing these agents. As a language it’s small, fast, and light on its feet, yet has many useful features.

One of the jobs I wanted to do was to keep a record of all the music being played in iTunes. With a bit of AppleScript and a bit of newLISP I rustled up this little script:

#!/usr/bin/newlisp

(set 'previous-music "")

(while true
   (and
      (exec {ps x | grep [/]Applications/iTunes.app/Contents/MacOS/iTunes}) ; iTunes running?
      (set 'current-music
       (exec [text]osascript -e 'tell application "iTunes" to if
         player state is playing then get (player state & "~~~" &
         name of current track & "~~~" & artist of current track &
         "~~~" & current stream title) as Unicode text'[/text]))
      (set 'current-music
       (parse (first current-music) "~~~"))
      (= (current-music 0) "playing")        ; and playing?
      (!= previous-music current-music)      ; different track?
      (set 'the-date (date (date-value) 0 "%Y-%m-%d %H:%M:%S "))
      (if (find "SomaFM" (current-music 1))
         ; streaming
         (set 'display-string
           (string the-date
           "[SomaFM] "
           (0 12 (current-music 1))
           "... : "
           (current-music 3) "\n"))
         ; not streaming
         (set 'display-string
          (string the-date
            "[Library] "
            (current-music 1)
            ": "
            (current-music 2) "\n")))

      (append-file "/Users/me/Music/itunes-playlist" display-string)
      (set 'previous-music current-music)) ; remember this one

   ; in any case, sleep for 20 seconds before trying again
   (sleep 20000))

Notice that I’ve been listening to SomaFM internet radio recently, so I’m asking iTunes for the current stream title as well as the current track’s name and artist. If you listen to – or record :-) – streaming radio, you can get the latest song details as the songs change, even though iTunes thinks it’s just playing the same track.

I’ve used a separator of “~~~” which makes parsing the string returned from iTunes easy. And I’ve found myself using that and construct again, which pleases me strangely.

This all seems to work fine, so the one remaining question is: how do I make it launch as a background ‘agent’ whenever I log in, without a visit to the terminal? Apple have done something a bit different, here. They’ve developed a new Unix architecture for launching processes, which uses the command ‘launchd’. This is gradually replacing the old Unix standards such as rc (whatever that is), and which is also going to supersede things like cron, eventually. (In fact, if you look at the /etc/crontab file, it says that “the periodic and atrun jobs have moved to launchd jobs”. So the supersession is already under way.)

Since this is a Mac, though, you can usually avoid learning all those command-line mystic runes by using a nice friendly GUI application. For controlling your daemons and agents, all you need is Lingon, a lovely bit of programming by Peter Borg that makes all the launchd and launchctl stuff easy to use: “Launch your dreams right here” is his slogan, and all you do is show it your script and a new agent will be sent on its mission.

In use, this secret agent doesn’t look like it’s using much memory, compared with cron, for example:


               %cpu  VMem      Real mem  User  PID   CPU  #   Private    Shared   Messages
   cron        0.00  26.88 MB  504.00 KB root   76  00.01 1  136.00 KB   352.00 KB   56
   newlisp     0.00  26.93 MB  512.00 KB me   5062  00.00 1  176.00 KB   532.00 KB   62

What’s cron like for programming in?

Blog at WordPress.com.