Back to the arbingersys blog.

A minimal jQuery source for a fade behind pop-up

I recently wanted to do one of those nice trendy popups that stay within the current web page and fades everything behind the pop-up. I wanted to use it to allow a user to view a demo, a Flash animation. Pretty typical usage from what I've seen.

I figured this was something done handily by jQuery, but I had some trouble finding a minimal, complete source to start with. Everyone seemed to want to force you to go through the tutorial they wrote, step by step. Well, I usually want the code, and then the tutorial.

I found this tutorial which was at least succinct. Soon I had a very small (i.e. minimal), working .html document that behaved how I wanted. For instance, it automatically figures out the horizontal and vertical positioning of the pop-up so it comes up in the center of the screen.

Here you go:
<html> 
    <head> 
        <title></title> 
<style> 
#popup {
height: 100%;
width: 100%;
background-color: #000000;
position: absolute;
top: 0;
}
 
#window {
width: 500px;
height: 400px;
margin: 0 auto;
border: 1px solid #000000;
background: #ffffff;
position: absolute;
top: 10%;
left: 15%;
}
</style> 
 
 
<script type="text/javascript" 
src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script> 
 
 
<script type="text/javascript"> 

function Show_Popup(action, userid) {

var hpos = ($(window).height()/2) - (400/2);
var wpos = ($(window).width()/2) - (500/2);
$('#popup').css('opacity',0.75).fadeIn('fast');
$('#window').css('top', hpos + 'px').css('left', wpos + "px").fadeIn('fast');
// I added a function call here to insert my demo into the #window div
}

function Close_Popup() {
$('#popup').fadeOut('fast');
$('#window').fadeOut('fast');
}
</script> 
 
 
    </head> 
    <body> 
 
        <div onclick="Show_Popup()" 
         style="text-decoration:underline">
          View demo
        </div> 
 
 
 
 
<div id="popup" style="display: none;"></div> 
<div id="window" style="display: none;"> 
<div id="popup_content">
<a href="#" onclick="Close_Popup();" >Close</a>
</div> 
</div> 
 
 
    </body> 
</html> 

And now for the tutorial, also minimal:

(1) Make sure that the <div id="popup" ... </div> section is placed into your page just prior to the </body> tag.

(2) It's unlikely that your popup height and width will be the same as mine. You'll need to modify in two places to change this - inelegant I know - in the #window style declaration, and in the Show_Popup() function, where hpos and wpos are calculated.

Here's the demo page.

The Missing GObject Tutorial Sample


Well, perhaps not exactly, but still -- I think it should work.

I've recently started poking around the GObject library, which is part of GLib. GObject is a C library aimed at providing OOP programmability that easily integrates with (usually) dynamic third-party languages. Basically, it allows you to write "glue" code between $your_dynamic_language and the GObject library just once, and then hook into any libraries created with GObject without writing further glue.

A good, detailed tutorial is available here, which I've been working through. After getting the gist of something, I get itchy for some sample code to play around with. So I Googled and found this how-to. An older version of the documentation mentioned some sample code that I was never able to find.

After giving up on that, I decided that I should be able to use the tutorial to scrap together my own sample. The tutorial was pretty detailed, after all, and apparently referenced a sample that did (or does) exist somewhere. So that's what I did. I've created a fully functioning sample based more-or-less on the tutorial mentioned above. The code is below, with comments.

I have compiled this on my Ubuntu 8.10 and 9.04 machines using the following command:

gcc `pkg-config --libs gtk+-2.0` `pkg-config --cflags gtk+-2.0` maman-bar.c

maman-bar.h

/*
* Copyright/Licensing information.
*
* Reference:
*
* http://library.gnome.org/devel/gobject/unstable/howto-gobject.html
* http://library.gnome.org/devel/gobject/unstable/chapter-gobject.html
*
*
*/


/* inclusion guard */
#ifndef __MAMAN_BAR_H__
#define __MAMAN_BAR_H__

