Oddmuse is the wiki engine running all the wikis at emacswiki.org – including EmacsWiki itself. My main interests are:

See OddmuseRoadmap for my thoughts about the design of Oddmuse.
I just rewrote my Tag Cloud to use the Google Treemap.
What it does is the following:
cloud action runs the old code (text representation).tagcloud action runs the new code.tag action which shows the last blog pages with that tag.Try it! → Tag Cloud. (I realize that the tag cloud isn’t very interesting in and of itself. I just enjoyed using the Google tools and learning a little bit of Javascript on the way.)
$Action{cloud} = $Action{tagcloud};
$Action{tagcloud} = \&MyTagCloud;
sub MyTagCloud {
print GetHeader('', T('Tag Cloud'), '');
# open the DB file
require DB_File;
tie %h, "DB_File", $TagFile;
my $max = 0;
my $min = 0;
my %count = ();
foreach my $tag (grep !/^_/, keys %h) {
$count{$tag} = split(/$FS/, $h{$tag});
$max = $count{$tag} if $count{$tag} > $max;
$min = $count{$tag} if not $min or $count{$tag} < $min;
}
untie %h;
# ignore 90% of all tags
my @values = sort values %count;
$min = GetParam('min', $values[int($#values * 0.9)]);
# https://developers.google.com/chart/interactive/docs/gallery/treemap
print <<EOT;
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["treemap"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Location', 'Parent', 'Mentions', ''],
['Tags', null, 0, 0],
EOT
foreach my $tag (sort keys %count) {
my $n = $count{$tag};
next unless $n > $min;
print " ['$tag', 'Tags', $n, 0],\n";
}
print <<EOT;
]);
// Create and draw the visualization.
var tree = new google.visualization.TreeMap(document.getElementById('treemap'));
tree.draw(data);
google.visualization.events.addListener(tree, 'select', selectHandler);
function selectHandler() {
var selection = tree.getSelection();
var item = selection[0];
window.location = "/alex?action=tag;id=" + data.getValue(item.row,0);
}
}
</script>
EOT
print $q->start_div({-class=>'content cloud'});
print $q->p(ScriptLink('action=tagcloud;min=0', T('Include all tags')),
Ts('(currently showing tags with more than %s occurences)', $min));
print $q->p(Ts('Or switch to a %s.', ScriptLink('action=cloud', T('text format'))));
print $q->start_div({-id=>'treemap', -style=>'height: 1000px;'});
print $q->end_div();
print $q->end_div();
PrintFooter();
}Tags: Oddmuse
Javascript
Google 
My websites have not been sending any email notifications out to people who had subscribed to page edits. The reason was that I had switched my Google account to use 2-step verification. Only today did I realize that the error messages were trying to tell me that I needed an application specific password for my script.
Everything should be back in working order. 
I feel relieved. For a while I thought I’d have to dig around in the Perl SMTP libraries. Ugh!
And I feel much better with 2-step verification. The Mat Honan story was scary.
Tags: Oddmuse 
I’ve started tinkering with the CSS again. No more secret theme switching by clicking on my face up there. 
I’m going for black and white and the default blue for all links. The previous classification for site links, links to sister sites, links to Wikipedia and all other links didn’t really work with all the redirections I had implemented. Thus, be gone!
I’m sticking to Garamond as my favorite font even though I must admit it looks absolutely horrible when viewed on Windows without Clear Type. Oh well! Most people will be reading the site via a feed reader anyway, I guess.
I’ll also try to stick to a larger than average font-size. I haven’t decided whether I should be using Google Web Fonts.
Let me know if there is something you’d like to see changed. 
This is why I like the Oddmuse channel on Freenode so much… 
(Dan later discovers that the term he was looking for is cognitive inertia.)

I’ve been working on a submission form for the Old School RPG Planet. Today I added another little feature. This is how I like to develop code. No time pressure. One little step at a time. Keep polishing it.
The planet uses Planet Venus to collect the RSS and Atom feeds of many of the Old School RPG blogs out there. Planet Venus allows you to get the list of feeds via an URL. I’m hosting the list of feeds on Campaign Wiki itself (raw format). As you can see, it the format doesn’t look nice.
The thing I did, therefore, was to write a script that makes it easy for people who are not into the technical details to submit new blogs. It also makes it easier for me to submit new blogs!
The things it handles:
http:// and try again.application/rss+xml, application/atom+xml, application/xml (yeah) and text/xml (just making sure) and allow the user to pick one of them.I think it’s pretty cool.
If you look at the interface, you’ll note that it has a link to its own source code. I love this little Perl trick:
__DATA__ at the end of the source file. Usually you would add actual data at the end. The script could read it using the DATA file handle.seek DATA, 0, 0; print "Content-type: text/plain; charset=UTF-8\r\n\r\n", <DATA>; This resets the current position of the DATA file handle to the beginning of the source file. Tadaa! 
I noticed that my blog no longer validated as XHTML 1.0 and I started investigating. On the Diary page, you can click on the comment links of the various blog posts (such as Comments on 2011-07-05 Google Plus) and you’ll get the comments inlined. This uses a tiny piece of javascript (and some CSS):
function togglecomments (id) {
var elem = document.getElementById(id);
if (elem.className=="commentshown") {
elem.className="commenthidden";
}
else {
elem.className="commentshown";
}
}Thus, the HTML source already includes the comments in an appropriate div:
<div class="commenthidden" id="Comments_on_2011-07-05_Google_Plus"> … </div>
Links such as Comments on 2011-07-05 Google Plus will simply call the javascript function defined above and pass the id of the div to toggle:
<a href="javascript:togglecomments('Comments_on_2011-07-05_Google_Plus')">Comments on 2011-07-05 Google Plus</a>That’s why the id attribute is important. The trivial solution is to simply use the blog post title (“2011-07-05 Google Plus”) but soon enough you’ll note that there are some interesting restrictions on the values of id attributes:
Now—how exactly is this defined? See the definition of Name in the XML spec:
NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]Name ::= NameStartChar (NameChar)*Now, those are Unicode code points. But sadly, Oddmuse tries to be encoding agnostic. (I will have to revisit this decision, soon!)
Here’s a simple beginning of a regular expression that would identify well-formed names: /^[:_A-Za-z][-.:_A-Za-z0-9]*/
Now to extend it using the information above:
Unicode Codepoint UTF-8 encoding [#xC0-#xD6] c3 80 - c3 96 [#xD8-#xF6] c3 98 - c3 b6 [#xF8-#x2FF] c3 b8 - cb bf [#x370-#x37D] cd b0 - cd bd [#x37F-#x1FFF] cd bf - e1 bf bf [#x200C-#x200D] e2 80 8c - e2 80 8d [#x2070-#x218F] e2 81 b0 - e2 86 8f [#x2C00-#x2FEF] e2 b0 80 - e2 bf af [#x3001-#xD7FF] e3 80 81 - ed 9f bf [#xF900-#xFDCF] ef a4 80 - ef b7 8f [#xFDF0-#xFFFD] ef b7 b0 - ef bf bd [#x10000-#xEFFFF] f0 90 80 80 - f3 af bf bf
I started writing the following regular expression:
$regexp = "|\xc3[\x80-\x96\x98-\xb6\xb8-\xff]|[\xc4-\xca].|\xcb[\x00-\xbf]"
. "|\xcd[\xb0-\xbd\xbf-\xff]|[\xce-\xDF].|\xe0..|\xe1[\x00-\xbe]."
. "|\xe1\xbf[\x00-\xbf]|\xe2\x80[\x8c\x8d]"
if $HttpCharset eq 'UTF-8';
$id = ":$id" unless $id =~ /^[:_A-Za-z]$regexp/;
return join('', $id =~ m/([-.:_A-Za-z0-9]$regexp)/g);Then I got tired and though, “if anybody reports an error, I’ll add the rest…”
Comments on 2011-07-06 Regular Expression To Validate Id Attributes
You do know RegEx match open tags except XHTML self-contained tags?
– Harald 2011-07-12 12:00 UTC
AlexSchroeder Habe ich schon mal gesehen, ja. Und kennst du Oh Yes You Can Use Regexes to Parse HTML!?
In meinem Fall geht es aber nicht um Parsen von HTML sondern um die Transformation von Wiki Seitentiteln zu id Werten, welche ich im generierten HTML dann verwenden kann.
– AlexSchroeder 2011-07-12 12:15 UTC
Wow, what a spam storm! I rolled back all those changes and locked the wiki for the moment. There’s no fighting a bot manually. 
I’ll look into what allowed this to happen later today and hopefully enable page editing and commenting again. 
Update: IP number blocked, lock removed. That was weird. 
On Community:AlexSchroeder I include my Twitter feed. In order to strip the unfortunate duplication of title and description, and in order to strip my username from the feed, I wrote a little proxy which will remove the description if it matches the title and which will remove the username if possible.
Compare:
Cheers. 
Tags: Oddmuse 
I’m thinking about not using a goto bar at the bottom of my pages:
# show goto bar only once
*MyOldGetGotoBar = *GetGotoBar;
*GetGotoBar = *MyNewGetGotoBar;
my $MyGetGotoBar = 0;
sub MyNewGetGotoBar {
return MyOldGetGotoBar(@_) unless $MyGetGotoBar++;
return '';
}
# get rid of extra break
*MyOldGetFooterLinks = *GetFooterLinks;
*GetFooterLinks = *MyNewGetFooterLinks;
sub MyNewGetFooterLinks {
my $html = MyOldGetFooterLinks(@_);
$html =~ s!<br />!!;
return $html;
}The reason I started thinking about it is a. I hardly use the links in the footer and b. the link to the comments tends to get lost, visually.
What do you think?
Tags: Oddmuse 
Comments on 2009-08-26 Oddmuse Footer
I agree with this. I usually think of the top bar as my “User Bar” and the bottom one as my admin bar.
– PhillipReay 2010-05-08 00:18 UTC
Today I had to make the following change to Oddmuse because that fixes an image upload issue on my dad’s blog. What’s going on? He’s using the following:
Any ideas? The net result was that <$file> resulted in no content if run within the eval block.
*** wiki.pl.~1.925.~ Fri Jul 3 11:23:01 2009
--- wiki.pl Tue Aug 4 00:20:26 2009
***************
*** 3548,3554 ****
$type = $q->uploadInfo($filename)->{'Content-Type'};
ReportError(T('Browser reports no file type.'), '415 UNSUPPORTED MEDIA TYPE') unless $type;
local $/ = undef; # Read complete files
! eval { require MIME::Base64; $_ = MIME::Base64::encode(<$file>) };
$string = '#FILE ' . $type . "\n" . $_;
} else {
$string = AddComment($old, $comment) if $comment;
--- 3548,3555 ----
$type = $q->uploadInfo($filename)->{'Content-Type'};
ReportError(T('Browser reports no file type.'), '415 UNSUPPORTED MEDIA TYPE') unless $type;
local $/ = undef; # Read complete files
! my $content = <$file>; # Apparently we cannot count on <$file> to always work within the eval!?
! eval { require MIME::Base64; $_ = MIME::Base64::encode($content) };
$string = '#FILE ' . $type . "\n" . $_;
} else {
$string = AddComment($old, $comment) if $comment;Comments on 2009-08-03 Strange Perl Issue
This sounds like the issue we have on EmacsWiki as well.
– AaronHawley 2009-08-04 07:39 UTC
Thanks for the reminder! I had forgotten about it. 
– AlexSchroeder 2009-08-04 09:03 UTC
Andreas Gohr How does the referrer thingy at the bottom of the post work? The two pages linked seem not to link to this post?
Regarding styling: I’d prefer a non-serif font.
– Andreas Gohr 2012-03-08 10:14 UTC
AlexSchroeder The referrer thing works as follows: if a visitor to the wiki has referrer information, the wiki fetches this page and searches for a link to the page. If that works, it remembers the link. This means that eventually referrals expire if nobody ever follows them. Normally this works very well. Some sites such as Blogspot offer users a blog-roll. As far as I understand it, users will then see the n most recently updated entries or a random selection. Either way, by the time other visitors try and check the referral, it’s no longer being displayed.
If you check Self:action=refer you will notice that at the moment the authors of Dreams of Mythic Fantasy, The City of Iron and Troll and Flame seem to have me listed on their blog-roll. All of them are Blogspot blogs.
As for sans-serif, try this link. (Your preference is set in a cookie.) Feel free to switch back.
– AlexSchroeder 2012-03-08 11:46 UTC
AlexSchroeder For Pierre and others who preferred the old look: Try this! switch to the Red Beige theme and switch back to the default theme
– AlexSchroeder 2012-03-23 15:28 UTC
Add Comment