elfs: (Default)

I suppose I should make clear that what makes me most annoyed about Winterson’s The Stone Gods (see previous post) is that the Used Furniture problem is more pernicious than just a good writer “slumming” around inside the SF universe, borrowing from the warehouse, or failing to think clearly either the justifications for her setting or the consequences of it.

It’s that, for the past twenty years– longer, if we add in all the forward-looking material from Asimov through the early Cyberpunks (and even the proto-Biopunks like Rucker and Hansen)– there has been a serious, ongoing conversation within the SF writing and reading community about the consequences of our current setting.  We look at Real Dolls and bad phone voicejail trees, at insurance companies giving breaks to people who install GPS trackers on their cars, at the breaking point of Moore’s law and the attempts to keep going, and extrapolate out from there.  This conversation extends from Charlie Stross to Adam Warren (author of Hypervelocity, the most underappreciated posthuman novel of 2007, and inventor of the term “tachycognitive”), from Greg Egan to Masamune Shirow, and Elezier Yudkowski to, er, me.   We’ve been at this for most of our adult lives, thinking about what it means to share our cognosphere with thinking creatures of another substrate, and the moral and human consequences of creating those creatures out of whole silicon and steel.

Winterson apparently is unaware of that conversation.  She treats SF as if it were a Western In Space, a place where she can dodge the “real world” and write whatever she wants, without justification, explanation or extrapolation.  She didn’t do her research.  She didn’t reach out to anyone who reads SF and say, “What’s the state of the art in thinking about these topics?” or “Here’s where I’ve gone with my manuscript, what do you think?”  None of her pre-readers, if she had any, were SF fans.  Nobody pointed her at Accelerando, or Diaspora, or Ghost In The Shell, or even The Journal Entries.  Those are the state-of-the-art for the conversation about human/machine interaction.  Winterson was unaware, and chose to remain so.   I guess I expected better.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)

It’s hard to describe just how disappointed I am in Jeanette Winterson’s novel-length stab at science fiction, The Stone Gods. Winterson’s contemporary and historical fiction has a poetic sensibility that is beautiful beyond measure, a deftness of metaphor and exposition that will at times leave me breathless, unable to read another paragraph without pause to recover:

This is my day. This is Rome. I need to be as true as an animal and as wise as a saint. I shall need the luck of the devil if I am to hold it all in my hands.

‘Ciao Bella!’ My grocer throws me an apple – a model of the world in little, original sin, and the spinning globe, and just an apple.

This day. Don’t drop it. It will be gone soon enough.

(from Winterson’s A Roman Short Story, first published in Weekend Magazine, Jan 2004)

About the only writer I can compare her to, in my recent experience, is SF writer Justina Robson, who often acheive similar lyrical and metaphorical miracles with her own work. I especially like the following because, having been introduced as a work of SF, Robson’s names of things are so damned evocative:

Seraphs brought the news to General Machen first. They confirmed a sighting of Isol as she stole their wing space in the stratosphere and brushed sensor fields with the Heavy Angels surrounding Idlewild Base. They signalled him in official encrypted code.

(from Justina Robson’s Natural History.)

I suppose, when it comes to metaphor, Mark Helprin might come in ahead of Robson, but he’s sorta out of favor now that he’d like to see the Odyssey and Illiad be returned to copyright and profits from their sale somehow channeled to Homer’s children.

I’m about 50 pages into The Stone Gods. The story is set about 150 years from “now”; mankind has achieved FTL and interstellar flight, but it’s a risky proposition and is basically being treated like the Apollo, only longer. The world has divided into three Orwellian states: The Caliphate, the MoscoSino Axis, and the Central Authority. The CA, where our story opens, is basically a humungous shopping mall, a kind of 1984-meets-Brave-New-World mashup. It’s still economically powerful enough that it’s the only state fielding interstellar missions, developing immortality regimens, and building a robot-based economy.

But the population is full of Shiny Happy People, all medically “frozen” to some attractive age– 18 to 24 for most women, 30 to 40 for most men. If you’re not Shiny and Happy, the state will send out Enhancement personnel, which will do what they can to help you find your shiny happiness. If you prove troublesome, they send out Enforcement.

The heroine is a troublemaking misfit who works for Enhancement and owns the Last Organic Farm on the planet.