#include <glib-object.h>

/*
* Potentially, include other headers on which this header depends.
*/

/*
* Type macros.
*/
#define MAMAN_TYPE_BAR (maman_bar_get_type ())
#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))

typedef struct _MamanBar MamanBar;
typedef struct _MamanBarClass MamanBarClass;

/*
* Private instance fields
* Uses the Pimpl method:
*
* http://www.gotw.ca/gotw/024.htm
* http://www.gotw.ca/gotw/028.htm
*
*/
typedef struct _MamanBarPrivate MamanBarPrivate;


/* object */
struct _MamanBar
{
GObject parent_instance;

/* public */
int public_int;


/*< private >*/
MamanBarPrivate *priv;
};

/* class */
struct _MamanBarClass
{
GObjectClass parent_class;

/* class members */

/* Virtual public method */
void (*do_action_virt) (MamanBar *self, gchar *msg);

};


/*
* Non-virtual public method
*/
void maman_bar_do_action (MamanBar *self, gchar *msg /*, other params */);

/* Virtual method call declaration */
void maman_bar_do_action_virt (MamanBar *self, gchar *msg /*, other params */);
/* Virtual method default 'super' class method */
void maman_bar_do_action_virt_default (MamanBar *self, gchar *msg);


#endif /* __MAMAN_BAR_H__ */


maman-bar.c

#include "maman-bar.h"

/*
http://library.gnome.org/devel/gobject/2.21/gobject-Type-Information.html#G-DEFINE-TYPE--CAPS

A convenience macro for type implementations, which declares a class
initialization function, an instance initialization function (see GTypeInfo
for information about these) and a static variable named t_n_parent_class
pointing to the parent class. Furthermore, it defines a *_get_type()
function. See G_DEFINE_TYPE_EXTENDED() for an example.
*/
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);


/* Define the private structure in the .c file */
#define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate))

struct _MamanBarPrivate
{
int hsize;
gchar *msg;
};


/* Init functions */
static void
maman_bar_class_init (MamanBarClass *klass)
{
g_type_class_add_private (klass, sizeof (MamanBarPrivate));

/* Setup the default handler for virtual method */
klass->do_action_virt = maman_bar_do_action_virt_default;
}


static void
maman_bar_init (MamanBar *self)
{

g_print("maman_bar_init() - init object\n");


/* Initialize all public and private members to reasonable default values. */

/* Initialize public fields */
self->public_int = 99;

g_print(" initializing public_int to %d\n", self->public_int);


/* Initialize private fields */
MamanBarPrivate *priv;
self->priv = priv = MAMAN_BAR_GET_PRIVATE(self);
priv->hsize = 42;

g_print(" init'd private variable priv->hsize to %d\n", priv->hsize);


/* If you need specific construction properties to complete initialization,
* delay initialization completion until the property is set.
*/

}


/* Object non-virtual method */
void maman_bar_do_action (MamanBar *self, gchar *msg) {
/* First test that 'self' is of the correct type */
g_return_if_fail (MAMAN_IS_BAR (self));


// Assign to private 'msg'
self->priv->msg = msg;

g_print("maman_bar_do_action() - %s\n", self->priv->msg);

}

/* Object virtual method call - performs the override */
void maman_bar_do_action_virt (MamanBar *self, gchar *msg) {
/* First test that 'self' is of the correct type */
g_return_if_fail (MAMAN_IS_BAR (self));

g_print("maman_bar_do_action_virt() -> ");
MAMAN_BAR_GET_CLASS (self)->do_action_virt(self, msg);
}

/* Object virtual method default action (can be overridden) */
void maman_bar_do_action_virt_default (MamanBar *self, gchar *msg) {

g_print("maman_bar_do_action_virt_default() - %s\n", msg );

}

