rjbs forgot what he was saying

not logged in (root) | by date | tagcloud | help | login

rjbs's tags

-- - ?? + ++
4   80s  
4   _to_read  
1   abe.pm  
7   addex  
1   ads  
26   advice  
1   airlines  
1   algorithm  
9   amazon  
1   amber  
1   america  
1   animals  
1   aol  
43   apple  
7   applescript  
2   architecture  
1   arduino  
1   arf  
5   art  
1   assembler  
5   astronomy  
2   baby  
4   backup  
2   baking  
1   banjo  
2   barcode  
1   bash  
1   battletech  
6   beer  
2   bethlehem  
5   bible  
4   bicycle  
6   blog  
1   bonjour  
11   book  
49   books  
9   booze  
1   boston  
1   brainfuck  
1   breadmachine  
1   bryar  
1   bugzilla  
1   bus  
2   c  
1   calculator  
1   calendar  
33   campaign  
1   car  
4   cartoons  
1   cdbi  
1   cellphone  
6   chart  
1   chemistry  
14   chess  
1   china  
1   chinese  
20   christianity  
2   christmas  
1   chrome  
1   cloud  
6   cocoa  
16   code  
15   color  
9   comics  
7   compsci  
1   computers  
1   conference  
2   convention  
1   cooking  
22   cpan  
1   cricket  
2   criticism  
1   cron  
3   crossword  
4   crypto  
3   css  
11   culture  
1   cvs  
1   cygwin  
1   dad  
1   dashboard  
8   database  
2   dbi  
1   dcbpw  
1   debian  
2   debug  
8   delicious  
3   design  
2   dice  
2   dictionary  
27   distzilla  
1   diy  
79   dnd  
2   dns  
1   drawing  
4   dreamcast  
12   dreams  
1   drm  
1   dropbox  
1   dvorak  
4   ebook  
1   ebooks  
2   economics  
8   editor  
2   emacs  
67   email  
1   encoding  
4   english  
3   ergo  
1   erlang  
9   esperanto  
2   etiquette  
1   evolution  
1   exchange  
2   exercises  
1   extreme  
3   family  
1   fax  
1   fbl  
2   ff  
2   fiction  
6   firefox  
1   flags  
10   flash  
2   fletch  
1   flickr  
1   fluxx  
1   foaf  
1   folk  
11   fonts  
20   food  
5   forth  
2   forum  
1   free  
2   freesoftware  
2   friends  
1   friendship  
1   frink  
1   fud  
3   functional  
1   fundraising  
2   furniture  
8   game  
3   gameboy  
18   gamecube  
212   games  
50   gamesite  
1   gaming  
1   geography  
2   geometry  
1   german  
20   git  
1   github  
1   glasses  
1   gloria  
1   gmail  
15   go  
2   golf  
3   goof  
6   google  
9   gov  
1   groups  
11   guineapigs  
2   gun  
3   gwb  
7   haiku  
2   halo  
49   hardware  
10   haskell  
1   hate  
1   health  
1   high-st  
3   hiring  
15   history  
7   hiveminder  
1   home  
14   house  
16   howto  
7   html  
2   http  
35   humor  
1   icehouse  
2   icon  
6   icons  
4   idea  
1   ideas  
3   illusion  
16   image  
1   infocom  
11   infocom-replay  
2   inform  
17   int-fiction  
1   io  
1   ipad  
3   iphoto  
6   ipod  
5   irc  
10   itunes  
1   jargon  
2   java  
27   javascript  
4   jonstewart  
1   jott  
1245   journal  
1   jquery  
1   json  
1   karaoke  
15   keyboard  
5   keynote  
1   kinesis  
1   knave  
3   kwiki  
10   language  
2   lasertag  
2   latex  
2   latin  
6   law  
1   lazyweb  
2   lego  
2   library  
1   lighttpd  
11   linux  
4   liquidplanner  
10   lisp  
1   list  
2   literature  
7   logic  
1   logo  
2   lovecraft  
1   lua  
116   macosx  
1   magazine  
1   make  
2   management  
2   map  
4   maps  
6   mario  
1   markdown  
6   martha  
10   math  
3   mecha  
1   media  
2   memory  
1   metabase  
2   metroid  
2   mh  
1   microscopy  
1   microsoft  
1   minecraft  
1   mk  
12   mnm  
4   money  
3   moose  
2   motivation  
1   mouse  
24   movies  
3   mozilla  
1   mp3  
5   msie  
23   music  
10   mutt  
2   mysql  
1   mythology  
1   negativland  
1   nethack  
23   network  
9   networking  
8   news  
1   oauth  
2   ocaml  
3   omnifocus  
1   omniweb  
2   online  
1   ook  
1   openid  
1   oracle  
8   oscon  
1   oscon2008  
1   outliner  
7   paranoia  
2   parsing  
1   pdf  
6   pedagogy  
3   pennsylvania  
365   perl  
1   perl6  
2   perlmonks  
1   perlqa2011  
1   perlqa2012  
1   perlqa2013  
1   perlqa2014  
1   perlqah2015  
7   pets  
2   philosophy  
22   phone  
1   photos  
8   php  
1   physics  
1   piercing  
1   piet  
1   pike  
5   platformer  
1   pobox  
10   pod  
3   poetry  
11   politics  
1   porn  
1   portland  
2   postfix  
2   postgres  
2   ppw2007  
1   pr0n  
6   presentation  
1   printer  
32   productivity  
2   profiling  
1   progamming  
1   programing  
453   programming  
5   prolog  
7   ps2  
2   psx  
1   psych  
1   pvoice  
11   python  
1   qmail  
1   quality  
1   querylet  
2   quiz  
2   rant  
3   rants  
2   reading  
3   recipe  
56   reference  
1   regex  
12   religion  
7   repair  
1   replication  
1   resource  
3   rest  
18   retail  
11   review  
1   rhetoric  
1   rifts  
1   robot  
1   rpc  
124   rpg  
5   rss  
3   rtf  
1   rubik  
20   rubric  
17   ruby  
1   rugby  
1   russia  
1   rust  
6   rx  
2   safari  
1   satire  
1   scala  
2   scheme  
8   science  
1   sco  
2   screen  
2   search  
11   security  
2   sega  
3   service  
4   sh  
5   shaving  
1   sheetmusic  
2   slack  
1   slony  
2   smalltalk  
1   smoking  
1   social  
13   socialnetworking  
184   software  
1   solaris  
2   sonic  
2   space  
8   spam  
1   speech  
2   sports  
1   sql  
2   sqlite  
1   startrek  
3   starwars  
2   steelbat  
1   strategy  
68   stupid  
10   subversion  
1   sudo  
1   superhero  
3   svk  
1   switcher  
5   syntax  
1   tarot  
1   taxes  
17   testing  
1   tex  
1   thanksgiving  
1   theatre  
1   thunderbird  
7   tiddlywiki  
6   time  
5   tivo  
8   todo  
1   tolkien  
54   tool  
1   tools  
1   toys  
15   travel  
1   trek  
25   tutorial  
16   tv  
3   typing  
1   uk  
6   unicode  
9   unix  
1   usenet  
2   vcs  
1   vector  
2   vi  
10   video  
94   videogame  
14   vim  
1   virtual  
1   virtue  
2   visualization  
2   vnc  
1   vocabulary  
1   voip  
2   voting  
6   war  
1   weapons  
1   weather  
57   web  
1   webgames  
1   weight  
2   wii  
20   wiki  
1   wikipedia  
14   win32  
2   wireless  
1   wodehouse  
1   wordplay  
19   work  
3   writing  
20   wtf  
19   xbox  
1   xcode  
1   xen  
8   xml  
1   xp  
1   xslt  
2   xul  
1   yahoo  
3   yaml  
29   yapc  
1   yapcasia  
5   ywar  
4   zelda  
1   zen  
3   zombie  
1   zombies  
5   zsh  

RSS feed rjbs's entries with a body

collapse entry bodies

trust no one (body)

by rjbs, created 2015-08-14 18:06
tagged with: @markup:md journal security

At work recently moved from our own office space to a coworking space. Bryan said, "remember to lock you laptop screen when you're not using it." I said, "I use Mobile Mouse so I can lock it with a hot corner from across the room."

He asked, "How does Mobile Mouse connect?"

The importance of the question was obvious. I knew it was wi-fi, and the wi-fi is shared with the rest of the coworkers. Surely anything that can remote control my computer will be a secure connection, right? Right? The docs said nothing, so I fired up a packet sniffer.

$ sudo tcpdump -i en0  -w mouse.packet port 9090
[ connect with Mobile Mouse, mouse around a little ]
$ strings mouse.packet

What did I find? Here's a sample:

[ a bunch of base64-looking stuff; I think it's the Dock icon images ]

There's my phone's device name, the password, my laptop's name, and a bunch of other identifying information. Anybody who sniffed the network for a while could find this traffic and then remote-control my laptop when I looked away. (Or, more amusingly, when I wasn't looking away.)

I asked the makers of Mobile Mouse why they didn't use a secure connection, and whether they would. They said, "Well, it's really intended for a secure local network, but we'll think about adding this feature." Still, they link to people who review this device as a presentation remote. This sounds like a recipe for at least hilarity, if not disaster. "Hey, the consultant is presenting with his phone on the guest wi-fi. Let's sniff it!"

My point here is not that Mobile Mouse is bad software. It's really good software with this one enormous flaw. My point is that nobody really cares about protecting you except for, hopefully, you. You had better pay attention!

no wrong way to play (body)

by rjbs, created 2015-05-24 22:03
last modified 2015-05-25 19:03
tagged with: @markup:md dnd journal

I am always baffled by the neverending stream of remarks of the form, "you people are playing D&D wrong." Here's one that particularly bugged me, today:

What SlyFlourish should be saying, here, is "hurts my ability to bring in and keep new players who care about the things I care about." Some players like playing in a very fatal environment. People play all kinds of games "on hard" on purpose, even games they haven't mastered on easy. And anyway, having a lot of character death doesn't make D&D harder, it just makes it different, because you don't win in D&D. And anyway, if you want to have victory conditions in D&D, that's cool, too.

It makes me crazy to think that people are being told, "you can't bring in or maintain new players if you let beginner characters die often." There are tons of games that work this way, and succeed in growing. I know: I have run some of them. Obviously, you have to know what your players expect, and what will make them unhappy. Part of this is asking, and part of this is establishing expectations up front. I make it clear that characters in my games die a lot, and that this is not about player failure, but about the kind of game I run. We still have fun. I have also played in games where the game master has gone out of their way to prevent character death when it seemed really justified, because they felt it would make the player unhappy. I still had fun.

I'm not a big fan of D&D 3E, but I thought its Dungeon Master's Guide II was great because it talked about how to establish and maintain a game based on what the players want. That's how you make a game succeed, after all: you figure out what you all think will be fun, try it, and then iterate on that. That's why "this is bad for players" makes me crazy. It's bad for some players. Or "I don't know how to do this in a way that players will like," which is a totally okay thing to be true. There's plenty of stuff I can't do, even though players might like it, and so I avoid it, because it would be bad.

The whole thing reminds me of [an episode of Parks and Recreation]. Ron "Mustache Guy" Swanson and Leslie "Amy Poehler" Knope have competing scouting groups. Leslie's group focuses on singing songs, baking cookies, and pillow fights. Ron's group struggles to build shelter and find something to eat. He tells his scouts, "We have one activity planned: not getting killed." By the end of the episode, all the scouts in Ron's group have defected to Leslie's, because they don't think Ron's group is fun. Leslie wins, Ron loses.

There is where a lesser show would end, but Parks and Rec is better than that. Leslie takes out an ad in the paper, calling for the kinds of kids who would like Ron's kind of camp.

Are you tough as nails? Would you rather sleep on a bed of pine needles than a mattress? Do you find video games pointless and shopping malls stupid? Do you march to the beat of your own drummer? Did you make the drum yourself? If so, you just might have what it takes to be a Swanson. Pawnee's most hardcore outdoor club starts today. Boys and girls welcome.

Then, some kids show up and they are excited to become Swansons. There is more than one way to be a scout.

So, here is my advice: ask your new or potential players what they want, or tell them what to expect. Or do both. Don't give up on what you like just because someone told you it was a niche style or that you'd be unable to retain players.

perl has built-in temp files (body)

by rjbs, created 2015-05-22 11:36
last modified 2015-05-23 19:31

I use temporary files pretty often. There are a bunch of ways to do this, and File::Temp is probably the most popular. It's pretty good, but also pretty complicated. A big part of this complication is that it's meant to keep your filename around until you're done with it, and to let you pick its name and location. Often, though, I don't need these features. I just need a place to stream a whole bunch of data that I'll seek around in later, or maybe just stream back out. In other words, instead of holding a whole lot of data in memory, put it in a file.