In those first 50 pages, here’s what Winterson has laid out for us as propositions:

  • Since everyone is a beautiful person at the height of their sexual attractiveness, everyone will become jaded. Those who wants to “compete” sexually will become absurdly hypersexualized: penises like pillars, balloon breasts and towering legs, eyes widened and bodies stretched beyond even anime superheroic proportions.
  • When that’s not enough, almost all men will resort to pedophilia, young kids being about the only thing “exotic” left in the world. The kids are bought from The Caliphate, which naturally sells them; since they’re not citizens of the Central Authority, nobody really cares what happens to them.
  • It’s against the law for women to compete against these children by having their own genecodes fixed below the age of 14. No reason is given for this.
  • There are robots everywhere. Most of them are drudgery alleviation machines that do all the work. But there is a super-high-end robot that looks and acts for all the world like a human being, although it’s not and fellow citizens wink and nod and say how remarkable it is that simple silicon can act so human-like and still not be conscious.
  • Despite being able to manufacture absolutely “drop dead gorgeous” robots that are outright chattel and perfectly loyal, humans and robots don’t boink. The narrator tells us without blinking an eye that “The penalty for inter-species sex is death.”
  • Apparently, US CA law does not hold true on CA starships. None of the astronauts we meet ever face a penalty for boinking their on-board observer robot, one of those super-sexy human models, so often that despite her described better than human self-repairing capability, she “wore out three silicone vaginas.”
  • We’re told time and again that robots don’t have feelings, but the robots we do meet frequently describe themselves as having “wants” and “desires” which are, uh, feelings.

There is, in science-fiction writing, a term we use to describe what happens when non-SF writers slum around in our genre: Used Furniture. Rather than invent a background and have to explain it, the writers just goes to the Warehouse Of Old SF and picks out a bunch of tropes with which to decorate her college-apartment plot. It doesn’t really matter, she won’t be there long.

The Stone Gods is such a viciously bad example that, for every one of those points I highlighted above, I had to restrain myself from throwing the book across the room with great force. (It’s a library book.)

The reason I’m mostly so worked up with this is that Winterson is exploring the same space in which I work: immortality, human/robot relationships, interspecies sex. And she’s doing so, so very badly. She’s said in an interview that she likes to write “at the frontiers of common sense,” but good gods, have some common sense about the background. The economics don’t make sense: you can’t have everyone sated into that classic dystopian unproductive consumerist happy stupidity that has been done badly by lots of SF writers (most recently by Jon Armstrong in his book Grey) and have a viable research field producing robots, immortals, and starships. You can’t make me believe that we would degenerate to child-abuse sexual slavery wrapped in nationalist politics, but would somehow come as a nation to impose the death penalty for boinking the toaster.

Even Winterson’s usual voice is missing, that beauty and lyricism somehow replaced with a heart-not-in-it world-weary narrator.

I thought, for a while, that Winterson might be trying to achieve a parable, but the encounter in the brothel scene convinced me otherwise. The Heroine has been dispatched to try and make HappyShiny a woman who wants the legal right to be turned into a 12-year-old so her husband will boink her again; the Heroine goes to the pedophile’s brothel– the most popular place in the city, we’re told– to find him and ask how he feels about her court battle. A panoramic tapestry of how All Men Can And Will Abuse The Powerless and Innocent is on full display. Winterson has an Axe To Grind– about men, about progress, about beauty, I can’t tell, but there is an Axe, and in this scene it is Ground until there are angry sparks flying from the writer’s pen.

Look, I write this stuff to: human/robot relationships (even, gasp lesbian human/robot relationships, like Winterson’s). I struggle with a vision for how the human species will survive a post-Transcendence technology, and to do so I limit my vision to showing how humans and near-humans and quasi-humans live in such a place; doing so, I must also struggle with racism and sexism (sometimes, okay, I revel in it too). But I aim my ground axes at stupidity, mostly, and not at stereotypes.

And while I may have started out with Used Furniture, I eventually went out and built my own set with my own two hands. I make no excuses for the results.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)

Like many designers, I’ve been enjoying Clients from Hell, a collection of various incidents freelance designers and developers have had working with customers over the years.  Oh, boy, do I know some of these.  But there’s one that stuck in my craw: “Slow It Down.”  The basic complaint is common to Ajax-based applications: if you’re close to the server when using Ajax for state management (send commands back to the server to change or save some detail), the transition from “working” to “done” can be so short that some users won’t realize that the action they committed has been saved.

I saw this on a project for an intranet deployment once.  The user was presented with a list of alert states, and if the alerts were being dealt with he could click on a checkbox to “silent” the alert and it would stop harassing his pager.  Since it was an intranet, the LAN was very fast and the server lightly loaded, so the “working” spinner would blink by so fast some people complained that they didn’t know if the action had been saved.  Where, they asked, was the submit button?