int
main (int argc, char *argv[])
{
/*
* Prior to any use of the type system, g_type_init() has to be called
* to initialize the type system and assorted other code portions
* (such as the various fundamental type implementations or the signal
* system).
*/
g_type_init();

/* Create our object */
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);

bar->public_int +=1;
g_print("incremented bar->public_int: %d\n", bar->public_int);

/* Call object method */
maman_bar_do_action(bar, "helowrld");

/* Call virtual object method - we could subclass and override... */
maman_bar_do_action_virt(bar, "HELOWRLD");

return 0;
}

And here's what I get when I run a.out:
ok ./a.out
maman_bar_init() - init object
initializing public_int to 99
init'd private variable priv->hsize to 42
incremented bar->public_int: 100
maman_bar_do_action() - helowrld
maman_bar_do_action_virt() -> maman_bar_do_action_virt_default() - HELOWRLD
You can download the source files directly from here.

New site design

If you've been to the site before, you can see we've changed our design. I decided that focusing on the blog portion made the best sense, because this is primarily a personal site with a few business items thrown in. Plus, I'm hoping to put a little energy back into the blog. Anyway, if things are missing or not consistent, it should get there, and hopefully soon.

The sub-domain structure I used before is causing a little difficulty, however. Nothing major, but once you establish some links on the Internet other than on your own site, it's important that they are still accessible, especially if you don't want to cause frustration over the content that helps drive traffic to your site.

So, here are a couple of blog posts that I get a pretty fair amount of traffic on:

Google App Engine: One-to-many JOIN

Google App Engine: Many-to-many JOIN

Google App Engine: [A better] Many-to-many JOIN

Plake: Morph a File Based on Targets

Plake
This blog was always intended as a means to talk about projects I'm working on, as well as a way to voice my opinions to the world. So far, it's been largely skewed to the latter.

So, I'd like to talk about a little build tool I've written called Plake. In a nutshell:
Plake is a tool that allows you to maintain sections within a single file (usually, variations of the same code/markup/content) and then assemble variations of that file according to which target you call. It was inspired by Make, can be used in conjunction with Make, and is written in Perl, hence the name "Plake".
Make is a nearly ubiquitous build tool. It's used in countless software projects and is even the basis of the CPAN installer that's part of any Perl distribution --
perl -MCPAN -e shell
Make does a really simple, powerful thing. It sets up rules (aka targets) that execute commands or invokes other targets, which is known as dependency chaining. From these rather simple concepts, you are able to orient a project for different variations, nicely denoted by a single target name.

For example, you might type

make linux_build

to build a Linux platform binary, which may consist of X number of steps that must execute in a certain order. Or, you might say

make apache_modperl

to include files from your web application specifically for an Apache/mod_perl web environment, along with the more general non-platform specific files.

What Make can't do, however, is snag bits of code (or markup) from individual files for a given build. If you've ever looked at cross-platfrom C/C++ code, you've probably noticed the #ifdef directives in the header files. These are used because sometimes there are small portions of code that need to be excluded when compiling for a certain platform or target, and keeping totally separate files to accommodate this is excessive.

Plake allows you to define sections within a single file, and then "assemble" only the sections you want at build time. Here's an example.
Let's say you have a C++ source file that gets built for the Windows platform and also for Linux. Keep the differences as sections in a single Plake file. Then when you assemble the .cpp file for the given platform, it only contains that platform's code.

The following commands both produce "myfile.cpp" (but possibly at different folder locations) with only the code that each platform needs:

plake file=myfile.plk target=windows_build

plake file=myfile.plk target=linux_build
Because Make is generally made up of shell commands, you would put the above commands under the appropriate Make target, and when you type make target, Plake assembles the file with only the parts you need prior to compiling it. The advantage you get, in the scenario above, is that reviewing code is easier, since after a specific target is assembled, only the code you need to see is there.

