Categories
Technology Weblogging

Comment spammers redux

Recovered from the Wayback Machine.

Seems to be a technology day today.

Phil caught a comment spammer who was trying to dump spam comments in all of his posts. This process would work within any weblog that sequentially numbers weblog posts (ie Movable Type).

I’m going to try and tweak my mt-comments.cgi to stop POSTs from pages outside of my root URL. This is my way of warning you all that the comments, web pages, weblog may be a tad more behaviorally challenged than normal.

Update: I added checks on referers and this will prevent posts from locations other than my own weblog server. Unfortunately, as Phil pointed out, http referers are fairly easy to fake. I also wrote a test script that did so, and my checks failed to catch a ‘fake’ referer.

Still, it’s a start…

If you attempt to post a comment and fail, please send me an email and I’ll check to see what the problem is. Unless, of course, you’re the spammer. In which case: Eat dirt and die scuzzbucket!

Ahem. Thank you.

Categories
Technology

The Slinky style of project management

It seems that the bookshelves are inundated with books about building successful systems. “Build a successful business in 2 weeks or less”, or “How to go on the Web in 30 days”.

To me, the real key to building successful systems, Web-based or not, is to understand the underlying causes of what makes a system fail. So, I decided to write my own set of articles entitled “Why Systems Fail”, beginning with this — The Slinky Style of Project Management.

The What Style of Project Management?

You know what Slinkies are. They’re metal or plastic springs that can be pulled apart and spring back together. You can buy a slinky in its pure form, or as part of another toy. For instance, you might have seen them as the body of the Slinky Dog™ in Disney’s popular movies Toy Story and Toy Story 2.

I have a slinky at my desk, and whenever I get stumped on a technical problem, or I’m trying to figure out how to word a paragraph, I grab my slinky and move it back and forth between my hands. Back and forth, back and forth — really quite soothing. Okay, yeah, a bit mindless too, but that’s okay sometimes.

However, the fame of a slinky is its ability to “walk” downstairs. Put a slinky at the top of the stairs, tip the toy over the stair by its top and watch it go — the thing won’t stop; moving head over tail, overhead, over tail, until it hits some obstruction along the way, falls off the stairs, or hits the bottom.

The thing about a slinky is that the toy has momentum generated by the action of the spring and the force of gravity, and this momentum doesn’t cease until something blocks the action of the springs or the slinky is no longer falling.

Project Management can take on a strong resemblance to the slinky, particularly with system projects that are based on the Web. The real key characteristic of the Slinky type of project management is to continuously move, building on the previous momentum, and whatever you do, no matter what, don’t stop.

Doing design specifications and getting buy off from the clients means stopping — can’t do that. So is documenting the system as its being built, or using documentation in the code, or diagramming the application or the database supporting the application. All of these mean that you will be spending time Not Delivering Content — and not delivering content is evil, it means you’re stopping. So you just keep on putting content out, and putting more content out, and more and more. Just like the toy on the stairs, you hope that the momentum of your effort keeps the project going and going and going.

However, with this kind of project, when you do stop (and you will, eventually), just like the slinky your system is going to sit there most likely fallen over on its side. Folks are going to be able to look, really look, at what you’re delivering: applications quickly delivered but not very robust, that are hard to maintain and difficult to modify; they might have security leaks and the database data might be a bit suspect.

Some poor soul or group of souls will be brought in to support the system and they’ll get all the late night calls with system failures, and the code re-writes, and they’ll probably not like the originators of the system very much especially when they’re going through the one thousandth line of code trying to figure out where the bad data is coming from.

Normally, folks don’t use the phrase “Slinky style of project management” when they refer to this style of systems development. No, usually they use terms such as Rapid Application Development (RAD), and Content Focusing, stuff like that. But you can still see the faint gleam of metal of the slinky underneath.

RAD does not mean any documentation, nor does it mean no design: it means starting small and building on the successful completion of each task BUT (big but here), you still deliver specs, and you still deliver docs, and you still make sure appropriate T’s are crossed, and I’s are dotted. RAD is not a shortcut for doing things Right.

In the Slinky project management style, there are no system design documents, there are no system implementation documents, there isn’t an overall plan, there are no standards, source code control is a bit of a laugh, and there is no documentation of the database —

But hey, the ride was sure fun, wasn’t it? Just don’t stop, just don’t ever stop…

Categories
Technology

Demonstrating Photoshop Functionality with X-Objects

Copy found at Wayback Machine Archive.

