<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;"># NOTE -- This file is generated by running make-js-interfaces.pl
package mozilla;

use strict;
use vars qw/@ISA $standardheader/;
$standardheader = &lt;&lt;EOF;
&lt;!-- This is part of CGI:IRC 0.5
  == http://cgiirc.sourceforge.net/
  == Copyright (C) 2000-2003 David Leadbeater &lt;cgiirc\@dgl.cx&gt;
  == Released under the GNU GPL
  --&gt;
EOF

use default;
@ISA = qw/default/;
my %colours = (
	  '00' =&gt; '#FFFFFF', '01' =&gt; '#000000', '02' =&gt; '#0000FF', 
	  '03' =&gt; '#008000', '04' =&gt; '#FF0000', '05' =&gt; '#800000', 
	  '06' =&gt; '#800080', '07' =&gt; '#FF6600', '08' =&gt; '#FFFF00', 
	  '09' =&gt; '#00FF00', '10' =&gt; '#008080', '11' =&gt; '#00FFFF', 
	  '12' =&gt; '#0000FF', '13' =&gt; '#FF00FF', '14' =&gt; '#808080', 
	  '15' =&gt; '#C0C0C0');

my %options = (
   timestamp =&gt; {
      type =&gt; 'toggle',
      info =&gt; 'Display a timestamp next to each message', 
      img =&gt; 'time.gif'
   },
   font =&gt; { 
      type =&gt; 'select',
      options =&gt; [qw/serif sans-serif fantasy cursive monospace/,
                 'Arial Black', 'Comic Sans MS', 'Fixedsys',
                 'Tahoma', 'Verdana'],
      info =&gt; 'The font that messages are displayed in',
      img =&gt; 'font.gif'
   },
   shownick =&gt; {
      type =&gt; 'toggle',
      info =&gt; 'Show your nickname next to the text entry box',
      img =&gt; 'entry.gif'
   },
   smilies =&gt; {
      type =&gt; 'toggle',
      info =&gt; 'Convert smilies into pictures',
      img =&gt; 'smile.gif'
   },
   scrollback =&gt; {
      type =&gt; 'toggle',
      info =&gt; 'Store all scrollback data (uses more memory)',
		img =&gt; 'scrollback.gif',
   },
   'actsound' =&gt; {
      type =&gt; "toggle",
      info =&gt; "Play a sound when activity directed at you occurs",
		img =&gt; 'actsound.gif',
   },
   'joinsound' =&gt; {
      type =&gt; "toggle",
      info =&gt; "Play a sound when some one joins a channel",
		img =&gt; 'joinsound.gif',
   },
);

my(%output_status, %output_none, %output_active);

sub new {
   my($class,$event, $timer, $config, $icookies) = @_;
   my $self = bless {}, $class;
   tie %$self, 'IRC::UniqueHash';
   my $tmp='';
   for(keys %$icookies) {
      $tmp .= "$_: " . _escapejs($icookies-&gt;{$_}) . ', ';
   }
   $tmp =~ s/, $//;
   _out('parent.options = { ' . $tmp . '};');
   $event-&gt;add('user add', code =&gt; \&amp;useradd);
   $event-&gt;add('user del', code =&gt; \&amp;userdel);
   $event-&gt;add('user change nick', code =&gt; \&amp;usernick);
   $event-&gt;add('user change', code =&gt; \&amp;usermode);
   $event-&gt;add('user self', code =&gt; \&amp;mynick);
   $event-&gt;add('user 005', code =&gt; sub { _func_out('prefix',$_[1])});
   $event-&gt;add('user connected', code =&gt; sub { _out('parent.connected = 1;')
   }); 
   $self-&gt;add('Status', 0);
   _func_out('witemnospeak', 'Status');
   _func_out('fontset', $icookies-&gt;{font}) if exists $icookies-&gt;{font};
   _func_out('enable_sounds') if ((exists $icookies-&gt;{actsound} || exists $icookies-&gt;{joinsound}) &amp;&amp; ($icookies-&gt;{actsound} || $icookies-&gt;{joinsound}));

   if(exists $::config-&gt;{'output status'}) {
      @output_status{split /,\s*/, $::config-&gt;{'output status'}} = 1;
   }

   if(exists $::config-&gt;{'output none'}) {
      @output_none{split /,\s*/, $::config-&gt;{'output none'}} = 1;
   }
   
   if(exists $::config-&gt;{'output active'}) {
      @output_active{split /,\s*/, $::config-&gt;{'output active'}} = 1;
   }
   
   return $self;
}

sub end {
   _out('parent.connected = 0;');
}

sub _out {
   unless(print "&lt;script&gt;$_[0]&lt;/script&gt;\r\n") {
      $::needtodie++;
   }
}

sub _func_out {
   my($func,@rest) = @_;
   @rest = map(ref $_ eq 'ARRAY' ? _outputarray($_) : _escapejs($_), @rest);
   if($func eq 'witemaddtext') {
      return 'parent.' . $func . '(' . _jsp(@rest) . ');';
   }
   _out('parent.' . $func . '(' . _jsp(@rest) . ');');
}

sub _escapejs {
   my $in = shift;
   return "''" unless defined $in;
   $in =~ s/\\/\\\\/g;
   $in =~ s/'/\\'/g;
   $in =~ s/&lt;\/script/&lt;\\\/\\script/g;
   if(defined $_[0]) {
      return "$_[0]$in$_[0]";
   }
   return '\'' . $in . '\'';
}

sub _escapehtml {
   my $in = shift;
   return "''" unless defined $in;
   $in =~ s/&lt;/&amp;lt;/g;
   $in =~ s/&gt;/&amp;gt;/g;
   $in =~ s/"/&amp;quot;/g;
   return $in;
}

sub _jsp {
   return join(', ', @_);
}

sub _outputarray {
   my $array = shift;
   return '[' . _jsp(map(_escapejs($_), @$array)) . ']';
}

sub useradd {
   my($event, $nicks, $channel) = @_;
   _func_out('channeladdusers', $channel, $nicks);
}

sub userdel {
   my($event, $nick, $channels) = @_;
   _func_out('channelsdeluser', $channels, $nick);
}

sub usernick {
   my($event,$old,$new,$channels) = @_;
   _func_out('channelsusernick', $old, $new);
}