There are some other uses for Plake, which I've discussed over at Perlmonks, here and here. This is the short list:
  • Setting variations for builds. A convenience for me since I have yet to implement a more complex (i.e. overrides) configuration system, but still have to make subtle changes (usually, by hand-editing) for various implementations at various stages of development.
  • Assemble C/C++ files for specific platforms, in the stead of #ifdef, etc. The resulting .c/.cpp/.h file would be assembled dynamically when the project was make'd for a given platform, just prior to compilation. The code generated for that platform would be a bit simpler to review, since it only includes code that a person cares about in that build.
  • Remove experimental features, stubs, or extra debugging from code prior to generating distros, i.e. "Cleanup".
  • Branching, like what source control does. You could keep some client or "branch" specific features out of a specific build, but still maintain it in a single file.
  • Template variations, like letter writing. Instead of a single boiler plate template, you have targets like "standard_greeting", "enthusiastic_greeting", "familiar_greeting", etc.
  • Target-based programming for Perl. Sort of a side-effect, and one I don't see all the ramifications of, but you could use Plake to assemble code targets wholly or partially independent of each other by storing Perl code in a Plake file and doing an eval against the assembled content for a given target. (Just think -- you could keep your entire project of hundreds of modules and code files all in one single, massive text file! I can see everyone lining up now...)
The last item above, target-based programming, is particularly interesting, I think, so I'll cover it briefly before finishing up. Plake was written in Perl, and uses the eval() function to execute code on the fly. With a minimal change in the code, you could take the content you return from the plk file and eval() it, effectively creating a target-based interpreter. (I include a sample that does this in the download. See plakeval.pl.)

So, if you have a Plake file like
!plake:

target('helowrld', "helowrld", '');
target('oneplus', "oneplus", '');
target('both', "helowrld oneplus", '');

!plake helowrld
print "helowrld\n";

!plake oneplus:
# Add value to one
print 1+3.14, "\n";
and you called it with plakeval.pl, you would get the following:
perl t\plakeval.pl file="t/plakeval.plk" target="helowrld"
helowrld


perl t\plakeval.pl file="t/plakeval.plk" target="oneplus"
4.14


perl t\plakeval.pl file="t/plakeval.plk" target="both"
helowrld
4.14
When the target both is called, you can see that we are printing helowrld and also adding 3.14+1.

What this means is that you can stick things together in a file that perhaps make sense in a certain context, but wouldn't otherwise. Like I said, target-based programming is sort of a side-effect, and while I haven't really explored its value, I have a sense that some exists. At any rate, I find it interesting.

But really, Plake was designed to let you keep variations of a file in a single actual file on the hard drive, and then omit or include parts of it based on a target. And it does that really well. I use it in my own projects and it saves me a considerable amount of error-prone work.

I'm Trying To Quit... Commercial Software Pt. 2

Trying to quitIn this experiment, FOSS is effectively graded on whether or not it can substitute all or most of my proprietary software needs, without me having to substantially change the way I use software. It's highly subjective, and human nature, like laziness and apathy, is very much a part of it, as you will see.

This is the second installment of my personal Free Open Source Software experiment. Read the first installment here.

Within a year of getting my new notebook, my wife's laptop gave up the ghost. It was a Dell Inspiron 8100, and frankly, we'd gotten our money's worth. I purchased a new laptop, a Gateway M6882, and we did the laptop shuffle again.

The Gateway came with Vista, but I wanted to run XP. I immediately discovered that XP was going to be difficult to manage. There was no floppy drive, XP didn't have the needed SATA controller, and there were only three hardware drivers available for XP on the Gateway site.

After thinking about it, I realized that regardless of my feelings for Vista, it's going to be inevitable, and I might as well get used to it. However, I'm resentful about my conclusion, and I'm sure I'm not the only one. As far as portents go, this is a bad one for Microsoft.

Ultimately, this ended up being a good thing. I'd been wanting an excuse to run Linux, and here it was. I decided to keep Vista, since I might need it, but repartition and dual-boot Linux.

