Print Page

Tuesday, September 30, 2014

Paperclip 4.11 / Climate_control 0.3 problem with Jenkins - postmortem

In case we need to deal with this again or somebody else bumps into it...

Having just completed manual testing on a branch of our Proposals application that moves it from Rails 3.2 to 4.0.9, with other gems upgraded. Ruby is still on 1.9.3 in this project, with Ruby upgrade probably next on the list before dealing with remaining deprecations to lift Rails into the 4.1s or 4.2s. I merged the Rails4 branch into the dev branch and pushed, which means for us that as a deployment candidate, it starts getting run by the Jenkins continuous integration server. All the tests were succeeding there except for a set that had to do with file uploads using Paperclip. Paperclip and its dependencies from the Gemfile.lock:

    paperclip (4.1.1)
      activemodel (>= 3.0.0)
      activesupport (>= 3.0.0)
      cocaine (~> 0.5.3)

    cocaine (0.5.4)
      climate_control (>= 0.0.3, < 1.0)

   climate_control (0.0.3)

Representative error (43 more like it, testing various things about attachments):

 [1000D [?25l [31m1229/1464: 1.2k/1.4k, 83%, 2.4/s, elapsed: 00:05:54, ETA: 00:01:39
sh: file: No such file or directory
 [31mERROR [0m SupportingFileTest#test_supporting_file_passes_validation_with_unique_filename (0.07s) [K
  Errno::EINVAL:   Invalid argument - setenv
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/climate_control-0.0.3/lib/climate_control/modifier.rb:57:in `[]='
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/climate_control-0.0.3/lib/climate_control/modifier.rb:57:in `block in revert_changed_keys'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/climate_control-0.0.3/lib/climate_control/modifier.rb:56:in `each'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/climate_control-0.0.3/lib/climate_control/modifier.rb:56:in `revert_changed_keys'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/climate_control-0.0.3/lib/climate_control/modifier.rb:17:in `process'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/climate_control-0.0.3/lib/climate_control.rb:6:in `modify'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/cocaine-0.5.4/lib/cocaine/command_line/runners/process_runner.rb:44:in `with_modified_environment'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/cocaine-0.5.4/lib/cocaine/command_line/runners/process_runner.rb:21:in `call'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/cocaine-0.5.4/lib/cocaine/command_line.rb:122:in `execute'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/cocaine-0.5.4/lib/cocaine/command_line.rb:79:in `run'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/helpers.rb:31:in `run'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/file_command_content_type_detector.rb:18:in `type_from_file_command'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/file_command_content_type_detector.rb:10:in `detect'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/content_type_detector.rb:61:in `type_from_file_command'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/content_type_detector.rb:57:in `block in calculated_type_matches'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/content_type_detector.rb:57:in `select'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/content_type_detector.rb:57:in `calculated_type_matches'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/content_type_detector.rb:33:in `detect'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/io_adapters/file_adapter.rb:14:in `cache_current_values'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/io_adapters/file_adapter.rb:5:in `initialize'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/io_adapters/registry.rb:29:in `new'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/io_adapters/registry.rb:29:in `for'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/attachment.rb:98:in `assign'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/vendor/ruby/1.9.1/gems/paperclip-4.1.1/lib/paperclip/has_attached_file.rb:66:in `block in define_setter'
  /scratch/rails/.hudson/jobs/wip_bb/workspace/test/unit/file_attachments/supporting_file_test.rb:14:in `setup'

Reading the trace and inspection of code around the error did not get me too far. Standard rake test from the workspace directory worked correctly, so it had something to do with Jenkins or its configuration.

Insertion of debug "puts" statements showed that the problem in climate_control revert_changed_keys where it was restoring potentially changed enviroment variables cropped up against an environment variable at the head of the array of keys, that had the key of "", which setenv behind ENV[]= could not handle. So where does the weird empty string key come from? This env var had PATH-like contents, but a lot at a level that appeared to be for Jenkins and not for our application. When we looked at the environment variables listing from the most recent Jenkins build of the app, it showed up at the head of the list, above the _ one. Looking at the environment variables lists for earlier runs it does not show up. So apparently it is there for Jenkins and only displays for the most recent run. Got Jenkins to run green again by hacking the vendored climate_control gem (bundle install --path vendor is a build step before running tests).

Here is the change to the gem that fixed it:
climate_control(v0.0.3)/lib/climate_control/modifier.rb line 56:

  (@original_env.keys - keys_changed_by_block).each do |key|
changed to
(@original_env.keys - [""] - keys_changed_by_block).each do |key|

Thanks to David Hays who paired with me on sorting this one out.

Tuesday, September 16, 2014

Aiming for D&D 5e with B10 Night's Dark Terror

After a lot of reading and wrestling with alternatives I have settled on how to get started at running 5th Edition. This time around I am going to be a lazy bastard and use the old Night's Dark Terror module as a wilderness sandbox with assorted bits reworked or bolted on as needed, and nestle a couple dungeons of my own creation into the map, giving me a target for populating some of these inked maps I've been knocking out since last Fall, and keeping the scope of the task manageable.

I'll aim to do something with it for upcoming conventions, and start running some sessions, probably on Sundays in person or on Roll20.

For a bit of graphics in my Wall'oText, here is a tiny dungeon I don't think I've posted yet. I like the experiment with the stairs but it's a bit out of place on this map, and a candidate for digital erasure.

Monday, September 8, 2014

Stone Chain Walls - a Mapping Variation

I shared photos of two of these in progress on the G+ Map Making in Games Community. Here are final scans.

The inspiration was a desire to make the stonework I was wrapping around my outlines as part of making it prettier matter more by putting texture and intrusive shapes into the rooms and corridors, so there would be built in tactical nooks and crannies for thieves and stealthy monsters to hide in on otherwise plain walls, etc.

Pencil in guidelines against a straight edge. On the third one I used a rolling ruler that could double as a compass for curves.  Break up the simple grid by doing two or three of grids at angles, a stray extra guideline at an off angle, a spray of radii out from a point, or some arcs.

Mostly running along grid lines draw chains of stones. Vary size and shape both in runs and patterns to maintain visual interest. Wiggle off the lines, and occasionally meander a diagonal or curve for more interest. I used a 0.3 Staedtler Pigment Liner for these. Have started also experimenting with the 0.1 for stonework.

Do some minimal stippling to show what is solid. I used the Staedtler 0.1 for this.

Erase the guidelines with a good white artist's eraser.

These were done on a big pad of Canson 1557 Drawing paper.

It is a surprisingly easy style to do and goes pretty quickly since the stippling is so little it kind of makes up for doing the chains of stones instead of simple lines. It it both pretty forgiving of minor goofs and the slower pace of making a line as a chain of stones puts me in a contemplative mood for where the lines should go, and there is an inherent roughness to the resulting stonework so I don't find myself regretting a misplaced line as often as with more conventional draw the outline and then stone + stipple or hatch around it.

All three will get further detailing when I stock them. For now they are missing doors, floor textures, statues, objects, etc. I like them as is, since they have such a ruin look to them. Kind of an archaeological sketch vibe, Put in a few ways to go from one level to the another and they'll make a nice midsized dungeon.

I'll probably stock them for D&D 5E. Also thinking about making some 2.5D terrain pieces that would fit together to depict parts of these for miniatures.

Wednesday, September 3, 2014


I went to Pacificon this past weekend. Had a great time on Saturday, was too tired Sunday to hit similar highs. After an aborted Dungeon World game I signed up for, but with no one else showing up to play except for the GM, I mostly hung out with friends I don't see often enough. Didn't do my usual Pacificon thing of playing lots of miniatures games, or run any official minis or RPG games.

The games we played:

Gone a Viking - Spades with Norse Gods and points accumulated in trade goods that can be taxed by the Jarl to change it up. Fun.

Comrade Koba - A game kind of like Guillotine, even darker and funnier, with Stalin's purges of rivals as the theme.

Barbarians of Lemuria - Saturday night after dinner until about one - this was the highlight of the con for me. I volunteered to run just before dinner. Had the options of either D&D 5e Phandelver, or BoL off the cuff. BoL got a rousing yes from Martin, who I had run in it once before, so we went with that. Prep time consisted of some mulling it over during dinner. It was improv game of BoL for 8: both Jims, Barry, Zoe, Kira, Martin, Pete, and Julie.

 Fleeing a burning caravan destroyed by savages on a jungle road, our intrepid adventurers had a grueling escape through the jungle  and encountered ghostly spirits and the Apemen of the Lost City of Qar, ending in a battle with the terrible duck headed dinosaur that had terrorized the ape men. BoL proved its merit as a game to run with minimal prep. I had run one previous adventure in Qar, so I had an idea of how I wanted the city to be, but no notes, and only the Mythic playtest rules on my tablet. Up front I knew I wanted to get them into Qar and use the Apemen and one of the temples at the center of the city as foci of the adventure. Possibly with the Blood cult in the Temple like the previous time, possibly something else, which is how it played out with just a bit of foreshadowing about the cult at the end, in case there is a next time. The rest was call and response and weaving in their ideas. I figure there are three or four big structures at the center of the city and the Ziggurat this time is a different one from the Temple last time, so they must have approached from a different side of the city to it to be the dominant building seen at the center. The game came off very well and everyone seemed to be having fun.

 BoL is an excellent light system for winging it. Offhand I can think of three play aids that would help: the campaign map (Martin pulled it off the web using his iPad, since I didn't have my Legendary book along and the playtest rules I was running are text only), careers list and names lists for making NPCs and for places, assuming the book is not to hand and running from PDF, and a tropes checklist to spur ideas that might answer "What's next?".

Serenissima - Sunday morning, was very sleepy, handed off my position during turn 2 to Cyrus who had shown up a bit late, introducing him to the rules by co-playing most of the turn, and wished him well.

Nuclear War - Sunday - a couple of hands of Nuke War were about right for my reduced capacity.

I missed the epic double map Formula De game that was getting under way as I headed off home.

Wednesday, August 20, 2014

Books, books, books

I have been reading several things lately, with reading mostly winning the time conflict with gaming prep and computer gaming:

 The new D&D PHB of course, which I am mostly liking so far. I wish they had gone with less subtle page numbering and larger type in the index, but at least they toned down the background texture this time around. Aging eyes and all that. I mostly like the art, aside from the giant-headed, tiny-footed mutant halflings. The remix of the rules is interesting and nowhere too deeply annoying so far, though I'm sure I'd fiddle with it a bit if I were to run it much. I've knocked together a sorcerer and a rogue so far in running through character generation to drive rules reading. Of the Hasbro/Wizards D&D versions, its the one I'd most likely want to run at this point. I'm happy playing Pathfinder when somebody else runs it, and also enjoy the Labyrinth Lord games I've played in on Roll20. I'm still a big fan of dragging out my tattered LBBs and ancillary stuff and riffing with impromptu variants.

 Just finished 1636: The Devil's Opera, yet another in the Eric Flint 1632 series. Good enough. If you like the series you'll like it, but it isn't the place to start.

  The Science of Discworld: reading more of the Pratchett interludes than the science bits, but both are pretty good.

 Still slowly reabsorbing EPT, as I grind out more dungeon contents and start to think about where to plunk the thing down on the map and what sort of cursory scenario to wrap the dungeon crawl in.

 Getting close to the end of Black Halo, Sam Sykes second of the Aeon's Gate series. I'd read the first, Tome of the Undergates, a couple years ago and rather enjoyed it. Black Halo gets a bit repetitive of some of the themes, but overall is a fun take on the D&D adventurers as misfit outsiders that society barely tolerates, and a bickering, dysfunctional party of PCs. It strikes me as more of a DCC than D&D setting, with characters afflicted by various curses and personality issues, nasty side effects for overtaxed wizards, and a world that leans towards the swords and sorcery end of the spectrum.

 The other night my daughter and I watched an Italian/Polish (TV?) movie about the siege of Vienna in 1683, which got me thinking to re-read Tim Powers's Drawing of the Dark a historical fantasy about the first siege in 1529. The book holds up well, at least for the first 40 pages or so, as much as I read tonight. It might make a good setting for Lamentations of the Flame Princess or Honor + Intrigue in its more fantastical guise, or maybe Savage Worlds/Solomon Kane.

 My copy of Honor + Intrigue turned back up yesterday in a bit of housecleaning, so I've been paging through it again. It's really quite a nice swashbuckling rules set based on the rules engine from Barbarians of Lemuria. Some friends and I have been batting back and forth the idea of running a game, not sure whose campaign idea will win out, probably whoever actually implements a starter scenario first.

 Lastly, over the weekend I was reading a rather dry history book with some serious possibilities as source material for use in either of those last two games or anything with a strong historical element from late medieval through at least the pike and shot period, A History of Greek Fire and Gunpowder, by J.R. Partington. Mine is an old, used, deaccessioned library copy, but you can buy the paperback reprint on Amazon and it is worth it if you want authentic pyrotechnic recipes and delivery devices for your alchemists, or details of historical manuscripts and period books on the topic. It's also been scanned by Google if you just want a taste of it.

 And while I haven't read more than the beginning of the G.R.R. Martin's first Song of Ice and Fire book, some years ago, I have been binge watching the Game of Thrones series in a few bouts of several episodes at a time, and plowed through another three episodes in season three about a week and a half ago. Good stuff.

Tuesday, August 12, 2014

Ruby on Rails: Ajax upload form loses form params - debugging post mortem

In a rails application I work on, I encountered a form that stopped submitting correctly after it had previously been working. It was a rarely used web form last used in production some months ago.

Fill in the form, submit, get back a validation error on a field that was filled in being blank.

Start investigating and find the params posted to the controller include the authentication token, but not any of the values filled in on the form.

The form is submitted via Ajax, using the Malsup jquery.form.js plugin to jQuery and includes a file input field.

The bug reproduces in both Firefox and Chrome. Looking at the post in Firebug and Chrome's Developer Tools shows a Request Payload of
[object FormData]&authenticity_token=our_auth_token_string

This I initially mistook as being an object that wasn't parsing in the tool for some reason, but when I added
puts "content_length: " + request.content_length.to_s puts "raw_post: " + request.raw_post.to_s
to the controller's create method I saw that it was literally receiving the form payload as the string "[object FormData]".

That is what cracked it open. I went to the old bit of JavaScript where we put the authenticity token in for Ajax requests:

  $(document).ajaxSend(function(event, request, settings) {
    if (settings.contentType === "application/json") return;
    if (typeof(AUTH_TOKEN) == "undefined") return; = || ""; += ( ? "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);

And sure enough, we were expecting a string there, to which the authenticity token argument could be concatenated. Since it is now a formData object after updating the jQuery version from 1.7.x to current recently, the concatenation was casting it to the object as a string form that you tend to see first when alerting variable contents in debugging and the variable happens to hold an object. Rails only kept the parseable portion as params.

So that function needs revision to only add the authenticity token to if it is a string and it needs one. Off to write the Karma Jasmine test that should catch this and then fix it...

Sunday, August 10, 2014

Empire of the Petal Throne dungeon take two getting traction

 That temple level was not shaking out as interesting enough the way I conceived it so it's going on the backburner for awhile, until it morphs into something more amusing. Another map IS in the works and today I got a third of the rooms detailed, before and after drawing up Shadowkarst, yay for progress!  Looking forward to running it and eventually posting it, fully keyed. This time, the map is staying rough until I write it up, and then the pens will come out for detailing, as carrot to drive the write up.

Anybody up for some old school EPT on Google Hangouts/Roll20 later this month?


Breaking out of a map drawing rut and posting hiatus, here is one I like enough to post.

Friday, July 11, 2014

EPT dungeon level in progress

Started designing an EPT dungeon level tonight based on the map "Temple of the Weeping Moon". I hope it comes out worth posting.

Thursday, July 10, 2014

Variant Character Creation for Empire of the Petal Throne

I have still been mucking about with EPT at a low level. After that character creation experiment a few weeks ago, I came across a blog post in which the author talked about stat roll mirroring as an approach to use instead of something like 4D6 and drop lowest for D&D. I forget the author or blog, but he called it twinning. Under this scheme if you don't like your rolls, you can subtract ALL of them from the max roll possible + 1, no picking and choosing, and get that set of inverted rolls.

 Another way to add some flexibility between the roll X stats and assign the rolls as you like and roll for each stat in order is to write down an ordered set of rolls and then pick any stat as the first stat and apply them in order starting there, and wrapping around at the end of the list until all are filled.

 Taking these two together, there are nine percentile rolls to make to set up a starting EPT character, the six basic stats, original skills, professional skills, and starting Kaitars. Throwing the last three in there as an additional minor help. It is nice to have a good skills roll, and Kaitars may be a handy "dump stat".

 For example:
Here is our template:
Original Skills
Professional Skills
 With percentile rolls: 34 12 13 90 75 73 35 96 55
 Interesting mixed bag there, the average is 53.7, so not going to mirror it.
Let's say we want a Warrior, and are more interested in attributes than skills.
So we start with the 90 for Strength
STR 90
INT 75
CON 73
PSY 35
DEX 96
COM 55
Original Skills 34
Professional Skills 12
Kaitars 13
 This character will be a peasant or other relatively untrained fighter at first, but has a good attributes profile for a non-caster and will be good once levelled up.

 A high professional skills character that might be decent from these rolls:
STR 73
INT 35
CON 96
PSY 55
DEX 34
COM 12
Original Skills 12
Professional Skills 90
Kaitars 75

 Rescuing one of the lamers from the previous set of roll-ups, need to roll three more:
Dorik hiAkaliyalalu
STR 07
INT 19
CON 21
PSY 96
DEX 02
COM 49
Or Sk 45
Pr Sk 19
Kai 13

This is a perfect character to mirror the rolls, subtracting each from 101:

Kirod hiAkaliyalalu
STR 94
INT 82
CON 80
DEX 99
COM 51
Or Sk 56
Pr Sk 82
Kai 88

That's very powerful as is, or could be slid some to improve the PSY stat if planning to be a caster.