sub usermode {
   my($event,$nick, $channel, $action, $type) = @_;
   _func_out('channelusermode', $channel, $nick, $action, $type);
}

sub mynick {
   my($event, $nick) = @_;
   _func_out('mynick', $nick);
}

sub exists {
   return 1 if defined &amp;{__PACKAGE__ . '::' . $_[1]};
}

sub query {
   return 1;
}

sub style {
   my($self, $cgi, $config) = @_;
   my $style = $cgi-&gt;{style} || 'default';
   $cgi-&gt;{style} =~ s/[^a-z]//gi;
   open(STYLE, "&lt;interfaces/style-$style.css") or die("Error opening stylesheet $style: $!");
   print &lt;STYLE&gt;;
   close(STYLE);
}

sub makeline {
   my($self, $info, $html) = @_;
   my $target = defined $info-&gt;{target} ? $info-&gt;{target} : 'Status';

   if(ref $target eq 'ARRAY') {
     my %tmp = %$info;
     my $text = '';
	  for(@$target) {
	     $tmp{target} = $_;
        $text .= $self-&gt;makeline(\%tmp, $html) . "\r\n";
	  }
	  return $text;
   }

   my $out = "";
   if(not exists $self-&gt;{$target}) {
      if(defined $info &amp;&amp; ref $info &amp;&amp; exists $info-&gt;{create} &amp;&amp; $info-&gt;{create}) {
	     $self-&gt;add($target, $info-&gt;{type} eq 'join' ? 1 : 0);
	  }elsif($target ne '-all') {
         $target = 'Status';
	  }
   }elsif($info-&gt;{type} eq 'join') {
      $out = "parent.joinsound();";
   }

   $info-&gt;{type} =~ s/^(\w+ \w+) .*/$1/;
   return if exists $output_none{$info-&gt;{type}};
   $target = "Status" if exists $output_status{$info-&gt;{type}};
   $target = "-active" if exists $output_active{$info-&gt;{type}};
   
   if($info-&gt;{style}) {
      $html = "&lt;span class=\"main-$info-&gt;{style}\"&gt;$html&lt;/span&gt;";
   }
   return $out . _func_out('witemaddtext', $target, $html . '&lt;br&gt;', $info-&gt;{activity} || 0, 0);
}

sub lines {
   my($self, @lines) = @_;
   _out(join("\r\n", @lines)."\r\nparent.witemredraw();");
   print "&lt;!-- mozilla padding --&gt;\r\n";
}

sub header {
   my($self, $cgi, $config, $fg, $bg) = @_;
   _func_out('maincolor', $fg, $bg);
}

sub error {
   my($self,$message) = @_;
   $self-&gt;lines($self-&gt;makeline({ target =&gt; 'Status'}, $message));
   _func_out('disconnected');
}

sub add {
   my($self,$add,$channel) = @_;
   return if not defined $add;
   $self-&gt;{$add}++;
   _func_out('witemadd', $add, $channel);
   _func_out('witemchg', $add) if $channel;
}

sub del {
   my($self, $del) = @_;
   return if not defined $del;
   _func_out('witemdel', $del);
   return if not exists $self-&gt;{$del};
   delete($self-&gt;{$del});
}

sub clear {
   my($self, $window) = @_;
   _func_out('witemclear', $window);
}

sub active {
   my($self, $window) = @_;
   _func_out('witemchg', $window);
}

sub smilie { # js runs in fmain. (XXX: doesn't actually work?)
   return '&lt;img src="'.$_[1].'" alt="' . $_[2] . '"&gt;';
}

sub link {
   shift; # object
   return "&lt;a href=\"$_[0]\" target=\"cgiirc@{[int(rand(200000))]}\" class=\"main-link\"&gt;$_[1]&lt;/a&gt;";
}

sub frameset {
   my($self, $scriptname, $config, $random, $out, $interface, $style) = @_;
print &lt;&lt;EOF;
$standardheader
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;CGI:IRC - Loading&lt;/title&gt;
&lt;link rel="stylesheet" href="$config-&gt;{script_login}?interface=mozilla&amp;item=style&amp;style=$style" /&gt;
&lt;link rel="SHORTCUT ICON" href="$config-&gt;{image_path}/favicon.ico"&gt;
&lt;script language="JavaScript"&gt;&lt;!--
function form_focus() {
   if(document.frames &amp;&amp; document.frames.fform)
	  document.frames.fform.fns();
}
//--&gt;
&lt;/script&gt;
&lt;/head&gt;
&lt;frameset
rows="40,*,25,0"
framespacing="0" border="0" frameborder="0" onfocus="form_focus()" onload="form_focus()"&gt; 
&lt;frame name="fwindowlist" src="$scriptname?$out&amp;item=fwindowlist&amp;style=$style"
scrolling="no"&gt;
&lt;frameset cols="*,120" framespacing="0" border="0" frameborder="0"&gt;
&lt;frame name="fmain"
src="$scriptname?item=fmain&amp;interface=$interface&amp;style=$style" scrolling="yes"&gt;
&lt;frame name="fuserlist"
src="$scriptname?item=fuserlist&amp;interface=$interface&amp;style=$style"
scrolling="yes"&gt;
&lt;/frameset&gt;
&lt;frame name="fform"
src="$scriptname?item=fform&amp;interface=$interface&amp;style=$style" scrolling="no"
framespacing="0" border="0" frameborder="0" resize="no"&gt;
&lt;frame name="hiddenframe" src="$scriptname?item=blank&amp;style=$style"
scrolling="no" framespacing="0" border="0" frameborder="0" resize="no"&gt;
&lt;noframes&gt;
This interface requires a browser that supports frames and javascript.
&lt;/noframes&gt;
&lt;/frameset&gt;
&lt;/html&gt;
EOF
}

sub blank {
   return '';
}

sub ctcpping {
   my($self, $nick, $params) = @_;
   _func_out('sendcmd',"/ctcpreply $nick PING $params");
   1;
}

sub ping {
   1;
}

sub sendping {
   _func_out('sendcmd',"/noop");
}