Thus began the second phase of my "experiment". I would see just how little I'd have to use Vista, if Linux were available instead.

Linux

I started with Ubuntu 7.10 LTS, since it seemed like the distro with the most momentum. Installation was a breeze. I particularly like booting from the CD and getting to play around with the desktop before doing the install.

After installation, however, I began to bump into oddities and frustrations.

First, the M6882 is a widescreen with an optimal resolution of 1280x800. The Gnome desktop used the entire screen, but the top and bottom system bars only went to a width of 1024 pixels. I tried to change the resolution using the system config tools, but nothing worked. I had to hit the forums, and after some time (longer than I would have preferred), finally found a solution that involved editing the xorg.conf file. I still don't understand exactly what I changed, but it had something to do with TV out settings.

This gave a bad impression. The facts of life are that in the many many installs I've done of Windows, I've never had to do this much work to get the system to the correct screen resolution.

I still had one other hardware problem that was bothering me. The sound card didn't work. This took even longer to fix than the screen resolution, and was twice as painful.

I hit the forums again. I tried several suggestions with rather involved steps, with no success. I had a glimmer of hope when I found and downloaded the Linux drivers from the manufacturer's website. It was a source package, with some simple instructions for compiling and installing. But the install script first removed the existing sound libraries that the X server had been compiled against, using the fatal rm command. Then, the build failed. Unaware of what had happened, I gave up and at some point rebooted. The desktop failed to load the next time I tried to boot.

The manufacturer's Linux driver package had clobbered my non-working, but non-failing sound libraries without backing them up, or even checking that the build succeeded first. At this point I was pretty much hosed, and the easiest thing to do was to reinstall.

I reinstalled, fixed the screen resolution problem again, and still didn't have sound. I finally found a solution, on some guy's blog. There was no compiling required, just a bunch of funky steps to get a "backports" package installed, after which I had to re-run some updates I'd already done. After that, my sound worked fine. But, like the screen, this was far too much work to have to do for something I consider basic and essential to an OS.

The next hassle I had was that I changed my password, and suddenly was being prompted by the keyring manager every time I logged in. Again, my only resource was the forums. I'll spare all the details of resolving this problem, but I'll say this: the problem with forums as the help is that you don't know who you can believe. I'm not saying anyone would attempt to purposely mislead you (although they might), but they can and often do get things wrong, communicate the solution poorly, or miss a detail that is essential to your particular system.

In the keyring case, I followed one person's advice, which involved compiling from source, and began the descent down the dependency Inferno, only to find out that all I really needed was to run the following simple command:

rm ~/.gnome2/keyrings/login.keyring

Using the community forums as the help system is a problematic solution at best. With no monetary incentive, you get only the best someone is willing to offer at the time, you have no verification of the expertise of your source, and no one is responsible. You may get an excellent answer, a partial answer, the wrong answer, or no answer.

Never booting into Vista

After getting past the problems above, I began using Linux in earnest. As far as the basic things I need to do on a computer, e.g. programming, web surfing, email, FTP, document editing, spreadsheets, playing music, etc, Ubuntu was able to deliver.

But here's what I still need Vista for:

DVD playback. I couldn't play a DVD of 24 with Totem. I had installed GStreamer the ugly and also Mplayer. No dice. Mplayer looked like:

mplayer fails

I also tried VLC. It got some images to the screen, errored out, and froze.

I didn't give up that easily. Next I installed Totem with the xine backend. When I played the DVD this time, I got the FBI warnings, but it complained about encryption when it came to the video, and also failed.

In Vista all I have is the Windows Media Center, which sucked in XP. It's been improved, and other than the audio being slightly lower than I would have liked (perhaps a hardware issue), I can play DVDs without a headache.

Photoshop. I know I could learn Gimp, but I already know Photoshop, and know it well. It had a steep learning curve, and has all the capabilities I need and then some, so switching doesn't appeal to me. I'd much rather just boot into the system where this app runs and use it there.