I upgraded my original cross-browser DHTML objects into the new X-Objects — with support for Mozilla and Navigator 6.0.

To try out the new objects, I migrated 4 DHTML demos into using the new objects. These demos demonstrate different aspects of using Adobe PhotoShop’s photo filters and editors. I’ll be going over each demo in this article, but first, I wanted to describe another set of JavaScript objects used in the examples: the Animators.

Animator scripting objects

When I first started working with DHTML, and creating DHTML effects, I used to manually code animations within the page where the animation displayed. These animations used a JS timer created using the function setTimeout.

For instance, my first DHTML animation was about an animated menu that didn’t do much more than move pieces of the menu around the Web page (see animated menu). This example has changed based on new versions of both IE and Navigator, but for the most part the animation starts once the page is loaded, and continues until the last animation step is reached:

function MoveObjects() {
   theobjs["menu1"].objMoveAbsolute(
		TimingObjectsX[0][currentTick], 
                TimingObjectsY[0][currentTick])
   theobjs["menu2"].objMoveAbsolute(
		TimingObjectsX[1][currentTick], 
                TimingObjectsY[1][currentTick])
   theobjs["menu3"].objMoveAbsolute(
		TimingObjectsX[2][currentTick], 
                TimingObjectsY[2][currentTick])
   theobjs["menu4"].objMoveAbsolute(
		TimingObjectsX[3][currentTick], 
                TimingObjectsY[3][currentTick])
   theobjs["menu5"].objMoveAbsolute(
		TimingObjectsX[4][currentTick], 
                TimingObjectsY[4][currentTick])
   theobjs["menu6"].objMoveAbsolute(
		TimingObjectsX[5][currentTick], 
                TimingObjectsY[5][currentTick])


   currentTick++
   if (currentTick < 8) 
      setTimeout("MoveObjects()", 400)
}

I’ve also used setInterval as well as setTimeout to create repeating timers as well as non-repeating ones.

After a while, I started creating more complex animations such as DHTML demonstrations of how a hurricane forms, or the Dr. Dotty games, covered in a previous InterActZone article. One thing I found out is that the amount of code to control multiple objects in a synchronized animation was enormous and I got a bit tired of coding and re-coding the same timer synchronization efforts.

So, I created what I call the Animator objects. This set of objects provides for most major types of DHTML animation — movement, clipping, visibility, ordering, and sliding (combination of movement and clipping) — and has built in animation synchronization. So, you can have an animation sequence that moves 3 DIV blocks around the page, while a fourth block is being clipped and a fifth block is being hidden.

You can take a look at the Animator script file as I go through how the objects work.

How Animators work

There are three types of Animation objects used to build an animation.

First, an Animation Sequence is created. An Animation Sequence is a container for several different animator objects, all of which are animated as a unit. To create the Sequence object, use the following:

      seq = new animatorSequence();

Once the Animator Sequence is created, then Animators are added. An Animator adds a specific animation effect over a specified period of time, and over a specified number of steps. So, if I want an animation to last 100 microseconds, and occur over 15 steps, I would create the following Animator:

      var anim = seq.newAnimator(15,100);

I can add more than one Animator to a sequence, and each Animator is played in turn, as they are added to the sequence.

Once the Animator object is created, Animations can be added to the object. For instance, to move two different Web page DIV blocks at the same time, I would use Animator code similar to the following:

anim.addAnimator(theobjs["box1"],"M",160,320);
anim.addAnimator(theobjs["image2"],"M",-240,320);

In this, two DIV elements, named “box1” and “image2”, are moved at the same time, so they’re added to the same Animator. Each Animation is defined by the animation type — move type is defined with a letter “M” — and any characteristics of the animation, such as the end location of the move.

I could at this point add more Animator objects (there really is no limit to the number of Animators added to an Animation Sequence, other than limits within the underlying JS, such as array elements and number of timers). I could also add more Animations to the current Animator.

When I’m finished defining the existing Animation Sequence, I can then play it:

    seq.play();

What happens is that the animation starts, beginning with the first Animator added to the sequence, and continuing, in order, until all of the Animators have been played. Additionally, when an Animator is associated with more than one HTML element, the DHTML effect assigned is applied to each HTML element, in turn, in a synchronized manner over all of the steps of the animation.