See, if you're going to put data in a file, then close it, then ask some other program to operate on it, it almost certainly needs a name. You might open that program and pipe data into it, but it's often much easier to just give it a filename of a file on disk. If you don't need that, though, the filename is totally extraneous. In fact, it just gets in the way by making it possible to leak disk usage. A filename is a reference to storage in use, just like an open filehandle is. Just like you can leak a RAM by leaving a reference to a variable in global scope, you can leak storage by leaving a name on the filesystem. That RAM will come back when your program dies, but the storage will wait until you erase the filesystem!

On most platforms, you can't create a truly anonymous filehandle, but you can do the next best thing: you can create a named file on disk, hang on to the filehandle, and immediately unlink the name. When your program terminates, there will no longer be any reference to the data on disk, and it can be freed.

Perl even makes this easy to do:

open my $fh, '+>', undef or die "can't create anonymous storage: $!";

This creates a file in your temporary directory (either $TMPDIR or /tmp or your current directory) with a name like "PerlIO_TQ50Oh" and then immediately unlinks it. The magic comes from the use of an undefined value as the filename. That mode, +>, is nothing special. It just means "create the file, clobbering anything that's in the way, and open it read-write." Now you can write to it, seek backward, and then read from it. This feature has been there since 5.8.0! If you can't use it because of your perl version, you have my sympathy!

Of course, maybe I'm weird in being able, ever, to make do with temporary files like these. I don't think so, though. When I asked on IRC recently, whether I was missing some reason that it wasn't more common, almost every single response was, "Woah, I never heard of that feature."

Now you have!

less worse command line editing in the perl6 repl (body)

by rjbs, created 2015-05-13 09:56
last modified 2015-05-13 10:38

I've been doing more puttering about with perl6 lately. One of my chief complaints has been that the repl is pretty lousy, keyboard-wise. There's no history, so I do a lot of copy and paste, and there's no way to move left non-destructively. If you notice a typo at the beginning of your line, you're stuffed.

This isn't that surprising. Rakudo doesn't ship with a readline implementation, and that's totally reasonable. You have to install something to make it go, and the common suggestion is Linenoise. It's easy to install with Panda, the perl6 package manager. Panda is installed with rakudobrew, if you're using it. If not, you can just clone panda and follow the instructions.

After that: panda install Linenoise

I hit a couple problems getting it to work subsequent to that. Some of them are fixed. (Update: It looks like all of this has now been fixed if you use rakudobrew and install a fresh moar! tadzik++ FROGGS++) For one, it tried to load liblinenoise.so, even though OS X dynamic libraries are generally .dylib files. That's fixed in the repo, and panda installs from the repo.

On the other hand, the OS X dynamic loader needs some help getting paths right. I had to fix the installed library's identity and register a path with the MoarVM binary so that it would look for installed dynamic libraries.

For the first:

cd ~/perl6/share/perl6/site/lib
install_name_tool -id $PWD/liblinenoise.dylib liblinenoise.dylib

That sets the library file's idea of its own identity to its installed location, rather than its build location.

For the second:

install_name_tool -add_rpath $PWD $(which moar)

...which adds the cwd to the moar binary's library resolution path.

Now when I run perl6, I get a repl with somewhat working line editor. I can go back and forward in the line with ^B and ^F, and I back and forward in history with ^P and ^N. Unfortunately what I can't do is use the arrow keys. I know, I know, I should probably be avoiding them, because I'm a Vim user. Too bad, I'm used to it, except when in Vim.

Strangely enough I found that the arrow keys work under tmux. It turns out that my iTerm2 profile was set to default to "application keypad mode." Why? No idea. To turn it off, I went to Preferences → Profiles → (my default) → Keys → Load Preset… → xterm Defaults.