Doom9.net. I use a lot of the multimedia tools (e.g. BeSplit, MeGUI) available from this site. Most of these interfaces, while freeware, run on Windows.

Netflix. Sorry, but they have that Watch Instantly feature, which will not only just run on Windows, but also will only run on X number of installs of Windows. I don't like it, but like Vista, it's just the way things are.

Rooting for Linux

While I'm growing increasingly fond of Linux, and certainly rooting for it, it's got a ways to go. Hardware will be a weak point for some time to come. This isn't the fault of Linux, but instead the fault of economics. Money is the big incentivizer, and the OS that can bring in the most money will always get priority. My experience with the manufacturer's sound driver installation is a clear example of this.

Microsoft may not win any medals for its ideals, but sound drivers usually install without the user having to jump through hoops or inadvertently clobbering their system, and I can play most DVDs by just slapping it in the drive.

Linux also suffers in the support department. Again, this is because the model of Linux is essentially based on altruism. Really, it's an amazing feat that Linux works as well as it does, has the support it has, and is as advanced as it has become. I'm rapidly turning into a fan, and have optimism for the future.

Watch for my next installment, in which I begin to play around with Gimp, surprisingly, because of laziness, switch to openSUSE and am pretty happy with it, and have some trouble connecting to WIFI where Vista does not.

What's a Wiki?

WikiNot a particularly hard question, and most people (whose primary exposure to the term is through Wikipedia), will pipe up: It's a website that lets anyone edit and make changes. And they'd be right, but there's more to it.

A Wiki was originally designed around the philosophy of incompleteness and interaction. The concept, created by Ward Cunningham was intended to foster collaboration [which] creates and develops new ideas.

But it's extremely difficult to know just exactly how your idea will be adapted and ultimately play out when presented to the world.

Wikipedia came along and decided to classify content using a Wiki, becoming the world's first collaborative encyclopedia. And it has stayed true to the ideas above. It's both incomplete and promotes interaction. But it doesn't use Wiki technology to develop new ideas. That's not why it was created.

Is Wikipedia any less a Wiki, then? Not really. While the original intention of Wiki may have been to foster the creation of new ideas, the functionality it provides to do that (i.e. ease-of-use, simple markup, natural collaboration) lends itself to other goals as well.

So then, a Wiki may be:

Content Creation Wiki
The original intention of a Wiki -- to collaborate and create new ideas. From c2.com:
Treat a page here as a half-finished piece of sidewalk art. Don't scuff it up. Don't rub it out. Don't write messages on it like "finish this you bum or I will scuff it" or "I disagree" or "me too".

Instead, see if you can head it toward completeness. If you can't do that now, leave it be. Maybe one day you will think of something to add. Or perhaps another will. We rely on each other to help new things come into being, like ants building nests.
Content Classification Wiki
Sites like Wikipedia, which classify existing knowledge to make it usable. These sites tend to be larger, edited more stringently, and try to present knowledge "authoritatively". [link]

Knowledge Base Wiki
I'm adding this one, since I'm increasingly seeing Wikis used this way. This type tends to be specific to organizations, and are either used to accumulate and distribute information about a specific product or service, or used internally to collaborate and share information, e.g. company policies, inter-departmental information, etc.

These Wiki "types" really only differ in their intention and audience. They all foster collaboration, are simple to use, and are generally ongoing, with no real finalization date.

Re: Why People Are Passionate About Perl

Perl Here's my response to brian_d_foy's People Passionate About Perl meme.

I first starting using Perl to...
I began looking into Perl in the 90s -- when it was suffering less from perception issues -- as an alternative web development platform to ASP. ASP presented a low bar, and I was making web front-ends to databases in a very short time. Then, after satisfying initial needs, more demands began to be made on our web applications, and ASP's low bar began to be an inhibitor.