In “Slow it Down,” the developer says that he added a 1.5 second delay “on the server.”  He gives this as an example of a dumb client, but in this case, the client is right and the developer is wrong, and the developer is solving the problem the wrong way.  Using sleep() on the server blocks the thread, may slow down other transactions, and most importantly blocks the client from performing other actions.   The correct solution is to do it on the client, where you don’t use up server resources and the user can have many such transactions going on at the same time.

Here’s the whole solution, using jQuery. I create a function that clears the spinner out. Then I add an event handler that handles my data transaction and registers an on-end event handler. That event handler checks to see if the transaction took longer than the “display spinner” timeout. If it did, it clears the spinner.  If it did not, it creates a new setTimeout event to clear the spinner after the specified amount of time has passed.

(function() {
    var timeout = 500;

    function swapSpinner() {
        $('#spinner_container').html('');
    }

    $('#submit_button').click(function() {
            $('#spinner_container').html(
                '<img src="/assets/images/spinner.gif" alt="" />');
            var form = $('remote_form');
            var data = $(form).serialize();
            var action = $(form).attr('action');
            var started = new Date();

            $.post(action, data,
                   function(data, status) {
                       var when = new Date();
                       var inter = when.getTime() - started.getTime();
                       console.log(status, inter);
                       if (inter < timeout) {
                           setTimeout(swapSpinner, timeout - inter);
                       } else {
                           swapSpinner();
                       }
                   },
                   'text');
        });
        return false;
})();

This is the correct way to do this: a server thread is freed the moment the transaction is done, but the cognitive message the server is doing something has been successfully delivered to the user, and the (admittedly minimal, but as Google can tell you gazillions of minimal costs add up) CPU load has been distributed to the client. Because javascript is single-threaded and event modeled, many such events can be going on at once, so in the example I described above, the customer could click several boxes in a row and the system would do the right thing.

The developer might say that this is a case of educating the user.  I disagree: this is a case of unpleasant surprise.  There’s a rule in web design: exceed your client’s expectations gently.  If you’re going to make transactions instantaneous, you’re taking away the cognitive step submit the transaction.  You must replace that with some alternative acknowledgment.  A delay does that.  A delay done right does that and creates new opportunities for further exploration of the technique.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

It’s hard to believe that I found a way to write a sex scene in the middle of what was probably the worst horror story of the mid-1990’s, the genocidal war that wracked Rwanda.  I’ve even read two terrifying accounts, We Wish to Inform You That Tomorrow We Will Be Killed With Our Families, and the oddly more depressing Shake Hands with the Devil, in which the UN general on the ground in Rwanda accounts just how poorly equipped he was to save all those people.  It seems even more sad that in order to make the story work, I had to throw a trio of white kids into the middle of the conflict.  (Well, okay, one’s not “white”; he’s not even human.  He is very visibly not African, however.)

And yet, one of the things I’ve learned about writing is that to make a story work for the reader, it requires verisimilitude in the very small.  I don’t have to get the big details correct (and to be honest I didn’t: Highway KKM14 wasn’t finished at the time of the genocide, but I needed a road there), but I did need something the reader could grab onto.  Jake’s real commitment to his cause, and reality suddenly catching up to Maryse’s liberal whimsy, were things I could understand and wrap my head around.  So that’s where the story went.

I don’t want to make it sound like spinach reading– you do it because it’s good for you.  I think it’s a pretty damn good story all on its own.  Without further ado, here’s Bujumbura.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)

Heathen Philosopher: One who has left his fly open.  (1811 Dictionary of the Vulgar Tongue).

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)

Okay, I’ll confess: the reason I have three Yowler stories that aren’t released is simple: setting up the home page is proving to be a pain in the neck.

You see, I had this brilliant f’ing idea: the home page would look like a Wikipedia page.   It would provide a long, detailed explanation of the Yowler universe: myths and legends, recent history, modern attitudes, and so forth and so on.  It would provide context for anyone who cared to read that much into it.  Down the right hand side of the page, where “extra details” are frequently put, I would keep the list of stories, along with a second list at the bottom, so readers could actually find the stories I posted.

But actually putting all the backstory I have in my head and in various scattered notes onto paper isn’t coming together as much as I’d like.  It’s taking a long time.  A page on a specific race or ethnicity is really long (as my template I’m using the Indigenous Australians page) and getting it all to make sense, to not sound stupid, to provide a working world and universe that looks like our own, is actually a lot of work.  I admire the Urban Fantasists who pull it off well.  It  might be a few weeks before I get this all together.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)