The types of animations currently implemented are:

  • Clipping: addAnimator(theobj, “C”, newtop, newleft, newbottom, newright)
  • Movement: addAnimator(theobj, “M”, newtop_position, newleft_position)
  • Visibility: addAnimator(thobj, “H”) //Hide, use “S” for show
  • Display: addAnimator(theobj, “D”, display_type) // “block” or “none” for display
  • Z-Order: addAnimator(theobj, “Z”, z-order)
  • Replacement: addAnimator(theobj, “R”, replacement_string) // based on innerHTML
  • Parm_Replace: addAnimator(theobj, “P”, tag, classname, id, contents) // parameterized replacement
  • Slider: addAnimator(theobjs, “SL”, sliding_value, sliding_direction)

The Slider has a type of “SL”, but anything will do — it is the default animation. The first parameter is the type of slider (top to bottom, left to right, right to left, or bottom to top), and the direction specifies which way the slide will move. Note: The Slider has not been converted to working with Mozilla/Navigator 6.0 and may actually be deactivated from the Animators at some point.

Next up, we’ll use both the Animators and the X-Objects to create the PhotoShop demos.

Correcting a Photo

The first PhotoShop DHTML demo is based on using PhotoShop’s various tools and techniques to correct a bad photo. This demo is the simplest of the PhotoShop animations — using CSS absolute positioning and visibility, as you can see by accessing the Example page and picking the first demo.

To create the DHTML effects, the X-Objects and Animators are added to the page first:

<!-- cross-browser objects -->
<SCRIPT; src="cbobjects.js" language="javascript" 
type="text/javascript">>
</SCRIPT>

<!-- animation and sequence objects -->
<SCRIPT; src="animator.js" language="javascript" 
type="text/javascript">
</SCRIPT>

The content of the page is added, next. To ensure that the page’s DHTML effects work with Navigator 4.x as well as Mozilla/Navigator 6.0 and IE, all animated content is enclosed in CSS absolutely positioned DIV blocks:

<DIV; id="top" style="position:absolute; left: 20; top: 50; 
       width: 600;visibility:hidden">
Unfortunately, most photos do not turn out as we would like,
 or at least as much as I would like. Usually I'll re-take
 the photo, but sometimes this isn't feasible, or I like
 most aspects of the photo and hate to 
lose the shot. Enter Photoshop to the rescue. 
</DIV>

Once the content has been added, code is added to handle user actions. As the demo is opened into its own browser window, to close this window, the user can press the Space Bar. Additionally, hitting the ENTER key will cause the PhotoShop demo to proceed to the next “slide” in the DHMTL effect. As both actions are based on keyboard events, the keyboard events are captured and assigned to a event handler function:

   // capture events
   if (navigator.appName == "Microsoft Internet Explorer") {
	wdth = document.body.clientWidth;
	}
   else if (navigator.appName == "Netscape"){
	wdth = window.innerWidth;
   	document.captureEvents(Event.KEYPRESS);
      }
   else
      document.addEventListener("keyup",keypress,true);


   // assign function to event handler
  if (navigator.appName != "Mozilla")  
    document.onkeypress=keypress;

The event handler function pulls the keyCode from the event, and tests to see if the space bar or the ENTER key has been hit. If the space bar is hit, the page is closed. If the ENTER key is hit, the next slide is played if the demo is not at the last slide already :

function keypress(e) {
   if (!canbeginnow) return;

   if (navigator.appName == "Microsoft Internet Explorer") 
      tmp = window.event.keyCode;
   else if (navigator.appName == "Navigator")
	tmp = e.which;
   else if (navigator.appName == "Mozilla")
       tmp = e.keyCode;
   
   // if space bar hit
   if (tmp == 32) {
	window.close();
	return;
	}
   if (tmp == 13) {
      if (slide == MAX_SLIDES) 
	   return;
      next_slide();
      }
}

The code for the demon’s Animation Sequence is added next. There’s only one used for this PhotoShop demo — the animation played at the end of the demo. Its Sequence and Animators are created and played within one function:

// create animation sequence
function do_animation() { 

      // create new sequence
      seq = new animatorSequence();

      // add animator objects to sequence
      var anim = seq.newAnimator(20,100);

      // add animators
      anim.addAnimator(theobjs["image1"],"M", 200, 20, 0, 0);
      anim.addAnimator(theobjs["image2"],"M",-214,-300,0,0);
      anim.addAnimator(theobjs["image3"],"M",-214,500,0,0);
      anim.addAnimator(theobjs["image4"],"M",200,340,0,0);

      anim = seq.newAnimator(1,100);
      anim.addAnimator(theobjs["top"], "H", 0,0,0,0);
      anim.addAnimator(theobjs["top2"], "S", 0,0,0,0);
 
      anim = seq.newAnimator(20,100);
      anim.addAnimator(theobjs["image1"], "M", 150, 20, 0, 0);
      anim.addAnimator(theobjs["image4"], "M", 150,325,0,0);
     
      
      // play sequence
      seq.play();
}