sub help {
   my($self,$config) = @_;
   my $help = &lt;&lt;EOF;
&lt;!-- this is included in ie.pm and mozilla.pm by make-js-interfaces.pl --&gt;
&lt;h1&gt;CGI:IRC Help&lt;/h1&gt;

&lt;h3&gt;Interface&lt;/h3&gt;

The interface of CGI:IRC is very similar to a standard graphical IRC client, it
 should be easy to use if you are familiar with IRC clients. Along the top is a
 list of tabs, there will be a tab here for each channel you are in and each
 query (private message) you have open. To close a window click the X button on
 the far right of the tab list.&lt;br /&gt;
The userlist is on the right, when in a channel tab it will show a list of all
 the people in that channel. Double clicking a nickname will open a query with
 that user or perform whichever other action you select in the select box at the
 bottom.&lt;br /&gt;
The text entry box should be simple, the little arrow to the right of the text
 entry area shows a toolbar that allows easy typing of colour, bold and underline. It is also where you enter all the commands.

&lt;h3&gt;Commands&lt;/h3&gt;
Commands begin with / and should be familiar to anyone who has used IRC before
- here is a quick summary of the most useful commands.
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;/me&lt;/td&gt;&lt;td&gt;This turns the text after /me into an action, eg: /me looks
around.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/join&lt;/td&gt;&lt;td&gt;Joins the specified channel. eg: /join #cgiirc&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/list&lt;/td&gt;&lt;td&gt;Lists all the channels on the network (this outputs a lot
of information).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/part&lt;/td&gt;&lt;td&gt;Leaves the current channel (same as clicking the X while
in the channel).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/quit&lt;/td&gt;&lt;td&gt;Quits IRC totally (same as clicking X in Status window).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/msg&lt;/td&gt;&lt;td&gt;Sends a private message to a user. eg: /msg someone Hi&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;/whois&lt;/td&gt;&lt;td&gt;Gives some information about a user.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;Options&lt;/h3&gt;
The options window lets you change some settings in CGI:IRC. Hopefully it
 should be fairly self explanatory, change a setting and it should take effect
 immediately.

&lt;h3&gt;Keyboard shortcuts&lt;/h3&gt;
There are several shortcuts to help make using CGI:IRC nicer.
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;Tab&lt;/td&gt;&lt;td&gt;Will autocomplete a nickname or channel.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ctrl+number / Alt+number&lt;/td&gt;&lt;td&gt;Will go to that number window if you number
 the windows from the left (Status = 1 and so on).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ctrl+B&lt;/td&gt;&lt;td&gt;Write "%B" for bold text.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ctrl+C&lt;/td&gt;&lt;td&gt;Write "%C" for colored text.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Cursor Up/Down&lt;/td&gt;&lt;td&gt;Move in the command history.&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;h3&gt;About CGI:IRC&lt;/h3&gt;
CGI:IRC is written in Perl by David Leadbeater with help from lots of people. See the &lt;a
 href="http://cgiirc.sourceforge.net/" target="cgiirc-web"&gt;website&lt;/a&gt; for more information.
EOF
   $help =~ s/[\n\r]/ /g;
   _func_out('doinfowin', '-Help', $help);
}

sub setoption {
   my($self, $name, $value) = @_;
   _func_out('setoption', $name, $value);
   $self-&gt;options({}, {}, $main::config)
}

sub options {
   my($self, $cgi, $irc, $config) = @_;
   $config = $irc unless ref $config;
   my $ioptions = $main::ioptions;

   my $out = "&lt;html&gt;&lt;head&gt;&lt;title&gt;CGI:IRC Options&lt;/title&gt;&lt;/head&gt;&lt;body class=\"options-body\"&gt;&lt;h1 class=\"options-title\"&gt;Options&lt;/h1&gt;These options affect the appearence of CGI:IRC, they will stay between sessions provided cookies are turned on.&lt;form&gt;&lt;table border=0 class=\"options-table\"&gt; ";

   for my $option(sort keys %options) {
      my $o = $options{$option};
      my $value = defined $ioptions-&gt;{$option} ? $ioptions-&gt;{$option} : '';
      
      $out .= "&lt;tr&gt;&lt;td&gt;" . (exists $o-&gt;{img} ? "&lt;label for=\"$option\"&gt;&lt;img src=\"$config-&gt;{image_path}/$o-&gt;{img}\"&gt; " : '') . "&lt;b&gt;$option&lt;/b&gt;" . (exists $o-&gt;{info} ? " ($o-&gt;{info})" : '') . "&lt;/td&gt;&lt;td&gt;";
      if($o-&gt;{type} eq 'toggle') {
         $out .= "&lt;input class=\"options-checkbox\" type=\"checkbox\" name=\"$option\" value=\"1\"" . 
            ($value? ' checked=1' : '')."\" onclick=\"parent.fwindowlist.send_option(this.name, this.checked == true ? this.value : 0);return true;\"&gt;";
      }elsif($o-&gt;{type} eq 'select') {
         $out .= "&lt;select name\"$option\" onchange=\"parent.fwindowlist.send_option('$option', this.options[this.selectedIndex].value);return true\" class=\"options-select\"&gt;";
         for(@{$o-&gt;{options}}) {
            $out .= "&lt;option class=\"options-option\" name=\"$option\" value=\"$_\"".($_ eq $value ? ' selected=1' : '') . "&gt;$_&lt;/option&gt;";
         }
         $out .= "&lt;/select&gt;";
      }else{
         $out .= "&lt;input class=\"options-input\" type=\"text\" name=\"$option\" value=\""._escapehtml($value)."\" onChange=\"parent.fwindowlist.send_option(this.name, this.value);return true;\"&gt;";
      }
      $out .= "&lt;/label&gt;&lt;/td&gt;&lt;/tr&gt;";
   }
   
$out .= "
&lt;/table&gt;&lt;/form&gt;&lt;span onclick=\"parent.fwindowlist.witemdel('-Options')\" class=\"options-close\"&gt;close&lt;/span&gt;&lt;/body&gt;&lt;/html&gt;
";
   $out =~ s/\n//g;
   _func_out('doinfowin', '-Options', $out);
}

sub say {
   my($self) = @_;
   return 'ok';
}