For multi-select boxes where you have a list of things you want to filter on, and you want the queryset returned to be an OR’d set.

    qset = Q(mode__exact=modes[0])
    if len(modes) > 1:
        for mode in modes[1:]:
           qset = qset | Q(mode__exact=mode)
    r = Responses.objects.filter(qset)

Now, I need to figure out how to do this as a list comprehension!

For extra coolness, you can see what SQL you’re generating:

    print r.query.as_sql()
This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

For reasons I won’t go into, I’ve had to re-activate my “professional” login on my laptop.  In order to distinguish it from the Elf user, which uses Enlightenment, I use Gnome when at the office.  And one thing I absolutely loathe about Metacity, the Gnome window manager, is that when you’re flipping between workspaces, you cannot roll from the last workspace to the first, or vice versa.  You must flip all the way back.

This patch, to the file workspace.c, changes that:

--- workspace.c~        2005-07-13 10:06:21.000000000 -0700
+++ workspace.c 2006-01-06 21:11:36.000000000 -0800
@@ -758,13 +758,13 @@
     }

   if (layout.current_col < 0)
-    layout.current_col = 0;
-  if (layout.current_col >= layout.cols)
     layout.current_col = layout.cols - 1;
+  if (layout.current_col >= layout.cols)
+    layout.current_col = 0;
   if (layout.current_row < 0)
-    layout.current_row = 0;
-  if (layout.current_row >= layout.rows)
     layout.current_row = layout.rows - 1;
+  if (layout.current_row >= layout.rows)
+    layout.current_row = 0;

   i = layout.grid[layout.current_row * layout.cols + layout.current_col];

Why this isn’t implemented by default is beyond me. This patch has worked it Metacity 2.x since the beginning, and works great with Metacity 2.24.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

I can’t tell if I’m suffering from the geek equivalent of writer’s block, analysis paralysis, overload, or some combination of all of the above.

I’ve been working on a generalized platform for narrator, the story engine for the Journal Entries and everything else. As I’m working my way through the process, I’m thinking in typical RDBMS fashion, “Okay, the system has Authors and an Author has Serials and a Serial may have more Serials which eventually leads to having Stories.” (To make the whole “Serials” thing clearer: A universe has novels; novels have chapters. “Universe” and “Novel” are synonyms for Serial, and “Chapter” is a synonym, in this system, for “story”– an atomic block of text readable in one sitting. Theoretically.) I have a tree-based heirarchy for Serials working, although I’m damnably unhappy with where in the system the knowledge for “An author may have zero or more serials” is stored.

The actual architecture is sorta backwards: Each story has a foreign key to a serial, and a serial may have a foreign key to a parent, and ultimately all serials have a foreign key to a user, and so forth; the usual one-to-many relationships built within SQL. The nice thing about Django is that it notices these things and builds the backing querysets automagically, so you can traverse either way along this structure without having to write your own code.

And I pretty much have all that put together. I have some performance worries, and have seriously contemplated what this would work like under Mongo, but so far, it seems to be fine.

Time to upload my stories to the system, right? Four “Universes,” one merely labeled “Other Stories.” And I’m thinking, well, I could do it by hand– yeah, all 400 stories or so– or I could fake it just spew the data from the old database, through a transform, to the new one– fast, but misses the point– or, the choice I made, I could write a simple web-based API.

“Simple.”

It turns out that there are three mysteries to web-based APIs. First, there is RESTful verb architecture, meaning: do you encode the verb in the URL, or do you go with the HTTP verbs of PUT and DELETE along with the more traditional GET and POST?

RESTful verb architecture rigidifies the interaction with your system in strange ways. Consider my description above as a web page; a web designer would build a limited view of the author’s profile data, plus a tree-based view of the author’s serials and the stories they contain. Now, if your URL for an author is, say, “/author/<author_id>/”, it might make sense in an API to provide a complete view of the author profile and a complete list of his works, or it might make sense to have two two calls– one for profile, one for his works– but there’s no real way to structure the system in such a way that the URL refers some of the author’s information, and a tree of serials and stories. Those are four different relationships, referring to three different objects, one of which recurses.

This interacts with the other complete problem: how do you return data to the client? As… what? JSON? XML? YAML? A blob of text? Remember that one of the nifty miracles of narrator was its ubiquity: you could download the stories highly styled, or simplified for text-to-speech (I seem to have a lot of blind readers), or as text, or as a PDB Docbook format appropriate for ebook readers. Once the system has decided what action is going to be taken on the resource, that resources has to be rendered and returned to the client.

All of this, when dealing with a framework like Django or Rails, also seems to create the headache that they expect the REST commands to correspond to row actions on a table, which is not what’s going on here. An author isn’t just a row entry in the User table; it’s also a resource with other resources. Serializing it isn’t a simple matter of taking the row, the column names, and adding them together into a dictionary.