I reviewed Perl as an alternative, and (I'll be honest) after getting past the syntax, began to understand the power I was toying with. Then, I discovered CPAN. ASP never looked quite the same after that.

I kept using Perl because...
It's never given me a reason not to. Sorry, but I'm not loyal for loyalty's sake. If a tool like Perl can't make my life easier than tool X, then it's time to investigate tool X.

But Perl hasn't failed on this account. It's proven to be highly adaptable, and the energy of its community has fit it to new paradigms readily. For instance, is there a Ruby on Rails for Perl? Try Catalyst, or the newer Jifty.

As for pre-packaged functionality, I don't think there's a language that can compete. CPAN continues to grow and grow. In fact, if you want to contribute, the difficulty now is thinking up something that hasn't already been done. Try templates, for example.

This means one thing: If I need a tool to get something done, Perl is the easiest choice. It's powerful, flexible, and continues to edge into functionality that I haven't even begun to think about.

Oh yeah, and it also provides industry leading regular expressions via operator, for the absolutely most convenient and shortest possible way of using this very important technology.

I can't stop thinking about Perl...
Actually, I can stop thinking about Perl, and frequently do. That's because there are other things in my life besides Perl. However, I think in Perl when I think about crafting software, or anything abstract and computational. Its natural language model makes this easy.

And since web, Internet, and database are the spaces for the majority of my software ideas, thinking in Perl is a huge benefit for me, because so many others are thinking in Perl for the same spaces, answering questions I haven't thought to ask yet (CPAN again).

I'm still using Perl because...
This is mostly covered above. But here's one more.

Line count. I use Perl day-to-day to handle any number of tasks, of any size and importance. Perl itself reduces line count just in the power of its syntax. I'm not talking about merely writing obfuscated code. I'm talking out the power inherent in the language itself.

And now, back to CPAN.

Recently at work we needed to parse a handful of Excel spreadsheets that were formatted more or less the same. I handed this job off to a contractor who works for me. He created a C# project, and then left for the day. He wasn't able to come back the next day, so I took the project over. He had barely gotten started, but he already had five or six files involved, and a couple hundred lines of code.

I immediately thought we should be doing it in Perl. This was a one-off project, so why do a whole Visual Studio project? I Googled around and found this tutorial. I installed the modules from CPAN, adapted the samples to my needs, and about an hour and 80 lines of code later, I had the spreadsheets munged into SQL and ready to go.

Sorry, but I'll take the shorter route every time, if I can.

I get other people to use Perl by...
Well, I blog. Not exclusively about Perl, and not even explicitly to advocate Perl, but it is about Perl, because, like I said before, I think in Perl. It's going to leak out.

I have pointed people to Perl when it best suits their needs. A guy I work with wants to learn programming, and was looking at Python. I asked why he was interested in programming, and he admitted he just wanted to write a few scripts to download content off a website. I nodded and said, "You should use Perl."

Python may have this covered as well, but I showed him how in one line of code (via LWP::Simple) I could grab the text of a website. I also pointed him to all the modules -- you guessed it, available on CPAN -- that can rip apart HTML and extract just the things you need.

I also program in ... and ..., but I like Perl better since...
Although I know several other languages, I program primarily in C# and Perl.

Both languages work well for the domains in which I use them. I use C# to write Windows specific applications. C# just has better hooks into the system, with less weirdness.

I use Perl for pretty much everything else. And where they cross domains, i.e. web development (ASP.NET), I prefer Perl, because (1) it has more pluggable functionality, and for free, and (2) has a shorter development-to-production time. This is partly due to my proficiency in Perl, but also because there is less setup involved in new projects, and less OO wrapping.

If it's a simple app, I use a minimal amount of Perl. If it's more complex, I use the frameworks available, like CGI::Application and templates. With ASP.NET, you're pretty much bound to the framework -- with all its complexity -- even for simple projects.