189:2
  H   l4(Xqţ-:_ub&=LV[(am_J2R PLiۍLZ7 4    package Test::LongString;

use strict;
use vars qw($VERSION @ISA @EXPORT $Max $Context $EOL $LCSS);

$VERSION = '0.15';

use Test::Builder;
my $Tester = new Test::Builder();

use Exporter;
@ISA    = ('Exporter');
@EXPORT = qw( is_string is_string_nows like_string unlike_string
    contains_string lacks_string );

# Maximum string length displayed in diagnostics
$Max = 50;

# Amount of context provided when starting displaying a string in the middle
$Context = 10;

# Boolean: should we show LCSS context ?
$LCSS = 1;

# Regular expression that decides what a end of line is
$EOL = "\n";

sub import {
    (undef, my %args) = @_;
    $Max = $args{max} if defined $args{max};
    $LCSS = $args{lcss} if defined $args{lcss};
    $EOL = $args{eol} if defined $args{eol};
    @_ = $_[0];
    goto &Exporter::import;
}

# _display($string, [$offset = 0])
# Formats a string for display. Begins at $offset minus $Context.
# This function ought to be configurable,  la od(1).

sub _display {
    my $s = shift;
    if (!defined $s) { return 'undef'; }
    if (length($s) > $Max) {
	my $offset = shift || 0;
	if (defined $Context) {
	    $offset -= $Context;
	    $offset < 0 and $offset = 0;
	}
	else {
	    $offset = 0;
	}
	$s = sprintf(qq("%.${Max}s"...), substr($s, $offset));
	$s = "...$s" if $offset;
    }
    else {
	$s = qq("$s");
    }
    $s =~ s/([\0-\037\200-\377])/sprintf('\x{%02x}',ord $1)/eg;
    return $s;
}

sub _common_prefix_length {
    my ($str1, $str2) = @_;
    my $diff = $str1 ^ $str2;
    my ($pre) = $diff =~ /^(\000*)/;
    return length $pre;
}

sub contains_string($$;$) {
    my ($str,$sub,$name) = @_;

    my $ok;
    if (!defined $str) {
        $Tester->ok($ok = 0, $name);
        $Tester->diag("String to look in is undef");
    } elsif (!defined $sub) {
        $Tester->ok($ok = 0, $name);
        $Tester->diag("String to look for is undef");
    } else {
        my $index = index($str, $sub);
        $ok = ($index >= 0) ? 1 : 0;
        $Tester->ok($ok, $name);
        if (!$ok) {
            my ($g, $e) = (_display($str), _display($sub));

            $Tester->diag(<<DIAG);
    searched: $g
  can't find: $e
DIAG

            if ($LCSS) {
                # if _lcss() returned the actual substring,
                # all we'd have to do is:
                # my $l = _display( _lcss($str, $sub) );

                my ($off, $len) = _lcss($str, $sub);
                my $l = _display( substr($str, $off, $len) );

                $Tester->diag(<<DIAG);
        LCSS: $l
DIAG
                # if there's room left, show some surrounding context
                if ($len < $Max) {
                    my $available = int( ($Max - $len) / 2 );
                    my $begin = ($off - ($available*2) > 0) ? $off - ($available*2) 
                    : ($off - $available > 0) ? $off - $available : 0;
                    my $c = _display( substr($str, $begin, $Max) );

                    $Tester->diag("LCSS context: $c");
                }
            }
        }
    }
    return $ok;
}

sub _lcss($$) {
    my ($S, $T) = (@_);
    my @L;
    my ($offset, $length) = (0,0);

    # prevent us from having to zero a $ix$j matrix
    no warnings 'uninitialized';

    # now the actual LCSS algorithm
    foreach my $i (0 .. length($S) ) {
        foreach my $j (0 .. length($T)) {
            if (substr($S, $i, 1) eq substr($T, $j, 1)) {
                if ($i == 0 or $j == 0) {
                    $L[$i][$j] = 1;
                }
                else {
                    $L[$i][$j] = $L[$i-1][$j-1] + 1;
                }
                if ($L[$i][$j] > $length) {
                    $length = $L[$i][$j];
                    $offset = $i - $length + 1;
                }
            }
        }
    }

    # if you want to display just the lcss:
    # return substr($S, $offset, $length);

    # but to display the surroundings, we need to:
    return ($offset, $length);
}


sub lacks_string($$;$) {
    my ($str,$sub,$name) = @_;

    my $ok;