All of this comes with one surprisingly enormous pressure, from the Django community: DRY. Don’t Repeat Yourself. If you do, yur doin’ it wrong, as you Intarwebfolk like to say. (I am aware of all Internet traditions.) So when I start to write a generic method for handling the XML, YAML, and JSON versions, and have a “special” version for handling HTML, I worry that I’m repeating myself and the anxiety is crippling.

I should just say “Fuck it,” neh? Just write a stupid intake for “add a serial to a serial,” and another for “add a story to a serial,” and live with it. It might even become canon, and if I ever publish this thing, I’ll have people cursing me for using POX. Do everything in JSON (it’s what I know best) and worry about extensions later.

Oh, yeah, there was a third complication: Authentication.  That mystery is less difficult, but still annoying.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Today’s lesson: Always use the proper tool. I wrestled for an hour yesterday trying to the the Gimp to do “text along a curve.” It never quite came out right. The few times I got it close, the text looked awful.

This morning I tried a different tool: Inkscape, which is designed to handle vectors and curves. It looked great the first time. Well, it looked right.  Now I have to fiddle with it to get the text just right, and then fiddle some more.  I might be learning vector illustration by the time this is over, which was planned for the next project, not this one.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

I got an email today from one of the super secret stealth start-ups, the one I really wanted, and they told me that they had chosen to go with another candidate. Bummer.

At one recent interview, an engineer asked me to “give him the sum of the two highest digits in an integer array. Any language.” I thought for a moment, then wrote:

array.sort()
return array[-1] + array[-2]

He said that was fine, but since it would be O(n*logn), could I do it in O(n). He wanted a linear search instead.

After answering the question to his satisfaction, we got into a bit of a religious discussion about the merits of concentrating on performance during initial composition, versus concentrating on correctness. I’m much more a “get it working, then get it right, then profile the working program for bottlenecks and work them out.” It is possible that you can create systemically slow solutions that’ll require a re-write, but that’s actually far less likely than having I/O or CPU bottlenecks in small functions of code that can be fixed with optimization.

He later told me that, although I didn’t get the job, he voted to hire me. He liked my answers and appreciated that I was willing to stand my ground and discuss the relative merits of different approaches.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Grr.  Okay, so here’s the confession:

For the past eight-plus years, I have been working in a sealed greenhouse environment of web development, a veritable Biosphere II of HTML and HTTP.  I’ve been writing a web-based front end for a single product, working with a limited number of graphic designs handed to me by the marketing department, using a limited number of Javascript libraries and exactly one web development platform: Webware.  Now, there’s nothing wrong with Webware.  I like it.  But it’s an archaic design, based on the transaction model first published with WebObjects back in the mid-1990s.  I have had some opportunities in that time to work with other tools, deploying several PHP and Rails applications: the Journal Entries publishing toolkit is Django, these blogs are Wordpress,  I’ve done two freelance gigs involving Rails and Django,  I’ve done three “interactive” brochures in Wordpress and Joomla, and one wholly static brochure in plain ol’ HTML.  We did some in-depth analysis of what it would take to move off Webware to Django, and the results were sobering, but I’d actually made a significant first stab at creating a Django dispatcher that would correctly and succinctly manage a Webware applications, by analyzing the Django transaction model and comparing it to the Webware Emulation Layer in Pylons.

Compared to my Webware experience, everything is pretty shallow.  In the past nine weeks, I’ve been sucking down web development and design at a rate I can’t recall.  My brain hurts.  For this week, I’ve been working on a freelance job which has been an absolute blast, as it combines two of my favorite things: event-driven Javascript with realtime customer-facing updates, and an obscure programming language (if x86 assembly qualifies as “obscure”).  I did it in Django, which I’d definitely grown to love over the past year, much more so than Rails.

But one thing kept bugging the hell out of me: floats didn’t work well.  If at all.  And now I know why.

A long time ago, for miscellaneous reasons of ideological purity, we decided to go with a Strict DTD in the DOCTYPE header over at Isilon.  Our assignment was to code to IE7, Firefox 2, and Safari.  It turns out that if you don’t put one of those in the header, IE7 interprets some things in an IE6-ish fashion, including floats and margins.

How annoying.  For the first time in my life, I actually have to learn what “Quirks Mode” means. Well, now I know.

The funny thing is, we never had to worry about this at Isilon.  We’d set it once in the heirachy header, and that was that.  That was all we needed.  Even better, it was XHTML pure because we used a python-sided templating engine that made it impossible to write improperly closed HTML.