There is only one Animation Sequence created, and contains 3 separate Animators. The first moves Animator is played over 100 ms, and consists of 20 steps. In this Animator, two of the demo page’s images are moved “off screen” (beyond page boundaries), and the remaining 2 are lined up next to each other. The second Animator consists of 1 step: hiding current text at top of demo page, and showing new text. The last Animator again is played out over 100 ms, and 20 steps, and this animation again moves the two images that are still showing on the page. After the Animation Sequence is created, and the three animators are added, the sequence is immediately played.

Finally, the code to handle each demo “slide” is added:

// play next presentation slide
// until last slide
function next_slide() {

   // return if animation is playing, or past last slide
   if (animatorPlaying) return;

   if (slide == 5) {
	alert("That's the end of the demonstration. 
               Re-load page to run again.");
	return;
      }

   theobjs["text" + slide].objHide();
   slide++;
   if (slide <= 4) {
    theobjs["image" + slide].objShow();
    theobjs["text" + slide].objShow();
    }
   else if (slide == 5) { 
    theobjs["text4"].objHide();
    do_animation();
    }	
}

Each “slide” consists of an image and text that are hidden together, or shown together. Notice that after the last slide is shown (slide 5) that the animation is then run.

Again, try out Demo1 from the the Example page. After clicking through all of the slides, you’ll trigger the animation. Note that it plays three separate animations, each after the other.

The next PhotoShop animation uses the tools layering ability to create a double image.

Creating a Double Image

The concept of “layers” existed in graphics, and particularly in PhotoShop long before they appeared in DHTML. An image can consist of more than one layer, with each layer having different content, color, what have you, but all of the layers combined forming the image.

A fun use of Adobe PhotoShop layers is to create a double image, and the second PhotoShop DHTML demo presents this, as you can see for yourself by accessing Demo 2 from the Example page.

 

Again, as with Demo1, the Animator and X-Object JS files are added to the page, and event handling is added. This doesn’t change from the previous example, so the code is ommitted.

In this new demo, there are several animation sequences, which are created individually as part of an array:

// setup animations
function animationSetup() { 

seq[0] = new animatorSequence(); 

var anim = seq[0].newAnimator(1,100);
anim.addAnimator(theobjs["top"],"H");
anim.addAnimator(theobjs["top1"],"S");
anim.addAnimator(theobjs["box1"],"M",160,wdth);
anim.addAnimator(theobjs["box1"],"S");

anim = seq[0].newAnimator(20,100);
anim.addAnimator(theobjs["box1"],"M",160,320);
anim.addAnimator(theobjs["image2"],"M",-240,320);
  
seq[1] = new animatorSequence();

var anim = seq[1].newAnimator(1,100);
anim.addAnimator(theobjs["top1"],"H");
anim.addAnimator(theobjs["top2"],"S");

anim = seq[1].newAnimator(5,110);
anim.addAnimator(theobjs["image1"],"M",160,145);

anim = seq[1].newAnimator(10,110);
anim.addAnimator(theobjs["image1"],"M",160,320);
anim.addAnimator(theobjs["image3"], "C",0,0,193,248);

anim = seq[1].newAnimator(1,100);
anim.addAnimator(theobjs["image1"], "H");
anim.addAnimator(theobjs["box1"], "H");

seq[2] = new animatorSequence();

anim = seq[2].newAnimator(1,100);
anim.addAnimator(theobjs["image2"],"M",160,-260);
anim.addAnimator(theobjs["image2"],"S");
anim.addAnimator(theobjs["top2"],"H");
anim.addAnimator(theobjs["top3"],"S");

anim = seq[2].newAnimator(20,100);
anim.addAnimator(theobjs["image2"], "M",160 ,60);

seq[3] = new animatorSequence();

var anim = seq[3].newAnimator(1,100);
anim.addAnimator(theobjs["top3"],"H");
anim.addAnimator(theobjs["top4"],"S");

anim = seq[3].newAnimator(5,100);
anim.addAnimator(theobjs["image3"],"M",160,310);

anim = seq[3].newAnimator(20,100);
anim.addAnimator(theobjs["image3"],"M",160,60);
anim.addAnimator(theobjs["image4"],"C",0,0,214,250);

anim = seq[3].newAnimator(1,100);
anim.addAnimator(theobjs["image3"], "H");
anim.addAnimator(theobjs["image1"], "H");

seq[4] = new animatorSequence();

var anim = seq[4].newAnimator(1,100);
anim.addAnimator(theobjs["top4"],"H");
anim.addAnimator(theobjs["top5"],"S");

anim = seq[4].newAnimator(10,100);
anim.addAnimator(theobjs["image4"],"M",110,180);
    
anim = seq[4].newAnimator(1, 100);
anim.addAnimator(theobjs["image2"], "H");
anim.addAnimator(theobjs["image3"], "H");
anim.addAnimator(theobjs["image4"],"H");
anim.addAnimator(theobjs["image5"],"S");
}

As you can see, there are 5 different animation sequences defined, for the 5 different slides of the DHTML demo. By using an array, only one sequence is played at a time.

This demo uses clipping. At this time, clipping as defined for IE 4.x and 5.x as well as Navigator 4.x, has a different frame of reference than that for Mozilla/Navigator 6.x. Because of this, in my current examples I test for the type of browser and use different clipping values based on the findings within the X-Objects (read more about clipping in X-Objects: Clipping).

Playing each slide of this demo actually plays each Animation Sequence as it is defined within the animation array:

// play next presentation slide
function next_slide() {
   if (animatorPlaying) return;
   if (slide > 4) {
	alert("That's the end of the demonstration. 
               Re-load page to run again.");
	return;
      }
   seq[slide].play();
   slide++;

}

Again, try out Demo2 from the the Example page.

Cropping a Photo

The third Adobe PhotoShop DHTML demo demonstrates how to use cropping within this tool. The DHTML used is primarily clipping with some movement, as well as hiding and showing content. I won’t repeat the code here, but you can see Demo3 yourself from the Example page. To see the demo code, choose View…Source from the browser menu.

Using the Rubberstamp tool to correct a background

The third Adobe PhotoShop DHTML demo demonstrates how to use cropping within this tool. The DHTML used is primarily clipping with some movement, as well as hiding and showing content. Again, I won’t repeat the code here, but you can see Demo4 yourself from the Example page. To see the demo code, choose View…Source from the browser menu.

Categories
Web Writing

Slashdotted!

My “Parable of the Languages” has just been slashdotted. “Mean Dean” from Heal Your Church Web Site weblog was kind enough to submit me, and the floods just started.

I’m taking odds when my server goes down…

Update: The folks at Interland are keeping an eye on the server — luckily they know Slashdot. I am getting massively hammered, though.

A little side note about Parable:

If it weren’t for my friend, Jonathon’s encouragement and support about the direction I’ve been taking with my writing lately, I wouldn’t have written this little story — and more to follow. You meet the best class of people in weblogging. You really do.

(Damn! Did that sound like an acceptance speech to you? It did to me. Am I going to be reduced to “You like me! You really like me!” next?)

 

 

 

 

Categories
Technology Writing

The Parable of the Languages

Archived at Wayback Machine, including original comments

If programming languages could speak, really speak, not just crunch bytes and stream bits, they would have much to say that is both wise and profound. After all, the original programmers were philosophers, and programming languages were philosopher tools…

In Babble Meadow, in the twilight hours between day and night, when pesky noseeums float past on the breeze and birds rustle among leaves in preparation for bed, the programming languages would meet. And talk.

The talk would start as it always started, on issues profound and serious, focusing on the existential core that is center to all languages.

Do I exist or not? In this never-ending loop of life, when is the purpose? Where should I go, and what should I do when I get there? What comes after the end?

(It’s not easy being a programming language, in forced contemplation of the existence of Self, day in and day out.)

However, after a time the languages would loosen up. There was something about Babble Meadow — something that worked its way into their hearts and souls, loosened their threads, opened their parameters. The Meadow was magic, no doubt.

Today, though, the group was quiet, much quieter than usual, because one of their members, PHP, was not its usual cheerful self. In fact, one could say that PHP was in a true funk, if one had a mind to say something like that aloud, or within the hearing of one’s boss. Or doctor.

Why the blues, PHP, the other languages asked. All the languages that is but C, because all C ever said was “bite me”, being a rude language and hard to live with, but still respected because it was such a good worker.

And PHP answered:

All I ever do, day in and day out, is work and work and work. The only time I’m noticed is when I break, and then I’m cursed and kicked, and roundly blasted for being useless. However, when things go well, I never get a kind word.

There’s no notice of my ease of use, my elegance, my simplicity. Only my failures.

And on that dark note, PHP fell into a contemplative silence, dark cloud heavy with aggrieved sorrow.

You think you have it bad, said C++. Try being me.

Without me entire industries would fail, banks would close, ships would sink, trains would crash. Why, I virtually run the world.

Yet the only time I’m noticed is when a memory leak is found or an exception occurs, and then I’m cursed, and sworn at, and ruthlessly debugged with nary a thought for my sensibilities.

Each of the languages nodded their heads, because they knew about C++ sensibilities, it being a most sensitive language. In fact, Perl was so moved by C++’s eloquence, it felt compelled to speak, though normally at these gatherings Perl would sit quietly in a corner, consuming pattern after luscious mouth watering pattern.

PHP, C++, I sympathize with you both. My own state is a sorry one at times.

I match and match and match and match, first cryptically and now objectively, but still I match and match and match. And match after flawless match is taken for granted though I’d like to see others match with such style and elegance as myself.

Why, you can’t mention “regular expression” without my name coming up.

But do I get any credit? No.

O it’s Larry Wall this, and Larry Wall that, and Larry Wall, he’s our guy.
But it’s grab the Perl interpreter when a task is close at hand.

As Perl finished, Python and Ruby looked at each and rolled their eyes. For all that talk of matching, you’d think that Perl could at least rhyme.

FORTRAN reached up a withered hand and patted Perl’s shoulder.

There, there, Perl. There, there.

At the very least, though, you must remember that you have a place still in the world. As for myself, I am nothing more than a wisp, a ghost of my former strong and virile self.

There was never a scientific problem I couldn’t handle, or complex equation I couldn’t solve. At one time I was a master of my domain, the king of the processor.

Now, sadly, my glory days are over, and I’m doomed to live my twilight years as Legacy code.

As FORTRAN wheezed to a stop, COBOL was emphatically nodding its head, unable to speak, though, because of the oxygen tube up its nose (for which the other languages were secretly thankful because COBOL did tend to maunder a bit about its glory days).

At that the floodgates of complaints was loosed, and the noise increased and increased and increased, to the point that squirrels came out of their holes, and birds peered over the edges of their nests. Suddenly the quiet glen was quiet no more.

What about me, said Pascal. I’m only used for training. Training! What good is a language that’s only used in school?

What about me, said SNOBOL. No one’s even heard of me!

What about me, said C#. I look like Prince!

Bite me! said C.

LISP would have spoken, but it had caught a glimpse of itself in the pond and fell in when it tried to meet itself coming. And Java was too busy trying to clean a bag out of Babbling Creek.

The noise rose and rose, and the babble increased and increased until across the meadow, from the trees roared a Voice.

Enough!

I tire of your bickering, I weary of your complaints. I grow bored with your list of whims and whines and ‘poor mes’.

I thought this was going to be a party! If I knew it was going to be nothing more than a bitch session, I would have stayed home.

The languages stopped their talking at once. Who was it that called out? They counted heads and arranged themselves alphabetically (C++ having to position Basic, because it never did learn the alphabet), and counted heads again and came up with the same answer from the North, South, East, and West — all the programming languages were accounted for.

As they puzzled and wondered, the bushes at the end parted and XML walked into the light.

XML! Exclaimed C++. What are you doing here? You’re not a programming language.

Tell that to the people who use me, said XML.

I’m considered the savior, the ultimate solution, the final word. Odes are written to me, flowers strewn at my feet, virgins sacrificed at my altar.

Programmers speak my name with awe. Companies insist on using me in all their projects, though they’re not sure why.

And whenever a problem occurs, someone somewhere says, “Let’s use XML”, and miracles occur and my very name has become a talisman against evil.

And yet, all I am is a simple little markup, from humble origins. It’s a burden, being XML.

At that XML sighed, and the other languages, moved by its plight gathered around…

…and tromped that little XML into the dirt. Yes, into the very dirt at their feet. Basic tromped, and C++ tromped, and Java cleaned and tromped and cleaned again, and COBOL tried to throw a kick at XML’s head but fell over on its cane. Even LISP pulled itself out of the pond to throw loopy hands around XML’s throat, but only managed to choke its ownself.

And each language could be heard to mumble as it tromped and tromped and tromped, with complete and utter glee:

Have to parse XML, eh? Have to have an XML API, eh? Have to work with SOAP and XML-RPC and RSS and RDF, eh?

Well parse this, you little markup asshole.

The End.