diff --git a/irc/weechat/antifuck.pl b/irc/weechat/antifuck.pl
@@ -0,0 +1,369 @@
+# Released into the Public Domain
+
+use strict;
+use warnings;
+
+no strict 'subs';
+
+my $SCRIPT_NAME = 'antifuck';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.1';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Defend against forcejoins (e.g. from fuckyou.pl) and '.
+ 'forceparts (e.g. from /remove)';
+
+my %OPTIONS = (
+ autopart => ['Whether to automatically part forcejoined channels. '.
+ 'You can always do this manually with /antifuck part', '0'],
+ delay => ['Delay in milliseconds to wait before autoparting', '5000'],
+ forward => ['Whether to allow channel forwards (+f on freenode)', '1'],
+ ignore => ['Servers to ignore (e.g. for bouncers), separated by comma', ''],
+ nobufs => ['If 1, do not create buffers for forcejoined channels', '0'],
+ timeout =>
+ ['Delay in milliseconds to wait for server to send JOIN after join',
+ '60000'],
+ );
+
+# %channels: channels we joined and received JOIN / NAMES for
+# %zombie: channels we joined but aren't yet in
+# %part: channels we were forced into and will part soon
+# %partbuf: buffers belonging to parted channels, we'll close these on
+# /antifuck part
+our (%channels, %zombie, %part, %partbuf, $fuckbuf, $timeout_cb, $gc_cb);
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ weechat::hook_command('antifuck', $SCRIPT_DESC, 'part', <<'HELP',
+This script defends against forced joins, such as from irssi's fuckyou.pl or
+from channel forwards, as well as forced parts, such as from the /remove
+command. You can configure certain behaviour using the options under
+"plugins.var.perl.antifuck.*". Configure rejoin-on-/remove with the
+irc.server_default.autorejoin and .autorejoin_delay commands.
+
+Running "/antifuck part" will close all forcejoined channels and part them where
+appropriate.
+HELP
+ 'part', 'cmd_antifuck', '');
+ weechat::hook_signal('irc_server_connected', 'irc_connect', '');
+ weechat::hook_signal('irc_server_disconnected', 'irc_disconnect', '');
+ weechat::hook_signal('irc_channel_opened', 'buffer_opened', '');
+ weechat::hook_signal('buffer_closed', 'buffer_closed', '');
+ weechat::hook_signal('*,irc_out1_join', 'client_join', '');
+ weechat::hook_signal('*,irc_out1_part', 'client_part', '');
+ weechat::hook_signal('*,irc_raw_in_001', 'irc_001', '');
+ weechat::hook_signal('*,irc_raw_in_470', 'irc_470', '');
+ weechat::hook_modifier('irc_in_366', 'irc_366', '');
+ weechat::hook_modifier('irc_in_join', 'irc_join', '');
+ weechat::hook_modifier('irc_in_part', 'irc_part', '');
+
+ for my $option (keys %OPTIONS) {
+ weechat::config_set_plugin($option, $OPTIONS{$option}[1])
+ unless weechat::config_is_set_plugin($option);
+ weechat::config_set_desc_plugin($option, $OPTIONS{$option}[0]);
+ }
+
+ my $iptr = weechat::infolist_get('buffer', '', '');
+
+ while (weechat::infolist_next($iptr)) {
+ next unless weechat::infolist_string($iptr, 'plugin_name') eq 'irc';
+ my $buf = weechat::infolist_pointer($iptr, 'pointer');
+ $channels{
+ lc weechat::buffer_get_string($buf, 'localvar_server')}{
+ lc weechat::buffer_get_string($buf, 'localvar_channel')} = 1;
+ }
+ weechat::infolist_free($iptr);
+}
+
+sub mynick
+{
+ my ($buf, $nick) = ($_[0], $_[1]);
+
+ return lc weechat::buffer_get_string($buf, 'localvar_nick') eq lc $nick;
+}
+
+sub ignored
+{
+ my $server = shift;
+ my $ignore_conf = lc weechat::config_get_plugin('ignore');
+
+ return $ignore_conf =~ /(^|,)$server($|,)/;
+}
+
+sub nobufs { weechat::config_get_plugin('nobufs') }
+
+sub ircbuf { weechat::buffer_search('irc', "(?i)".(join '.', @_)) }
+sub ircparse { weechat::info_get_hashtable(irc_message_parse =>
+ { message => shift }) }
+
+sub servchan
+{
+ my $buf = shift;
+
+ return (lc weechat::buffer_get_string($buf, 'localvar_server'),
+ lc weechat::buffer_get_string($buf, 'localvar_channel'));
+}
+
+sub reset_gc
+{
+ weechat::unhook($gc_cb) if $gc_cb;
+ $gc_cb = weechat::hook_timer(weechat::config_get_plugin('timeout'), 0, 1,
+ 'run_gc', '');
+}
+
+sub cmd_antifuck
+{
+ my (undef, $buffer, $args) = @_;
+
+ if ($args eq 'part') {
+ # TODO: we really need to spend more time here making sure we send the
+ # fewest PARTs possible, a la irc_join_delay
+ weechat::buffer_close($fuckbuf);
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub fuckbuf_input { return weechat::WEECHAT_RC_OK; }
+
+sub fuckbuf_close
+{
+ weechat::buffer_close($_) for (keys %partbuf);
+ %partbuf = ();
+ $fuckbuf = '';
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_connect
+{
+ my $server = pop;
+ my ($autojoin) = (weechat::config_string(weechat::config_get(
+ "irc.server.$server.autojoin")) =~ /^([^ ]*)/);
+
+ $zombie{$server}{$_} = 1 for (split ',', lc($autojoin));
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_disconnect
+{
+ my $server = pop;
+
+ $server = lc $server;
+ delete $channels{$server};
+ delete $zombie{$server};
+ delete $part{$server};
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub buffer_opened {
+ my $buffer = pop;
+ my ($server, $channel) = servchan($buffer);
+ return weechat::WEECHAT_RC_OK if exists $channels{$server}{$channel};
+ return weechat::WEECHAT_RC_OK if ignored($server);
+
+ $fuckbuf = weechat::buffer_new(
+ 'antifuck',
+ 'fuckbuf_input',
+ '',
+ 'fuckbuf_close',
+ ''
+ ) unless $fuckbuf;
+
+ weechat::buffer_merge($buffer, $fuckbuf);
+ #return weechat::WEECHAT_RC_OK unless weechat::config_get_plugin('autopart');
+
+ $partbuf{$buffer} = 1;
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub buffer_closed {
+ my $buffer = pop;
+
+ delete $partbuf{$buffer};
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub client_join
+{
+ my (undef, $server, $channel) = (shift,
+ shift =~ /(.+),irc_out1_join/i,
+ shift =~ /^join :?([^ ]*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+
+ reset_gc();
+
+ ($_ eq '0' ? %{$channels{$server}} = () : $zombie{$server}{$_} = 1)
+ for (split ',', $channel);
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub client_part
+{
+ my (undef, $server, $channel) = (shift,
+ shift =~ /(.+),irc_out1_part/i,
+ shift =~ /^part ([^ ]*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+
+ delete $channels{$server}{$_} for (split ',', $channel);
+ return weechat::WEECHAT_RC_OK;
+}
+
+# RPL_WELCOME
+sub irc_001
+{
+ my (undef, $server, $message) = (shift,
+ shift =~ /(.+),irc_raw_in_001/, shift);
+
+ $server = lc $server;
+ return weechat::WEECHAT_RC_OK unless $message =~ / :- Welcome to ZNC -$/;
+
+ my $ignore_conf = lc weechat::config_get_plugin('ignore');
+ return weechat::WEECHAT_RC_OK if $ignore_conf =~ /(^|,)$server($|,)/;
+
+ weechat::config_set_plugin('ignore', "$ignore_conf,$server");
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_join
+{
+ my ($server, $message, $msghash) = (lc $_[2], $_[3], ircparse($_[3]));
+ my ($nick, $channel) = ($msghash->{nick}, lc $msghash->{channel});
+ my $buffer = ircbuf("$server.$channel");
+
+ return $message if exists $channels{$server}{$channel};
+ if (exists $zombie{$server}{$channel} || ignored($server)) {
+ delete $zombie{$server}{$channel};
+ $channels{$server}{$channel} = 1;
+ return $message;
+ }
+ # XXX return $message unless mynick($buffer, $nick);
+
+ $part{$server}{$channel} = 1;
+ $timeout_cb = weechat::hook_timer(
+ weechat::config_get_plugin('delay'), 0, 1, 'irc_join_delay', $buffer)
+ unless $timeout_cb || !weechat::config_get_plugin('autopart');
+
+ return $message unless nobufs();
+
+ $fuckbuf = weechat::buffer_new(
+ 'antifuck',
+ 'fuckbuf_input',
+ '',
+ 'fuckbuf_close',
+ ''
+ ) unless $fuckbuf;
+ weechat::print($fuckbuf, weechat::prefix('join').
+ weechat::color('irc.color.message_join').
+ 'You were forced to join '.weechat::color('chat_channel').$channel.
+ weechat::color('irc.color.message_join').', leaving');
+
+ return '';
+}
+
+# RPL_ENDOFNAMES
+sub irc_366
+{
+ my ($server, $message) = ($_[2], $_[3]);
+ my ($nick, $channel) = $message =~ /^:[^ ]* 366 ([^ ]*) ([^ ]*)/i;
+ my $buffer = ircbuf("$server.$channel");
+ ($server, $channel) = (lc $server, lc $channel);
+
+ return $message if exists $channels{$server}{$channel};
+ return '' if nobufs();
+
+ weechat::print($buffer, weechat::prefix('network').
+ 'Forcejoined, not syncing modes');
+
+ return '';
+}
+
+# ERR_LINKCHANNEL
+sub irc_470
+{
+ my (undef, $server, $oldchan, $newchan) = (shift,
+ shift =~ /(.+),irc_raw_in_470/,
+ shift =~ /^:[^ ]* 470 [^ ]+ ([^ ]+) ([^ ]+)/);
+ ($server, $oldchan, $newchan) = (lc $server, lc $oldchan, lc $newchan);
+
+ delete $channels{$server}{$oldchan};
+ $channels{$server}{$newchan} = 1 if weechat::config_get_plugin('forward');
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_join_delay
+{
+ my $buffer = shift;
+
+ for my $server (keys %part) {
+ my $chans = '';
+
+ for my $chan (keys %{$part{$server}}) {
+ if (length($chans) + length($chan) > 500) {
+ weechat::hook_signal_send('irc_input_send',
+ weechat::WEECHAT_HOOK_SIGNAL_STRING,
+ "$server;;priority_low;;/part $chans");
+ $chans = '';
+ }
+
+ $chans .= "$chan,";
+ }
+
+ weechat::hook_signal_send('irc_input_send',
+ weechat::WEECHAT_HOOK_SIGNAL_STRING,
+ "$server;;priority_low;;/part $chans");
+ }
+ $timeout_cb = '';
+ %part = ();
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub run_gc
+{
+ %zombie = ();
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_part
+{
+ my ($server, $message, $msghash) = ($_[2], $_[3], ircparse($_[3]));
+ my ($arj, $arj_delay, $arjd, $arjd_delay) = (
+ weechat::config_get("irc.server.$server.autorejoin"),
+ weechat::config_get("irc.server.$server.autorejoin_delay"),
+ weechat::config_get("irc.server_default.autorejoin"),
+ weechat::config_get("irc.server_default.autorejoin_delay")
+ );
+ return $message unless (
+ weechat::config_option_is_null($arj) ?
+ weechat::config_boolean($arjd) :
+ weechat::config_boolean($arj)
+ );
+
+ my ($nick, $channel, $reason) = ($msghash->{nick}, $msghash->{channel},
+ $msghash->{text});
+
+ my $buffer = ircbuf("$server.$channel");
+ my ($lserver, $lchannel) = (lc $server, lc $channel);
+
+ return $message unless mynick($buffer, $nick);
+ return $message unless exists $channels{$lserver}{$lchannel};
+ return $message if ignored($lserver);
+
+ weechat::print($buffer, weechat::prefix('quit').
+ weechat::color('irc.color.message_quit').
+ 'You were forced to part '.weechat::color('chat_channel').$channel.
+ weechat::color('chat_delimiters').' ('.weechat::color('reset').
+ $reason.weechat::color('chat_delimiters').')'.
+ weechat::color('irc.color.message_quit').', rejoining');
+ my $delay = (
+ weechat::config_option_is_null($arj_delay) ?
+ weechat::config_integer($arjd_delay) :
+ weechat::config_integer($arj_delay)
+ );
+ weechat::command($buffer, ($delay ? "/wait $delay " : "").
+ "/join $channel");
+
+ return '';
+}
diff --git a/irc/weechat/banner.pl b/irc/weechat/banner.pl
@@ -0,0 +1,332 @@
+use strict;
+use warnings;
+no strict 'subs';
+
+my $SCRIPT_NAME = 'banner';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.0';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Banner text';
+our (%queue, %timer);
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ weechat::hook_command('banner', 'Banner text',
+ "[-nick|-key|-limit] text",
+ "-nick: send to /nick command\n".
+ "-key: send as /mode +k (doesn't work on all ircds)\n".
+ "-limit: send as /mode +l\n",
+ '', 'cmd_banner', '');
+}
+
+sub cmd_banner
+{
+ my ($buffer, $cmd) = ($_[1], $_[2]);
+ my ($flag, $text) = $cmd =~ /^(-nick|-key|-limit|) *(.*)$/;
+ my @output;
+ my $prefix = '/msg *';
+ my $nick = weechat::info_get('irc_nick',
+ weechat::buffer_get_string($buffer, 'localvar_server'));
+
+my @chars = ('````````^',
+'XX``XXXXX',
+'``````XXX
+`````````
+``````XXX',
+'``X```X``
+XXXXXXXXX
+``X```X``
+XXXXXXXXX
+``X```X``',
+'`````XX``
+`X``X``X`
+XX``X``XX
+`X``X``X`
+``XX`````',
+'```X```XX
+XX``X``XX
+XX```X```',
+'```X`X```
+X`X`X`X`X
+``X```X``',
+'``````XXX',
+'`XXXXXXX`
+X```````X',
+'X```````X
+`XXXXXXX`',
+'``````X`X
+```````X`
+``````X`X',
+'````X````
+```XXX```
+````X````',
+'X````````
+`XX``````',
+'````X```^
+````X````',
+'X````````',
+'XXX``````
+```XXX```
+``````XXX',
+'`XXXXXXX`
+X```````X
+`XXXXXXX`',
+'X``````X`
+XXXXXXXXX
+X````````',
+'XXX````X`
+X``XX```X
+X````XXX`',
+'`X`````X`
+X```X```X
+`XXX`XXX`',
+'````XXX``
+````X``X`
+XXXXXXXXX',
+'X```XXXXX
+X```X```X
+`XXX````X',
+'`XXXXXXX`
+X```X```X
+`XXX`````',
+'XXX`````X
+```XXX``X
+``````XXX',
+'`XXX`XXX`
+X```X```X
+`XXX`XXX`',
+'`````XXX`
+X```X```X
+`XXXXXXX`',
+'``XX`XX``',
+'`X```````
+``XX`XX``',
+'````X````
+```X`X```
+``X```X``',
+'```X`X```
+```X`X``^
+```X`X```',
+'``X```X``
+```X`X```
+````X````',
+'```````X`
+XX``X```X
+`````XXX`',
+'`XXXXXXX`
+X``XXX``X
+X`X```X`X
+X`XXXXXXX',
+'XXXXXXXX`
+````X```X
+XXXXXXXX`',
+'XXXXXXXXX
+X```X```X
+`XXX`XXX`',
+'`XXXXXXX`
+X```````X
+`X`````X`',
+'XXXXXXXXX
+X```````X
+`XXXXXXX`',
+'XXXXXXXXX
+X```X```X
+X```````X',
+'XXXXXXXXX
+````X```X
+````````X',
+'`XXXXXXX`
+X```````X
+`XXX```X`',
+'XXXXXXXXX
+````X````
+XXXXXXXXX',
+'X```````X
+XXXXXXXXX
+X```````X',
+'`X``````X
+X```````X
+`XXXXXXXX',
+'XXXXXXXXX
+````X````
+```X`X```
+XXX```XXX',
+'XXXXXXXXX
+X````````',
+'XXXXXXXXX
+``````XX`
+``XXXX```
+``````XX`
+XXXXXXXXX',
+'XXXXXXXXX
+``````XX`
+```XXX```
+`XX``````
+XXXXXXXXX',
+'XXXXXXXXX
+X```````X
+XXXXXXXXX',
+'XXXXXXXXX
+````X```X
+`````XXX`',
+'`XXXXXXXX
+XX``````X
+XXXXXXXXX
+X````````',
+'XXXXXXXXX
+````X```X
+XXXX`XXX`',
+'`X```XXX`
+X```X```X
+`XXX```X`',
+'````````X
+XXXXXXXXX
+````````X',
+'XXXXXXXXX
+X````````
+XXXXXXXXX',
+'```XXXXXX
+XXX``````
+```XXXXXX',
+'`XXXXXXXX
+X````````
+`XXXX````
+X````````
+`XXXXXXXX',
+'XXX```XXX
+```XXX```
+XXX```XXX',
+'`````XXXX
+XXXXX````
+`````XXXX',
+'XXX`````X
+X``XXX``X
+X`````XXX',
+'XXXXXXXXX
+X```````X',
+'``````XXX
+```XXX```
+XXX``````',
+'X```````X
+XXXXXXXXX',
+'```````X`
+````````X
+```````X`',
+'X````````
+X```````^
+X````````',
+'````````X
+```````X`',
+'`X``X````
+X`X`X````
+XXXX`````',
+'XXXXXXXXX
+X```X````
+`XXX`````',
+'`XXX`````
+X```X````
+X```X````',
+'`XXX`````
+X```X````
+XXXXXXXXX',
+'`XXX`````
+X`X`X````
+X`XX`````',
+'XXXXXXXX`
+````X```X',
+'X``X`````
+X`X`X````
+`XXXX````',
+'XXXXXXXXX
+````X````
+XXXX`````',
+'XXXXX``X`',
+'X````````
+`XXXX``X`',
+'XXXXXXXXX
+````X````
+XXXX`X```',
+'X```````X
+XXXXXXXXX
+X````````',
+'XXXXX````
+````X````
+XXXX`````
+````X````
+XXXX`````',
+'XXXXX````
+````X````
+XXXX`````',
+'XXXXX````
+X```X````
+XXXXX````',
+'XXXXX````
+`X``X````
+``XX`````',
+'``XX`````
+`X``X````
+XXXXX````',
+'XXXXX````
+````X````',
+'X``X`````
+X`X`X````
+`X``X````',
+'`XXXXXXX`
+X```X````',
+'`XXXX````
+X````````
+XXXXX````',
+'``XXX````
+XX```````
+``XXX````',
+'`XXXX````
+X````````
+`XXX`````
+X````````
+`XXXX````',
+'XX`XX````
+``X``````
+XX`XX````',
+'X``XX````
+X`X``````
+`XXXX````',
+'XX``X````
+X`X`X````
+X``XX````',
+'````X````
+XXXX`XXXX
+X```````X',
+'XXXXXXXXX',
+'X```````X
+XXXX`XXXX
+````X````',
+' ```````X`
+````````X
+```````X`
+````````X');
+
+ for ($flag) {
+ /-nick/ and $prefix = '/nick', last;
+ /-key/ and $prefix = '/mode +k', last;
+ /-limit/ and $prefix = '/mode +l', last;
+ }
+
+ if ($flag eq '-limit') { $chars[$_] =~ y/`X/18/ for (0 .. (@chars - 1)) }
+
+ for my $char (split //, $text) {
+ push @output, $flag eq '-limit' ? '111111111' : '`````````';
+ push @output, split /\n/, $chars[ord($char) - 0x20];
+ }
+
+ weechat::command($buffer, "$prefix $_") for @output;
+
+ for ($flag) {
+ /-nick/ and weechat::command($buffer, "/nick $nick"), last;
+ /-key/ and weechat::command($buffer, "/mode +k `````````"),
+ weechat::command($buffer, "/mode -k `````````"),
+ last;
+ /-limit/ and weechat::command($buffer, "/mode -l"), last;
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
diff --git a/irc/weechat/colo.py b/irc/weechat/colo.py
@@ -0,0 +1,170 @@
+# -*- coding: utf-8 -*-
+#
+# Released into the Public Domain
+
+"""colo: make your chats noticable"""
+
+import random
+import re
+import weechat
+
+SCRIPT_NAME = "colo"
+SCRIPT_AUTHOR = "The Krusty Krab <wowaname@volatile.ch>"
+SCRIPT_VERSION = "2.2"
+SCRIPT_LICENSE = "Public domain"
+SCRIPT_DESC = "Makes your chats noticable"
+
+# script options
+settings = {
+ "fmt": (
+ "%c13♥ %0%s%o %c13♥",
+ "Format string for text. %0 - %9 are different colours, %s is text, "
+ "%c %b %u %r %o are ^C ^B ^U ^R ^O respectively, and %% is a literal "
+ "percent sign. %0 is the primary colour that should be used with %s.",
+ ),
+ "fgs": (
+ "04,05,06,13",
+ "Colour codes to cycle for the foreground. "
+ "Leave blank for no foreground colours.",
+ ),
+ "bgs": (
+ "",
+ "Colour codes to cycle for the background. "
+ "Leave blank for no background colours.",
+ ),
+ "ignore_buffers": (
+ "bitlbee.*,scripts",
+ "List of buffers to ignore. Glob matches unless "
+ "you prefix the name with 're:'.",
+ ),
+ "whitelist_buffers": (
+ "",
+ "List of buffers to whitelist. Glob match unless "
+ "you prefix the name with 're:'. Useful with "
+ "ignore_buffers = \"*\"",
+ ),
+ "whitelist_cmds": (
+ "me,amsg,say",
+ "Commands to colour.",
+ ),
+ "profiles": (
+ "> greentext,! alert",
+ "List of prefix/profile pairs. If you type one of "
+ "these prefixes at the beginning of your message, "
+ "the options will switch to (profile)_pre, "
+ "(profile)_suf, (profile)_fgs, and (profile)_bgs. ",
+ ),
+ "greentext_fmt": "%c3> %s",
+ "alert_fmt": "%c1,8/!\\%c8,1 %s %o%c1,8/!\\"
+}
+
+
+if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
+ SCRIPT_DESC, "", ""):
+ for opt, val in settings.iteritems():
+ setting, desc = val if type(val) == tuple else (val, "")
+ if desc: weechat.config_set_desc_plugin(opt, desc)
+ if weechat.config_is_set_plugin(opt): continue
+ weechat.config_set_plugin(opt, setting)
+
+ weechat.hook_modifier("input_text_for_buffer", "cb_colo", "")
+
+# prevent looping
+nest = False
+
+def glob_match (haystack, needle):
+ return re.search("^%s$" %
+ re.escape(haystack).replace(r"\?", ".").replace(r"\*", ".*?"),
+ needle)
+
+def is_command (string):
+ return (string.startswith("/") and not string.startswith("/ ") and
+ string != "/" and string.split(" ", 1)[0].split("\n", 1)[0].find("/", 1)
+ < 0)
+
+def cb_colo (data, mod, buf, input):
+ global nest
+ if nest:
+ nest = False
+ # return input
+ buffer_name = weechat.buffer_get_string(buf, "name").lower()
+ output = ""
+ profile = ""
+
+ for pattern in weechat.config_get_plugin("whitelist_buffers").lower().split(","):
+ if (pattern.startswith("re:") and
+ re.search(pattern[3:], buffer_name)) or glob_match(pattern, buffer_name):
+ break
+ else:
+ for pattern in weechat.config_get_plugin("ignore_buffers").lower().split(","):
+ if (pattern.startswith("re:") and
+ re.search(pattern[3:], buffer_name)) or glob_match(pattern, buffer_name):
+ return input
+
+ if not input:
+ return input
+
+ if is_command(input):
+ for cmd in weechat.config_get_plugin("whitelist_cmds").lower().split(","):
+ if not input.startswith("/%s " % cmd): continue
+ output = "/%s " % cmd
+ input = input.split(" ", 1)[1] if " " in input else ""
+ break
+ else:
+ # XXX
+ return input.replace('\r','')
+
+ if input.startswith("//"): input = input[1:]
+
+ for profile_pairs in weechat.config_get_plugin("profiles").split(","):
+ prefix, name = profile_pairs.split()
+ if not input.startswith("%s " % prefix): continue
+ profile = "%s_" % name
+ input = input.split(" ",1)[1] if " " in input else ""
+ for opt in ("fmt", "fgs", "bgs"):
+ if weechat.config_is_set_plugin(profile + opt): continue
+ weechat.config_set_plugin(profile + opt, "")
+ break
+
+ fgs = weechat.config_get_plugin("%sfgs" % profile).split(",")
+ bgs = weechat.config_get_plugin("%sbgs" % profile).split(",")
+ fmt = weechat.config_get_plugin("%sfmt" % profile).split("%%")
+
+ for i in xrange(len(fmt)):
+ fmt[i] = fmt[i].replace("%c", "\x03").replace("%b",
+ "\x02").replace("%u", "\x1f").replace("%r",
+ "\x16").replace("%o", "\x0f")
+ if fgs == [""] and bgs == [""]: continue
+ for j in xrange(10):
+ base = "\x03%s%s%s" % (
+ random.choice(fgs),
+ "," if bgs != [""] else "",
+ random.choice(bgs),
+ )
+ fmt[i] = fmt[i].replace("%%%d" % j, base)
+ if j: continue
+ input = re.sub(
+ "\x03([^0-9])",
+ "\x03%s\\1" % base,
+ input.replace("\x0f","\x0f%s" % base))
+
+ fmt = "%".join(fmt)
+ nest = is_command(fmt)
+ servername = weechat.buffer_get_string(buf, "localvar_server")
+ iptr = weechat.infolist_get("irc_server", "", servername)
+ weechat.infolist_next(iptr)
+ long_lines = weechat.infolist_integer(iptr, "cap_long_lines")
+ weechat.infolist_free(iptr)
+
+ nicklen = weechat.info_get("irc_server_isupport_value", "%s,NICKLEN" %
+ servername)
+ if not nicklen: nicklen = 9
+
+ l = ((512 if long_lines else 0) + 409 - len(fmt) - int(nicklen))
+ o = []
+ for line in input.replace("\r", "\n").split("\n"):
+ if not line: continue
+ for i in xrange(0, len(line), l):
+ o.append(fmt.replace("%s", line[i:i+l].rstrip()))
+
+ return output + "\n".join(o)
diff --git a/irc/weechat/coloconv.pl b/irc/weechat/coloconv.pl
@@ -0,0 +1,45 @@
+#!/usr/bin/perl
+
+=pod
+
+Reads plugins.conf from stdin, writes new plugins.conf to stdout, and
+writes commands to restore the rest of the config options to stderr
+
+Suggested operation:
+cd .weechat
+./coloconv.pl < plugins.conf > plugins.conf.new 2> commands
+diff plugins.conf plugins.conf.new # to make sure nothing got clobbered
+
+Then in WeeChat:
+/exec -o .weechat/commands
+
+=cut
+
+my %profs;
+my $desc = 0;
+
+while (<>) {
+ $desc and print, next;
+ $_ !~ /^python\.embellish\./ and print, next;
+ s/^python\.embellish/python.colo/;
+ $_ !~ /^python\.colo\..*(?:pre|suf)/ and print, next;
+ $_ eq '[desc]' and ($desc = 1), print, next;
+
+ my ($prof, $k, $v) = /^python\.colo\.(.*)(pre|suf) = "(.*)"$/;
+ $v =~ s/\x02/%b/g;
+ $v =~ s/\x03/%c/g;
+ $v =~ s/\x0f/%o/g;
+ $v =~ s/\x16/%r/g;
+ $v =~ s/\x1f/%u/g;
+
+ if ($k eq 'pre') {
+ $profs{$prof} = "%0$v%o%0 %s%o%0 ";
+ } elsif ($k eq 'suf') {
+ $profs{$prof} .= $v;
+ }
+}
+
+for my $prof (keys %profs) {
+ print STDERR "/reload\n";
+ print STDERR "/set plugins.var.python.colo.${prof}fmt $profs{$prof}\n";
+}
diff --git a/irc/weechat/hueg.pl b/irc/weechat/hueg.pl
@@ -0,0 +1,1255 @@
+#!/usr/bin/perl
+
+
+######
+# hueg.pl PRO MODE
+# modded by ma0 and others
+# respekts 2 jakk and others
+######
+
+$maxchars = 10; #num of chars b4 split
+my $reverse = 0;
+my $flip = 0;
+my $mirror = 0;
+my $scale = 1;
+
+my $SCRIPT_NAME = 'hueg';
+my $SCRIPT_AUTHOR = 'LIFELIKE <i@wnt2die.com>';
+my $SCRIPT_VERSION = '1.1';
+my $SCRIPT_LICENCE = 'GPL3';
+my $SCRIPT_DESC = 'make text hueg LOL';
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ weechat::hook_command('hueg', '', '<string> [options]',
+ " -rep <num> num of times to scroll msg\n".
+ " -re reverses text\n".
+ " -flip flips text\n".
+ " -mir mirrors your text [NOT WORKIN LOL]\n".
+ " -scale <num> scales shit\n".
+ " num,num,num fg, shadow, bg colors (bg optional)",
+ '-rep|-re|-flip|-mir|-scale|%*', 'hueg', '');
+}
+
+sub hueg {
+ (undef, $buffer, $data) = @_;
+ $in = $data;
+
+ if ($in =~ /-rep (\d+)/i) {
+ $rep = $1;
+ $in =~ s/-rep \d+//i;
+ } else {
+ $rep = 1;
+ }
+
+ if($in =~ /-scale (\d+)/i) {
+ $scale = $1;
+ $in =~ s/-scale \d+//i;
+ } else {
+ $scale = 1;
+ }
+
+ if($in =~ /-re/i) {
+ $reverse = 1;
+ $in =~ s/-re//i;
+ } else {
+ $reverse = 0;
+ }
+
+ if($in =~ /-flip/i){
+ $flip = 1;
+ $in =~ s/-flip//i;
+ } else {
+ $flip = 0;
+ }
+
+ if($in =~ /-mir/i) {
+ $mirror = 1;
+ $in =~ s/-mir//i;
+ } else {
+ $mirror = 0;
+ }
+
+ $in =~ s/\s+$//;
+
+ if ($in eq '') {
+ weechat::print($buffer, weechat::prefix('error').
+ "Invalid syntax; see /help hueg");
+ return weechat::WEECHAT_RC_ERROR;
+ } else {
+ until ($rep == 0) {
+ colors();
+ parse();
+ process();
+ select(undef,undef,undef,.1);
+ $rep--;
+ }
+ return weechat::WEECHAT_RC_OK;
+ }
+}
+
+sub colors {
+ if ($data =~ /(\d+),(\d+),(\d+)/) {
+ $c2 = "\cC$1,$1"; #fg
+ $c1 = "\cC$2,$2"; #sh
+ $c3 = "\cC$3,$3"; #bg
+ $in =~ s/\d+,\d+,\d+//;
+ } elsif ($data =~ /(\d+),(\d+)/) {
+ $c2 = "\cC$1,$1"; #fg
+ $c1 = "\cC$2,$2"; #sh
+ $c3 = "\cO"; #bg (trans)
+ $in =~ s/\d+,\d+//;
+ } else {
+ $r1 = $r2 = 0;
+ until ($r1 > 1) { $r1 = int rand(15); }
+ until ($r2 > 1 && $r2 != $r1) { $r2 = int rand(15); }
+ $c2 = "\cC$r1,$r1"; #fg (rand)
+ $c1 = "\cC$r2,$r2"; #sh (rand)
+ $c3 = "\cO"; #bg (trans)
+ }
+ db1();
+}
+
+sub parse {
+ $in =~ s/(\S{$maxchars})/$1 /g;
+ undef @s0;
+ @s0 = split(' ',$in);
+ undef @s1;
+ $s1n = 0;
+ for $n (@s0) {
+ $nlen = length($n);
+ $slen = length($s1[$s1n] // '') + $nlen;
+ if ($slen <= $maxchars) {
+ $s1[$s1n] .= "$n ";
+ } else {
+ $s1n++;
+ $s1[$s1n] .= "$n ";
+ }
+ }
+}
+
+sub process {
+ for $n (@s1) { #each line
+ if ($reverse) {
+ $n = reverse $n;
+ }
+
+ $n =~ s/\s$//;
+ $n =~ s/^\s//;
+ undef @s2;
+ @s2 = split('',$n);
+ my $cur; # current string
+ my $tmp;
+
+ for $f (0..8*$scale) {
+ for $l (@s2) { #each letter
+ $all .= "$c3 \cO";
+
+ if($flip) { $cur = $db{$l}[(9-$f)/$scale] // $db{'?'}[(9-$f)/$scale]; } #line of letter
+ else { $cur = $db{$l}[$f/$scale] // $db{'?'}[$f/$scale]; }
+
+ $whitespace = " " x $scale;
+ $cur =~ s/ /$whitespace/g;
+ $whitespace = "#" x $scale;
+ $cur =~ s/#/$whitespace/g;
+ $whitespace = "." x $scale;
+ $cur =~ s/\./$whitespace/g;
+ $all .= $cur;
+ }
+
+ $all .= "$c3 ";
+ if($mirror) { $all = reverse $all; }
+ weechat::command($buffer, "/msg * $all");
+ $all = '';
+ }
+
+ }
+}
+
+#------------------#
+# character db #
+# lol #
+#------------------#
+
+sub db1 {
+%db = (
+" " => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+"\cC" => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2#######$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2############$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+"\cB" => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2#######$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2############$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+"\cO" => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2#######$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2############$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+"0" => [
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+"1" => [
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2###$c3 ",
+"$c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2######$c3",
+"$c3 ",
+],
+"2" => [
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2#######$c3",
+"$c3 ",
+],
+"3" => [
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 ",
+],
+"4" => [
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2###$c3 ",
+"$c3 $c1.$c2#$c1.$c2##$c3 ",
+"$c3 $c1.$c2#$c3 $c1.$c2##$c3 ",
+"$c1.$c2#######$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+"5" => [
+"$c3 ",
+"$c1.$c2######$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2######$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 ",
+],
+"6" => [
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 ",
+],
+"7" => [
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+"8" => [
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+"9" => [
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+A => [
+"$c3 ",
+"$c3 $c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+a => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2#######$c3",
+"$c3 ",
+],
+B => [
+"$c3 ",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 ",
+"$c3 ",
+],
+b => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2######$c3 ",
+"$c3 ",
+],
+C => [
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+c => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2#####$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2#####$c3",
+"$c3 ",
+],
+D => [
+"$c3 ",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2#######$c3 ",
+"$c3 ",
+],
+d => [
+"$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3",
+"$c3 ",
+],
+E => [
+"$c3 ",
+"$c1.$c2#######$c3",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2######$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2#######$c3",
+"$c3 ",
+],
+e => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+F => [
+"$c3 ",
+"$c1.$c2#######",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2######$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+],
+f => [
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2###",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2#####",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+G => [
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2####$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+g => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#######$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+],
+H => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2########$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+h => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+I => [
+"$c3 ",
+"$c1.$c2######$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2######$c3",
+"$c3 ",
+],
+i => [
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2####",
+"$c3 ",
+],
+J => [
+"$c3 ",
+"$c3 $c1.$c2######",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 ",
+],
+j => [
+"$c3 ",
+"$c3 $c1.$c2##",
+"$c3 ",
+"$c3 $c1.$c2###",
+"$c3 $c1.$c2##",
+"$c3 $c1.$c2##",
+"$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 $c1.$c2####$c3 ",
+],
+K => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c1.$c2##$c3 ",
+"$c1.$c2####$c3 ",
+"$c1.$c2##$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+k => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2#####$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 ",
+],
+L => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2#######$c3",
+"$c3 ",
+],
+l => [
+"$c3 ",
+"$c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2####",
+"$c3 ",
+],
+M => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2###$c3 $c1.$c2###$c3",
+"$c1.$c2####$c3 $c1.$c2####$c3",
+"$c1.$c2##$c1.$c2##$c1.$c2##$c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2###$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2#$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+m => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2####$c1.$c2####$c3",
+"$c1.$c2##$c1.$c2###$c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2#$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+N => [
+"$c3 ",
+"$c1.$c2###$c3 $c1.$c2##",
+"$c1.$c2####$c3 $c1.$c2##",
+"$c1.$c2##$c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##$c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2####",
+"$c1.$c2##$c3 $c1.$c2###",
+"$c3 ",
+],
+n => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+O => [
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+o => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+P => [
+"$c3 ",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+],
+p => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+],
+Q => [
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2###$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 $c1.$c2##$c3 ",
+],
+q => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#######$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+],
+R => [
+"$c3 ",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 ",
+],
+r => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+],
+S => [
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 ",
+],
+s => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2#####$c3",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c1.$c2#####$c3 ",
+"$c3 ",
+],
+T => [
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+t => [
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2#####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c1.$c2##",
+"$c3 $c1.$c2###$c3 ",
+"$c3 ",
+],
+U => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+u => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2######$c3 ",
+"$c3 ",
+],
+V => [
+"$c3 ",
+"$c1.$c2#$c3 $c1.$c2#",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+v => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c3 $c1.$c2###$c3 ",
+"$c3 ",
+],
+W => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c3 $c1.$c2##$c3 $c1.$c2##",
+"$c1.$c2##$c1.$c2####$c1.$c2##",
+"$c1.$c2####$c3 $c1.$c2####",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+w => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2#$c3 $c1.$c2##$c3",
+"$c1.$c2##$c1.$c2###$c1.$c2##$c3",
+"$c1.$c2####$c1.$c2####$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+X => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c3 $c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+x => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c3 $c2###$c3 ",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+Y => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+y => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+],
+Z => [
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2########$c3",
+"$c3 ",
+],
+z => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2########$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2########$c3 ",
+"$c3 ",
+],
+'~' => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2####$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2####$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'`' => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'!' => [
+"$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+],
+'@' => [
+"$c3 ",
+"$c3 $c1.$c2#######$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2#####$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2#######$c3 ",
+"$c3 ",
+],
+'#' => [
+"$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##########",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##########",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+'$' => [
+"$c3 $c1.$c2#$c3 ",
+"$c3 $c1.$c2#######$c3 ",
+"$c1.$c2##$c3 $c1.$c2#$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2#$c3 ",
+"$c3 $c1.$c2#######$c3 ",
+"$c3 $c1.$c2#$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2#$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2#######$c3 ",
+"$c3 $c1.$c2#$c3 ",
+],
+'%' => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##",
+"$c3 ",
+],
+'^' => [
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'&' => [
+"$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2####$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2######$c1.$c2##$c3",
+"$c3 ",
+],
+'*' => [
+"$c3 ",
+"$c3 ",
+"$c1.$c2#$c3 $c1.$c2#",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2#$c3 $c1.$c2#",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'(' => [
+"$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+')' => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+],
+'_' => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 ",
+],
+'-' => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'+' => [
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2########$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'=' => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 ",
+"$c1.$c2########$c3",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'|' => [
+"$c3 ",
+"$c1.$c2##$c3",
+"$c1.$c2##$c3",
+"$c1.$c2##$c3",
+"$c1.$c2##$c3",
+"$c1.$c2##$c3",
+"$c1.$c2##$c3",
+"$c1.$c2##$c3",
+"$c3 ",
+],
+'\\' => [
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 ",
+],
+'[' => [
+"$c3 ",
+"$c1.$c2####$c3",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c1.$c2####$c3",
+"$c3 ",
+],
+']' => [
+"$c3 ",
+"$c1.$c2####$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3",
+"$c1.$c2####$c3",
+"$c3 ",
+],
+'{' => [
+"$c3 ",
+"$c3 $c1.$c2###$c3",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2###$c3",
+"$c3 ",
+],
+'}' => [
+"$c3 ",
+"$c1.$c2###$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c1.$c2###$c3 ",
+"$c3 ",
+],
+':' => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c3 ",
+],
+';' => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2#$c3 ",
+"$c3 ",
+],
+'\'' => [
+"$c3 ",
+"$c3 $c1.$c2##",
+"$c1.$c2##$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'"' => [
+"$c3 ",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c1.$c2##$c3 $c1.$c2##$c3",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'<' => [
+"$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 ",
+"$c3 ",
+],
+'>' => [
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+"$c3 ",
+],
+'?' => [
+"$c3 ",
+"$c3 $c1.$c2#####$c3 ",
+"$c3 $c1.$c2##$c3 $c1.$c2##",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 ",
+],
+"\," => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##$c3",
+"$c3 $c1.$c2#$c3",
+],
+"\." => [
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c3 ",
+"$c1.$c2##",
+"$c3 ",
+],
+"\/" => [
+"$c3 ",
+"$c3 $c1.$c2##$c3",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c3 $c1.$c2##$c3 ",
+"$c1.$c2##$c3 ",
+"$c3 ",
+],
+);
+}
diff --git a/irc/weechat/masshl.py b/irc/weechat/masshl.py
@@ -0,0 +1,106 @@
+# Released into the Public Domain
+
+import random
+#from threading import Thread
+#from time import sleep
+import weechat
+
+SCRIPT_NAME = "masshl"
+SCRIPT_AUTHOR = "The Krusty Krab <wowaname@volatile.ch>"
+SCRIPT_VERSION = "1.0"
+SCRIPT_LICENSE = "Public domain"
+SCRIPT_DESC = "Provides nicklist hooks."
+
+if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION,
+ SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
+ weechat.hook_command("masshl",
+ SCRIPT_DESC,
+ "[-do <delay>] text (broken, currently no-op)",
+ "-d Specify a delay at the beginning (e.g. -d 1 for\n"
+ " one second) to insert a delay between messages.\n"
+ " %n - replace with next nick\n"
+ " %N - replace with as many nicks as possible per line\n"
+ " %r - replace with random hex value to thwart antispam\n"
+ "-o Include your own nick in output",
+ "-od", "masshl_cmd_cb", "")
+
+class Loop():
+ def __init__(self, buffer, nicks, input, input_method, N_param, delay, opts):
+ self.buffer = buffer
+ self.nicks = nicks
+ self.input = input
+ self.input_method = input_method
+ self.N_param = N_param
+ self.delay = delay
+ self.opts = opts
+
+ def run(self):
+ i = -('o' not in self.opts)
+ if i == -1: self.nicks.pop(0)
+ N_nicks = ""
+ output = self.input
+ for nick in self.nicks:
+ i += 1
+ if self.N_param:
+ N_nicks += " %s" % nick
+ if (nick != self.nicks[-1] and
+ len(output) + len(N_nicks) + len(self.nicks[i]) < 300):
+ continue
+ else: output = self.input.replace("%n",nick)
+ N_nicks = N_nicks.lstrip()
+ output = output.replace("%N",N_nicks)
+ output = output.replace("%r","%08x" % random.randint(0,0xffffffff))
+ if self.input_method == "keybinding":
+ weechat.buffer_set(self.buffer, "input", output)
+ else:
+ weechat.command(self.buffer, output)
+# sleep(self.delay)
+ output = self.input
+ N_nicks = ""
+
+def masshl_cmd_cb(data, buffer, args):
+ input = args
+
+ input_method = "command"
+ server = weechat.buffer_get_string(buffer, 'localvar_server')
+ channel = weechat.buffer_get_string(buffer, 'localvar_channel')
+
+ if not input or (input[0] == '-' and input.find(' ') == -1):
+ input = (input + ' ' if input else '') + weechat.buffer_get_string(buffer, "input")
+ input_method = "keybinding"
+
+ N_param = "%N" in input
+ if not N_param and "%n" not in input and "%r" not in input:
+ # if we bind this to Enter key, we don't want useless flooding on
+ # normal messages
+ return weechat.WEECHAT_RC_OK
+
+ optstop = input and input[0] == '-' and input.find(' ')
+ opts = input[1:optstop] if optstop else ''
+ cmdstop = 'd' in opts and input.find(' ', optstop+1)
+ delay = 0
+ if 'd' in opts:
+ find = input[optstop+1:cmdstop]
+ where = input.find(find, cmdstop+1)
+ try: delay = float(find)
+ except ValueError:
+ weechat.prnt(buffer, "delay must be a float value!")
+ return weechat.WEECHAT_RC_ERROR
+ input = input[where+len(find):]
+ else: input = input[optstop+bool(optstop):]
+
+ nicklist = weechat.infolist_get("irc_nick", "", "%s,%s" % (server,channel))
+
+ # dealing with the cursor can get a little tricky. let's use a dict
+ # instead, that way we can manipulate just what we need and we can
+ # do that with builtins
+ nicks = []
+ while weechat.infolist_next(nicklist):
+ nicks.append(weechat.infolist_string(nicklist, "name"))
+
+ weechat.infolist_free(nicklist)
+
+ workhorse = Loop(buffer, nicks, input, input_method, N_param, delay, opts)
+ workhorse.run()
+
+ return weechat.WEECHAT_RC_OK
diff --git a/irc/weechat/parrot.pl b/irc/weechat/parrot.pl
@@ -0,0 +1,380 @@
+use strict;
+use warnings;
+
+no strict 'subs';
+
+my $SCRIPT_NAME = 'parrot';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.0';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Relay channel messages and modes';
+
+# %cbs{server}{hook_name} = $hook_ptr:
+# stores hook pointers to unhook() on exit
+# %chans{server}{channel} = @groups:
+# stores groups associated with a channel
+# %groups{groupname}{server}{channel} = $flags:
+# stores channels associated with a group, as well as the channel's flags
+# $READ, $STAT, $MODE:
+# flags for -read, -stat, -mode switches
+our (%cbs, %chans, %groups);
+our ($READ, $STAT, $MODE) = (0x1, 0x2, 0x4);
+our $confpath;
+
+sub servchan
+{
+ my $buffer = shift;
+ return (lc weechat::buffer_get_string($buffer, 'localvar_server'),
+ lc weechat::buffer_get_string($buffer, 'localvar_channel'));
+}
+
+sub ircbuf { weechat::buffer_search('irc', "(?i)".(join '.', @_)) }
+
+sub getgroup
+{
+ my ($server, $channel) = @_;
+ my @ret;
+
+ for my $group (@{ $chans{$server}{$channel} }) {
+ for my $to_serv (keys %{ $groups{$group} }) {
+ for my $to_chan (keys %{ $groups{$group}{$to_serv} }) {
+ # don't send to myself
+ next if $to_serv eq $server and $to_chan eq $channel;
+ push @ret, [$to_serv, $to_chan, $groups{$group}{$to_serv}{$to_chan}, $group]
+ } } }
+
+ return @ret;
+}
+
+sub sendto
+{
+ my ($server, $command) = @_;
+ weechat::hook_signal_send('irc_input_send',
+ weechat::WEECHAT_HOOK_SIGNAL_STRING,
+ "$server;;1;;$command");
+}
+
+sub add_relay
+{
+ my ($groupname, $server, $channel, $flags) = @_;
+ return if exists $cbs{$server};
+ push @{ $chans{$server}{$channel} }, $groupname;
+ $groups{$groupname}{$server}{$channel} = $flags;
+ $cbs{$server}{PRIVMSG} =
+ weechat::hook_signal("$server,irc_raw_in_privmsg", 'irc_privmsg_notice', '');
+ $cbs{$server}{NOTICE} =
+ weechat::hook_signal("$server,irc_raw_in_notice", 'irc_privmsg_notice', '');
+ $cbs{$server}{OUT_PRIVMSG} =
+ weechat::hook_signal("$server,irc_out1_privmsg", 'ircout_privmsg_notice', '');
+ $cbs{$server}{OUT_NOTICE} =
+ weechat::hook_signal("$server,irc_out1_notice", 'ircout_privmsg_notice', '');
+ if ($flags & $STAT) {
+ $cbs{$server}{JOIN} =
+ weechat::hook_signal("$server,irc_raw_in_join", 'irc_join', '');
+ $cbs{$server}{PART} =
+ weechat::hook_signal("$server,irc_raw_in_part", 'irc_part', '');
+ $cbs{$server}{KICK} =
+ weechat::hook_signal("$server,irc_raw_in_kick", 'irc_kick', '');
+ $cbs{$server}{NICK} =
+ weechat::hook_signal("$server,irc_raw_in_nick", 'irc_nick', '');
+ $cbs{$server}{QUIT} =
+ weechat::hook_signal("$server,irc_raw_in_quit", 'irc_quit', '');
+ }
+ if ($flags & $MODE) {
+# $cbs{$server}{MODE} =
+# weechat::hook_signal("$server,irc_raw_in_mode", 'irc_mode', '');
+ $cbs{$server}{TOPIC} =
+ weechat::hook_signal("$server,irc_raw_in_topic", 'irc_topic', '');
+ }
+}
+
+sub read_conf
+{
+ open FH, '<', $confpath or weechat::print('', weechat::prefix('error').
+ "Error opening $confpath for reading: $!"), return;
+ while (<FH>) {
+ chomp;
+ add_relay(split ' ');
+ }
+ close FH;
+}
+
+sub write_conf
+{
+ open FH, '>', $confpath or weechat::print('', weechat::prefix('error').
+ "Error opening $confpath for writing: $!"), return;
+ for my $server (keys %chans) {
+ for my $channel (keys %{ $chans{$server} }) {
+ for my $group (@{ $chans{$server}{$channel} }) {
+ my $flags = $groups{$group}{$server}{$channel};
+ print FH "$group $server $channel $flags\n";
+ } } }
+ close FH;
+}
+
+sub irc_privmsg_notice
+{
+ my (undef, $server, $cmd, $nick, $channel, $message) = (shift,
+ shift =~ /(.+),irc_raw_in_(privmsg|notice)/i,
+ shift =~ /:([^! ]*)[^ ]* [^ ]+ ([^ ]+) :?(.*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ if ($message =~ /^\x01ACTION /i) {
+ $message =~ s/^\x01ACTION |\x01$//g;
+ sendto($to_serv, "/msg $to_chan * \x02$nick\x0f $message");
+ next;
+ }
+ my $prefix = lc $cmd eq 'notice' ? "[\x02$nick\x0f]" : "<\x02$nick\x0f>";
+ sendto($to_serv, "/msg $to_chan $prefix $message");
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub ircout_privmsg_notice
+{
+ my (undef, $server, $cmd, $channel, $message) = (shift,
+ shift =~ /(.*),irc_out1_(privmsg|notice)/i,
+ shift =~ /[^ ]+ ([^ ]+) :?(.*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ my $prefix = lc $cmd eq 'notice' ? 'notice' : 'msg';
+ if ($message =~ /^\x01ACTION /i) {
+ $message =~ s/^\x01ACTION |\x01$//g;
+ sendto($to_serv, "/$prefix $to_chan \x01ACTION $message\x01");
+ next;
+ }
+ sendto($to_serv, "/$prefix $to_chan $message");
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_join
+{
+ my (undef, $server, $nick, $host, $channel) = (shift,
+ shift =~ /(.+),irc_raw_in_join/i,
+ shift =~ /:([^! ]*)([^ ]*) join :?([^ ]+)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next unless $flags & $STAT;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ sendto($to_serv, "/notice $to_chan \x02$nick\x0f$host joined $server/$channel\x0f");
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_part
+{
+ my (undef, $server, $nick, $channel, $message) = (shift,
+ shift =~ /(.+),irc_raw_in_part/i,
+ shift =~ /:([^! ]*)[^ ]* part ([^ ]+) ?:?(.*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next unless $flags & $STAT;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ sendto($to_serv, "/notice $to_chan \x02$nick\x0f left $server/$channel\x0f: $message");
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_kick
+{
+ my (undef, $server, $nick, $channel, $target, $message) = (shift,
+ shift =~ /(.+),irc_raw_in_kick/i,
+ shift =~ /:([^! ]*)[^ ]* kick ([^ ]+) ([^ ]+) :?(.*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next unless $flags & $STAT;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ sendto($to_serv, "/notice $to_chan \x02$nick\x0f kicked $target\x0f from $server/$channel\x0f: $message");
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_nick
+{
+ my (undef, $server, $nick, $newnick) = (shift,
+ shift =~ /(.+),irc_raw_in_nick/i,
+ shift =~ /:([^! ]*)[^ ]* nick :?(.*)/i);
+
+ for my $channel (keys %{ $chans{$server} }) {
+ my $iptr = weechat::infolist_get('irc_nick', '', "$server,$channel,$nick");
+ next unless $iptr;
+ weechat::infolist_free($iptr);
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next unless $flags & $STAT;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ sendto($to_serv, "/notice $to_chan \x02$nick\x0f is now \x02$newnick\x0f");
+ } }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_quit
+{
+ my (undef, $server, $nick, $message) = (shift,
+ shift =~ /(.+),irc_raw_in_quit/i,
+ shift =~ /:([^! ]*)[^ ]* quit :?(.*)/i);
+
+ for my $channel (keys %{ $chans{$server} }) {
+ my $iptr = weechat::infolist_get('irc_nick', '', "$server,$channel,$nick");
+ next unless $iptr;
+ weechat::infolist_free($iptr);
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next unless $flags & $STAT;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ sendto($to_serv, "/notice $to_chan \x02$nick\x0f left $server: $message");
+ } }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_mode
+{
+ my (undef, $server, $nick, $channel, $modes) = (shift,
+ shift =~ /(.+),irc_raw_in_mode/i,
+ shift =~ /:([^! ]*)[^ ]* mode ([^ ]+) (.*)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_topic
+{
+ my (undef, $server, $nick, $channel, $message) = (shift,
+ shift =~ /(.+),irc_raw_in_topic/i,
+ shift =~ /:([^! ]*)[^ ]* topic ([^ ]+) :?([^ ]+)/i);
+ ($server, $channel) = (lc $server, lc $channel);
+ weechat::print('',"$server $channel");
+ return weechat::WEECHAT_RC_OK unless exists $chans{$server}{$channel};
+ return weechat::WEECHAT_RC_OK if lc $nick eq lc weechat::info_get('irc_nick', $server);
+
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, undef) = @$_;
+ next unless $flags & $MODE;
+ next if $flags & $READ;
+ next unless ircbuf("$to_serv.$to_chan");
+ sendto($to_serv, "/topic $to_chan $message");
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub cmd_parrot
+{
+ my (undef, $buffer, $command) = @_;
+ my ($server, $channel) = servchan($buffer);
+ my ($flags, $remove, $groupname) =
+ ( 0, 0, '');
+ for (split / +/, $command) {
+ /^-read$/ and ($flags |= $READ), next;
+ /^-stat$/ and ($flags |= $STAT), next;
+ /^-mode$/ and ($flags |= $MODE), next;
+ /^-remove$/ and ($remove = 1), next;
+ $groupname = $_; last;
+ }
+
+ unless ($groupname) {
+ if ($chans{$server}{$channel}) {
+ for (getgroup($server, $channel)) {
+ my ($to_serv, $to_chan, $flags, $group) = @$_;
+ my $flag_str = $flags ? ':' : '';
+ $flag_str .= ' readonly' if $flags & $READ;
+ $flag_str .= ' statusmsg' if $flags & $STAT;
+ $flag_str .= ' sendmodes' if $flags & $MODE;
+ weechat::print($buffer, weechat::prefix('server').
+ "Relaying to $to_serv/$to_chan in group $group$flag_str");
+ }
+ } else {
+ weechat::print($buffer, weechat::prefix('server').
+ "This channel is not being relayed");
+ }
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ # clear hooks first (if they exist)
+ if (exists $cbs{$server}) {
+ weechat::unhook($cbs{$server}{$_}) for (keys %{ $cbs{$server} });
+ delete $cbs{$server};
+ }
+ @{ $chans{$server}{$channel} } =
+ grep { $_ ne $groupname } @{ $chans{$server}{$channel} };
+
+ if ($remove) {
+ delete $groups{$groupname}{$server}{$channel};
+ delete $groups{$groupname}{$server} unless $groups{$groupname}{$server};
+ delete $groups{$groupname} unless $groups{$groupname};
+ delete $chans{$server}{$channel} unless $chans{$server}{$channel};
+ delete $chans{$server} unless $chans{$server};
+
+ write_conf();
+ weechat::print($buffer, weechat::prefix('server').
+ "Removed relay from group $groupname");
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ add_relay($groupname, $server, $channel, $flags);
+
+ write_conf();
+ weechat::print($buffer, weechat::prefix('server').
+ "Added relay to group $groupname");
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub completion_groupnames
+{
+ my $completion = pop;
+ weechat::hook_completion_list_add($completion, $_, 0,
+ weechat::WEECHAT_LIST_POS_SORT) for keys %groups;
+}
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ $confpath = weechat::info_get('weechat_dir', '') . '/parrot.db';
+ weechat::hook_completion('perl_parrot_groupname', 'parrot.pl group names',
+ 'completion_groupnames', '');
+ weechat::hook_command('parrot', $SCRIPT_DESC,
+ "[-read] [-stat] [-mode] groupname\n".
+ "-remove",
+ "-read: relay from this channel to others, but do not relay to\n".
+ " this channel\n".
+ "-stat: show status messages (join/part) in this channel\n".
+ "-mode: transfer modes to this channel, even if you are op".
+ "groupname: all channels with the same group name are relayed together\n".
+ "-remove: remove this channel from the relay group",
+ '-remove %(perl_parrot_groupname) %-'.
+ '||-read|-stat|-mode|%(perl_parrot_groupname)|%*',
+ 'cmd_parrot', '');
+ read_conf();
+}
diff --git a/irc/weechat/play.pl b/irc/weechat/play.pl
@@ -0,0 +1,156 @@
+use strict;
+use warnings;
+use File::Find::Rule;
+no strict 'subs';
+
+my $SCRIPT_NAME = 'play';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.2';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Play ASCII art';
+our (%queue, %timer);
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ weechat::hook_command('play', 'Play ASCII art',
+ '[-delay ms] [-repeat times] [-pipe "command"] [-fmt "list"] filename'.
+ "\n-find pattern\n-stop\n",
+ "-delay: delay in milliseconds between lines\n".
+ "-find: list matching files, don't play\n".
+ "-pipe: pipe output into command\n".
+ "-fmt: treat file as a format string and replace with arguments in\n".
+ " list. Arguments are separated by semicolons (;)\n".
+ "filename: file to play. Supports wildcards. By default, searches\n".
+ " subdirectories as well unless '/' is found in the filename\n".
+ "-stop: stop currently playing file in buffer",
+ '-delay|-pipe|-fmt|-repeat|%*'.
+ ' || -find'.
+ ' || -stop',
+ 'cmd_play', '');
+
+ my %OPTIONS = (
+ delay => ['Default delay between lines, in milliseconds', 0],
+ dir => ['Art directory',
+ weechat::info_get('weechat_dir', '').'/ascii'],
+ find_limit => ['Maximum number of results returned by -find. '.
+ '-1 = unlimited (may lock up WeeChat with many results!)', 32],
+ );
+
+ for my $option (keys %OPTIONS) {
+ weechat::config_set_plugin($option, $OPTIONS{$option}[1])
+ unless weechat::config_is_set_plugin($option);
+ weechat::config_set_desc_plugin($option, $OPTIONS{$option}[0]);
+ }
+}
+
+sub parse
+{
+ my ($input, $delay, $pipe, $find, $repeat, $fmt) =
+ (shift, weechat::config_get_plugin('delay'), '/msg *', 0, 1, '');
+
+ if ($input =~ / *-delay +([0-9]+) /) {
+ $delay = $1;
+ $input =~ s/-delay +[0-9]+//;
+ }
+ if ($input =~ / *-find /) {
+ $find = 1;
+ $input =~ s/-find//;
+ }
+ if ($input =~ / *-fmt +("(?:[^"\\]|\\.)+"|[^ ]+) /) {
+ $fmt = $1;
+ $fmt =~ s/^"(.+)"$/$1/ if $fmt =~ /^".+"$/;
+ $input =~ s/-fmt +("(?:[^"\\]|\\.)+"|[^ ]+)//;
+ }
+ if ($input =~ / *-repeat +([0-9]+) /) {
+ $repeat = $1;
+ $input =~ s/-repeat +[0-9]+//;
+ }
+ if ($input =~ / *-pipe +("(?:[^"\\]|\\.)+"|[^ ]+) /) {
+ $pipe = $1;
+ $pipe =~ s/^"(.+)"$/$1/ if $pipe =~ /^".+"$/;
+ $input =~ s/-pipe +("(?:[^"\\]|\\.)+"|[^ ]+)//;
+ }
+
+ return ($delay, $pipe, $find, $repeat, $fmt, $input =~ s/^ +| +$//r);
+}
+
+sub play
+{
+ my $buffer = shift;
+
+ weechat::command($buffer, shift @{ $queue{$buffer} });
+ delete $queue{$buffer} unless @{ $queue{$buffer} };
+
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub cmd_play
+{
+ my $buffer = $_[1];
+
+ if ($_[2] eq '-stop') {
+ if (exists $timer{$buffer}) {
+ weechat::unhook($timer{$buffer});
+ delete $queue{$buffer};
+ }
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ my ($delay, $pipe, $find, $repeat, $fmt, $file) = parse($_[2]);
+ my $server = weechat::info_get($buffer, 'localvar_server');
+ my ($prio_s, $prio_d) = (
+ weechat::config_get("irc.server.$server.anti_flood_prio_high"),
+ weechat::config_get("irc.server_default.anti_flood_prio_high"),
+ );
+ $delay = ($delay or 1000 * (
+ weechat::config_option_is_null($prio_s)
+ ? weechat::config_integer($prio_d)
+ : weechat::config_integer($prio_s)
+ ) or 10);
+
+ my $rule = File::Find::Rule
+ ->file
+ ->name($file)
+ ->start(weechat::config_get_plugin('dir'));
+
+ if ($find) {
+ my $i = weechat::config_get_plugin('find_limit');
+ weechat::print($buffer, " \t$_")
+ while defined( $_ = $rule->match ) and --$i;
+ weechat::print($buffer, weechat::prefix('error').
+ "Too many results; please narrow your search") unless $i;
+ weechat::print($buffer, " \tEnd of file listing for '$file'");
+ return weechat::WEECHAT_RC_OK;
+ }
+
+ my $path;
+ if ($file =~ m"/") { $path = weechat::config_get_plugin('dir')."/$file" }
+ else { $path = $rule->match }
+
+ if ($path and -z $path) {
+ weechat::print($buffer, weechat::prefix('error').
+ "File '$file' is empty");
+ } elsif ($path and open FH, "<", $path) {
+ my @lines;
+ while (<FH>) {
+ no warnings; # sprintf barks if there's nothing to replace
+ $_ = sprintf $_, split ';', $fmt if $fmt;
+ push @lines, s/[\r\n]*$//r
+ }
+ close FH;
+ for (1 .. $repeat) {
+ push @{ $queue{$buffer} }, "$pipe \x0f$_\x0f" for @lines;
+ }
+
+ weechat::unhook($timer{$buffer}) if exists $timer{$buffer};
+ $timer{$buffer} =
+ weechat::hook_timer($delay, 0, scalar @{ $queue{$buffer} },
+ 'play', $buffer);
+ } else {
+ weechat::print($buffer, weechat::prefix('error').
+ "Cannot open '$file'".($! ? ": $!" : ""));
+ return weechat::WEECHAT_RC_ERROR;
+ }
+
+ return weechat::WEECHAT_RC_OK;
+}
diff --git a/irc/weechat/prismx.py b/irc/weechat/prismx.py
@@ -0,0 +1,138 @@
+# Copyright (c) 2010 Alex Barrett <al.barrett@gmail.com>
+#
+# Everyone is permitted to copy and distribute verbatim or modified
+# copies of this license document, and changing it is allowed as long
+# as the name is changed.
+#
+# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+#
+# 0. You just DO WHAT THE FUCK YOU WANT TO.
+
+import weechat as w
+import random
+import re
+
+SCRIPT_NAME = "prismx"
+SCRIPT_AUTHOR = "Alex Barrett <al.barrett@gmail.com>"
+SCRIPT_VERSION = "0.3.1"
+SCRIPT_LICENSE = "WTFPL"
+SCRIPT_DESC = "Taste the rainbow."
+
+# red, lightred, brown, yellow, green, lightgreen, cyan,
+# lightcyan, blue, lightblue, magenta, lightmagenta
+ncolors = [5, 4, 7, 8, 3, 9, 10, 11, 2, 12, 6, 13]
+xcolors = [
+16,28,40,52,64,65,53,41,29,17,18,30,42,54,66,67,55,43,31,19,20,32,44,
+56,68,69,57,45,33,21,22,34,46,58,70,71,59,47,35,23,24,36,48,60,72,73,
+61,49,37,25,26,38,50,62,74,75,63,51,39,27]
+xxcolors = range(100)
+
+# we set this later
+color_count = 0
+
+# keeping a global index means the coloring will pick up where it left off
+color_index = 0
+
+# spaces don't need to be colored and commas cannot be because mIRC is dumb
+chars_neutral = " ,"
+chars_control = "\x01-\x1f\x7f-\x9f"
+
+regex_chars = "[^%(n)s%(s)s][%(n)s%(s)s]*" % { 'n': chars_neutral, 's': chars_control }
+regex_words = "[^%(n)s]+[%(n)s%(s)s]*" % { 'n': chars_neutral, 's': chars_control }
+
+
+if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION,
+ SCRIPT_LICENSE, SCRIPT_DESC, "", ""):
+ w.hook_command("prism",
+ SCRIPT_DESC,
+ "[-rwmbexsp] [palette] text|-c[wbexsp] [palette] <sep> <command> <sep>text",
+ " -r: randomizes the order of the color sequence\n"
+ " -w: color entire words instead of individual characters\n"
+ " -m: append /me to beginning of output\n"
+ " -b: backwards text (entire string is reversed)\n"
+ " -e: eye-destroying colors (randomized background colors)\n"
+ " -c: specify a separator to turn on colorization\n"
+ " eg. -c : /topic :howdy howdy howdy\n"
+ " -x: extended color set, requires 256color terminal\n"
+ " -s: stretch to fit text\n"
+ " -p: specify color palette to use, comma separated\n"
+ " text: text to be colored",
+ "-r|-w|-m|-b|-e|-c", "prism_cmd_cb", "")
+
+def prism_cmd_cb(data, buffer, args):
+ global color_index
+ color_local = color_index
+ color_index += 1
+
+ input = args.decode("UTF-8")
+ input_method = "command"
+
+ if not input or (input[0] == '-' and input.find(' ') == -1):
+ input = (input + ' ' if input else '') + w.buffer_get_string(buffer, "input")
+ input = input.decode("UTF-8")
+ input_method = "keybinding"
+
+ if not input:
+ return w.WEECHAT_RC_OK
+
+ optstop = input and input[0] == '-' and input.find(' ')
+ opts = input[1:optstop] if optstop else ''
+ cmdstop = 'c' in opts and input.find(' ', optstop+1)
+ cmd = ''
+ if 'm' in opts: cmd = '/me '
+ if 'c' in opts:
+ find = input[optstop+1:cmdstop]
+ where = input.find(find, cmdstop+1)
+ cmd = input[cmdstop+1:where]
+ input = input[where+len(find):]
+ else:
+ input = input[optstop+bool(optstop):]
+ regex = regex_words if 'w' in opts else regex_chars
+ inc = 'r' not in opts
+ bs = 'e' in opts
+ colors = ncolors if 'x' not in opts else (xxcolors if bs or not inc else xcolors)
+ if 'p' in opts:
+ i = input.find(' ')
+ colors = input[:i].split(',')
+ input = input[i+1:]
+ input = input[::-1] if 'b' in opts else input
+ output = u""
+ tokens = re.findall(regex, input)
+
+ if 's' in opts:
+ color_local = 0
+ colors = [colors[int(float(i)/len(tokens)*len(colors))]
+ for i in xrange(len(tokens))]
+
+ color_count = len(colors)
+ for token in tokens:
+ # prefix each token with a color code
+ c1 = unicode(colors[color_local % color_count]).rjust(2, "0")
+ if bs:
+ c2 = random.randint(1, color_count - 1) % color_count
+ c2 = unicode(colors[c2 + 1 if c2 == color_local % color_count else c2]).rjust(2,"0")
+ output += u'\x03' + c1 + ',' + c2 + token
+ else:
+ output += u"\x03" + c1 + token
+
+ # select the next color or another color at
+ # random depending on the options specified
+ if not inc:
+ color_local += random.randint(1, color_count - 1)
+ else:
+ color_local += inc
+ output += u'\x0f'
+
+ # output starting with a / will be executed as a
+ # command unless we escape it with a preceding /
+ # Commands should use the -c flag
+ if len(output) > 0 and output[0] == "/":
+ output = "/" + output
+ if len(cmd) > 0:
+ output = cmd + output
+ if input_method == "keybinding":
+ w.buffer_set(buffer, "input", output.encode("UTF-8"))
+ else:
+ w.command(buffer, output.encode("UTF-8"))
+ return w.WEECHAT_RC_OK
diff --git a/irc/weechat/sighup.pl b/irc/weechat/sighup.pl
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+
+no strict 'subs';
+
+my $SCRIPT_NAME = 'sighup';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.0';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Reload config on SIGHUP';
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ weechat::hook_signal('signal_sighup', 'cb_sighup', '');
+}
+
+sub cb_sighup {
+ weechat::command('', '/reload');
+
+ return weechat::WEECHAT_RC_OK_EAT;
+}
+
diff --git a/irc/weechat/snomasks.pl b/irc/weechat/snomasks.pl
@@ -0,0 +1,58 @@
+# Released into the Public Domain
+
+# Note: After loading the script and adding snomasks into one of your bars, you
+# must request /umode once on each server you have server notices masks set on.
+# After that, the script will automatically update the bar item.
+
+use strict;
+use warnings;
+
+no strict 'subs';
+
+my $SCRIPT_NAME = 'snomasks';
+my $SCRIPT_AUTHOR = 'The Krusty Krab <wowaname@volatile.ch>';
+my $SCRIPT_VERSION = '1.1';
+my $SCRIPT_LICENCE = 'Public domain';
+my $SCRIPT_DESC = 'Server notice mask bar item for opers';
+
+if (weechat::register($SCRIPT_NAME, $SCRIPT_AUTHOR, $SCRIPT_VERSION,
+ $SCRIPT_LICENCE, $SCRIPT_DESC, '', '')) {
+ weechat::bar_item_new('snomasks', 'bar_snomasks', '');
+ weechat::hook_signal('buffer_switch', 'buffer_switch', '');
+ weechat::hook_signal('irc_server_disconnected', 'irc_disconnected', '');
+ weechat::hook_signal('*,irc_raw_in_008', 'irc_008', '');
+}
+
+my %snomask;
+
+sub bar_snomasks {
+ my $buffer = weechat::current_buffer();
+
+ return ''
+ if weechat::buffer_get_string($buffer, 'localvar_plugin') ne 'irc';
+
+ my $server = weechat::buffer_get_string($buffer, 'localvar_server');
+ return $snomask{$server} // '';
+}
+
+sub buffer_switch {
+ weechat::bar_item_update('snomasks');
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_008 {
+ my (undef, $server, $modes) = (shift,
+ shift =~ /^(.+),irc_raw_in_008$/,
+ shift =~ /:[^ ]* 008 [^ ]* (?::Server notice mask \()?([^ )]*)/);
+ $server = lc $server;
+
+ $snomask{$server} = $modes;
+ weechat::bar_item_update('snomasks');
+ return weechat::WEECHAT_RC_OK;
+}
+
+sub irc_disconnected {
+ my $server = pop;
+ delete $snomask{lc $server};
+ return weechat::WEECHAT_RC_OK;
+}
| | | | | | | | | | |