Live and learn.  One more thing for the developer/designer checklist.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

There’s one piece of advice SEO mavens always give out that always sets my hair on fire.  It’s this: “Always design your web pages with CSS.  No Tables!

This advice is pure, unmitigated bullshit.

I just designed a website for a client.  I used CSS for a lot of things.  Surprisingly enough, I used tables for– gasp– tabular data.  A table of classroom assignments.  A table of type/key/value tuples for features of the software the students are writing for each assignment.   Tabular data.  That’s what tables are for.

SEO experts who terrify newcomers into thinking they’re doing something wrong when they use a table– a perfectly useful tool intended for the liquid display of tabular information, the outer perimeter of which can be affixed to whatever grid makes you happy– do nobody any favors.  Be specific.  Say “Don’t use tables for layout.  Learn about semantic design.  Use tables for what they’re good for.”

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)


Experiment #5

Recently, I did some experiments with the GIMP, attempting to reproduce some of the “how to do it in photoshop” experiments that come across on the Internet from time to time.   To the left is my latest experiment: an attempt to reproduce the Apple&trade; glowly mark used in some of their advertising by using the new Layer Effects toolkit available for Gimp 2.6.

The experiment was not a complete success.  I managed to figure out how to do the inner glow (hint: it’s not the Layer Effect “inner glow”; it’s an ordinary gradient fill), and I almost got the drop shadow, although obviously the professional version is much more crisp and clean.  There are four copies of the peach: one for the glow, one for the inner shadow, one for the outer glow (again, I suspect that a straight up gaussian blur would have gotten me the effect I wanted much better than using the Outer Glow layer effect), and one for the grey background, all again on a gently gradient background square.  Five layers all told.

I spent an hour on this experiment.  When I do nail it, I’ll put up a tutorial with screenshots of GIMP 2.6 in various stages as I work my way through the example.  But before I do, I’ll have to figure out for myself how it works.  I suspect that the first step is to work very large and shrink it down to the scale I want when I’m ready to publish.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Well, that took a little bit longer than I anticipated. But, I’ve learned an important lesson and successfully brought a project in on time and budget, so I can’t complain.

When the customer says, “We tried this with the last contract but he was more of a designer than a developer. He almost got it, but couldn’t quite make it work,” don’t assume he still has that source code. Ask. That was my big mistake. It took me awhile to dig myself out of that hole, and yet when I was done I had a much better understanding of how Wordpress works than I would have otherwise.

Still, the site is looking fine now. The specific request was to make the “Categories” menu show “a list of pages associated with the current category,” which involved two magic tricks: one, in Wordpress, categories belong to posts, not pages. The two are separate database items. And two, once “pages have categories,” figuring out from the current page what category the visitor is in, and highlighting that category in the category list. This is a different task from doing the same thing through the current post.

I’ve learned about customized Category_Walkers (apparently, this is a Dark Art, as I’ve been able to find exactly one example other than my own that used it) and how to integrate category lookups with the Wordpress metadata engine.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

I’m putting this here because I’m tired of losing it.  I hate having to look up every time the exact same recipe for “how do I create a new empty database for Django or Rails in MySQL?’  It’s in two different sections of the O’Reilly MySQL in a Nutshell book, and while I have both bookdarted and know where to find them, it’s nice to have them in just one place!  The  phrase ‘to X’ on line 4 is the database username, and the ‘identified by’ string there is your database password, in case you were wondering.

# mysql -u admin -p
password:
mysql> create database secretproject;
mysql> grant all on secretproject.* to secretproject identified by 'redacted';
mysql> flush privileges;
mysql> quit;
#
This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

FireWatir is my preferred testing suite for developing web applications.   Watir is a domain-language that describes things you do with a web browser: navigate to this page, find this input field, type in this text, find this button and click on it.  Combinded with a unit testing framework like Ruby’s Unit::Test, and you can write scripts that perform the basic functions of any application website and report back on what works and what fails.

The basis of Test-Driven Design is simple, but getting it right seems a little weird.  You really do have to write the tests first.   So I’m going to start with the two absolutely simplest scripts you’ve ever seen.  I haven’t even run the application builder script (rails <project> or django-admin.py startproject <project>) and already I know two things that it has to do.  But before that, let me show you the boilerplate I use for my test-driven work.  Below is a script that I put into a directory in my application project called setup.rb:

END {$ff.close if $ff} # close ff at completion of the tests

require 'rubygems'
require 'firewatir'
require 'test/unit'
require 'test/unit/ui/console/testrunner'
require 'net/http'
require 'json'
require 'optparse'

