#!/usr/bin/perl

use 5.001 ; use strict ; use warnings ; 
use Digest::SHA1 qw[ sha1 sha1_hex sha1_base64 ]; 
use Getopt::Std ; getopts '1$:' , \my %o ; 
use Term::ANSIColor qw[ :constants ] ; $Term::ANSIColor::AUTORESET = 1 ; 

my $sum = 0 ; # undef の方が良いかもしれないかも。
my $postfix = $o{'$'} // '' ; # 各行の末尾に付加する文字列

$SIG{ALRM} = sub { my $t = sprintf "%02d:%02d:%02d",(localtime)[2,1,0] ; print STDERR CYAN "$. line(s) being processed. ($t)\n" ; alarm 60 } ; 
alarm 15;

while ( <> ) { 
	chomp ; 
    $_ .= $postfix ;
 	my @x =  unpack 'C4' , sha1( $_ ) ;  # 0 -  255 の数が4個現れる。
	$sum += ((($x[0]*256+$x[1])*256+$x[2])*256)+$x[3] ; 
    $sum -= 2147483648 if $o{1} ;
}

$sum *= 1 / 4294967296.0 * sqrt ( 12 ) if $o{1}; 
print $sum , "\n" ;

# 処理した結果について2次情報を出力する。
my $lines = $. ; 
$lines =~ s/(?<=\d)(?=(\d\d\d)+($|\D))/,/g ; # 3桁毎にコンマで区切る
print STDERR CYAN "Processed ${lines} line(s). " , sprintf "%02d:%02d:%02d\n" , (localtime)[2,1,0] ; 

exit 0 ;

sub VERSION_MESSAGE {}
sub HELP_MESSAGE {
    use FindBin qw[ $Script ] ; 
    my ($a1,$L,$opt,@out) = ($ARGV[1]//'',0,'^o(p(t(i(o(ns?)?)?)?)?)?$') ;
    open my $FH , '<' , $0 ;
    while(<$FH>){
        s/\$0/$Script/g ;
        $out[$L] .= $_ if s/^=head1\s*(.*)\n/$1/s .. s/^=cut\n//s && ++$L and $a1 =~ /$opt/i ? m/^\s+\-/ : 1 ;
    }
    close $FH ;
    print $ENV{LANG} =~ m/^ja/ ? $out[0] : $out[1] // $out[0] ;
    exit 0 ;
}

=encoding utf8

=head1

$0 

  入力の各行について(行末の改行文字は除去して)、SHA1ハッシュ値を求め、先頭4バイト(32ビット)を 0〜2^32-1の整数に変換し、
  全行についての、総和を求める。

  オプション :

    -1 : 各行について、加算対象の整数に対して -2^31 を加算し、最後に 2^32 で割って sqrt(12)をかけ算して、ある種の正規化を行う。
        -1 のオプションによる正規化により、出力された数の2乗は、2個のデータセットに対して異なる内容の行を自由度とするカイ二乗分布に近似的に従うように分布する。
        -1 のオプションで出力される数は、全く同じような内容の行が多数現れた場合の挙動は、かなり異なるようになるので、解釈に注意が必要である。

    -\$ str ; 各行の末尾に str を付加して、ハッシュ値を計算するようにする。何十回も異なる文字列の付加を反復すれば、出力値の分布から、統計が正確になる。

=cut