sub fwindowlist {
   my($self, $cgi, $config) = @_;
   my $string;
   for(keys %$cgi) {
      next if $_ eq 'item';
	  $string .= main::cgi_encode($_) . '=' . main::cgi_encode($cgi-&gt;{$_}).'&amp;';
   }
   $string =~ s/\&amp;$//;
print $standardheader;
print q~
&lt;html&gt;
&lt;head&gt;
&lt;script language="JavaScript"&gt;
&lt;!--
// This javascript code is released under the same terms as CGI:IRC itself
// http://cgiirc.sourceforge.net/
// Copyright (C) 2000-2003 David Leadbeater &lt;cgiirc\@dgl.cx&gt;

//               none      joins    talk       directed talk
var activity = ['#000000','#000099','#990000', '#009999'];

var Witems = {};
var options = {};
var currentwindow = '';
var lastwindow = '';
var connected = 0;
var mynickname = '';
var prefixchars = '@%+ ';


function witemadd(name, channel) {
   if(Witems[name] || findwin(name)) return;
   name = name.replace(/\"/g, '&amp;quot;');
   Witems[ name ] = { activity: 0, text: new Array, channel: channel, speak: 1,  info: 0 };
   if(channel) {
      Witems[name].users = {};
	  Witems[name].topic = '';
   }
   if(!currentwindow) currentwindow = name;
   wlistredraw();
}

function witemnospeak(name) {
   if(!Witems[name] &amp;&amp; !(name = findwin(name))) return;
   Witems[name].speak = 0;
}

function witeminfo(name) {
   if(!Witems[name] &amp;&amp; !(name = findwin(name))) return;
   Witems[name].info = 1;
}

function witemdel(name) {
   if(!Witems[name] &amp;&amp; !(name = findwin(name))) return;
   if(name == 'Status') return;
   delete Witems[name];
   if(currentwindow == name) witemchg(lastwindow ? lastwindow : 'Status');
}

function witemclear(name) {
   if(!Witems[name] &amp;&amp; !(name = findwin(name))) return;
   Witems[name].text.length = 0;
   witemredraw();
}


function channeladdusers(channel, users) {
   for(var i = 0;i &lt; users.length;i++) {
      channeladduser(channel, users[i]);
   }
   userlist();
}

function channeladduser(channel, user) {
   var o = user.substr(0,1)
   if(prefixchars.lastIndexOf(o) != -1) {
      user = user.substr(1)
      while(prefixchars.lastIndexOf(user.substr(0,1)) != -1)
         user = user.substr(1)
   }

   if(!Witems[channel] &amp;&amp; !(channel = findwin(channel))) return;

   Witems[channel].users[user] = { };

   if(o == '@') Witems[channel].users[user].op = 1;
   else if(o == '%') Witems[channel].users[user].halfop = 1;
   else if(o == '+') Witems[channel].users[user].voice = 1;
   else if(prefixchars.lastIndexOf(o) != -1)
      Witems[channel].users[user].other = o;
}

function channelsdeluser(channels, user) {
   if(channels == '-all-') {
      for(var i in Witems) {
         if(!Witems[i].channel) continue;
         if(!Witems[i].users[user]) continue;
         channeldeluser(i, user);
      }
      return;
   }
   for(var i = 0;i &lt; channels.length; i++) {
      channeldeluser(channels[i], user);
   }
   userlist();
}

function channeldeluser(channel, user) {
   if(!Witems[channel] &amp;&amp; !(channel = findwin(channel))) return;
   delete Witems[channel].users[user];
   userlist();
}

function channelsusernick(olduser, newuser) {
   for(var channel in Witems) {
      if(!Witems[channel].channel) continue;
      for(var nick in Witems[channel].users) {
	      if(nick == olduser) {
            Witems[channel].users[newuser] = Witems[channel].users[olduser];
            delete Witems[channel].users[olduser];
		   }
	   }
   }
   userlist();
}

function channelusermode(channel, user, action, type) {
   if(!Witems[channel] &amp;&amp; !(channel = findwin(channel))) return;
   if(!Witems[channel].users[user]) return;

   if(action == '+') {
      Witems[channel].users[user][type] = 1;
   }else{
      delete(Witems[channel].users[user][type]);
   }
   userlist();
}

function channellist(channel) {
   if(!Witems[channel] &amp;&amp; !(channel = findwin(channel))) return;
   var users = new Array();

   for (var i in Witems[channel].users) {
      var user = Witems[channel].users[i];
      if(user.other) i = user.other + i;
     else if(user.op == 1) i = '@' + i
	  else if(user.halfop == 1) i = '%' + i;
	  else if(user.voice == 1) i = '+' + i;
     else   i = ' ' + i;

      users[users.length] = i;
   }

   users = users.sort(usersort);
   return users;
}

function usersort(user1,user2) {
   var m1 = user1.substr(0,1);
   var m2 = user2.substr(0,1);

   if(m1 == m2) {
      if(user1.toUpperCase() &lt; user2.toUpperCase()) return -1
	   return 1
   }

   if(prefixchars.lastIndexOf(m1) &lt; prefixchars.lastIndexOf(m2)) return -1
   return 1
}

function witemchg(name) {
   if(!Witems[name] &amp;&amp; !(name = findwin(name))) name = 'Status';
   if(Witems[name].activity &gt; 0) Witems[name].activity = 0;
   lastwindow = (Witems[currentwindow] ? currentwindow : 'Status');
   currentwindow = name;
   wlistredraw();
   witemredraw();
   formfocus();
   userlist();
   retitle();
}

function retitle() {
   parent.document.title = 'CGI:IRC - ' + (Witems[currentwindow].info ? currentwindow.substr(1) : currentwindow) + (Witems[currentwindow].channel == 1 ? ' [' + countit(Witems[currentwindow].users) + '] ' : '');
}

function setoption(option, value) {
   options[option] = value;
   if(option == 'shownick' &amp;&amp; value == 1)
      mynick(mynickname)
   else if(option == 'shownick') {
      if(parent.fform &amp;&amp; parent.fform.nickchange) parent.fform.nickchange('');
   }else if(option == 'font')
      fontset(value)
}

function mynick(mynick) {
   mynickname = mynick;
   if(options.shownick != 1) return;
   if(parent.fform &amp;&amp; parent.fform.nickchange) parent.fform.nickchange(mynick);
}

function maincolor(bg, fg) {
   var maindoc = parent.fmain.document;
   if(!maindoc) return;
   maindoc.bgColor = bg;
   maindoc.fgColor = fg;
}

function prefix(chars) {
   if(!/ /.test(chars))
      chars += ' '
   prefixchars = chars;
}

function witemchgnum(num) {
   var count = 1;
   for(var name in Witems) {
      if(count++ == num) return name;
   }
   return false;
}

function countit(obj) {
   var i = 0;
   for(var foo in obj) i++;
   return i;
}

function witemaddtext(name, text, activity, redraw) {
   if(name == '-all') {
      for(var window in Witems) {
        if(window == '-all') return
        if(Witems[window].info) continue;
	     witemaddtext(window, text, activity, redraw);
	  }
      return;
   }
   if(name == '-active') name = currentwindow

   if(!Witems[name] &amp;&amp; !(name = findwin(name))) {
      if(!Witems["Status"]) return;
	  name = "Status";
   }
   
   if(options["timestamp"] == 1 &amp;&amp; !Witems[name].info) {
      var D = new Date();
      text = '[' + (D.getHours() &lt; 10 ? '0' + D.getHours() : D.getHours()) + ':' + (D.getMinutes() &lt; 10 ? '0' + D.getMinutes() : D.getMinutes()) + '] ' + text;
   }
  
   if(options["scrollback"] == 0)
      Witems[name].text = Witems[name].text.slice(Witems[name].text.length - 200);
   if(!Witems[name].info)
      text = "&lt;div class='main-item'&gt;" + text + "&lt;/div&gt;";
   Witems[name].text[Witems[name].text.length] = text;

   if(options["actsound"] == 1 &amp;&amp; activity &gt;= 3)
      playsound("actmsg");

   if(currentwindow != name &amp;&amp; activity &gt; Witems[name].activity)
       witemact(name, activity);
   if(redraw != 0 &amp;&amp; currentwindow == name) witemredraw();
}

function witemact(name, activity) {
   if(!Witems[name] &amp;&amp; !(name = findwin(name))) return;
   Witems[name].activity = activity;
   wlistredraw();
}

function witemredraw() {
   if(!parent.fmain.document) {
      setTimeout("witemredraw()", 1000);
	  return;
   }
   var doc = parent.fmain.document.body;
   var scrollok = 1;
   if(!currentwindow) currentwindow = 'Status';
   parent.fmain.document.getElementById('text').innerHTML = Witems[currentwindow].text.join('');
   if(Witems[currentwindow].info == 1) return;
   var doc = parent.fmain.window;
   var scroll = -1;
   while(doc.scrollY &gt; scroll) {
	  scroll = doc.scrollY;
	  doc.scrollBy(0, 500);
   }
}

function wlistredraw() {
   var output='';
   for (var i in Witems) {
      output += '&lt;span class="' + (i == currentwindow ? 'wlist-active' : 'wlist-chooser') + '" style="color: ' + activity[Witems[i].activity] + ';" onclick="witemchg(\'' + (i == currentwindow ? escapejs(lastwindow) : escapejs(i)) + '\')" onmouseover="this.className = \'wlist-mouseover\'" onmouseout="this.className = \'' + (i == currentwindow ? 'wlist-active' : 'wlist-chooser') + '\'"&gt;' + escapehtml(Witems[i].info ? i.substr(1) : i) + '&lt;/span&gt;\r\n';
   }
   document.getElementById('windowlist').innerHTML = output;
}

function findwin(name) {
   var wname = new String(name);
   wname = wname.replace(/\"/g, '&amp;quot;');
   for (var i in Witems) {
      if (i.toUpperCase() == wname.toUpperCase())
	     return i;
   }
   return false;
}

function escapejs(string) {
   out = string.replace(/\\\\/g,'\\\\\\\\').replace(/\\'/g, '\\\\\\'').replace(/\"/g, '&amp;quot;');
   return out;
}

function escapehtml(string) {
   var out = string;
   out = out.replace(/&lt;/g, '&amp;lt;');
   out = out.replace(/&gt;/g, '&amp;gt;');
   out = out.replace(/\"/g, '&amp;quot;');
   return out;
}

function reconnect() {
	  do_quit();
     Witems = { };
     document.getElementById('iframe').src = document.getElementById('iframe').src + '&amp;xx=yy';
}

function sendcmd(cmd) {
   if(cmd.substr(0, 10) == '/reconnect') {
      reconnect();
      return;
   }

   if(!connected &amp;&amp; cmd.substr(0,5) != '/quit') {
	  alert('Not connected to IRC!');
	  return;
   }
   if(Witems[currentwindow] &amp;&amp; !Witems[currentwindow].speak &amp;&amp; cmd.substr(0,1) != '/') return;
   sendcmd_real('say', cmd, currentwindow);
}

function sendcmd_userlist(action, user) {
   if(!Witems[currentwindow].channel) return;
   if(!connected) {
      alert('Not connected to IRC!');
      return;
   }
   sendcmd_real('say', '/' + action + ' ' + user, currentwindow);
}

function sendcmd_real(type, say, target) {
   send_make({ item: 'say', cmd: type, say: say, target: target })
}

function senditem(item) {
   send_make({ item: item })
}

function send_option(name, value) {
   send_make({ cmd: 'options', name: name, value: value })
}

function send_make(data) {
   var xmlhttp = xmlhttp_new()
   if(!xmlhttp) {
      for(var i in data) {
         document.hsubmit[i].value = data[i]
      }
      document.hsubmit.submit();
      for(var i in data) {
         document.hsubmit[i].value = ""
      }
   }else{
      xmlhttp_send(xmlhttp, data)
   }
}

function userlist() {
   if(!parent.fuserlist.userlist) {
      setTimeout(1000, "userlist()");
      return;
   }
   if(Witems[currentwindow] &amp;&amp; Witems[currentwindow].channel == 1) {
      userlistupdate(channellist(currentwindow));
   }else{
      userlistupdate([' No channel']);
   }
   retitle();
}

function userlistupdate(list) {
   if(!parent.fuserlist.userlist) return;
   parent.fuserlist.userlist(list);
}

function formfocus() {
   if(parent.fform.location) parent.fform.fns();
}

function disconnected() {
   if(connected == 1) {
	  connected = 0;
	  do_quit();
	  witemaddtext('-all', '&lt;b&gt;Disconnected&lt;/b&gt;', 1, 1);
   }
}

function doinfowin(name, text) {
   witemadd(name, 0);
   witemnospeak(name);
   witeminfo(name);
   witemclear(name);
   witemaddtext(name, text, 0, 1);
   witemchg(name);
}

function fontset(font) {
   if(parent.frames.fmain.document.getElementById('text')) {
      parent.frames.fmain.document.getElementById('text').style.fontFamily = font;
   }
}

function playsound(soundname) {
      top.window.focus();
}

function joinsound() {
   if(options["joinsound"] == 1)
      playsound("join");
}

~;
# ' (fix syntax hilight)
print &lt;&lt;EOF;
imghelpdn = new Image();
imghelpdn.src = "$config-&gt;{image_path}/helpdn.gif";
imghelpup = new Image();
imghelpup.src = "$config-&gt;{image_path}/helpup.gif";

imgoptionsdn = new Image();
imgoptionsdn.src = "$config-&gt;{image_path}/optionsdn.gif";
imgoptionsup = new Image();
imgoptionsup.src = "$config-&gt;{image_path}/optionsup.gif";

imgclosedn = new Image();
imgclosedn.src = "$config-&gt;{image_path}/closedn.gif";
imgcloseup = new Image();
imgcloseup.src = "$config-&gt;{image_path}/closeup.gif";

function do_quit() {
   var i = new Image();
   i.src = "$config-&gt;{script_form}?R=$cgi-&gt;{R}&amp;cmd=quit";
}
function xmlhttp_new() {
   if(window.XMLHttpRequest)
      xmlhttp = new XMLHttpRequest()
   else if (window.ActiveXObject)
      xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
   return xmlhttp
}

function xmlhttp_send(xmlhttp, data) {
   var send = "";
   xmlhttp.open("POST", "$config-&gt;{script_form}", 1)
   xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8")
   xmlhttp.onreadystatechange = post_results
   data.R = "$cgi-&gt;{R}";
   data.xmlhttp = 1; // should be header (needs client.cgi proto changes...)
   for(var i in data)
      send += i + "=" + escape(data[i]) + "&amp;"
   xmlhttp.send(send)
   return false
}

function post_results() {
   if(xmlhttp.readyState &lt; 4)
      return

   if(xmlhttp.status != 200) {
      var w = window.open()
      w.document.write(xmlhttp.responseText)
      w.document.close()
      return
   }
}
// --&gt;
&lt;/script&gt;
&lt;link rel="stylesheet" href="$config-&gt;{script_login}?interface=mozilla&amp;item=style&amp;style=$cgi-&gt;{style}" /&gt;
&lt;/head&gt;
&lt;body onload="wlistredraw()" onkeydown="formfocus()" onbeforeunload="do_quit()" onunload="do_quit()" class="wlist-body"&gt;
&lt;noscript&gt;Scripting is required for this interface&lt;/noscript&gt;
&lt;table class="wlist-table"&gt;
&lt;tr&gt;&lt;td width="1"&gt;
&lt;iframe src="$config-&gt;{script_nph}?$string" id="iframe" width="1" height="1" style="border:0"&gt;&lt;/iframe&gt;

&lt;iframe src="$config-&gt;{script_login}?interface=mozilla&amp;item=blank" id="iframe" width="1" height="1" style="border:0" name="hiddenframe"&gt;&lt;/iframe&gt;
&lt;/td&gt;
&lt;td id="windowlist" class="wlist-container"&gt;
&lt;/td&gt;&lt;td class="wlist-buttons"&gt;
&lt;img src="$config-&gt;{image_path}/helpup.gif" onclick="if(connected == 0)return;sendcmd('/help');" class="wlist-button" onmousedown="this.src=imghelpdn.src" onmouseup="this.src=imghelpup.src;" onmouseout="this.src=imghelpup.src;" title="Help"&gt;
&lt;/td&gt;&lt;td class="wlist-buttons"&gt;
&lt;img src="$config-&gt;{image_path}/optionsup.gif" onclick="senditem('options');" class="wlist-button" onmousedown="if(connected == 0)return;this.src=imgoptionsdn.src" onmouseup="this.src=imgoptionsup.src;" onmouseout="this.src=imgoptionsup.src;" title="Options"&gt;
&lt;/td&gt;&lt;td class="wlist-buttons"&gt;
&lt;img src="$config-&gt;{image_path}/closeup.gif" onclick="if(connected == 0)return;if(currentwindow != 'Status'){sendcmd('/winclose')}else if(confirm('Are you sure you want to quit?')){do_quit();parent.location='$config-&gt;{script_login}'}" class="wlist-button" onmousedown="this.src=imgclosedn.src" onmouseup="this.src=imgcloseup.src;" onmouseout="this.src=imgcloseup.src;" title="Close"&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;form name="hsubmit" method="post" action="$config-&gt;{script_form}" target="hiddenframe"&gt;
&lt;input type="hidden" name="R" value="$cgi-&gt;{R}"&gt;
&lt;input type="hidden" name="cmd" value="say"&gt;
&lt;input type="hidden" name="item" value="say"&gt;
&lt;input type="hidden" name="say" value=""&gt;
&lt;input type="hidden" name="target" value=""&gt;
&lt;input type="hidden" name="name" value=""&gt;
&lt;input type="hidden" name="value" value=""&gt;
&lt;/form&gt;
&lt;/body&gt;&lt;/html&gt;
EOF

}
sub fmain {
   my($self, $cgi, $config) = @_;
print &lt;&lt;EOF;
$standardheader
&lt;html&gt;&lt;head&gt;
&lt;link rel="stylesheet" href="$config-&gt;{script_login}?interface=mozilla&amp;item=style&amp;style=$cgi-&gt;{style}" /&gt;
&lt;/head&gt;
&lt;body class="main-body"
onkeydown="if((event &amp;&amp; ((event.keyCode &lt; 30 || event.keyCode &gt; 40) &amp;&amp; (event.keyCode &lt; 112 || event.keyCode &gt; 123) &amp;&amp; !event.ctrlKey)) &amp;&amp; parent.fform.location) { parent.fform.fns(); return false; }"
onkeypress="if((event &amp;&amp; ((event.keyCode &lt; 30 || event.keyCode &gt; 40) &amp;&amp; (event.keyCode &lt; 112 || event.keyCode &gt; 123) &amp;&amp; !event.ctrlKey)) &amp;&amp; parent.fform.location) { parent.fform.fns(); return false; }"
&gt;

&lt;span class="main-span" id="text"&gt;&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;
EOF
}
sub fuserlist {
   my($self, $cgi, $config) = @_;
print &lt;&lt;EOF;
$standardheader
&lt;html&gt;
&lt;head&gt;
&lt;script language="JavaScript"&gt;
&lt;!--
var selected;

function fsubmit(form) {
   var action = form.action.options[form.action.selectedIndex].value;
   var user = form.user.value;

   if(!user || !action) {
      alert("No user or action selected");
      return false;
   }
   user = user.replace(/^[@%+ ]/, '');
   parent.fwindowlist.sendcmd_userlist(action, user);
   return false;
}

function deselect() {
   if(!selected) return;
   selected.className = 'userlist-item';
}

function userlist(users) {
   var tmp = '&lt;table class="userlist-table"&gt;';
   for(var i = 0;i &lt; users.length; i++) {
      var status = users[i].substr(0, 1);
      var user = users[i].substr(1);

      tmp += '&lt;tr&gt;&lt;td class="userlist-status"&gt; ' + statushtml(status) + ' &lt;/td&gt;'
          + '&lt;td class="userlist-item" ' + 
        (user != 'No channel' ? 
          ' onmouseout="this.className=(this == selected ?'
          + '\\'userlist-selected\\':\\'userlist-item\\')"'
          + ' onmouseover="this.className=\\'userlist-hover\\'"'
          + ' onclick="' + 'this.className=\\'userlist-selected\\';'
          + 'deselect();selected = this;document.mform.user.value = \\''
          + parent.fwindowlist.escapejs(user) + '\\';return false;" ondblclick="fsubmit(document.mform);"'
          : '') + '&gt;' + user + '&lt;/td&gt;&lt;/tr&gt;';
   }
   tmp += '&lt;/table&gt;';
   document.getElementById('usertable').innerHTML = tmp;
   document.mform.user.value = '';
}

function statushtml(status) {
   if(status == "@") {
      return '&lt;div class="userlist-op"&gt;@&lt;/div&gt;';
   }else if(status == "+") {
      return '&lt;div class="userlist-voice"&gt;+&lt;/div&gt;';
   }else if(status == "%") {
      return '&lt;div class="userlist-halfop"&gt;%&lt;/div&gt;';
   }else if(status == ' ') {
      return '';
   }else{
      return '&lt;div class="userlist-other"&gt;' + status + '&lt;/div&gt;';
   }
}

// --&gt;
&lt;/script&gt;
&lt;link rel="stylesheet" href="$config-&gt;{script_login}?interface=mozilla&amp;item=style&amp;style=$cgi-&gt;{style}" /&gt;
&lt;/head&gt;

&lt;body class="userlist-body" onkeydown="if((event &amp;&amp; event.keyCode &amp;&amp; ((event.keyCode &lt; 30 || event.keyCode &gt; 40) &amp;&amp; (event.keyCode &lt; 112 || event.keyCode &gt; 123) &amp;&amp; !event.ctrlKey)) &amp;&amp; parent.fform.location) { parent.fform.fns(); return false; }"&gt;

&lt;div class="userlist-div" id="usertable"&gt;

&lt;table class="userlist-table"&gt;
&lt;tr&gt;&lt;td class="userlist-status"&gt;&lt;/td&gt;
&lt;td class="userlist-item"&gt;No channel&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;/div&gt;

&lt;form name="mform" onsubmit="return fsubmit(this)" class="userlist-form"&gt;
&lt;input type="hidden" name="user"&gt;
&lt;select name="action" class="userlist-select"&gt;
&lt;option value="query"&gt;Query&lt;/option&gt;
&lt;option value="whois"&gt;Whois&lt;/option&gt;
&lt;option value="kick"&gt;Kick&lt;/option&gt;
&lt;/select&gt;
&lt;input type="submit" class="userlist-btn" value="&amp;gt;&amp;gt;"&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;
EOF
}
sub fform {
   my($self, $cgi, $config) = @_;
print &lt;&lt;EOF;
$standardheader
&lt;html&gt;
&lt;head&gt;
&lt;html&gt;&lt;head&gt;
&lt;script language="JavaScript"&gt;&lt;!--
var shistory = [ ];
var hispos;
var tabtmp = [ ];
var tabpos;
var tablen;
var tabinc;

function fns(){
   if(!document.myform.say) return;
   document.myform.say.focus();
}

function t(item,text) {
   if(item.style.display == 'none') {
      item.style.display = 'inline';
	  text.value = '&gt;&gt;';
	  document.myform.say.style.width='10%' // For IE
     document.myform.say.style.width = document.body.offsetWidth - document.getElementById('excont').offsetWidth - 20
   }else{
      item.style.display = 'none';
	  text.value = '&lt;&lt;';
	  document.myform.say.style.width='90%'
   }
   fns();
}

function load() {
   fns();
EOF
if($ENV{HTTP_USER_AGENT} !~ /Mac_PowerPC/ &amp;&amp; (!exists $config-&gt;{disable_format_input} || !$config-&gt;{disable_format_input})) {
print "document.getElementById('extra').style.display = 'none';"
}
print &lt;&lt;EOF;
   document.onkeypress = enter_key_trap;
}

function append(a) {
   document.myform["say"].value += a;
   fns();
}

function cmd() {
   if(document.myform["say"].value.length &lt; 1) return false;
   hisadd();
   tabpos = 0;
   tabtmp = [];
   parent.fwindowlist.sendcmd(document.myform["say"].value);
   document.myform["say"].value = ''
   return false;
}

function nickchange(nick) {
   if(document.getElementById('nickname'))
      document.getElementById('nickname').innerHTML = nick;
}

function hisadd() {
   shistory[shistory.length] = document.myform["say"].value;
   hispos = shistory.length;
}

function hisdo() {
   if(shistory[hispos]) {
      document.myform["say"].value = shistory[hispos];
   }else{
      document.myform["say"].value = '';
   }
}

function enter_key_trap(e) {
   if(e == null) { // MSIE
      return keypress(event.srcElement, event);
   }else{ // Mozilla, Netscape, W3C
      return keypress(e.target, e);
   }
}

function keypress(srcEl, event) {
   if (srcEl.tagName != 'INPUT' || srcEl.name.toLowerCase() != 'say')
       return true;
   var charCode = event.charCode; // MSIE: undef, Mozilla: different when shifted
   var keyCode = event.keyCode; // the only one in MSIE, Mozilla: only special keys (up, down, etc)
   var which = event.which; // the only one in NN

   if(keyCode == null) { // NN
      charCode = which;
      if(which &lt; 32) keyCode = which;
      // NN only has charcodes (and some special keys below 32, i.e. Esc)
   }
   if(charCode == null) charCode = keyCode; // MSIE

EOF
if(!exists $config-&gt;{disable_format_input} || !$config-&gt;{disable_format_input}) {
print &lt;&lt;EOF;
   if((charCode == 66 || charCode == 98) &amp;&amp; event.ctrlKey) {
       // in NN/Mozilla charcodes are case sensitive
       append('\%B');
   }else if((charCode == 67 || charCode == 99) &amp;&amp; event.ctrlKey) {
       append('\%C');
   }
EOF
}
print &lt;&lt;EOF;
   
   if(keyCode == 9) { // TAB
       var tabIndex = srcEl.value.lastIndexOf(' ');
	   var tabStr = srcEl.value.substr(tabIndex+1 || tabIndex).toLowerCase();

       if(tabpos == tabIndex &amp;&amp; !tabStr &amp;&amp; tabtmp.length) {
	      if(tabinc &gt;= tabtmp.length) tabinc = 0;
	      for(var i = (tabinc &gt; 0 ? tabinc : 0); i &lt; tabtmp.length;i++) {
			 srcEl.value = srcEl.value.substr(0, tabIndex - tablen) + 
			       tabtmp[i] + (tabIndex == tablen ? ': ' : ' ');
			 tabpos = (tabIndex == -1 ? 0 : tabIndex) + tabtmp[i].length - tablen + (tabIndex == tablen ? 1 : 0);
			 tablen = tabtmp[i].length + (tabIndex == tablen ? 1 : 0);
			 tabinc++;
			 break;
		  }
	   }else{
	      tabtmp = [];
	      var list = parent.fwindowlist.channellist(parent.fwindowlist.currentwindow);
		  for(var i = 0;i &lt; list.length; i++) {
		     var item = list[i].replace(/^[+%@ ]/,'');
		     if(item.substr(0, tabStr.length).toLowerCase() == tabStr) {
			    tabtmp[tabtmp.length] = item;
			 }
		  }
		  if(!tabtmp[0]) {
		     for(var i in parent.fwindowlist.Witems) {
			    if(i.substr(0, tabStr.length).toLowerCase() == tabStr) {
               if(parent.fwindowlist.Witems[i].speak)
				      tabtmp[tabtmp.length] = i;
				}   
			 }
		  }
		  if(!tabtmp[0]) return false;
		  srcEl.value = srcEl.value.substr(0, tabIndex) + 
		        (tabIndex &gt; 0 ? ' ' : '') + tabtmp[0] + (tabIndex == -1 ? ': ' : ' ');
		  tablen = tabtmp[0].length + (tabIndex == -1 ? 1 : 0);
		  tabpos = (tabIndex == -1 ? 0 : tabIndex + 1) + tablen;
		  tabinc = 1;
	   }
   }else if(keyCode == 38) { // UP, doesn't work in NN
       if(!shistory[hispos]) {
	      if(document.myform["say"].value) hisadd();
		  hispos = shistory.length;
	   }
	   hispos--;
	   hisdo();
   }else if(keyCode == 40) { // DOWN, dito
       if(!shistory[hispos]) {
	      if(document.myform["say"].value) hisadd();
		  document.myform["say"].value = '';
		  return false;
	   }
	   hispos++;
	   hisdo();
   }else if(((event.altKey &amp;&amp; !event.ctrlKey) || (!event.altKey &amp;&amp; event.ctrlKey)) &amp;&amp; charCode &gt; 47 &amp;&amp; charCode &lt; 58) {
       // Alt or Ctrl + number is often bound to browser functions
       // Ctrl+Alt is totally equal to AltGr on Windows (strange!)
       // so use Ctrl+num or Alt+num, whatever the browser passes through
       var num = charCode - 48;
	   if(num == 0) num = 10;

	   var name = parent.fwindowlist.witemchgnum(num);
	   if(!name) return false;
	   parent.fwindowlist.witemchg(name);
   }else if(keyCode == 27) { // ignore escape (to stop..)
   }else{
       return true;
   }
   return false;
}

function pastedata(text) {
   var paste = text.split("\\n");
   if(paste.length == 1)
      return true;
   if(paste.length &gt; 20) {
      alert("You can't paste more than 20 lines");
      return false;
   }

   if(paste.length &lt; 5 ||
     confirm("Are you sure you want to paste " + paste.length + " lines?")) {
      parent.fwindowlist.sendcmd_real('paste', text, parent.fwindowlist.currentwindow);
      return false;
   }
}

//--&gt;
&lt;/script&gt;
&lt;link rel="stylesheet" href="$config-&gt;{script_login}?interface=mozilla&amp;item=style&amp;style=$cgi-&gt;{style}" /&gt;
&lt;/head&gt;
&lt;body onload="load()" onfocus="fns()" class="form-body"&gt;
&lt;form name="myform" onSubmit="return cmd();" class="form-form"&gt;
&lt;span id="nickname" class="form-nickname"&gt;&lt;/span&gt;
&lt;input type="text" class="form-say" name="say" autocomplete="off"
  onpaste="return pastedata(window.clipboardData.getData('Text',''));"&gt;
&lt;/form&gt;
EOF
if($ENV{HTTP_USER_AGENT} !~ /Mac_PowerPC/ &amp;&amp; (!exists $config-&gt;{disable_format_input} || !$config-&gt;{disable_format_input})) {
print &lt;&lt;EOF;
&lt;span class="form-econtain" id="excont"&gt;
&lt;input type="button" class="form-expand" onclick="t(document.getElementById('extra'),this);" value="&amp;lt;&amp;lt;"&gt;
&lt;span id="extra" class="form-extra"&gt;
&lt;input type="button" class="form-boldbutton" value="B" onclick="append('\%B')"&gt;
&lt;input type="button" class="form-boldbutton" value="_" onclick="append('\%U')"&gt;
EOF
for(sort {$a &lt;=&gt; $b} keys %colours) {
   print "&lt;input type=\"button\" style=\"background: $colours{$_}\" value=\"&amp;nbsp;\" onclick=\"append('\%C$_')\"&gt;\n";
}
print &lt;&lt;EOF;
&lt;/span&gt;
&lt;/span&gt;
EOF
}
print &lt;&lt;EOF;
&lt;/body&gt;
&lt;/html&gt;
EOF
}

1;
</pre></body></html>