$options = {:address => 'http://localhost:8000/'}
OptionParser.new do |opts|
  opts.banner = "Usage: example.rb [options]"

  opts.on("-a", "--address", "Base address to test") do |v|
    $options[:address] = v
  end
end.parse!

This script is meant to be called by all testing scripts in the system.  It does two things: defines all of the libraries that the tests will need, defines a default address where we expect to find the development server, and accepts an alternative address as needed.

FireWatir invokes and drives Firefox.  The END clause at the top of this script banishes the window in which the tests were run when FireWatir has run all of its scripts.

Now, here’s the most basic test you’ll ever run.  I keep this in a file called, surprise, basic_test.rb.  This test has an important side-effect, which I’ll discuss in a moment.

require 'setup'
class TC_Basic < Test::Unit::TestCase
  include FireWatir

  def test_01_server_presence
    $ff = FireWatir::Firefox.start($options[:address])
    sleep 2
    # Do this rather than an assert; the tests cannot run if the server
    # is not present.
    if ($ff.title =~ /Page Load Error/) then
      puts "Could not contact server"
      exit
    end
  end

  def test_02_homepage_presence
    $ff.goto($options[:address])
    assert($ff.title =~ /SecretProject/)
  end
end

This file imports the setup script, which in turn does all of the argument parsing and setting up of libraries and stuff.  So that’s all taken care of.   It also defines a single test case, and two tests within that test case.  The first test is not really a test at all; it does the invocation of Firefox, sending it the address of the server.  If it cannot contact the server, it does not “fail” as a test should, instead it halts the tests right there.

The second test is much more fundamental, and is an accurate test.  It sets one variable (the home page URL), and asserts one true thing about the operation (the page’s title is set correctly)

One thing to note about these tests: I haven’t actually written the code these tests will test yet. That’s important.  My job, now, is to make these tests pass.  Once I’ve done that, I will go on to other things: logging in and registration, and then user interaction.

Each test will define one thing the user can actually do: list the user’s documents, pick a document, edit some detail of the document, save the document, delete the document, etc. etc.  That’s what TDD is for.  TDD is part of your documentation: it tells future testers what you expected your program to do well.

This entry was automatically cross-posted from Elf's technical journal, ElfSternberg.com
elfs: (Default)

Yesterday, I posted a very silly bit of Dr. Who fanfic to my livejournal.  It was quite literally the first thing out of my head.  I was putting daughter Kouryou-chan to bed, and she was whining that she hadn’t had time to read.  I explained to her that we’d used up the time playing board games and now it was bed time.  She’s fond of clever wordplay, and as we were going back and forth with her protests and my stern, parental admonitions of sleep, an idea struck me that I had to write it down.

After I turned out her bedroom light, I sat down with my laptop in my lap and hammered out the story in one very quick draft, less than half an hour really.  I needed very fast furniture for my ridiculous idea, which involved time travel, something the audience could “get” quickly.  Dr. Who was the perfect setting.  I ran it through a spell-check and hit “Publish.”

Looking back, that was probably a mistake.  There’s a lot wrong with the story.  I made my first mistake of writing: I failed to read the story aloud.  That alone would have improved the story greatly; I would have seen how Tom Baker and Elizabeth Sladen’s voices were mangled.  Sarah uses “why” much more often than “how,” yet I used “how” in my story. Baker was much more expressive with his hands, face, and body than the story implies.  The meter-long cylinder in the Doctor’s hands needed a little more attention, as did conveying just how disgusting the infestation of insects was to poor Sarah.

Still, it worked reasonably well.  Lesson learned, again: first drafts are first drafts.  Read your work aloud.  Be critical after the draft.  Convey character first, and everything else will follow.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)


Storyboarding Princess Jera

I’ve recently begun experimenting with storyboarding my longer works the way Elmore Leonard does. He uses 3×5 cards, but I figure that with my crabbed handwriting and tragically bad organization, 1×1.5 post-it notes is going to work just fine.

The story to my left is the rubble of Princess Jera, a novel told in twenty alternating chapters of about 2500 words each, so about 50,000 words total, not novel length but good fun and practice.  The story is about half gonzo; Jera’s magic powers come from arousal and pubescence (classic themes beaten to zero Kelvin death by the X-Men and the Twilight series, but still pliable in the marketplace), the Traditionalists are terrified of a Mage upon the throne and the Mages are terrified that she’ll be like the last royal, discovered-at-puberty Mage, who damn near wrecked the kingdom with his self-indulgence and self-destructive tendencies.   That he wasn’t very bright compared to Jera doesn’t quite enter into their calculations.

