pax_global_header00006660000000000000000000000064130303410540014503gustar00rootroot0000000000000052 comment=86b22e41e4145a0d442c807690a22b8bb05fdc38 cadubi-1.3.3/000077500000000000000000000000001303034105400127365ustar00rootroot00000000000000cadubi-1.3.3/LICENSE000066400000000000000000000020701303034105400137420ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 Ian Langworth Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cadubi-1.3.3/README.md000066400000000000000000000132711303034105400142210ustar00rootroot00000000000000# CADUBI - Creative ASCII Drawing Utility By Ian This Perl program was written sometime around 1997 -- many years before I knew anything about Perl or Unix -- and the code hasn't changed much since then. It has, however, become very widely adopted and is available as a package on most Linux distributions. CADUBI is an application written in Perl that allows you to draw text-based images that are viewable on typical unix-based consoles. Usually the applications that emulate these consoles support various text modes, such as background and foreground colors, bold, and inverse. This text art, commonly called "ASCII art," is used in various places such as online BBSes, email and login prompts. ## Screen shots ## Installation * [Homebrew](http://brew.sh/): `brew install cadubi` * [Debian](https://packages.debian.org/wheezy/cadubi) and [Ubuntu](http://packages.ubuntu.com/precise/cadubi): `apt-get install cadubi` * From source: * Perl 5.002 or later * `Term::ReadKey` Perl module ## Usage CADUBI has a 'pen' which describes the current mode. Properties of the pen are the painting character, foreground color, background color, bold, inverse, and blink. Whenever you paint or use the text mode, the characters drawn on the screen will have the properties of the pen. The current mode of the pen is shown at the bottom of the console and is what will be drawn on screen when you paint. Move around the cursor with the i, j, k and l keys. Holding down shift and typing these keys will move the cursor five spaces instead of one. Pressing return/enter will move the cursor down one line and all the way to the left of the console. To paint the current pen on the screen, press the space bar. To delete a character, press the delete/backspace key. You'll notice that editing is much like common text editors, such as pico or joe. You can also delete with the tilde key, which makes moving & painting (right hand) and erasing (left hand) much easier. The pen character is the character that is drawn when you paint using the space bar. To change the character, press p and then the character you would like it to be. To set the foreground or background colors for the cursor, press f for foreground or b for background, and then a corresponding color code. The color codes are case-insensitive and are listed below: 0 or N Normal (standard text) 1 or W White 2 or R Red 3 or G Green 4 or Y Yellow 5 or B Blue 6 or M Magenta 7 or C Cyan 8 or K Black If you can't remember the codes above, you can always hit Ctrl-h to view the Quick Help which will display a summary of all the keys, color codes and examples of how they look. Typically, foreground text colors are the same as background colors, unless the text is bold. If the text is bold, foreground colors are usually lighter than the background color, making text easier to read when the text has the same foreground and background color. Refer to the Quick Help (Ctrl-h) to see what the colors look like on your console. Bold and inverse are two widely-supported modes. Bold is toggled with the g key, and inverse is toggled with the v key. Blink, though regarded as highly annoying, can be toggled with by pressing Shift-w. Text mode is an extremely useful feature. Once in the text mode you can type as if you were using a normal text editor, and all the characters drawn onscreen will use the same mode as the pen. To enter text mode, press the t key. To exit, press escape. To exit the CADUBI application, press Ctrl-x. Quick help can be accessed by pressing Ctrl-h. In case it is needed, pressing Ctrl-w will refresh the entire screen by redrawing each character. ### Reading and writing files To read a file and use it with CADUBI, type Ctrl-r. To write a file, type Ctrl-o. You will be prompted for a filename. When CADUBI reads a file, it will only read as much that will fit in the workspace (the area of the console minus the bottom row [status bar]). To gain more workspace, see the `-s` operator in 'COMMAND LINE USAGE' below. CADUBI optimizes its output files to display properly and take up as little space as possible. All CADUBI output can be viewed with the 'cat' utility. ## Command line usage Usage: cadubi [OPTIONS] [FILE] Available options: -h, --help what you're looking at now -m, --mute turn off beeping -s, --size [W] [H] sets the size of the console for use with CADUBI, where W is number of columns and H is number of rows. -v, --version show CADUBI version Example: Will make the cadubi workspace 160 columns wide, 48 rows high, disable beeping, and open the file 'bacon.txt': cadubi --mute --size 160 48 bacon.txt Will display the version of CADUBI, copyright and author: cadubi -v ## Tips Whenever you are prompted to type in information, such as the name of a file to read/write to, you can hit escape to cancel. You can also hit escape to get out of text mode. When using the `-s` or `--size` command line option, make sure your console actually _is_ that size or the text won't wrap properly and CADUBI will look funny. cadubi-1.3.3/cadubi000077500000000000000000000741421303034105400141230ustar00rootroot00000000000000#!/usr/bin/perl eval 'case $# in 0) exec /usr/bin/perl -S "$0";; *) exec /usr/bin/perl -S "$0" "$@";; esac' if 0; $VERSION = '1.3.3'; ######################################################################## # MAIN LOOP # kludge to make this easier (?) for package maintainers # (sorry guys, i wrote this years before i had the remotest clue as to # what the hell i was doing) use FindBin qw($Bin); $HELPFILE = "$Bin/help.txt"; # other stuff $DEBUG = 0; $CADUBI_VERSION = $VERSION; use Term::ReadKey; use lib "$Bin/../lib"; # global variables $ESC = "\x1b"; # our most important var $AUDIBLE = 1; # beep unless -m, --mute, or configured in 'cadubi' @pos = (1,1); # position of cursor (x,y) @totalspan = undef; # width & height of console (x,y) @workspan = undef; # same as $totalspace, but y-1 @charmap = undef; # a 3D array: # [col] [row] [(0 => char to paint with # 1 => bg color # 2 => fg color # 3 => bold # 4 => inverse # 5 => blink # 6 => special char command # )] @charmode = ('x',0,0,0,0,0,''); $status_changed = 1; # used with &status so we don't constantly redraw. $current_filename = undef; # name of file we're working with $cadubi_done = 0; # main loop var # runtime statements &initKeys(); # setup %controlkeys and %keymap &initANSI(); # setup %ansi_mode &setspan(); # setup span of terminal (default 24x80) &get_args; # read in command line parameters &clear; # clear screen &debug_open(); # open debug file ReadMode raw; # set terminal getchar mode if ($current_filename) { # file has been specified via command line, open it &user_readfile($current_filename); } else { # draw default status bar &status(); } do { &status if &HandleKeystroke(ReadKey(0)); # handle the key } until ($cadubi_done); &clear; # clear screen &cleanup; # cleanup code sub cleanup { ReadMode restore; # restore previous terminal getchar mode &debug_close(); # close debug file print $ESC.'[0m'; # return to normal ansi mode if anything has messed up } ######################################################################## # ANSI MODES sub initANSI { %ansi_mode = ( 'escape' => "\x1b", 'normal' => 0, 'bold' => 1, 'blink' => 5, 'inverse ' => 7, 'invisible' => 8, 'fg_black' => 30, 'fg_red' => 31, 'fg_green' => 32, 'fg_yellow' => 33, 'fg_blue' => 34, 'fg_magenta' => 35, 'fg_cyan' => 36, 'fg_white' => 37, 'bg_black' => 40, 'bg_red' => 41, 'bg_green' => 42, 'bg_yellow' => 43, 'bg_blue' => 44, 'bg_magenta' => 45, 'bg_cyan' => 46, 'bg_white' => 47 ); # color codes is used strictly for interface purposes %color_codes = qw( N normal 0 normal W white 1 white R red 2 red G green 3 green Y yellow 4 yellow B blue 5 blue M magenta 6 magenta C cyan 7 cyan K black 8 black ); } ######################################################################## # CONSOLE ROUTINES sub curs_move { # accepts coordinates ((x,y) or (column, row)) if (($_[0] >= 1) && ($_[0] <= $totalspan[0]) && ($_[1] >= 1) && ($_[1] <= $totalspan[1])) { print $ESC.'['.$_[1].';'.$_[0].'H'; @pos = ($_[0], $_[1]); } else { #&debug('&curs_move out of range: ('.$_[0].','.$_[1].')'); #&debug(' >> @totalspan = ('.$totalspan[0].','.$totalspan[1].')'); #&debug(' >> @workspan = ('.$workspan[0].','.$workspan[1].')'); #&debug(' >> @pos = ('.$pos[0].','.$pos[1].')'); return 0; } 1; } sub curs_move_up { if ($pos[1] > 1) { print $ESC.'[1A'; $pos[1]--; } else { &beep; return 0; } 1; } sub curs_move_dn { if ($pos[1] < $workspan[1]) { print $ESC.'[1B'; $pos[1]++; } else { &beep; return 0; } 1; } sub curs_move_rt { if ($pos[0] < $workspan[0]) { print $ESC.'[1C'; $pos[0]++; } else { &beep; return 0; } 1; } sub curs_move_lt { if ($pos[0] > 1) { print $ESC.'[1D'; $pos[0]--; } else { &beep; return 0; } 1; } sub clear { print $ESC.'[2J'; &curs_move(1,1); } # set the size of our workspace sub setspan { if (@_) { @totalspan = ($_[0],$_[1]); @workspan = ($_[0],$_[1]-1); &debug("\&setspan (specified): $_[0], $_[1]"); } elsif (GetTerminalSize) { #Term::ReadKey my ($w, $h, @x) = GetTerminalSize; #Term::ReadKey @totalspan = ($w,$h); @workspan = ($w,$h-1); &debug("\&setspan (using Term::ReadKey): $w, $h"); } else { # we must assume, even though it makes an ass of u and me @totalspan = (80,24); @workspan = (80,23); &debug("\&setspan (assumed): 80, 24"); } } # our status bar # if no parameters, erases if status has changed # if string is first argument, fills entire status bar with string # if string begins with '>', only replace 'CADUBI v1.x' in status bar with string # if second argument is true, leave the cursor at the end of the status text... # (good for prompts, see &user_writefile(). sub status { my $msg = shift; my $leave_cursor = shift; my $out = undef; if ($msg && (substr($msg,0,1) ne '>')) { $out = ''.$ESC.'[0m'.$ESC.'[7m '. pack('A'.($totalspan[0]-1), $msg).$ESC.'[0m'; $status_changed = 1; } else { if ($status_changed || $msg) { my $out_vers; if ($msg) { $out_vers = pack('A34',' '.substr($msg,1).' '); $status_changed = 1; } else { $out_vers = pack('A34',' cadubi '.$CADUBI_VERSION.' '); $status_changed = 0; } my $out_help = ' Type ^H for Help '; my $out_char = ' Pen: '.&printchar(@charmode).' '; $out = $ESC.'[0m'.$ESC.'[7m'.$out_vers. $ESC.'[0m'.$out_char.$ESC.'[7m'. (' ' x ($totalspan[0]- length($out_vers)- length($out_help)- 8) ). $out_help.$ESC.'[0m'; } } my @oldpos = @pos; &curs_move(1,$totalspan[1]); print $out; &curs_move(@oldpos) unless $leave_cursor; } # this promps the user with the first argument given, and waits for a string. # pass it a maximum string length for second argument. if no second argument, # user's allowed to fill the width between prompt & right edge with text. # a third argument is treated as a default answer, already filled in the field sub get_user_string { my $msg = shift; my $max = shift; my $out = shift; my @oldpos = @pos; my $char = undef; &curs_move(1,$totalspan[1]); # notice we don't print a normal mode sequence (\x1b[0m) because we # want to keep writing in inverse. we print a normal mode right before # we do a return. print $ESC.'[7m '.pack('A'.($workspan[0]-2),$msg)." "; $max = $workspan[0]-length($msg)-3 unless $max; &curs_move(length($msg)+3,$totalspan[1]); print $out; while (not $char =~ /[\n\x1b]/) { $char = ReadKey(0); # no chars < space if ($char =~ /[\x00-\x1f]/) { &beep; } # delete, but don't delete past starting x position elsif (ord($char) == $keymap{'del'}) { if ($out) { # print a backspace...the same as move left one char, print # a space (which moves the cursor right one char), then move # back one char again print $ESC.'[1D '.$ESC.'[1D'; $out = substr($out,0,-1); } else { &beep; } } else { if (length($out) >= $max) { &beep; } else { $out .= $char; print $char; } } } &curs_move(@oldpos); print $ESC.'[0m'; # refresh status bar $status_changed = 1; &status(); # user hit enter return $out if ($char eq "\n"); # user hit cancel return undef; } ######################################################################## # SUPPORT SUBROUTINES sub beep { print "\x07" if $AUDIBLE; } sub refresh { my @oldpos = @pos; &clear(); my ($x, $y); for ($y=1; $y<=$workspan[1]; $y++) { for ($x=1; $x<=$workspan[0]; $x++) { if (@{$charmap[$x][$y]}) { print &printchar(@{$charmap[$x][$y]}); } else { print ' '; } } &curs_move($x--,$y); } &curs_move(@oldpos); } sub printchar { # returns a string with the current ANSI mode and the character my $out = undef; my @desc = @_; my $char = shift(@desc); #key to draw pop(@desc); #remove special char command $out.= $ESC.'['; #print properties foreach (@desc) { $out.= $_.';' if ($_); } $out = substr($out,0,-1).'m'; $out = undef if ($out eq $ESC.'m'); if (defined($char)) { #print char or space if there's no char $out.= $char; } else { $out.= ' '; } $out.= $ESC.'[0m'; return $out; } sub paintchar { # prints the char on screen and saves it to @charmap $charmap->[$pos[0]][$pos[1]] = [@charmode]; print &printchar(@charmode); &curs_move(@pos); #print moves to the right on us, without asking. the nerve! } sub erasechar { # saves blank char to @charmap, prints $charmap->[$pos[0]][$pos[1]] = undef; print &printchar(@{$charmap->[$pos[0]][$pos[1]]}); &curs_move(@pos); #print moves to the right on us, without asking. the nerve! } sub usage { if ($_[0]) { print $_[0]."\n"; } print <> printed &usage'); &usage(); &cleanup; exit(1); } elsif (($option eq '-v') || ($option eq '--version')) { &debug('>> printed &version'); &version; &cleanup; exit(1); } elsif (($option eq '-m') || ($option eq '--mute')) { &debug('>> disabled audio'); $AUDIBLE = 0; } elsif (($option eq '-s') || ($option eq '--size')) { ($param1, $param2) = (shift(@ARGS), shift(@ARGS)); &debug('>> grabbing setspan variables, raw:'); &debug('>> $param1 = '.$param1); &debug('>> $param2 = '.$param2); $param1 = 80 unless $param1; $param2 = 24 unless $param2; &debug('>> processed setspan vars:'); &debug('>> $param1 = '.$param1); &debug('>> $param2 = '.$param2); &setspan($param1, $param2); } elsif ($option =~ /^-/) { &usage('Unknown option: '.$option); &cleanup; exit(1); } elsif (not $got_filename) { $got_filename = 1; $current_filename = $option; } else { &usage('Unknown argument: '.$option); &cleanup; exit(1); } } } ######################################################################## # DEBUGGING sub debug { print DEBUGFH $_[0]."\n" if ($DEBUG && DEBUGFH); } sub debug_open { open(DEBUGFH, '>cadubi_debug.txt') if $DEBUG; &debug('Debug file opened '.(localtime)); } sub debug_close { &debug('Debug file closed '.(localtime)); close(DEBUGFH) if DEBUGFH; } ######################################################################## # KEY HANDLING sub initKeys { %controlkeys = GetControlChars; #Term::ReadKey # DISCARD # DSUSPEND # EOF # EOL # EOL2 # ERASE # ERASEWORD # INTERRUPT # KILL # MIN # QUIT # QUOTENEXT # REPRINT # START # STATUS # STOP # SUSPEND # SWITCH # TIME %keymap = ( '^a' => 1, '^b' => 2, '^d' => 4, '^e' => 5, '^f' => 6, '^g' => 7, #bell '^h' => 8, '^i' => 9, '^k' => 11, '^o' => 15, '^p' => 16, '^r' => 18, '^t' => 20, '^u' => 21, '^v' => 22, '^w' => 23, '^x' => 24, '^y' => 25, 'esc' => 27, 'del' => 127, 'up' => 30, 'dn' => 31, 'lt' => 28, 'rt' => 29, 'space' => 32, 'cr' => 13, 'lf' => 10); } sub HandleKeystroke { my $key = shift; # ansi escape chars, like arrow keys if ($key eq $ESC) { if (ReadKey(0) eq '[') { my $newkey = ReadKey(0); if ($newkey eq 'A') {&curs_move_up; return 1;} elsif ($newkey eq 'B') {&curs_move_dn; return 1;} elsif ($newkey eq 'C') {&curs_move_rt; return 1;} elsif ($newkey eq 'D') {&curs_move_lt; return 1;} else { &status("Unknown escape sequence: '".$newkey."'"); return 0; } } else { &status("Unknown escape sequence."); return 0; } } # moving around keys (ijkl, IJKL, arrow keys) if ($key eq 'i') {&curs_move_up; return 1;} if ($key eq 'j') {&curs_move_lt; return 1;} if ($key eq 'k') {&curs_move_dn; return 1;} if ($key eq 'l') {&curs_move_rt; return 1;} if ($key eq 'I') {for (1 .. 5) {&curs_move_up}; return 1;} if ($key eq 'J') {for (1 .. 5) {&curs_move_lt}; return 1;} if ($key eq 'K') {for (1 .. 5) {&curs_move_dn}; return 1;} if ($key eq 'L') {for (1 .. 5) {&curs_move_rt}; return 1;} # exit if (ord($key) == $keymap{'^x'}) { $cadubi_done = 1; return 1; } # carrage return if ($key eq "\n") { # if we're at the bottom of the workspace, don't return if ($pos[1] >= $workspan[1]) { &curs_move(1, $pos[1]); } else { &curs_move(1, $pos[1]); &curs_move_dn; } return 1; } # paint if ($key eq ' ') { &paintchar; &curs_move_rt if ($pos[0] < $workspan[0]); return 1; } # erase if ((ord($key) == $keymap{'del'}) || ($key eq '`')) { &curs_move_lt; &erasechar; return 1; } # text mode if ($key eq 't') { my $char = undef; my $oldchar = $charmode[0]; my $startingx = $pos[0]; &status('Text mode (escape key exits)'); while ($char ne "\x1b") { $char = ReadKey(0); # if user hit return, move down a line to starting point if ($char eq "\n") { # if we're at the bottom of the workspace, don't return if ($pos[1] >= $workspan[1]) { &beep; } else { &curs_move($startingx, $pos[1]); &curs_move_dn; } } # no chars < space elsif ($char =~ /[\x00-\x1a\x1c-\x1f]/) { &beep; } # delete, but don't delete past starting x position elsif (ord($char) == $keymap{'del'}) { if ($pos[0] > $startingx) { &curs_move_lt; } else { &beep; } &erasechar; } elsif ($char ne $ESC) { $charmode[0] = $char; &paintchar(@charmode); &curs_move_rt; } } $charmode[0] = $oldchar; return 1; } # paint modes if ($key eq 'p') { # pen character &status('Set pen character:'); my $newkey = ReadKey(0); if ($newkey =~ /[\x00-\x1f\x7f]/) { &beep; &status('Unusable pen selection'); } else { $charmode[0] = $newkey; &status(">Pen char now: '".$newkey."'"); } return 0; } if ($key eq 'g') { # bold $charmode[3] = ($charmode[3]) ? 0 : 1; &status(">Bold enabled") if $charmode[3]; &status(">Bold disabled") unless $charmode[3]; return 0; } if ($key eq 'v') { # inverse $charmode[4] = ($charmode[4]) ? 0 : 7; &status(">Inverse enabled") if $charmode[4]; &status(">Inverse disabled") unless $charmode[4]; return 0; } if ($key eq 'W') { # blink (that's W for "why?") $charmode[5] = ($charmode[5]) ? 0 : 5; &status(">Blink enabled") if $charmode[5]; &status(">Blink disabled") unless $charmode[5]; return 0; } if ($key eq 'f') { &status('Set pen foreground color:'); my $newkey = ReadKey(0); if ($newkey =~ /[nN0]/) {$charmode[2] = $ansi_mode{'normal'}} elsif ($newkey =~ /[wW1]/) {$charmode[2] = $ansi_mode{'fg_white'}} elsif ($newkey =~ /[rR2]/) {$charmode[2] = $ansi_mode{'fg_red'}} elsif ($newkey =~ /[gG3]/) {$charmode[2] = $ansi_mode{'fg_green'}} elsif ($newkey =~ /[yY4]/) {$charmode[2] = $ansi_mode{'fg_yellow'}} elsif ($newkey =~ /[bB5]/) {$charmode[2] = $ansi_mode{'fg_blue'}} elsif ($newkey =~ /[mM6]/) {$charmode[2] = $ansi_mode{'fg_magenta'}} elsif ($newkey =~ /[cC7]/) {$charmode[2] = $ansi_mode{'fg_cyan'}} elsif ($newkey =~ /[kK8]/) {$charmode[2] = $ansi_mode{'fg_black'}} if ($newkey =~ /[NWRGYBMCK012345678]/i) { &status(">Foreground: ".$color_codes{uc($newkey)}); } else { &beep; &status("Unknown color selection: '".$newkey."'") } return 0; } if ($key eq 'b') { &status('Set pen background color:'); my $newkey = ReadKey(0); if ($newkey =~ /[nN0]/) {$charmode[1] = $ansi_mode{'normal'}} elsif ($newkey =~ /[wW1]/) {$charmode[1] = $ansi_mode{'bg_white'}} elsif ($newkey =~ /[rR2]/) {$charmode[1] = $ansi_mode{'bg_red'}} elsif ($newkey =~ /[gG3]/) {$charmode[1] = $ansi_mode{'bg_green'}} elsif ($newkey =~ /[yY4]/) {$charmode[1] = $ansi_mode{'bg_yellow'}} elsif ($newkey =~ /[bB5]/) {$charmode[1] = $ansi_mode{'bg_blue'}} elsif ($newkey =~ /[mM6]/) {$charmode[1] = $ansi_mode{'bg_magenta'}} elsif ($newkey =~ /[cC7]/) {$charmode[1] = $ansi_mode{'bg_cyan'}} elsif ($newkey =~ /[kK8]/) {$charmode[1] = $ansi_mode{'bg_black'}} if ($newkey =~ /[NWRGYBMCK012345678]/i) { &status(">Background: ".$color_codes{uc($newkey)}); } else { &beep; &status("Unknown color selection: '".$newkey."'") } return 0; } # file i/o if (ord($key) == $keymap{'^r'}) { return &user_readfile; } if (ord($key) == $keymap{'^o'}) { return &user_writefile; } # refresh if (ord($key) == $keymap{'^w'}) { #refresh &refresh(); &status('Workspace refreshed'); return 1; } # help if (ord($key) == $keymap{'^h'}) { #Help if (-e $HELPFILE) { my @oldmap = @charmap; my @oldpos = @pos; &readfile($HELPFILE); &status('Press a key to continue...', 1); my $temp = ReadKey(0); @charmap = @oldmap; $oldmap = undef; &curs_move(@oldpos); &refresh; &status; } else { &beep; &status("$HELPFILE not available"); } return 0; } # other if (ord($key) == $keymap{'^t'}) { # TEST &beep; return 0; } # no cigar! &beep; return 0; } ######################################################################## # FILE SUBROUTINES sub readfile { # pass it a filename as first argument, reads a file into # the @charmap array my $filepath = shift; my @oldpos = @pos; my @oldcharmode = @charmode; my ($char, $buf, $command, @nums); my $x = 1; my $y = 1; open(IN, '<'.$filepath); unless (IN) { return 0; } @charmap = undef; &debug('&readfile parsing:'); PARSE: while (not eof(IN)) { # MAGICAL ANSI ESCAPE SEQUENCE PARSER # This parses almost all the escape sequences I could get documentation on. # Even though, other than the mode change sequences, they will hardly ever # appear in an ascii art file, it's good to be prepared. # # I've parsed all EXCEPT this format: # ESC[#;"string";#p # $char = ReadKey(0, IN); &debug('>> "'.$char.'"'); # exit if we've found more lines than max if ($y > $workspan[1]) { &debug('>> '.$y.' is greater than '.$workspan[1]); last PARSE; } # if we've hit a newline in the file if ($char eq "\n") { &debug('>> newline'); $y++; $x = 1; } # if we've found more chars on the line than max elsif ($x > $workspan[0]) { &debug('>> maximum chars hit'); $y++; $x = 1; # read until newline do { $char = ReadKey(0, IN); } until ($char eq "\n"); } elsif ($char eq $ESC) { # escape sequence $char = ReadKey(0, IN); if ($char eq '[') { $char = ReadKey(0, IN); # These escape sequence types don't need support if ($char =~ /[usK]/) { # example: ESC[u } # Double-char unsupported escape sequences elsif ($char =~ /[2]/) { # example: ESC[2J $char = ReadKey(0, IN); } # Multi-numbered wierd with digits elsif ($char =~ /[\=\?]/) { # example: ESC[=21;29h do { $char = ReadKey(0, IN); } until (not ($char =~ /[\d\;]/)); } # Eeek! Keyboard reassignment! elsif ($char eq '"') { # example: ESC["string"p $char = ReadKey(0, IN); # get first " do { $char = ReadKey(0, IN); # get string" } until ($char eq '"'); $char = ReadKey(0, IN); # get final p } # Oh great. We've hit digits. elsif ($char =~ /\d/) { # example: ESC[31;7m $buf = $char; # read until we hit a non-digit or non-; char do { $char = ReadKey(0, IN); $buf .= $char; } until (not ($char =~ /[\d\;]/)); # $command is the letter following the number series $command = substr($buf,-1,1); # $buf ends up being a ; delimeted list of numbers $buf = substr($buf,0,-1); # @nums is a list the numbers @nums = split(/\;/, $buf); &debug(">> Sequence:"); &debug(">> -> \$command = $command"); &debug(">> -> \$buf = $bug"); &debug(">> -> \@nums = "); foreach (@nums) {&debug(">> -> !- $_")} # make sure these numbers are a mode change if ($command eq 'm') { # did we get a set-to-normal mode? (ESC[0m]) if (grep(/0/, @nums)) { @charmode = (' ',0,0,0,0,0,''); # no, we got a regular mode change } else { foreach (@nums) { $charmode[1] = $_ if (($_ >= 40) && ($_ <= 47)); $charmode[2] = $_ if (($_ >= 30) && ($_ <= 37)); $charmode[3] = $_ if ($_ == 1); $charmode[4] = $_ if ($_ == 7); $charmode[5] = $_ if ($_ == 5); } } } } } } else { $charmode[0] = $char; $charmap->[$x][$y] = [@charmode]; $x++; } } close(IN); &refresh; &curs_move(@oldpos); @charmode = @oldcharmode; return 1; } sub writefile { # pass it a filename, writes the entire @charmap to file, readable by # cat, more, less, whatever. my $filepath = shift; my $out = undef; my ($thisline, $thischar); my $inital_space = 1; my ($x, $y, $i, $d, $max, @newmode, @oldmode, @outlines); for ($y=1; $y<=$workspan[1]; $y++) { # fresh new line to work with @oldmode = qw(99 99 99 99 99 99); $thisline = undef; for ($x=1; $x<=$workspan[0]; $x++) { # set @newmode to the mode of the char we're about to write @newmode = @{$charmap[$x][$y]}; # is our new char mode different from our old one? $d = 0; $max = ($#oldmode > $#newmode) ? $#oldmode : $#newmode; for($i=1; $i<=$max; $i++) { # notice $i starts at one so we skip the character $d++ if ($oldmode[$i] != $newmode[$i]); } # if our new char mode is indeed different, add a normal # mode sequence and our new mode and char. else, just add # the char. if ($d) { $thisline .= $ESC.'[0m'.substr(&printchar(@{$charmap[$x][$y]}),0,-4); } else { # make sure it's not just a space if (@{$charmap[$x][$y]}) { $thisline .= $newmode[0]; } else { $thisline .= ' '; } } # now make @newmode our @oldmode @oldmode = @newmode; } # kill trailing whitespace on single lines $thisline =~ s/(\s+)$//; # make sure each line ends with a normal mode sequence push(@outlines, $thisline.$ESC."[0m\n"); } open(OUT, ">$filepath") or return 0; # kill trailing lines $x = 0; for ($i=$#outlines; $i>=0; $i--) { unless (($outlines[$i] eq $ESC.'[0m'.$ESC."[0m\n") && (not $x)) { $out = $outlines[$i].$out; $x++; } } print OUT $out; close(OUT); if ($out) { return length($out); } else { # if no bytes were written, we'll return 'zero' return 'zero'; } } sub user_writefile { my ($filename, $reply, $bytes_written); my $file_exists = 1; my @oldpos = @pos; while ($file_exists) { $filename = &get_user_string('File name to write:', undef, $current_filename); # user canceled return 1 unless defined($filename); # check if file exists if (-e $filename) { &status('File already exists. Overwrite? (y/n)',1); $reply = uc(ReadKey(0)); $file_exists = 0 if ($reply eq 'Y'); return 1 if ($reply eq $ESC); &status(); } else { $file_exists = 0; } } $current_filename = $filename; $bytes_written = &writefile($filename); if ($bytes_written) { &status("Wrote '".$filename."' (".$bytes_written.' bytes)'); } else { &beep; &status("Couldn't write file '".$filename."': ".$!); } &curs_move(@oldpos); return 0; } sub user_readfile { my $filename; if ($_[0]) { $filename = $_[0]; } else { $filename = &get_user_string('File name to read:', undef, $current_filename); } # user canceled return 1 unless defined($filename); if (-e $filename) { if (&readfile($filename)) { &status("Read file '".$filename."'"); } else { &status("Couldn't read file '".$filename."': ".$!); } } else { &status("File '".$filename."' doesn't exist."); } return 0; } ######################################################################## # EOF 1; cadubi-1.3.3/cadubi.1000066400000000000000000000112041303034105400142450ustar00rootroot00000000000000.\" created by Abel Daniel for the Debian Gnu/Linux version, but may be used by others. .TH "cadubi" "1" "1.3.3" "Abel Daniel" "User commands" .SH "NAME" cadubi \- Creative ASCII Drawing Utility By Ian .SH "DESCRIPTION" cadubi is an application written in Perl that allows you to draw text\-based images that are viewable on typical UNIX\-based consoles. Usually the applications that emulate these consoles support various text modes, such as background and foreground colors, bold, and inverse. This text art, commonly called "ASCII art", is used in various places such as online BBSes, email and login prompts. .SH "OPTIONS" .TP .B \-h \-\-help display some documentation .TP .BI \-m \-\-mute turn off beeping .TP .BI "\-s ["W "] ["H ] .TP .BI "\-\-size ["W "] ["H ] sets the size of the console for use with cadubi, where W is number of columns and H is number of rows. .TP .B \-v \-\-version show cadubi's version .SH "CONFIGURING" Beeping and command line options can be also set in /usr/bin/cadubi. .SH "KEYBOARD" .TP .B i j k l Move the cursor around. Holding down shift and typing these keys will move the ursor five spaces instead of one. .TP .B space Paint the current pen on the screen. .TP .B return/enter Move the cursor down one line and all the way to the left of the console. .TP .BI "delete " "or " "backspace " "or "` Delete the character before the cursor. .TP .B p Prompt for a pen character .TP .B f Prompt for foreground color (see section colors). .TP .B b Prompt for background color (see section colors). .TP .B g Toggle bold mode. .TP .B v Toggle inverse mode. .TP .B shift-w Toggle blink (highly annoying). .TP .B t Enter text mode. This allows you to type like as if you were using a normal text editor, and all the characters drawn onscreen will use the same mode as the pen . Pressing Esc will exit text mode. .TP .B control-w Refresh the entire screen by redrawing each character. .TP .B control-r Open a file. .TP .B control-o Save the file. .TP .B control-h Show the quick help screen. .TP .B control-x Exit cadubi. .SH "USING" Cadubi has a 'pen' which describes the current mode. Properties of the pen are the painting character, foreground color, background color, bold, inverse, and blink. Whenever you paint or use the text mode, the characters drawn on the screen will have the properties of the pen. The current mode of the pen is shown at the bottom of the console and is what will be drawn on screen when you paint. . Typically, foreground text colors are the same as background colors, unless the text is bold. If the text is bold, foreground colors are usually lighter than the background color, making text easier to read when the text has the same foreground and background color. Refer to the Quick Help (control-'h') to see what the colors look like on your console. Text mode is an extremely useful feature. Once in the text mode you can type as if you were using a normal text editor, and all the characters drawn onscreen will use the same mode as the pen. To enter text mode, press the 't' key. To exit, press escape. When cadubi reads a file, it will only read as much that will fit in the workspace (the area of the console minus the bottom row [status bar]). To gain more workspace, see the '-s' operator in section "options". Cadubi optimizes its output files to display properly and take up as little space as possible. All cadubi output can be viewed with the 'cat' utility. .SH "COLORS" The color codes are case-insensitive. The following color codes can be chosen as fore- or background colors: .IP 0 or N \- Normal (standard text) .IP 1 or W \- White .IP 2 or R \- Red .IP 3 or G \- Green .IP 4 or Y \- Yellow .IP 5 or B \- Blue .IP 6 or M \- Magenta .IP 7 or C \- Cyan .IP 8 or K \- Black .SH "WARNING" Cadubi uses escape sequences for things like color. These may differ from system to system. This means that the file generated by cadubi may trash your console when viewed with for example cat. It is generally safe to use the files on the same type of console as they were generated on. .SH "AUTHORS" Cadubi was created and is currently being maintained by Ian Langworth. Please send all questions, comments, hate mail and bug reports to cadubi@logicallemon. com .SH "SEE ALSO" The "Keyboard and Console HOWTO" and the "Text Terminal HOWTO" from the Linuxdoc project (www.linuxdoc.org). Both are available in a Debian GNU/Linux system by installing the doc-linux-text package at .B /usr/share/doc/HOWTO/en-txt/Keyboard-and-Console-HOWTO.gz and .B /usr/share/doc/HOWTO/en-txt/Text-Terminal-HOWTO.gz respectively. This man page was copy-pasted from other documentation by Abel Daniel (abli@mai lbox.hu) for the Debian GNU/Linux distributions, but can be used by others. cadubi-1.3.3/extras/000077500000000000000000000000001303034105400142445ustar00rootroot00000000000000cadubi-1.3.3/extras/ansi_term_codes.txt000066400000000000000000000102671303034105400201510ustar00rootroot00000000000000ANSI TERMINAL CODES ------------------------------------------------------------------------ From the "Castle Perilous Manual" Original text Copyright (c) 1998 CircleWorld Converted to text & updated by Ian L. (1/23/00) ------------------------------------------------------------------------ ANSI is a standard for screen displays. Here is a listing of ANSI codes for color. Not available for game play, but is handy for coders. Wherever you see '#', that should be replaced by the appropriate number. The ESC char is usually hexidecimal 1B (ASCII 27, Octal 033) on most computers. To clarify this, in the example 'ESC[#B', to move the cursor down two lines you would print "\x1b[2B" in perl or in C. ESC code sequence Function ------------------------------------------------------------------------ >> Cursor Controls: ESC[#;#H or ESC[#;#f Moves cusor to line #, column # ESC[#A Moves cursor up # lines ESC[#B Moves cursor down # lines ESC[#C Moves cursor forward # spaces ESC[#D Moves cursor back # spaces ESC[#;#R Reports current cursor line & column ESC[s Saves cursor position for recall later ESC[u Return to saved cursor position ------------------------------------------------------------------------ >> Erase Functions: ESC[2J Clear screen and home cursor ESC[K Clear to end of line ------------------------------------------------------------------------ >> Set Graphics Rendition: ESC[#m Set single display attribute ESC[#;#;...;#m Set multiple display attributes where # is: 0 for normal display 1 for bold on 4 underline (mono only) 5 blink on 7 reverse video on 8 nondisplayed (invisible) 30 black foreground 31 red foreground 32 green foreground 33 yellow foreground 34 blue foreground 35 magenta foreground 36 cyan foreground 37 white foreground 40 black background 41 red background 42 green background 43 yellow background 44 blue background 45 magenta background 46 cyan background 47 white background ESC[=#;7h or.. ESC[=h or.. ESC[=0h or.. ESC[?7h Put screen in indicated mode where # is 0 for 40 x 25 black & white 1 for 40 x 25 color 2 for 80 x 25 b&w 3 for 80 x 25 color 4 for 320 x 200 color graphics 5 for 320 x 200 b & w graphics 6 for 640 x 200 b & w graphics 7 to wrap at end of line ESC[=#;7l or.. ESC[=l or.. ESC[=0l or.. ESC[?7l Resets mode # set with above command ------------------------------------------------------------------------ >> Keyboard Reassignments: ESC[#;#;...p or.. ESC["string"p or.. ESC[#;"string";#; Using: #;"string";#p The first ASCII code defines which code is to be changed. The remaining codes define what it is to be changed to. Example: Reassign the Q and q keys to the A and a keys (and vice versa). ESC[65;81p --> A becomes Q ESC[97;113p --> a becomes q ESC[81;65p --> Q becomes A ESC[113;97p --> q becomes a Example: Reassign the F10 key to a DIR command. ESC [0;68;"dir";13p The 0;68 is the extended ASCII code for the F10 key and 13 is the ASCII code for a carriage return. Other function key codes: F1=59 F2=60 F3=61 F4=62 F5=63 F6=64 F7=65 F8=66 F9=67 F10=68 ------------------------------------------------------------------------ Eat snacky smores! cadubi-1.3.3/help.txt000066400000000000000000000073101303034105400144300ustar00rootroot00000000000000oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo o cadubi Keys o Color Codes o o o o o ijkl Move o Key FG BG Bold All o o IJKL Move Quick o n / 0 X X XXX o o space Paint with Pen o w / 1 X   X XXX o o del Erase o r / 2 X   X XXX o o p Set Pen Character o g / 3 X   X XXX o o  g Toggle Pen Bold o y / 4 X   X XXX o o  v Toggle Pen Inverse o b / 5 X   X XXX o o  f Set Pen Foreground o m / 6 X   X XXX o o  b Set Pen Background o c / 7 X   X XXX o o  t Text Mode o k / 8 X   X XXX o o  W Toggle Pen Blink o o o ^r Read File In ooooooooooooooooooooooooooooooooooooooooooooooooo o ^o Write File Out o o o ^x Exit o Website: https://github.com/statico/cadubi o o ^w Refresh Screen o o o  ` Erase (also) o   o o o o o o o o o o oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo cadubi-1.3.3/logo.txt000066400000000000000000000016551303034105400144460ustar00rootroot00000000000000 cccc rrrr yyy g g bbb m  c r r y y g g b b m  c rrrr y y g g bbb m  c r r y y g g b b m  cccc r r yyy gggg bbb m cadubi-1.3.3/screenshots/000077500000000000000000000000001303034105400152765ustar00rootroot00000000000000cadubi-1.3.3/screenshots/catfile.png000066400000000000000000000400071303034105400174140ustar00rootroot00000000000000PNG  IHDRj8.H pHYs !dtIME"JaS IDATxyXWO-@ ( WNL8ɨ4qI:ļ8a%q̈q8Q  hPAhqą}ŲjyxxnuoW֡>ڐ vr.a7 9WNa[ b/x`_u`Y̛KKTWW?,h,CM`>L&enݨ1w9Hvn9}jkg}ŮT*ǩ5yMI|nڹ}_lٻ1lǿwy$ g88`|ѽ"TD34EQPSc k(2(il{z-36nɻMzO^:6ww7͖=G{tm\7<|Z+qeqpn/w{m#U*m?k]''EQX];X"Τ.x"1eyl6 ƂZɨV;tP[[[ZVZV^V[[[RfӨd7M>C u.p&Wg'uUr+mYĹ'髮/xز~?w=zK|J;-t%gRiko3nm.~sׁFqgW#~s%3Og(ƫy~!FC%iꚚl[Vk P@X<4ͼsծ!9OLҿc`o|ֿK bYvu:dw 2Nw_b_pߡ=C>=_{[&쵗fa, ~7fPOP[S3/bn'N;5fd2WxX-l6.:Yr0Mf3فLp<Ѯ#q&̙6MS*qVu1H(me?%jfcZ!'bwpf'٫kǿ/Q;:Uq^>^.`4/nϽn5jLFg -9^L2BNEQ.|hK_z܋o/}i,j&5[[IѴ< /,/.2!!tUc'ѥ0 w?da' `>**+jk2usj''jkM&SEyEyEymmmyE"7팛7Y3:ҴkVpb6voYe+y5*7ӷKѼ/4^ "ۗyPSS[2Mw'rukJ(.k[7k6m;G-ox7 uyάR]L&d2M555&\֢{4Կh)>_ߌ bQ7x(Jg6I_(aU juV *3XlAV@!A{y7}_9ڸ ӂtB1/}!oO>|! {<Ө.-.8fіpl6۽nINKJJrsR6 11eY;wҶVMfƏb AX{WA{t rPtVaz^322f͚E~m0SNN9޿777KjuIv###cbbF0̈#7&&sE,KzI L>}ѢE999HB~^ra5k-du]^cǎ 8ǧeY!{Ua$Ma!lݺhƌ]sx!'55d2Ɛe˖iگJy^|p„ N:v옿?u:]EEqEdEHү_?[XX1lذOOOҵ)...((y>222**jΝ#G(800pҤI8N\$-qYYYwuqq(bʛBU^N>m2_R"}]ggg$Mלiڤ [y 4hҥǹm}xWYeM6pEr{_xCڵ#"&$0r]4M&ݻ_$i?? .ԩS׮]{ UٳNcYV^#I%g߿E뛐YQQ |}}ݻG:{n۶?,'. "=A9QGNN8+އk5Emڴ͍8Vo޼9!!ԩS-g& @Նy&wѣGG Zl&L.]]Foٲ_lݺ9|pttʕ+aŊ{^f qI+,jɒ%[l*--?~k׮ݵkWAAAii)l۶-!!!==DEEgݺuhq4OAA$kQFwwC<|r<BJxܾ}{ܸq$„2 #$H!4CL&!|sL_R@߾}FufYJR$^'C$,&9q%YQ%L+Re2|M(隭 I;Pq{3FZ{}[|KK.2ɮȃ † VLN#B4d IZd%%*"m$XSw%o Hۖ+왠!B{㙜cH-"5  {<1ѐΝ;?;>f̘9s_̙3w@@ۇ %LR ٣W]~ 2W^>}-[ &O0Lfff>}| Hh vVB0 4b{4-t\]]kjjXvZϞ=333N{ҥ={J,͛wƍӧOJ0z{*{,Xҭ̟?F[1DLUUUJJSxxxMMͩSZ HA . 7yyy䈂Ejiii%*++۴iS\\m |$%%1Ç;rHdd$67{u+r"ۃisV(Z A AZPvR_Wq4{l:w+PU߷i}79j>E޼l޼966_~ٸqرcQ ݚCfddOSL(J*QXU|/o222rss_x!¬Y6n܈iq0a„Pl6-[6o޼7o&'':tHz~(bs/,,l$Bxxxaa! AHԩd"D֭[ݺuk۶Pp‰'N2E  Y4FҥK znݺEt4&LPTo~}AZda5kl۶it"WĈ:toM&FYxlްaU*՟g㸏?8>>~""~E!"J1jx ,Ve! [O*S΄ġE (Z$HrEM } @ h>W Uw)44&SRRΝ;.رcWiuT Y-lo'x'N%''3 u֓'O;w.888333jZM>|;sue rѼ<IdaUj ̞=[XJV9sf~eee۶m#Ca4sMc裏jjjqXܹScDHㅄ,[,**>~ʔ)*tE%7o3 C <2@ɲ{|}}3{ly_.ydzzzΝő۷oO?`IJO~yQk׊O埼 ###CCCZQ$ I/}(Иjzȑ/ߥ6ljfYjEmڴ͍8Vq\TTT>}֭['9nݚyq=zܽiŻiiik׮̙3g֗3;v;w.EQZ}ԩk׮5LdD  Mw޿o]G5/MyUXܶuh^qA"~Nk-QLj}>P4/ʒܴ& v ^"Nb#A4xD?/cقҶ ESC,?0N81a;hM1޷Hh~^1L^b#z G3͋Vo߾*jڴik׮%2d,{nLdJD?/hQ+ּx{LNvS }R)ISM7)_|Tn*E#t= |LN,!eو7&$$h4PP՘ȶg 󒚚Ű0⬤uk^ץ?Y;b6m&i' =d6Mqּ麓'(Y[[j^;OS4<93qB(EQh ( S<_G13t5/[H;4,-K}֪yķ:񕅕P:3!NjKb"c#A4<󡬤p($ qEBtttrrrFFƬY(RNi5/#)# G7bgDa13׼Hh4 øݸqa*77GYnG}R\\\mXe͋-#"΢hXحy:tŋcbb܄Gk^r1yPUUe65 Y\nӦ :thFFO?4efΜpB=<ĵ4=rڈyk'}v7/G1"wGzI#V|mHz/MߜiL~qlűcSYYI#-E"H3Y9E֭[f̘!s}UÇw_β  t <==>}E N۾} a4/B^ˊA/+ĵ4þ86bGlHP9k(WϨBd^}hYٕF4wE3mNs QJ}fee׉eh4/#G4/o֞={$2{IIIAAA  nԩSǎqIDATV***lԼ؞*4hҥKIZ*ٳg Bb '"I&wnK*h^Ão} *g ϙ[{/;*.&PU.$1j7hƒLƕ;_,p0qm܍su jժ]vX昚415/b:󼻻9S!&&fҥf͚m۶4fbm>rJ899.ذ #'EnRO|Ie'[ܼUN+M8I Ȑ(f5/i&\R"Z_`d2Y,qU Լ(+@b9(h3S4M@b;(EӚ>5y̦'A'Oy>͋w|͋kUѼ(lKx',rհʚHҧ3LAqL?/U$tܸqgϞ=w܇~ƍyyyҶn?/TAׯ+W5A:,GC4|<]?/ʑi_1(XVE^Ay7XGˣ8=ùyŁA [pL͋aÆ_xqĈrrZZA d8EBBBB>}H^7J"Uh~^U(5/_~!ksBD H^H/_tСCOfF* 5/- Լ4#F=ݢBDH$U4hP+**ؑA͋>P$i%,[lɒ%cǎqƂ *D$t?/$Uvݻ'ؑA͋ڵkcǎ߿@@- 9- U-*t޽xWPr/yi@Z aaaiii}iZQ&e#F?~"bh4EEED>|={ϟ??jd5/E)WĪI~ʕCWPԼP~^"TyUif77A͋} H3?-\ A ^Eܔc'd]!mmY$iveeQb隭 Feeex {sr, l_mBbboQ H[Rî,`5 nE2j^sbeJNsإ(H yt:#""Ғ#""䢏lEH>D>SJ*(((111555..aI}zŘҏE;g4]3$[{7D.Em4(222&&fԨQ  Ν;S,%ID999r)VCbJX$&Y *cSYY)_c+v"if.Ȗ A{x!GP(K!bQ@> Æ KHH$]₂###v9rH8EVCbJ zuiDfeeYlUsJf+.m9ǑСUv!BDM=z45ݻ+Wd|dTuʕ t!...!!l6Ei%>D5'8 :tVuvvԗ7n޼Itڵ8ˋd9 -"bs{A+C`ѢE6mrss8N~7oNHH8uԢEEjCCCɼF~~~};ydiiѣ}aVK<.]8;;_v߲eFٺu+9r+Wg+$i Ê+zf5$W088XՒ%KlUZZ:~xI}׮]k׮Rضm[BBBzz:1f9**O>֭#E. y 2 Hdd$)]Վ5J:tyww˗ND%fo߾=nܸ :sثkh4^~Ns3~D$i>D$IA\AIVpTAR_!($Cn/0k$lQ""4njhisk^(pIubelW+}[MrYP#!#5&+<$iCg7{ \ Ahg1c :aoq|3 իWOe˖aÆ5 yVVV߾}Ϟ)O  vM8&SzdO ܰ(@/!z l2~/r$pê{ ]ج~„ ϯVFE&UUU)))NNN555N 79n9jj!bGF%$'''**,BC/!b/|p‰'N2E(,I |;w% wUyDS_D{Bʣm۶b/!m۶{ B aaaH oi bt+b7wȑǏKB`I#F=YfͶmh&޽;77$$ڮ]+Wl޼yԩB{&yh &bdVEA$0e^By>[x&i1nA95%A}A/!ǠFH?9ʿzGYOkIvֆr^~$.EԼ }yh4U cpU7Zg=)̇+4+` p %Ѯ G<ww(-6m a`(*wA=2xr@;4, OL ,,+TFR(u_5F:w,N]%X Pi>dKj۷Q^+WQ|UPQ] 7|]Ed=2ʻ F迻a Ta K)֤Bw?8xLȄ^py8ߴ͇c`ͻJ܆7O#2xrt_$:v dOJަj d##はA5/MA|rĚ }&X!ּ4*DbFJEȨyAZAh^Nm4%%p27.r6@WED>cݠ)F&gWL4/BEZIbXlE9SҼR9ȨyAZIbv}V͋UT5/ʠis+c [U-ʑźa=2AZ.c +2"۪jQ4/XGUrdԼ f>P(GF </-e/(rAZ8JA4yAp4xyiJ?/yA?/sm>~^( 2O]~^XL`]áر]뭄qKyʳѼ}A!}T3ڕOʾhyLj h>i AbiW4Ḳ]vS-f4/)*XYV(D,cGb(vo2(soy(Wp {幡/O\Ƃx n@6@hSҼdt=Vlԓ2A0(ⵠoA0H Hhyx'ZS$cw5/H+}H4/vZ5/ vnkWyAŮznywXڕ~^}Zb |Gh.^=DƢDb.Ph:݊c"7 j: u'<G_ "8钒ܔc$&&ݖ;wҴMhڴi=ǯX ڛNcƖkW$1k,8@b{رTVV,+C6rssCBB|}}^0隹 [:,[͘1C9&h4,[L~W'&L8uԱc***8(8N_~d0""bذa kS\\\PP|dddTTΝ;GIQTqqqqqq``I}d2񿤾YYYEEEEEE[5;;ݻEI9 jIIIAAA\O4hҥK) _!OPHfeemڴ̙3|8::zʕ IZbŊ޽{Y8y$ gdɒ-[DEE?^RߵkڵmۖN̥lӧϺuH h 3IJjF(y}]ZG9Fo7n\EEI_al4MǑ LӴÇ93LB>I+%зo_xur;IΡ,q4Iz2D"ynsWPEQB(EQ&Iȇ ܄BiH 3I+ 8+8x1c4 7iMAF!d-oÇ*Ri"cƌaE]}۫W>}-[ byzvV$&AGK 233MWWךe]ֳg̩S^tgϞ.͛wƍӧOCqAZvVϟ_SS#֭FAN"*%%)<isVhČ𴴴c"sd>$}9rؠ@VE"Da8 s eQ ! At5/8ZA} @ h>A A4@ h>A A4@ A| A4@A A| A4 h>A #b "֣@!,_mKUK RJ89%1Ms44@ h>A A4oe@ +_Ap ^ 8xA/8xAi ^p)  h>A A| @ h>iSA/cK4 [ AO> dh[Zh>RZ\Drr9b6Ni0h>A HsX`L} bE%G_*D  o ۷ KB| ;pf< V(h>i h>i (C1/}g+G۷{۸ | {y7}_9ڸ ӂti M 3& AU%f ʩ&9AJSݪA&ɫAT.igIENDB`cadubi-1.3.3/screenshots/edit.png000066400000000000000000000271531303034105400167410ustar00rootroot00000000000000PNG  IHDRj8.H pHYs !dtIME"a} IDATxyxE! @H9EA±,+Ȫ"(f]uvc $bFX!+5&COLLH0tMWוw0/ m\n!$P#UUUUK\ $KV#\UQ:g֠ Ifs%%充E+ҎFD5|'k779}oWxe7sҴ9͸ї|Fb9͚"XGE ̞6C=ϞA򡪒_z5eju΂**0y|eEK>3?m(  2M;vu9<ҮS+dMq "UUѮ+([;yY3~1xi b?7~re8EQuB=a) -$I%%ʊJaZ#Irbr,˲E;nME;>6:[ڼ#ڣKRTdV''F7X?%>׌gёXŮc`nAA?܀UNI&ߗ-y9٠P.컄h!i<}Vit؃c[l¢¢"VP׬ɱ`>m{SWg?7eƂА z( :f_yk/Ll?᛭FFǸ!۶d`-mbgim cr$"2"&&&<,,88Vil"A*/|i]:mCeҺeOL(JZƦ]Z$tt8_lHoٶK [K74n*WRs/[&v)pFǷԡv cEG>[6rgs~S@[Ad{O!u>9K `nQYYi^k_ +aW?;z49rfUvT*++I#'G=0|gv$I-c{jC_Y2C6n`˦ ~ג,//_h+;JJK*+<}$8$DU[pl g <-d9h,4$4y+J+wTUǷ74jޡTR;u 4>9Rѯ}TTUWVT*‚NGeT4lw[Nw. K^љ2@j0&6>cxGtTQqF͌1j%sA4?8s&i@UnUVV*b;BBB򃂃򥶍bZՅ&pmd s(+gh7pWHsY>TUWܠ*Π0t8NGEEa%,wE:۟ ++Nۊ !D/'/$Lt5ϋHXAkP}.R8"lBHHqqqlBHuM@qQּom؈Qm&Y}&>A~s7%H|DGv:b͋7(Zi̗GF!.4(?(h8ժ#'jbMkc-dgRXKձL+K &PԪtyj]\&@/؀L  H"* n\ϞxQQ(,ĉ 99#*rG\h} 42_A8` dV`[.K-*p na&?nxQ﵏()(p8 fD#". e>[< K+x )DP+R+^y>*!)`(rkYHˍT?V(TӠ%(iF! G0ha Jޙ 4iR$-M^݁Uk著h1̃^فC06|fiYQ;6h-XE\:G_,$۫2 B2 z,. ayѦ\>8`:F}pQyЌXA`k62!I?AmD&5ǭlAƼPskKE4ȘG&r{Aeu?yLdsLȵ[wş I5R yW9,x^eYZcRcZ%m|AK((޽ɹȇD@cY!4Țe wkȚ%8 D)~X«%Z#גgR>"B(^m,EwGUϋ|}Cyn_WyZF#B|%F /}dB(nԮ&yA"sBjK>*B&rG RG>/了 !:R |\prC}^ !6>/G>/y?2y!7ϋ ڇʇP>B&RG ?tf 5}^u  B(uB8y!ՄʇzK&$d@wR zVxLl0 "?(fh6 PXiLN^ܺUd0 (@]t-y^ (wKHCZ:cBH߈MT Ґ=".N F%gjW a떀[> x^ z1jl,E(?(y!}{^2}@ol,A6AQ |)!BB P>!A5e|R3Bu.5҇~[OϷf#{c4.gk>b{?a0k@~l>AϷf#{"^aMVk(?@y4%cr {Cޝ,EkC7tz=שbRq="lu՞Kk\׎w˷yyQ!$aE}eHÑ.-hх鱒#~*vʒ/ (CYq͍.~U>oX1K/PH=vEgb;zO(tsc1/˽QW)tHm>K/:U{)SV -CPѫu- s[;Jmzobθ7J_ !)m-_B|h(`ݮ@Q!IPU Rj"]pp# ӕor\Ќ{RCW*V,sUQB)TK+rZZZ֍,;jh$IHhd=tQPϗ(ƌ.ό =GT~{Di0LZCQ1}hh߾).[7!$ʗcpp( mK5 uHt3>C l˱*ƒ%WGhbKސ3v1SJ)p.pD3rwt^U#:sgX#b̪lI^hdIHQesV(^XQ,F@[G-r1t/ jńڊX_ !)-7͒pmX݇ج^>C.!BB !A|B(!P>!BK'n|pY&?3}jyO9rdǒϟ?d;vL?kڷyǺgfϦMc)@>&LXVb>;1άY}M:͓{wON~_̟1`~͘+o+.Q# ~/%eNG׮-229x wzɟ}PddܱcҮ]x$Io%؃*Iڵ32l4֘믧Gi'=#q<,EGn2>>>zݺQ_=n˖͵͙oӦs<֭6o;qb7I+曃\=saNS`<;ib-#\-)B 2!P߇u̾,m>c?oXd%dfФ&֍JOC9HdGLzڗqu֢YҿX wڢi_;͛GjgN8{.]b##obՂI5jyXE3z{*'%5YvvV9(ȲmۄhUoT[Xhώ(=[Chɜ:wn޼y}[,bP(vB[  ,7,,o'Z,ojq'[<Бb5e}z2zkkc:TyBBC.ϟ/кuVCÇ/VV:@QTGڇ^۝JFc+*-[6T~~y~~EBBȑz*m̘fejjYʵ8[hLڧAUlpLRɟ7c{o3ϸCPQC.8JXUĠǿ2RwYoy}γwᇓǍM i[VIБixsʺS3gڵk|tQLL+xT6h/.5i(jaZglT\lpV߳~!CVʉ'իNt{DDЩS]X`ǶmUAZt2}3֍ڸ ۥX$IvgAA$yX!,Kϝ+cXH}2.]75Oh5'#F|hѰe͚CƳO䱛 5"@>X,r||TzA~l' m\7,͝({6n|xt}:ujѾV:Wc m))+$©n46'flLϏ̟?:}zƂC"#EMO?k[1.ڲeTxxТEUU/TмyAڵ\.ռy)ǣB>AUUBflLJ(ВYvC,|?%$D{QEQz*--].Z4L%WK 1$P23mzyyJm)I6fʲ$I$9kվ6o^PYEh,5kW(6&7OJ[WU|(+q*(c_"]Zȑ;TkPHcgdX;&↓XW :nF\k:0# Z!(jՔ^.<~wκu6bV)}䔱B%Z8 SQ ·mxժ?8DHځ:: \O>"T!>ȇQ#ZB5fdK,&+; +C@H ef{(jk h!PKTll ~??`Pq@eUx 0Pu,@5|N|t*F6medUA02^[[UA5\y=kn\B!-0]H @S`~lT)`l-@<`DuT[@`%p/`bS@4(e 9Az (9Z }),/-`~ <~m{Ò@u*;t"_ 4V<"ysE5GVd` @2(JP~`"PrKՔ!8=CcG9x#NNXT>Ν+xGvj~<4Z^n }h1Z`naCכpj=E6^[ 4'X`}r8Z##E}@(O;pBy{O1b l-6]@(^cO?}PW1Ks}p>Ç(X_{O_HYWpyx̛U>* ,d`nw*+H1D6^O`# 0XE^n5@ pӵiҁAU_Oi.`: xK5E",NF`{]-d{Ͻn z*a |+f;M\? I(^!_'5=/"t˵ŞWR(?cj)hM7ʏ|Q#i'?֫{j4{RRRWbtDV Yk0#!"X$1u IDATV{ n<,X3|M d ěK,U!,4jnN yB0wπ@S@V  4 ݚ!cuM#SkwfZ!FfB-@0wd`VHpXB A=/#]ϋ36@9pӵ pe nh* xP|9D&аBF| SiB!yјG~ z3CDvHN  tԽm7 8uI fB+w[]]k!"G?*!#&$BPZհU%kcuvz^.Qa" /v "u4+,ab6 qqG(i?RvU{jJ*N^j;r{e |uJBB P>!B|B(!A|BB P>!BB(!A|BB P>!BB(!A|B(B P>!BB(!A|B(B P>!BB !A|B(B P>!BB !A|B(!P>!BB !A|B(!P>!BB P>!A|B(!A!BB P>!A|B(!A!BB P>!B|B(!A!BB P>!B|B(!A|BB P>!B|B(!aeB\>|#BHu|T!D0(T\8pRm(!A|B(B P>!?3|m~g(w'S>!>ȿuN^!B8y!pB '/ژSBH5|B(!A|BB P>!uJx?$!)}B̗m_Z&aeyY: k9eNtKjA>:uԿl6ۆ >QzVxŋe\Ξ=OdyvZdw*zv\/,Kǎ,tiӦ_Zfn:fff+Aciii;vFEJju֞={~WکS3g̙gΜ6lwݷo]vHWL}Rv駟ڵٳEٺuknメWN8UUgu%gϞo~shY} bHnݺz˖-YYYo={f͚6mxL޲e޴ijPPw=Pݬlppϵ>̙3GQ^z%%%3K.~]СCoFBBoa}Ǐ=:lذi~kP*A:vBӤY˘q7Ŷ9.>UBR|[ K\$%%s=1c4hݻ/\йsgM풒֯_o+++Gaۏ92lذCر… # I%%%={'&&:ڵܹsZ4UU;t蠕A`999/]4|D}Rӎm6PC ǎۼy={N*ʕ+^՚v.]DFFfggiVVٳ , d~^\};p8W~ߟp8"tˋUǮ(,,Ձ]8N}'4˼ݡZRjBB t٩STU-;wKjO>yA5?~5kڴisiZk6hX\;N\5 _`mTU ߹sQSRR6ln]i߾!ԗ7nܹs+**n&EQ;ּy cWf]fTō5Ҧ*Tsgst1kc&LPE ξkSL)))e9%%gyG6l3 & 8W^m,?yر ѮMbty˗/ݻwffпNӧSRR҂G}=DGG Ux8q1} DFF*Q͛Q>*nMZ:邱cgݺu;yO>)IRppٳ+tӧa~c,O<1p_򗯽 .^"ߟ V<\T$9RZZڽ{,ժ,$M%IRUbbjȪpBr+AW|Yk"BMu_ٳM6lؾ}{m~v?g.3OY(ΒeX0;u̗ت勭) wؑZRRj?+$%v`5X6U޲&7&pѣG92**"g]fY޵n>|cw;[G&\|%\0‰G׭y<ڰڴMdV0/FhN[%SSw[dFUSBjUi'T+K95VMCUjV4'IENDB`cadubi-1.3.3/screenshots/help.png000066400000000000000000000562421303034105400167450ustar00rootroot00000000000000PNG  IHDRj8.H pHYs !dtIME80 IDATx]iX>ݳ&DQ DP#7uh+ɍ1\/WD" ( DT\YD0/ t?* 2tuW}~/OlB kA@@P-eY`䥀hU# _`Gg3%e y}]\&{ښ='nYXšaF՟/^Ѡ"Y5iηk]qɣ5)}^7^7}۹853,KQ͎.bX*=q]mmMMMYiYMuk!+ M-s?Ը1mZ>fNfT*܉P;Q#۵07eY-}^_GMc{CƧr61(D9o(ac\fTaDh^Tc{iZm}>aBs=;?ugg=?׫icڷ]])w%*:Yk0fXCH%\m?Eo9߻yս`aN$%ɵ\=>ѹC`+w=_[.m޾ӎ3%W(N:zrilٱ[[/imPCaXƌY^Q___W[?s]{w+ \.aXB)-6+*UW@LP6h҄aYVN @4MUMeu5|B*dI} ~G#,\]]lv/I%qQ˶FA_erپ1;]A YZ.3 ^9}NPXAQc{=𿗾4^ XQ[kmOi"{2+prӿ{Dj|93~&fVzGnwd̓/^]ϽQX 52bYN.|Q ;U+.gN4-p݇txJ%e%[QU{ UF\:9t8t({ޗ7 hhd"eeu&B^oi2f_sQV_޼*,]3hVo5)"rϳGw**WP4,k6@}}R4Q0pwk ,dzad2QiiD*):ص5K PbA~Z?r#ܲ1>в1>z%$->X<̍gD"166 \2 1iӡy>碫~mfL EQR#S ⼰< XY8.H$ph 1"B4T6mU xA.'nވ;O8xoKU# ]PX!T8}p@10,`|7;:j'!"H xEtxkא$IdL :Y&\*Uxܯؑ$I$[\R]phڸ߽}CE0?{!3XDQX$IdKv.v[׎%s5rsR($I$[lC+{gl[gǍʱl(FK$I-2>=- {oV,f݇B!'>ȺײCCK6%%h >ჀcF>^ =YUsg3JIGY3iRBQў+W>N0w[[_oq\3a€mm7mFZxW:wԥ[/mr^Y4G0ʼڣG{^%8`@']L4J˽ ԹewAshk+ӆ @źw7_ƏDuuإ˼~̥}׮=;%K'ppؔv 7VOO+n?AL$22 "|xK## رnZmHM5OϚy;)W;;8a_ #S(㭷~3FDQ[Μ57 veCyy\\2KJNI[w@۶3{&m~c`GֽoWff͛a i:gЬC9rW_XІϜyTU4cFl^яiݻ1x萳gOߺ&xOccfؘ6cㅅ3{J_ a65}V]uV WR^2k<˝>bμsgݩSEaHaحܜ8Yu]oߖ3LE]xw2_Z‚pF&{\UO+b1BpH2,22z/wㅅ=W bJkjj tq;_8t!C,^=~q$-51yJem} ʣ*gF-c ߠf>кjuϞyV͛bqLhР{֢Epm[ے ;SSkejʰ *nk{Ni%Tds'ɓ2aPgץK+ 1?PYy~Dq"afe)ġ C :/ġ}S$C >JN{LP ^H Ⴠ>ԔiHW$mXk.D" b1斔 ###XŇjkk,X H6lPPPe lh\䬽{QMixHԦM'N4Mٌ R՘C...IIIʷ ,OJ*>|ՕoJƞ*00c oٳI֭[^^^yyy B.+*))8p]\\h1&hblrڵ{6X,3f  ƍlْ޺ukEn߾1ebII ]'qq//H)oxt sƤ{Ewy'))g͚"˘yرc/_tܹSR5sE4meewԞ={F~W&&&}BhӦ J^i,m~}P(뗞.>|Mb,HMq#GksFcƌrrrŘ)E[G}Oulh˗/{yyQ"իW̙ӫWŋksq=zQaVZ0zUV4}?;vl֭!!!#Gׯ_OBDӦMkժzW~;v,EQƍ;~x#&ׯi!۷oONN&*%&&8p}:b7sʕs̱<<<Ξ={ܹR-^eqKرc>|@̙3[୷޺~zMM1EQeeeeee'O/}}}WZb KKKICC u={dMMͅ 8}KP,0 2`-{^^^666iiiaaa)HXNWWǏ5/suuҥǝiR$%Ʉ 窪,,,aaa(ܽ{߶GG8矛ݹs'??͚5#F1c |;TPTWW/Zh˖-ؕT(vZhqqqq# ^r_~+6̢nKc*H&*mذa)g}4"(\\\8_8q";;8,,,!!!---((H`.6lذsN7n܈vo֭cYvɒ%?907o&Q6-**ڿڵk-[]ɭ[^x+MLLhff0Lcnܸpɒ%6mڽ{۷˵ 6m啕2 3~o7 u^H [(~znr97]*P ,yΛ 圂&S'0"ܹs#FxycZ*2v{xڵk׮]K招7o0\m@A@@мO:U]]x.?ydyy⼈☘YfKRuDsRaÆƬw?uT||rvRɞВcĉk֬.QSSS Ih[˧LcTjoo'/"… ~iXXD"qrr&C3l2rH_&)ѣG?|gڼy˗hF TNq߻wޣ(EK:,Yd׮]w?2L̞=[DW#~c0;v`oI6n8}t]¡C:tйsknܸQo-m׮ڵkۦکS5k֬_~߾}:txW^7ߴ s MqILᑗ:gt8555..wpEѡ,/ fnnW9/O>Uݻw_jUbb/WTTÖmҥ bsr+Ǝkff|}Z4|weeeoV/^055ݲeuܹ111~~~&&&MW/fY8"‡9/:uccc+ Ϟ=;l0FqVZ*WZXXAQrѡm۶.]ׯ[ou]=J{{{__͛7GGG^̲@Ll|ٟ| >~x4Mk?}tJJʲe˰1c|||ZZ͛7]]]ϟ;vbQRiǎSRRf,F3:Sh^㲱 ĈJP\\ܣG+WD"333HdddTXX(80fXݻwȑbcǎG,\t)00iEQܚ.W^(:{Κ5СCbo +Yn$vF\Yu(v5T^#Go^]/Lz3uL??^DRTT4o<QcrϹK6hРec y ZbEttt||<0rĄ(oos:;;SI0I̲H$˂`Wd2Dwۜٿ??*kkk =eFDe_ Pj(g4~~~G2eJllluuޮ=ҡe33jje-!)rm^\reqqq 4M?z}~ѢEcǎd$555?Sff&˲e$=Ø)}T~0c͛7GFFz{{~l… JUءFPP֭[[n=iҤS>y>駟s2|GPăiSSӧO2 "@鼄;;;FDD,[__f͚]" 4P\\˖- _bEyyĉ$΂eGGG:u\vO>~~~FLHH@%iet32w1Ů:t`ll2yyyK7|pf,]4,,f޽G[ذa֭[#""222t>e٪*;;;X,l iRPPУGq@! rNDˆ* NEUE,##`*@/+L .85)ʿ9/BKdkhB΋M3 CB{re1)uvTA#jWPYKx\ a !/ 6Uy! 0#rss.`NP+???55555599X^mW-$8/hq ߾}ϟ?~ZYJR~vvSu1~T$73;Kvvб#PH$ЧCN%{{xm(Jo_2xi05Y0fqqȑ#-izԨQ O5t@MӧOGy+Ww IDATs玵uJJJ\\p-inbmo,i nkpoSSuiprpv۷3pt+Y\'[Hhk+ӆ Ƙ s玹9i&<<ҒWj#77СC ̼vZ@@}BBBfϞ=s̺;w:9957ʿ_rUy?^ :=ˏ={gYvyR?|^[{ [Or@g$l ɂT*|<>V\]1888$$۷.ȲGO0 bL[(TzAX:s̏?胚XE}QKʿ*;k_|W_}iӦm۶iӒk/^8Z\;Q/WiM mGB!l!Aa qh(* 2m/60 FfӴ4hPчeԩ 9s6R_G.=lv9}{33w*p:3-\ 28;ÃB>yƦMv}rPlݺ5,,,!!!---((HMS!QoĦy s^"""`Ĉ¦6oΝj?o_ #Gn=sZ&p!_}{()O05J QIwFXeAC(9œXo҅|<*%+%hmn(΋0DDIq0_AVX4b)ʃlkA@@@`cȑYYY)))*J._1228uٳgt^y.^8k,5M 84OTdjo:t]ZN))N]'xR@/v.#a$ 4J^?~GVVV*_Y>&6fccMϟ?_,GE@_ ! ˲W0?LLL\Xw b zvo2`z7f7f Jڀ JGt^ׯ۷/''gڴiGYի˲Ϟ=cYPPrWƍ۷o\.A_`r3~O:-)))555..N$a 2X0S:}w/]tA ujBajjZ %Xojҗ>cv:Q`'+l)4|Q 8vح[PPJJ.˯(At?3&72 D"k)`BG9Szs#G׺u/^kyx3j`^G UEhJfiֿۋb) 扦yidQ>=~x''`4e5 Zʯ(?E%̘ ʠ`mVI2斓SSSŅ9/~mRRݻ57e.@ @@^s{]ͯ[nTJK:\r!W2d!E_SIIIYY(e\+'N:ujhhD"A~fr38 |F =ye;;v}:1u+ɞ?=/pG"ڛvG}dmҙe0 ]j}r G Y-"|" (uֹY[[w (e\04H~e۶m)))>>>Qk#|ӵQ(6+Q]gaGEE=\,ZZZ^Zs;6l_xo{綞W˯F\ax; W}l-!|`G5X\)eF3c\d(`mΨ`*J م v 9/ մzzm> "0y"@k-?-Le]ګ4qFss`K e:  Dp̙!C}5^> 4𑘘\QQ!@{Q  uLAe322.\hP07BG}$˵S =#eʔn;v|(ΟS>! `0'" > h2fC +))AAe:۷ 4C˸4BQKJZ  ·zqw]ߦv@[iZ}4%r^ tգG$2seggO:(%.Q~^ ?xFbx#G Џ?x4Mdee̜9*W)`arؾ9/,._~rqΖǎV8 0dˀ8/|<:>>wޭ[zH$˜ b`U2A{.*5kcooxP?C$M2믿V"Ur^LMMHDEE0o4T8e_k($QQ͛׏)eeE,,ۏe)d3yf[`z555EaeMi}ye *kcc5ˉ pOW_)UyY`]Й;bb@!tuJp^S ^EHL5 ĶVɶzH2Bʦ _f#f̘H>^g-{bƛ3L8/?|4 ҥKO<C9}"??8/g\Sq0j3$`oiaSFI63~%٦s؈h05g l `fDеgOks#zP>akdŠiXh8煦QFi\n>`zς?9ٽ(]m߯jfc&fyQmL[Yg=bjk.fQP‡^9/}YPPT*R4 43Ϝ9sѢE4M[YYdddN6k|iuq^w™0r;Ÿ)Y6ur-o^Oj^;6&⛏jYV(R0zؠ>%KT1p HL;} dffb25ZTTԳgO u:/'Nx"*j$g_8L^\_CŒ}E'̣hA%ޡTPdr^\]]'O_bG Ey&ˌŋWXaaaCC_^__:/ÇGcǎkn;PpM 31G圈ls33;w(^IDs©( IYYQTQ9¨)NPXʕ+ ,pttKHH27"ktTU}^&4z gsOwG}'ݫFt7Ә3O꙾ͯݩHm!CoBCC׭[5LҥKG⒘8j(v wvv655Pμa*+VtmʗE~\njjtRxo  [譲+ELa*RưW_L`k.HapN jA) .?X,FS (Qצ1Ct k΋a.m,L\ݼW8E]-|vh+999\,ZIJH h`3* UZ >h^`|tȑYYYuE/ݒo4i΋]rr3gϟ)hCJI%{OevHER{tZ +  ` N|WV F/0Q>?~GVVV*;Y*g/݂`S4Feqqqaaa42YBDž՟KlQ7w+=~{^8xlw^}};%&&Xl^X}˲$..5))I]ߤ-Dm-8O29/Xnw}02a$::ԩS垞s nCYEw}'\ڹsgBBBVVCQ|e8/(,,Lc36lzk:qDF 7lZ^1%C-C1@Wd q^4r@Tit t oY,c~fA2yjW œeh1Rg bVf4 ͯ0,9/9 kJ$1&v3%̗ћ( rœT!xWA@`XAJ7B@@_aD󒑑pBeMC漜i4*eܹbb]iopL H)=,rwwV0P(5kxzz1bƌE`Hω'*yyZhѢI&M:B%Ʉ (Br3kkk>Nbcc+΋:*m۶[駟hTboͥzl|1:zN5hp`LWQ>9/fff àblٲ+VO8Ś/ĉr3|&;#J s^Rȑ#.]J neDDtxYO6ںH]=E,-{{Rar9@* H$fy+*yQw ul#4G΋pEœ R/A8/$| L#My! hღӧWHLLLNN!@;w.EQ6lWgJg=qDEǏ?Ξ= ?hҤIaaah*:++Ko,O6M I‡0ʕ+̀3^^^_p޽{(,8^ϟc˚5k>#F,^ִСC:tܹڵkU~tbWdK z=z(V0ҵkףGJ$M6 lر/_%]U8UrGq^7??_c3X]|۝;kwՋYfF R~yAuVbHHHBBÇߺuCIII| ]"xi;*2x7o޺uO>H$yѴ^MW/fY8 S$jꙦhx+ ZugϞ &ٳV3g|n݂'O>E.y1b`CCǎkffW/yo&M4hРUVi3;wnLL۠)tbo@"‡˦M6mc/aaa V0E7U(&L8try133{iiiD">}}}ѣ@u6uk.f}-pxѺq]I/r .!]vӧSRR-[6nܸ;wAƊD"ΔJ>49|vv6r.]:rȽ{b1VPtqlllڵkСՍ.'Lpܹs-X@c<""b4M8KՋYHq^t-t^oС MÔiz1j^Yr^kA:/g,|SAVA@@@ 8]鼬];P  -%t% *׻k.o%Z&ņ ^N+**D"Щ3vt̘1>zSIIW^^#QpΞ=[[I!x{zܺu9//=q^0 %ƢQ{NJJ(&!hc`G2 d٤ݼy{۷pUV=zժU4M/[lΜ9{( KbeCBBF矯_^YMLLLOO2K$ݻwhܹ7֭['E"4 IΟ??c k$ SQDEi(Afҥ'ODLX! _غu f=11bʕZ%7nW ̃C< ^ztdÔkthK.AAAo BԕC 4(33sX~a [ZZRةSs皛۷/$$dwAZ-G޽{oݺť[ndv HaYV,gff[N믿(On߾}ppCbqNNNhhʕ+޽TbY633믿FTZL(gr 7+| -1:ǟ:u*>>^;c[E@@‡8/ʙ_xadde*B(0K,ٵkݻ*7@V dAD{q-ʙ1'''__BѣH i#±]05ixxxH a:/Xf%J~*Hp`ek~y\n`HӢ]\)=^㓟oddw/MӜ}||ɓ'[N*'OLNNF|6͹RT'NvZssӧO;w]]X~:{ (|4H煦QF >ӳVP3YfףUVq Nj:cvTL#G_6~A4+V̡k֬A땕ouaaa2 X|{d畷m:?۷ϛ7ڵkF:tGOQqc7K׮]=*H|||6mڤL2 p^HD [ϟ;[ZzXY9[Z}>K쳞9quNQ}f̚߷/EQf]P~򉫕UҌ3ghf llԵ388ҥKdd^^ޞ={._-~;AܒRSSD"ÇSRR>qFT;>`߾}r ;#/9rI q ]I*kú&}{n? IHH0552$''GGG/3Sm! r'vrrCϞ3u4ݱU|r뫯z:88_]@D.VVbXM|񅘦mKE"MN7vldAAA^ E"P,Y\\ܣGW8"‘#Gڷoo$wH$222Bb8rH~Zn Xw^WWYf:t(11wޭ[z*`̘1bX"`m,cTKJJܹceeu%T;4@SyFǏӧ}UUX,mU=Vp *Zv6BgϞ+V*fh'?3qSa&Zه;|ypvu EOUC2Қe?}ZP@PBŠ!C,^/,dYVaaYёo )p߻a|DD=BeeeoF{ܹ` 77'O@fff۴iÑf`E{oYc.O( u.rHYok5xA #1'q6moݺEcft3` a,+g5WU?y&%sv8tp66S(Ç ~}IB7Ç3Dl˦PLA_e4Mؠy OOO ڶmG/ӄ-Z4iҤSr<oر5Tffdd[iښOocƌ\XXAQʯ2mĉh#J̰3Blll)TVVjΎe[[[s@>UV+VrJXXɓ VӦM0`? 似FvaBءeepϲ2x1̥Re]1th7{ii ˆlaa*D\l"rL1+*^zԬY嵵QQK~73e/,Ԧ|B'׬Yӵk׍7rAOLLT(:t066A7> MpA1QQQEEEϟ?k׮oԨQ{H[*IU6- MQwm͈Յ6;@(oC & ?YPP* pA+ؽ{wLv tK˲>4M0TP(.\еkWeC!hk&oJI 74Q6.]3&SH@;w΅_U/K 5Wňd=)HKb a=߸qypp0*F}$"EbF*g@4j! :ur'B|̙!C2YN@@@>yAj,ϟ1cJܹsӹ%}CxQȑ#Њ5@{4y/&LpA4S _pN@@kjj:}]%~Ǐ>J*zz`  ףXJxxxǎЛjxnжm[~?<###%%˲zbYٳg,bdኜɼ<@Jt^q^0q^NJ޽{G);v숸sɅO72={E,#j0`ǎuҗ𓅅\EoC x.c`E"СCccc14^st,sPPЊ+,,,A}pܹ;99%''8p##W%25D@szܼy3 5?F 3gff:::%$$mۖ!""#$&&RWΝ; .+zB7 Pa3gβeBBBz+1qݻ;99FDDh|׭[fmmw1 U5վsp^D4b49H Ⴠo9QW ^~eN ۷JI߀B߽ .X[[MnjP1~s)+//O{S={/rއ^),˦)S|ԩSb#([vXZQ~5}*ѣGӧOgF,gff[}Tb8'''44t̙hfY6888$$۷ƂBΝo޼G||Ç9SX0˫V ())III9xB(//oժ!;pJáH`:/#||1 ՂqO-me>0˘g͐J8/ CP.7[hѢcd2Drʂ 8VFLAAA]l )++ST3ܹõٳgTy!_0H$<}wvvX-e֭˝Cyzz2 ,+ p5~3d ~`@829~$/y)LűӦML: L?oH ჀC mm#{dT5oC >E w1My&6۰Cz5b\-w$.Cb.41Q!1Qb֘% }QX1ل/.e ˲,T,,W ?aZjj~ӧgن(v]*qH$6oL5fsKKK]]Ғ( {r~q:0 qfyqqvxL?쬺lFxRѳ tM2c7O&  OǦ&F"6;4~6qեN^'8q" p8~U AK._~dd$uJ$1t  ={ܿΝSI]޺u`H$ =~Loذ!ecŒò(SK=3 ClƊ )>~[gr<ٟ {2XNɺu¶mngf~~^qWQQcǎ)TtrH$S\\r555nݪTo*' ɤH^K),,ߴi4l-[twwD"a0ԍ{V7͝bYvzz:"tvvz<][ oGz4A};sL cYv?zhlll~~aڑ)TA0L~{.j*6tرݻw 9rD3!ݾ}; VWW  8O:U[[n޼rcE^X,v-+**l65l}}:D7ȏ)oV2އ|%0{镎%(D~~>˲ VxgYaEo<ϗ޽{wƍO"N7)h>RՔà DQW1ƴ%-zQBlbּcck^__Ś+Y5/|z200:™|/0ūPuyϿ+/ܙ6ٳ[~qW1;jvfrp/;Vn`@:g+6HGjϱCp:TꚞV*S* MzBO+SkCwHIENDB`