Monday, May 15, 2006

A simple user login and registration system

The GMTT Lite Login System is a wonderful little easily understood piece of code. There's a lot of other good stuff on the site, but it's being rebuilt so you have to navigate arounda bit from the front page to find it.

Wednesday, May 03, 2006

Programmer’s Critique of Joomla

Ten reasons Joomla!/Mambo is an outdated CMS

[From: "RipperDoc’s Clinic, Dissecting just about everything, live from Hong Kong, China"]

"Having recently been working intensely with Joomla!, and in the same time with Wordpress and some AJAX-development I have come to the following conclusion: Joomla!/Mambo is outdated. It has moved from being cool and hot to being mainstream, boring and just old…here is my list of reasons that it’s outdated…”

“The layout is based on tables.”

[Shouldn't the parts of a Content Management System be distributed as follows: content [database], presentation [template file], and control flow [program file]?]

“It is also very cluttered and when making a template, you have very little control on how system outputted data should be displayed.”

[The template tags in Movable Type and Wordpress REALLY DO separate the data and presentation layer]

The templates and style sheets tend to be large and cluttered, with heaps of different, class names, often confusingly named.

[Again template tags]

“The administrative interface is slow and not very user friendly.”

[Modules seemed easy to handle. components couldn’t figure out]

“You can still not sort tables after columns, even though they look sortable. You often get stuck by pressing back and getting the message “Do you want to resend the POSTDATA?”.

“Some simple AJAX and usability thinking would make the interface much better. “

[Usability for sure, but not really sure how making it asynchronous would make it simpler]

There is a plethora of templates and plugins, but it’s very hard to find good ones. Many plugins are badly developed, very specialized or cost money. When searching for templates you get hundreds of sites selling templates but not looking very trustworthy.

[One plug and play module with functionality (poll, login, quiz...) that you can put in any CMS block (left, top, right, center) that can be used in any CMS, Joomla, PostNuke, Wordpress…]

“Of course, the fork has caused greats problem. Plugins are being shifted from Mambo to Joomla, some deprecated, and the confusion is considerable.”

[It confuses me, but its free, how can I complain?]

“This is very different from the Wordpress community, where most plugins are of high quality, and where you quite easily can find the plugins thanks to the blogging community.”

[Wordpress looks like it has everything and the registration is in one non-OO file, I’m going to try this]

“The code base is huge and the API is complicated and often inconsequent. Just getting the right information as a developer is a challenge. To add to this, the balance between backwards compability and refactoring is a constant issue, and it seems Mambo is always somewhere in between, in the bad sense.”

[Getting right information, that’s it. Wasted a lot of time. Just going to use a debugger.]

“The whole CMS package is big and bulky, and so is the system itself. It’s often slow, either in loading or in finishing administrative tasks, due to many page loads until completion of a task.”

[Is Wordpress or any PHP system really any faster?]

“The category system is inconseqent, having sections, with categories, but no more sub levels. Add to this components with their own separate systems. This needs a real cleanup. The same problems occur in the user management system, with a rigid hiearchy of ACL that is buggy and not used everywhere… Where is the social collaboration in Mambo… “

[Make the content taggable with multiple key words, so it can role up into different semantic hierarchies]

"Development is very slow. It takes months and months to make just a slight update, which mostly consists of bug fixes. The whole mess around the forking of the code into Joomla! also made a halt in the progress. My guess is that the code base is cluttered and makes it hard for developers to quickly add features, especially when having to consider backwards compability."

"I admit, I have compared with Wordpress in many of these issues. And Wordpress is a clear role model, but it is a blog system, not a full-fledged CMS. Even though Wordpress can be a CMS, with some plugins, it’s not optimal. Where are all the modern and original CMS:es? There must be a huge user base that’s craving something new, light-weight, easily integrated and extendable?"

[Seems like Wordpress. I’ll give it a try. Don’t mean to be negative, but need something simple to understand]

Choosing a PHP Debugger II

The Eclipse IDE (Integrated Development Environment) with PHP plugin seems like the best option for stepping through CMS execution to see how control flow and variable scope works.

The combination must be widely used since there is even an acronym for it AMPLE (Apache Mysql PHP Eclipse) programming.

Confusing mix of object-oriented and imperative programming

There’s a confusing mix of imperative and object-oriented PHP in the registration module. What’s confusing is that in the object-oriented presentation layer I have to make a call back to the non-OO data layer to look up the subscriber id in a table.

I’m running it under PHP 4 also. I thought PHP 5 was object oriented? What’s up? So I guess I have to find out what PHP 4 OO programming was. Luckily there’s a little article by the authors of PHP themselves.

To understand what is happening I’ve also started to recall those old ideas from the theory of programming languages: variable scope and control flow (as well as the Scheme concepts of closures and continuations that help make sense of the most difficult aspects like non-local control flow and scope in objects).

Anyway don't mean to be negative, but I am going to make sense of this stuff, and this blog is going to record the steps I take to understand it.

Tuesday, May 02, 2006

Debugger to follow control flow and namespaces with

I can already see that I'm going to need a PHP debugger since I can print variables out to the Joomla webpage. It will also show what namespaces are defined in any given part of a program and also show me control flow.

Wikipedia has a list of PHP editors and debugger front-ends.

What debugger to choose?

I downloaded Activestate's Komodo IDE to check out first.

Modifying the registration component II

Control flows from registration.php to registration.html.php, from the data layer to the presentation layer.

registration.php just has functions, no classes.
registration.html.php has one big class in it called HTML_registration.

The main switch statement in registration.php calls registerForm below.

The data layer function registerForm calls the presentation layer function registerForm: HTML_registration::registerForm($option, $useractivation);

Control then passes to the validation if-statement that I'm modifying.

If I define the function subscriber_exists() and the constant _REGWARN_SUBSCRIBER in registration.php it should be available inside the class HTML_registration?

registration.php:


function registerForm( $option, $useractivation ) {
    global $mainframe;
    
    if (!$mainframe->getCfg( 'allowUserRegistration' )) {
        mosNotAuth();
        return;
    }
    
    $mainframe->SetPageTitle(_REGISTER_TITLE);
    
    HTML_registration::registerForm($option, $useractivation);
}



registration.html.php:


function registerForm($option, $useractivation) {
    ?>
    function submitbutton() {
        var form = document.mosForm;
        var r = new RegExp("[\<|\>|\"|\'|\%|\;|\(|\)|\&|\+|\-]", "i");
        
        // do field validation
        if (subscriber_exists(form.subscriberid.value)) {
            alert( "<?php echo html_entity_decode(_REGWARN_SUBSCRIBER);?>" );
            } else if (form.name.value == "") {
            alert( "<?php echo html_entity_decode(_REGWARN_NAME);?>" );
            } else if (form.username.value == "") {
            alert( "<?php echo html_entity_decode(_REGWARN_UNAME);?>" );
            } else if (r.exec(form.username.value) || form.username.value.length < 3) {
            alert( "<?php printf( html_entity_decode(_VALID_AZ09), html_entity_decode(_PROMPT_UNAME), 2 );?>" );
            } else if (form.email.value == "") {
            alert( "<?php echo html_entity_decode(_REGWARN_MAIL);?>" );
            } else if (form.password.value.length < 6) {
            alert( "<?php echo html_entity_decode(_REGWARN_PASS);?>" );
            } else if (form.password2.value == "") {
            alert( "<?php echo html_entity_decode(_REGWARN_VPASS1);?>" );
            } else if ((form.password.value != "") && (form.password.value != form.password2.value)){
            alert( "<?php echo html_entity_decode(_REGWARN_VPASS2);?>" );
            } else if (r.exec(form.password.value)) {
            alert( "<?php printf( html_entity_decode(_VALID_AZ09), html_entity_decode(_REGISTER_PASS), 6 );?>" );
            } else {
            form.submit();
        }
    }

Modifying the registration component (com_registration)

Today I decided to jump straight into the the registration component and modify it.

The form-validation if-statement in registration.html.php listed below was quick to modify. Now I have to decide where to define the two things I'm adding:

1. The subscriber validation function: subscriber_exists($id)
2. The error message constant: _REGWARN_SUBSCRIBER

The function does a database lookup so I guess I got to put it in the data later: registration.php, not the presentation layer: registration.html.php , but there are no obvious examples to follow. Going to have look it over and make a reasonable guess.


function submitbutton() {
    var form = document.mosForm;
    var r = new RegExp("[\<|\>|\"|\'|\%|\;|\(|\)|\&|\+|\-]", "i");
    
    // do field validation
    if (subscriber_exists(form.subscriberid.value)) {
        alert( "<?php echo html_entity_decode(_REGWARN_SUBSCRIBER);?>" );
        } else if (form.name.value == "") {
        alert( "<?php echo html_entity_decode(_REGWARN_NAME);?>" );
        } else if (form.username.value == "") {
        alert( "<?php echo html_entity_decode(_REGWARN_UNAME);?>" );
        } else if (r.exec(form.username.value) || form.username.value.length < 3) {
        alert( "<?php printf( html_entity_decode(_VALID_AZ09), html_entity_decode(_PROMPT_UNAME), 2 );?>" );
        } else if (form.email.value == "") {
        alert( "<?php echo html_entity_decode(_REGWARN_MAIL);?>" );
        } else if (form.password.value.length < 6) {
        alert( "<?php echo html_entity_decode(_REGWARN_PASS);?>" );
        } else if (form.password2.value == "") {
        alert( "<?php echo html_entity_decode(_REGWARN_VPASS1);?>" );
        } else if ((form.password.value != "") && (form.password.value != form.password2.value)){
        alert( "<?php echo html_entity_decode(_REGWARN_VPASS2);?>" );
        } else if (r.exec(form.password.value)) {
        alert( "<?php printf( html_entity_decode(_VALID_AZ09), html_entity_decode(_REGISTER_PASS), 6 );?>" );
        } else {
        form.submit();
    }
}

Monday, May 01, 2006

Reasonable people can't understand Joomla

I posted the following to OpenSourceCMS. I haven't given up on Joomla! (as if anyone cares) and when I am finished mastering it, I am going to create some documentation that describes the big picture because the details are pretty intuitive already. If they don't want it on the Joomla! site, I'll just stick in this blog, which can double as a general web publishing platform (if you pre-date entries to the very beginning of the blog and then put links to them in the right sidebar):

Two quotes from people who have been having problems with Joomla! documentation:

"I must say that if the team behind Joomla, and also the other developers that use it, want to see it beeing widely used and really apreciated by the rest of us an effort torwards clear, adequate and effective starting documentation must be in place. I would love to start using it, since there are so many good opinions about its strengths, unfortunatly good documentation not being one of them."

"I'm a programmer and ever reading through what little documentation I could find I still could not get the site configured in any sort of decent manner."

I agree. I've had a hard time customizing it without delving deeply into the code. I can actually write what I need in fairly simple PHP so I think stanadalone system is the approach I'm going to take unless I can find a simpler system to customize.

The incredibly rude replies are probably by people who've never had a job in their life or incredibly socially inept.

REALITY: Increasingly non-programmers or programmers who have a only a limited amount of time to spare from other duties are being called on to customize CMSs. CMSs that adapt themselves to these peoples' needs will survive, those that don't, won't. The documentation doesn't explain the big picture of how the whole thing operates. Once you know the big picture, everything else should be common-sense. Movable-Type is an example of a CMS like this. The presentation of content on web pages also usually violates long established principles. Take for instance, Anna's Joomla! Tips which should be in h2 or h1 and visible on this page when it displays without scrolling:

http://forum.joomla.org/index.php/topic,5503.0.html

Jon Fernquest
http://joomlafordummieslikeme.blogspot.com/
Posted by Jon Fernquest on Monday, 01 May 2006 at 1:43

Sunday, April 30, 2006

Making sense of components II

There are some confusing things about components. My personal approach to figuring out how a system works without manuals is to poke around the system looking at menus, the database, and source code files looking for patterns and consistencies. Gotta admit it didn't help much this time. Going to dig a little deeper, like right into the guts of the code, I guess. Trying to find patterns, here's what I found:

There are 14 components in the component directory:

com_banners
com_contact
com_content
com_frontpage
com_login
com_messages
com_newsfeeds
com_poll
com_registration
com_rss
com_search
com_user
com_weblinks
com_wrapper

But only 10 of the 14 components are used in the jos_components table:

com_banners
com_weblinks
com_contact
com_frontpage
com_poll
com_newsfeeds
com_login
com_search
com_syndicate
com_massmail

And it is not one row per component as you would expect like it is in the modules table, so how do I know if the component install was successful? Isn't the component officially recorded somewhere in the db at install time?

The even more important question is: what do I do with the component after I install it? Connect it to the main menu would be a reasonable thing to do.

Menu -> Main Menu -> New -> [check component] Next

Gets you to: Add Menu Item :: Component

How do you get your new component to show up in the little list of components on this screen? Only 7 of the 14 components can be found there:

Contacts
FrontPage
Login
News Feeds
Polls
Search
Web Links

It's also worth noting that only x of the 14 components display on the Components menu in Administration:

Banners
Contacts
Mass Mail
News Feeds
Polls
Syndicate
Web Links

Making sense of Joomla! components I

What was I thinking? I want to create my first new component. What do I do? Clone it, of course. Take com_content let's and change everything to com_content2. Immediately there's a problem. No content.xml install file, so I clone one I already have.

I zip the three files together using this free zip utility, a Winzip clone. Then I get error messages indicating that I got to stick the xml file in the directory ../joomla/media/ so I do this and no error messages, so I guess it's installed, but how do I really know. There doesn't seem to be a master list of all the components anywhere, not in the administration menus or in the tables themselves...

Mambo -> Joomla 1.0 -> Joomla 1.5

Mambo tutorials seem to help somewhat, but sometimes they are way off. Like Joomla! components added an extra presentation layer, e.g. hello.html.php gets added to hello.php.

I'm confident about finishing my little Jambla I mean Joomla customization quickly and I will post haste contribute to documentation, but the budding Joomalateer has to carefully navigate between the Scylla of Mambo and Charybdis of Joomla 1.5 with the new Joomla Framework API (everything prefixed with a J, JExec, JGetParam, etc...thought Joomla and Java were getting together there for a moment).

The tutorials at Joomla Development Wiki (Tutorials seem to all use the new API so they are Joomla 1.5 which I would like to master here shortly, but I got to get a reliable production system running quickly. Joomla 1.5 appears to only be in the Alpha stage.

Joomla!-Mambo Help Videos

Mambodemo has a full set of videos that help you step through Joomla! tasks. The list of tasks is itself informative, a sort of list of all the things you can do with Joomla! :

Add a Category
Add a Contact
Add a Content Item
Add a Menu Item - Blog Category
Add a Menu Item - Component
Add a Menu Item - Link URL
Add a Menu Item - Table Category
Add a Menu Item - Wrapper
Add a Section
Add Content from the Frontend
Approve a Submitted Item
Archive Manager
Assign a Template
Change Access Level of Content
Change Menu Orientation
Change the Frontpage Layout
Change the Home Page
Change the Installed Directory
Create a Module
Database Backup with phpMyAdmin
Edit the Content Layout
Edit the Template
Email Users
Enable SEF URLs
Install a Component
Install a Component Manually
Install a Language
Install a Language Manually
Install a Mambot
Install a Mambot Manually
Install a Module
Install a Module Manually
Install a Template
Install a Template Manually
Install Joomla with cPanel
Manage the Global Configuration
Publishing Control of Content
Setup RSS
Updating Users - Backend
Updating Users - Frontend
Using the Media Manager
Using the Menu Manager
Using the Module Manager
Using the Trash Manager
Using the User Manager

The Mambo legacy, tutorials, etc...

Got to remind myself to look at Mambo examples, tutorials, too.

Joomla! has just recently forked from Mambo.

Mambohut's basic module and component is about as simple as you can get. Get info from database, display info web page:

1. Module tutorial
2. Component tutorial

Content items = articles

I think I'm starting to understand Joomla!. The articles you publish everyday are called content items. Here's a meaty definition:

"A content item is a discrete piece of content within the Joomla! hierarchy. A content item may be associated with a particular Section/Category combination or a Static Content Item. Usually content items are displayed in the main body of your page. Content item is the last in the Section/Category/Content Items hierarchy or it can be a separate Static Content Item."

1. Joomla! hierarchy = Section/Category/Content-Items hierarchy, for example: business/marketing/how to sell people things they don't need, the section is business and the category is marketing.

[Observation: Joomla!'s hierarchy is a tree, but forests like folk taxonomies in del.icio.us allow for different categorizations, different ways of looking at the same thing. The tree versus forest distinction has been around for a long time though. I used to deal with trees all the time as a COBOL-CICS General Ledger computer consultant in corporate America. For example, better designed General Ledgers for corporations have corporate reporting structures built into the hierarchy of accounts and these hierarchies are forests, not trees. The various reports of a company will break down the same information in different ways.]

2. Main body of page = center, so...

3. Components must display content items.

4. An ItemId must be the unique identifier of a content item, right?

[No, if you look at the menu manager screen under administrator, ItemId is in one column and CID which must mean content id is in another. Not the same.]

ItemId, the definition?

One day I will discover what an ItemId is.

It gets tacked on to the end of almost every Joomla! URL I've seen.

Like Home, the mother of all URLs:

http://127.0.0.1/joomla/index.php?option=com_frontpage&Itemid=1

Or News, another important destination:

http://127.0.0.1/joomla/index.php?option=com_content&task=section&id=1&Itemid=2

But as this thread at Joomla! Forums tells me, there may be no easy definition, but I'm not losing hope.

I am creating my own little Joomla! Glossary to celebrate when I discover simple definitions for complicated little things like ItemId!

Parameters II

Where do parameters come from mommy?

Playing around with the Joomla front page. Clicking on something and seeing what URL it gives me. Inside the URL I can see parameters ($REQUIRE, $GET) being passed to a component that will display in the center of the page. Still doesn't tell me how or why they got there, but it's a start in unravelling the logic of Joomla! code.

Hit the Register link on the Joomla front page and I get this URL:

http://127.0.0.1/joomla/index.php?option=com_registration&task=register

On the Main Menu:

1. Home:

http://127.0.0.1/joomla/index.php?option=com_frontpage&Itemid=1

2. Joomla! License:

http://127.0.0.1/joomla/index.php?option=com_content&task=view&id=5&Itemid=6

3. News:

http://127.0.0.1/joomla/index.php?option=com_content&task=section&id=1&Itemid=2

4. Blog:

http://127.0.0.1/joomla/index.php?option=com_content&task=blogsection&id=0&Itemid=9

5. Links:

http://127.0.0.1/joomla/index.php?option=com_weblinks&Itemid=23

6. Contact Us:

http://127.0.0.1/joomla/index.php?option=com_contact&Itemid=3

7. Search:

http://127.0.0.1/joomla/index.php?option=com_search&Itemid=5

8. News Feeds:

http://127.0.0.1/joomla/index.php?option=com_newsfeeds&Itemid=7

9. FAQs:

http://127.0.0.1/joomla/index.php?option=com_content&task=category§ionid=3&id=7&Itemid=25

10. Wrapper:
http://127.0.0.1/joomla/index.php?option=com_wrapper&Itemid=8

11. Joomla! Home:

http://www.joomla.org/


Some generalizations:

1. Option is the component being called like com_registration. So after you click on the frontpage something is mapping your click to a component call. Must be the infamous template I've been hearing so much about.

2. Task comes from a limited set: view, section, register, blogsection... It selects the thing to do once you reach the component.

3. ItemId ??????????????

4. Id I guess would be a user Id, maybe?

Parameters I

What I need to understand next about modules is how they get input parameters like $task, $option, or $id. For example, from mod_relcontent:

$option = trim( mosGetParam( $_REQUEST, 'option', null ) );

Or from mod_latestnews :

$type = intval( $params->get( 'type', 1 ) );

mosGetParam must be the preferred to the raw PHP $params->get() since it is in the Joomla! API.

mod_login also has to get user supplied parameters like username and password. What are all the parameters defined in mod_login.xml used for?

Where do parameters like $task come from? Where do they go? What are the calling conventions in modules? Which parameters are required and which are optional?

Time to hit the code again.

Modules vs. Components in Joomla! III

Joomla! Modules are written differently from components. They use different function calls and variables, so they need different example programs.

For example, take login and user registration. If a user can't login, then she registers first. We login to a module on the left, right, or top. We register in a component in the center.

Compare the login code with the registration code. The login code is in one file: mod_login.php. The registration code is in the directory: com_registration. There are two registration program files:

1. registration.html.php : displays data
2. registration.php : makes decisions about what to display (does logic).

Both files get data from the database. Right now I'm going to stick with figuring out modules, even though my goal is to modify user registration. My user registration customization will require the user to supply an 8-digit subscriber id checked against a table of ids added to Joomla.

Saturday, April 29, 2006

Joomla! cookbook anyone?

Surprised to see that the PHP cookbook is only 2.9% finished at PLEAC, the repository of code snippets for programming (PLEAC = Programming Language Examples Alike Cookbook). Why?

Maybe PHP is different from other programming languages so it needs its own special list of code snippets?

Maybe it's better to start thinking at the level of applications, like a Joomla or Content Management System cookbook.

Programming in small doses?

Maybe programming in small doses is the antidote to this Joomla! user's problems:

"I found Joomla very frustrating though. I installed the dummy template site that comes with the distribution, a site about soccer teams. I wanted to remove the frames in the site, change the background images and colors, and otherwise set up a small publishing site with news and blogs. I was unable to do a lot of this without digging in directly to the css, which is of course far too much to ask a common user. I spent several hours with this, learning how the interface work and making backend changes, and mostly gave up out of frustration and lack of time to devote."

That's why I'm focusing on code snippets. Little pieces of stand alone code that do a small task that you can learn from.

A forum or library of code snippets does seems to be in the making over at the official Joomla org.

From database to web page

Here's a tiny module to get data from the Joomla database and display it on the front Joomla! page. Take the zip file and install the module. It will will list the published modules and their positions, one per line. The file contents is given below.

[Note: There's a Mambo module tutorial that has almost the same thing.]

mod_getandgive.php:

<?php

defined
( '_VALID_MOS' )
or die(
'Direct Access not allowed.' );

$query = "SELECT * FROM jos__session";
$database->setQuery( $query );
$result = $database->loadResult();
echo
"result: " . $result;

?>



getandgive.xml:
<?xml version="1.0" ?>
<mosinstall type='module'>
<name>getandgive</name>
<creationDate>19/Jun/2006</creationDate>
<author>Mr. Hello Smiley</author>
<copyright>This template is released
under the GNU/GPL License</copyright>
<authorEmail>blackhole@saynotospam.com</authorEmail>
<authorUrl>http://readbangkokpost.com/business/</authorUrl>
<version>1.0</version>
<description>To get something from the Joomla database
and display it in a box on the front of Joomla</description>
<files>
<filename module='mod_getandgive'>mod_getandgive.php</filename>
</files>
</mosinstall>

Installing a Module

The following steps will make your module the last thing on the right-hand sidebar.

1. Download a zip file with the two files mod_mymodulename.php and mymodulename.xml inside.

2. From the administrators panel in Joomla select: installers -> modules.

3. Then browse and select the zip file.

4. Then select "Upload file and install".

5. There shouldn't be any error messages.

6. Then select from the navigation bar running along the top of the administrators panel: Modules -> Site Modules.

7. Then click on the name of your module.

8. Now you are editing the settings for your module.

9. Choose position: Right.

10. Choose Access Level: at-the-very-bottom-of-everything.

11. Choose: Public.

12. Then save.

13. Then check the box in the left column next to your module name and publish.

14. Go to the front of Joomla (http://joomla/index.php).

15. Hit the browser refresh button.

16. You should see a box with your module's name on it on the bottom with whatever your module displays inside of it.

17. I know this descrption is overkill, but didn't want to leave anything out.

There are other descriptions of how to do this here.

Friday, April 28, 2006

A very, very simple module

Whoopee! I can display text in a Joomla box. Use the two files listed below or this zip file and install the module. Here is the contents of the two files in the zip file:

helloworld4.php:


<?php

defined
( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );

echo
"Hello World!";

?>



helloworld4.xml:

<?xml version="1.0" ?>
<mosinstall type='module'>
<name>helloworld4</name>
<creationDate>19/Jun/2006</creationDate>
<author>Mr. Hello Smiley</author>
<copyright>This template is released under the GNU/GPL License</copyright>
<authorEmail>blackhole@saynotospam.com</authorEmail>
<authorUrl>http://readbangkokpost.com/business/</authorUrl>
<version>1.0</version>
<description>To display some text in a box on the front of Joomla</description>
<files>
<filename module='mod_helloworld4'>mod_helloworld4.php</filename>
</files>
</mosinstall>

Pretty printing PHP for documentation examples

How do I format php and html properly to provide examples in documentation?

Prettyprint of course! How could I forget that?

Here's an online PHP pretty printer that indents html properly also.

It maps plain text file space ("_") to html file space ("&nbsp;") using GNU's Indent and plain text file angle brackets ("<", ">") to html angle brackets ("&lt;", "&gt;").

Here's an example.