The simple test to see what was going on was to hit ^V then ←. If I saw \eOD, I was in keypad mode. The right thing to see was \e[D.

Now I can edit my repl entry line easily! There's also very rudimentary tab completion, but frankly I'm not much of a tab completer. I just wanted to be able to fix my typos. (I like to pretend that my typos all come from bumpy bus rides, but sadly that's just not true.)

Although I did a little bit of my own digging to figure the above out, almost all the real answers came from geekosaur++ and hoelzro++ and others on #perl6. Thanks, friends!

use disposable ramdisks! (body)

by rjbs, created 2015-05-08 10:42

Recently I wrote about my dumb CPAN metafile analyzer, and how I'd tried to keep it fast. One of the things I tried to speed it up was creating a ramdisk for all of the archive extraction. The speed boost in this case turned out to be low, but it isn't always. (Also, I inexplicably used a journaling filesystem .) When you're doing a ton of file operations, the difference between physical storage and in-memory can be huge.

It was useful for another reason, though: I was running the program on an OS X system with a case-insensitive filesystem. A few tarballs on the CPAN have case conflicts, which would cause errors in analysis. Instead of running against /tmp, I set up my program to build a case-sensitive filesystem on a ramdisk and use that. It's easy, here's the code:

use 5.20.0;
use warnings;
package Ramdisk;
use Process::Status;

sub new {
  my ($class, $mb) = @_;

  state $i = 1;

  my $dev  = $class->_mk_ramdev($mb);
  my $type = q{Case-sensitive Journaled HFS+};
  my $name = sprintf "ramdisk-%s-%05u-%u", $^T, $$, $i++;

  system(qw(diskutil eraseVolume), $type, $name, $dev)
    and die "couldn't create fs on $dev: " . Process::Status->as_string;

  my $guts = {
    root => "/Volumes/$name",
    size => $mb,
    dev  => $dev,
    pid  => $$,

  return bless $guts, $class;

sub root { $_[0]{root} }
sub size { $_[0]{size} }
sub dev  { $_[0]{dev}  }

  return unless $$ == $_[0]{pid};
  system(qw(diskutil eject), $_[0]->dev)
    and warn "couldn't unmount $_[0]{root}: " . Process::Status->as_string;

sub _mk_ramdev {
  my ($class, $mb) = @_;

  my $size_arg = $mb * 2048;
  my $dev  = `hdiutil attach -nomount ram://$size_arg`;

  chomp $dev;
  $dev =~ s/\s+\z//;

  return $dev;

So, you can call:

my $disk = Ramdisk->new(1024);

…and get an object representing a gigabyte ramdisk. Its root method tells you where it's mounted, and when the object is garbage collected, the filesystem is unmounted and the device destroyed. This means that for any code that's going to use a tempdir, you can write:

  my $ramdisk = Ramdisk->new(...);
  local $ENV{TEMPDIR} = $ramdisk->root;

There's overhead to making the ramdisk, but it's not programmer overhead, and that's the important part. All you have to do is figure out whether it's worth it.

I didn't put my ramdisk code on the CPAN, because there's already Sys-Ramdisk, which does nearly the same job. I didn't use it because I "just wrote mine" because I thought it would be faster than finding an existing solution. It's probably a better replacement for what I wrote, because it probably wasn't written in twenty minutes at a bar.

my dumb CPAN "meta analyzer" (body)

by rjbs, created 2015-04-30 00:08

Just about exactly five years ago, I wrote a goofy little program that walked through all of the CPAN and produced a CSV file telling me what was used to produce most dists. That is: it looked at the generated_by field in the META files and categorized them. Here's what the first report, from April 11, 2010, looked like:

  generator             | dists | authors | %
  ExtUtils::MakeMaker   | 7864  | 2193    | 39.49%
                        | 5273  | 2228    | 26.48%
  Module::Install       | 3149  |  465    | 15.81%
  Module::Build         | 3104  |  618    | 15.59%
  Dist::Zilla           |  475  |   64    | 2.39%
  ExtUtils::MY_Metafile |   25  |    3    | 0.13%
  __OTHER__             |   20  |    8    | 0.10%
  software              |    5  |    1    | 0.03%

Over time, I puttered around with it, but mostly I just ran it once in a while to see how things changed. (The above data is actually a truncation. The "other" category is all the generators used by fewer than 5 dists.)

Here's what the data look like for last month, only generators with at least 100 dists:

  generator                    | dists | authors | %
  ExtUtils::MakeMaker          | 10419 | 2997    | 34.27%
  Dist::Zilla                  |  6225 |  836    | 20.48%
                               |  4807 | 2299    | 15.81%
  Module::Build                |  3931 |  918    | 12.93%
  Module::Install              |  3549 |  622    | 11.67%
  __OTHER__                    |   792 |  189    | 2.61%
  Dist::Milla                  |   225 |   54    | 0.74%
  Dist::Inkt::Profile::TOBYINK |   141 |    3    | 0.46%
  The Hand of Barbie 1.0       |   106 |    1    | 0.35%
  Minilla/v2.3.0               |   104 |   55    | 0.34%
  Minilla/v2.1.1               |   103 |   46    | 0.34%

The program that generates this data is (now) pretty fast. It generates all the data for a minicpan in about fifteen minutes. Generating the above table takes a second or two.

Back in 2010, all the data went into a CSV file, but now it goes into an SQLite database. It's faster, easier to query, and can store a bunch of data that would've been a real drag to put into CSV. For example, there's a table that tells me prerequisites. I can write a pretty simple program to print a dependency tree. This can show you all kinds of stuff. For example, installing the should-be-lightweight Sub::Exporter ends up having to bring in Module::Build because constant, part of core, is also on CPAN. If you ever have to upgrade to the CPAN version, you'll find that it has a configure-time requirement on Module::Build, despite not really needing it.

Maybe we'll fix that in the next CPAN release, due this week...

The data generated isn't perfect, but it's still darn useful. It's very similar, in fact, to Adam Kennedy's old CPANDB library, which I used for similar things.

My code isn't on the CPAN yet, because it's sort of a mess. It was a gross hack for years and only now am I trying to make it sort of semi-reusable. Give it a try yourself! You can clone the CPAN-Metanalyzer GitHub repo, edit meta-gen.pl to point to your own repo, and have a look at the messy results.

I'll probably write more about some of the fun of implementing this in the next week or so. Until then, have fun!

the 2015 Perl QA Hackathon in Berlin (body)

by rjbs, created 2015-04-22 20:20
last modified 2015-04-30 15:52

I spent last week in Berlin, at the 2015 Perl QA Hackathon. This is an annual event where a group of various programmers involved with the "CPAN toolchain" and closely related projects get together, hash out future plans, write code that is hard to get written in "free time," and communicate in person the hard that is stuff to communicate over IRC and email.

I always find the QA Hackathon to be very invigorating, as I get to really dig into things that I know need work. That was the case this year, too. I was a bit slow to start, by by the last day I didn't really want to stop for food or socialization, and I spent dinner scowling at my laptop trying to run new code.

The hackathon is an invitational event, and I was fortunate to be invited and even more fortunate that my travel and lodging was covered in part by The Perl Foundation and in part by the conference sponsors, who deserve a set of big high fives: thinkproject!, amazon Development Center, STRATO AG, Booking.com, AffinityLive, Travis CI, Bluehost, GFU Cyrus AG, Evozon, infinity interactive, Neo4j, Frankfurt Perl Mongers, Perl 6 Community, Les Mongueurs de Perl, YAPC Europe Foundation, Perl Weekly, elasticsearch, LiquidWeb, DreamHost, qp procura, mongoDB, Campus Explorer

Pre-Hackathon Stuff

I arrived in Berlin ahead of time, which helped me overcome jetlag. Happily enough, I was on the same flight as David Golden, Matthew Horsfall (+1), and Tatsuhiko Miyagawa. We chatted and sat around at Newark and on the way to the hotel in Berlin. More than that, Matthew and I set up an ad hoc network on the plane and chatted using netcat. Eventually I wrote an incredibly bad file transfer tool and we swapped some code and music. It was stupid, but excellent. We vowed to do better on the way back.

Once we'd dropped our bags at the hotel, we went out for a walk around the neighborhood. We saw a still-standing hunk of the wall, considered walking to the big TV tower, and then gave up and got currywurst. It was okay. After that, we caught a train back to the hotel, checked in, and crashed for a little while.

the wall

We found a totally decent little restaurant and got some dinner. Eventually, I ended up in bed and felt pretty normal the next morning!

The next day, we did more exploring, this time seeing more of the sorts of things you're meant to see when you visit Berlin.

Brandenburg Gate

I wish we'd had more time (and, more importantly, energy) to really explore the Tiergarten. There were quite a few things listed on the map that I wanted to see, but I was barely up for the little exploration we did. In my defense, the Tiergarten is ⅔ the size of Central Park!

The hackathon got started that night with the arrival dinner. I was delighted to get goulash and spätzle. Peter Rabbitson was nonplussed. "Getting excited about spätzle is like getting excited about… grits!"

"Mmmm," I said, "grits!"

Topics of Discussion

Last year, we skipped having any long debates about how to move things forward, and I was delighted. The previous round of them, in Lancaster, had been gruelling, and I expected much worse from them this year. Instead, I ended up thinking that they were pretty much okay. I think there were a number of reasons, although chief among them, I think that there were fewer people, and most of them had more actual stake in the problems being discussed. David Golden did an excellent job keeping them on topic and moving forward.

I won't get too deep into how these went, because I know that others will do so better than I would. Neil Bowers has already written up some of the final day's discussions on the river that is CPAN.

In brief, we talked about:

  • whether, why, and how to move Test::Builder changes forward
  • what promises we want to extract from each other as maintainers of the toolchain
  • the possibility of a CPAN::Meta::Spec v3
  • how we can promote a sense of responsibility and community among CPAN authors with many downstream dependents

I felt pretty good about how these talks went, for the most part. It remains to be seen how the planned actions pan out, but I'm hopeful on all fronts.

I'm going to throw in one negative thing, though, which came up not just during the big meetings, but all the time.

I get it. People have feelings about a written and enforceable code of conduct. They might feel uncomfortable that they'll accidentally get themselves kicked out, or they might resent it, or all kinds of other things. In reality, though, a conference's code of conduct only comes up in three situations:

  1. when you have to accept it to attend
  2. when someone actually behaves very badly
  3. when endless trivializing jokes are made about it

If everybody would shut up about it, and just take to heart that technical conferences are places that should be free of abuse and harrassment, I think things like a written code of conduct would be generally unnoticed except by people in need of relief for actually being abused. Instead, there constant jokes about anyone making a comment with an unintended double meaning. "Hey, you're violating my cock!" Yes, phrased like that, because I guess it's hilarious that "code of conduct" acronymizes to sound like a slang phrase for a penis.

It's gross, without even being funny to make up for it.

Dist::Zilla Hacking

I actually try not to spend too much time on Dist::Zilla stuff at the QA Hackathon. I don't think of it as part of the toolchain, precisely, and to me it's very much a personal project that some other people happen to like. "Seriously," I say, "you can use it, and it's great, but it's not making you any real guarantees. Check its work!" So, using time at the QA hackathon seems a bit disingenuous.

This year, though, I planned to spend a day on dealing with its backlog, because there were quite a few things where I felt that toolchain and QA things could be helped. As it turned out, though, very little actually went through.

I merged David Golden's work to make release_status plugin-driven. This is in furtherance of implementing a hands-off semver-like setup. Hopefully we'll see something new on that front in the future. That was a couple minutes of work re-reading code I'd already reviewed.

Most of the dzil time that I spent was on making it possible to build your to-be-released dist with one perl but then test it with another one. This was suggested by Olivier Mengué when I half-jokingly suggested bumping the minimum perl version for Dist::Zilla to 5.20. Someone said it would interfere with Travis CI testing, and Olivier said, "what if you could test with a perl other than $^X?"

I implemented it, and also the ability to set a built environment (for things like PERL5LIB) and it worked. The only problem was that … well, I just didn't feel like it was the right way forward.

If you want to test with five perls, you'll still have to run the whole building workflow five times, because of how Dist::Zilla works. I see a way out of that, but it wasn't a good project for a single day of unplanned work. It turned out that there were a few problems like this. It ended up feeling like a good idea that just didn't pan out. I'll probably leave the branch around, though. It might be useful eventually anyway. Maybe I could use it to use a new perl to "cross-compile" for deployment on an older environment, like at work.

PAUSE hacking

Most of my time, as seems traditional at this point, was spent on PAUSE. I went into the hackathon with one big goal: I wanted to get PAUSE running on Plack. Until now, PAUSE has been running on mod_perl. All other potential objections to mod_perl aside, there's a problem: it means that testing the PAUSE website requires a running mod_perl (and, thus, Apache) instance. What a pain!

I'd really wanted to work on this, and every once in a while I would have a look at the code and think about how I'd do it, but never very hard. When I finally sat down to do the work, I started to think that it was going to be a nightmare. I didn't think I could get it done in time. I despaired. I said, "I think we should look at just starting over, but I know that's usually a terrible idea." There was some agreement that I might be right from other attendees.

Then, this happened:

Amazing! Now, "he has it" may have been a mild overstatement, but not really. He showed me the site working right there on the second day. Charsbar just needed to keep hacking at the details. By the end of the fourth day, it was live! You can log in and upload to pause2!

Speaking of logging in, that's where I made my first actual bit of progress. PAUSE passwords have long been crypted with crypt, meaning the long-obsolete DES algorithm. I'd been meaning for quite a while to switch it over to bcrypt. The commits to switch PAUSE to bcrypt took a few goes, but it got done. To get your password rehashed, you just need to log in. If you've uploaded since the weekend, you've already been rehashed!

I fixed recursive symlinks killing reindexing.

Andreas König and I looked into the strange way that perl-5.18.4 still showed up in the CPAN index for things that perl-5.20.2 should've owned. This led to two small changes: we fixed bizarre error messages that appeared when you couldn't get your Foo module indexed because of somebody else's Bar.pm file; we allowed versions with underscores to be indexed if (and only if) the module was only available through perl, and was found in the latest perl release. This shouldn't really happen, but when it does, better to index than to not!

I did a lot of work, through all this, on improving the TestPAUSE library that's used to test the indexer. It makes it almost trivial to test the indexer. You can write code like this:

It starts a brand new PAUSE, uploads a file, indexes all the recent uploads, and gives you a "result" object that can do things like tell you what mail was sent, what's in the various index files, what's in the database, what got written to the logs, and what's in the PAUSE-data git repository.

It was really worth working on, in part because it let me write the (still under development) build-fresh-cpan tool. This tool takes a list of cpanid/dist pairs and uploads them to a new fake CPAN, indexing them as often as you specify. It's great for seeing what the indexer would do on a dist you haven't uploaded, or after a potential bugfix. I've been looking at using it to do a historical replay of subsets of the CPAN. It's clearly going to be useful for testing improvements to the indexer over time.

I've still got a few tasks left over that I'd like to get to, including warnings to users who don't have license or metafile data. I'd also like to implement the "fast deletion" feature to let you delete files from your CPAN directory sooner than three days from now — and charsbar's Plackification work should make that so much easier!


A few years after I published Dist::Zilla, I wanted to see how many indexed distributions had been built by it. I wrote a really crummy script using David Golden's excellent CPAN::Visitor to crawl through all of the CPAN and report on what seemed to have been used to build the dist. Every once in a while, I'd re-run the script to get newer data, occasionally making a small improvement to the code.

The big problem, though, was its speed. It took hours to run. This was, in part, because it ran in strict series. I'd tried to parallelize it one night, but it was a half-hearted attempt, and it didn't quite work. At the QAH, though, a task came up for which it was going to be well-suited. The gang voted to begin requiring a META file of some sort for indexing, and I wanted to see how many dists already had one, and of what kind. My script would provide this! I got it running in parallel, taking it down to about 90 minutes of runtime. David Golden remarked that he'd just been writing something similar, and had it running in about 75 minutes.

It was on!

We both worked on our code off and on while solving other problems, trading bug reports and optimizations. Maybe it wasn't very cutthroat, but I felt motivated to improve the code more and more. Last I checked, we both had our indexers gathering tons more information and running (across the whole of the CPAN index) in fifteen minutes.

I'm pretty sure we can both get it faster, yet, too.

I have my CPAN-Metanalyzer, in very rough form, up on GitHub. I'll probably keep working on it, though, and use it instead of CPANDB in the ancient code I once had using that.


Early on, Miyagawa asked whether we could provide structured data from CPAN::Meta::Requirements objects. These are the things that tell you what versions of what modules your code needs to be tested, built, run, and so on. You could only get the string form out, leading to re-parsing stuff like >= 4.2, < 5, != 4.4, which is a big drag. I suggested an API and that maybe I could do it the next day. The next day...

The API was even exactly what I'd suggested. Woah!

I also found some really weird-o problems. I had my meta-analyzer looking for valid or invalid META.json files, and I found an extremely high number of bogus ones. Why? Well, there were two common cases:

What?! I still have no idea where this came from, and I couldn't produce this behavior by re-testing old releases of JSON::PP. There was no report of behavior like this in changelogs. I don't know!

Part of the problem is that you can't tell from a dist just which JSON emitter was used to make its META.json. I've got a trial release of CPAN-Meta that adds an x_serialization_backend to store this data. Too bad I didn't think of this nine months ago! (Most or many of these errors, if not all, were in September 2014.) Hopefully that will go into production in about a week.

The Trip Home

After the end of the QAH, we got dinner and went back to the hotel. We tried to go to the conference space (betahaus in Berlin) but it was locked up with some of our hackers still inside. This had actually happened to me one night: without somebody with keys around, you could get stuck inside. I'm told that some people had to jump the fence. I was luckier than that.

At the hotel we sat around, talked about what we'd gotten done, and I did just a little more coding on my CPAN crawler. Eventually, though, I got to bed so that I could get up bright and early for the flight home. We left the hotel around seven.

I didn't really try to sleep on the plane. Instead, I poked at code that I could think about with my sleep-deprived brain. I ran an ngircd IRC daemon on my laptop and chatted with some fellow travelers. I watched the entire Back to the Future trilogy. It was a decent flight. (Except for lunch. Lunch was really lousy.) Only yesterday, I found out that there's been a sudden crackdown on people doing suspicious computer things on the plane. "Look out for plane hackers!" I can only imagine what would've happened if we had, as I considered doing, set up Mumble to voice chat during the flight.

Now that I'm home, I've got plenty of other stuff to catch up on, but I'm trying to keep my momentum going. I've got plenty of my usual post-QAH energy, and a fair number of remaining things to do, and I think I can actually do them.

We don't yet know where QAH 2016 will be, but I hope to make it there!

checkpoint charlie

Q&A with Larry Wall (body)

by rjbs, created 2015-04-08 21:48
tagged with: @markup:md journal perl yapc

At the Perl conference, YAPC::NA, there will be a ninety minute question and answer session with Larry Wall.

Larry Wall is the creator of Perl, rn, patch, and other revolutionary monstrosities. He's smart, funny, and full of interesting things to say. I will be acting as host, asking him questions. My goal is to have great questions that coax the most interesting answers possible out of him.

You can help!

If you've got a topic or question you'd like asked, file an GitHub issue or comment on an existing issue. If you'd rather I keep your amazing question close to my chest, or if you don't want to use GitHub, you can send me an email at rjbs@cpan.org.

notes on drawing programming for children (body)

by rjbs, created 2015-03-21 23:10
tagged with: @markup:md journal programming

Once in a while, my daughter asks me to teach her programming. We've done a number of little things together, including some Python, some Scratch, and other things. When I was trying to think of what I enjoyed doing with computers around that age, one of the things I remembered was drawing. We did turtle graphics with Logo in my school, and it was nice to get instant and visual feedback of what the program did. I thought this seemed like a fun idea.

I had looked at using Scratch for this, but it didn't seem likely to work out. Scratch is neat, in some ways, but terribly limited in others. I decided we'd stick to Logo. I downloaded ACSLogo, the only gratis OS X implementation of Logo I could find. At first, it went well. We drew some stuff. She drew a vampire girl.

vampire girl

I wanted, next, to show her how to do some of the more commonly-seen tricks, like rotated squares making a flower. This is simple: you define a function and call it in a loop. Then I realized that ACSLogo had neither of these things. Or, worse, it had functions, but they weren't defined in the program text. You have to bring up an inspector pane, edit them across several different GUI widgets... it's a mess.

Fine, I said, forget it. There are other languages specialized for drawing stuff! I decided to teach her PostScript. We'd already played with RPN calculators, so we were halfway there, right? She was a natural. I showed her this little box-drawer:

    250 225 moveto 275 225 lineto
    275 200 lineto 250 200 lineto
    250 225 lineto

...and she said "moveto, and lineto, but don't use goto!" I don't even know where she picked this up. Kids these days!

Anyway, she drew a skull, and it was awesome:

vampire girl

Those three squares were going to be a lesson. After we did one square, we could turn it into a square subroutine! Only as I began to say this out loud did I remember that like only the most backward of languages, PostScript routines did not have parameter lists. This is pretty obvious, of course, but I hadn't thought of it until I got there.

A routine to compute a²+b² would look something like:

/sum2sq { dup mul swap dup mul add }

If you wanted to actually get "a" and "b" to use, you'd write something like (and please forgive the fact that I will get this wrong, probably):

/sum2sq {
  2 dict
  /b exch def
  /a exch def
  a a mul
  b b mul

So, you declare that the next two definitions are local, then you define named routines that return the values you've popped off the stack, in reverse order, of course... this is not something you want to bother teaching a second-grader who just wants to draw a cool skull.

(It gets a lot worse, if you care about the program, actually. The above program re-alloctes a new local dictionary every time you call the routine. In reality, you'd want to move that definition outside the routine, then swap the routine's definition in and out of the dictionary stack. But then it isn't re-entrant! This gets easier if you're using Level-2 PostScript, but my reference is only for the original version with no garbage collection.)


I seriously considered writing a PostScript preprocessor to allow for something like:

/sum2sq(a b) { ... }

...but this was bordering on madness. PostScript has so many other drawbacks to begin with that I took this as a sign.

I looked for another version of Logo, found one, bought it, and found that it, too, had no procedure definition. I got a refund. Thanks, Apple Store!

Finally, I learned that Python's Tk system comes with turtle graphics. We'd already done some Python, so this was familiar! It was a lot easier to work with, we could write named functions, and the kid was pleased that TextMate had good syntax highlighting for it. She made the long-overdue flower:

vampire girl

Next up, I'd like to make it easier for her to run the program without a bunch of terminal nonsense and "hit a key to continue" stuff. Still, so far so good. She tells me that when she gets older, she'll be a better programmer than I am, because her programs "won't have bugs."

Ah, innocence!

RPG Recap: Beyond the Temple of the Abyss, 2015-03-14 (body)

by rjbs, created 2015-03-14 22:28

Saturday, 4th day of the Frost Moon, 937

Knash, Brenda, Mumford, and Wim — their host — connected the party's scrying screen to the village's antenna, and Wim got in touch with his superior: an androgynous floating head. Wim gave the head a quick summary of his situation, and they agreed that the likely solution would be to enact "the contingency plan." The head said it would communicate again in twelve hours.

Wim didn't really know what the contingency plan was, when asked. He just figured it would be something very likely fatal to the "atheist" who'd been hanged in the village center. He started packing up, and told the party they might want to do some looting.

The party did loot, loading up on food, dry goods, and a few expensive knick-knacks. They finally found a use for the heavy rainbow-colored coins they'd been carrying: a building in the village housed a machine that would process the coins into anything, it seemed, that could fit in its output space. They conjured up explosives, a magical staff, and healing potions.

They raided the library, and found a catalog listing numerous hard to find arcane librams (Hebram's Thesis on Abdesius' Commonplace Book, for example!) but almost all the books had been destroyed by Halewin, the hanged man. All that was left were some novels: Sense and Centurions, To Love a Wizard, Finnegan's Wake, The Cyborg's Lament, and other works of no interest to the adventurers.

In the library, and indeed all through the town, they found lifelike statues in various states of horror or surprise. Wim confirmed that these were the former villagers, turned to stone by Halewin's gaze.

While looking at the village graveyard, outside its walls, the gang saw that the scrying screen was pulsing, and fetch Wim. Wim came to communicate, but the call wasn't the floating head, but one of the goblins who'd expected the party to show up and fight the vampire. While he laid into the party, though, the floating head did contact Wim. With Wim out of the village, the plan was ready to be enacted immediately. The presence of other humans in the village didn't sway the head.

A dome of blue light began to form over the village walls, and the party members inside them hightailed it to, and over, the fence, while the horses struggled to make it to the gates, spurred on by bowshots from across the fence. Only Burdoc the cook, already weakened by an accident the previous day, didn't make it.

The contingency plan seemed to involve deploying a lumbering metal death machine, which emerged from beneath a pile of stones and engaged Halewin with powerful blasts of energy. Halewin was injured, but survived. The horses made it to the gate, but by then the dome blocked all but a few feed of the exit. Knash, then Rago, made daring rolls back and forth under the dome to salvage the party's bags. Quite a bit was left behind, but the most important things were saved.

A massive explosion occurred within the dome, and as the group regathered to decide how to proceed, it collapsed, and movement within suggested that Halewin had survived. The party fled east.

why I'm not sold on YubiKey OTP (body)

by rjbs, created 2015-03-07 14:19
last modified 2015-03-07 16:59
tagged with: @markup:md journal

[ update: I added a bit of an update at the end, in which I find that my fundamental worries were wrong, because the system is less convenient than I hoped! So it goes. ☹ I decided to post this anyway, because the thoughts were worth thinking, so maybe somebody else will find them interesting to see. Or not. Who even reads this thing? ]

Lots of people and sites now urge (or even require) you to set up two-factor authentication. This usually means something that emulates those old LCD RSA SecurID key fobs you used to see on the university administrators' keyrings, if you attended my college when I was there. (Have we met?) The idea here is, in part, that even if someone intercepts your login once, they will no longer be able to use it later. You may have one password (probably "kittens" or "123456") that you use over and over, but the other password — the second factor — can only be used once.

There's more going on here, but I think this is a safe simplification.

In reality, most sites use TOTP, so the password is valid many times, but only within a small window, usually between 30 and 90 seconds. A man-in-the-middle attack can get the full set of credentials, but they're only valid within a small period of time, so they can't be held in escrow for a delayed attack.

TOTP is built on top of HOTP, in which there's a counter that's incremented with each use. TOTP just replaces the incrementing counter with a timestamp. Otherwise, HOTP can be a bit trickier to use: the verifier needs to know the counter being verified, or at least the minimum counter not previously seen, to prevent replay attacks. TOTP just replaces the counter with the current time. Both are built on a shared secret which is shared only between the remote server and the user.

The hassle of TOTP, to once again grossly oversimplify, is that we tend to use a device other than our computer to store the shared secret. We put it on our phone, or a little keyfob, or the like. When we log in, we need to look at that, slide to unlock, find the site in a list, and then type in the six digits onto the web page. This is why we're often quick to click "trust this computer for a month."

A YubiKey is a little USB HID device that will enter your OTP for you. When you tap it, it emits a string of characters (because it's pretending to be a keyboard) and then enter. Those characters are your one-time password. You don't need to unlock your phone, swipe things, or any of that. You just tap your USB port. Great!

Now, there are complications. Since your YubiKey doesn't know what site you're logging into, it needs to use a single secret. It doesn't have a clock, so it uses (something analagous to) HOTP. Remember that when you're using counter-mode OTP like HOTP, you need to know the minimum unused counter to prevent replay attacks. To allow sites to synchronize their "last seen counter" data, there's a "YubiCloud" server. They way you're expected to verify an OTP string is to send it to this server, which will reply with a yea/nay. If the OTP is cryptographically valid, but for an already-validated counter, it will be rejected. Once you've verified the OTP, you can't use it again. This is secure.

The problem is that not everybody wants to use a server run by some third party as part of their system. This is a pretty understandable desire, and it can be met: there are several implementations of verification servers that one can run to do local verification without talking to the cloud. You can run your own server, and if YubiCloud is down, you can still verify. You can also feel secure that if YubiCloud's logs are leaked, no one will learn the usage pattern of your users.

See, your users could be identified, more or less, from those logs. Because your YubiKey device has a single secret, your "user id" is visible across all the sites where you use it.

So, now we've got a world where many sites are running their own local verification servers. This creates a new problem: they are not synchronizing their "last seen counter" data. Imagine that a user has accounts with two different services, A and B. They log into A every day and into B rarely.

If site A is compromised, the OTPs used to log into it can be held in escrow to be used against B later. The fact that they have been verified already won't matter, because A and B do not synchronize their last seen counter data. If, like many users, this user is using the same email address and password, then there is nearly no security present. (Remember, everybody: don't use the same password everywhere.)

As more sites run their own YubiKey OTP, the threat of having your OTP held in escrow increases. The precomputed attack on TOTP isn't mitigated by avoiding counters. It's avoided by having shared secrets on a per server basis.

I haven't performed a very careful reading of the specifications involved here, but from what I can tell, my concerns are warranted. I would be delighted to hear that I am mistaken. I don't think that this is a critical exploit that makes the whole system worthless, but I do think it indicates that per-server-secret TOTP is more secure than YubiKey. Of course, it's also less convenient. Isn't that always the way?

YubiKey devices now also support FIDO U2F. That's based on private key cryptography. The server issues a random challenge which the attacker must sign, so playback is of negligible use, given challenges over a large enough space. There's more to it than this, but it seems clearly to be a more secure system. Unfortunately, it's also more complex for services to implement. Isn't that always the way, too?

[update] I think what I'm finding is that since a YubiKey validation server is acting as a key escrow, you can't actually use one key against more than one server. You need to pick which one server you'll work against. This swings things back towards secure, but away from convenient. I will continue looking for documentation on the subject.

RPG Recap: Beyond the Temple of the Abyss, 2015-02-28 (body)

by rjbs, created 2015-03-06 20:42

Friday, 3rd day of the Frost Moon, 937

After a strange and gloomy day spent creeping through the elven woods, Argo had led the party to a clearing in which a small village stood. He fled, promising to return, but nobody believe that for a second. As night fell, they headed in without him.

They neared the gates and Brenda and Rago opened them and went inside. The place seemed deserted, although not ruined by any means. As the party moved forward, they were suddenly surrounded by a pack of stray dogs. They quickly put them down with minimal injuries, although Rago suffered a few broken ribs.

Through they melee, they'd been slowly approached by two torch-bearing men who were cirling the town's wall from the east. They claimed to be devotees of Ibrim, although they were a bit muddy on any details whatsoever. Knash interrogated the clerics, and a villager appeared from behind a building, carrying a dim red torch. He asked whether the group was entirely human, and when assured (especially about Brenda the Greenish), told everyone they could stay the night. He led them through the deserted street, past an occupied gallows. "Don't touch the hanged man," he said, the only instruction he gave. He left them at a small guest house. The group went inside, turned on the space heater, and got their first tolerable night's sleep in days.

Saturday, 4th day of the Frost Moon, 937

In the morning, the party made a slow circuit of the village. They saw a small bakehouse with a pile of many-colored logs beside it. There were several small houses, seemingly unoccupied; a reinforced and especially warm building; a few buildings burned to the ground to differing extents; a big pile of stones; a spiraling metal structure; a closed-up stable; and the large, high building in the middle of the town, where the gallows stood.

The man in the gallows (later identified as "Halewin") looked fresh, based on the pink flesh of his chest. His shirt had been pulled up over his head and tied to the noose. The party left him alone.

Eventually, their circuit completed, a few went into the bakehouse and there found their host, making bread, which he shared. He said that things were difficult because he was unable to contact his superiors, due to damage to their communication equipment. Knash suggested that the group could help, and the host was dismissive until he was shown that the party had a scrying screen. He immediately asked to use it, and he and Knash went off to connect it to the rest of the village equipment while the rest of the party enjoyed some fresh bread.

my "syntax highlighting as RTF" code is now on the CPAN (body)

by rjbs, created 2015-02-20 20:04
last modified 2015-02-20 20:07

In 2007, I wrote code to generate RTF that syntax highlights code, using Vim's syntax highlighting. I wrote about it in an earlier post or two. After that, I didn't think about it much, apart from fixing a couple things once in a while or running it once every year or so.

Earlier this week, David Golden tweeted a link to Joshua Timberman's blog, in which he was using a different tool, called highlight, for the same purpose: getting highlighted code into Keynote slides. He sounded pretty excited about it, so I thought maybe somebody would be excited about my program. (Over time, I've come to really appreciate having the same highlighting on my slides as in my editor!)

Rather than point at my GitHub repository in a tweet or something, I decided to make a proper CPAN release, which meant improving the code a fair bit and writing at least a very thin bit of documentation.

I've now released RTF::VimColor on the CPAN. You can install it and you end up with synrtf, a program that reads source code from a file and prints out RTF. You can (as Joshua points out) do something like:

synrtf lib/Awesome/Code.pm | pbcopy

...and then paste it into Keynote. Or whatever! Use it for printable code listings! Or do other cool stuff! Just have fun!

RPG Recap: Beyond the Temple of the Abyss, 2015-02-14 (body)

by rjbs, created 2015-02-15 12:05
last modified 2015-02-15 12:21

This guest entry written by Breno, Rago's player, who deserves great praise for doing so!


  • Brenda the Fighter (PC)
  • Rago the Barbarian (PC)
  • Perrin the Hunter (PC)
  • Knash Wiggl'Pops the Unseen (PC, player absent)
  • Hoyte the Soldier (hireling)
  • Dera the Sword (hireling)
  • Clem the Carrier (hireling)
  • Oresta the Healer (hireling)
  • Tucky the Page (hireling)
  • Burdoc the Cook (hireling)

After the plant-zombies fight, the party was really beat. Knash, having turned back into a human after reading his monster-morphing secret scroll, was completely unconscious but looked okay, just sleeping. Hoyte was convinced his fatal wounds were just a minor scratch, and had Oresta — our appointed school nurse — try and bandage it for him. Perrin, who was being carried away by a giant vine while also unconscious, was was slapped awake by Rago and was okay except for a broken left hand.

Perrin led the group away from that damned place to find safer grounds for some R&R. Knash was put on the cart and slept for the entire trip. Nightfall came as Perrin found us a nice-enough spot just outside the main road. We buried Hoyte (who was dead by now) and Rago and Brenda stood watch while the others rested.

Brenda's shift had barely started when she saw something moving up the forest canopy. She woke Rago — who can't see anything anyway but stood guard on the ground — put on her gear and went up to investigate.

As she got closer, she saw some spider webs and decided to burn them. Because she's the kind of bad-ass fighter who climbs trees holding a torch.

you know, kinda like this:


Meanwhile, down below, Rago heard some movement on the ground close to the party's cart, right where Hoyte had been buried. Axe in hand, the barbarian went to check it out. As he approached the site, he saw a horse-sized spider carrying a sleeping Burdoc off to who knows where. "Spider!", Rago belted as he charged to aid the poor cook. Brenda starts to climb down, and the spider is already too far away for Rago to reach with his axe. In a swift movement, he holsters his axe, picks up and throws a dagger which lands right in one of the spider's eyes. The beast shrieks in pain, drops Burdoc and climbs back to the canopy, away from everyone's sight. Brenda, now back with the party, throws a flaming arrow in the general direction of the spider and, although missing, is able to see some shadowy humanoid figures up in the trees, as if they were watching the whole thing. Could they be the wood elves?

As the group stands dumbfounded, a tiny man approaches from the road. Not very tall, terrible looking, with a giant beard and a crazy look in his eyes. He's barely naked except for some rags, and he's carrying a stick and a lantern attached to whatever he's using as a belt. He pokes everybody with a stick "to make sure you're real", and looks surprised when he realizes we are.

He presents himself as Argo Fallowel, sole survivor of the "Fallowel's Mysterious Menagerie", a caravan that was passing these woods and had... trouble.

  • "do they know you are here yet?"
  • "they?"
  • "it's them who owns these woods, you know."

He offers to help the party find a way out these woods through the east if we agree to have him tag along, since he needs a cart to carry his things and his caravan is in no condition to move. "But we're not lost!", says Rago. He looks down and smirks "Aren't you, really?".

We follow him and eventually reach a clearing. The caravan is indeed in pretty bad shape, its wagons rotten and eaten by the wood. Looks like Argo had stayed in this woods for way longer than he thinks - at least 3 years after Brenda's inquiry - but refuses to accept it. He says he'll be ready shortly, picks up a shovel and starts to dig behind one of the wagons.

Aside from the wagons, the party sees a huge glass box, with a humanoid shape inside, sitting on a chair in front of a table. We hear a ticking coming from a box that, on further inspection, reads "the next show will begin in 6492 minutes". Brenda removes some branches from within it, and the gears start moving quickly down to only 6 minutes.

  • "Um... Argo? What is this... show?"
  • "The amazing thinking corpse. He has a mind, a will, and cannot die."
  • "Don't you want to come and watch?"
  • "I've seen it."

As we approach two minutes left, we can feel a gentle vibration on the ground. Warm yellow light fills the place.


The figure on the chair rises. It looks like a person made of stone, metal and wood, and we get the impression that at some point there had even been flesh on it. It gesticulates, moves, bows. Then it looks at Perrin and makes a sound that could be a question. There's a lot of distortion on the sound. Perrin shrugs and it shrugs back at him. It looks like its eye sockets are starting to grow moist, some tissue forming, maybe. The creature continues moving to the cabinet, opens a drawer, pulls out three balls, looks as if its going to juggle them, but they are so rotten they just crack and fall on the ground. It looks at Rago and makes another question-like noise. Rago just stares back at it through the glass. It goes back to the cabinet, picks a knife and starts to do some fairly impressive knife play. Finally, it looks at Brenda, who makes a "no" motion with her head. It holds up one finger and the artificial voice comes up again. The creature grabs a pistol from the cabinet, opens the breech to show us the rounds, then holds the weapon to its temple and pulls the trigger. The creature falls, barren curtain-hooks close, box now reads "next show in 90 minutes".

The party doesn't really know what to make of it. Rago tries to break the glass to retrieve the pistol but his axe does almost no damage to the giant box.

Argo puts a closed chest in the party's wagon, and attaches a tapestry to it, containing a bunch of circus-like labels and titles, likely from his late friends. "I've seen the village at the east end, but I didn't trust them to help me", he says, claiming that as the party's way out. The party decides to follow through and see where the weird-eyed Tom Bombadil will lead them.

"We agree this is east, right?" says Argo. Perrin nods but has really no idea. The group follow the route for a few hours, occasionally looking up to check the tree canopies. Nothing. Suddenly, Argo asks us to stop. He says he forgot something and needs to go back to get it. If we keep on walking for about half an hour, we'll reach the village. He asks us to wait outside the village for him and runs back the trail. Perrin decides to follow him for a bit, but just as he comes to a fork on the road, a 3-foot long arrow hits the ground right in front of him, a clear warning from above the trees not to pursue Argo. Meanwhile, Brenda and Rago open Argo's wooden chest, only to find a bunch of lead coins, otherwise identical to real gold, silver, and copper ones. Once Perrin comes back, the party decides to keep going.

We reach the end of the woods and enter a clearing, where we can see at a distance two burning torches and a fence.

the gate?

todo for 2015? (body)

by rjbs, created 2015-01-16 22:35
tagged with: @markup:md journal

I wrote a todo for 2014, which I probably stopped thinking about roughly two weeks after writing it. Here's a summary:

  • write more prose and/or poetry: BARELY
  • write a Cocoa application: FAIL
  • write more programs for fun: DUNNO
  • spend more time with friends: FAIL
  • get my driver's license: FAIL
  • cook and bake more often: FAIL


I perennially fail at these things, with rare exceptions. I still think it's worth making a short list, but maybe, then, I should be forced to re-read it every week and write down what kind of progress I've made.

Here we go, I'll keep it brief:

  • write more
  • write some non-trivial programs in other languages
  • get my driver's license
  • read more (on Goodreads, I said I'd try to read 50 books in 2015)
  • work through my enormous backlog of games in my Steam library
  • get some home improvements done

That's it. I will attempt to report progress regularly, at least to myself.

The Great Infocom Replay: Planetfall (body)

by rjbs, created 2015-01-09 09:12

I am a lousy record keeper. I actually played Planetfall quite a while ago. August, if my filesystem is to be trusted! The problem is that I played it pretty hard, and tried to get to the end, but eventually I gave up. I knew I wasn't too far from the end, but I just didn't have it in me to work my way to the end. It's the same as with Starcross, actually! And, as with Starcross, I kept deluding myself with the idae that I'd really finish it, maybe by finding a walkthrough. I didn't.

I guess, in the end, there's less fun in using a walkthrough than in just giving up.

I was mostly really happy with Planetfall, though. The world was interesting, a number of the puzzles were fun, and it seemed to be on the better end of the spectrum so far… but the thing that everybody complains about is what I am going to complain about: the "you have to eat and sleep" problem. I'm not opposed to a time management problem. I really enjoy Pikmin, and I just love Suspended, but the basic "you have to eat or you will die" problem is just too frustrating and not at all fun. I'm not sure exactly why, but I think it's because it boils down to this: Your problem is to find a food object. If you don't find it, you die, and your last saved state might be useless.

It's like "find the key," except it doesn't open a door to a new area. It just lets you keep playing. And if you were X moves from the food and you saved the game with X-N turns left to live, your save is never going to be in a winnable state.

There are some patches you can apply to the game file to eliminate the hunger and sleep issues, and maybe someday I'll go back and apply them and try again, but eventually I just gave up on this one. Despite my long-lasting love of interactive fiction, I think I'm going to finally have to admit, at some point, that I don't really like puzzles. Or: I like the idea of puzzles, but most of the time, I get frustrated with them, in these sorts of games.

Good things in Planetfall:

  • the setting is interesting, including its backstory
  • Floyd, of course, although I don't think of him in as glowing terms as some do
  • the mystery of how to even win the game; can you escape? call help? fix the planet's problems?

Bad things in Planetfall:

  • starving to death, passing out
  • waiting for the elevator
  • the incredibly hateful "get the keycard from Floyd" puzzle
  • verb guessing

Next up is Enchanter. I've never played the Enchanter series!

I got an Xbox One (part one?) (body)

by rjbs, created 2014-12-31 23:28

I decided quite a while ago that I'd use some of my American Express reward points to buy a next-generation console, eventually. Once the intervals between my compulsive price-checking and review-reading grew short enough, I placed an order. This Tuesday, I received:

  • an Xbox One
  • a Kinect
  • download codes for:
    • Assassin's Creed: Black Flag
    • Assassin's Creed Unity
    • Dance Central Spotlight
  • Sunset Overdrive
  • Watch Dogs

I set it up, which was no problem, and then I started to use it. So far, it has been… a mixed thing.

I've played a bunch of Watch Dogs and some Sunset Overdrive. They are good. They are great-looking and impressive. If I have complaints about them, they'll come another time. I got the Xbone to play them, and that's fine. For everything else, though…

The Xbone UI is just a complete and utter mess. It is nearly incomprehensible, and I don't understand how anybody can use it without thinking so. The Xbox 360's navigation is strictly hierarchical, and the B button pretty much always moves back up one level of the hierarchy. Geting from one place to another is pretty easy no matter where you are.

On Xbone, the B button is more like a brower's "back." It goes to where you were last, even if that was in some other application. Even if it was as another user. At one point, the home screen was showing, in my color scheme, with a panel of apps in use by my daughter was shown in the picture-in-picture of "last active app." What? Is there more than one active login at once?

The only way to get to somewhere else reliably is to hit the home button… except even that's not so great, because the home screen dynamically redoes itself based on your usage. You can pin things to a small side panel, if you can figure out how. To find something you haven't used in a while, you need to get into "Games & Apps," which is something of a mess of "everything on the whole system."

It took me quite a while to figure out how to change my gamerpic, and when I had to find it again later for my daughter, it took at least a long. In theory, using voice commands should make this less painful, but the voice commands are a mess, too. Not everything is as addressable as I'd like, and there's very little leeway in what you can say. Xbox One's voice commands are certainly no Siri.

Kinect should also be dealing with login, but it continually fails to recognize me. I say, "You failed to recognize me!" and it brings up picture of the room. "Is this you?" it asks, pointing at my wife's elbow, in the corner of the frame. Eventually, after moving around, adjusting lighting, and trying to hold my hand in many different positions above my head, the Xbox says, "Oh, is this you?" Yes! Then I have to enter my Microsoft account password for the thirtieth time. On a d-pad.

When I try to use gesture control, imagining the frenetic gesturing we see in movies set in the near future, I spend most of my time waiting for Kinect to notice that I've raised a hand. Then, I try to move it to right place on the screen before my arm gets tired.

The Xbox One UI is in nearly every way a complete step backward from Xbox 360. If they'd taken the Xbox 360 UI and added voice and gesture control, they'd be a lot better off. It wouldn't be innovative, but when you innovate you need to avoid innovating yourself into the realm of unusability.

It is really baffling. I don't know how this was permitted to happen. Do people really find this … okay?

Still, in the end, I got the Xbox One to play games. The games are good. I just won't use it for anything else, and that will be fine.

Parental controls don't help (body)

by rjbs, created 2014-12-11 22:26
tagged with: @markup:md journal macosx

My parents recently got new computers, and my mother's old (but still pretty modern) Mac Mini has more or less become my daughter's. It's what she's been using to play Minecraft, as I mentioned recently. OS X has a "Parental Controls" system, and I figured it would be useful. I'd tell it to use its default anti-porn web blacklist, to have a list of (say) ten allowed applications, and to limit her instant messaging to a few approved people. It was a big mess.

First off, I enabled "Simple Finder." I remember this well, as we used it in the college labs on OS 8 when I worked at (while attending) Boston University. Then, it was pretty simple. You defined a list of applications which would show up in a simple launcher, and that was that. It's not that simple anymore. Minecraft wouldn't work because it would want to spawn Java, which wasn't approved. Other apps couldn't run, seemingly because they weren't properly signed. I turned it off and opted, instead, to lock the dock. That was a mess, too, and I couldn't even figure out what the point was, as far as "parental" control went. I gave up.

My daughter likes to search the web for stuff. Who doesn't?

I don't want to impose draconian limits on her web usage ("you can only go to cute-puppy-games.biz!"), and I don't want to have to limit her to only strictly supervised time, because I know that she really just wants to go read about Daria in every free minute, including when I'm not available. I just want to limit the chances that she will accidentally end up on some horrible, horrible page.

So, I turned on the Parental Controls option to "try to limit adult websitse automatically." I figured there'd be some Apple-curated block list, and that was probably some help. Well, it turned out that this block list included things like Akami and other content-delivery networks. Apple uses Akami, so the App Store stopped working properly, as did apple.com. I turned that right off, again. I'll stick to enabling safe search on Google and YouTube.

Parental Controls let you limit with whom your kid can correspond in Mail and Messages. I really didn't want to set her up to use iMessage, because it stinks. I'd end up getting messages on my phone all the time. Anyway, the few people I figured she'd want to talk to are instead on GTalk or AIM. I set up an AIM account for her to use (although I had to put it in my name as there are no children under 13 allowed). This was actually just fine. I had to put contacts in her address book for the people with whom she should be allowed to chat, and then mark them as approved contacts. Great!

I haven't yet set up a GTalk user for her because, once again, you can't get an account if you're under 13. I'll probably make one myself for her to use, although I'm really unclear on whether this is permitted. Still, she wants to be able to chat with her aunt and uncle. So there you go.

So, there's one winning feature. I really wish I could have let her use Adium instead, as its UI is much, much better. Unfortunately, there are two big problems. First, even though they were briefly considered a blocker for a major release, parental controls never got implemented and are now marked as "would be nice to have." Parental controls in IM are probably the ones I wanted most. I still get unknown and presumably malicious people sending me random instant messages. I can ignore them. I think my daughter would just like chatting, and I don't want to have to worry about it. Secondly, Adium can't use TLS to talk to AIM. It used to use SSL, but AOL disabled SSL after the Poodle vulnerability. If you use Adium, you have to authenticate in the clear.

Finally, there's Mail. To let her use some of my App Store purchases, I made her an iCloud child account attached to our family. That got her an iCloud mailbox, which I figured would be fine to just get started. The idea behind how Mac Mail parental controls work is good: you (the parent) limit correspondence to known contacts. If your kid tries to mail someone else, or if someone else tries to mail your kid, the mail goes to you. You can then mark the sender approved, or not. There are a few problems, though.

The biggest one is that it doesn't work. I was sent one of those approval messages, and it had a big "click here to approve" button displayed inside Mail's own UI. I clicked and clicked, but nothing happened. Gloria reported the same. So, now the only way to deal with updating the permitted senders is to edit the contacts on the machine. It's doable, but a much bigger hassle.

The other problem, of course, is that email isn't authenticated. If you know a kid's parent's email address, you can send them mail "from" the parent. This means that your kid might be protected from getting random mail, but they're still wide open to targeted nasty mail.

In the end, I'm not crazy worried about most of these things. I would like my daughter to enjoy her time using the computer, and I'd like her to be able to use lots of the cool things on the Internet, and that's my priority. I just don't want the many, many gross things on and about the Internet to show up and ruin her day. I don't think that's too much to ask.

Oh… one more thing.

She's been asking repeatedly for "some kind of music player." I really wanted her to have one, because she likes music, but I didn't want something that would be totally uncontrolled. I like Spotify, but its UI is really confusing. Our music library is available on the NAS on our home network, but I couldn't find any DLNA music players for OS X. I ended up installing the Synology iTunes Media Server on the NAS and pointing her iTunes at that. It's not a great solution. I also had to say, "You should ask about albums before listening to them." She's not thrilled about that, and I wouldn't be, either, but I have way too much stuff on there that isn't for her ears (yet).

I may set up Spotify, just because I know that mostly she wants to listen to Selena Gomez, and won't go looking for trouble. Searching around in my music, she'd be adrift, and there's plenty of trouble lurking. This is another place that I'd love a quick across-the-internet system that could say, "Your kid wants to listen to Li'l Kim. Allow or deny?"

In Soviet Minecraft, server op you! (body)

by rjbs, created 2014-11-29 09:50
last modified 2014-11-29 09:54


A couple weeks ago, my daughter became interested in Minecraft. She'd tried it before and thought it was interesting enough, but this time she seemed to have a more abiding interest. She did a bit more flipping through the Minecraft Essential Handbook and made a few things from it, and had fun, but was finding it just a bit tedious to have to gather all the resources she needed. Still, she built a simple house in the trees, explored some nearby caves and villages, and kept looking through the book… and then she found reference to creative mode. I showed her how to play in creative mode, and she was elated. She was even more excited when she found out she could fly.

We played some LAN games, which was fun, but I knew I'd want a server. I wanted to be able to muck about when she was not playing, and I knew she'd want to play when I wasn't home. To do both those things in one shared world, we'd need a server. I asked some friends, who said it was easy, but all of the instructions I found online had a bunch of steps, wanted me to add apt repositories, create system users, and so on. It just looked like a big drag, and I started to consider just using Minecraft Realms, Mojang's "we host your Minecraft world for you" service, but at $13 per month, it was enough to make me want to put a real effort into getting the service running on my Linode.

I read through the instructions carefully, and realized that the whole thing was a big complicated way of saying:

  • make sure you have Java 1.7
  • download the Minecraft server jar file
  • run java -Xms1024M -Xmx1024M -jar minecraft_server.1.8.jar nogui and keep it running

Well, I could do that! Once I realized that, I had a running server in a minute or two. Wow! I spent just a little time updating the server configuration, then rsynced the kid's Minecraft world files to my Linode, and it all worked!

The Teleport Network

I knew that sharing a Minecraft server with a seven year old might lead to angry times later, when one of us wrecked the other one's work product. I declared that we'd each have a big hunk of land where we'd be in charge. We could visit, but not build or destroy stuff without permission.

This led to an obvious logistical problem: how would we get from one place to another? Minecraft has a teleport command, and I could've left it available, but teleporting works by map coordinates rather than named locations. If I wanted Martha to be able to teleport home, she'd need to know the coordinates for her home. I could put them on a sticky note, but that would surely get lost immediately.

I decided to solve the problem by building a point-to-point teleport network!

You can build loads of amazing stuff in Minecraft by using "redstone" devices. This is sort of code for "electrical stuff," but it has its own physics, and you don't want to think of it too much like electricity or you'll end up deeply confused. You can't build a teleportation booth out of things you can mine in Minecraft, but there's something you can use as a bit of a cheat: the command block. It's a block that, when powered, executes a console command… like /teleport.

I build a pair of booths, each with a button. Push the button in booth A, and you'd end up in booth B. It worked the other way, too.

This was a good start. We had our own places, we stuck to the rules, and we had a good time. Martha started to ask about inviting some friends to our server, which led me to realize that booth-to-booth teleporters would not scale. I could build a targeting system, but that would become very complicated quickly. Instead, I built a hub.

Minecraft Teleport Network v2.0

I left the two booths in place, but now instead of linking to each other, they'd drop you at a floating platform at (0,0) on the map. This place, "the hub," was meant to have eight sub-platforms, each with a teleporter leading to a new place. I scouted out some locations and set up a few machines ahead of time, but not all of them, just enough to show how it would work. It worked great! Mostly!

Martha kept having weird problems. Parts of the network would work for me, but not for her. Then, it would all work. Meanwhile, I was struggling with spawn protection. This feature prevents users from editing the world near the spawn point. Without this, some jerk could fill the spawn point with lava, or solid stone, and when a new player joined, they'd be stuffed. I wanted to set the hub as the spawn point, and then keep it from being edited. It just didn't work.

Eventually, I realized that the problems were related. Spawn protection disables redstone inside the protected area, which meant that the teleport machine buttons didn't work. So, why did it only affect Martha? Because I was an operator, and could still use the button inside of protection. Why only sometimes? I really didn't want to have ops on myself, so I kept disabling it. When there are no operators configured for a server, spawn protection is disabled. Yow!

I didn't really want to make everyone operators, and I did want a protected hub area. I'd have to figure something else out.

The Stupidest Thing That Could Possibly Work

I did a lot of searching for solutions, and I found them. They were almost always in the form of "mods." Those are plugins to change how the Minecraft server behaves. As far as I could tell, they always worked by having you first run a modded server. That's a replacement Minecraft server which is, itself, a Java subclass of the base server. The most popular of these, Bukkit, was recently removed from distribution because of alleged GPL violations. Its whole situation is, to me, an unclear mess.

The new thing people seem to be using is CanaryMod. It's entirely unencumbered by any sort of GPL issues, but it (like Bukkit, actually) only supports Minecraft Server 1.7. We've been running 1.8, which is a big difference. Of course, there are some bleading edge nightly builds that are 1.8, but… I felt like this was going to lead to me spending time writing Java or hanging out on a phpBB, and this thought killed all my motivation. Surely, I thought, there is some stupider, easier way.

Well, here's what I did:

When you run that java command up above, the Minecraft server starts on your console. It prints out some status messages, then as the game goes on prints out logins, logouts, the results of various messages, and all of the global chat. Importantly, it's also an operator console. You can key in commands that get run with superuser privileges. Obviously, if I wrote a program that owned pipes into and out of the server, I could monitor what was going on and execute operator commands. It would be a grody hack, but it would work!

I thought about using Expect, but decided that I'd be miserable. I tried to remember how to write this kind of thing in Perl, but couldn't remember a few key bits about non-blocking I/O. I asked Dominus for a reminder and he said "Expect!" I didn't take the bait.

By the evening, I had a crude prototype working in pure core Perl, but getting there involved some annoying things. For example, I had to keep calling waitpid inside my read/write loop, and I knew that if I wanted to add more non-blocking behavior, it would just get worse. I needed an event loop. I had a look at using IO::Async, which I keep meaning to use in anger, but it wasn't immediately obvious how to proceed, and my goal was to deliver something (to my seven year-old) rather than to do something elegant and modern. I was already using Perl, right? Anyway, when I want to get something really cool done and I don't care what people think of me, I use POE. I use it badly. It worked, as usually, really well.

Basically, the setup is this: my POE program runs the Minecraft server with non-blocking a linewise event machine. When it gets lines from the server, it decides whether it cares about them. Mostly, it cares about chat. Occasionally, it cares about other status updates, but it mostly ignores those. As for chat, it looks for players saying commands, just like an IRC bot. Players can say !home to be teleported to their home, or !set home to decide where that is. They also have a "porch," and can !set porch to set that location. The porch is where another player goes if they try to !visit player. They can switch between creative and survival modes.

Setting home was a tiny bit interesting to implement. There's no command to get a player's location, so how could I save it? Well, if a player is teleported, their location is logged. Teleportation can be to a location relative to a player's current location. So, to set home, you register a callback for "do this when the player next teleports" and then immediately teleport them to their current location, plus a 3-D delta of (0,0,0). Ha!

Something I knew was important to Martha was the ability to skip night time. I could have disabled the day/night cycle, but I knew that it would also be nice to have it enabled sometimes, for adventuring. I added !sunrise and !sunset commands. This wasn't going to be good enough, though. When she invites friends, they will surely argue about whether to change the time, so I made it a voting system. As soon as one player casts a vote for a time change, the other players have thirty seconds to also vote. Whatever change is requested wins. In the event of a tie, nothing happens. Critically, once everybody online votes, the change happens immediately. This is most critical because if you're playing alone, waiting thirty seconds for opposition stinks.

Actually, I lied a bit. The voting doesn't end when everyone online votes. It ends when there are at least as many votes cast as there are players online. This can be a bit weird. Imagine:

  • currently online: players A, B, C, D
  • players A, B vote
  • player B logs off
  • player C votes

Now there are three votes (A, B, C), and three players (A, C, D), so the election is complete. Oops.

Getting the list of currently online players is easy, but not trivial. The list command prints out the current count of logged-in players, then their names. To gather that properly, I need to get the first line, then intercept the next n lines, then fire off a "updated roster" event. I haven't bothered yet, because I'm guessing it's just a bit more pain than it's worth.

A simpler solution, which I may implement if the server becomes popular with her friends, would be to notice logout events and immediately cancel the votes of disconnected users. I could also add some facility for speaking to the server over RCON, but… again, I'm guessing it's not worth the bother.

If I had any next steps actually planned, they'd probably be:

  • add an SMS interface to allow remote whitelisting ("Oh, your kid wants on? What's their user name?" // send SMS to whitelist)
  • an "alone time" mode where a player disables the ability of others to teleport to their location
  • refusal to let a player set their home/porch within some distance of another player's home
  • a way to say "if you want to join me or come to my realm, you have to enter the mode I'm in"

For now, though, I think it's good enough. I'll wait for its overwhelming success with the kids before putting more time into it.

Meanwhile, I have published the code. As I said, it's a hot mess. I barely know how to use POE, and I did not aim at all for maintainability. I just wanted it to work. I also have a bunch of code that's copied from POE documentation, and could really be rewritten to be better. The whole thing should be turned into a MooseX::POE class for my own sanity.

Whatever, it works, right?

Soviet Minecraft is on GitHub.

Email::MIME::Kit v3 will fix-and-or-break your code (body)

by rjbs, created 2014-11-20 21:47
last modified 2014-11-20 22:21

Ever since its early releases, Email::MIME::Kit had a big problem. It screwed up encodings. Specifically, imagine this manifest (I'm kinda skipping some required junk):

# manifest.yaml
renderer: TemplateToolkit
  - Subject: "Message for [% name %]"
  - type: text/plain
    path: body.txt
  - type: text/html
    path: body.html

The manifest turns into a data structure before it's used, and the subject header is a text string that, later, will get encoded into MIME encoded-words on the assumption that it's all Unicode text.

The files on disk are read with :raw, then filled in as-is, and trusted to already be UTF-8.

If your customer's name is Распутин, strangely enough, you're okay. The header handling encodes it properly, and the wide characters (because Cyrillic codepoints are all above U+00FF) turn into UTF-8 with a warning. On the other hand, for some trouble, consider Ævar Arnfjörð Bjarmason. All those codepoints are below U+0100, so the non-ASCII ones are encoded directly, and you end up with =C6 (Æ) in your quoted-printable body instead of =C3=86 (Æ UTF-8 encoded).

Now, you're probably actually okay. Your email is not correct, but email clients are good at dealing with your (read: my) stupid mistakes. If your email part says it's UTF-8 but it's actually Latin-1, mail clients will usually do the right thing.

The big problem is when you've got both Ævar Arnfjörð Bjarmason and Распутин both in your email. Your body is a mish mash of Latin-1 and UTF-8 data.

In Email::MIME::Kit v3, templates (or non-template bodies) loaded from disk are — if and only if they're for text/* parts — decoded into text and then, when the email is assembled, it's encoded by Email::MIME's usual header_str handling.

There's a case where this can start making things worse, rather than better. If you know that templates in files are treated as bytes, you might be passing in strings pre-encoded into UTF-8. If that was the case, it will now become mojibake.

Finally, plugins that read kit contents for uses as text will need upgrading. The only one I know of like this is my own Email::MIME::Kit::Assembler::Markdown. I will fix it. The trick is: look at what content-type is being built and consider using get_decoded_kit_entry instead of get_kit_entry.

I think this is an important change, and worth the breakage. Please look at your use of EMK and test with v3.

RPG Recap: Beyond the Temple of the Abyss, 2014-11-08 (body)

by rjbs, created 2014-11-18 23:06

Thursday, 2nd day of the Frost Moon, 937

After spending the night off the road, the party headed into the elven woods. They moved slowly, for a few hours, through the narrow road as it faded into a path and branched in several directions. In the canopy, giant spiders and other things leapt from tree to tree, ignoring the party.

Another small party, made up of wary insectoid creatures carrying lavender lanterns, passed them slowly by, pausing only to attempt to negotiate the purchase of Oresta. The party declined as best it could, lacking any common tongue.

After some time, they came to a clearing and, investigating, found a number of flat surfaces along the treeline. In one, they found a door, which Knash carefully prised open. The door led to a small room, in which was a small collection of overgrown rotten furniture, including a chair with an overgrown corpse. As the gang raided the room (finding a few weird coins, a pistol, and some bullets), the corpse tore itself from its chair and rushed outside, where it keened loudly, calling to the rest of its kind, similarly sealed up in the trees.

The party fought against the plant men, slowly losing ground. Perrin was badly injured and a vine dragged him toward the cabin. Hoyte was fatally injured, but fought on, making a desperate last stand. Finally, Knash uncased and read one of his scrolls: Imperial War Horror! Instantly transformed into monstrous form, he tore through the remaining plant men, rending them limb from limb and scattering their leaves to the wind. In the end, everyone — save for Hoyte — seemed sure to make it.

"Once he's dead," someone said, "let's check his pockets and get his wages back."

Horror Movie Month 2014 (body)

by rjbs, created 2014-11-11 11:19
last modified 2016-10-20 08:34
tagged with: @markup:md journal movies

Last year, I forgot to write up our horror movie watching until about eleven months later. This year, I'm going to write things down while they're still fresh!

A Slow Start

October 1 - The Bay
October 2 - Truth or Die
October 3 - Outpost

First up, we watched a few random things from our list. The Bay was a found footage movie, which lost it a lot of points with us, I think. Found footage has its place, but its place is not "every single movie." I will also never forgive it for starting with the narrator's deep reluctance to review the horrible events of that day… to be followed almost immediately with "gosh, look at those awful pants I was wearing." Still, I liked parts of it. There's something to be said for the creepiness of being eaten from the inside out by bugs, I guess.

Truth or Die was fair. It reminded me, quite a bit, of My Little Eye, one of the other English horror movies I've seen. A bunch of young people are invited to a party at an isolated cabin where someone will extract revenge on them for their poor treatment of some guy at a party. It had its moments.

Outpost was just crap. It was Dead Snow all over again, but worse.

The Big Re-Watch

Before horror movie month began, Gloria and I watched Never Sleep Again, a four hour (!) documentary on the making of the entire Nightmare on Elm Street series, and Crystal Lake Memories, a seven hour (!!) documentary on the making of the entire Friday the 13th series. Gloria said, "Maybe we should rewatch those," so we did! We watched every one of the movies (and skipped the TV series) in the order of their release:

October 4 - Friday the 13th (1980)
October 5 - Friday the 13th Part 2
October 6 - Friday the 13th Part Ⅲ
October 7 - Friday the 13th: The Final Chapter

The first one is still probably the best, and worth watching if you like thrillers with some gore. It's not a great movie, but it's a good one, and sets up a lot of things to come, but will also surprise a lot of viewers, I think. The rest of the quartet ranges from mediocre to bad.

Did you know that Friday the 13th ends before A Nightmare on Elm Street even begins? Yup. You also might not know that it ends when Corey Feldman slices Jason's head nearly in two with a machete. Jason's face slides down the blade, and the long curse on Camp Crystal Lake is over. Four movies and done!

October 8 - A Nightmare on Elm Street (1984)

...and then we get into the first Nightmare on Elm Street, which still holds up pretty well. It's not perfect, but it's good. The body bag scene remains excellently weird, Johnny Depp's bed still eats him, and John Saxon is still great as Nancy's father.

October 9 - Friday the 13th: A New Beginning

Wait? A new beginning? How does that work?

Well, somebody decides to dress up like Jason and kill people. It's not very good at all, but it might actually be better than some of the previous ones.

October 10 - A Nightmare on Elm Street 2: Freddy's Revenge

Never Sleep Again had a lot of talk about how Freddy's Revenge is often cited as "the gayest horror movie ever made." I told Gloria that I didn't remember any kind of homoerotic subtext in it from our previous watching and she looked at me like I was crazy. On re-watching, I can see why. In my defense, while the actors and screenwriter say that it was intentional, the director and producer say they had no idea at the time. Bizarre!

Either way, it's a lousy sequel that really compromises the mythology. In fact, Gloria and I would go on to discuss how this was a big problem with the rest of the Nightmare movies. While it's easy to say that "Jason is a scary monster who just keeps coming back," Freddy is more complicated. He's some kind of ghost, and we see him soundly defeated in the first movie. Then in the second movie, he's defeated by another means. In the third, another. The series never quite settles on rules, and it becomes a big problem, because without rules, you don't know what to expect. The whole thing becomes a mess.

On the other hand, Freddy's Revenge has Clu Gulager, so that's cool.

October 11 - Friday the 13th Part Ⅵ: Jason Lives and A Nightmare on Elm Street 3: Dream Warriors

This was a Saturday, and we watched two movies: one during the afternoon while my parents watched the kid, and once after she was in bed. I was please by how it worked out, because these are two of the best movies in either series. I really like part six of Friday the 13th. I think it has a great balance of scary to funny, it establishes "Jason can't die" much more firmly, and it looks great on screen. I will watch this one again and again, over the rest of my life, I bet. It really hits the sweet spot on my funny vs. gory plot.

Dream Warriors, on the other hand, mostly gets its "best of" ranking by virtue of being one of the least lousy. I don't think it's as good as the first one by half, but it does establish a fair bit of canon. It introduces hypnocil, the experimental drug that prevents dreaming, which I always liked. It also, unfortunately, introduces the idea that the dreamers can use their "dream powers" to fight Freddy. For example, if you often dream about being a ninja, you can fight Freddy in your dreams using ninjitsu. This leads to really childish scenes that just get worse as the series goes on.

October 12 - Friday the 13th Part Ⅶ: The New Blood
October 13 - A Nightmare on Elm Street 4: The Dream Master
October 14 - Friday the 13th Part Ⅷ: Jason Takes Manhattan
October 15 - A Nightmare on Elm Street 5: The Dream Child
October 16 - A Nightmare on Elm Street: The Final Nightmare
October 17 - Jason Goes to Hell

This is just a procession of crappier and crappier crap. Jason fights a psychic teenager. A kid who plays a lot of D&D goes to sleep and puts on his wizard robe and hat. Jason kills a bunch of teenagers on a dingy yacht before punching off the head of a guy down by the river. Several movies add rape scenes, showing us that horror movies have begun to go from goofy to gritty. Finally, Jason is reduced to a slug-like parasite that's vomited from body to body, and Freddy is turned into a child by a stream of projectile vomit.

Skip these movies.

There is at least one tiny scene that I really liked, though. In Jason Takes Manhattan, a few teenagers have fled Jason and headed into the Manhattan sewer system. They run into some pipefitter who is horrified to see them. "We've gotta get out of here!" he cries. "Every night at midnight, the New York City sewer system is flooded with toxic waste, and that's in just a few minutes!"

Love it.

October 18 - Wes Craven's New Nightmare and Jason X
October 19 - Freddy vs. Jason

These movies rock. They are the light at the end of the tunnel. New Nightmare is brilliant, working in an extradiegetic framework where the previous Nightmare films were acting as an escape valve for some well of evil, which now begins to haunt the cast and crew of the first, and now next, film. It's creepy and intelligent, and that scene at Wes Craven's house, at his word processor? Good stuff.

Jason X is great, too. It's not cerebral by any means, but it's fun. It gives you all the things that made the horror movies of the 80's fun, but puts them in a space ship in the year 2450 because… why not? I have no serious complaints about this movie, and while I don't begrudge anybody their opinion, I think it's baffling that there are people who prefer the previous few movies to this one. Jason! In! Spaaaaaaaaaaace! Right?

Freddy vs. Jason was also a lot of fun. It did a good job of putting the feel of the previous movies — both series — into a modern setting. I was happy with the fight scenes, the characterization of the villains, and the tone. This movie could've been a complete wreck, and it wans't. I'm not in a rush to watch it for a third time, but it was good. Main complaint: one character is utterly and without question a total clone of Jason Mewes' "Jay" character. It's dumb, and a distraction.

October 20 - Friday the 13th (2009)
October 21 - A Nightmare on Elm Street (2010)

I was bummed to get to these. I knew it would happen, but it was still a downer. If the previous three movies were the light at the end of the tunnel, these two began a new tunnel. They rebooted the franchises, and in doing so took them out of the 1980's slasher tradition and brought them closer to the 2000's torture porn. There are already some gritty, unflinching movies worth watching. Freddy and Jason didn't need to join them.

A Nightmare on Elm Street keeps rubbing your face in the fact that Freddy was a child molester. That is not fun. That is awful.

Friday the 13th is shot to look like Texas Chainsaw Massacre. No surprise, given that its director, Marcus Nispel, also directed the 2003 remake of TCM. I think it's much closer to the originals than the 2010 Nightmare was, but its naturalism makes everything seem dirty and awful. I would've preferred a bit more Tom Savini, I think.

That concluded our big rewatch, which I doubt we will attempt again, at least until Martha is old enough to watch with us. I was happier with the rewatch than I thought I would be, though, if only because we got to re-watch some of the good ones.

The whole thing left me thinking that I could produce a better set of plots for both series. I spent some time on this and concluded that it would be much easier to do for Friday than Nightmare. Jason can come back repeatedly at various inconvenient times and places, and the story of how the public responds could be an interesting one. The Nightmare movies have to deal with the fact that "beating Freddy" is really hard to explain, and if it's some magic trick, seeing it over and over will be boring. On the other hand, the one good thing to come from the later Nightmare movies is the idea that Freddy wins, and finds himself with no more children to torment. The town is a ghost town and Freddy is powerless and bored. There's a good movie to be made out of that.

Back to the Queue!

October 22 - Bad Kids Go to Hell
October 23 - Grabbers
October 24 - (out of town visitor)
October 25 - Stage Fright and Resolution

Bad Kids was clearly intended as something like "Breakfast Club, but horror." It failed. It stank. It made me angry, because I really liked the idea. I think a movie like that would need to have a slow build of creepy events, maybe something like The Innkeepers. Instead, this was all over the place, and kept flashing back to events in the crowded school, totally contrary to how Breakfast Club works. As a big fan of Breakfast Club, I was predisposed to dislike this movie, and I disliked this movie.

Grabbers was a fun creature feature about weird tentacle monsters attaching an Irish town where everybody defends themselves by converging on the pub and getting wasted. I approve.

On Friday the 24th, I stayed late in Philly to have dinner with a friend. On Saturday, we watched two movies again, with Stage Fright as our "date night" movie. Woah. Stage Fright is a musical horror movie in which Meat Loaf murders Minnie Driver. It was pretty lousy, but I'm glad we watched it. As a proof of concept, it worked. You could, in fact, make a good musical horror movie. This just wasn't one.

Resolution was really good. A truthy summary would be "a young man tries to detox his friend at a cabin in the woods built atop an ancient Indian burial ground." It was creepy, subtle, and smart. The ending was maybe not entirely satisfying, but it was a solid ending for the story they told. Resolution would be on my list for best new movie we watched in Horror Movie Month.

The Final Week

October 26 - Cockneys vs. Zombies
October 27 - The Hole
October 28 - Castle Freak
October 29 - Oculus
October 30 - Grave Encounters

Cockneys vs. Zombies does what it says on the tin. I enjoyed it.

The Hole was made by Joe Dante, of Gremlins fame, as well as many other fine films. I enjoyed it. It was, in some ways, nothing special, but it was well made and enjoyable. I'm almost tempted to put it on the upcoming playlist for scary movies for Martha, but I think it's just a little too creepy here and there.

Castle Freak was really lousy, but had Jeffrey Combs, who is always a real joy to watch. I think there was an idea for a good movie in there, they just didn't make one.

Oculus was a good one. A brother and sister whose parents are killed in a haunted house return to the scene of the crime, ten years later, to destroy the evil entity. (I'm simplifying a bit, bit it's close enough.) They take precautions to avoid letting the haunting get to them, too much, but their precautions slowly fail. The ending of this one bugged me, too, but the rest of the film was pretty darn good. There were a few scenes that really impressed me with their clever creepiness.

Grave Encounters was another found footage film, but I forgive it. The crew of a "Ghost Hunters"-like show spend the night in an abandoned, haunted asylum. They all go in seeming pretty sure that it's not haunted, and probably that hauntings are bunk. They pay off the gardener to make up a story about seeing ghosts. Then, of course, the place really is haunted. None of this is interesting, but the way that the place torments them was really well done. It wasn't just bloody walls and jump scares. The place ground them down and panicked them over time. I was happy to see some new, or at least rarely used, ideas being put to use so effectively.

Leslie Vernon

October 31 - Behind the Mask: The Rise of Leslie Vernon

This was another re-watch. We saw this one years ago, very early on in the month, and it was so good that the rest of the month was jinxed. Nothing could live up to it. Behind the Mask is a clever deconstruction of the slasher movie, which ends with an extremely economical reconstruction. The title character, Leslie Vernon, is the killer, and he is great fun to watch. The film is a documentary, or rather, it's a a film about the making of a documentary. The subject, Vernon, spends a lot of the movie discussing how one prepares for a slasher spree, and while doing so he's energetic, funny, and charming. Later, he is not. The film is set in a world where Freddy, Jason, and others like them are real, but it's not a fantasy world. Why, the documentarian wonders, do people go on these killing sprees? "I can't explain," Leslie says, "I have to show you."

We'll almost certainly watch this one again in a few years.

Bonus Movies

Since October we watched two more horror movies, and I might as well make a note of them.

Detention was amazing. Just go watch it. Don't even read about it. Its structure is unusual, its tone is all over the place, and it doesn't worry too much about making a lot of sense. I put this on thinking it would be background viewing, but I could not tear my eyes away from the TV. Probably this is my pick for best new horror movie we watched this year. I hesitate to even call it a horror movie, but I think that if I have to classify it, that's where it goes.

Germ Z was lousy. It was a formulaic zombie movie with no new ideas of its own. It was poorly written, acted, and filmed. The only character who interested me, the doctor slash medical examiner slash part-time deputy, was given only about five minutes of screen time. Ugh.

We already have at least 31 movies we could watch for next year. Probably they'll make a couple more between now and then. Here's hoping we pick winners.

RPG Recap: Beyond the Temple of the Abyss, 2014-10 (body)

by rjbs, created 2014-10-28 23:01

Wednesday, 1st day of the Frost Moon, 937

The party had told "the dwarf" that they'd do a favor for him and deploy some equipment below Gladwell's place, in exchange for some extra time before Epstien got the full report. Their attempt to follow through ended in disaster, though, and they headed back to town much the worse for wear.

With a growing sense that they'd be doomed in town, our heroes decided to take their money and go on the run from the law. To go on the run, though, they needed to be able to run. They decided to go look for healing. They asked Pastor Vieu about the theurge who had healed Perrin's leg, and were told that he'd headed out of town to investigate some travelers' stories of miracles. The party (or most of it) headed along that road, following it all the way to Bridgend, where the saloonkeeper disavowed any knowledge of the guy. He did, though, suggested that Billy Buford in Brideford could "fix" anything. They paid a heft toll of five sovereigns (each way!), and paid Buford twenty five more to run Perrin through his machine, which left him as good as new. They didn't have enough money on them to pay for the rest of the party's healing, and Buford wouldn't take a check.

Back in town, they decided to get a good night's sleep before putting their plan into effect.

Well, except for Knash. He'd been invited to the secret meeting of the mysterious organization he'd accidentally joined while completed drunk one night.

When he made it to the designated meeting point — just far enough out of town to worry the locals but not far enough to actually be particularly dangerous — he found a strange assortment of townspeople, all wearing animal costumes. Fortunately, Knash had thought to wear his fine goat-head cloak. The revelers drank, chatted, read bad poetry, played music, and discussed their fervent hope that one day, somehow, they could actually achieve the form their hearts desired. One of the brotherhood implored Knash to let him know if he ever found any relevant-seeming magic during his exciting adventures. Knash waited for the meeting's big reveal and, finding none, he snuck back to the village.

Thursday morning, the party went to the treasury to clean house ont heir savings. The bursar was made quite nervous by this, and kept back a small amount to cover any outstanding checks. "Don't worry," they promised, "we just want to have cash on hand for this utterly fantastic party we're throwing. We'll deposit whatever's left tomorrow."

Knash, Brenda, and Perrin staked out the town's three taverns and let the gold flow. They spent hundreds of soverigns shutting down the town's businesses and getting everyone drunk. When the gendarmes came to collect them for an interview with Epstein, they inveigled the guard with drinks and had the crowd on their side. When the moment was right, they fled out their respective back doors and went to grab their stuff... which was all already missing.

Rather than hunt down their gold, horses (and camel), and henchmen, they stole new horses and got on their way. The gang was delighted to find their crew already waiting for them several miles down the road, with their mounts and belongings. "We heard them talking about you," said Tucky the page boy, "so we got on the road ahead of you." Gratuities were showered on all the hirelings.

Lacking any particular plan, the gang spent a night in the woods and in the morning set off for the elves' forest on Friday morning.

I rewrote uni (body)

by rjbs, created 2014-10-21 10:49
last modified 2014-10-25 08:36

For years, I've used Audrey Tang's uni program for stupid things. It helps you find Unicode characters:

$ uni ☺

# Only on Perl 5.14+
$ uni wry

I've never been super happy with searching. All of the args to the program are joined on space and searched for. That means that uni roman five won't find ROMAN NUMERAL FIVE. I also used to like using Carl Masak's little HTML+JavaScript unicode deconstructor. This thing would let you type in a string, and it would display each codepoint. I've long since lost it… and anyway, I didn't want to use a web browser. I thought that maybe Tom Christiansen's Unicode-Tussle tools would have the answer, but nothing quite did what I wanted.

After fidgeting unhappily for about ten minutes, I realized that I could've used those ten minutes to write my own solution. I'm sure it's awful in some way, but I'm very pleased with it, and maybe someone else will be, too.

It has four modes:

Single Character Mode


This will print out the name and codepoint of the character.

$ uni ¿

Name Search Mode


This one will look for codepoints where each term appears as a (\b-bounded) word in the name. If the term is bounded by slashes, it's treated as a regular expression and is used to filter candidate codepoints by name.

$ uni roman five

String Decomposition


This prints out the codepoints in each string, with a blank line between each argument's codepoints.

$ uni -c Hey リコ


Lookup By Codepoint


This prints out the codepoint for each given hex value.

$ uni -u FF 1FF 10FF

My uni program is now on GitHub (update: and now on the CPAN) or, for those who are curious, but not curious enough to click a link, it's right here:

use 5.12.0;
use warnings;

use charnames ();
use Encode qw(decode);
use Unicode::GCString;

binmode STDOUT, ':encoding(utf-8)';

my $todo;
$todo = \&split_string if @ARGV && $ARGV[0] eq '-c';
$todo = \&codepoints   if @ARGV && $ARGV[0] eq '-u';

shift @ARGV if $todo;

die "only one swich allowed!\n" if grep /\A-/, @ARGV;

@ARGV = map {; decode('UTF-8', $_) } @ARGV;

$todo //= @ARGV == 1 && length $ARGV[0] == 1
        ? \&one_char
        : \&search_chars;


sub one_char {

sub split_string {
  my (@args) = @_;

  while (my $str = shift @args) {
    my @chars = split '', $str;

    say '' if @args;

sub print_chars {
  my (@chars) = @_;
  for my $c (@chars) {
    my $c2 = Unicode::GCString->new($c);
    my $l  = $c2->columns;

    # I'm not 100% sure why I need this in all cases.  It would make sense in
    # some, since for example COMBINING GRAVE beginning a line becomes its
    # own extended grapheme cluster (right?), but why does INVISIBLE TIMES at
    # the beginning of a line take up a column despite being printing width
    # zero?  The world may never know.  Until Tom tells me.
    # -- rjbs, 2014-10-04
    $l = 1 if $l == 0; # ???

    # Yeah, probably there's some insane %*0s$ invocation of printf to use
    # here, but... just no. -- rjbs, 2014-10-04
    my $p = $c . (' ' x (2 - $l));

    my $chr  = ord($c);
    my $name = charnames::viacode($chr);
    printf "%s- U+%05X - %s\n", $p, $chr, $name;

sub codepoints {
  my (@points) = @_;

  my @chars = map {; chr hex s/\Au\+//r } @points;

sub search_chars {
  my @terms = map {; s{\A/(.+)/\z}{$1} ? qr/$_/i : qr/\b$_\b/i } @_;

  my $corpus = require 'unicore/Name.pl';
  die "somebody beat us here" if $corpus eq '1';

  my @lines = split /\cJ/, $corpus;
  my @chars;
  LINE: for my $line (@lines) {
    my $i = index($line, "\t");
    next if rindex($line, " ", $i) >= 0; # no sequences

    $line =~ $_ || next LINE for @terms;

    push @chars, chr hex substr $line, 0, $i;


RPG Recap: Beyond the Temple of the Abyss, 2014-09 (body)

by rjbs, created 2014-09-30 21:44
last modified 2014-09-30 21:44

Monday, 29th day of the Leafy Moon, 937

Monday morning, the party arrived at the temple to take watch and they didn't like what they found. The usually boring and unremarkable ruin was overrun with cats. The guards awaiting relief were all on edge and eager to get gone. They argued amongst themselves about whether they'd actually seen or heard anything "down there," but clearly they'd had a worse time of things than usual.

Once they were gone, the party was agreed: there was no way that they were going down into the dungeons. They'd just lie about having done so.

This wasn't quite a solution, though! Captain Epstien had said he'd be sending an inspector to look into the problem of the missing mystical seals (which the party had stolen and tried to fence just earlier in the week). They decided to solve things more permanently by collapsing the dungeon entrance down into the dungeon. ("What about Drip [the guy who lives in the dungeon]?" asked one party member. "Yeah? What about him?" replied another. That ended that conversation.)

There was agreement on the best way to demolish the entrance: call in the goblins. After first scheduling their raid on the vampire's lair (for Saturday), they explained what they needed, and the goblins sent out a bomber. He sent the party away from the building and with good old goblin know-how, brought much of the foundation crumbling down into a heap atop the old stairway down.

The party returned to town to report the mysterious and unexpected collapse of the ruins. "It's just a good thing we weren't any deeper down when the rumbling started!"

Epstien was not entirely convinced. "Tell you what," he said, "you go back there and tomorrow I'll send over … The Dwarf."

Tuesday, 30th day of the Leafy Moon, 937

Tuesday morning, the dwarf showed up in a dune buggy, none to pleased to be dealing with this situation or the riff raff on the scene. He got the party's story and headed to the site to scope things out. As he did so, the cats grew more anxious, circling and hissing, until one grew bolder and attacked him. He tore the cat from his face, threw it into the weeds, and shot it with a small pistol produced from inside his jumpsuit. This marked the end of his inspection, and he asked the party whether they'd like to revise their story.

They declined, and he explained that he was going to have to tell Epstien what happened, and that the party should probably get in front of the story, if they wanted to save their credibility.

"Well," they waffled, "okay. We weren't actually inside. We were nearby. And we didn't want to get in trouble. But we definitely had no idea what might have happened."

The dwarf shrugged and was on his way.

"Huh." Dera was surprised. "I was all but sure we were just gonna kill that guy." Somebody wondered whether Knash's absence was related to the dwarf's unmolested exit.

After some further discussion, the gang decided to hunt the dwarf down … and talk to him. They mounted up and sped off toward Teak's Bottom, where some grizzled ex-adventurer in town said they might find him. In fact, they found him at Bridgend, halfway to Teak's Bottom, and got him to pull over and chat.

"Okay," they lied, "we decided we should tell you the new, revised version of our story."

The dwarf was tired of it. "You're in league with goblins and had one of them blow the place up while you stood out in the field." This put the party's situation in a new light.

The dwarf made an offer: if they'd agree to head into the caverns under the Gladwell place and do a little reconnaissance, he'd delay his report to Epstien a few days, giving the party some time to prepare their flight from punishment. They agreed to the plan and took the dwarf's equipment back to Edgwold.

Wednesday, 1st day of the Frost Moon, 937

In the morning, Perrin, Brenda, Rago, Dera, and Hoyte headed to the blasted magic tree in the woods south of the Astodan, planning to use the portal in the tree's upper trunk to enter the dungeon without alerting Gladwell or his men. They arrived in the dungeon, southeast of the complex junction, and made their way toward the mine tunnels. Only halfway there, though, they encountered two ghasts and immediately turned tail and ran. They reached the portal exit and leapt through, scrambling or falling from the tree. Several were badly hurt, but no one died, and the ghasts declined to follow them down.

prev page
next page
page 2 of 53
1321 entries, 25 per page