With help from a friend in her father’s court, Jera finds documents from that era, four centuries prior, and embarks on a journey of self-discovery (ahem), discovers that there’s a word for her and the two mages assigned to her training have been mostly training her how to tamp down and ignore her powers.

Even worse, Jera discovers that an incident from four centuries ago that both her nation and the kingdom to the north portray as a great betrayal by her ancestors was something far, far more complicated… and she may be able to undo much of the damage.  There are those in the court who like things exactly the way they are.

The story ends with a violent confrontation in an ancient castle, a ruin where once her predecessor’s secret mage council practiced forbidden necromancy, and a discovery that will turn the entire region upside down with its implications.

The storyboard is an attempt to isolate important scenes and ideas.  Not all of those above will make it into the story.  And as I said, this is half of them; the other half is told in diaries, journals, and letters from her predecessor’s era, a cache of documents that stun Jera with their wanton depravity, so unlike the elegant, controlled concupiscience of her father’s Imperial harem.   And then among the documents Jera stumbles across the most dangerous find of all– the grimoire of another student of her predecessor’s mentor, a woman whose training made her cruel and dangerous.  Those post-it notes, with descriptions of various orgy scenes and other laciviousness haven’t  been put down yet.

It’s an attempt.  We’ll see how it goes.  I really should transfer these to a much larger canvas, like something from a very large sketchpad or something, but the notebook is a compromise between space and portability.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.
elfs: (Default)

Damn. So, I had what I thought was a great idea for a story, salvaged out of the back of my brain with no real thought for the characters involved. It seemed simple enough, inspired by the absolutely ridiculous PS2 game Interceptor Robot Hoi-Hoi San: what happens when an archaic sex ‘droid awakens to find herself in a minuscule robot only 18 inches tall?

I created a setting: a cold corner of Discovery, the once-lovely world now turned into a post-apocalyptic mess by the sudden worldwide crash of its computational infrastructure.   A few AIs are left, and everyone’s trying to figure out how to reboot the planet without causing the crash a second time.  I had characters: the bitter but geekily brilliant Chelle, fourteen when the crash happened, now eighteen, who’s digging around in the most obscure places for defensively obsolecent technology that can be used to reboot small corners of the planet without risking another runaway.  Her best friend, The Nooj, a bit of a dork but loyal to Chelle.   A few other characters in a tight-knit group of “survivors” who have no idea how good they’ve got it compared to truly primitive people without heat or electricity.  Cy, one of the last few AIs, cold-hearted although he doesn’t mean to be.  It’s his lack of romantic emotionalism that saved him from the runaway.

The Corridor is standing off, afraid that what happened on Discovery is infectious: the very first Singularity Runaway in Pendorian history.  Everyone knew it was coming.  Discovery seemed like the last place it would happen.   Nobody knows what to do.

The basic plot is this: Chelle finds a Hunda Pest-Control Robot from the 25th century Terran CE while rooting around in a warehouse no one’s visited in centuries.  It’s made by the same company that made the “nursing unit” shells like Linia.  She also digs up an ancient drive case which contains a backup of Linia made shortly after she was deactivated but before she was crated up for shipment to Indigo 161-4.  (I have not yet found a credible excuse for how the backup made its way from Terra to Discovery.)  A little bit of playing and technogeekery and Chelle manages to find a blank robot brain that will emulate the full-sized Hunda OS, fit in the tiny doll body, and maybe work.

It doesn’t seem to, so she and Nooj leave to go find their friends and share a meal.

Linia wakes up.  Chelle and Nooj come back, find Linia walking around on the table, and hilarity ensues.

Only, it doesn’t. There’s no chemistry between Linia, Chelle and Nooj.  What Chelle wants is to get the world working; love is the last thing on her mind.  The Nooj wants Chelle’s body, but he doesn’t really quite understand why, being, y’know, barely out of his teens.  And Linia is in no physical condition to be a lover to either one of them.

Getting any two of these characters falling madly into bed is gonna be hard.

I even looked up the legal term that could be applied to Linia falling into Chelle’s hands: bona vacantia, or possibly thesaurus inventus, although the latter implies that Linia’s mind was left deliberately for someone to find.

This entry was automatically cross-posted from Elf's writing journal, Pendorwright.com. Feel free to comment on either LiveJournal or Pendorwright.

Profile

elfs: (Default)
Elf Sternberg

May 2025

S M T W T F S
    123
45678910
111213141516 17
18192021222324
25262728293031

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 27th, 2025 06:17 pm
Powered by Dreamwidth Studios