line
stmt
bran
cond
sub
pod
time
code
1
#!/usr/bin/perl
2
package Acme::Tools;
3
4
our $VERSION = '0.172'; #new version: C-s ny versjon
5
6
28
28
643398
use 5.008; #Perl 5.8 was released July 18th 2002
28
107
7
28
28
155
use strict;
28
51
28
656
8
28
28
133
use warnings;
28
54
28
866
9
28
28
148
use Carp;
28
44
28
9224
10
11
require Exporter;
12
our @ISA = qw(Exporter);
13
our %EXPORT_TAGS = ( all => [ qw() ] );
14
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
15
our @EXPORT = qw(
16
min
17
max
18
mins
19
maxs
20
sum
21
avg
22
geomavg
23
harmonicavg
24
stddev
25
median
26
percentile
27
$Resolve_iterations
28
$Resolve_last_estimate
29
resolve
30
resolve_equation
31
conv
32
rank
33
rankstr
34
eqarr
35
sorted
36
sortedstr
37
pushsort
38
pushsortstr
39
binsearch
40
binsearchstr
41
random
42
random_gauss
43
big
44
bigi
45
bigf
46
bigr
47
bigscale
48
nvl
49
repl
50
replace
51
decode
52
decode_num
53
between
54
curb bound
55
distinct
56
in
57
in_num
58
uniq
59
union
60
union_all
61
minus
62
minus_all
63
intersect
64
intersect_all
65
not_intersect
66
mix
67
zip
68
subhash
69
hashtrans
70
zipb64
71
zipbin
72
unzipb64
73
unzipbin
74
gzip
75
gunzip
76
bzip2
77
bunzip2
78
ipaddr
79
ipnum
80
webparams
81
urlenc
82
urldec
83
ht2t
84
chall
85
makedir
86
qrlist
87
ansicolor
88
ccn_ok
89
KID_ok
90
writefile
91
readfile
92
readdirectory
93
basename
94
dirname
95
wipe
96
username
97
range
98
permutations
99
trigram
100
sliding
101
chunks
102
chars
103
cart
104
reduce
105
int2roman
106
roman2int
107
num2code
108
code2num
109
gcd
110
lcm
111
pivot
112
tablestring
113
upper
114
lower
115
trim
116
rpad
117
lpad
118
cpad
119
dserialize
120
serialize
121
srlz
122
bytes_readable
123
distance
124
tms
125
easter
126
time_fp
127
sleep_fp
128
sleeps
129
sleepms
130
sleepus
131
sleepns
132
eta
133
sys
134
recursed
135
md5sum
136
pwgen
137
read_conf
138
openstr
139
ldist
140
$Re_isnum
141
isnum
142
part
143
parth
144
parta
145
ed
146
$Edcursor
147
brainfu
148
brainfu2perl
149
brainfu2perl_optimized
150
bfinit
151
bfsum
152
bfaddbf
153
bfadd
154
bfcheck
155
bfgrep
156
bfgrepnot
157
bfdelete
158
bfstore
159
bfretrieve
160
bfclone
161
bfdimensions
162
$PI
163
install_acme_command_tools
164
165
$Dbh
166
dlogin
167
dlogout
168
drow
169
drows
170
drowc
171
drowsc
172
dcols
173
dpk
174
dsel
175
ddo
176
dins
177
dupd
178
ddel
179
dcommit
180
drollback
181
);
182
183
our $PI = '3.141592653589793238462643383279502884197169399375105820974944592307816406286';
184
185
=head1 NAME
186
187
Acme::Tools - Lots of more or less useful subs lumped together and exported into your namespace
188
189
=head1 SYNOPSIS
190
191
use Acme::Tools;
192
193
print sum(1,2,3); # 6
194
print avg(2,3,4,6); # 3.75
195
196
my @list = minus(\@listA, \@listB); # set operations
197
my @list = union(\@listA, \@listB); # set operations
198
199
print length(gzip("abc" x 1000)); # far less than 3000
200
201
writefile("/dir/filename",$string); # convenient
202
my $s=readfile("/dir/filename"); # also conventient
203
204
print "yes!" if between($pi,3,4);
205
206
print percentile(0.05, @numbers);
207
208
my @even = range(1000,2000,2); # even numbers between 1000 and 2000
209
my @odd = range(1001,2001,2);
210
211
my $dice = random(1,6);
212
my $color = random(['red','green','blue','yellow','orange']);
213
214
...and more.
215
216
=encoding utf8
217
218
=head1 ABSTRACT
219
220
About 120 more or less useful perl subroutines lumped together and exported into your namespace.
221
222
=head1 DESCRIPTION
223
224
Subs created and collected since the mid-90s.
225
226
=head1 INSTALLATION
227
228
sudo cpan Acme::Tools
229
sudo cpanm Acme::Tools # after: sudo apt-get install cpanminus make # for Ubuntu 12.04
230
231
=head1 EXPORT
232
233
Almost every sub, about 90 of them.
234
235
Beware of namespace pollution. But what did you expect from an Acme module?
236
237
=head1 NUMBERS
238
239
=head2 num2code
240
241
See L
242
243
=head2 code2num
244
245
C convert numbers (integers) from the normal decimal system to some arbitrary other number system.
246
That can be binary (2), oct (8), hex (16) or others.
247
248
Example:
249
250
print num2code(255,2,"0123456789ABCDEF"); # prints FF
251
print num2code( 14,2,"0123456789ABCDEF"); # prints 0E
252
253
...because 255 are converted to hex FF (base C<< length("0123456789ABCDEF") >> ) which is 2 digits of 0-9 or A-F.
254
...and 14 are converted to 0E, with leading 0 because of the second argument 2.
255
256
Example:
257
258
print num2code(1234,16,"01")
259
260
Prints the 16 binary digits 0000010011010010 which is 1234 converted to binary zeros and ones.
261
262
To convert back:
263
264
print code2num("0000010011010010","01"); #prints 1234
265
266
C can be used to compress numeric IDs to something shorter:
267
268
$chars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
269
print num2code("241274432",5,$chars); # prints EOOv0
270
print code2num("EOOv0",$chars); # prints 241274432
271
272
=cut
273
274
#Math::BaseCnv
275
276
sub num2code {
277
4
4
1
495
my($num,$digits,$validchars,$start)=@_;
278
4
8
my $l=length($validchars);
279
4
6
my $key;
280
28
28
149
no warnings;
28
49
28
188058
281
4
50
14
croak if $num<$start;
282
4
7
$num-=$start;
283
4
12
for(1..$digits){
284
25
49
$key=substr($validchars,$num%$l,1).$key;
285
25
44
$num=int($num/$l);
286
}
287
4
50
11
croak if $num>0;
288
4
17
return $key;
289
}
290
291
sub code2num {
292
1
50
1
1
4
my($code,$validchars,$start)=@_; $start=0 if !defined $start;
1
5
293
1
2
my $l=length($validchars);
294
1
2
my $num=0;
295
1
14
$num=$num*$l+index($validchars,$_) for split//,$code;
296
1
7
return $num+$start;
297
}
298
299
300
=head2 gcd
301
302
I< C<">The Euclidean algorithm (also called Euclid's algorithm) is an
303
algorithm to determine the greatest common divisor (gcd) of two
304
integers. It is one of the oldest algorithms known, since it appeared
305
in the classic Euclid's Elements around 300 BC. The algorithm does not
306
require factoring.C<"> >
307
308
B two or more positive numbers (integers, without decimals that is)
309
310
B an integer
311
312
B
313
314
print gcd(12, 8); # prints 4
315
316
Because the (prime number) factors of 12 is 2 * 2 * 3 and the factors of 8 is 2 * 2 * 2
317
and the common ('overlapping') factors for both 12 and 8 is then 2 * 2 and the result becomes 4.
318
319
B:
320
321
print gcd(90, 135, 315); # prints 45
322
print gcd(2*3*3*5, 3*3*3*5, 3*3*5*7); # prints 45 ( = 3*3*5 which is common to all three args)
323
324
Implementation:
325
326
sub gcd { my($a,$b,@r)=@_; @r ? gcd($a,gcd($b,@r)) : $b==0 ? $a : gcd($b, $a % $b) }
327
328
L
329
330
L
331
332
=cut
333
334
26
100
26
1
406
sub gcd { my($a,$b,@r)=@_; @r ? gcd($a,gcd($b,@r)) : $b==0 ? $a : gcd($b, $a % $b) }
26
100
101
335
336
=head2 lcm
337
338
C finds the Least Common Multiple of two or more numbers (integers).
339
340
B two or more positive numbers (integers)
341
342
B an integer number
343
344
Example: C< 2/21 + 1/6 = 4/42 + 7/42 = 11/42>
345
346
Where 42 = lcm(21,6).
347
348
B
349
350
print lcm(45,120,75); # prints 1800
351
352
Because the factors are:
353
354
45 = 2^0 * 3^2 * 5^1
355
120 = 2^3 * 3^1 * 5^1
356
75 = 2^0 * 3^1 * 5^2
357
358
Take the bigest power of each primary number (2, 3 and 5 here).
359
Which is 2^3, 3^2 and 5^2. Multiplied this is 8 * 9 * 25 = 1800.
360
361
sub lcm { my($a,$b,@r)=@_; @r ? lcm($a,lcm($b,@r)) : $a*$b/gcd($a,$b) }
362
363
Seems to works with L as well: (C of all integers from 1 to 200)
364
365
perl -MAcme::Tools -MMath::BigInt -le'print lcm(map Math::BigInt->new($_),1..200)'
366
367
337293588832926264639465766794841407432394382785157234228847021917234018060677390066992000
368
369
=cut
370
371
3
100
3
1
8
sub lcm { my($a,$b,@r)=@_; @r ? lcm($a,lcm($b,@r)) : $a*$b/gcd($a,$b) }
3
16
372
373
=head2 resolve
374
375
Resolves an equation by Newtons method.
376
377
B 1-6 arguments. At least one argument.
378
379
First argument: must be a coderef to a subroutine (a function)
380
381
Second argument: if present, the target, f(x)=target. Default 0.
382
383
Third argument: a start position for x. Default 0.
384
385
Fourth argument: a small delta value. Default 1e-4 (0.0001).
386
387
Fifth argument: a maximum number of iterations before resolve gives up
388
and carps. Default 100 (if fifth argument is not given or is
389
undef). The number 0 means infinite here. If the derivative of the
390
start position is zero or close to zero more iterations are typically
391
needed.
392
393
Sixth argument: A number of seconds to run before giving up. If both
394
fifth and sixth argument is given and > 0, C stops at
395
whichever comes first.
396
397
B returns the number C for C = 0
398
399
...or equal to the second input argument if present.
400
401
B
402
403
The equation C<< x^2 - 4x - 21 = 0 >> has two solutions: -3 and 7.
404
405
The result of C will depend on the start position:
406
407
print resolve { $_**2 - 4*$_ - 21 }; # -3 with $_ as your x
408
print resolve(sub{ my $x=shift; $x**2 - 4*$x - 21 }); # -3 more elaborate call
409
print resolve(sub{ my $x=shift; $x**2 - 4*$x - 21 },0,3); # 7 with start position 3
410
print "Iterations: $Acme::Tools::Resolve_iterations\n"; # 3 or larger, about 10-15 is normal
411
412
The variable C< $Acme::Tools::Resolve_iterations > (which is exported) will be set
413
to the last number of iterations C used. Also if C dies (carps).
414
415
The variable C< $Acme::Tools::Resolve_last_estimate > (which is exported) will be
416
set to the last estimate. This number will often be close to the solution and can
417
be used even if C dies (carps).
418
419
B
420
421
If either second, third or fourth argument is an instance of L, so will the result be:
422
423
use Acme::Tools;
424
my $equation = sub{ $_ - 1 - 1/$_ };
425
my $gr1 = resolve( $equation, 0, 1 ); #
426
my $gr2 = resolve( $equation, 0, bigf(1) ); # 1/2 + sqrt(5)/2
427
bigscale(50);
428
my $gr3 = resolve( $equation, 0, bigf(1) ); # 1/2 + sqrt(5)/2
429
430
print 1/2 + sqrt(5)/2, "\n";
431
print "Golden ratio 1: $gr1\n";
432
print "Golden ratio 2: $gr2\n";
433
print "Golden ratio 3: $gr3\n";
434
435
Output:
436
437
1.61803398874989
438
Golden ratio 1: 1.61803398874989
439
Golden ratio 2: 1.61803398874989484820458683436563811772029300310882395927211731893236137472439025
440
Golden ratio 3: 1.6180339887498948482045868343656381177203091798057610016490334024184302360920167724737807104860909804
441
442
See:
443
444
L
445
446
L
447
448
L
449
450
TODO: fix fail for div by 0, e.g.:
451
452
perl -MAcme::Tools -le'for(map$_/10,-4..20){printf"%9.4f %s\n",$_,3*$_+$_**4-12}print resolve(sub{$x=shift;3*$x+$x**4-12},0,1)'
453
resolve(sub{ my $x=shift; $x**2 - 4*$x - 21 },undef,1.9)
454
resolve_equation "x + 13*(3-x) = 17 - 1/x"
455
456
=cut
457
458
our $Resolve_iterations;
459
our $Resolve_last_estimate;
460
461
#sub resolve(\[&$]@) {
462
sub resolve(&@) {
463
13
13
1
1177
my($f,$g,$start,$delta,$iters,$sec)=@_;
464
13
100
31
$g=0 if !defined $g;
465
13
100
26
$start=0 if !defined $start;
466
13
50
34
$delta=1e-4 if !defined $delta;
467
13
50
28
$iters=100 if !defined $iters;
468
13
100
27
$sec=0 if !defined $sec;
469
13
50
25
$iters=13e13 if $iters==0;
470
13
50
33
58
croak "Iterations ($iters) or seconds ($sec) can not be a negative number" if $iters<0 or $sec<0;
471
13
19
$Resolve_iterations=undef;
472
13
16
$Resolve_last_estimate=undef;
473
13
50
28
croak "Should have at least 1 argument, a coderef" if !@_;
474
13
50
33
croak "First argument should be a coderef" if ref($f) ne 'CODE';
475
476
13
22
my @x=($start);
477
13
100
28
my $time_start=$sec>0?time_fp():undef;
478
13
21
my $timeout=0;
479
13
50
23
my $ds=ref($start) eq 'Math::BigFloat' ? Math::BigFloat->div_scale() : undef;
480
my $fx=sub{
481
546
546
743
local$_=$_[0];
482
546
1048
my $fx=&$f($_);
483
546
50
33
4142
if($fx=~/x/ and $fx=~/^[ \(\)\.\d\+\-\*\/x\=]+$/){
484
0
0
$fx=~s/^(.*)=(.*)$/($1)-($2)/;
485
0
0
$fx=~s,x,\$_,g;
486
0
0
$f=eval"sub{$fx}";
487
0
0
$fx=&$f($_);
488
}
489
$fx
490
13
50
};
546
1365
491
13
34
for my $n (0..$iters-1){
492
177
426
my $fd= &$fx($x[$n]+$delta*0.5) - &$fx($x[$n]-$delta*0.5);
493
177
100
423
$fd = &$fx($x[$n]+$delta*0.6) - &$fx($x[$n]-$delta*0.4) if $fd==0; #wiggle...
494
177
100
343
$fd = &$fx($x[$n]+$delta*0.3) - &$fx($x[$n]-$delta*0.7) if $fd==0;
495
#warn "n=$n fd=$fd\n";
496
177
100
532
croak "Div by zero: df(x) = $x[$n] at n'th iteration, n=$n" if $fd==0;
497
176
348
$Resolve_last_estimate=
498
$x[$n+1]=$x[$n]-(&$fx($x[$n])-$g)/($fd/$delta);
499
176
239
$Resolve_iterations=$n;
500
176
100
100
792
last if $n>3 and $x[$n+1]==$x[$n] and $x[$n]==$x[$n-1];
100
501
165
50
66
625
last if $n>3 and ref($x[$n+1]) eq 'Math::BigFloat' and substr($x[$n+1],0,$ds) eq substr($x[$n],0,$ds); #hm
33
502
165
100
100
433
croak "Could not resolve, perhaps too little time given ($sec), iteratons=$n"
100
503
if $sec>0 and time_fp()-$time_start>$sec and $timeout=1;
504
#warn "$n: ".$x[$n+1]."\n";
505
}
506
11
50
26
croak "Could not resolve, perhaps too few iterations ($iters)" if @x>=$iters;
507
11
116
return $x[-1];
508
}
509
510
=head2 resolve_equation
511
512
This prints 2:
513
514
print resolve_equation "x + 13*(3-x) = 17 - x"
515
516
A string containing at least one x is converted into a perl function.
517
Then x is found by using L. The string conversion is done by
518
replacing every x with $_ and if a C< = > char is present it converts
519
C< leftside = rightside > into C< (leftside) - (rightside) = 0 > which
520
is the default behaviour of L.
521
522
=cut
523
524
#sub resolve_equation { my $e=shift;$e=~s/x/\$_/g;$e=~s/(.*)=(.*)/($1)-($2)/;resolve sub{eval$e},@_ }
525
0
0
1
0
sub resolve_equation { my $e=shift;resolve sub{$e},@_ }
0
0
0
0
0
526
527
=head2 conv
528
529
Converts between:
530
531
=over 4
532
533
=item * units of measurement
534
535
=item * number systems
536
537
=item * currencies
538
539
=back
540
541
B
542
543
print conv( 2000, "meters", "miles" ); #prints 1.24274238447467
544
print conv( 2.1, 'km', 'm'); #prints 2100
545
print conv( 70,"cm","in"); #prints 27.5590551181102
546
print conv( 4,"USD","EUR"); #prints 3.20481552905431 (depending on todays rates)
547
print conv( 4000,"b","kb"); #prints 3.90625 (1 kb = 1024 bytes)
548
print conv( 4000,"b","Kb"); #prints 4 (1 Kb = 1000 bytes)
549
print conv( 1000,"mb","kb"); #prints 1024000
550
print conv( 101010,"bin","roman"); #prints XLII
551
print conv( "DCCXLII","roman","oct"); #prints 1346
552
553
B are:>
554
555
Note: units starting with the symbol _ means that all metric
556
prefixes from yocto 10^-24 to yotta 10^+24 is supported, so _m means
557
km, mm, cm, µm and so on. And _N means kN, MN GN and so on.
558
559
Note2: Many units have synonyms: m, meter, meters ...
560
561
acceleration: g, g0, m/s2, mps2
562
563
angle: binary_degree, binary_radian, brad, deg, degree, degrees,
564
gon, grad, grade, gradian, gradians, hexacontade, hour,
565
new_degree, nygrad, point, quadrant, rad, radian, radians,
566
sextant, turn
567
568
area: a, ar, are, ares, bunder, ca, centiare, cho, cm2,
569
daa, decare, decares, deciare, dekar,
570
djerib, m2, dunam, dönüm, earths, feddan, ft2, gongqing, ha
571
ha, hectare, hectares, hektar, jerib, km2, m2, manzana,
572
mi2, mm2, mu, qing, rai, sotka,
573
sqcm, sqft, sqkm, sqm, sqmi, sqmm
574
stremmata, um2, µm2
575
576
bytes: Eb, Gb, Kb, KiB, Mb, Pb, Tb, Yb, Zb, b, byte,
577
kb, kilobyte, mb, megabyte,
578
gb, gigabyte, tb, terabyte,
579
pb, petabyte, eb, exabyte,
580
zb, zettabyte, yb, yottabyte
581
582
charge: As, C, _e, coulomb, e
583
584
current: A, _A, N/m2
585
586
energy: BTU, Btu, J, Nm, W/s, Wh, Wps, Ws, _J, _eV,
587
cal, calorie, calories, eV, electronvolt,
588
erg, ergs, foot-pound, foot-pounds, ftlb, joule, kWh,
589
kcal, kilocalorie, kilocalories,
590
newtonmeter, newtonmeters, th, thermie
591
592
force: N, _N, dyn, dyne, dynes, lb, newton
593
594
length: NM, _m, _pc, astronomical unit, au, chain, ft, furlong,
595
in, inch, inches, km, league, lightyear, ls, ly,
596
m, meter, meters, mi, mil, mile, miles,
597
nautical mile, nautical miles, nmi,
598
parsec, pc, planck, yard, yard_imperical, yd, Å, ångstrøm
599
600
mass: Da, _eV, _g, bag, carat, ct, dwt, eV, electronvolt, g,
601
grain, grains, gram, grams, kilo, kilos, kt, lb, lb_av,
602
lb_t, lb_troy, lbs, ounce, ounce_av, ounce_troy, oz, oz_av, oz_t,
603
pennyweight, pound, pound_av, pound_metric, pound_troy, pounds,
604
pwt, seer, sl, slug, solar_mass, st, stone, t, tonn, tonne, tonnes, u, wey
605
606
mileage: mpg, l/100km, l/km, l/10km, lp10km, l/mil, liter_pr_100km, liter_pr_km, lp100km
607
608
money: AED, ARS, AUD, BGN, BHD, BND, BRL, BWP, CAD, CHF, CLP, CNY,
609
COP, CZK, DKK, EUR, GBP, HKD, HRK, HUF, IDR, ILS, INR, IRR,
610
ISK, JPY, KRW, KWD, KZT, LKR, LTL, LVL, LYD, MUR, MXN, MYR,
611
NOK, NPR, NZD, OMR, PHP, PKR, PLN, QAR, RON, RUB, SAR, SEK,
612
SGD, THB, TRY, TTD, TWD, USD, VEF, ZAR, BTC, LTC, mBTC, XBT
613
Currency rates are automatically updated from the net
614
at least every 24h since last update (on linux/cygwin).
615
616
numbers: dec, hex, bin, oct, roman, dozen, doz, dz, dusin, gross, gro,
617
gr, great_gross, small_gross (not supported: decimal numbers)
618
619
power: BTU, BTU/h, BTU/s, BTUph, GWhpy, J/s, Jps, MWhpy, TWhpy,
620
W, Whpy, _W, ftlb/min, ftlb/s, hk, hp, kWh/yr, kWhpy
621
622
pressure: N/m2, Pa, _Pa, at, atm, bar, mbar, pascal, psi, torr
623
624
radioactivity: Bq, becquerel, curie
625
626
speed: _m/s, km/h, km/t, kmh, kmph, kmt, m/s, mi/h, mph, mps,
627
kn, knot, knots, kt, mach, machs, c, fps, ft/s, ftps
628
629
temperature: C, F, K, celsius, fahrenheit, kelvin
630
631
time: _s, biennium, century, d, day, days, decade, dy, fortnight,
632
h, hour, hours, hr, indiction, jubilee, ke, lustrum, m,
633
millennium, min, minute, minutes, mo, moment, mon, month,
634
olympiad, quarter, s, season, sec, second, seconds, shake,
635
tp, triennium, w, week, weeks, y, y365, ySI, ycommon,
636
year, years, ygregorian, yjulian, ysideral, ytropical
637
638
volume: l, L, _L, _l, cm3, m3, ft3, in3, liter, liters, litre, litres,
639
gal, gallon, gallon_imp, gallon_uk, gallon_us, gallons,
640
pint, pint_imp, pint_uk, pint_us, tsp, tablespoon, teaspoon,
641
floz, floz_uk, therm, thm, fat, bbl, Mbbl, MMbbl, drum
642
643
See: L
644
645
=cut
646
647
#TODO: @arr2=conv(\@arr1,"from","to") # is way faster than:
648
#TODO: @arr2=map conv($_,"from","to"),@arr1
649
#TODO: conv(123456789,'b','h'); # h converts to something human-readable
650
651
our %conv=(
652
length=>{
653
m => 1,
654
_m => 1,
655
meter => 1,
656
meters => 1,
657
km => 1000,
658
mil => 10000, #scandinavian #also: inch/1000!
659
in => 0.0254,
660
inch => 0.0254,
661
inches => 0.0254,
662
ft => 0.0254*12, #0.3048 m
663
feet => 0.0254*12, #0.3048 m
664
yd => 0.0254*12*3, #0.9144 m
665
yard => 0.0254*12*3, #0.9144 m
666
yards => 0.0254*12*3, #0.9144 m
667
fathom => 0.0254*12*3*2, #1.8288 m
668
fathoms => 0.0254*12*3*2, #1.8288 m
669
chain => 0.0254*12*3*22, #20.1168 m
670
chains => 0.0254*12*3*22, #20.1168 m
671
furlong => 0.0254*12*3*22*10, #201.168 m
672
furlongs=> 0.0254*12*3*22*10, #201.168 m
673
mi => 0.0254*12*3*22*10*8, #1609.344 m
674
mile => 0.0254*12*3*22*10*8, #1609.344 m
675
miles => 0.0254*12*3*22*10*8,
676
league => 0.0254*12*3*22*10*8*3, #4828.032 m
677
leagues => 0.0254*12*3*22*10*8*3, #4828.032 m
678
yard_imperical => 0.914398416,
679
NM => 1852, #nautical mile
680
nmi => 1852, #nautical mile
681
'nautical mile' => 1852,
682
'nautical miles' => 1852,
683
'Å' => 1e-10,
684
'ångstrøm' => 1e-10,
685
ly => 299792458*3600*24*365.25,
686
lightyear => 299792458*3600*24*365.25, # = 9460730472580800 by def
687
ls => 299792458, #light-second
688
pc => 3.0857e16, #3.26156 ly
689
_pc => 3.0857e16, #3.26156 ly
690
parsec => 3.0857e16,
691
au => 149597870700, # by def, earth-sun
692
'astronomical unit' => 149597870700,
693
planck => 1.61619997e-35, #planck length
694
#Norwegian (old) lengths:
695
tomme => 0.0254,
696
tommer => 0.0254,
697
fot => 0.0254*12, #0.3048m
698
alen => 0.0254*12*2, #0.6096m
699
favn => 0.0254*12*2*3, #1.8288m
700
kvart => 0.0254*12*2/4, #0.1524m a quarter alen
701
},
702
mass =>{ #https://en.wikipedia.org/wiki/Unit_conversion#Mass
703
g => 1,
704
_g => 1,
705
gram => 1,
706
grams => 1,
707
kilo => 1000,
708
kilos => 1000,
709
t => 1000000,
710
tonn => 1000000,
711
tonne => 1000000,
712
tonnes => 1000000,
713
seer => 933.1,
714
lb => 453.59237,
715
lbs => 453.59237,
716
lb_av => 453.59237,
717
lb_t => 373.2417216, #5760 grains
718
lb_troy => 373.2417216,
719
pound => 453.59237,
720
pounds => 453.59237,
721
pound_av => 453.59237,
722
pound_troy => 373.2417216,
723
pound_metric => 500,
724
ounce => 28, # US food, 28g
725
ounce_av => 453.59237/16, # avoirdupois lb/16 = 28.349523125g
726
ounce_troy => 31.1034768, # lb_troy / 12
727
oz => 28, # US food, 28g
728
oz_av => 453.59237/16, # avoirdupois lb/16 = 28.349523125g
729
oz_t => 31.1034768, # lb_troy / 12,
730
grain => 64.79891/1000, # 453.59237/7000
731
grains => 64.79891/1000,
732
pennyweight => 31.1034768 / 20,
733
pwt => 31.1034768 / 20,
734
dwt => 31.1034768 / 20,
735
st => 6350.29318, # 14 lb_av
736
stone => 6350.29318,
737
wey => 114305.27724, # 252 lb = 18 stone
738
carat => 0.2,
739
ct => 0.2, #carat (metric)
740
kt => 64.79891/1000 * (3+1/6), #carat/karat
741
u => 1.66053892173e-30, #atomic mass carbon-12
742
Da => 1.66053892173e-30, #atomic mass carbon-12
743
slug => 14600,
744
sl => 14600,
745
eV => 1.783e-33, #e=mc2
746
_eV => 1.783e-33,
747
electronvolt => 1.783e-33,
748
'solar mass' => 1.99e33,
749
solar_mass => 1.99e33,
750
bag => 60*1000, #60kg coffee
751
},
752
area =>{ # https://en.wikipedia.org/wiki/Unit_conversion#Area
753
m2 => 1,
754
dm2 => 0.1**2,
755
cm2 => 0.01**2,
756
mm2 => 0.001**2,
757
'µm2' => 1e-6**2,
758
um2 => 1e-6**2,
759
sqm => 1,
760
sqcm => 0.01**2,
761
sqmm => 0.001**2,
762
km2 => 1000**2,
763
sqkm => 1000**2,
764
a => 100,
765
ar => 100,
766
are => 100,
767
ares => 100,
768
dekar => 1000,
769
decare => 1000,
770
decares => 1000,
771
daa => 1000,
772
'mål' => 1000,
773
ha => 10000,
774
hektar => 10000,
775
hectare => 10000,
776
hectares=> 10000,
777
ft2 => (0.0254*12)**2,
778
sqft => (0.0254*12)**2,
779
mi2 => 1609.344**2,
780
sqmi => 1609.344**2,
781
yd2 => (0.0254*12*3)**2, #square yard
782
sqyd => (0.0254*12*3)**2,
783
yard2 => (0.0254*12*3)**2,
784
sqyard => (0.0254*12*3)**2,
785
rood => 1210*(0.0254*12)**2, # 1/4 acres
786
roods => 1210*(0.0254*12)**2, # 1/4 acres
787
ac => 4840*(0.0254*12)**2, # 4840 square yards
788
acre => 4840*(0.0254*12)**2,
789
acres => 4840*(0.0254*12)**2,
790
homestead => 4840*(0.0254*12)**2 *160, #160 acres US Surveyors or 1/4 sqmiles
791
township => 4840*(0.0254*12)**2 *160*144, #144 homesteads or 36 sqmiles
792
perches => 4840*(0.0254*12)**2 /160, #160 perches = 1 acre in sri lanka
793
sotka => 100, #russian are
794
jerib => 10000, #iran hectare
795
djerib => 10000, #turkish hectare
796
gongqing => 10000, #chinese hectare
797
manzana => 10000, #argentinian hectare
798
bunder => 10000, #dutch hectare
799
centiare => 1,
800
deciare => 10,
801
ca => 1,
802
mu => 10000/15, #China
803
qing => 10000/0.15, #China
804
dunam => 10000/10, #Middle East
805
'dönüm' => 10000/10, #Middle East
806
stremmata =>10000/10, #Greece
807
rai => 10000/6.25, #Thailand
808
cho => 10000/1.008, #Japan
809
feddan => 10000/2.381, #Egypt
810
earths => 510072000*1000**2, #510072000 km2, surface area of earth
811
barn => 1e-28, #physics
812
outhouse => 1e-34, #physics
813
shed => 1e-52, #physics
814
},
815
volume=>{
816
l => 1,
817
L => 1,
818
_L => 1,
819
_l => 1,
820
liter => 1,
821
liters => 1,
822
litre => 1,
823
litres => 1,
824
gal => 231*2.54**3/1000, #3.785411784, #231 cubic inches
825
gallon => 231*2.54**3/1000,
826
gallons => 231*2.54**3/1000,
827
gallon_us => 231*2.54**3/1000,
828
gallon_uk => 4.54609,
829
gallon_imp=> 4.54609,
830
gallon_us_dry => 4.40488377086, # ~ 9.25**2*pi*2.54**3/1000 L
831
m3 => 10**3, #1000 L
832
cm3 => 0.1**3, #0.001 L
833
in3 => 0.254**3, #0.016387064 L
834
ft3 => (0.254*12)**3,
835
tablespoon=> 3.785411784/256, #14.78676478125 mL
836
tsp => 3.785411784/256/3, #4.92892159375 mL
837
teaspoon => 3.785411784/256/3, #4.92892159375 mL
838
floz => 3.785411784/128, #fluid ounce US
839
floz_uk => 4.54609/160, #fluid ounce UK
840
pint => 4.54609/8, #0.56826125 L
841
pint_uk => 4.54609/8,
842
pint_imp => 4.54609/8,
843
pint_us => 3.785411784/8, #0.473176473
844
therm => 2.74e3, #? 100000BTUs? (!= thermie)
845
thm => 2.74e3, #? (!= th)
846
fat => 42*231*2.54**3/1000,
847
bbl => 42*231*2.54**3/1000, #oil barrel ~159 liters https://en.wikipedia.org/wiki/Barrel_(unit)
848
Mbbl => 42*231*2.54**3, #mille (thousand) oil barrels
849
MMbbl => 42*231*2.54**3*1000, #mille mille (million) oil barrels
850
drum => 200,
851
#Norwegian:
852
meterfavn => 2 * 2 * 0.6, #ved 2.4 m3
853
storfavn => 2 * 2 * 3, #ved 12 m3
854
},
855
time =>{
856
s => 1,
857
_s => 1,
858
sec => 1,
859
second => 1,
860
seconds => 1,
861
m => 60,
862
min => 60,
863
minute => 60,
864
minutes => 60,
865
h => 60*60,
866
hr => 60*60,
867
hour => 60*60,
868
hours => 60*60,
869
d => 60*60*24,
870
dy => 60*60*24,
871
day => 60*60*24,
872
days => 60*60*24,
873
w => 60*60*24*7,
874
week => 60*60*24*7,
875
weeks => 60*60*24*7,
876
mo => 60*60*24 * 365.2425/12,
877
mon => 60*60*24 * 365.2425/12,
878
month => 60*60*24 * 365.2425/12,
879
quarter => 60*60*24 * 365.2425/12 * 3, #3 months
880
season => 60*60*24 * 365.2425/12 * 3, #3 months
881
y => 60*60*24 * 365.2425, # 365+97/400 #97 leap yers in 400 years
882
year => 60*60*24 * 365.2425,
883
years => 60*60*24 * 365.2425,
884
yjulian => 60*60*24 * 365.25, # 365+1/4
885
y365 => 60*60*24 * 365, # finance/science
886
ycommon => 60*60*24 * 365, # finance/science
887
ygregorian => 60*60*24 * 365.2425, # 365+97/400
888
#ygaussian => 365+(6*3600+9*60+56)/(24*3600), # 365+97/400
889
ytropical => 60*60*24 * 365.24219,
890
ysideral => 365.256363004,
891
ySI => 60*60*24*365.25, #31556925.9747
892
decade => 10 * 60*60*24*365.2425,
893
biennium => 2 * 60*60*24*365.2425,
894
triennium => 3 * 60*60*24*365.2425,
895
olympiad => 4 * 60*60*24*365.2425,
896
lustrum => 5 * 60*60*24*365.2425,
897
indiction => 15 * 60*60*24*365.2425,
898
jubilee => 50 * 60*60*24*365.2425,
899
century => 100 * 60*60*24*365.2425,
900
millennium => 1000 * 60*60*24*365.2425,
901
shake => 1e-8,
902
moment => 3600/40, #1/40th of an hour, used by Medieval Western European computists
903
ke => 864, #1/100th of a day, trad Chinese, 14m24s
904
fortnight => 14*24*3600,
905
tp => 5.3910632e-44, #planck time, time for ligth to travel 1 planck length
906
},
907
speed=>{
908
'm/s' => 1,
909
'_m/s' => 1,
910
mps => 1,
911
mph => 1609.344/3600,
912
'mi/h' => 1609.344/3600,
913
kmh => 1/3.6,
914
kmph => 1/3.6,
915
'km/h' => 1/3.6,
916
kmt => 1/3.6, # t=time or temps (scandinavian and french and dutch)
917
'km/t' => 1/3.6,
918
kn => 1852/3600,
919
kt => 1852/3600,
920
knot => 1852/3600,
921
knop => 1852/3600, #scandinavian
922
knots => 1852/3600,
923
c => 299792458, #speed of light
924
mach => 340.3, #speed of sound
925
machs => 340.3,
926
fps => 0.3048, #0.0254*12
927
ftps => 0.3048,
928
'ft/s' => 0.3048,
929
},
930
acceleration=>{
931
'm/s2' => 1,
932
'mps2' => 1,
933
g => 9.80665,
934
g0 => 9.80665,
935
#0-100kmh or ca 0-60 mph x seconds...
936
},
937
temperature=>{ #http://en.wikipedia.org/wiki/Temperature#Conversion
938
C=>1, F=>1, K=>1, celsius=>1, fahrenheit=>1, kelvin=>1
939
},
940
radioactivity=>{
941
Bq => 1,
942
becquerel => 1,
943
curie => 3.7e10,
944
},
945
current=> {
946
A => 1,
947
_A => 1,
948
'N/m2' => 2e-7,
949
},
950
charge=>{
951
e => 1,
952
_e => 1,
953
C => 6.24150964712042e+18,
954
coulomb => 6.24150964712042e+18,
955
As => 6.24150964712042e+18,
956
#Faraday unit of charge ???
957
},
958
power=> {
959
W => 1,
960
_W => 1,
961
'J/s' => 1,
962
Jps => 1,
963
hp => 746,
964
hk => 746, #hestekrefter (norwegian, scandinavian)
965
'kWh/yr' => 1000 * 3600/(24*365), #kWh annually
966
Whpy => 3600/(24*365), #kWh annually
967
kWhpy => 1000 * 3600/(24*365), #kWh annually
968
MWhpy => 1000**2 * 3600/(24*365), #kWh annually
969
GWhpy => 1000**3 * 3600/(24*365), #kWh annually
970
TWhpy => 1000**4 * 3600/(24*365), #kWh annually
971
BTU => 1055.05585262/3600, #
972
BTUph => 1055.05585262/3600,
973
'BTU/h' => 1055.05585262/3600,
974
'BTU/s' => 1055.05585262,
975
'ftlb/s' => 746/550,
976
'ftlb/min'=> 746/550/60,
977
},
978
energy=>{
979
joule => 1,
980
J => 1,
981
_J => 1,
982
Ws => 1,
983
Wps => 1,
984
'W/s' => 1,
985
Nm => 1,
986
newtonmeter => 1,
987
newtonmeters => 1,
988
Wh => 3600,
989
kWh => 3600000, #3.6 million J
990
cal => 4.1868, # ~ 3600/860
991
calorie => 4.1868,
992
calories => 4.1868,
993
kcal => 4.1868*1000,
994
kilocalorie => 4.1868*1000,
995
kilocalories => 4.1868*1000,
996
BTU => 4.1868 * 252, # = 1055.0736 or is 1055.05585262 right?
997
Btu => 4.1868 * 252,
998
ftlb => 746/550, # ~ 1/0.7375621
999
'foot-pound' => 746/550,
1000
'foot-pounds' => 746/550,
1001
erg => 1e-7,
1002
ergs => 1e-7,
1003
eV => 1.60217656535e-19,
1004
_eV => 1.60217656535e-19,
1005
electronvolt => 1.60217656535e-19,
1006
thermie => 4.1868e6,
1007
th => 4.1868e6,
1008
},
1009
force=> {
1010
newton=> 1,
1011
N => 1,
1012
_N => 1,
1013
dyn => 1e-5,
1014
dyne => 1e-5,
1015
dynes => 1e-5,
1016
lb => 4.448222,
1017
},
1018
pressure=>{
1019
Pa => 1,
1020
_Pa => 1,
1021
pascal => 1,
1022
'N/m2' => 1,
1023
bar => 100000.0,
1024
mbar => 100.0,
1025
at => 98066.5, #technical atmosphere
1026
atm => 101325.0, #standard atmosphere
1027
torr => 133.3224,
1028
psi => 6894.8, #pounds per square inch
1029
},
1030
bytes=> {
1031
b => 1,
1032
kb => 1024, #2**10
1033
mb => 1024**2, #2**20 = 1048576
1034
gb => 1024**3, #2**30 = 1073741824
1035
tb => 1024**4, #2**40 = 1099511627776
1036
pb => 1024**5, #2**50 = 1.12589990684262e+15
1037
eb => 1024**6, #2**60 =
1038
zb => 1024**7, #2**70 =
1039
yb => 1024**8, #2**80 =
1040
KiB => 1024, #2**10
1041
KiB => 1024**2, #2**20 = 1048576
1042
KiB => 1024**3, #2**30 = 1073741824
1043
KiB => 1024**4, #2**40 = 1099511627776
1044
KiB => 1024**5, #2**50 = 1.12589990684262e+15
1045
KiB => 1024**6, #2**60 =
1046
KiB => 1024**7, #2**70 =
1047
KiB => 1024**8, #2**80 =
1048
Kb => 1000, #2**10
1049
Mb => 1000**2, #2**20 = 1048576
1050
Gb => 1000**3, #2**30 = 1073741824
1051
Tb => 1000**4, #2**40 = 1099511627776
1052
Pb => 1000**5, #2**50 = 1.12589990684262e+15
1053
Eb => 1000**6, #2**60 =
1054
Zb => 1000**7, #2**70 =
1055
Yb => 1000**8, #2**80 =
1056
byte => 1,
1057
kilobyte => 1024, #2**10
1058
megabyte => 1024**2, #2**20 = 1048576
1059
gigabyte => 1024**3, #2**30 = 1073741824
1060
terabyte => 1024**4, #2**40 = 1099511627776
1061
petabyte => 1024**5, #2**50 = 1.12589990684262e+15
1062
exabyte => 1024**6, #2**60 =
1063
zettabyte => 1024**7, #2**70 =
1064
yottabyte => 1024**8, #2**80 =
1065
},
1066
milage=>{ #fuel consumption
1067
'l/mil' => 1,
1068
'l/10km' => 1,
1069
'lp10km' => 1,
1070
'l/km' => 10,
1071
'l/100km' => 1/10,
1072
lp100km => 1/10,
1073
liter_pr_100km => 1/10,
1074
liter_pr_km => 10,
1075
mpg => -23.5214584, #negative signals inverse
1076
},
1077
# light=> {
1078
# cd => 1,
1079
# candela => 1,
1080
# },
1081
# lumens
1082
# lux
1083
angle =>{
1084
turn => 1,
1085
rad => 1/(2*$PI), # 2 * pi
1086
radian => 1/(2*$PI), # 2 * pi
1087
radians => 1/(2*$PI), # 2 * pi
1088
deg => 1/360, # 4 * 90
1089
degree => 1/360, # 4 * 90
1090
degrees => 1/360, # 4 * 90
1091
grad => 1/400,
1092
gradian => 1/400,
1093
gradians => 1/400,
1094
grade => 1/400, #french revolutionary unit
1095
gon => 1/400,
1096
new_degree => 1/400,
1097
nygrad => 1/400, #scandinavian
1098
quadrant => 1/4,
1099
sextant => 1/6,
1100
hour => 1/24,
1101
point => 1/32, #used in navigation
1102
hexacontade => 1/60,
1103
binary_degree => 1/256,
1104
binary_radian => 1/256,
1105
brad => 1/256,
1106
},
1107
money =>{ # rates at dec 17 2015
1108
AED => 2.389117, #
1109
ARS => 0.895122, #
1110
AUD => 6.253619, #
1111
BGN => 4.847575, #
1112
BHD => 23.267384, #
1113
BND => 6.184624, #
1114
BRL => 2.260703, #
1115
BTC => 3910.932213547, #bitcoin
1116
BWP => 0.794654, #
1117
CAD => 6.289957, #
1118
CHF => 8.799974, #
1119
CLP => 0.012410, #
1120
CNY => 1.353406, #
1121
COP => 0.00262229, #
1122
CZK => 0.351171, #
1123
DKK => 1.271914, #
1124
EUR => 9.489926, #
1125
GBP => 13.069440, #
1126
HKD => 1.131783, #
1127
HRK => 1.240878, #
1128
HUF => 0.029947, #
1129
IDR => 0.00062471, #
1130
ILS => 2.254456, #
1131
INR => 0.132063, #
1132
IRR => 0.00029370, #
1133
ISK => 0.067245, #
1134
JPY => 0.071492, #
1135
KRW => 0.00739237, #
1136
KWD => 28.862497, #
1137
KZT => 0.027766, #
1138
LKR => 0.061173, #
1139
LTC => 31.78895354018, #litecoin
1140
LTL => 2.748472, #
1141
LVL => 13.503025, #
1142
LYD => 6.296978, #
1143
MUR => 0.240080, #
1144
MXN => 0.515159, #
1145
MYR => 2.032465, #
1146
NOK => 1.000000000, #norwegian kroner
1147
NPR => 0.084980, #
1148
NZD => 5.878331, #
1149
OMR => 22.795994, #
1150
PHP => 0.184839, #
1151
PKR => 0.083779, #
1152
PLN => 2.207243, #
1153
QAR => 2.409162, #
1154
RON => 2.101513, #
1155
RUB => 0.122991, #
1156
SAR => 2.339745, #
1157
SEK => 1.023591, #
1158
SGD => 6.184624, #
1159
THB => 0.242767, #
1160
TRY => 2.994338, #
1161
TTD => 1.374484, #
1162
TWD => 0.265806, #
1163
USD => 8.774159, #
1164
VEF => 1.395461, #
1165
ZAR => 0.576487, #
1166
XBT => 3910.932213547, # bitcoin
1167
mBTC => 3910.932213547, # bitcoin
1168
mXBT => 3910.932213547, # bitcoin
1169
},
1170
numbers =>{
1171
dec=>1,hex=>1,bin=>1,oct=>1,roman=>1, des=>1,#des: spelling error in v0.15-0.16
1172
dusin=>1,dozen=>1,doz=>1,dz=>1,gross=>144,gr=>144,gro=>144,great_gross=>12*144,small_gross=>10*12,
1173
}
1174
);
1175
our $conv_prepare_time=0;
1176
our $conv_prepare_money_time=0;
1177
sub conv_prepare {
1178
1
1
0
11
my %b =(da =>1e+1, h =>1e+2, k =>1e+3, M =>1e+6, G =>1e+9, T =>1e+12, P =>1e+15, E =>1e+18, Z =>1e+21, Y =>1e+24, H =>1e+27);
1179
1
8
my %big =(deca=>1e+1, hecto=>1e+2, kilo =>1e+3, mega =>1e+6, giga=>1e+9, tera=>1e+12, peta =>1e+15, exa =>1e+18, zetta=>1e+21, yotta=>1e+24, hella=>1e+27);
1180
1
9
my %s =(d =>1e-1, c =>1e-2, m =>1e-3,'µ' =>1e-6, u=>1e-6, n =>1e-9, p =>1e-12, f =>1e-15, a =>1e-18, z =>1e-21, y =>1e-24);
1181
1
7
my %small=(deci=>1e-1, centi=>1e-2, milli=>1e-3, micro =>1e-6, nano=>1e-9, pico=>1e-12, femto=>1e-15, atto=>1e-18, zepto=>1e-21, yocto=>1e-24);
1182
# myria=> 10000 #obsolete
1183
# demi => 1/2, double => 2 #obsolete
1184
# lakh => 1e5, crore => 1e7 #south asian
1185
1
12
my %x = (%s,%b);
1186
1
9
for my $type (keys%conv) {
1187
20
30
for(grep/^_/,keys%{$conv{$type}}) {
20
267
1188
15
29
my $c=$conv{$type}{$_};
1189
15
26
delete$conv{$type}{$_};
1190
15
22
my $unit=substr($_,1);
1191
15
556
$conv{$type}{$_.$unit}=$x{$_}*$c for keys%x;
1192
}
1193
}
1194
1
17
$conv_prepare_time=time();
1195
}
1196
1197
our $Currency_rates_url = 'http://calthis.com/currency-rates';
1198
our $Currency_rates_expire = 6*3600;
1199
sub conv_prepare_money {
1200
0
0
0
0
eval {
1201
0
0
require LWP::Simple;
1202
0
0
0
my $td=$^O=~/^(?:linux|cygwin)$/?"/tmp":"/tmp"; #hm wrong!
1203
0
0
my $fn="$td/acme-tools-currency-rates.data";
1204
0
0
0
0
if( !-e$fn or time() - (stat($fn))[9] >= $Currency_rates_expire){
1205
0
0
LWP::Simple::getstore($Currency_rates_url,"$fn.$$.tmp"); # get ... see getrates.cmd
1206
0
0
0
die "nothing downloaded" if !-s"$fn.$$.tmp";
1207
0
0
rename "$fn.$$.tmp",$fn;
1208
0
0
chmod 0666,$fn;
1209
}
1210
0
0
my $d=readfile($fn);
1211
0
0
my %r=$d=~/^\s*([A-Z]{3}) +(\d+\.\d+)\b/gm;
1212
0
0
$r{lc($_)}=$r{$_} for keys%r;
1213
#warn serialize([minus([sort keys(%r)],[sort keys(%{$conv{money}})])],'minus'); #ARS,AED,COP,BWP,LVL,BHD,NPR,LKR,QAR,KWD,LYD,SAR,KZT,CLP,IRR,VEF,TTD,OMR,MUR,BND
1214
#warn serialize([minus([sort keys(%{$conv{money}})],[sort keys(%r)])],'minus'); #LTC,I44,BTC,BYR,TWI,NOK,XDR
1215
0
0
0
$conv{money}={%{$conv{money}},%r} if keys(%r)>20;
0
0
1216
};
1217
0
0
0
carp "conv: conv_prepare_money (currency conversion automatic daily updated rates) - $@\n" if $@;
1218
0
0
$conv{money}{"m$_"}=$conv{money}{$_}/1000 for qw/BTC XBT/;
1219
0
0
$conv_prepare_money_time=time();
1220
0
0
1; #not yet
1221
}
1222
1223
sub conv {
1224
41
41
1
14271
my($num,$from,$to)=@_;
1225
41
50
103
croak "conf requires 3 args" if @_!=3;
1226
41
100
89
conv_prepare() if !$conv_prepare_time;
1227
41
82
152
my $types=sub{ my $unit=shift; [sort grep$conv{$_}{$unit}, keys%conv] };
82
114
82
1498
1228
41
33
81
my @types=map{ my $ru=$_; my $r;$r=&$types($_) and @$r and $$ru=$_ and last for ($$ru,uc($$ru),lc($$ru)); $r }(\$from,\$to);
82
33
103
82
50
97
82
259
82
280
1229
41
74
my @err=map "Unit ".[$from,$to]->[$_]." is unknown",grep!@{$types[$_]},0..1;
82
150
1230
41
92
my @type=intersect(@types);
1231
41
50
105
push @err, "from=$from and to=$to has more than one possible conversions: ".join(", ", @type) if @type>1;
1232
push @err, "from $from (".(join(",",@{$types[0]})||'?').") and "
1233
41
50
0
92
."to $to (" .(join(",",@{$types[1]})||'?').") has no known common unit type.\n" if @type<1;
0
1234
41
50
83
croak join"\n",map"conv: $_",@err if @err;
1235
41
57
my $type=$type[0];
1236
41
50
66
114
conv_prepare_money() if $type eq 'money' and time() >= $conv_prepare_money_time + $Currency_rates_expire;
1237
41
100
89
return conv_temperature(@_) if $type eq 'temperature';
1238
34
100
78
return conv_numbers(@_) if $type eq 'numbers';
1239
29
46
my $c=$conv{$type};
1240
29
35
my($cf,$ct)=@{$conv{$type}}{$from,$to};
29
70
1241
29
100
100
188
my $r= $cf>0 && $ct<0 ? -$ct/$num/$cf
100
66
1242
: $cf<0 && $ct>0 ? -$cf/$num/$ct
1243
: $cf*$num/$ct;
1244
# print STDERR "$num $from => $to from=$ff to=$ft r=$r\n";
1245
29
178
return $r;
1246
}
1247
1248
sub conv_temperature { #http://en.wikipedia.org/wiki/Temperature#Conversion
1249
7
7
0
32
my($t,$from,$to)=(shift(),map uc(substr($_,0,1)),@_);
1250
7
100
25
$from=~s/K/C/ and $t-=273.15;
1251
#$from=~s/R/F/ and $t-=459.67; #rankine
1252
7
100
21
return $t if $from eq $to;
1253
1
1
7
{CK=>sub{$t+273.15},
1254
3
3
23
FC=>sub{($t-32)*5/9},
1255
2
2
14
CF=>sub{$t*9/5+32},
1256
0
0
0
FK=>sub{($t-32)*5/9+273.15},
1257
6
126
}->{$from.$to}->();
1258
}
1259
1260
sub conv_numbers {
1261
5
5
0
10
my($n,$fr,$to)=@_;
1262
5
0
41
my $dec=$fr eq 'dec' ? $n
50
50
50
50
50
50
100
50
100
50
1263
:$fr eq 'hex' ? hex($n)
1264
:$fr eq 'oct' ? oct($n)
1265
:$fr eq 'bin' ? oct("0b$n")
1266
:$fr =~ /^(dusin|dozen|doz|dz)$/ ? $n*12
1267
:$fr =~ /^(gross|gr|gro)$/ ? $n*144
1268
:$fr eq 'great_gross' ? $n*12*144
1269
:$fr eq 'small_gross' ? $n*12*10
1270
:$fr eq 'skokk' ? $n*60 #norwegian unit
1271
:$fr eq 'roman' ? roman2int($n)
1272
:$fr eq 'des' ? $n
1273
:croak "Conv from $fr not supported yet";
1274
5
50
52
my $ret=$to eq 'dec' ? $dec
100
50
50
50
50
50
100
100
50
50
1275
:$to eq 'hex' ? sprintf("%x",$dec)
1276
:$to eq 'oct' ? sprintf("%o",$dec)
1277
:$to eq 'bin' ? sprintf("%b",$dec)
1278
:$to =~ /^(dusin|dozen|doz|dz)$/ ? $dec/12
1279
:$to =~ /^(gross|gr|gro)$/ ? $dec/144
1280
:$to eq 'great_gross' ? $dec/(12*144)
1281
:$to eq 'small_gross' ? $dec/(12*10)
1282
:$to eq 'skokk' ? $dec/60
1283
:$to eq 'roman' ? int2roman($dec)
1284
:$to eq 'des' ? $dec
1285
:croak "Conv to $to not suppoerted yet";
1286
5
34
$ret;
1287
}
1288
#http://en.wikipedia.org/wiki/Norwegian_units_of_measurement
1289
1290
1291
=head2 bytes_readable
1292
1293
Input: a number
1294
1295
Output:
1296
1297
the number with a B behind if the number is less than 1000
1298
1299
the number divided by 1024 with two decimals and "kB" behind if the number is less than 1024*1000
1300
1301
the number divided by 1048576 with two decimals and "MB" behind if the number is less than 1024*1024*1000
1302
1303
the number divided by 1073741824 with two decimals and "GB" behind if the number is less than 1024*1024*1024*1000
1304
1305
the number divided by 1099511627776 with two decimals and "TB" behind otherwise
1306
1307
Examples:
1308
1309
print bytes_readable(999); # 999 B
1310
print bytes_readable(1000); # 1000 B
1311
print bytes_readable(1001); # 0.98 kB
1312
print bytes_readable(1024); # 1.00 kB
1313
print bytes_readable(1153433.6); # 1.10 MB
1314
print bytes_readable(1181116006.4); # 1.10 GB
1315
print bytes_readable(1209462790553.6); # 1.10 TB
1316
print bytes_readable(1088516511498.24*1000); # 990.00 TB
1317
1318
=cut
1319
1320
sub bytes_readable {
1321
7
7
1
4727
my $bytes=shift();
1322
7
50
34
return undef if !defined $bytes;
1323
7
100
55
return "$bytes B" if abs($bytes)<=2** 0*1000; #bytes
1324
5
100
52
return sprintf("%.2f kB",$bytes/2**10) if abs($bytes)<2**10*1000; #kilobyte
1325
4
100
37
return sprintf("%.2f MB",$bytes/2**20) if abs($bytes)<2**20*1000; #megabyte
1326
3
100
33
return sprintf("%.2f GB",$bytes/2**30) if abs($bytes)<2**30*1000; #gigabyte
1327
2
50
51
return sprintf("%.2f TB",$bytes/2**40) if abs($bytes)<2**40*1000; #terrabyte
1328
0
0
return sprintf("%.2f PB",$bytes/2**50); #petabyte, exabyte, zettabyte, yottabyte
1329
}
1330
1331
=head2 int2roman
1332
1333
Converts integers to roman numbers.
1334
1335
B
1336
1337
print int2roman(1234); # prints MCCXXXIV
1338
print int2roman(1971); # prints MCMLXXI
1339
1340
(Adapted subroutine from Peter J. Acklam, jacklam(&)math.uio.no)
1341
1342
I = 1
1343
V = 5
1344
X = 10
1345
L = 50
1346
C = 100 (centum)
1347
D = 500
1348
M = 1000 (mille)
1349
1350
See also L.
1351
1352
See L for more.
1353
1354
=head2 roman2int
1355
1356
roman2int("MCMLXXI") == 1971
1357
1358
=cut
1359
1360
#alternative algorithm: http://www.rapidtables.com/convert/number/how-number-to-roman-numerals.htm
1361
sub int2roman {
1362
1161
1161
1
9018
my($n,@p)=(shift,[],[1],[1,1],[1,1,1],[1,2],[2],[2,1],[2,1,1],[2,1,1,1],[1,3],[3]);
1363
!defined($n)? undef
1364
: !length($n) ? ""
1365
: int($n)!=$n ? croak"int2roman: $n is not an integer"
1366
: $n==0 ? ""
1367
: $n<0 ? "-".int2roman(-$n)
1368
: $n>3999 ? "M".int2roman($n-1000)
1369
1161
100
6219
: join'',@{[qw/I V X L C D M/]}[map{my$i=$_;map($_+5-$i*2,@{$p[$n/10**(3-$i)%10]})}(0..3)];
913
100
6024
3652
100
4160
3652
50
3787
3652
100
11202
100
1370
}
1371
1372
sub roman2int {
1373
1017
1017
1
7468
my($r,$n,%c)=(shift,0,'',0,qw/I 1 V 5 X 10 L 50 C 100 D 500 M 1000/);
1374
1017
100
66
4307
$r=~s/^-//?-roman2int($r):
1375
$r=~s/(C?)([DM])|(X?)([LCDM])|(I?)([VXLCDM])|(I)|(.)/
1376
croak "roman2int: Invalid number $r" if $8;
1377
$n += $c{$2||$4||$6||$7} - $c{$1||$3||$5||''}; ''/eg && $n
1378
}
1379
1380
#sub roman2int_slow {
1381
# my $r=shift;
1382
# $r=~s,^\-,, ? 0-roman2int($r)
1383
# : $r=~s,^M,,i ? 1000+roman2int($r)
1384
# : $r=~s,^CM,,i ? 900+roman2int($r)
1385
# : $r=~s,^D,,i ? 500+roman2int($r)
1386
# : $r=~s,^CD,,i ? 400+roman2int($r)
1387
# : $r=~s,^C,,i ? 100+roman2int($r)
1388
# : $r=~s,^XC,,i ? 90+roman2int($r)
1389
# : $r=~s,^L,,i ? 50+roman2int($r)
1390
# : $r=~s,^XL,,i ? 40+roman2int($r)
1391
# : $r=~s,^X,,i ? 10+roman2int($r)
1392
# : $r=~s,^IX,,i ? 9+roman2int($r)
1393
# : $r=~s,^V,,i ? 5+roman2int($r)
1394
# : $r=~s,^IV,,i ? 4+roman2int($r)
1395
# : $r=~s,^I,,i ? 1+roman2int($r)
1396
# : !length($r) ? 0
1397
# : croak "Invalid roman number $r";
1398
#}
1399
1400
=head2 distance
1401
1402
B the four decimal numbers of two GPS positions: latutude1, longitude1, latitude2, longitude2
1403
1404
B the air distance in meters between the two points
1405
1406
Calculation is done using the Haversine Formula for spherical distance:
1407
1408
a = sin((lat2-lat1)/2)^2
1409
+ sin((lon2-lon1)/2)^2 * cos(lat1) * cos(lat2);
1410
1411
c = 2 * atan2(min(1,sqrt(a)),
1412
min(1,sqrt(1-a)))
1413
1414
distance = c * R
1415
1416
With earth radius set to:
1417
1418
R = Re - (Re-Rp) * sin(abs(lat1+lat2)/2)
1419
1420
Where C (equatorial radius) and C (polar radius).
1421
1422
B
1423
1424
my @oslo = ( 59.93937, 10.75135); # oslo in norway
1425
my @rio = (-22.97673, -43.19508); # rio in brazil
1426
1427
printf "%.1f km\n", distance(@oslo,@rio)/1000; # 10431.7 km
1428
printf "%.1f km\n", distance(@rio,@oslo)/1000; # 10431.7 km
1429
printf "%.1f nmi\n", distance(@oslo,@rio)/1852.000; # 5632.7 nmi (nautical miles)
1430
printf "%.1f miles\n",distance(@oslo,@rio)/1609.344; # 6481.9 miles
1431
printf "%.1f miles\n",conv(distance(@oslo,@rio),"meters","miles");# 6481.9 miles
1432
1433
See L
1434
1435
and L
1436
1437
and L
1438
1439
and L, but Acme::Tools::distance() is about 8 times faster.
1440
1441
=cut
1442
1443
our $Distance_factor = $PI / 180;
1444
0
0
0
0
sub acos { atan2( sqrt(1 - $_[0] * $_[0]), $_[0] ) }
1445
sub distance_great_circle {
1446
0
0
0
0
my($lat1,$lon1,$lat2,$lon2)=map $Distance_factor*$_, @_;
1447
0
0
my($Re,$Rp)=( 6378137.0, 6356752.3 ); #earth equatorial and polar radius
1448
0
0
my $R=$Re-($Re-$Rp)*sin(abs($lat1+$lat2)/2); #approx
1449
0
0
return $R*acos(sin($lat1)*sin($lat2)+cos($lat1)*cos($lat2)*cos($lon2-$lon1))
1450
}
1451
1452
sub distance {
1453
4
4
1
1791
my($lat1,$lon1,$lat2,$lon2)=map $Distance_factor*$_, @_;
1454
4
1500
my $a= sin(($lat2-$lat1)/2)**2
1455
+ sin(($lon2-$lon1)/2)**2 * cos($lat1) * cos($lat2);
1456
4
50
9
my $sqrt_a =sqrt($a); $sqrt_a =1 if $sqrt_a >1;
4
12
1457
4
50
8
my $sqrt_1ma=sqrt(1-$a); $sqrt_1ma=1 if $sqrt_1ma>1;
4
10
1458
4
34
my $c=2*atan2($sqrt_a,$sqrt_1ma);
1459
4
7
my($Re,$Rp)=( 6378137.0, 6356752.3 ); #earth equatorial and polar radius
1460
4
10
my $R=$Re-($Re-$Rp)*sin(abs($lat1+$lat2)/2); #approx
1461
4
21
return $c*$R;
1462
}
1463
1464
1465
=head2 big
1466
1467
=head2 bigi
1468
1469
=head2 bigf
1470
1471
=head2 bigr
1472
1473
=head2 bigscale
1474
1475
big, bigi, bigf, bigr and bigscale are sometimes convenient shorthands for using
1476
C<< Math::BigInt->new() >>, C<< Math::BigFloat->new() >> and C<< Math::BigRat->new() >>
1477
(preferably with the GMP for faster calculations). Examples:
1478
1479
my $num1 = big(3); #returns a new Math::BigInt-object
1480
my $num2 = big('3.0'); #returns a new Math::BigFloat-object
1481
my $num3 = big(3.0); #returns a new Math::BigInt-object
1482
my $num4 = big(3.1); #returns a new Math::BigFloat-object
1483
my $num5 = big('2/7'); #returns a new Math::BigRat-object
1484
my($i1,$f1,$i2,$f2) = big(3,'3.0',3.0,3.1); #returns the four new numbers, as the above four lines
1485
#uses wantarray
1486
1487
print 2**200; # 1.60693804425899e+60
1488
print big(2)**200; # 1606938044258990275541962092341162602522202993782792835301376
1489
print 2**big(200); # 1606938044258990275541962092341162602522202993782792835301376
1490
print big(2**200); # 1606938044258990000000000000000000000000000000000000000000000
1491
1492
print 1/7; # 0.142857142857143
1493
print 1/big(7); # 0 because of integer arithmetics
1494
print 1/big(7.0); # 0 because 7.0 is viewed as an integer
1495
print 1/big('7.0'); # 0.1428571428571428571428571428571428571429
1496
print 1/bigf(7); # 0.1428571428571428571428571428571428571429
1497
print bigf(1/7); # 0.142857142857143 probably not what you wanted
1498
1499
print 1/bigf(7); # 0.1428571428571428571428571428571428571429
1500
bigscale(80); # for increased precesion (default is 40)
1501
print 1/bigf(7); # 0.14285714285714285714285714285714285714285714285714285714285714285714285714285714
1502
1503
In C the characters C<< . >> and C<< / >> will make it return a
1504
Math::BigFloat- and Math::BigRat-object accordingly. Or else a Math::BigInt-object is returned.
1505
1506
Instead of guessing, use C, C and C to return what you want.
1507
1508
B Acme::Tools does not depend on Math::BigInt and
1509
Math::BigFloat and GMP, but these four big*-subs do (by C).
1510
To use big, bigi, bigf and bigr effectively you should
1511
install Math::BigInt::GMP and Math::BigFloat::GMP like this:
1512
1513
sudo cpanm Math::BigFloat Math::GMP Math::BingInt::GMP # or
1514
sudo cpan Math::BigFloat Math::GMP Math::BingInt::GMP # or
1515
sudo yum install perl-Math-BigInt-GMP perl-Math-GMP # on RedHat, RHEL or
1516
sudo apt-get install libmath-bigint-gmp-perl libmath-gmp-perl # on Ubuntu or some other way
1517
1518
Unless GMP is installed for perl like this, the Math::Big*-modules
1519
will fall back to using similar but slower built in modules. See: L
1520
1521
=cut
1522
1523
sub bigi {
1524
9
100
9
1
239
eval q(use Math::BigInt try=>"GMP") if !$INC{'Math/BigInt.pm'};
2
2
30595
2
28441
2
281
1525
9
100
27827
if (wantarray) { return (map Math::BigInt->new($_),@_) }
2
12
1526
7
32
else { return Math::BigInt->new($_[0]) }
1527
}
1528
sub bigf {
1529
7
100
7
1
1634
eval q(use Math::BigFloat try=>"GMP") if !$INC{'Math/BigFloat.pm'};
2
2
36896
2
24380
2
607
1530
7
100
1234
if (wantarray) { return (map Math::BigFloat->new($_),@_) }
2
10
1531
5
21
else { return Math::BigFloat->new($_[0]) }
1532
}
1533
sub bigr {
1534
17
100
17
1
15557
eval q(use Math::BigRat try=>"GMP") if !$INC{'Math/BigRat.pm'};
2
2
2674
2
12382
2
509
1535
17
100
1594
if (wantarray) { return (map Math::BigRat->new($_),@_) }
7
30
1536
10
35
else { return Math::BigRat->new($_[0]) }
1537
}
1538
sub big {
1539
wantarray
1540
12
50
12
1
5981
? (map /\./ ? bigf($_) : /\// ? bigr($_) : bigi($_), @_)
100
100
100
100
1541
: $_[0]=~/\./ ? bigf($_[0]) : $_[0]=~/\// ? bigr($_[0]) : bigi($_[0]);
1542
}
1543
sub bigscale {
1544
4
100
4
1
3795
@_==1 or croak "bigscale requires one and only one argument";
1545
2
5
my $scale=shift();
1546
2
50
9
eval q(use Math::BigInt try=>"GMP") if !$INC{'Math/BigInt.pm'};
1547
2
50
7
eval q(use Math::BigFloat try=>"GMP") if !$INC{'Math/BigFloat.pm'};
1548
2
50
8
eval q(use Math::BigRat try=>"GMP") if !$INC{'Math/BigRat.pm'};
1549
2
10
Math::BigInt->div_scale($scale);
1550
2
38
Math::BigFloat->div_scale($scale);
1551
2
28
Math::BigRat->div_scale($scale);
1552
2
24
return;
1553
}
1554
1555
#my $R_authalic=6371007.2; #earth radius in meters, mean, Authalic radius, real R varies 6353-6384km, http://en.wikipedia.org/wiki/Earth_radius
1556
#*)
1557
# ( 6378157.5, 6356772.2 ) #hmm
1558
#my $e=0.081819218048345;#sqrt(1 - $b**2/$a**2); #eccentricity of the ellipsoid
1559
#my($a,$b)=( 6378137.0, 6356752.3 ); #earth equatorial and polar radius
1560
#warn "e=$e\n";
1561
#warn "t=".(1 - $e**2)."\n";
1562
#warn "n=".((1 - $e**2 * sin(($lat1+$lat1)/2)**2)**1.5)."\n";
1563
#my $t=1 - $e**2;
1564
#my $n=(1 - $e**2 * sin(($lat1+$lat1)/2)**2)**1.5;
1565
#warn "t=$t\n";
1566
#warn "n=$n\n";
1567
#$a * (1 - $e**2) / ((1 - $e**2 * sin(($lat1+$lat2)/2)**2)**1.5); #hmm avg lat
1568
#$R=$a * $t/$n;
1569
1570
#=head2 fractional
1571
#=cut
1572
1573
sub fractional { #http://mathcentral.uregina.ca/QQ/database/QQ.09.06/h/lil1.html
1574
0
0
0
0
carp "fractional: NOT FINISHED";
1575
0
0
my $n=shift;
1576
0
0
print "----fractional n=$n\n";
1577
0
0
my $nn=$n; my $dec;
0
0
1578
0
0
$nn=~s,\.(\d+)$,$dec=length($1);$1.,;
1579
0
0
my $l;
1580
0
0
my $max=0;
1581
0
0
my($te,$ne);
1582
0
0
for(1..length($nn)/2){
1583
0
0
0
if( $nn=~/^(\d*?)((.{$_})(\3)+)$/ ){
1584
0
0
print "_ = $_ ".length($2)."\n";
1585
0
0
0
if(length($2)>$max){
1586
0
0
$l=$_;
1587
0
0
$te="$1$3"-$1;
1588
0
0
$max=length($2);
1589
}
1590
}
1591
}
1592
0
0
0
0
return fractional($n) if !$l and !recursed() and $dec>6 and substr($n,-1) and substr($n,-1)--;
0
0
0
1593
0
0
print "l=$l max=$max\n";
1594
0
0
$ne="9" x $l;
1595
0
0
print log($n),"\n";
1596
0
0
0
my $st=sub{print "status: ".($te/$ne)." n=$n ".($n/$te*$ne)."\n"};
0
0
1597
0
0
while($n/$te*$ne<0.99){ &$st(); $ne*=10 }
0
0
0
0
1598
0
0
while($te/$n/$ne<0.99){ &$st(); $te*=10 }
0
0
0
0
1599
0
0
&$st();
1600
0
0
while(1){
1601
0
0
my $d=gcd($te,$ne); print "gcd=$d\n";
0
0
1602
0
0
0
last if $d==1;
1603
0
0
$te/=$d; $ne/=$d;
0
0
1604
}
1605
0
0
&$st();
1606
0
0
0
wantarray ? ($te,$ne) : "$te/$ne"; #gcd()
1607
}
1608
1609
=head2 isnum
1610
1611
B String to be tested on regexp C<< /^ \s* [\-\+]? (?: \d*\.\d+ | \d+ ) (?:[eE][\-\+]?\d+)?\s*$/x >>. If no argument is given isnum checks C<< $_ >>.
1612
1613
B True or false (1 or 0)
1614
1615
=cut
1616
1617
our $Re_isnum=qr/^ \s* [\-\+]? (?: \d*\.\d+ | \d+ ) (?:[eE][\-\+]?\d+)?\s*$/x;
1618
20
100
20
1
11390
sub isnum {(@_?$_[0]:$_)=~$Re_isnum}
1619
1620
=head2 between
1621
1622
Input: Three arguments.
1623
1624
Returns: Something I if the first argument is numerically between the two next.
1625
1626
=cut
1627
1628
sub between {
1629
27
27
1
10924
my($test,$fom,$tom)=@_;
1630
28
28
208
no warnings;
28
58
28
6396
1631
27
100
66
488
return $fom<$tom ? $test>=$fom&&$test<=$tom
33
1632
: $test>=$tom&&$test<=$fom;
1633
}
1634
1635
=head2 curb
1636
1637
B Three arguments: value, minumum, maximum.
1638
1639
B Returns the value if its between the given minumum and maximum.
1640
Returns minimum if the value is less or maximum if the value is more.
1641
1642
my $v = 234;
1643
print curb( $v, 200, 250 ); #prints 234
1644
print curb( $v, 150, 200 ); #prints 200
1645
print curb( $v, 250, 300 ); #prints 250
1646
print curb(\$v, 250, 300 ); #prints 250 and changes $v
1647
print $v; #prints 250
1648
1649
In the last example $v is changed because the argument is a reference. (To keep backward compatability, C<< bound() >> is a synonym for C<< curb() >>)
1650
1651
=cut
1652
1653
sub curb {
1654
129
129
1
1215
my($val,$min,$max)=@_;
1655
129
50
66
1631
croak "curb: wrong args" if @_!=3 or !defined$min or !defined$max or !defined$val or $min>$max;
100
66
66
1656
126
100
287
return $$val=curb($$val,$min,$max) if ref($val) eq 'SCALAR';
1657
125
100
339
$val < $min ? $min :
100
1658
$val > $max ? $max :
1659
$val;
1660
}
1661
0
0
0
0
sub bound { curb(@_) }
1662
1663
=head1 STRINGS
1664
1665
=head2 upper
1666
1667
=head2 lower
1668
1669
Returns input string as uppercase or lowercase.
1670
1671
Can be used if Perls build in C and C for some reason does not convert æøå or other latin letters outsize a-z.
1672
1673
Converts C<< æøåäëïöüÿâêîôûãõàèìòùáéíóúýñð >> to and from C<< ÆØÅÄËÏÖÜ?ÂÊÎÔÛÃÕÀÈÌÒÙÁÉÍÓÚÝÑÐ >>
1674
1675
See also C<< perldoc -f uc >> and C<< perldoc -f lc >>
1676
1677
=head2 trim
1678
1679
Removes space from the beginning and end of a string. Whitespace (C<< \s >>) that is.
1680
And removes any whitespace inside the string of more than one char, leaving the first whitespace char. Thus:
1681
1682
trim(" asdf \t\n 123 ") eq "asdf 123"
1683
trim(" asdf\t\n 123\n") eq "asdf\t123"
1684
1685
Works on C<< $_ >> if no argument i given:
1686
1687
print join",", map trim, " please ", " remove ", " my ", " spaces "; # please,remove,my,spaces
1688
print join",", trim(" please ", " remove ", " my ", " spaces "); # works on arrays as well
1689
my $s=' please '; trim(\$s); # now $s eq 'please'
1690
trim(\@untrimmedstrings); # trims array strings inplace
1691
@untrimmedstrings = map trim, @untrimmedstrings; # same, works on $_
1692
trim(\$_) for @untrimmedstrings; # same, works on \$_
1693
1694
=head2 lpad
1695
1696
=head2 rpad
1697
1698
Left or right pads a string to the given length by adding one or more spaces at the end for I or at the start for I.
1699
1700
B First argument: string to be padded. Second argument: length of the output. Optional third argument: character(s) used to pad.
1701
Default is space.
1702
1703
rpad('gomle',9); # 'gomle '
1704
lpad('gomle',9); # ' gomle'
1705
rpad('gomle',9,'-'); # 'gomle----'
1706
lpad('gomle',9,'+'); # '++++gomle'
1707
rpad('gomle',4); # 'goml'
1708
lpad('gomle',4); # 'goml'
1709
rpad('gomle',7,'xyz'); # 'gomlxy'
1710
lpad('gomle',10,'xyz'); # 'xyzxygoml'
1711
1712
=head2 cpad
1713
1714
Center pads. Pads the string both on left and right equal to the given length. Centers the string. Pads right side first.
1715
1716
cpad('mat',5) eq ' mat '
1717
cpad('mat',4) eq 'mat '
1718
cpad('mat',6) eq ' mat '
1719
cpad('mat',9) eq ' mat '
1720
cpad('mat',5,'+') eq '+mat+'
1721
cpad('MMMM',20,'xyzXYZ') eq 'xyzXYZxyMMMMxyzXYZxy'
1722
1723
=cut
1724
1725
28
50
28
1
156
sub upper {no warnings;my $s=@_?shift:$_;$s=~tr/a-zæøåäëïöüÿâêîôûãõàèìòùáéíóúýñð/A-ZÆØÅÄËÏÖÜÿÂÊÎÔÛÃÕÀÈÌÒÙÁÉÍÓÚÝÑÐ/;$s}
28
1
66
28
2348
1
5
1
4
1
5
1726
28
50
28
1
171
sub lower {no warnings;my $s=@_?shift:$_;$s=~tr/A-ZÆØÅÄËÏÖÜÿÂÊÎÔÛÃÕÀÈÌÒÙÁÉÍÓÚÝÑÐ/a-zæøåäëïöüÿâêîôûãõàèìòùáéíóúýñð/;$s}
28
1
72
28
86147
1
4
1
3
1
6
1727
1728
sub trim {
1729
24
100
24
1
74
return trim($_) if !@_;
1730
20
100
50
return map trim($_), @_ if @_>1;
1731
19
28
my $s=shift;
1732
19
100
46
if(ref($s) eq 'SCALAR'){ $$s=~s,^\s+|(?<=\s)\s+|\s+$,,g; return $$s}
5
25
5
14
1733
14
100
31
if(ref($s) eq 'ARRAY') { trim(\$_) for @$s; return $s }
1
4
1
3
1734
13
94
$s=~s,^\s+|(?<=\s)\s+|\s+$,,g;
1735
13
63
$s;
1736
}
1737
1738
sub rpad {
1739
4
4
1
795
my($s,$l,$p)=@_;
1740
4
100
66
20
$p=' ' if @_<3 or !length($p);
1741
4
23
$s.=$p while length($s)<$l;
1742
4
20
substr($s,0,$l);
1743
}
1744
1745
sub lpad {
1746
5
5
1
1384
my($s,$l,$p)=@_;
1747
5
100
66
24
$p=' ' if @_<3 or !length($p);
1748
5
100
34
$l
1749
? substr($s,0,$l)
1750
: substr($p x (1+$l/length($p)), 0, $l-length($s)).$s;
1751
}
1752
1753
sub cpad {
1754
11
11
1
2894
my($s,$l,$p)=@_;
1755
11
100
66
48
$p=' ' if @_<3 or !length($p);
1756
11
16
my $ls=length($s);
1757
11
50
20
return substr($s,0,$l) if $l<$ls;
1758
11
29
$p=$p x (($l-$ls+2)/length($p));
1759
11
63
substr($p, 0, ($l-$ls )/2) . $s .
1760
substr($p, 0, ($l-$ls+1)/2);
1761
}
1762
1763
sub cpad_old {
1764
0
0
0
0
my($s,$l,$p)=@_;
1765
0
0
0
$p=' ' if !length($p);
1766
0
0
0
return substr($s,0,$l) if $l
1767
0
0
my $i=0;
1768
0
0
while($l>length($s)){
1769
0
0
0
my $pc=substr($p,($i==int($i)?1:-1)*($i%length($p)),1);
1770
0
0
0
$i==int($i) ? ($s.=$pc) : ($s=$pc.$s);
1771
0
0
$i+=1/2;
1772
}
1773
0
0
$s;
1774
}
1775
1776
=head2 trigram
1777
1778
B A string (i.e. a name). And an optional x (see example 2)
1779
1780
B A list of this strings trigrams (See examlpe)
1781
1782
B
1783
1784
print join ", ", trigram("Kjetil Skotheim");
1785
1786
Prints:
1787
1788
Kje, jet, eti, til, il , l S, Sk, Sko, kot, oth, the, hei, eim
1789
1790
B
1791
1792
Default is 3, but here 4 is used instead in the second optional input argument:
1793
1794
print join ", ", trigram("Kjetil Skotheim", 4);
1795
1796
And this prints:
1797
1798
Kjet, jeti, etil, til , il S, l Sk, Sko, Skot, koth, othe, thei, heim
1799
1800
C was created for "fuzzy" name searching. If you have a database of many names,
1801
addresses, phone numbers, customer numbers etc. You can use trigram() to search
1802
among all of those at the same time. If the search form only has one input field.
1803
One general search box.
1804
1805
Store all of the trigrams of the trigram-indexed input fields coupled
1806
with each person, and when you search, you take each trigram of you
1807
query string and adds the list of people that has that trigram. The
1808
search result should then be sorted so that the persons with most hits
1809
are listed first. Both the query strings and the indexed database
1810
fields should have a space added first and last before C-ing
1811
them.
1812
1813
This search algorithm is not includes here yet...
1814
1815
C should perhaps have been named ngram for obvious reasons.
1816
1817
=head2 sliding
1818
1819
Same as trigram (except there is no default width). Works also with arrayref instead of string.
1820
1821
Example:
1822
1823
sliding( ["Reven","rasker","over","isen"], 2 )
1824
1825
Result:
1826
1827
( ['Reven','rasker'], ['rasker','over'], ['over','isen'] )
1828
1829
=head2 chunks
1830
1831
Splits strings and arrays into chunks of given size:
1832
1833
my @a = chunks("Reven rasker over isen",7);
1834
my @b = chunks([qw/Og gubben satt i kveldinga og koste seg med skillinga/], 3);
1835
1836
Resulting arrays:
1837
1838
( 'Reven r', 'asker o', 'ver ise', 'n' )
1839
( ['Og','gubben','satt'], ['i','kveldinga','og'], ['koste','seg','med'], ['skillinga'] )
1840
1841
=head2 chars
1842
1843
chars("Tittentei"); # ('T','i','t','t','e','n','t','e','i')
1844
1845
=cut
1846
1847
2
100
2
1
20
sub trigram { sliding($_[0],$_[1]||3) }
1848
1849
sub sliding {
1850
3
3
1
6
my($s,$w)=@_;
1851
3
100
35
return map substr($s,$_,$w), 0..length($s)-$w if !ref($s);
1852
1
50
19
return map [@$s[$_..$_+$w-1]], 0..@$s-$w if ref($s) eq 'ARRAY';
1853
}
1854
1855
sub chunks {
1856
2
2
1
6
my($s,$w)=@_;
1857
2
100
33
return $s=~/(.{1,$w})/g if !ref($s);
1858
1
50
14
return map [@$s[$_*$w .. min($_*$w+$w-1,$#$s)]], 0..$#$s/$w if ref($s) eq 'ARRAY';
1859
}
1860
1861
0
0
1
0
sub chars { split//, shift }
1862
1863
=head2 repl
1864
1865
Synonym for replace().
1866
1867
=head2 replace
1868
1869
Return the string in the first input argument, but where pairs of search-replace strings (or rather regexes) has been run.
1870
1871
Works as C in Oracle, or rather regexp_replace() in Oracle 10 and onward. Except that this C accepts more than three arguments.
1872
1873
Examples:
1874
1875
print replace("water","ater","ine"); # Turns water into wine
1876
print replace("water","ater"); # w
1877
print replace("water","at","eath"); # weather
1878
print replace("water","wa","ju",
1879
"te","ic",
1880
"x","y", # No x is found, no y is returned
1881
'r$',"e"); # Turns water into juice. 'r$' says that the r it wants
1882
# to change should be the last letters. This reveals that
1883
# second, fourth, sixth and so on argument is really regexs,
1884
# not normal strings. So use \ (or \\ inside "") to protect
1885
# the special characters of regexes. You probably also
1886
# should write qr/regexp/ instead of 'regexp' if you make
1887
# use of regexps here, just to make it more clear that
1888
# these are really regexps, not strings.
1889
1890
print replace('JACK and JUE','J','BL'); # prints BLACK and BLUE
1891
print replace('JACK and JUE','J'); # prints ACK and UE
1892
print replace("abc","a","b","b","c"); # prints ccc (not bcc)
1893
1894
If the first argument is a reference to a scalar variable, that variable is changed "in place".
1895
1896
Example:
1897
1898
my $str="test";
1899
replace(\$str,'e','ee','s','S');
1900
print $str; # prints teeSt
1901
1902
=cut
1903
1904
46
46
1
105
sub replace { repl(@_) }
1905
sub repl {
1906
69
69
1
142
my $str=shift;
1907
69
100
165
return $$str=replace($$str,@_) if ref($str) eq 'SCALAR';
1908
#return ? if ref($str) eq 'ARRAY';
1909
#return ? if ref($str) eq 'HASH';
1910
68
157
while(@_){
1911
82
153
my($fra,$til)=(shift,shift);
1912
82
100
5308
defined $til ? $str=~s/$fra/$til/g : $str=~s/$fra//g;
1913
}
1914
68
500
return $str;
1915
}
1916
1917
1918
=head1 ARRAYS
1919
1920
=head2 min
1921
1922
Returns the smallest number in a list. Undef is ignored.
1923
1924
@lengths=(2,3,5,2,10,undef,5,4);
1925
$shortest = min(@lengths); # returns 2
1926
1927
Note: The comparison operator is perls C<< < >>> which means empty strings is treated as C<0>, the number zero. The same goes for C, except of course C<< > >> is used instead.
1928
1929
min(3,4,5) # 3
1930
min(3,4,5,undef) # 3
1931
min(3,4,5,'') # returns the empty string
1932
1933
=head2 max
1934
1935
Returns the largest number in a list. Undef is ignored.
1936
1937
@heights=(123,90,134,undef,132);
1938
$highest = max(@heights); # 134
1939
1940
=head2 mins
1941
1942
Just as L, except for strings.
1943
1944
print min(2,7,10); # 2
1945
print mins("2","7","10"); # 10
1946
print mins(2,7,10); # 10
1947
1948
=head2 maxs
1949
1950
Just as L, except for strings.
1951
1952
print max(2,7,10); # 10
1953
print maxs("2","7","10"); # 7
1954
print maxs(2,7,10); # 7
1955
1956
=cut
1957
1958
35
100
100
35
1
1760
sub min {my $min;for(@_){ $min=$_ if defined($_) and !defined($min) || $_ < $min } $min }
35
66
75
7087
31902
35
247
1959
1
100
100
1
1
2
sub mins {my $min;for(@_){ $min=$_ if defined($_) and !defined($min) || $_ lt $min} $min }
1
33
3
3
22
1
5
1960
26
100
100
26
1
42
sub max {my $max;for(@_){ $max=$_ if defined($_) and !defined($max) || $_ > $max } $max }
26
66
55
7069
32019
26
285
1961
1
100
100
1
1
3
sub maxs {my $max;for(@_){ $max=$_ if defined($_) and !defined($max) || $_ gt $max} $max }
1
33
3
3
22
1
4
1962
1963
=head2 zip
1964
1965
B Two or more arrayrefs. A number of equal sized arrays
1966
containing numbers, strings or anything really.
1967
1968
B An array of those input arrays zipped (interlocked, merged) into each other.
1969
1970
print join " ", zip( [1,3,5], [2,4,6] ); # 1 2 3 4 5 6
1971
print join " ", zip( [1,4,7], [2,5,8], [3,6,9] ); # 1 2 3 4 5 6 7 8 9
1972
1973
Example:
1974
1975
zip() creates a hash where the keys are found in the first array and values in the secord in the correct order:
1976
1977
my @media = qw/CD DVD VHS LP Blueray/;
1978
my @count = qw/20 12 2 4 3/;
1979
my %count = zip(\@media,\@count); # or zip( [@media], [@count] )
1980
print "I got $count{DVD} DVDs\n"; # I got 12 DVDs
1981
1982
Dies (croaks) if the two lists are of different sizes
1983
1984
...or any input argument is not an array ref.
1985
1986
=cut
1987
1988
sub zip {
1989
7
7
1
74509
my @t=@_;
1990
7
66
328
ref($_) ne 'ARRAY' and croak "ERROR: zip should have arrayrefs as arguments" for @t;
1991
5
66
17
@{$t[$_]} != @{$t[0]} and croak "ERROR: zip should have equal sized arrays" for 1..$#t;
5
8
5
215
1992
3
5
my @res;
1993
3
5
for my $i (0..@{$t[0]}-1){
3
8
1994
9
28
push @res, $$_[$i] for @t;
1995
}
1996
3
21
return @res;
1997
}
1998
1999
2000
=head2 pushsort
2001
2002
Adds one or more element to a numerically sorted array and keeps it sorted.
2003
2004
pushsort @a, 13; # this...
2005
push @a, 13; @a = sort {$a<=>$b} @a; # is the same as this, but the former is faster if @a is large
2006
2007
=head2 pushsortstr
2008
2009
Same as pushsort except that the array is kept sorted alphanumerically (cmp) instead of numerically (<=>). See L.
2010
2011
pushsort @a, "abc"; # this...
2012
push @a, "abc"; @a = sort @a; # is the same as this, but the former is faster if @a is large
2013
2014
=cut
2015
2016
our $Pushsort_cmpsub=undef;
2017
sub pushsort (\@@) {
2018
10915
10915
1
18082
my $ar=shift;
2019
2020
#not needed but often faster
2021
10915
100
100
32419
if(!defined $Pushsort_cmpsub and @$ar+@_<100){ #hm speedup?
2022
2348
4690
@$ar=(sort {$a<=>$b} (@$ar,@_));
51956
59714
2023
2348
4684
return 0+@$ar;
2024
}
2025
2026
8567
13067
for my $v (@_){
2027
2028
#not needed but often faster
2029
7567
100
14284
if(!defined $Pushsort_cmpsub){ #faster rank() in most cases
2030
901
100
50
1837
push @$ar, $v and next if $v>=$$ar[-1];
2031
898
100
50
2047
unshift @$ar, $v and next if $v< $$ar[0];
2032
}
2033
2034
7558
14327
splice @$ar, binsearch($v,$ar,1,$Pushsort_cmpsub)+1, 0, $v;
2035
}
2036
8567
16316
0+@$ar
2037
}
2038
0
0
1
0
sub pushsortstr(\@@){ local $Pushsort_cmpsub=sub{$_[0]cmp$_[1]}; pushsort(@_) } #speedup: copy sub pushsort
1000
1000
3862
1000
2063
2039
2040
=head2 binsearch
2041
2042
Returns the position of an element in a numerically sorted array. Returns undef if the element is not found.
2043
2044
B Two, three or four arguments
2045
2046
B the element to find. Usually a number.
2047
2048
B a reference to the array to search in. The array
2049
should be sorted in ascending numerical order (se exceptions below).
2050
2051
B Optional. Default false.
2052
2053
If present, whether result I should return undef or a fractional position.
2054
2055
If the third argument is false binsearcg returns undef if the element is not found.
2056
2057
If the third argument is true binsearch returns 0.5 plus closest position below the searched value.
2058
2059
Returns C< last position + 0.5 > if the searched element is greater than all elements in the sorted array.
2060
2061
Returns C< -0.5 > if the searched element is less than all elements in the sorted array.
2062
2063
Fourth argument: Optional. Default C<< sub { $_[0] <=> $_[1] } >>.
2064
2065
If present, the fourth argument is a code-ref that alters the way binsearch compares two elements.
2066
2067
B
2068
2069
binsearch(10,[5,10,15,20]); # 1
2070
binsearch(10,[20,15,10,5],undef,sub{$_[1]<=>$_[0]}); # 2 search arrays sorted numerically in opposite order
2071
binsearch("c",["a","b","c","d"],undef,sub{$_[0]cmp$_[1]}); # 2 search arrays sorted alphanumerically
2072
binsearchstr("b",["a","b","c","d"]); # 1 search arrays sorted alphanumerically
2073
2074
=head2 binsearchstr
2075
2076
Same as binsearch except that the arrays is sorted alphanumerically
2077
(cmp) instead of numerically (<=>) and the searched element is a
2078
string, not a number. See L.
2079
2080
=cut
2081
2082
our $Binsearch_steps;
2083
our $Binsearch_maxsteps=100;
2084
sub binsearch {
2085
14603
14603
1
50019
my($search,$aref,$insertpos,$cmpsub)=@_; #search pos of search in array
2086
14603
50
33653
croak "binsearch did not get arrayref as second arg" if ref($aref) ne 'ARRAY';
2087
14603
50
66
42691
croak "binsearch got fourth arg which is not a code-ref" if $cmpsub and ref($cmpsub) ne 'CODE';
2088
14603
50
26570
return $insertpos ? -0.5 : undef if !@$aref;
100
2089
14591
20571
my($min,$max)=(0,$#$aref);
2090
14591
18924
$Binsearch_steps=0;
2091
14591
30175
while (++$Binsearch_steps <= $Binsearch_maxsteps) {
2092
128669
194631
my $middle=int(($min+$max+0.5)/2);
2093
128669
144580
my $middle_value=$$aref[$middle];
2094
2095
#croak "binsearch got non-sorted array" if !$cmpsub and $$aref[$min]>$$aref[$min]
2096
# or $cmpsub and &$cmpsub($$aref[$min],$$aref[$min])>0;
2097
2098
128669
100
100
748228
if( !$cmpsub and $search < $middle_value
100
100
66
100
100
66
2099
or $cmpsub and &$cmpsub($search,$middle_value) < 0 ) { #print "<\n";
2100
39065
50
66
92919
$max=$min, next if $middle == $max and $min != $max;
2101
39065
50
76541
return $insertpos ? $middle-0.5 : undef if $middle == $max;
100
2102
37589
80384
$max=$middle;
2103
}
2104
elsif( !$cmpsub and $search > $middle_value
2105
or $cmpsub and &$cmpsub($search,$middle_value) > 0 ) { #print ">\n";
2106
82567
100
100
209356
$min=$max, next if $middle == $min and $max != $min;
2107
75062
50
146964
return $insertpos ? $middle+0.5 : undef if $middle == $min;
100
2108
68984
156954
$min=$middle;
2109
}
2110
else { #print "=\n";
2111
7037
17279
return $middle;
2112
}
2113
}
2114
0
0
croak "binsearch exceded $Binsearch_maxsteps steps";
2115
}
2116
2117
sub binsearchfast { # binary search routine finds index just below value
2118
0
0
0
0
my ($x,$v)=@_;
2119
0
0
my ($klo,$khi)=(0,$#{$x});
0
0
2120
0
0
my $k;
2121
0
0
while (($khi-$klo)>1) {
2122
0
0
$k=int(($khi+$klo)/2);
2123
0
0
0
if ($$x[$k]>$v) { $khi=$k; } else { $klo=$k; }
0
0
0
0
2124
}
2125
0
0
return $klo;
2126
}
2127
2128
2129
2
2
1
11
sub binsearchstr {binsearch(@_[0..2],sub{$_[0]cmp$_[1]})}
1
1
9
2130
2131
=head2 rank
2132
2133
B Two or three arguments. N and an arrayref for the list to look at.
2134
2135
In scalar context: Returns the nth smallest number in an array. The array doesn't have to be sorted.
2136
2137
In array context: Returns the n smallest numbers in an array.
2138
2139
To return the n(th) largest number(s) instead of smallest, just negate n.
2140
2141
An optional third argument can be a sub that is used to compare the elements of the input array.
2142
2143
Examples:
2144
2145
my $second_smallest = rank(2, [11,12,13,14]); # 12
2146
my @top10 = rank(-10, [1..100]); # 100, 99, 98, 97, 96, 95, 94, 93, 92, 91
2147
my $max = rank(-1, [101,102,103,102,101]); #103
2148
my @contest = ({name=>"Alice",score=>14},{name=>"Bob",score=>13},{name=>"Eve",score=>12});
2149
my $second = rank(2, \@contest, sub{$_[1]{score}<=>$_[0]{score}})->{name}; #Bob
2150
2151
=head2 rankstr
2152
2153
Just as C but sorts alphanumerically (strings, cmp) instead of numerically.
2154
2155
=cut
2156
2157
sub rank {
2158
35
35
1
498
my($rank,$aref,$cmpsub)=@_;
2159
35
100
77
if($rank<0){
2160
10
100
29957
45
$cmpsub||=sub{$_[0]<=>$_[1]};
29957
146705
2161
10
59997
43
return rank(-$rank,$aref,sub{0-&$cmpsub});
59997
92764
2162
}
2163
25
28
my @sort;
2164
25
35
local $Pushsort_cmpsub=$cmpsub;
2165
25
48
for(@$aref){
2166
8914
16135
pushsort @sort, $_;
2167
8914
100
23121
pop @sort if @sort>$rank;
2168
}
2169
25
100
1484
return wantarray ? @sort : $sort[$rank-1];
2170
}
2171
0
50
0
1
0
sub rankstr {wantarray?(rank(@_,sub{$_[0]cmp$_[1]})):rank(@_,sub{$_[0]cmp$_[1]})}
60067
10
292870
10
61
2172
2173
=head2 eqarr
2174
2175
B Two or more references to arrays.
2176
2177
B True (1) or false (0) for whether or not the arrays are numerically I alphanumerically equal.
2178
Comparing each element in each array with both C< == > and C< eq >.
2179
2180
Examples:
2181
2182
eqarr([1,2,3],[1,2,3],[1,2,3]); # 1 (true)
2183
eqarr([1,2,3],[1,2,3],[1,2,4]); # 0 (false)
2184
eqarr([1,2,3],[1,2,3,4]); # undef (different size, false)
2185
eqarr([1,2,3]); # croak (should be two or more arrays)
2186
eqarr([1,2,3],1,2,3); # croak (not arraysrefs)
2187
2188
=cut
2189
2190
sub eqarr {
2191
27
27
1
491
my @arefs=@_;
2192
27
100
276
croak if @arefs<2;
2193
26
66
245
ref($_) ne 'ARRAY' and croak for @arefs;
2194
25
100
61
@{$arefs[0]} != @{$arefs[$_]} and return undef for 1..$#arefs;
27
52
27
94
2195
24
35
my $ant;
2196
2197
24
75
for my $ar (@arefs[1..$#arefs]){
2198
26
60
for(0..@$ar-1){
2199
272
50
33
967
++$ant and $ant>100 and croak ">100"; #TODO: feiler ved sammenligning av to tabeller > 10000(?) tall
2200
272
100
66
1284
return 0 if $arefs[0][$_] ne $$ar[$_]
2201
or $arefs[0][$_] != $$ar[$_];
2202
}
2203
}
2204
22
137
return 1;
2205
}
2206
2207
=head2 sorted
2208
2209
Return true if the input array is numerically sorted.
2210
2211
@a=(1..10); print "array is sorted" if sorted @a; #true
2212
2213
Optionally the last argument can be a comparison sub:
2214
2215
@person=({Rank=>1,Name=>'Amy'}, {Rank=>2,Name=>'Paula'}, {Rank=>3,Name=>'Ruth'});
2216
print "Persons are sorted" if sorted @person, sub{$_[0]{Rank}<=>$_[1]{Rank}};
2217
2218
=head2 sortedstr
2219
2220
Return true if the input array is Inumerically sorted.
2221
2222
@a=(1..10); print "array is sorted" if sortedstr @a; #false
2223
@a=("01".."10"); print "array is sorted" if sortedstr @a; #true
2224
2225
=cut
2226
2227
sub sorted (\@@) {
2228
4
4
1
13
my($a,$cmpsub)=@_;
2229
4
13
for(0..$#$a-1){
2230
1197
50
66
6421
return 0 if !$cmpsub and $$a[$_]>$$a[$_+1]
66
33
2231
or $cmpsub and &$cmpsub($$a[$_],$$a[$_+1])>0;
2232
}
2233
4
24
return 1;
2234
}
2235
99
99
1
797
sub sortedstr { sorted(@_,sub{$_[0]cmp$_[1]}) }
2
2
17
2236
2237
=head2 part
2238
2239
B A code-ref and a list
2240
2241
B Two array-refs
2242
2243
Like C but returns the false list as well. Partitions a list
2244
into two lists where each element goes into the first or second list
2245
whether the predicate (a code-ref) is true or false for that element.
2246
2247
my( $odd, $even ) = part {$_%2} (1..8);
2248
print for @$odd; #prints 1 3 5 7
2249
print for @$even; #prints 2 4 6 8
2250
2251
(Works like C< partition() > in the Scala programming language)
2252
2253
=head2 parth
2254
2255
Like C but returns any number of lists.
2256
2257
B A code-ref and a list
2258
2259
B A hash where the returned values from the code-ref are keys and the values are arrayrefs to the list elements which gave those keys.
2260
2261
my %hash = parth { uc(substr($_,0,1)) } ('These','are','the','words','of','this','array');
2262
print serialize(\%hash);
2263
2264
Result:
2265
2266
%hash = ( T=>['These','the','this'],
2267
A=>['are','array'],
2268
O=>['of'],
2269
W=>['words'] )
2270
2271
=head2 parta
2272
2273
Like L but returns an array of lists.
2274
2275
my @a = parta { length } qw/These are the words of this array/;
2276
2277
Result:
2278
2279
@a = ( undef, undef, ['of'], ['are','the'], ['this'], ['These','words','array'] )
2280
2281
Two undefs at first (index positions 0 and 1) since there are no words of length 0 or 1 in the input array.
2282
2283
=cut
2284
2285
1
100
1
1
13
sub part (&@) { my($c,@r)=(shift,[],[]); push @{ $r[ &$c?0:1 ] }, $_ for @_; @r }
1
4
8
42
1
6
2286
1
1
1
258
sub parth (&@) { my($c,%r)=(shift); push @{ $r{ &$c } }, $_ for @_; %r }
1
4
7
37
1
9
2287
1
1
1
289
sub parta (&@) { my($c,@r)=(shift); push @{ $r[ &$c ] }, $_ for @_; @r }
1
4
7
34
1
7
2288
2289
#sub mapn (&$@) { ... } like map but @_ contains n elems at a time, n=1 is map
2290
2291
=head1 STATISTICS
2292
2293
=head2 sum
2294
2295
Returns the sum of a list of numbers. Undef is ignored.
2296
2297
print sum(1,3,undef,8); # 12
2298
print sum(1..1000); # 500500
2299
print sum(undef); # undef
2300
2301
=cut
2302
2303
28
66
28
1
179
sub sum { my $sum; no warnings; defined($_) and $sum+=$_ for @_; $sum }
28
45
56
28
2943
45
5074
45
16185
45
454
2304
2305
=head2 avg
2306
2307
Returns the I number of a list of numbers. That is C
2308
2309
print avg( 2, 4, 9); # 5 (2+4+9) / 3 = 5
2310
print avg( [2, 4, 9] ); # 5 pass by reference, same result but faster for large arrays
2311
2312
Also known as I.
2313
2314
Pass by reference: If one argument is given and it is a reference to an array,
2315
this array is taken as the list of numbers. This mode is about twice as fast
2316
for 10000 numbers or more. It most likely also saves memory.
2317
2318
=cut
2319
2320
sub avg {
2321
880
880
1
3568
my($sum,$n,@a)=(0,0);
2322
28
28
382
no warnings;
28
54
28
14487
2323
880
50
1740
if( @_==0 ) { return undef }
0
0
2324
880
100
100
2070
if( @_==1 and ref($_[0]) eq 'ARRAY' ){ @a=grep defined,@{$_[0]} }
1
3
1
6
2325
879
3942
else { @a=grep defined,@_ }
2326
880
100
1553
if( @a==0 ) { return undef }
1
4
2327
879
5597
$sum+=$_ for @a;
2328
879
3983
return $sum/@a
2329
}
2330
2331
=head2 geomavg
2332
2333
Returns the I (a.k.a I) of a list of numbers.
2334
2335
print geomavg(10,100,1000,10000,100000); # 1000
2336
print 0+ (10*100*1000*10000*100000) ** (1/5); # 1000 same thing
2337
print exp(avg(map log($_),10,100,1000,10000,100000)); # 1000 same thing, this is how geomavg() works internally
2338
2339
=cut
2340
2341
771
771
1
3193
sub geomavg { exp(avg(map log($_), @_)) }
2342
2343
=head2 harmonicavg
2344
2345
Returns the I (a.k.a I) of a list of numbers. L
2346
2347
print harmonicavg(10,11,12); # 3 / ( 1/10 + 1/11 + 1/12) = 10.939226519337
2348
2349
=cut
2350
2351
0
0
1
0
sub harmonicavg { my $s; $s+=1/$_ for @_; @_/$s }
0
0
0
0
2352
2353
=head2 variance
2354
2355
C<< variance = ( sum (x[i]-Average)**2)/(n-1) >>
2356
2357
=cut
2358
2359
sub variance {
2360
0
0
1
0
my $sumx2; $sumx2+=$_*$_ for @_;
0
0
2361
0
0
my $sumx; $sumx+=$_ for @_;
0
0
2362
0
0
(@_*$sumx2-$sumx*$sumx)/(@_*(@_-1));
2363
}
2364
2365
=head2 stddev
2366
2367
C<< Standard_Deviation = sqrt(variance) >>
2368
2369
Standard deviation (stddev) is a measurement of the width of a normal
2370
distribution where one stddev on each side of the mean covers 68% and
2371
two stddevs 95%. Normal distributions are sometimes called Gauss curves
2372
or Bell shapes. L
2373
2374
stddev(4,5,6,5,6,4,3,5,5,6,7,6,5,7,5,6,4) # = 1.0914103126635
2375
avg(@testscores) + stddev(@testscores) # = the score for IQ = 115 (by one definition)
2376
avg(@testscores) - stddev(@testscores) # = the score for IQ = 85
2377
2378
=cut
2379
2380
sub stddev {
2381
14
100
14
1
621
return undef if @_==0;
2382
13
100
66
72
return stddev(\@_) if @_>0 and !ref($_[0]);
2383
8
12
my $ar=shift;
2384
8
50
18
return undef if @$ar==0;
2385
8
100
24
return 0 if @$ar==1;
2386
6
6
my $sumx2; $sumx2 += $_*$_ for @$ar;
6
105
2387
6
6
my $sumx; $sumx += $_ for @$ar;
6
68
2388
6
38
sqrt( (@$ar*$sumx2-$sumx*$sumx)/(@$ar*(@$ar-1)) );
2389
}
2390
2391
=head2 median
2392
2393
Returns the median value of a list of numbers. The list do not have to
2394
be sorted.
2395
2396
Example 1, list having an odd number of numbers:
2397
2398
print median(1, 100, 101); # 100
2399
2400
100 is the middlemost number after sorting.
2401
2402
Example 2, an even number of numbers:
2403
2404
print median(1005, 100, 101, 99); # 100.5
2405
2406
100.5 is the average of the two middlemost numbers.
2407
2408
=cut
2409
2410
sub median {
2411
28
28
147
no warnings;
28
48
28
14993
2412
6
6
1
417
my @list = sort {$a<=>$b} @_;
10035
11679
2413
6
8
my $n=@list;
2414
6
100
217
$n%2 ? $list[($n-1)/2]
2415
: ($list[$n/2-1] + $list[$n/2])/2;
2416
}
2417
2418
2419
=head2 percentile
2420
2421
Returns one or more percentiles of a list of numbers.
2422
2423
Percentile 50 is the same as the I, percentile 25 is the first
2424
quartile, 75 is the third quartile.
2425
2426
B
2427
2428
First argument is your wanted percentile, or a refrence to a list of percentiles you want from the dataset.
2429
2430
If the first argument to percentile() is a scalar, this percentile is returned.
2431
2432
If the first argument is a reference to an array, then all those percentiles are returned as an array.
2433
2434
Second, third, fourth and so on argument are the numbers from which you want to find the percentile(s).
2435
2436
B
2437
2438
This finds the 50-percentile (the median) to the four numbers 1, 2, 3 and 4:
2439
2440
print "Median = " . percentile(50, 1,2,3,4); # 2.5
2441
2442
This:
2443
2444
@data=(11, 5, 3, 5, 7, 3, 1, 17, 4, 2, 6, 4, 12, 9, 0, 5);
2445
@p = map percentile($_,@data), (25, 50, 75);
2446
2447
Is the same as this:
2448
2449
@p = percentile([25, 50, 75], @data);
2450
2451
But the latter is faster, especially if @data is large since it sorts
2452
the numbers only once internally.
2453
2454
B
2455
2456
Data: 1, 4, 6, 7, 8, 9, 22, 24, 39, 49, 555, 992
2457
2458
Average (or mean) is 143
2459
2460
Median is 15.5 (which is the average of 9 and 22 who both equally lays in the middle)
2461
2462
The 25-percentile is 6.25 which are between 6 and 7, but closer to 6.
2463
2464
The 75-percentile is 46.5, which are between 39 and 49 but close to 49.
2465
2466
Linear interpolation is used to find the 25- and 75-percentile and any
2467
other x-percentile which doesn't fall exactly on one of the numbers in
2468
the set.
2469
2470
B
2471
2472
As you saw, 6.25 are closer to 6 than to 7 because 25% along the set of
2473
the twelve numbers is closer to the third number (6) than to he fourth
2474
(7). The median (50-percentile) is also really interpolated, but it is
2475
always in the middle of the two center numbers if there are an even count
2476
of numbers.
2477
2478
However, there is two methods of interpolation:
2479
2480
Example, we have only three numbers: 5, 6 and 7.
2481
2482
Method 1: The most common is to say that 5 and 7 lays on the 25- and
2483
75-percentile. This method is used in Acme::Tools.
2484
2485
Method 2: In Oracle databases the least and greatest numbers
2486
always lay on the 0- and 100-percentile.
2487
2488
As an argument on why Oracles (and others?) definition is not the best way is to
2489
look at your data as for instance temperature measurements. If you
2490
place the highest temperature on the 100-percentile you are sort of
2491
saying that there can never be a higher temperatures in future measurements.
2492
2493
A quick non-exhaustive Google survey suggests that method 1 here is most used.
2494
2495
The larger the data sets, the less difference there is between the two methods.
2496
2497
B
2498
2499
In method one, when you want a percentile outside of any possible
2500
interpolation, you use the smallest and second smallest to extrapolate
2501
from. For instance in the data set C<5, 6, 7>, if you want an
2502
x-percentile of x < 25, this is below 5.
2503
2504
If you feel tempted to go below 0 or above 100, C will
2505
I (or I to be more precise)
2506
2507
Another method could be to use "soft curves" instead of "straight
2508
lines" in interpolation. Maybe B-splines or Bezier curves. This is not
2509
used here.
2510
2511
For large sets of data Hoares algorithm would be faster than the
2512
simple straightforward implementation used in C
2513
here. Hoares don't sort all the numbers fully.
2514
2515
B
2516
2517
Data: 1, 4, 6, 7, 8, 9, 22, 24, 39, 49, 555, 992
2518
2519
Percentile Method 1 Method 2
2520
(Acme::Tools::percentile (Oracle)
2521
and others)
2522
----------- --------------------------- ---------
2523
0 -2 1
2524
1 -1.61 1.33
2525
25 6.25 6.75
2526
50 (median) 15.5 15.5
2527
75 46.5 41.5
2528
99 1372.19 943.93
2529
100 1429 992
2530
2531
Found like this:
2532
2533
perl -MAcme::Tools -le 'print for percentile([0,1,25,50,75,99,100], 1,4,6,7,8,9,22,24,39,49,555,992)'
2534
2535
And like this in Oracle-databases:
2536
2537
create table tmp (n number);
2538
insert into tmp values (1); insert into tmp values (4); insert into tmp values (6);
2539
insert into tmp values (7); insert into tmp values (8); insert into tmp values (9);
2540
insert into tmp values (22); insert into tmp values (24); insert into tmp values (39);
2541
insert into tmp values (49); insert into tmp values (555); insert into tmp values (992);
2542
select
2543
percentile_cont(0.00) within group(order by n) per0,
2544
percentile_cont(0.01) within group(order by n) per1,
2545
percentile_cont(0.25) within group(order by n) per25,
2546
percentile_cont(0.50) within group(order by n) per50,
2547
percentile_cont(0.75) within group(order by n) per75,
2548
percentile_cont(0.99) within group(order by n) per99,
2549
percentile_cont(1.00) within group(order by n) per100
2550
from tmp;
2551
2552
(Oracle also provides a similar function: C where I
2553
is short for I, meaning no interpolation is taking
2554
place. Instead the closest number from the data set is picked.)
2555
2556
=cut
2557
2558
sub percentile {
2559
3
3
1
7
my(@p,@t,@ret);
2560
3
100
14
if(ref($_[0]) eq 'ARRAY'){ @p=@{shift()} }
1
50
1
1
4
2561
2
4
elsif(not ref($_[0])) { @p=(shift()) }
2562
0
0
else{croak()}
2563
3
7
@t=@_;
2564
3
50
9
return if !@p;
2565
3
50
8
croak if !@t;
2566
3
8
@t=sort{$a<=>$b}@t;
72
80
2567
3
50
9
push@t,$t[0] if @t==1;
2568
3
7
for(@p){
2569
9
50
33
40
croak if $_<0 or $_>100;
2570
9
18
my $i=(@t+1)*$_/100-1;
2571
9
50
53
push@ret,
100
100
2572
$i<0 ? $t[0]+($t[1]-$t[0])*$i:
2573
$i>$#t ? $t[-1]+($t[-1]-$t[-2])*($i-$#t):
2574
$i==int($i)? $t[$i]:
2575
$t[$i]*(int($i+1)-$i) + $t[$i+1]*($i-int($i));
2576
}
2577
3
100
56
return @p==1 ? $ret[0] : @ret;
2578
}
2579
2580
=head1 RANDOM
2581
2582
=head2 random
2583
2584
B One or two arguments.
2585
2586
B
2587
2588
If two integer arguments: returns a random integer between the integers in argument one and two.
2589
2590
If the first argument is an arrayref: returns a random member of that array without changing the array.
2591
2592
If the first argument is an arrayref and there is a second arg: return that many random members of that array
2593
2594
If the first argument is an hashref and there is no second arg: return a random key weighted by the values of that hash
2595
2596
If the first argument is an hashref and there is a second arg: return that many random keys weighted by the values of that hash
2597
2598
If there is no second argument and the first is an integer, a random integer between 0 and that number is returned. Including 0 and the number itself.
2599
2600
B
2601
2602
$dice=random(1,6); # 1, 2, 3, 4, 5 or 6
2603
$dice=random([1..6]); # same as previous
2604
@dice=random([1..6],10); # 10 dice tosses
2605
$dice=random({1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>2}); # weighted dice with 6 being twice as likely as the others
2606
@dice=random({1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>2},10); # 10 weighted dice tosses
2607
print random({head=>0.4999,tail=>0.4999,edge=>0.0002}); # coin toss (sum 1 here but not required to be)
2608
print random(2); # prints 0, 1 or 2
2609
print 2**random(7); # prints 1, 2, 4, 8, 16, 32, 64 or 128
2610
@dice=map random([1..6]), 1..10; # as third example above, but much slower
2611
perl -MAcme::Tools -le 'print for random({head=>0.499,tail=>0.499,edge=>0.002},10000);' | sort | uniq -c
2612
2613
=cut
2614
2615
sub random {
2616
21002
21002
1
57288
my($from,$to)=@_;
2617
21002
29728
my $ref=ref($from);
2618
21002
100
43101
if($ref eq 'ARRAY'){
100
2619
15001
100
74104
my @r=map $$from[rand@$from], 1..$to||1;
2620
15001
100
74889
return @_>1?@r:$r[0];
2621
}
2622
elsif($ref eq 'HASH') {
2623
4001
11371
my @k=keys%$from;
2624
28
66
28
150
my $max;do{no warnings 'uninitialized';$_>$max and $max=$_ or $_<0 and croak"negative weight" for values%$from};
28
33
48
28
66
29186
4001
5479
4001
4039
4001
55836
2625
4001
100
13644
my @r=map {my$r;1 while $$from{$r=$k[rand@k]}
4010
4247
4010
16139
4010
9109
2626
4001
100
18238
return @_>1?@r:$r[0];
2627
}
2628
2000
100
4098
($from,$to)=(0,$from) if @_==1;
2629
2000
50
3571
($from,$to)=($to,$from) if $from>$to;
2630
2000
6135
return int($from+rand(1+$to-$from));
2631
}
2632
#todo?: https://en.wikipedia.org/wiki/Irwin%E2%80%93Hall_distribution
2633
2634
=head2 random_gauss
2635
2636
Returns an pseudo-random number with a Gaussian distribution instead
2637
of the uniform distribution of perls C or C in this
2638
module. The algorithm is a variation of the one at
2639
L which is both faster
2640
and better than adding a long series of C.
2641
2642
Uses perls C function internally.
2643
2644
B 0 - 3 arguments.
2645
2646
First argument: the average of the distribution. Default 0.
2647
2648
Second argument: the standard deviation of the distribution. Default 1.
2649
2650
Third argument: If a third argument is present, C
2651
returns an array of that many pseudo-random numbers. If there is no
2652
third argument, a number (a scalar) is returned.
2653
2654
B One or more pseudo-random numbers with a Gaussian distribution. Also known as a Bell curve or Normal distribution.
2655
2656
Example:
2657
2658
my @I=random_gauss(100, 15, 100000); # produces 100000 pseudo-random numbers, average=100, stddev=15
2659
#my @I=map random_gauss(100, 15), 1..100000; # same but more than three times slower
2660
print "Average is: ".avg(@I)."\n"; # prints a number close to 100
2661
print "Stddev is: ".stddev(@I)."\n"; # prints a number close to 15
2662
2663
my @M=grep $_>100+15*2, @I; # those above 130
2664
print "Percent above two stddevs: ".(100*@M/@I)."%\n"; #prints a number close to 2.2%
2665
2666
Example 2:
2667
2668
my $num=1e6;
2669
my @h; $h[$_/2]++ for random_gauss(100,15, $num);
2670
$h[$_] and printf "%3d - %3d %6d %s\n",
2671
$_*2,$_*2+1,$h[$_],'=' x ($h[$_]*1000/$num)
2672
for 1..200/2;
2673
2674
...prints an example of the famous Bell curve:
2675
2676
44 - 45 70
2677
46 - 47 114
2678
48 - 49 168
2679
50 - 51 250
2680
52 - 53 395
2681
54 - 55 588
2682
56 - 57 871
2683
58 - 59 1238 =
2684
60 - 61 1807 =
2685
62 - 63 2553 ==
2686
64 - 65 3528 ===
2687
66 - 67 4797 ====
2688
68 - 69 6490 ======
2689
70 - 71 8202 ========
2690
72 - 73 10577 ==========
2691
74 - 75 13319 =============
2692
76 - 77 16283 ================
2693
78 - 79 20076 ====================
2694
80 - 81 23742 =======================
2695
82 - 83 27726 ===========================
2696
84 - 85 32205 ================================
2697
86 - 87 36577 ====================================
2698
88 - 89 40684 ========================================
2699
90 - 91 44515 ============================================
2700
92 - 93 47575 ===============================================
2701
94 - 95 50098 ==================================================
2702
96 - 97 52062 ====================================================
2703
98 - 99 53338 =====================================================
2704
100 - 101 52834 ====================================================
2705
102 - 103 52185 ====================================================
2706
104 - 105 50472 ==================================================
2707
106 - 107 47551 ===============================================
2708
108 - 109 44471 ============================================
2709
110 - 111 40704 ========================================
2710
112 - 113 36642 ====================================
2711
114 - 115 32171 ================================
2712
116 - 117 28166 ============================
2713
118 - 119 23618 =======================
2714
120 - 121 19873 ===================
2715
122 - 123 16360 ================
2716
124 - 125 13452 =============
2717
126 - 127 10575 ==========
2718
128 - 129 8283 ========
2719
130 - 131 6224 ======
2720
132 - 133 4661 ====
2721
134 - 135 3527 ===
2722
136 - 137 2516 ==
2723
138 - 139 1833 =
2724
140 - 141 1327 =
2725
142 - 143 860
2726
144 - 145 604
2727
146 - 147 428
2728
148 - 149 275
2729
150 - 151 184
2730
152 - 153 111
2731
154 - 155 67
2732
2733
=cut
2734
2735
sub random_gauss {
2736
1
1
1
3
my($avg,$stddev,$num)=@_;
2737
1
50
4
$avg=0 if !defined $avg;
2738
1
50
4
$stddev=1 if !defined $stddev;
2739
1
50
3
$num=1 if !defined $num;
2740
1
50
3
croak "random_gauss should not have more than 3 arguments" if @_>3;
2741
1
3
my @r;
2742
1
5
while (@r<$num) {
2743
2500
2736
my($x1,$x2,$w);
2744
2500
2636
do {
2745
3150
4271
$x1=2.0*rand()-1.0;
2746
3150
3822
$x2=2.0*rand()-1.0;
2747
3150
6852
$w=$x1*$x1+$x2*$x2;
2748
} while $w>=1.0;
2749
2500
3658
$w=sqrt(-2.0*log($w)/$w) * $stddev;
2750
2500
6100
push @r, $x1*$w + $avg,
2751
$x2*$w + $avg;
2752
}
2753
1
50
8
pop @r if @r > $num;
2754
1
50
9
return $r[0] if @_<3;
2755
1
812
return @r;
2756
}
2757
2758
=head2 mix
2759
2760
Mixes an array in random order. In-place if given an array reference or not if given an array.
2761
2762
C could also have been named C, as in shuffling a deck of cards.
2763
2764
Example:
2765
2766
This:
2767
2768
print mix("a".."z"),"\n" for 1..3;
2769
2770
...could write something like:
2771
2772
trgoykzfqsduphlbcmxejivnwa
2773
qycatilmpgxbhrdezfwsovujkn
2774
ytogrjialbewcpvndhkxfzqsmu
2775
2776
B
2777
2778
=over 4
2779
2780
=item 1.
2781
Either a reference to an array as the only input. This array will then be mixed I. The array will be changed:
2782
2783
This: C<< @a=mix(@a) >> is the same as: C<< mix(\@a) >>.
2784
2785
=item 2.
2786
Or an array of zero, one or more elements.
2787
2788
=back
2789
2790
Note that an input-array which COINCIDENTLY SOME TIMES has one element
2791
(but more other times), and that element is an array-ref, you will
2792
probably not get the expected result.
2793
2794
To check distribution:
2795
2796
perl -MAcme::Tools -le 'print mix("a".."z") for 1..26000'|cut -c1|sort|uniq -c|sort -n
2797
2798
The letters a-z should occur around 1000 times each.
2799
2800
Shuffles a deck of cards: (s=spaces, h=hearts, c=clubs, d=diamonds)
2801
2802
perl -MAcme::Tools -le '@cards=map join("",@$_),cart([qw/s h c d/],[2..10,qw/J Q K A/]); print join " ",mix(@cards)'
2803
2804
(Uses L, which is not a typo, see further down here)
2805
2806
Note: C is approximately four times faster. Both respects the Perl built-in C.
2807
2808
=cut
2809
2810
sub mix {
2811
1020
50
33
1020
1
5191
if(@_==1 and ref($_[0]) eq 'ARRAY'){ #kun ett arg, og det er ref array
2812
0
0
my $r=$_[0];
2813
0
0
push@$r,splice(@$r,rand(@$r-$_),1) for 0..(@$r-1);
2814
0
0
return $r;
2815
}
2816
else{
2817
1020
2097
my@e=@_;
2818
1020
13494
push@e,splice(@e,rand(@e-$_),1) for 0..$#e;
2819
1020
5249
return @e;
2820
}
2821
}
2822
2823
=head2 pwgen
2824
2825
Generates random passwords.
2826
2827
B 0-n args
2828
2829
* First arg: length of password(s), default 8
2830
2831
* Second arg: number of passwords, default 1
2832
2833
* Third arg: string containing legal chars in password, default A-Za-z0-9,-./&%_!
2834
2835
* Fourth to n'th arg: list of requirements for passwords, default if the third arg is false/undef (so default third arg is used) is:
2836
2837
sub{/^[a-zA-Z0-9].*[a-zA-Z0-9]$/ and /[a-z]/ and /[A-Z]/ and /\d/ and /[,-.\/&%_!]/}
2838
2839
...meaning the password should:
2840
* start and end with: a letter a-z (lower- or uppercase) or a digit 0-9
2841
* should contain at least one char from each of the groups lower, upper, digit and special char
2842
2843
To keep the default requirement-sub but add additional ones just set the fourth arg to false/undef
2844
and add your own requirements in the fifth arg and forward (examples below). Sub pwgen uses perls
2845
own C internally.
2846
2847
C<< $Acme::Tools::Pwgen_max_sec >> and C<< $Acme::Tools::Pwgen_max_trials >> can be set to adjust for how long
2848
pwgen tries to find a password. Defaults for those are 0.01 and 10000.
2849
Whenever one of the two limits is reached, a first generates a croak.
2850
2851
Examples:
2852
2853
my $pw=pwgen(); # a random 8 chars password A-Z a-z 0-9 ,-./&%!_ (8 is default length)
2854
my $pw=pwgen(12); # a random 12 chars password A-Z a-z 0-9 ,-./&%!_
2855
my @pw=pwgen(0,10); # 10 random 8 chars passwords, containing the same possible chars
2856
my @pw=pwgen(0,1000,'A-Z'); # 1000 random 8 chars passwords containing just uppercase letters from A to Z
2857
2858
pwgen(3); # dies, defaults require chars in each of 4 group (see above)
2859
pwgen(5,1,'A-C0-9', qr/^\D{3}\d{2}$/); # a 5 char string starting with three A, B or Cs and endring with two digits
2860
pwgen(5,1,'ABC0-9',sub{/^\D{3}\d{2}$/}); # same as above
2861
2862
Examples of adding additional requirements to the default ones:
2863
2864
my @pwreq = ( qr/^[A-C]/ );
2865
pwgen(8,1,'','',@pwreq); # use defaults for allowed chars and the standard requirements
2866
# but also demand that the password must start with A, B or C
2867
2868
push @pwreq, sub{ not /[a-z]{3}/i };
2869
pwgen(8,1,'','',@pwreq); # as above and in addition the password should not contain three
2870
# or more consecutive letters (to avoid "offensive" words perhaps)
2871
2872
=cut
2873
2874
our $Pwgen_max_sec=0.01; #max seconds/password before croak (for hard to find requirements)
2875
our $Pwgen_max_trials=10000; #max trials/password before croak (for hard to find requirements)
2876
our $Pwgen_sec=0; #seconds used in last call to pwgen()
2877
our $Pwgen_trials=0; #trials in last call to pwgen()
2878
2981
100
100
2981
0
37768
sub pwgendefreq{/^[a-z\d].*[a-z\d]$/i and /[a-z]/ and /[A-Z]/ and /\d/ and /[,-.\/&%_!]/}
100
100
2879
sub pwgen {
2880
60
60
1
4560
my($len,$num,$chars,@req)=@_;
2881
60
100
134
$len||=8;
2882
60
100
126
$num||=1;
2883
60
100
137
$chars||='A-Za-z0-9,-./&%_!';
2884
60
100
50
143
$req[0]||=\&pwgendefreq if !$_[2];
2885
60
1373
$chars=~s/([$_])-([$_])/join("","$1".."$2")/eg for ('a-z','A-Z','0-9');
125
1943
2886
60
132
my($c,$t,@pw)=(length($chars),time_fp());
2887
60
104
($Pwgen_trials,$Pwgen_sec)=(0,0);
2888
TRIAL:
2889
60
137
while(@pw<$num){
2890
12272
100
100
58227
croak "pwgen timeout after $Pwgen_trials trials"
2891
if ++$Pwgen_trials >= $Pwgen_max_trials
2892
or time_fp()-$t > $Pwgen_max_sec*$num;
2893
12270
77077
my $pw=join"",map substr($chars,rand($c),1),1..$len;
2894
12270
26420
for my $r (@req){
2895
18815
100
47683
if (ref($r) eq 'CODE' ){ local$_=$pw; &$r() or next TRIAL }
7086
100
9880
7086
50
15387
2896
28
100
28
156
elsif(ref($r) eq 'Regexp'){ no warnings; $pw=~$r or next TRIAL }
28
46
28
7153
11729
56697
2897
0
0
else { croak "pwgen: invalid req type $r ".ref($r) }
2898
}
2899
651
2566
push@pw,$pw;
2900
}
2901
58
111
$Pwgen_sec=time_fp()-$t;
2902
58
100
409
return $pw[0] if $num==1;
2903
7
352
return @pw;
2904
}
2905
2906
# =head1 veci
2907
#
2908
# Perls C takes 1, 2, 4, 8, 16, 32 and possibly 64 as its third argument.
2909
#
2910
# This limitation is removed with C (vec improved, but much slower)
2911
#
2912
# The third argument still needs to be 32 or lower (or possibly 64 or lower).
2913
#
2914
# =cut
2915
#
2916
# sub vecibs ($) {
2917
# my($s,$o,$b,$new)=@_;
2918
# if($b=~/^(1|2|4|8|16|32|64)$/){
2919
# return vec($s,$o,$b)=$new if @_==4;
2920
# return vec($s,$o,$b);
2921
# }
2922
# my $bb=$b<4?4:$b<8?8:$b<16?16:$b<32?32:$b<64?64:die;
2923
# my $ob=int($o*$b/$bb);
2924
# my $v=vec($s,$ob,$bb)*2**$bb+vec($s,$ob+1,$bb);
2925
# $v & (2**$b-1)
2926
# }
2927
2928
2929
=head1 SETS
2930
2931
=head2 distinct
2932
2933
Returns the values of the input list, sorted alfanumerically, but only
2934
one of each value. This is the same as L except uniq does not
2935
sort the returned list.
2936
2937
Example:
2938
2939
print join(", ", distinct(4,9,3,4,"abc",3,"abc")); # 3, 4, 9, abc
2940
print join(", ", distinct(4,9,30,4,"abc",30,"abc")); # 30, 4, 9, abc note: alphanumeric sort
2941
2942
=cut
2943
2944
1
1
1
261
sub distinct { return sort keys %{{map {($_,1)} @_}} }
1
3
7
22
2945
2946
=head2 in
2947
2948
Returns I<1> (true) if first argument is in the list of the remaining arguments. Uses the perl-operator C<< eq >>.
2949
2950
Otherwise it returns I<0> (false).
2951
2952
print in( 5, 1,2,3,4,6); # 0
2953
print in( 4, 1,2,3,4,6); # 1
2954
print in( 'a', 'A','B','C','aa'); # 0
2955
print in( 'a', 'A','B','C','a'); # 1
2956
2957
I guess in perl 5.10 or perl 6 you could use the C<< ~~ >> operator instead.
2958
2959
=head2 in_num
2960
2961
Just as sub L, but for numbers. Internally uses the perl operator C<< == >> instead of C< eq >.
2962
2963
print in(5000, '5e3'); # 0
2964
print in(5000, 5e3); # 1 since 5e3 is converted to 5000 before the call
2965
print in_num(5000, 5e3); # 1
2966
print in_num(5000, '+5.0e03'); # 1
2967
2968
=cut
2969
2970
sub in {
2971
28
28
158
no warnings 'uninitialized';
28
47
28
2630
2972
89
89
1
125
my $val=shift;
2973
89
100
172
for(@_){ return 1 if $_ eq $val }
282
752
2974
6
27
return 0;
2975
}
2976
2977
sub in_num {
2978
28
28
146
no warnings 'uninitialized';
28
53
28
57939
2979
1
1
1
2
my $val=shift;
2980
1
100
4
for(@_){ return 1 if $_ == $val }
5000
8972
2981
0
0
return 0;
2982
}
2983
2984
=head2 union
2985
2986
Input: Two arrayrefs. (Two lists, that is)
2987
2988
Output: An array containing all elements from both input lists, but no element more than once even if it occurs twice or more in the input.
2989
2990
Example, prints 1,2,3,4:
2991
2992
perl -MAcme::Tools -le 'print join ",", union([1,2,3],[2,3,3,4,4])' # 1,2,3,4
2993
2994
=cut
2995
2996
1
1
1
2
sub union { my %seen; grep !$seen{$_}++, map @{shift()},@_ }
1
3
2
14
2997
=head2 minus
2998
2999
Input: Two arrayrefs.
3000
3001
Output: An array containing all elements in the first input array but not in the second.
3002
3003
Example:
3004
3005
perl -MAcme::Tools -le 'print join " ", minus( ["five", "FIVE", 1, 2, 3.0, 4], [4, 3, "FIVE"] )'
3006
3007
Output is C<< five 1 2 >>.
3008
3009
=cut
3010
3011
sub minus {
3012
1
1
0
2
my %seen;
3013
1
2
my %notme=map{($_=>1)}@{$_[1]};
3
8
1
2
3014
1
66
3
grep !$notme{$_}&&!$seen{$_}++, @{$_[0]};
1
35
3015
}
3016
3017
=head2 intersect
3018
3019
Input: Two arrayrefs
3020
3021
Output: An array containing all elements which exists in both input arrays.
3022
3023
Example:
3024
3025
perl -MAcme::Tools -le 'print join" ", intersect( ["five", 1, 2, 3.0, 4], [4, 2+1, "five"] )' # 4 3 five
3026
3027
Output: C<< 4 3 five >>
3028
3029
=cut
3030
3031
sub intersect {
3032
42
42
1
48
my %first=map{($_=>1)}@{$_[0]};
50
140
42
72
3033
42
60
my %seen;
3034
42
100
44
return grep{$first{$_}&&!$seen{$_}++}@{$_[1]};
48
299
42
75
3035
}
3036
3037
=head2 not_intersect
3038
3039
Input: Two arrayrefs
3040
3041
Output: An array containing all elements member of just one of the input arrays (not both).
3042
3043
Example:
3044
3045
perl -MAcme::Tools -le ' print join " ", not_intersect( ["five", 1, 2, 3.0, 4], [4, 2+1, "five"] )'
3046
3047
The output is C<< 1 2 >>.
3048
3049
=cut
3050
3051
sub not_intersect {
3052
1
1
1
10
my %code;
3053
my %seen;
3054
1
3
for(@{$_[0]}){$code{$_}|=1}
1
4
5
14
3055
1
2
for(@{$_[1]}){$code{$_}|=2}
1
4
3
6
3056
1
100
2
return grep{$code{$_}!=3&&!$seen{$_}++}(@{$_[0]},@{$_[1]});
8
35
1
3
1
2
3057
}
3058
3059
=head2 uniq
3060
3061
Input: An array of strings (or numbers)
3062
3063
Output: The same array in the same order, except elements which exists earlier in the list.
3064
3065
Same as L but distinct sorts the returned list, I does not.
3066
3067
Example:
3068
3069
my @t=(7,2,3,3,4,2,1,4,5,3,"x","xx","x",02,"07");
3070
print join " ", uniq @t; # prints 7 2 3 4 1 5 x xx 07
3071
3072
=cut
3073
3074
1
1
1
2
sub uniq(@) { my %seen; grep !$seen{$_}++, @_ }
1
24
3075
3076
=head1 HASHES
3077
3078
=head2 subhash
3079
3080
Copies a subset of keys/values from one hash to another.
3081
3082
B First argument is a reference to a hash. The rest of the arguments are a list of the keys of which key/value-pair you want to be copied.
3083
3084
B The hash consisting of the keys and values you specified.
3085
3086
Example:
3087
3088
%population = ( Norway=>5000000, Sweden=>9500000, Finland=>5400000,
3089
Denmark=>5600000, Iceland=>320000,
3090
India => 1.21e9, China=>1.35e9, USA=>313e6, UK=>62e6 );
3091
3092
%scandinavia = subhash( \%population , 'Norway', 'Sweden', 'Denmark' ); # this and
3093
%scandinavia = (Norway=>5000000,Sweden=>9500000,Denmark=>5600000); # this is the same
3094
3095
print "Population of $_ is $scandinavia{$_}\n" for keys %scandinavia;
3096
3097
...prints the populations of the three scandinavian countries.
3098
3099
Note: The values are NOT deep copied when they are references. (Use C<< Storable::dclone() >> to do that).
3100
3101
Note2: For perl version 5.20+ subhashes (hash slices returning keys as well as values) is built in like this:
3102
3103
%scandinavia = %population{'Norway','Sweden','Denmark'};
3104
3105
=cut
3106
3107
sub subhash {
3108
1
1
1
3
my $hr=shift;
3109
1
1
my @r;
3110
1
3
for(@_){ push@r,($_=>$$hr{$_}) }
3
9
3111
1
10
return @r;
3112
}
3113
3114
=head2 hashtrans
3115
3116
B a reference to a hash of hashes
3117
3118
B a hash like the input-hash, but matrix transposed (kind of). Think of it as if X and Y has swapped places.
3119
3120
%h = ( 1 => {a=>33,b=>55},
3121
2 => {a=>11,b=>22},
3122
3 => {a=>88,b=>99} );
3123
print serialize({hashtrans(\%h)},'v');
3124
3125
Gives:
3126
3127
%v=( 'a'=>{'1'=>'33','2'=>'11','3'=>'88'},
3128
'b'=>{'1'=>'55','2'=>'22','3'=>'99'} );
3129
3130
=cut
3131
3132
#Hashtrans brukes automatisk når første argument er -1 i sub hashtabell()
3133
3134
sub hashtrans {
3135
1
1
1
2
my $h=shift;
3136
1
2
my %new;
3137
1
4
for my $k (keys%$h){
3138
3
4
my $r=$$h{$k};
3139
3
14
for(keys%$r){
3140
6
15
$new{$_}{$k}=$$r{$_};
3141
}
3142
}
3143
1
11
return %new;
3144
}
3145
3146
=head1 COMPRESSION
3147
3148
L, L, L, L, L, and L
3149
compresses and uncompresses strings to save space in disk, memory,
3150
database or network transfer. Trades time for space. (Beware of wormholes)
3151
3152
=head2 zipb64
3153
3154
Compresses the input (text or binary) and returns a base64-encoded string of the compressed binary data.
3155
No known limit on input length, several MB has been tested, as long as you've got the RAM...
3156
3157
B One or two strings.
3158
3159
First argument: The string to be compressed.
3160
3161
Second argument is optional: A I string.
3162
3163
B a base64-kodet string of the compressed input.
3164
3165
The use of an optional I string will result in an even
3166
further compressed output in the dictionary string is somewhat similar
3167
to the string that is compressed (the data in the first argument).
3168
3169
If x relatively similar string are to be compressed, i.e. x number
3170
automatic of email responses to some action by a user, it will pay of
3171
to choose one of those x as a dictionary string and store it as
3172
such. (You will also use the same dictionary string when decompressing
3173
using L.
3174
3175
The returned string is base64 encoded. That is, the output is 33%
3176
larger than it has to be. The advantage is that this string more
3177
easily can be stored in a database (without the hassles of CLOB/BLOB)
3178
or perhaps easier transfer in http POST requests (it still needs some
3179
url-encoding, normally). See L and L for the
3180
same without base 64 encoding.
3181
3182
Example 1, normal compression without dictionary:
3183
3184
$txt = "Test av komprimering, hva skjer? " x 10; # ten copies of this norwegian string, $txt is now 330 bytes (or chars rather...)
3185
print length($txt)," bytes input!\n"; # prints 330
3186
$zip = zipb64($txt); # compresses
3187
print length($zip)," bytes output!\n"; # prints 65
3188
print $zip; # prints the base64 string ("noise")
3189
3190
$output=unzipb64($zip); # decompresses
3191
print "Hurra\n" if $output eq $txt; # prints Hurra if everything went well
3192
print length($output),"\n"; # prints 330
3193
3194
Example 2, same compression, now with dictionary:
3195
3196
$txt = "Test av komprimering, hva skjer? " x 10; # Same original string as above
3197
$dict = "Testing av kompresjon, hva vil skje?"; # dictionary with certain similarities
3198
# of the text to be compressed
3199
$zip2 = zipb64($txt,$dict); # compressing with $dict as dictionary
3200
print length($zip2)," bytes output!\n"; # prints 49, which is less than 65 in ex. 1 above
3201
$output=unzipb64($zip2,$dict); # uses $dict in the decompressions too
3202
print "Hurra\n" if $output eq $txt; # prints Hurra if everything went well
3203
3204
3205
Example 3, dictionary = string to be compressed: (out of curiosity)
3206
3207
$txt = "Test av komprimering, hva skjer? " x 10; # Same original string as above
3208
$zip3 = zipb64($txt,$txt); # hmm
3209
print length($zip3)," bytes output!\n"; # prints 25
3210
print "Hurra\n" if unzipb64($zip3,$txt) eq $txt; # hipp hipp ...
3211
3212
zipb64() and zipbin() is really just wrappers around L and C & co there.
3213
3214
=cut
3215
3216
sub zipb64 {
3217
9
9
1
996
require MIME::Base64;
3218
9
21728
return MIME::Base64::encode_base64(zipbin(@_));
3219
}
3220
3221
3222
=head2 zipbin
3223
3224
C does the same as C except that zipbin()
3225
does not base64 encode the result. Returns binary data.
3226
3227
See L for documentation.
3228
3229
=cut
3230
3231
sub zipbin {
3232
17
17
1
125
require Compress::Zlib;
3233
17
39
my($data,$dict)=@_;
3234
17
50
100
166
my $x=Compress::Zlib::deflateInit(-Dictionary=>$dict||'',-Level=>Compress::Zlib::Z_BEST_COMPRESSION()) or croak();
3235
17
50
7977
my($output,$status)=$x->deflate($data); croak() if $status!=Compress::Zlib::Z_OK();
17
84501
3236
17
50
131
my($out,$status2)=$x->flush(); croak() if $status2!=Compress::Zlib::Z_OK();
17
3057
3237
17
779
return $output.$out;
3238
}
3239
3240
=head2 unzipb64
3241
3242
Opposite of L.
3243
3244
Input:
3245
3246
First argument: A string made by L
3247
3248
Second argument: (optional) a dictionary string which where used in L.
3249
3250
Output: The original string (be it text or binary).
3251
3252
See L.
3253
3254
=cut
3255
3256
sub unzipb64 {
3257
2
2
1
7
my($data,$dict)=@_;
3258
2
15
require MIME::Base64;
3259
2
52
unzipbin(MIME::Base64::decode_base64($data),$dict);
3260
}
3261
3262
=head2 unzipbin
3263
3264
C does the same as L except that C
3265
wants a pure binary compressed string as input, not base64.
3266
3267
See L for documentation.
3268
3269
=cut
3270
3271
sub unzipbin {
3272
5
5
1
22
require Compress::Zlib;
3273
5
23
require Carp;
3274
5
12
my($data,$dict)=@_;
3275
5
50
50
43
my $x=Compress::Zlib::inflateInit(-Dictionary=>$dict||'') or croak();
3276
5
748
my($output,$status)=$x->inflate($data);
3277
5
50
738
croak() if $status!=Compress::Zlib::Z_STREAM_END();
3278
5
155
return $output;
3279
}
3280
3281
=head2 gzip
3282
3283
B A string you want to compress. Text or binary.
3284
3285
B The binary compressed representation of that input string.
3286
3287
C is really the same as C< Compress:Zlib::memGzip() > except
3288
that C just returns the input-string if for some reason L
3289
could not be C. Not installed or not found. (L is a built in module in newer perl versions).
3290
3291
C uses the same compression algorithm as the well known GNU program gzip found in most unix/linux/cygwin distros. Except C does this in-memory. (Both using the C-library C).
3292
3293
=cut
3294
3295
sub gzip {
3296
8
8
1
622
my $s=shift();
3297
8
20
eval{ # tries gzip, if it works it works, else returns the input
3298
8
2211
require Compress::Zlib;
3299
8
136008
$s=Compress::Zlib::memGzip(\$s);
3300
8
72025
};undef$@;
3301
8
85
return $s;
3302
}
3303
3304
=head2 gunzip
3305
3306
B A binary compressed string. I.e. something returned from
3307
C earlier or read from a C<< .gz >> file.
3308
3309
B The original larger non-compressed string. Text or binary.
3310
3311
=cut
3312
3313
sub gunzip {
3314
3
3
1
8
my $s=shift();
3315
3
6
eval {
3316
3
16
require Compress::Zlib;
3317
3
12
$s=Compress::Zlib::memGunzip(\$s);
3318
3
891
};undef$@;
3319
3
18
return $s;
3320
}
3321
3322
=head2 bzip2
3323
3324
See L and L.
3325
3326
C and C works just as C and C,
3327
but use another compression algorithm. This is usually better but slower
3328
than the C-algorithm. Especially in the compression. Decompression speed is less different.
3329
3330
See also C, C and L
3331
3332
=cut
3333
3334
sub bzip2 {
3335
0
0
1
0
my $s=shift();
3336
0
0
eval { require Compress::Bzip2; $s=Compress::Bzip2::memBzip($s) }; undef$@;
0
0
0
0
0
0
3337
0
0
return $s;
3338
}
3339
3340
=head2 bunzip2
3341
3342
Decompressed something compressed by bzip2() or the data from a C<.bz2> file. See L.
3343
3344
=cut
3345
3346
sub bunzip2 {
3347
0
0
1
0
my $s=shift();
3348
0
0
eval { require Compress::Bzip2; $s=Compress::Bzip2::memBunzip($s) }; undef$@;
0
0
0
0
0
0
3349
0
0
return $s;
3350
}
3351
3352
3353
=head1 NET, WEB, CGI-STUFF
3354
3355
=head2 ipaddr
3356
3357
B an IP-number
3358
3359
B either an IP-address I or an empty string
3360
if the DNS lookup didn't find anything.
3361
3362
Example:
3363
3364
perl -MAcme::Tools -le 'print ipaddr("129.240.8.200")' # prints www.uio.no
3365
3366
Uses perls C internally.
3367
3368
C memoizes the results internally (using the
3369
C<%Acme::Tools::IPADDR_memo> hash) so only the first loopup on a
3370
particular IP number might take some time.
3371
3372
Some few DNS loopups can take several seconds.
3373
Most is done in a fraction of a second. Due to this slowness, medium to high traffic web servers should
3374
probably turn off hostname lookups in their logs and just log IP numbers by using
3375
C in Apache C and then use I afterwards if necessary.
3376
3377
=cut
3378
3379
our %IPADDR_memo;
3380
sub ipaddr {
3381
2
2
1
506
my $ipnr=shift;
3382
#NB, 2-tallet på neste kodelinje er ikke det samme på alle os,
3383
#men ser ut til å funke i linux og hpux. Den Riktige Måten(tm)
3384
#er konstanten AF_INET i Socket eller IO::Socket-pakken.
3385
2
66
176520
return $IPADDR_memo{$ipnr} ||= gethostbyaddr(pack("C4",split("\\.",$ipnr)),2);
3386
}
3387
3388
=head2 ipnum
3389
3390
C does the opposite of C
3391
3392
Does an attempt of converting an IP address (hostname) to an IP number.
3393
Uses DNS name servers via perls internal C.
3394
Return empty string (undef) if unsuccessful.
3395
3396
print ipnum("www.uio.no"); # prints 129.240.13.152
3397
3398
Does internal memoization via the hash C<%Acme::Tools::IPNUM_memo>.
3399
3400
=cut
3401
3402
our %IPNUM_memo;
3403
sub ipnum {
3404
1
1
1
3
my $ipaddr=shift;
3405
#croak "No $ipaddr" if !length($ipaddr);
3406
1
50
4
return $IPNUM_memo{$ipaddr} if exists $IPNUM_memo{$ipaddr};
3407
1
48973
my $h=gethostbyname($ipaddr);
3408
#croak "No ipnum for $ipaddr" if !$h;
3409
1
50
16
return if !defined $h;
3410
1
24
my $ipnum = join(".",unpack("C4",$h));
3411
1
50
33
$IPNUM_memo{$ipaddr} = $ipnum=~/^(\d+\.){3}\d+$/ ? $ipnum : undef;
3412
1
11
return $IPNUM_memo{$ipaddr};
3413
}
3414
3415
=head2 webparams
3416
3417
B (optional)
3418
3419
Zero or one input argument: A string of the same type often found behind the first question mark (C<< ? >>) in URLs.
3420
3421
This string can have one or more parts separated by C<&> chars.
3422
3423
Each part consists of C pairs (with the first C<=> char being the separation char).
3424
3425
Both C and C can be url-encoded.
3426
3427
If there is no input argument, C uses C<< $ENV{QUERY_STRING} >> instead.
3428
3429
If also C<< $ENV{QUERY_STRING} >> is lacking, C checks if C<< $ENV{REQUEST_METHOD} eq 'POST' >>.
3430
In that case C<< $ENV{CONTENT_LENGTH} >> is taken as the number of bytes to be read from C
3431
and those bytes are used as the missing input argument.
3432
3433
The environment variables QUERY_STRING, REQUEST_METHOD and CONTENT_LENGTH is
3434
typically set by a web server following the CGI standard (which Apache and
3435
most of them can do I guess) or in mod_perl by Apache. Although you are
3436
probably better off using L. Or C<< $R->args() >> or C<< $R->content() >> in mod_perl.
3437
3438
B
3439
3440
C returns a hash of the key/value pairs in the input argument. Url-decoded.
3441
3442
If an input string has more than one occurrence of the same key, that keys value in the returned hash will become concatenated each value separated by a C<,> char. (A comma char)
3443
3444
Examples:
3445
3446
use Acme::Tools;
3447
my %R=webparams();
3448
print "Content-Type: text/plain\n\n"; # or rather \cM\cJ\cM\cJ instead of \n\n to be http-compliant
3449
print "My name is $R{name}";
3450
3451
Storing those four lines in a file in the directory designated for CGI-scripts
3452
on your web server (or perhaps naming the file .cgi is enough), and C
3453
/.../cgi-bin/script> and the URL
3454
L will print
3455
C to the web page.
3456
3457
L will print C.
3458
3459
=cut
3460
3461
sub webparams {
3462
2
2
1
394
my $query=shift();
3463
2
50
9
$query=$ENV{QUERY_STRING} if !defined $query;
3464
2
50
33
7
if(!defined $query and $ENV{REQUEST_METHOD} eq "POST"){
3465
0
0
read(STDIN,$query , $ENV{CONTENT_LENGTH});
3466
0
0
$ENV{QUERY_STRING}=$query;
3467
}
3468
2
3
my %R;
3469
2
15
for(split("&",$query)){
3470
7
50
18
next if !length($_);
3471
7
22
my($nkl,$verdi)=map urldec($_),split("=",$_,2);
3472
7
100
30
$R{$nkl}=exists$R{$nkl}?"$R{$nkl},$verdi":$verdi;
3473
}
3474
2
15
return %R;
3475
}
3476
3477
=head2 urlenc
3478
3479
Input: a string
3480
3481
Output: the same string URL encoded so it can be sent in URLs or POST requests.
3482
3483
In URLs (web addresses) certain characters are illegal. For instance I and I.
3484
And certain other chars have special meaning, such as C<+>, C<%>, C<=>, C>, C<&>.
3485
3486
These illegal and special chars needs to be encoded to be sent in
3487
URLs. This is done by sending them as C<%> and two hex-digits. All
3488
chars can be URL encodes this way, but it's necessary just on some.
3489
3490
Example:
3491
3492
$search="Østdal, Åge";
3493
my $url="http://machine.somewhere.com/search?q=" . urlenc($search);
3494
print $url;
3495
3496
Prints C<< http://machine.somewhere.com/search?q=%D8stdal%2C%20%C5ge >>
3497
3498
=cut
3499
3500
sub urlenc {
3501
4
4
1
20
my $str=shift;
3502
4
16
$str=~s/([^\w\-\.\/\,\[\]])/sprintf("%%%02x",ord($1))/eg; #more chars is probably legal...
608
1569
3503
4
26
return $str;
3504
}
3505
3506
=head2 urldec
3507
3508
Opposite of L.
3509
3510
Example, this returns 'C< ø>'. That is space and C<< ø >>.
3511
3512
urldec('+%C3')
3513
3514
=cut
3515
3516
sub urldec {
3517
14
14
1
18
my $str=shift;
3518
14
107
$str=~s/\+/ /gs;
3519
14
25
$str=~s/%([a-f\d]{2})/pack("C", hex($1))/egi;
609
1520
3520
14
61
return $str;
3521
}
3522
3523
=head2 ht2t
3524
3525
C is short for I.
3526
3527
This sub extracts an html-C<< >>s and returns its C<< s >>
3528
and C<< s >> as an array of arrayrefs. And strips away any html
3529
inside the C<< s >> as well.
3530
3531
my @table = ht2t($html,'some string occuring before the you want');
3532
3533
Input: One or two arguments.
3534
3535
First argument: the html where a C<< >> is to be found and converted.
3536
3537
Second argument: (optional) If the html contains more than one C<<
3538
>>, and you do not want the first one, applying a second
3539
argument is a way of telling C which to capture: the one with this word
3540
or string occurring before it.
3541
3542
Output: An array of arrayrefs.
3543
3544
C is a quick and dirty way of scraping (or harvesting as it is
3545
also called) data from a web page. Look too L to do this
3546
more accurate.
3547
3548
Example:
3549
3550
use Acme::Tools;
3551
use LWP::Simple;
3552
my $url = "http://en.wikipedia.org/wiki/List_of_countries_by_population";
3553
for( ht2t( get($url), "Countries" ) ) {
3554
my($rank, $country, $pop) = @$_;
3555
$pop =~ s/,//g;
3556
printf "%3d | %-32s | %9d\n", @$_ if $pop>0;
3557
}
3558
3559
Output:
3560
3561
1 | China | 1367740000
3562
2 | India | 1262090000
3563
3 | United States | 319043000
3564
4 | Indonesia | 252164800
3565
5 | Brazil | 203404000
3566
3567
...and so on.
3568
3569
=cut
3570
3571
sub ht2t {
3572
9
100
100
9
1
451
my($f,$s,$r)=@_; 1>@_||@_>3 and croak; $s='' if @_==1;
9
100
314
7
17
3573
7
121
$f=~s,.*?($s).*?(
3574
28
28
835971
my $e=0;$e++ while index($f,$s=chr($e))>=$[;
28
13345
28
104398
7
13
7
36
3575
7
85
$f=~s//\l$1$s/gsi;
3576
7
54
$f=~s/\s*<.*?>\s*/ /gsi;
3577
7
66
my @t=split("r$s",$f);shift @t;
7
12
3578
20
20
32
$r||=sub{s/&(#160|nbsp);/ /g;s/&/&/g;s/^\s*(.*?)\s*$/$1/s;
20
28
20
81
3579
7
100
100
38
s/(\d) (\d)/$1$2/g if /^[\d \.\,]+$/};
20
71
3580
7
16
for(@t){my @r=split/[dh]$s/;shift@r;$_=[map{&$r;$_}@r]}
9
52
9
14
9
16
20
31
20
64
3581
7
38
@t;
3582
}
3583
3584
=head1 FILES, DIRECTORIES
3585
3586
=head2 writefile
3587
3588
Justification:
3589
3590
Perl needs three or four operations to make a file out of a string:
3591
3592
open my $FILE, '>', $filename or die $!;
3593
print $FILE $text;
3594
close($FILE);
3595
3596
This is way simpler:
3597
3598
writefile($filename,$text);
3599
3600
Sub writefile opens the file i binary mode (C) and has two usage modes:
3601
3602
B Two arguments
3603
3604
B is the filename. If the file exists, its overwritten.
3605
If the file can not be opened for writing, a die (a croak really) happens.
3606
3607
B is one of:
3608
3609
=over 4
3610
3611
=item * Either a scaler. That is a normal string to be written to the file.
3612
3613
=item * Or a reference to a scalar. That referred text is written to the file.
3614
3615
=item * Or a reference to an array of scalars. This array is the written to the
3616
file element by element and C<< \n >> is automatically appended to each element.
3617
3618
=back
3619
3620
Alternativelly, you can write several files at once.
3621
3622
Example, this:
3623
3624
writefile('file1.txt','The text....tjo');
3625
writefile('file2.txt','The text....hip');
3626
writefile('file3.txt','The text....and hop');
3627
3628
...is the same as this:
3629
3630
writefile([
3631
['file1.txt','The text....tjo'],
3632
['file2.txt','The text....hip'],
3633
['file3.txt','The text....and hop'],
3634
]);
3635
3636
B Nothing (for the time being). Cs (C really) if something goes wrong.
3637
3638
=cut
3639
3640
#todo: use openstr() as in readfile(), transparently gzip .gz filenames and so on
3641
sub writefile {
3642
4
4
1
70151
my($filename,$text)=@_;
3643
4
50
25
if(ref($filename) eq 'ARRAY'){
3644
0
0
writefile(@$_) for @$filename;
3645
0
0
return;
3646
}
3647
4
50
33
306
open(WRITEFILE,">",$filename) and binmode(WRITEFILE) or croak($!);
3648
4
50
33
41
if(!defined $text or !ref($text)){
0
0
3649
4
733
print WRITEFILE $text;
3650
}
3651
elsif(ref($text) eq 'SCALAR'){
3652
0
0
print WRITEFILE $$text;
3653
}
3654
elsif(ref($text) eq 'ARRAY'){
3655
0
0
print WRITEFILE "$_\n" for @$text;
3656
}
3657
else {
3658
0
0
croak;
3659
}
3660
4
167
close(WRITEFILE);
3661
4
15
return;
3662
}
3663
3664
=head2 readfile
3665
3666
Just as with L you can read in a whole file in one operation with C. Instead of:
3667
3668
open my $FILE,'<', $filename or die $!;
3669
my $data = join"",<$FILE>;
3670
close($FILE);
3671
3672
This is simpler:
3673
3674
my $data = readfile($filename);
3675
3676
B
3677
3678
Reading the content of the file to a scalar variable: (Any content in C<$data> will be overwritten)
3679
3680
my $data;
3681
readfile('filename.txt',\$data);
3682
3683
Reading the lines of a file into an array:
3684
3685
my @lines;
3686
readfile('filnavn.txt',\@lines);
3687
for(@lines){
3688
...
3689
}
3690
3691
Note: Chomp is done on each line. That is, any newlines (C<< \n >>) will be removed.
3692
If C<@lines> is non-empty, this will be lost.
3693
3694
Sub readfile is context aware. If an array is expected it returns an array of the lines without a trailing C<< \n >>.
3695
The last example can be rewritten:
3696
3697
for(readfile('filnavn.txt')){
3698
...
3699
}
3700
3701
With two input arguments, nothing (undef) is returned from C.
3702
3703
=cut
3704
3705
#http://blogs.perl.org/users/leon_timmermans/2013/05/why-you-dont-need-fileslurp.html
3706
#todo: readfile with grep-filter code ref in a third arg (avoid reading all into mem)
3707
3708
sub readfile {
3709
12
12
1
11518
my($filename,$ref)=@_;
3710
12
100
59
if(@_==1){
3711
6
100
22
if(wantarray){ my @data; readfile($filename,\@data); return @data }
1
3
1
5
1
4976
3712
5
8
else { my $data; readfile($filename,\$data); return $data }
5
457
5
698
3713
}
3714
else {
3715
6
50
46
open my $fh,openstr($filename) or croak("ERROR: readfile $! $?");
3716
6
100
30
if ( ref($ref) eq 'SCALAR') { $$ref=join"",<$fh> }
5
50
6899
3717
1
18
elsif( ref($ref) eq 'ARRAY' ) { while(my $l=<$fh>){ chomp($l); push @$ref, $l } }
20003
20569
20003
54199
3718
0
0
else { croak "ERROR: Second arg to readfile should be a ref to a scalar og array" }
3719
6
1166
close($fh);
3720
6
38
return;#?
3721
}
3722
}
3723
3724
=head2 readdirectory
3725
3726
B
3727
3728
Name of a directory.
3729
3730
B
3731
3732
A list of all files in it, except of C<.> and C<..> (on linux/unix systems, all directories have a C<.> and C<..> directory).
3733
3734
The names of all types of files are returned: normal files, directories, symbolic links,
3735
pipes, semaphores. That is every thing shown by C except C<.> and C<..>
3736
3737
C do not recurce down into subdirectories (but see example below).
3738
3739
B
3740
3741
my @files = readdirectory("/tmp");
3742
3743
B
3744
3745
Sometimes calling the built ins C, C and C seems a tad tedious, since this:
3746
3747
my $dir="/usr/bin";
3748
opendir(D,$dir);
3749
my @files=map "$dir/$_", grep {!/^\.\.?$/} readdir(D);
3750
closedir(D);
3751
3752
Is the same as this:
3753
3754
my @files=readdirectory("/usr/bin");
3755
3756
See also: L
3757
3758
B
3759
3760
On huge directories with perhaps tens or houndreds of thousands of
3761
files, readdirectory() will consume more memory than perls
3762
opendir/readdir. This isn't usually a concern anymore for modern
3763
computers with gigabytes of RAM, but might be the rationale behind
3764
Perls more tedious way created in the 80s. The same argument goes for
3765
file slurping. On the other side it's also a good practice to never
3766
assume to much on available memory and the number of files if you
3767
don't know for certain that enough memory is available whereever your
3768
code is run or that the size of the directory is limited.
3769
3770
B
3771
3772
How to get all files in the C directory including all subdirectories below of any depth:
3773
3774
my @files=("/tmp");
3775
map {-d $_ and unshift @files,$_ or push @files,$_} readdirectory(shift(@files)) while -d $files[0];
3776
3777
...or to avoid symlinks and only get real files:
3778
3779
map {-d and !-l and unshift @files,$_ or -f and !-l and push @files,$_} readdirectory(shift(@files)) while -d $files[0];
3780
3781
=cut
3782
3783
sub readdirectory {
3784
0
0
1
0
my $dir=shift;
3785
0
0
opendir(my $D,$dir);
3786
0
0
my @filer=map "$dir/$_", grep {!/^\.\.?$/} readdir($D);
0
0
3787
0
0
closedir($D);
3788
0
0
return @filer;
3789
}
3790
3791
=head2 basename
3792
3793
The basename and dirname functions behaves like the *nix shell commands with the same names.
3794
3795
B One or two arguments: Filename and an optional suffix
3796
3797
B Returns the filename with any directory and (if given) the suffix removed.
3798
3799
basename('/usr/bin/perl') # returns 'perl'
3800
basename('/usr/local/bin/report.pl','.pl') # returns 'report' since .pl at the end is removed
3801
basename('report2.pl','.pl') # returns 'report2'
3802
basename('report2.pl','.\w+') # returns 'report2.pl', probably not what you meant
3803
basename('report2.pl',qr/.\w+/) # returns 'report2', use qr for regex
3804
3805
=head2 dirname
3806
3807
B A filename including path
3808
3809
B Removes the filename path and returns just the directory path up until but not including
3810
the last /. Return just a one char C<< . >> (period string) if there is no directory in the input.
3811
3812
dirname('/usr/bin/perl') # returns '/usr/bin'
3813
dirname('perl') # returns '.'
3814
3815
=head2 username
3816
3817
Returns the current linux/unix username, for example the string root
3818
3819
print username(); #just (getpwuid($<))[0] but more readable perhaps
3820
3821
=cut
3822
3823
8
100
8
1
3286
sub basename { my($f,$s)=(@_,'');$s=quotemeta($s)if!ref($s);$f=~m,^(.*/)?([^/]*?)($s)?$,;$2 }
8
25
8
226
8
38
3824
2
100
66
2
1
438
sub dirname { $_[0]=~m,^(.*)/,;defined($1) && length($1) ? $1 : '.' }
2
23
3825
0
0
1
0
sub username { (getpwuid($<))[0] }
3826
3827
=head2 wipe
3828
3829
Deletes a file by "wiping" it on the disk. Overwrites the file before deleting. (May not work properly on SSDs)
3830
3831
B
3832
* Arg 1: A filename
3833
* Optional arg 2: number of times to overwrite file. Default is 3 if omitted, 0 or undef
3834
* Optional arg 3: keep (true/false), wipe() but no delete of file
3835
3836
B Same as the C (remove file): 1 for success, 0 or false for failure.
3837
3838
See also: L, L
3839
3840
=cut
3841
3842
sub wipe {
3843
2
2
1
704
my($file,$times,$keep)=@_;
3844
2
100
14
$times||=3;
3845
2
50
33
82
croak "ERROR: File $file nonexisting\n" if not -f $file or not -e $file;
3846
2
28
my $size=-s$file;
3847
2
50
78
open my $WIFH, '+<', $file or croak "ERROR: Unable to open $file: $!\n";
3848
2
5
binmode($WIFH);
3849
2
8
for(1..$times){
3850
4
16
my $block=chr(int(rand(256))) x 1024;#hm
3851
4
10
for(0..($size/1024)){
3852
73
521
seek($WIFH,$_*1024,0);
3853
73
142
print $WIFH $block;
3854
}
3855
}
3856
2
30
close($WIFH);
3857
2
100
141
$keep || unlink($file);
3858
}
3859
3860
=head2 chall
3861
3862
Does chmod + utime + chown on one or more files.
3863
3864
Returns the number of files of which those operations was successful.
3865
3866
Mode, uid, gid, atime and mtime are set from the array ref in the first argument.
3867
3868
The first argument references an array which is exactly like an array returned from perls internal C -function.
3869
3870
Example:
3871
3872
my @stat=stat($filenameA);
3873
chall( \@stat, $filenameB, $filenameC, ... ); # by stat-array
3874
chall( $filenameA, $filenameB, $filenameC, ... ); # by file name
3875
3876
Copies the chmod, owner, group, access time and modify time from file A to file B and C.
3877
3878
See C, C, C, C
3879
3880
=cut
3881
3882
3883
sub chall {
3884
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks )
3885
1
50
1
1
28244
= ref($_[0]) ? @{shift()} : stat(shift());
1
4
3886
1
2
my $successful=0;
3887
1
50
33
4
for(@_){ chmod($mode,$_) && utime($atime,$mtime,$_) && chown($uid,$gid,$_) && $successful++ }
1
33
73
3888
1
3
return $successful;
3889
}
3890
3891
=head2 makedir
3892
3893
Input: One or two arguments.
3894
3895
Works like perls C except that C will create nesessary parent directories if they dont exists.
3896
3897
First input argument: A directory name (absolute, starting with C< / > or relative).
3898
3899
Second input argument: (optional) permission bits. Using the normal C<< 0777^umask() >> as the default if no second input argument is provided.
3900
3901
Example:
3902
3903
makedir("dirB/dirC")
3904
3905
...will create directory C if it does not already exists, to be able to create C inside C.
3906
3907
Returns true on success, otherwise false.
3908
3909
C memoizes directories it has checked for existence before (trading memory and for speed).
3910
Thus directories removed during running the script is not discovered by makedir.
3911
3912
See also C<< perldoc -f mkdir >>, C<< man umask >>
3913
3914
=cut
3915
3916
our %MAKEDIR;
3917
3918
sub makedir {
3919
0
0
1
0
my($d,$p,$dd)=@_;
3920
0
0
0
$p=0777^umask() if !defined$p;
3921
(
3922
$MAKEDIR{$d} or -d$d or mkdir($d,$p) #or croak("mkdir $d, $p")
3923
or ($dd)=($d=~m,^(.+)/+([^/]+)$,) and makedir($dd,$p) and mkdir($d,$p) #or die;
3924
0
0
0
0
) and ++$MAKEDIR{$d};
0
0
0
0
3925
}
3926
3927
=head2 md5sum
3928
3929
B a filename.
3930
3931
B a string of 32 hexadecimal chars from 0-9 or a-f.
3932
3933
Example, the md5sum gnu/linux command without options could be implementet like this:
3934
3935
use Acme::Tools;
3936
print eval{ md5sum($_)." $_\n" } || $@ for @ARGV;
3937
3938
This sub requires L, which is a core perl-module since
3939
version 5.?.? It does not slurp the files or spawn new processes.
3940
3941
=cut
3942
3943
sub md5sum {
3944
2
2
1
18
require Digest::MD5;
3945
2
4
my $fn=shift;
3946
2
100
212
croak "md5sum: $fn is a directory (no md5sum)" if -d $fn;
3947
1
50
34
open my $FH, '<', $fn or croak "Could not open file $fn for md5sum() $!";
3948
1
2
binmode($FH);
3949
1
3
my $r = eval { Digest::MD5->new->addfile($FH)->hexdigest };
1
19
3950
1
50
8
croak "md5sum on $fn failed ($@)\n" if $@;
3951
1
16
$r;
3952
}
3953
3954
=head2 read_conf
3955
3956
B A file name or a reference to a string with settings in the format described below.
3957
3958
B A reference to a hash. This hash will have the settings from the file (or stringref).
3959
The hash do not have to be empty beforehand.
3960
3961
Returns a hash with the settings as in this examples:
3962
3963
my %conf = read_conf('/etc/your/thing.conf');
3964
print $conf{sectionA}{knobble}; #prints ABC if the file is as shown below
3965
print $conf{sectionA}{gobble}; #prints ZZZ, the last gobble
3966
print $conf{switch}; #prints OK here as well, unsectioned value
3967
print $conf{part2}{password}; #prints oh:no= x
3968
3969
File use for the above example:
3970
3971
switch: OK #before first section, the '' (empty) section
3972
[sectionA]
3973
knobble: ABC
3974
gobble: XYZ #this gobble is overwritten by the gobble on the next line
3975
gobble: ZZZ
3976
[part2]
3977
password: oh:no= x #should be better
3978
text: { values starting with { continues
3979
until reaching a line with }
3980
3981
Everything from # and behind is regarded comments and ignored. Comments can be on any line.
3982
To keep a # char, put a \ in front of it.
3983
3984
A C< : > or C< = > separates keys and values. Spaces at the beginning or end of lines are
3985
ignored (after removal of #comments), as are any spaces before and after : and = separators.
3986
3987
Empty lines or lines with no C< : > or C< = > is also ignored. Keys and values can contain
3988
internal spaces and tabs, but not at the beginning or end.
3989
3990
Multi-line values must start and end with { and }. Using { and } keep spaces at the start
3991
or end in both one-line and multi-line values.
3992
3993
Sections are marked with C<< [sectionname] >>. Section names, keys and values is case
3994
sensitive. C above the first section or below and empty C<< [] >> is placed
3995
both in the empty section in the returned hash and as top level key/values.
3996
3997
C can be a simpler alternative to the core module L which has
3998
its own hassles.
3999
4000
$Acme::Tools::Read_conf_empty_section=1; #default 0 (was 1 in version 0.16)
4001
my %conf = read_conf('/etc/your/thing.conf');
4002
print $conf{''}{switch}; #prints OK with the file above
4003
print $conf{switch}; #prints OK here as well
4004
4005
=cut
4006
4007
our $Read_conf_empty_section=0;
4008
sub read_conf {
4009
3
3
1
18
my($fn,$hr)=(@_,{});
4010
3
100
14
my $conf=ref($fn)?$$fn:readfile($fn);
4011
3
101
$conf=~s,\s*(?
4012
3
32
my($section,@l)=('',split"\n",$conf);
4013
3
12
while(@l) {
4014
63
93
my $l=shift@l;
4015
63
100
330
if( $l=~/^\s*\[\s*(.*?)\s*\]/ ) {
100
4016
12
22
$section=$1;
4017
12
100
68
$$hr{$1}||={};
4018
}
4019
elsif( $l=~/^\s*([^\:\=]+)[:=]\s*(.*?)\s*$/ ) {
4020
33
66
33
108
my $ml=sub{my$v=shift;$v.="\n".shift@l while $v=~/^\{[^\}]*$/&&@l;$v=~s/^\{(.*)\}\s*$/$1/s;$v=~s,\\#,#,g;$v};
33
71
33
168
33
68
33
52
33
60
4021
33
71
my $v=&$ml($2);
4022
33
100
66
145
$$hr{$section}{$1}=$v if length($section) or $Read_conf_empty_section;
4023
33
100
175
$$hr{$1}=$v if !length($section);
4024
}
4025
}
4026
3
25
%$hr;
4027
}
4028
# my $incfn=sub{return $1 if $_[0]=~m,^(/.+),;my$f=$fn;$f=~s,[^/]+$,$_[0],;$f};
4029
# s,]+)>,"".readfile(&$incfn($1)),eg; #todo
4030
4031
4032
=head2 openstr
4033
4034
# returned from openstr:
4035
open my $FH, openstr("fil.txt") or die; # fil.txt
4036
open my $FH, openstr("fil.gz") or die; # zcat fil.gz |
4037
open my $FH, openstr("fil.bz2") or die; # bzcat fil.bz2 |
4038
open my $FH, openstr("fil.xz") or die; # xzcat fil.xz |
4039
open my $FH, openstr(">fil.txt") or die; # > fil.txt
4040
open my $FH, openstr(">fil.gz") or die; # | gzip > fil.gz
4041
open my $FH, openstr(">fil.bz2") or die; # | bzip2 > fil.bz2
4042
open my $FH, openstr(">fil.xz") or die; # | xz > fil.bz2
4043
4044
Environment variable PATH is used. So in the examples above, /bin/gzip
4045
is returned instead of gzip if /bin is the first directory in
4046
$ENV{PATH} containing an executable file gzip. Dirs /usr/bin, /bin and
4047
/usr/local/bin is added to PATH in openstr(). They are checked even if
4048
PATH is empty.
4049
4050
=cut
4051
4052
our @Openstrpath=(grep$_,split(":",$ENV{PATH}),qw(/usr/bin /bin /usr/local/bin));
4053
sub openstr {
4054
14
14
1
4221
my($fn,$ext)=(shift()=~/^(.*?(?:\.(t?gz|bz2|xz))?)$/i);
4055
14
100
389
return $fn if !$ext;
4056
6
50
6
42
my $prog=sub{@Openstrpath or return $_[0];(grep -x$_, map "$_/$_[0]", @Openstrpath)[0] or die};
6
50
26
6
108929
4057
$fn =~ /^\s*>/
4058
? "| ".(&$prog({qw/tgz gzip gz gzip bz2 bzip2 xz xz/ }->{lc($ext)})).$fn
4059
6
100
89
: &$prog({qw/tgz zcat gz zcat bz2 bzcat xz xzcat/}->{lc($ext)})." $fn |";
4060
}
4061
4062
=head1 TIME FUNCTIONS
4063
4064
=head2 tms - timestring, works somewhat like the Gnu/Linux C command and Oracle's C
4065
4066
Converts timestamps to more readable forms of time strings.
4067
4068
Converts seconds since I and time strings on the form C to other forms.
4069
4070
B One, two or three arguments.
4071
4072
B A format string.
4073
4074
B An epock C number or a time
4075
string of the form YYYYMMDD-HH24:MI:SS or YYYYMMDDTHH:MI:SS or
4076
YYYY-MM-DDTHH:MI:SS (in which T is litteral and HH is the 24-hour
4077
version of hours) or YYYYMMDD. Uses the current C if the
4078
second argument is missing.
4079
4080
TODO: Formats with % as in C (C<%Y%m%d> and so on)
4081
4082
B True or false. If true and first argument
4083
is eight digits: Its interpreted as a date like YYYYMMDD time string,
4084
not an epoch time. If true and first argument is six digits its
4085
interpreted as a date like DDMMYY (not YYMMDD!).
4086
4087
B a date or clock string on the wanted form.
4088
4089
B
4090
4091
Prints C<< 3. july 1997 >> if thats the dato today:
4092
4093
perl -MAcme::Tools -le 'print timestr("D. month YYYY")'
4094
4095
print tms("HH24:MI"); # prints 23:55 if thats the time now
4096
tms("HH24:MI",time()); # ...same,since time() is the default
4097
tms("HH:MI",time()-5*60); # 23:50 if that was the time 5 minutes ago
4098
tms("HH:MI",time()-5*60*60); # 18:55 if thats the time 5 hours ago
4099
tms("Day Month Dth YYYY HH:MI"); # Saturday July 1st 2004 23:55 (big S, big J)
4100
tms("Day D. Month YYYY HH:MI"); # Saturday 8. July 2004 23:55 (big S, big J)
4101
tms("DAY D. MONTH YYYY HH:MI"); # SATURDAY 8. JULY 2004 23:55 (upper)
4102
tms("dy D. month YYYY HH:MI"); # sat 8. july 2004 23:55 (small s, small j)
4103
tms("Dy DD. MON YYYY HH12:MI am"); # Sat 08. JUL 2004 11:55 pm (HH12, am becomes pm if after 12)
4104
tms("DD-MON-YYYY"); # 03-MAY-2004 (mon, english)
4105
4106
The following list of codes in the first argument will be replaced:
4107
4108
YYYY Year, four digits
4109
YY Year, two digits, i.e. 04 instead of 2004
4110
yyyy Year, four digits, but nothing if its the current year
4111
YYYY|HH:MI Year if its another year than the current, a time in hours and minutes elsewise
4112
MM Month, two digits. I.e. 08 for August
4113
DD Day of month, two digits. I.e. 01 (not 1) for the first day in a month
4114
D Day of month, one digit. I.e. 1 (not 01)
4115
HH Hour. From 00 to 23.
4116
HH24 Same as HH.
4117
HH12 12 becomes 12 (never 00), 13 becomes 01, 14 02 and so on.
4118
Note: 00 after midnight becomes 12 (am). Tip: always include the code
4119
am in a format string that uses HH12.
4120
MI Minutt. Fra 00 til 59.
4121
SS Sekund. Fra 00 til 59.
4122
am Becomes am or pm
4123
pm Same
4124
AM Becomes AM or PM (upper case)
4125
PM Same
4126
4127
Month The full name of the month in English from January to December
4128
MONTH Same in upper case (JANUARY)
4129
month Same in lower case (january)
4130
Mont Jan Feb Mars Apr May June July Aug Sep Oct Nov Dec
4131
Mont. Jan. Feb. Mars Apr. May June July Aug. Sep. Oct. Nov. Dec. (always four chars)
4132
Mon Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec (always three chars)
4133
4134
Day The full name of the weekday. Sunday to Saturday
4135
Dy Three letters: Sun Mon Tue Wed Thu Fri Sat
4136
DAY Upper case
4137
DY Upper case
4138
Dth 1st 2nd 3rd 4th 5th ... 11th 12th ... 20th 21st 22nd 23rd 24th ... 30th 31st
4139
4140
WW Week number of the year 01-53 according to the ISO8601-definition (which most countries uses)
4141
WWUS Week number of the year 01-53 according to the most used definition in the USA.
4142
Other definitions also exists.
4143
4144
epoch Converts a time string from YYYYMMDD-HH24:MI:SS, YYYYMMDD-HH24:MI:SS, YYYYMMDDTHH:MI:SS,
4145
YYYY-MM-DDTHH:MI:SS or YYYYMMDD to the number of seconds since January 1st 1970.
4146
Commonly known as the Unix epoch.
4147
4148
JDN Julian day number. Integer. The number of days since the day starting at noon on January 1 4713 BC
4149
JD Same as JDN but a float accounting for the time of day
4150
4151
TODO: sub smt() (tms backward... or something better named, converts the other way)
4152
As to_date and to_char in Oracle. Se maybe L instead
4153
4154
B (optional) Is_date. False|true, default false. If true, the second argument is
4155
interpreted as a date of the form YYYYMMDD, not as a number of seconds since epoch (January 1st 1970).
4156
4157
=cut
4158
4159
#Se også L og L
4160
4161
our $Tms_pattern;
4162
our %Tms_str=
4163
('MÅNED' => [4, 'JANUAR','FEBRUAR','MARS','APRIL','MAI','JUNI','JULI',
4164
'AUGUST','SEPTEMBER','OKTOBER','NOVEMBER','DESEMBER' ],
4165
'Måned' => [4, 'Januar','Februar','Mars','April','Mai','Juni','Juli',
4166
'August','September','Oktober','November','Desember'],
4167
'måned' => [4, 'januar','februar','mars','april','mai','juni','juli',
4168
'august','september','oktober','november','desember'],
4169
'MÅNE.' => [4, 'JAN.','FEB.','MARS','APR.','MAI','JUNI','JULI','AUG.','SEP.','OKT.','NOV.','DES.'],
4170
'Måne.' => [4, 'Jan.','Feb.','Mars','Apr.','Mai','Juni','Juli','Aug.','Sep.','Okt.','Nov.','Des.'],
4171
'måne.' => [4, 'jan.','feb.','mars','apr.','mai','juni','juli','aug.','sep.','okt.','nov.','des.'],
4172
'MÅNE' => [4, 'JAN','FEB','MARS','APR','MAI','JUNI','JULI','AUG','SEP','OKT','NOV','DES'],
4173
'Måne' => [4, 'Jan','Feb','Mars','Apr','Mai','Juni','Juli','Aug','Sep','Okt','Nov','Des'],
4174
'måne' => [4, 'jan','feb','mars','apr','mai','juni','juli','aug','sep','okt','nov','des'],
4175
'MÅN' => [4, 'JAN','FEB','MAR','APR','MAI','JUN','JUL','AUG','SEP','OKT','NOV','DES'],
4176
'Mån' => [4, 'Jan','Feb','Mar','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Des'],
4177
'mån' => [4, 'jan','feb','mar','apr','mai','jun','jul','aug','sep','okt','nov','des'],
4178
'MONTH' => [4, 'JANUARY','FEBRUARY','MARCH','APRIL','MAY','JUNE','JULY',
4179
'AUGUST','SEPTEMBER','OCTOBER','NOVEMBER','DECEMBER'],
4180
'Month' => [4, 'January','February','March','April','May','June','July',
4181
'August','September','October','November','December'],
4182
'month' => [4, 'january','february','march','april','may','june','july',
4183
'august','september','october','november','december'],
4184
'MONT.' => [4, 'JAN.','FEB.','MAR.','APR.','MAY','JUNE','JULY','AUG.','SEP.','OCT.','NOV.','DEC.'],
4185
'Mont.' => [4, 'Jan.','Feb.','Mar.','Apr.','May','June','July','Aug.','Sep.','Oct.','Nov.','Dec.'],
4186
'mont.' => [4, 'jan.','feb.','mar.','apr.','may','june','july','aug.','sep.','oct.','nov.','dec.'],
4187
'MONT' => [4, 'JAN','FEB','MAR','APR','MAY','JUNE','JULY','AUG','SEP','OCT','NOV','DEC'],
4188
'Mont' => [4, 'Jan','Feb','Mar','Apr','May','June','July','Aug','Sep','Oct','Nov','Dec'],
4189
'mont' => [4, 'jan','feb','mar','apr','may','june','july','aug','sep','oct','nov','dec'],
4190
'MON' => [4, 'JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'],
4191
'Mon' => [4, 'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
4192
'mon' => [4, 'jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'],
4193
'DAY' => [6, 'SUNDAY','MONDAY','TUESDAY','WEDNESDAY','THURSDAY','FRIDAY','SATURDAY'],
4194
'Day' => [6, 'Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
4195
'day' => [6, 'sunday','monday','tuesday','wednesday','thursday','friday','saturday'],
4196
'DY' => [6, 'SUN','MON','TUE','WED','THU','FRI','SAT'],
4197
'Dy' => [6, 'Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
4198
'dy' => [6, 'sun','mon','tue','wed','thu','fri','sat'],
4199
'DAG' => [6, 'SØNDAG','MANDAG','TIRSDAG','ONSDAG','TORSDAG','FREDAG','LØRDAG'],
4200
'Dag' => [6, 'Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'],
4201
'dag' => [6, 'søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag'],
4202
'DG' => [6, 'SØN','MAN','TIR','ONS','TOR','FRE','LØR'],
4203
'Dg' => [6, 'Søn','Man','Tir','Ons','Tor','Fre','Lør'],
4204
'dg' => [6, 'søn','man','tir','ons','tor','fre','lør'],
4205
);
4206
my $_tms_inited=0;
4207
sub tms_init {
4208
1
50
1
0
7
return if $_tms_inited++;
4209
1
5
for(qw(MAANED Maaned maaned MAAN Maan maan),'MAANE.','Maane.','maane.'){
4210
9
36
$Tms_str{$_}=$Tms_str{replace($_,"aa","å","AA","Å")};
4211
}
4212
45
121
$Tms_pattern=join("|",map{quotemeta($_)}
4213
1
23
sort{length($b)<=>length($a)}
197
402
4214
keys %Tms_str);
4215
#uten sort kan "måned" bli "mared", fordi "mån"=>"mar"
4216
}
4217
4218
0
0
sub totime {
4219
4220
}
4221
4222
sub date_ok {
4223
0
0
0
0
my($y,$m,$d)=@_;
4224
0
0
0
0
return date_ok($1,$2,$3) if @_==1 and $_[0]=~/^(\d{4})(\d\d)(\d\d)$/;
4225
0
0
0
return 0 if $y!~/^\d\d\d\d$/;
4226
0
0
0
0
return 0 if $m<1||$m>12||$d<1||$d>(31,$y%4||$y%100==0&&$y%400?28:29,31,30,31,30,31,31,30,31,30,31)[$m-1];
0
0
0
0
4227
0
0
return 1;
4228
}
4229
4230
sub weeknum {
4231
0
0
0
0
0
return weeknum(tms('YYYYMMDD')) if @_<1;
4232
0
0
0
0
return weeknum($1,$2,$3) if @_==1 and $_[0]=~/^(\d{4})(\d\d)(\d\d)$/;
4233
0
0
my($year,$month,$day)= @_;
4234
0
0
eval{
4235
0
0
0
if(@_<2){
0
4236
0
0
0
if($year=~/^\d{8}$/) { ($year,$month,$day)=unpack("A4A2A2",$year) }
0
0
0
4237
0
0
elsif($year>99999999){ ($year,$month,$day)=(localtime($year))[5,4,3]; $year+=1900; $month++ }
0
0
0
0
4238
0
0
else {die}
4239
}
4240
0
0
elsif(@_!=3){croak}
4241
0
0
0
croak if !date_ok(sprintf("%04d%02d%02d",$year,$month,$day));
4242
};
4243
0
0
0
croak "ERROR: Wrong args Acme::Tools::weeknum(".join(",",@_).")" if $@;
4244
28
28
23013
use integer;#heltallsdivisjon
28
303
28
158
4245
0
0
my $y=$year+4800-(14-$month)/12;
4246
0
0
my $j=$day+(153*($month+(14-$month)/12*12-3)+2)/5+365*$y+$y/4-$y/100+$y/400-32045;
4247
0
0
my $d=($j+31741-$j%7)%146097%36524%1461;
4248
0
0
return (($d-$d/1460)%365+$d/1460)/7+1;
4249
}
4250
4251
sub tms {
4252
40
50
66
40
1
56004
return undef if @_>1 and not defined $_[1]; #time=undef => undef
4253
40
100
107
if(@_==1){
4254
2
15
my @lt=localtime();
4255
2
50
13
$_[0] eq 'YYYY' and return 1900+$lt[5];
4256
2
50
9
$_[0] eq 'YYYYMMDD' and return sprintf("%04d%02d%02d",1900+$lt[5],1+$lt[4],$lt[3]);
4257
2
100
66
56
$_[0] =~ $Re_isnum and @lt=localtime($_[0]) and return sprintf("%04d%02d%02d-%02d:%02d:%02d",1900+$lt[5],1+$lt[4],@lt[3,2,1,0]);
4258
}
4259
39
72
my($format,$time,$is_date)=@_;
4260
39
100
96
$time=time_fp() if !defined$time;
4261
39
100
100
326
($time,$format)=($format,$time) if @_>=2 and $format=~/^[\d+\:\-\.]+$/; #swap /hm/
4262
39
203
my @lt=localtime($time);
4263
#todo? $is_date=0 if $time=~s/^\@(\-?\d)/$1/; #@n where n is sec since epoch makes it clear that its not a formatted, as in `date`
4264
#todo? date --date='TZ="America/Los_Angeles" 09:00 next Fri' #`info date`
4265
# Fri Nov 13 18:00:00 CET 2015
4266
#date --date="next Friday" #--date or -d
4267
#date --date="last friday"
4268
#date --date="2 days ago"
4269
#date --date="yesterday" #or tomorrow
4270
#date --date="-1 day" #date --date='10 week'
4271
4272
39
50
102
if( $is_date ){
4273
0
0
0
0
my $yy2c=sub{10+$_[0]>$lt[5]%100?"20":"19"}; #hm 10+
0
0
4274
0
0
0
$time=totime(&$yy2c($1)."$1$2$3")."000000" if $time=~/^(\d\d)(\d\d)(\d\d)$/;
4275
0
0
0
$time=totime("$1$2${3}000000") if $time=~/^((?:18|19|20)\d\d)(\d\d)(\d\d)$/; #hm 18-20?
4276
}
4277
else {
4278
39
50
141
$time = yyyymmddhh24miss_time("$1$2$3$4$5$6") #yyyymmddhh24miss_time ???
4279
if $time=~/^((?:19|20|18)\d\d) #yyyy
4280
(0[1-9]|1[012]) #mm
4281
(0[1-9]|[12]\d|3[01]) \-? #dd
4282
([01]\d|2[0-3]) \:? #hh24
4283
([0-5]\d) \:? #mi
4284
([0-5]\d) $/x; #ss
4285
}
4286
39
100
78
tms_init() if !$_tms_inited;
4287
39
100
108
return sprintf("%04d%02d%02d-%02d:%02d:%02d",1900+$lt[5],1+$lt[4],@lt[3,2,1,0]) if !$format;
4288
38
463
my %p=('%'=>'%',
4289
a=>'Dy',
4290
A=>'Day',
4291
b=>'Mon',
4292
b=>'Month',
4293
c=>'Dy Mon D HH:MI:SS YYYY',
4294
C=>'CC',
4295
d=>'DD',
4296
D=>'MM/DD/YY',
4297
e=>'D',
4298
F=>'YYYY-MM-DD',
4299
#G=>'',
4300
h=>'Month', H=>'HH24', I=>'HH12',
4301
j=>'DoY', #day of year
4302
k=>'H24', _H=>'H24',
4303
l=>'H12', _I=>'H12',
4304
m=>'MM', M=>'MI',
4305
n=>"\n",
4306
#N=>'NS', #sprintf%09d,1e9*(time_fp()-time()) #000000000..999999999
4307
p=>'AM', #AM|PM upper (yes, opposite: date +%H%M%S%P%p)
4308
P=>'am', #am|pm lower
4309
S=>'SS',
4310
t=>"\t",
4311
T=>'HH24:MI:SS',
4312
u=>'DoW', #day of week 1..7, 1=mon 7=sun
4313
w=>'DoW0', #day of week 0..6, 1=mon 0=sun
4314
#U=>'WoYs', #week num of year 00..53, sunday as first day of week
4315
#V=>'UKE', #ISO week num of year 01..53, monday as first day of week
4316
#W=>'WoYm', #week num of year 00..53, monday as first day of week, not ISO!
4317
#x=>$ENV{locale's date representation}, #e.g. MM/DD/YY
4318
#X=>$ENV{locale's time representation}, #e.g. HH/MI/SS
4319
y=>'YY',
4320
Y=>'YYYY',
4321
#z=>'TZHHMI', #time zone hour minute e.g. -0430
4322
#':z'=>'TZHH:MI',
4323
#'::z'=>'TZHH:MI:SS',
4324
#':::z'=>'TZ', #number of :'s necessary precision, e.g. -02 or +03:30
4325
#Z=>'TZN', #e.g. CET, EDT, ...
4326
);
4327
38
260
my $pkeys=join"|",keys%p;
4328
38
1641
$format=~s,\%($pkeys),$p{$1},g;
4329
38
459
$format=~s/($Tms_pattern)/$Tms_str{$1}[1+$lt[$Tms_str{$1}[0]]]/g;
4330
38
92
$format=~s/YYYY / 1900+$lt[5] /gxe;
13
44
4331
38
0
70
$format=~s/(\s?)yyyy / $lt[5]==(localtime)[5]?"":$1.(1900+$lt[5])/gxe;
0
0
4332
38
65
$format=~s/YY / sprintf("%02d",$lt[5]%100) /gxei;
1
5
4333
38
67
$format=~s|CC | sprintf("%02d",(1900+$lt[5])/100) |gxei;
2
10
4334
38
59
$format=~s/MM / sprintf("%02d",$lt[4]+1) /gxe;
5
25
4335
38
56
$format=~s/mm / sprintf("%d",$lt[4]+1) /gxe;
0
0
4336
38
57
$format=~s,M/ , ($lt[4]+1).'/' ,gxe;
2
7
4337
38
52
$format=~s,/M , '/'.($lt[4]+1) ,gxe;
1
4
4338
38
62
$format=~s/DD / sprintf("%02d",$lt[3]) /gxe;
6
25
4339
38
110
$format=~s/d0w|dow0 / $lt[6] /gxei;
4
11
4340
38
100
67
$format=~s/dow / $lt[6]?$lt[6]:7 /gxei;
2
8
4341
38
81
$format=~s/d0y|doy0 / $lt[7] /gxei; #0-364 (365 leap)
2
7
4342
38
117
$format=~s/doy / $lt[7]+1 /gxei; #1-365 (366 leap)
1
4
4343
38
98
$format=~s/D(?![AaGgYyEeNn]) / $lt[3] /gxe; #EN pga desember og wednesday
5
15
4344
38
55
$format=~s/dd / sprintf("%d",$lt[3]) /gxe;
0
0
4345
38
100
50
88
$format=~s/hh12|HH12 / sprintf("%02d",$lt[2]<13?$lt[2]||12:$lt[2]-12)/gxe;
8
51
4346
38
86
$format=~s/HH24|HH24|HH|hh / sprintf("%02d",$lt[2]) /gxe;
4
22
4347
38
77
$format=~s/MI / sprintf("%02d",$lt[1]) /gxei;
12
42
4348
38
100
68
$format=~s{SS\.([1-9]) }{ sprintf("%0*.$1f",3+$1,$lt[0]+(repl($time,qr/^[^\.]+/)||0)) }gxei;
3
21
4349
38
64
$format=~s/SS / sprintf("%02d",$lt[0]) /gxei;
4
16
4350
38
100
77
$format=~s/am|pm / $lt[2]<13 ? 'am' : 'pm' /gxe;
4
14
4351
38
100
75
$format=~s/AM|PM / $lt[2]<13 ? 'AM' : 'PM' /gxe;
4
13
4352
38
107
$format=~s/WWI|WW / sprintf("%02d",weeknum($time)) /gxei;
0
0
4353
38
60
$format=~s/W / weeknum($time) /gxei;
0
0
4354
38
323
$format;
4355
}
4356
4357
=head2 easter
4358
4359
Input: A year (a four digit number)
4360
4361
Output: array of two numbers: day and month of Easter Sunday that year. Month 3 means March and 4 means April.
4362
4363
sub easter { use integer;my$Y=shift;my$C=$Y/100;my$L=($C-$C/4-($C-($C-17)/25)/3+$Y%19*19+15)%30;
4364
(($L-=$L>28||($L>27?1-(21-$Y%19)/11:0))-=($Y+$Y/4+$L+2-$C+$C/4)%7)<4?($L+28,3):($L-3,4) }
4365
4366
...is a "golfed" version of Oudins algorithm (1940) L
4367
(see also http://www.smart.net/~mmontes/ec-cal.html )
4368
4369
Valid for any Gregorian year. Dates repeat themselves after 70499183
4370
lunations = 2081882250 days = ca 5699845 years. However, our planet will
4371
by then have a different rotation and spin time...
4372
4373
Example:
4374
4375
( $day, $month ) = easter( 2012 ); # $day == 8 and $month == 4
4376
4377
Example 2:
4378
4379
my @e=map sprintf("%02d%02d", reverse(easter($_))), 1800..300000;
4380
print "First: ".min(@e)." Last: ".max(@e)."\n"; # First: 0322 Last: 0425
4381
4382
=cut
4383
4384
28
28
1
53963
sub easter { use integer;my$Y=shift;my$C=$Y/100;my$L=($C-$C/4-($C-($C-17)/25)/3+$Y%19*19+15)%30;
28
5000
52
28
124
5000
11620
5000
6188
5000
8536
4385
5000
100
66
24827
(($L-=$L>28||($L>27?1-(21-$Y%19)/11:0))-=($Y+$Y/4+$L+2-$C+$C/4)%7)<4?($L+28,3):($L-3,4) }
4386
4387
4388
=head2 time_fp
4389
4390
No input arguments.
4391
4392
Return the same number as perls C except with decimals (fractions of a second, _fp as in floating point number).
4393
4394
print time_fp(),"\n";
4395
print time(),"\n";
4396
4397
Could write:
4398
4399
1116776232.38632
4400
4401
...if that is the time now.
4402
4403
Or just:
4404
4405
1116776232
4406
4407
...from perl's internal C if C isn't installed and available.
4408
4409
4410
=cut
4411
4412
sub time_fp { # {return 0+gettimeofday} is just as well?
4413
12416
50
12416
1
19116
eval{ require Time::HiRes } or return time();
12416
75841
4414
12416
47644
my($sec,$mic)=Time::HiRes::gettimeofday();
4415
12416
53145
return $sec+$mic/1e6; #1e6 not portable?
4416
}
4417
4418
=head2 sleep_fp
4419
4420
sleep_fp() work as the built in C<< sleep() >> but also accepts fractional seconds:
4421
4422
sleep_fp(0.020); # sleeps for 20 milliseconds
4423
4424
Sub sleep_fp do a C, thus it might take some
4425
extra time the first call. To avoid that, add C<< use Time::HiRes >>
4426
to your code. Sleep_fp should not be trusted for accuracy to more than
4427
a tenth of a second. Virtual machines tend to be less accurate (sleep
4428
longer) than physical ones. This was tested on VMware and RHEL
4429
(Linux). See also L.
4430
4431
=head2 sleeps
4432
4433
=head2 sleepms
4434
4435
=head2 sleepus
4436
4437
=head2 sleepns
4438
4439
sleep_fp(0.020); #sleeps for 20 milliseconds
4440
sleeps(0.020); #sleeps for 20 milliseconds, sleeps() is a synonym to sleep_fp()
4441
sleepms(20); #sleeps for 20 milliseconds
4442
sleepus(20000); #sleeps for 20000 microseconds = 20 milliseconds
4443
sleepns(20000000); #sleeps for 20 million nanoseconds = 20 milliseconds
4444
4445
=cut
4446
4447
13
50
13
1
81
sub sleep_fp { eval{require Time::HiRes} or (sleep(shift()),return);Time::HiRes::sleep(shift()) }
13
156
13
221802
4448
1
50
1
1
12
sub sleeps { eval{require Time::HiRes} or (sleep(shift()),return);Time::HiRes::sleep(shift()) }
1
14
1
10162
4449
1
50
1
1
18
sub sleepms { eval{require Time::HiRes} or (sleep(shift()/1e3),return);Time::HiRes::sleep(shift()/1e3) }
1
24
1
10168
4450
1
50
1
1
14
sub sleepus { eval{require Time::HiRes} or (sleep(shift()/1e6),return);Time::HiRes::sleep(shift()/1e6) }
1
21
1
10158
4451
1
50
1
1
13
sub sleepns { eval{require Time::HiRes} or (sleep(shift()/1e9),return);Time::HiRes::sleep(shift()/1e9) }
1
19
1
10140
4452
4453
=head2 eta
4454
4455
Estimated time of arrival (ETA).
4456
4457
for(@files){
4458
...do work on file...
4459
my $eta = eta( ++$i, 0+@files ); # file now, number of files
4460
print "" . localtime($eta);
4461
}
4462
4463
..DOC MISSING..
4464
4465
=head2 etahhmm
4466
4467
...NOT YET
4468
4469
=cut
4470
4471
#http://en.wikipedia.org/wiki/Kalman_filter god idé?
4472
our %Eta;
4473
our $Eta_forgetfulness=2;
4474
sub eta {
4475
2004
100
2004
1
15296
my($id,$pos,$end,$time_fp)=( @_==2 ? (join(";",caller()),@_) : @_ );
4476
2004
66
4544
$time_fp||=time_fp();
4477
2004
100
4853
my $a=$Eta{$id}||=[];
4478
2004
4265
push @$a, [$pos,$time_fp];
4479
2004
100
5365
@$a=@$a[map$_*2,0..@$a/2] if @$a>40; #hm 40
4480
2004
100
100
9090
splice(@$a,-2,1) if @$a>1 and $$a[-2][0]==$$a[-1][0]; #same pos as last
4481
2004
100
4117
return undef if @$a<2;
4482
2001
2410
my @eta;
4483
2001
3755
for(2..@$a){
4484
58602
158569
push @eta, $$a[-1][1] + ($end-$$a[-1][0]) * ($$a[-1][1]-$$a[-$_][1])/($$a[-1][0]-$$a[-$_][0]);
4485
}
4486
2001
2940
my($sum,$sumw,$w)=(0,0,1);
4487
2001
3107
for(@eta){
4488
58602
74926
$sum+=$w*$_;
4489
58602
70451
$sumw+=$w;
4490
58602
83675
$w/=$Eta_forgetfulness;
4491
}
4492
2001
2729
my $avg=$sum/$sumw;
4493
2001
6189
return $avg;
4494
# return avg(@eta);
4495
#return $$a[-1][1] + ($end-$$a[-1][0]) * ($$a[-1][1]-$$a[-2][1])/($$a[-1][0]-$$a[-2][0]);
4496
0
0
1;
4497
}
4498
4499
=head2 sleep_until
4500
4501
sleep_until(0.5) sleeps until half a second has passed since the last
4502
call to sleep_until. This example starts the next job excactly ten
4503
seconds after the last job started even if the last job lasted for a
4504
while (but not more than ten seconds):
4505
4506
for(@jobs){
4507
sleep_until(10);
4508
print localtime()."\n";
4509
...heavy job....
4510
}
4511
4512
Might print:
4513
4514
Thu Jan 12 16:00:00 2012
4515
Thu Jan 12 16:00:10 2012
4516
Thu Jan 12 16:00:20 2012
4517
4518
...and so on even if the C<< ...heavy job... >>-part takes more than a
4519
second to complete. Whereas if sleep(10) was used, each job would
4520
spend more than ten seconds in average since the work time would be
4521
added to sleep(10).
4522
4523
Note: sleep_until() will remember the time of ANY last call of this sub,
4524
not just the one on the same line in the source code (this might change
4525
in the future). The first call to sleep_until() will be the same as
4526
sleep_fp() or Perl's own sleep() if the argument is an integer.
4527
4528
=cut
4529
4530
our $Time_last_sleep_until;
4531
sub sleep_until {
4532
0
0
0
1
0
my $s=@_==1?shift():0;
4533
0
0
my $time=time_fp();
4534
0
0
my $sleep=$s-($time-nvl($Time_last_sleep_until,0));
4535
0
0
$Time_last_sleep_until=time;
4536
0
0
0
sleep_fp($sleep) if $sleep>0;
4537
}
4538
4539
=head2 leapyear
4540
4541
B A year. A four digit number.
4542
4543
B True (1) or false (0) of whether the year is a leap year or
4544
not. (Uses current calendar even for periods before leapyears was used).
4545
4546
print join(", ",grep leapyear($_), 1900..2014)."\n";
4547
4548
1904, 1908, 1912, 1916, 1920, 1924, 1928, 1932, 1936, 1940, 1944, 1948, 1952, 1956,
4549
1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000, 2004, 2008, 2012
4550
4551
Note: 1900 is not a leap year, but 2000 is. Years divided by 100 is a leap year only
4552
if it can be divided by 400.
4553
4554
=cut
4555
4556
0
0
0
1
0
sub leapyear{$_[0]%400?$_[0]%100?$_[0]%4?0:1:0:1} #bool
0
0
4557
4558
#http://rosettacode.org/wiki/Levenshtein_distance#Perl
4559
our %ldist_cache;
4560
sub ldist {
4561
0
0
0
0
my($s,$t,$l) = @_;
4562
0
0
0
return length($t) if !$s;
4563
0
0
0
return length($s) if !$t;
4564
0
0
0
0
%ldist_cache=() if !$l and 1000<0+%ldist_cache;
4565
$ldist_cache{$s,$t} ||=
4566
0
0
0
do {
4567
0
0
my($s1,$t1) = ( substr($s,1), substr($t,1) );
4568
0
0
0
substr($s,0,1) eq substr($t,0,1)
4569
? ldist($s1,$t1)
4570
: 1 + min( ldist($s1,$t1,1+$l), ldist($s,$t1,1+$l), ldist($s1,$t,1+$l) );
4571
};
4572
}
4573
4574
=head1 OTHER
4575
4576
=head2 nvl
4577
4578
The I function (or I function)
4579
4580
C takes two or more arguments. (Oracles nvl-function take just two)
4581
4582
Returns the value of the first input argument with length() > 0.
4583
4584
Return I if there is no such input argument.
4585
4586
In perl 5.10 and perl 6 this will most often be easier with the C< //
4587
> operator, although C and C<< // >> treats empty strings C<"">
4588
differently. Sub nvl here considers empty strings and undef the same.
4589
4590
=cut
4591
4592
sub nvl {
4593
38
100
66
38
1
285
return $_[0] if defined $_[0] and length($_[0]) or @_==1;
100
4594
22
100
83
return $_[1] if @_==2;
4595
9
100
36
return nvl(@_[1..$#_]) if @_>2;
4596
1
4
return undef;
4597
}
4598
4599
=head2 decode_num
4600
4601
See L.
4602
4603
=head2 decode
4604
4605
C and C works just as Oracles C.
4606
4607
C and C accordingly uses perl operators C and C<==> for comparison.
4608
4609
Examples:
4610
4611
my $a=123;
4612
print decode($a, 123,3, 214,4, $a); # prints 3
4613
print decode($a, 123=>3, 214=>4, $a); # prints 3, same thing since => is synonymous to comma in Perl
4614
4615
The first argument is tested against the second, fourth, sixth and so on,
4616
and then the third, fifth, seventh and so on is
4617
returned if decode() finds an equal string or number.
4618
4619
In the above example: 123 maps to 3, 124 maps to 4 and the last argument $a is returned elsewise.
4620
4621
More examples:
4622
4623
my $a=123;
4624
print decode($a, 123=>3, 214=>7, $a); # also 3, note that => is synonym for , (comma) in perl
4625
print decode($a, 122=>3, 214=>7, $a); # prints 123
4626
print decode($a, 123.0 =>3, 214=>7); # prints 3
4627
print decode($a, '123.0'=>3, 214=>7); # prints nothing (undef), no last argument default value here
4628
print decode_num($a, 121=>3, 221=>7, '123.0','b'); # prints b
4629
4630
Sort of:
4631
4632
decode($string, %conversion, $default);
4633
4634
The last argument is returned as a default if none of the keys in the keys/value-pairs matched.
4635
4636
A more perl-ish and often faster way of doing the same:
4637
4638
{123=>3, 214=>7}->{$a} || $a # (beware of 0)
4639
4640
=cut
4641
4642
sub decode {
4643
4
50
4
1
10
croak "Must have a mimimum of two arguments" if @_<2;
4644
4
6
my $uttrykk=shift;
4645
4
50
100
11
if(defined$uttrykk){ shift eq $uttrykk and return shift or shift for 1..@_/2 }
4
33
37
4646
0
0
0
else { !defined shift and return shift or shift for 1..@_/2 }
0
4647
2
8
return shift;
4648
}
4649
4650
sub decode_num {
4651
1
50
1
1
5
croak "Must have a mimimum of two arguments" if @_<2;
4652
1
2
my $uttrykk=shift;
4653
1
50
100
3
if(defined$uttrykk){ shift == $uttrykk and return shift or shift for 1..@_/2 }
1
33
15
4654
0
0
0
else { !defined shift and return shift or shift for 1..@_/2 }
0
4655
0
0
return shift;
4656
}
4657
4658
=head2 qrlist
4659
4660
Input: An array of values to be used to test againts for existence.
4661
4662
Output: A reference to a regular expression. That is a C
4663
4664
The regex sets $1 if it match.
4665
4666
Example:
4667
4668
my @list=qw/ABc XY DEF DEFG XYZ/;
4669
my $filter=qrlist("ABC","DEF","XY."); # makes a regex of it qr/^(\QABC\E|\QDEF\E|\QXY.\E)$/
4670
my @filtered= grep { $_ =~ $filter } @list; # returns DEF and XYZ, but not XYZ because the . char is taken literally
4671
4672
Note: Filtering with hash lookups are WAY faster.
4673
4674
Source:
4675
4676
sub qrlist (@) { my $str=join"|",map quotemeta, @_; qr/^($str)$/ }
4677
4678
=cut
4679
4680
sub qrlist (@) {
4681
0
0
1
0
my $str=join"|",map quotemeta,@_;
4682
0
0
return qr/^($str)$/;
4683
}
4684
4685
=head2 ansicolor
4686
4687
Perhaps easier to use than L ?
4688
4689
B One argument. A string where the char C<¤> have special
4690
meaning and is replaced by color codings depending on the letter
4691
following the C<¤>.
4692
4693
B The same string, but with C<¤letter> replaced by ANSI color
4694
codes respected by many types terminal windows. (xterm, telnet, ssh,
4695
telnet, rlog, vt100, cygwin, rxvt and such...).
4696
4697
B
4698
4699
¤r red
4700
¤g green
4701
¤b blue
4702
¤y yellow
4703
¤m magenta
4704
¤B bold
4705
¤u underline
4706
¤c clear
4707
¤¤ reset, quits and returns to default text color.
4708
4709
B
4710
4711
print ansicolor("This is maybe ¤ggreen¤¤?");
4712
4713
Prints I where the word I is shown in green.
4714
4715
If L is not installed or not found, returns the input
4716
string with every C<¤> including the following code letters
4717
removed. (That is: ansicolor is safe to use even if Term::ANSIColor is
4718
not installed, you just don't get the colors).
4719
4720
See also L.
4721
4722
=cut
4723
4724
sub ansicolor {
4725
0
0
1
0
my $txt=shift;
4726
0
0
0
eval{require Term::ANSIColor} or return replace($txt,qr/¤./);
0
0
4727
0
0
my %h=qw/r red g green b blue y yellow m magenta B bold u underline c clear ¤ reset/;
4728
0
0
my $re=join"|",keys%h;
4729
0
0
$txt=~s/¤($re)/Term::ANSIColor::color($h{$1})/ge;
0
0
4730
0
0
return $txt;
4731
}
4732
4733
=head2 ccn_ok
4734
4735
Checks if a Credit Card number (CCN) has correct control digits according to the LUHN-algorithm from 1960.
4736
This method of control digits is used by MasterCard, Visa, American Express,
4737
Discover, Diners Club / Carte Blanche, JCB and others.
4738
4739
B
4740
4741
A credit card number. Can contain non-digits, but they are removed internally before checking.
4742
4743
B
4744
4745
Something true or false.
4746
4747
Or more accurately:
4748
4749
Returns C (false) if the input argument is missing digits.
4750
4751
Returns 0 (zero, which is false) is the digits is not correct according to the LUHN algorithm.
4752
4753
Returns 1 or the name of a credit card company (true either way) if the last digit is an ok control digit for this ccn.
4754
4755
The name of the credit card company is returned like this (without the C<'> character)
4756
4757
Returns (wo '') Starts on Number of digits
4758
------------------------------ ------------------------ ----------------
4759
'MasterCard' 51-55 16
4760
'Visa' 4 13 eller 16
4761
'American Express' 34 eller 37 15
4762
'Discover' 6011 16
4763
'Diners Club / Carte Blanche' 300-305, 36 eller 38 14
4764
'JCB' 3 16
4765
'JCB' 2131 eller 1800 15
4766
4767
And should perhaps have had:
4768
4769
'enRoute' 2014 eller 2149 15
4770
4771
...but that card uses either another control algorithm or no control
4772
digits at all. So C is never returned here.
4773
4774
If the control digits is valid, but the input does not match anything in the column C, 1 is returned.
4775
4776
(This is also the same control digit mechanism used in Norwegian KID numbers on payment bills)
4777
4778
The first digit in a credit card number is supposed to tell what "industry" the card is meant for:
4779
4780
MII Digit Value Issuer Category
4781
--------------------------- ----------------------------------------------------
4782
0 ISO/TC 68 and other industry assignments
4783
1 Airlines
4784
2 Airlines and other industry assignments
4785
3 Travel and entertainment
4786
4 Banking and financial
4787
5 Banking and financial
4788
6 Merchandizing and banking
4789
7 Petroleum
4790
8 Telecommunications and other industry assignments
4791
9 National assignment
4792
4793
...although this has no meaning to C.
4794
4795
The first six digits is I, that is the bank
4796
(probably). The rest in the "account number", except the last digits,
4797
which is the control digit. Max length on credit card numbers are 19
4798
digits.
4799
4800
=cut
4801
4802
sub ccn_ok {
4803
0
0
1
0
my $ccn=shift(); #credit card number
4804
0
0
$ccn=~s/\D+//g;
4805
0
0
0
if(KID_ok($ccn)){
4806
0
0
0
return "MasterCard" if $ccn=~/^5[1-5]\d{14}$/;
4807
0
0
0
return "Visa" if $ccn=~/^4\d{12}(?:\d{3})?$/;
4808
0
0
0
return "American Express" if $ccn=~/^3[47]\d{13}$/;
4809
0
0
0
return "Discover" if $ccn=~/^6011\d{12}$/;
4810
0
0
0
return "Diners Club / Carte Blanche" if $ccn=~/^3(?:0[0-5]\d{11}|[68]\d{12})$/;
4811
0
0
0
return "JCB" if $ccn=~/^(?:3\d{15}|(?:2131|1800)\d{11})$/;
4812
0
0
return 1;
4813
}
4814
#return "enRoute" if $ccn=~/^(?:2014|2149)\d{11}$/; #ikke LUHN-krav?
4815
0
0
return 0;
4816
}
4817
4818
=head2 KID_ok
4819
4820
Checks if a norwegian KID number has an ok control digit.
4821
4822
To check if a customer has typed the number correctly.
4823
4824
This uses the LUHN algorithm (also known as mod-10) from 1960 which is also used
4825
internationally in control digits for credit card numbers, and Canadian social security ID numbers as well.
4826
4827
The algorithm, as described in Phrack (47-8) (a long time hacker online publication):
4828
4829
"For a card with an even number of digits, double every odd numbered
4830
digit and subtract 9 if the product is greater than 9. Add up all the
4831
even digits as well as the doubled-odd digits, and the result must be
4832
a multiple of 10 or it's not a valid card. If the card has an odd
4833
number of digits, perform the same addition doubling the even numbered
4834
digits instead."
4835
4836
B A KID-nummer. Must consist of digits 0-9 only, otherwise a die (croak) happens.
4837
4838
B
4839
4840
- Returns undef if the input argument is missing.
4841
4842
- Returns 0 if the control digit (the last digit) does not satify the LUHN/mod-10 algorithm.
4843
4844
- Returns 1 if ok
4845
4846
B L
4847
4848
=cut
4849
4850
sub KID_ok {
4851
0
0
0
1
0
croak "Non-numeric argument" if $_[0]=~/\D/;
4852
0
0
0
my @k=split//,shift or return undef;
4853
0
0
my $s;$s+=pop(@k)+[qw/0 2 4 6 8 1 3 5 7 9/]->[pop@k] while @k;
0
0
4854
0
0
0
$s%10==0?1:0;
4855
}
4856
4857
4858
4859
=head2 range
4860
4861
B
4862
4863
One or more numeric arguments:
4864
4865
First: x (first returned element)
4866
4867
Second: y (last but not including)
4868
4869
Third: step, default 1. The step between each returned element
4870
4871
If a fourth, fifth and so on arguments are given, they change the step for each returned element. As first derivative, second derivative.
4872
4873
B
4874
4875
If one argument: returns the array C<(0 .. x-1)>
4876
4877
If two arguments: returns the array C<(x .. y-1)>
4878
4879
If three arguments: The default step is 1. Use a third argument to use a different step.
4880
4881
B
4882
4883
print join ",", range(11); # prints 0,1,2,3,4,5,6,7,8,9,10 (but not 11)
4884
print join ",", range(2,11); # 2,3,4,5,6,7,8,9,10 (but not 11)
4885
print join ",", range(11,2,-1); # 11,10,9,8,7,6,5,4,3
4886
print join ",", range(2,11,3); # 2,5,8
4887
print join ",", range(11,2,-3); # 11,8,5
4888
print join ",", range(11,2,+3); # prints nothing
4889
4890
print join ", ",range(2,11,1,0.1); # 2, 3, 4.1, 5.3, 6.6, 8, 9.5 adds 0.1 to step each time
4891
print join ", ",range(2,11,1,0.1,-0.01); # 2, 3, 4.1, 5.29, 6.56, 7.9, 9.3, 10.75
4892
4893
Note: In the Python language and others, C is a build in iterator (a
4894
generator), not an array. This saves memory for large sets and sometimes time.
4895
Use C in L to get a similar lazy generator in Perl.
4896
4897
=cut
4898
4899
sub range {
4900
8
100
8
1
35
return _range_accellerated(@_) if @_>3; #se under
4901
6
13
my($x,$y,$jump)=@_;
4902
6
100
71
return ( 0 .. $x-1 ) if @_==1;
4903
5
100
21
return ( $x .. $y-1 ) if @_==2;
4904
4
50
33
28
croak "Wrong number of arguments or jump==0" if @_!=3 or $jump==0;
4905
4
6
my @r;
4906
4
100
11
if($jump>0){ while($x<$y){ push @r, $x; $x+=$jump } }
2
8
772
856
772
1292
4907
2
6
else { while($x>$y){ push @r, $x; $x+=$jump } }
12
18
12
21
4908
4
57
return @r;
4909
}
4910
4911
#jumps derivative, double der., trippled der usw
4912
sub _range_accellerated {
4913
2
2
6
my($x,$y,@jump)=@_;
4914
2
4
my @r;
4915
2
50
0
10
my $test = $jump[0]>=0 ? sub{$x<$y} : sub{$x>$y};
17
45
0
0
4916
2
6
while(&$test()){
4917
15
23
push @r, $x;
4918
15
18
$x+=$jump[0];
4919
15
50
$jump[$_-1]+=$jump[$_] for 1..$#jump;
4920
}
4921
2
29
return @r;
4922
}
4923
4924
=head2 permutations
4925
4926
How many ways (permutations) can six people be placed around a table:
4927
4928
If one person: one
4929
If two persons: two (they can swap places)
4930
If three persons: six
4931
If four persons: 24
4932
If five persons: 120
4933
If six persons: 720
4934
4935
The formula is C where the postfix unary operator C, also known as I is defined like:
4936
C. Example: C<5! = 5 * 4 * 3 * 2 * 1 = 120>.Run this to see the 100 first C<< n! >>
4937
4938
perl -MAcme::Tools -le'$i=big(1);print "$_!=",$i*=$_ for 1..100'
4939
4940
1! = 1
4941
2! = 2
4942
3! = 6
4943
4! = 24
4944
5! = 120
4945
6! = 720
4946
7! = 5040
4947
8! = 40320
4948
9! = 362880
4949
10! = 3628800
4950
.
4951
.
4952
.
4953
100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
4954
4955
C takes a list and return a list of arrayrefs for each
4956
of the permutations of the input list:
4957
4958
permutations('a','b'); #returns (['a','b'],['b','a'])
4959
4960
permutations('a','b','c'); #returns (['a','b','c'],['a','c','b'],
4961
# ['b','a','c'],['b','c','a'],
4962
# ['c','a','b'],['c','b','a'])
4963
4964
Up to five input arguments C is probably as fast as it
4965
can be in this pure perl implementation (see source). For more than
4966
five, it could be faster. How fast is it now: Running with different
4967
n, this many time took that many seconds:
4968
4969
n times seconds
4970
-- ------- ---------
4971
2 100000 0.32
4972
3 10000 0.09
4973
4 10000 0.33
4974
5 1000 0.18
4975
6 100 0.27
4976
7 10 0.21
4977
8 1 0.17
4978
9 1 1.63
4979
10 1 17.00
4980
4981
If the first argument is a coderef, that sub will be called for each permutation and the return from those calls with be the real return from C. For example this:
4982
4983
print for permutations(sub{join"",@_},1..3);
4984
4985
...will print the same as:
4986
4987
print for map join("",@$_), permutations(1..3);
4988
4989
...but the first of those two uses less RAM if 3 has been say 9.
4990
Changing 3 with 10, and many computers hasn't enough memory
4991
for the latter.
4992
4993
The examples prints:
4994
4995
123
4996
132
4997
213
4998
231
4999
312
5000
321
5001
5002
If you just want to say calculate something on each permutation,
5003
but is not interested in the list of them, you just don't
5004
take the return. That is:
5005
5006
my $ant;
5007
permutations(sub{$ant++ if $_[-1]>=$_[0]*2},1..9);
5008
5009
...is the same as:
5010
5011
$$_[-1]>=$$_[0]*2 and $ant++ for permutations(1..9);
5012
5013
...but the first uses next to nothing of memory compared to the latter. They have about the same speed.
5014
(The examples just counts the permutations where the last number is at least twice as large as the first)
5015
5016
C was created to find all combinations of a persons
5017
name. This is useful in "fuzzy" name searches with
5018
L if you can not be certain what is first, middle
5019
and last names. In foreign or unfamiliar names it can be difficult to
5020
know that.
5021
5022
=cut
5023
5024
#TODO: se test_perl.pl
5025
5026
sub permutations {
5027
2
50
2
1
16
my $code=ref($_[0]) eq 'CODE' ? shift() : undef;
5028
2
50
33
11
$code and @_<6 and return map &$code(@$_),permutations(@_);
5029
5030
2
50
7
return [@_] if @_<2;
5031
5032
2
100
19
return ([@_[0,1]],[@_[1,0]]) if @_==2;
5033
5034
1
50
19
return ([@_[0,1,2]],[@_[0,2,1]],[@_[1,0,2]],
5035
[@_[1,2,0]],[@_[2,0,1]],[@_[2,1,0]]) if @_==3;
5036
5037
0
0
0
return ([@_[0,1,2,3]],[@_[0,1,3,2]],[@_[0,2,1,3]],[@_[0,2,3,1]],
5038
[@_[0,3,1,2]],[@_[0,3,2,1]],[@_[1,0,2,3]],[@_[1,0,3,2]],
5039
[@_[1,2,0,3]],[@_[1,2,3,0]],[@_[1,3,0,2]],[@_[1,3,2,0]],
5040
[@_[2,0,1,3]],[@_[2,0,3,1]],[@_[2,1,0,3]],[@_[2,1,3,0]],
5041
[@_[2,3,0,1]],[@_[2,3,1,0]],[@_[3,0,1,2]],[@_[3,0,2,1]],
5042
[@_[3,1,0,2]],[@_[3,1,2,0]],[@_[3,2,0,1]],[@_[3,2,1,0]]) if @_==4;
5043
5044
0
0
0
return ([@_[0,1,2,3,4]],[@_[0,1,2,4,3]],[@_[0,1,3,2,4]],[@_[0,1,3,4,2]],[@_[0,1,4,2,3]],
5045
[@_[0,1,4,3,2]],[@_[0,2,1,3,4]],[@_[0,2,1,4,3]],[@_[0,2,3,1,4]],[@_[0,2,3,4,1]],
5046
[@_[0,2,4,1,3]],[@_[0,2,4,3,1]],[@_[0,3,1,2,4]],[@_[0,3,1,4,2]],[@_[0,3,2,1,4]],
5047
[@_[0,3,2,4,1]],[@_[0,3,4,1,2]],[@_[0,3,4,2,1]],[@_[0,4,1,2,3]],[@_[0,4,1,3,2]],
5048
[@_[0,4,2,1,3]],[@_[0,4,2,3,1]],[@_[0,4,3,1,2]],[@_[0,4,3,2,1]],[@_[1,0,2,3,4]],
5049
[@_[1,0,2,4,3]],[@_[1,0,3,2,4]],[@_[1,0,3,4,2]],[@_[1,0,4,2,3]],[@_[1,0,4,3,2]],
5050
[@_[1,2,0,3,4]],[@_[1,2,0,4,3]],[@_[1,2,3,0,4]],[@_[1,2,3,4,0]],[@_[1,2,4,0,3]],
5051
[@_[1,2,4,3,0]],[@_[1,3,0,2,4]],[@_[1,3,0,4,2]],[@_[1,3,2,0,4]],[@_[1,3,2,4,0]],
5052
[@_[1,3,4,0,2]],[@_[1,3,4,2,0]],[@_[1,4,0,2,3]],[@_[1,4,0,3,2]],[@_[1,4,2,0,3]],
5053
[@_[1,4,2,3,0]],[@_[1,4,3,0,2]],[@_[1,4,3,2,0]],[@_[2,0,1,3,4]],[@_[2,0,1,4,3]],
5054
[@_[2,0,3,1,4]],[@_[2,0,3,4,1]],[@_[2,0,4,1,3]],[@_[2,0,4,3,1]],[@_[2,1,0,3,4]],
5055
[@_[2,1,0,4,3]],[@_[2,1,3,0,4]],[@_[2,1,3,4,0]],[@_[2,1,4,0,3]],[@_[2,1,4,3,0]],
5056
[@_[2,3,0,1,4]],[@_[2,3,0,4,1]],[@_[2,3,1,0,4]],[@_[2,3,1,4,0]],[@_[2,3,4,0,1]],
5057
[@_[2,3,4,1,0]],[@_[2,4,0,1,3]],[@_[2,4,0,3,1]],[@_[2,4,1,0,3]],[@_[2,4,1,3,0]],
5058
[@_[2,4,3,0,1]],[@_[2,4,3,1,0]],[@_[3,0,1,2,4]],[@_[3,0,1,4,2]],[@_[3,0,2,1,4]],
5059
[@_[3,0,2,4,1]],[@_[3,0,4,1,2]],[@_[3,0,4,2,1]],[@_[3,1,0,2,4]],[@_[3,1,0,4,2]],
5060
[@_[3,1,2,0,4]],[@_[3,1,2,4,0]],[@_[3,1,4,0,2]],[@_[3,1,4,2,0]],[@_[3,2,0,1,4]],
5061
[@_[3,2,0,4,1]],[@_[3,2,1,0,4]],[@_[3,2,1,4,0]],[@_[3,2,4,0,1]],[@_[3,2,4,1,0]],
5062
[@_[3,4,0,1,2]],[@_[3,4,0,2,1]],[@_[3,4,1,0,2]],[@_[3,4,1,2,0]],[@_[3,4,2,0,1]],
5063
[@_[3,4,2,1,0]],[@_[4,0,1,2,3]],[@_[4,0,1,3,2]],[@_[4,0,2,1,3]],[@_[4,0,2,3,1]],
5064
[@_[4,0,3,1,2]],[@_[4,0,3,2,1]],[@_[4,1,0,2,3]],[@_[4,1,0,3,2]],[@_[4,1,2,0,3]],
5065
[@_[4,1,2,3,0]],[@_[4,1,3,0,2]],[@_[4,1,3,2,0]],[@_[4,2,0,1,3]],[@_[4,2,0,3,1]],
5066
[@_[4,2,1,0,3]],[@_[4,2,1,3,0]],[@_[4,2,3,0,1]],[@_[4,2,3,1,0]],[@_[4,3,0,1,2]],
5067
[@_[4,3,0,2,1]],[@_[4,3,1,0,2]],[@_[4,3,1,2,0]],[@_[4,3,2,0,1]],[@_[4,3,2,1,0]]) if @_==5;
5068
5069
0
0
my(@r,@p,@c,@i,@n); @i=(0,@_); @p=@c=1..@_; @n=1..@_-1;
0
0
0
0
0
0
5070
PERM:
5071
0
0
while(1){
5072
0
0
0
if($code){if(defined wantarray){push(@r,&$code(@i[@p]))}else{&$code(@i[@p])}}else{push@r,[@i[@p]]}
0
0
0
0
0
0
0
0
0
5073
0
0
0
for my$i(@n){splice@p,$i,0,shift@p;next PERM if --$c[$i];$c[$i]=$i+1}
0
0
0
0
0
0
5074
return@r
5075
0
0
}
5076
}
5077
5078
=head2 cart
5079
5080
Cartesian product
5081
5082
B
5083
5084
Input: two or more arrayrefs with accordingly x, y, z and so on number of elements.
5085
5086
Output: An array of x * y * z number of arrayrefs. The arrays being the cartesian product of the input arrays.
5087
5088
It can be useful to think of this as joins in SQL. In C statements with
5089
more tables behind C, but without any C condition to join the tables.
5090
5091
B
5092
5093
B
5094
5095
- Either two or more arrayrefs with x, y, z and so on number of elements.
5096
5097
- Or coderefs to subs containing condition checks. Somewhat like C conditions in SQL.
5098
5099
B An array of x * y * z number of arrayrefs (the cartesian product)
5100
minus the ones that did not fulfill the condition(s).
5101
5102
This of is as joins with one or more where conditions as coderefs.
5103
5104
The coderef input arguments can be placed last or among the array refs
5105
to save both runtime and memory if the conditions depend on
5106
arrays further back.
5107
5108
B
5109
5110
for(cart(\@a1,\@a2,\@a3)){
5111
my($a1,$a2,$a3) = @$_;
5112
print "$a1,$a2,$a3\n";
5113
}
5114
5115
Prints the same as this:
5116
5117
for my $a1 (@a1){
5118
for my $a2 (@a2){
5119
for my $a3 (@a3){
5120
print "$a1,$a2,$a3\n";
5121
}
5122
}
5123
}
5124
5125
B (with a condition: the sum of the first two should be dividable with 3)
5126
5127
for( cart( \@a1, \@a2, sub{sum(@$_)%3==0}, \@a3 ) ) {
5128
my($a1,$a2,$a3)=@$_;
5129
print "$a1,$a2,$a3\n";
5130
}
5131
5132
Prints the same as this:
5133
5134
for my $a1 (@a1){
5135
for my $a2 (@a2){
5136
next if 0==($a1+$a2)%3;
5137
for my $a3 (@a3){
5138
print "$a1,$a2,$a3\n";
5139
}
5140
}
5141
}
5142
5143
B
5144
5145
my @a1 = (1,2);
5146
my @a2 = (10,20,30);
5147
my @a3 = (100,200,300,400);
5148
5149
my $s = join"", map "*".join(",",@$_), cart(\@a1,\@a2,\@a3);
5150
ok( $s eq "*1,10,100*1,10,200*1,10,300*1,10,400*1,20,100*1,20,200"
5151
."*1,20,300*1,20,400*1,30,100*1,30,200*1,30,300*1,30,400"
5152
."*2,10,100*2,10,200*2,10,300*2,10,400*2,20,100*2,20,200"
5153
."*2,20,300*2,20,400*2,30,100*2,30,200*2,30,300*2,30,400");
5154
5155
$s=join"",map "*".join(",",@$_), cart(\@a1,\@a2,\@a3,sub{sum(@$_)%3==0});
5156
ok( $s eq "*1,10,100*1,10,400*1,20,300*1,30,200*2,10,300*2,20,200*2,30,100*2,30,400");
5157
5158
B
5159
5160
Returns hashrefs instead of arrayrefs:
5161
5162
my @cards=cart( #5200 cards: 100 decks of 52 cards
5163
deck => [1..100],
5164
value => [qw/2 3 4 5 6 7 8 9 10 J Q K A/],
5165
col => [qw/heart diamond club star/],
5166
);
5167
for my $card ( mix(@cards) ) {
5168
print "From deck number $$card{deck} we got $$card{value} $$card{col}\n";
5169
}
5170
5171
Note: using sub-ref filters do not work (yet) in hash-mode. Use grep on result instead.
5172
5173
=cut
5174
5175
sub cart {
5176
5
5
1
850
my @ars=@_;
5177
5
100
17
if(!ref($_[0])){ #if hash-mode detected
5178
1
33
2
my(@k,@v); push@k,shift@ars and push@v,shift@ars while @ars;
1
13
5179
1
7
return map{my%h;@h{@k}=@$_;\%h}cart(@v);
24
26
24
68
24
44
5180
}
5181
4
6
my @res=map[$_],@{shift@ars};
4
20
5182
4
9
for my $ar (@ars){
5183
9
100
50
26
@res=grep{&$ar(@$_)}@res and next if ref($ar) eq 'CODE';
24
51
5184
8
13
@res=map{my$r=$_;map{[@$r,$_]}@$ar}@res;
34
38
34
49
120
257
5185
}
5186
4
63
return @res;
5187
}
5188
5189
sub cart_easy { #not tested/exported http://stackoverflow.com/questions/2457096/in-perl-how-can-i-get-the-cartesian-product-of-multiple-sets
5190
0
0
0
0
my $last = pop @_;
5191
0
0
0
@_ ? (map {my$left=$_; map [@$left, $_], @$last } cart_easy(@_) )
0
0
0
0
5192
: (map [$_], @$last);
5193
}
5194
5195
=head2 reduce
5196
5197
From: Why Functional Programming Matters: L
5198
5199
L
5200
5201
DON'T TRY THIS AT HOME, C PROGRAMMERS.
5202
5203
sub reduce (&@) {
5204
my ($proc, $first, @rest) = @_;
5205
return $first if @rest == 0;
5206
local ($a, $b) = ($first, reduce($proc, @rest));
5207
return $proc->();
5208
}
5209
5210
Many functions can then be implemented with very little code. Such as:
5211
5212
sub mean { (reduce {$a + $b} @_) / @_ }
5213
5214
=cut
5215
5216
sub reduce (&@) {
5217
0
0
1
0
my ($proc, $first, @rest) = @_;
5218
0
0
0
return $first if @rest == 0;
5219
28
28
135865
no warnings;
28
61
28
32373
5220
0
0
local ($a, $b) = ($first, reduce($proc, @rest));
5221
0
0
return $proc->();
5222
}
5223
5224
5225
=head2 pivot
5226
5227
Resembles the pivot table function in Excel.
5228
5229
C is used to spread out a slim and long table to a visually improved layout.
5230
5231
For instance spreading out the results of C-selects from SQL:
5232
5233
pivot( arrayref, columnname1, columnname2, ...)
5234
5235
pivot( ref_to_array_of_arrayrefs, @list_of_names_to_down_fields )
5236
5237
The first argument is a ref to a two dimensional table.
5238
5239
The rest of the arguments is a list which also signals the number of
5240
columns from left in each row that is ending up to the left of the
5241
data table, the rest ends up at the top and the last element of
5242
each row ends up as data.
5243
5244
top1 top1 top1 top1
5245
left1 left2 left3 top2 top2 top2 top2
5246
----- ----- ----- ---- ---- ---- ----
5247
data data data data
5248
data data data data
5249
data data data data
5250
5251
Example:
5252
5253
my @table=(
5254
["1997","Gerd", "Weight", "Summer",66],
5255
["1997","Gerd", "Height", "Summer",170],
5256
["1997","Per", "Weight", "Summer",75],
5257
["1997","Per", "Height", "Summer",182],
5258
["1997","Hilde","Weight", "Summer",62],
5259
["1997","Hilde","Height", "Summer",168],
5260
["1997","Tone", "Weight", "Summer",70],
5261
5262
["1997","Gerd", "Weight", "Winter",64],
5263
["1997","Gerd", "Height", "Winter",158],
5264
["1997","Per", "Weight", "Winter",73],
5265
["1997","Per", "Height", "Winter",180],
5266
["1997","Hilde","Weight", "Winter",61],
5267
["1997","Hilde","Height", "Winter",164],
5268
["1997","Tone", "Weight", "Winter",69],
5269
5270
["1998","Gerd", "Weight", "Summer",64],
5271
["1998","Gerd", "Height", "Summer",171],
5272
["1998","Per", "Weight", "Summer",76],
5273
["1998","Per", "Height", "Summer",182],
5274
["1998","Hilde","Weight", "Summer",62],
5275
["1998","Hilde","Height", "Summer",168],
5276
["1998","Tone", "Weight", "Summer",70],
5277
5278
["1998","Gerd", "Weight", "Winter",64],
5279
["1998","Gerd", "Height", "Winter",171],
5280
["1998","Per", "Weight", "Winter",74],
5281
["1998","Per", "Height", "Winter",183],
5282
["1998","Hilde","Weight", "Winter",62],
5283
["1998","Hilde","Height", "Winter",168],
5284
["1998","Tone", "Weight", "Winter",71],
5285
);
5286
5287
.
5288
5289
my @reportA=pivot(\@table,"Year","Name");
5290
print "\n\nReport A\n\n".tablestring(\@reportA);
5291
5292
Will print:
5293
5294
Report A
5295
5296
Year Name Height Height Weight Weight
5297
Summer Winter Summer Winter
5298
---- ----- ------ ------ ------ ------
5299
1997 Gerd 170 158 66 64
5300
1997 Hilde 168 164 62 61
5301
1997 Per 182 180 75 73
5302
1997 Tone 70 69
5303
1998 Gerd 171 171 64 64
5304
1998 Hilde 168 168 62 62
5305
1998 Per 182 183 76 74
5306
1998 Tone 70 71
5307
5308
.
5309
5310
my @reportB=pivot([map{$_=[@$_[0,3,2,1,4]]}(@t=@table)],"Year","Season");
5311
print "\n\nReport B\n\n".tablestring(\@reportB);
5312
5313
Will print:
5314
5315
Report B
5316
5317
Year Season Height Height Height Weight Weight Weight Weight
5318
Gerd Hilde Per Gerd Hilde Per Tone
5319
---- ------ ------ ------ ----- ----- ------ ------ ------
5320
1997 Summer 170 168 182 66 62 75 70
5321
1997 Winter 158 164 180 64 61 73 69
5322
1998 Summer 171 168 182 64 62 76 70
5323
1998 Winter 171 168 183 64 62 74 71
5324
5325
.
5326
5327
my @reportC=pivot([map{$_=[@$_[1,2,0,3,4]]}(@t=@table)],"Name","Attributt");
5328
print "\n\nReport C\n\n".tablestring(\@reportC);
5329
5330
Will print:
5331
5332
Report C
5333
5334
Name Attributt 1997 1997 1998 1998
5335
Summer Winter Summer Winter
5336
----- --------- ------ ------ ------ ------
5337
Gerd Height 170 158 171 171
5338
Gerd Weight 66 64 64 64
5339
Hilde Height 168 164 168 168
5340
Hilde Weight 62 61 62 62
5341
Per Height 182 180 182 183
5342
Per Weight 75 73 76 74
5343
Tone Weight 70 69 70 71
5344
5345
.
5346
5347
my @reportD=pivot([map{$_=[@$_[1,2,0,3,4]]}(@t=@table)],"Name");
5348
print "\n\nReport D\n\n".tablestring(\@reportD);
5349
5350
Will print:
5351
5352
Report D
5353
5354
Name Height Height Height Height Weight Weight Weight Weight
5355
1997 1997 1998 1998 1997 1997 1998 1998
5356
Summer Winter Summer Winter Summer Winter Summer Winter
5357
----- ------ ------ ------ ------ ------ ------ ------ ------
5358
Gerd 170 158 171 171 66 64 64 64
5359
Hilde 168 164 168 168 62 61 62 62
5360
Per 182 180 182 183 75 73 76 74
5361
Tone 70 69 70 71
5362
5363
Options:
5364
5365
Options to sort differently and show sums and percents are available. (...MORE DOC ON THAT LATER...)
5366
5367
See also L
5368
5369
=cut
5370
5371
sub pivot {
5372
4
4
1
11
my($tabref,@vertikalefelt)=@_;
5373
4
50
15
my %opt=ref($vertikalefelt[-1]) eq 'HASH' ? %{pop(@vertikalefelt)} : ();
0
0
5374
4
50
16
my $opt_sum=1 if $opt{sum};
5375
4
50
0
8
my $opt_pro=exists $opt{prosent}?$opt{prosent}||0:undef;
5376
4
50
23
my $sortsub = $opt{'sortsub'} || \&_sortsub;
5377
4
33
18
my $sortsub_bortover = $opt{'sortsub_bortover'} || $sortsub;
5378
4
33
29
my $sortsub_nedover = $opt{'sortsub_nedover'} || $sortsub;
5379
#print serialize(\%opt,'opt');
5380
#print serialize(\$opt_pro,'opt_pro');
5381
4
7
my $antned=0+@vertikalefelt;
5382
4
7
my $bakerst=-1+@{$$tabref[0]};
4
10
5383
4
5
my(%h,%feltfinnes,%sum);
5384
#print "Bakerst<$bakerst>\n";
5385
4
9
for(@$tabref){
5386
112
256
my $rad=join($;,@$_[0..($antned-1)]);
5387
112
222
my $felt=join($;,@$_[$antned..($bakerst-1)]);
5388
112
150
my $verdi=$$_[$bakerst];
5389
112
50
240
length($rad) or $rad=' ';
5390
112
50
185
length($felt) or $felt=' ';
5391
112
227
$h{$rad}{$felt}=$verdi;
5392
112
239
$h{$rad}{"%$felt"}=$verdi;
5393
112
50
33
411
if($opt_sum or defined $opt_pro){
5394
0
0
$h{$rad}{Sum}+=$verdi;
5395
0
0
$sum{$felt}+=$verdi;
5396
0
0
$sum{Sum}+=$verdi;
5397
}
5398
112
164
$feltfinnes{$felt}++;
5399
112
50
319
$feltfinnes{"%$felt"}++ if $opt_pro;
5400
}
5401
4
26
my @feltfinnes = sort $sortsub_bortover keys%feltfinnes;
5402
4
50
12
push @feltfinnes, "Sum" if $opt_sum;
5403
4
8
my @t=([@vertikalefelt,map{replace($_,$;,"\n")}@feltfinnes]);
23
42
5404
#print serialize(\@feltfinnes,'feltfinnes');
5405
#print serialize(\%h,'h');
5406
#print "H = ".join(", ",sort _sortsub keys%h)."\n";
5407
4
18
for my $rad (sort $sortsub_nedover keys(%h)){
5408
my @rad=(split($;,$rad),
5409
map{
5410
23
50
33
154
if(/^\%/ and defined $opt_pro){
120
309
5411
0
0
my $sum=$h{$rad}{Sum};
5412
0
0
my $verdi=$h{$rad}{$_};
5413
0
0
0
if($sum!=0){
5414
0
0
0
defined $verdi
5415
?sprintf("%*.*f",3+1+$opt_pro,$opt_pro,100*$verdi/$sum)
5416
:$verdi;
5417
}
5418
else{
5419
0
0
0
$verdi!=0?"div0":$verdi;
5420
}
5421
}
5422
else{
5423
120
243
$h{$rad}{$_};
5424
}
5425
}
5426
@feltfinnes);
5427
23
84
push(@t,[@rad]);
5428
}
5429
4
50
12
push(@t,"-",["Sum",(map{""}(2..$antned)),map{print "<$_>\n";$sum{$_}}@feltfinnes]) if $opt_sum;
0
0
0
0
0
0
5430
4
53
return @t;
5431
}
5432
5433
# default sortsub for pivot()
5434
5435
sub _sortsub {
5436
28
28
160
no warnings;
28
47
28
13139
5437
#my $c=($a<=>$b)||($a cmp $b);
5438
#return $c if $c;
5439
#printf "%-30s %-30s ",replace($a,$;,','),replace($b,$;,',');
5440
72
72
489
my @a=split $;,$a;
5441
72
470
my @b=split $;,$b;
5442
72
172
for(0..$#a){
5443
110
232
my $c=$a[$_]<=>$b[$_];
5444
110
100
66
398
return $c if $c and "$a[$_]$b[$_]"!~/[iI][nN][fF]|þ/i; # inf(inity)
5445
96
125
$c=$a[$_]cmp$b[$_];
5446
96
100
274
return $c if $c;
5447
}
5448
0
0
return 0;
5449
}
5450
5451
=head2 tablestring
5452
5453
B a reference to an array of arrayrefs -- a two dimensional table of strings and numbers
5454
5455
B a string containing the textual table -- a string of two or more lines
5456
5457
The first arrayref in the list refers to a list of either column headings (scalar)
5458
or ... (...more later...)
5459
5460
In this output table:
5461
5462
- the columns will not be wider than necessary by its widest value (any -tags are removed in every internal width-calculation)
5463
5464
- multi-lined cell values are handled also
5465
5466
- and so are html-tags, if the output is to be used inside -tags on a web page.
5467
5468
- columns with just numeric values are right justified (header row excepted)
5469
5470
Example:
5471
5472
print tablestring([
5473
[qw/AA BB CCCC/],
5474
[123,23,"d"],
5475
[12,23,34],
5476
[77,88,99],
5477
["lin\nes",12,"asdff\nfdsa\naa"],[0,22,"adf"]
5478
]);
5479
5480
Prints this string of 11 lines:
5481
5482
AA BB CCCC
5483
--- -- -----
5484
123 23 d
5485
12 23 34
5486
77 8 99
5487
5488
lin 12 asdff
5489
es fdsa
5490
aa
5491
5492
10 22 adf
5493
5494
As you can see, rows containing multi-lined cells gets an empty line before and after the row to separate it more clearly.
5495
5496
=cut
5497
5498
sub tablestring {
5499
5
5
1
27
my $tab=shift;
5500
5
50
14
my %o=$_[0] ? %{shift()} : ();
0
0
5501
5
8
my $fjern_tom=$o{fjern_tomme_kolonner};
5502
5
8
my $ikke_space=$o{ikke_space};
5503
5
50
23
my $nodup=$o{nodup}||0;
5504
5
7
my $ikke_hodestrek=$o{ikke_hodestrek};
5505
5
50
13
my $pagesize=exists $o{pagesize} ? $o{pagesize}-3 : 9999999;
5506
5
6
my $venstretvang=$o{venstre};
5507
5
6
my(@bredde,@venstre,@hoeyde,@ikketom,@nodup);
5508
5
7
my $hode=1;
5509
5
8
my $i=0;
5510
5
8
my $j;
5511
5
11
for(@$tab){
5512
33
34
$j=0;
5513
33
43
$hoeyde[$i]=0;
5514
33
37
my $nodup_rad=$nodup;
5515
33
50
72
if(ref($_) eq 'ARRAY'){
5516
33
53
for(@$_){
5517
210
272
my $celle=$_;
5518
210
100
431
$bredde[$j]||=0;
5519
210
50
33
582
if($nodup_rad and $i>0 and $$tab[$i][$j] eq $$tab[$i-1][$j] || ($nodup_rad=0)){
0
33
5520
0
0
0
$celle=$nodup==1?"":$nodup;
5521
0
0
$nodup[$i][$j]=1;
5522
}
5523
else{
5524
210
213
my $hoeyde=0;
5525
210
201
my $bredere;
5526
28
28
1335
no warnings;
28
1237
28
16611
5527
210
100
100
799
$ikketom[$j]=1 if !$hode && length($celle)>0;
5528
210
445
for(split("\n",$celle)){
5529
236
50
411
$bredere=/
5530
236
277
s/<[^>]+>//g;
5531
236
239
$hoeyde++;
5532
236
265
s/>/>/g;
5533
236
258
s/</
5534
236
100
585
$bredde[$j]=length($_)+1+$bredere if length($_)+1+$bredere>$bredde[$j];
5535
236
100
100
1545
$venstre[$j]=1 if $_ && !/^\s*[\-\+]?(\d+|\d*\.\d+)\s*\%?$/ && !$hode;
100
5536
}
5537
210
100
66
614
if( $hoeyde>1 && !$ikke_space){
5538
25
100
53
$hoeyde++ unless $hode;
5539
25
100
100
69
$hoeyde[$i-1]++ if $i>1 && $hoeyde[$i-1]==1;
5540
}
5541
210
100
477
$hoeyde[$i]=$hoeyde if $hoeyde>$hoeyde[$i];
5542
}
5543
210
279
$j++;
5544
}
5545
}
5546
else{
5547
0
0
$hoeyde[$i]=1;
5548
0
0
$ikke_hodestrek=1;
5549
}
5550
33
37
$hode=0;
5551
33
50
$i++;
5552
}
5553
5
9
$i=$#hoeyde;
5554
5
7
$j=$#bredde;
5555
5
50
33
24
if($i==0 or $venstretvang) { @venstre=map{1}(0..$j) }
0
0
0
0
5556
5
50
11
else { for(0..$j){ $venstre[$_]=1 if !$ikketom[$_] } }
33
68
5557
5
8
my @tabut;
5558
5
5
my $rad_startlinje=0;
5559
5
8
my @overskrift;
5560
my $overskrift_forrige;
5561
5
8
for my $x (0..$i){
5562
33
50
88
if($$tab[$x] eq '-'){
5563
0
0
0
my @tegn=map {$$tab[$x-1][$_]=~/\S/?"-":" "} (0..$j);
0
0
5564
0
0
$tabut[$rad_startlinje]=join(" ",map {$tegn[$_] x ($bredde[$_]-1)} (0..$j));
0
0
5565
}
5566
else{
5567
33
54
for my $y (0..$j){
5568
210
50
33
464
next if $fjern_tom && !$ikketom[$y];
5569
28
28
1318
no warnings;
28
49
28
22085
5570
5571
210
0
33
1343
my @celle=
50
5572
!$overskrift_forrige&&$nodup&&$nodup[$x][$y]
5573
?($nodup>0?():((" " x (($bredde[$y]-length($nodup))/2)).$nodup))
5574
:split("\n",$$tab[$x][$y]);
5575
210
434
for(0..($hoeyde[$x]-1)){
5576
261
310
my $linje=$rad_startlinje+$_;
5577
261
100
606
my $txt=shift @celle || '';
5578
261
100
100
1489
$txt=sprintf("%*s",$bredde[$y]-1,$txt) if length($txt)>0 && !$venstre[$y] && ($x>0 || $ikke_hodestrek);
66
66
5579
261
374
$tabut[$linje].=$txt;
5580
261
100
431
if($y==$j){
5581
42
185
$tabut[$linje]=~s/\s+$//;
5582
}
5583
else{
5584
219
223
my $bredere;
5585
219
50
399
$bredere = $txt=~/
5586
219
275
$txt=~s/<[^>]+>//g;
5587
219
271
$txt=~s/>/>/g;
5588
219
245
$txt=~s/</
5589
219
591
$tabut[$linje].= ' ' x ($bredde[$y]-length($txt)-$bredere);
5590
}
5591
}
5592
}
5593
}
5594
33
45
$rad_startlinje+=$hoeyde[$x];
5595
5596
#--lage streker?
5597
33
50
63
if(not $ikke_hodestrek){
5598
33
100
33
155
if($x==0){
50
33
0
5599
5
9
for my $y (0..$j){
5600
33
50
33
64
next if $fjern_tom && !$ikketom[$y];
5601
33
68
$tabut[$rad_startlinje].=('-' x ($bredde[$y]-1))." ";
5602
}
5603
5
8
$rad_startlinje++;
5604
5
15
@overskrift=("",@tabut);
5605
}
5606
elsif(
5607
$x%$pagesize==0 || $nodup>0&&!$nodup[$x+1][$nodup-1]
5608
and $x+1<@$tab
5609
and !$ikke_hodestrek
5610
)
5611
{
5612
0
0
push(@tabut,@overskrift);
5613
0
0
$rad_startlinje+=@overskrift;
5614
0
0
$overskrift_forrige=1;
5615
}
5616
else{
5617
28
52
$overskrift_forrige=0;
5618
}
5619
}
5620
}#for x
5621
5
56
return join("\n",@tabut)."\n";
5622
}
5623
5624
=head2 serialize
5625
5626
Returns a data structure as a string. See also C
5627
(serialize was created long time ago before Data::Dumper appeared on
5628
CPAN, before CPAN even...)
5629
5630
B One to four arguments.
5631
5632
First argument: A reference to the structure you want.
5633
5634
Second argument: (optional) The name the structure will get in the output string.
5635
If second argument is missing or is undef or '', it will get no name in the output.
5636
5637
Third argument: (optional) The string that is returned is also put
5638
into a created file with the name given in this argument. Putting a
5639
C<< > >> char in from of the filename will append that file
5640
instead. Use C<''> or C to not write to a file if you want to
5641
use a fourth argument.
5642
5643
Fourth argument: (optional) A number signalling the depth on which newlines is used in the output.
5644
The default is infinite (some big number) so no extra newlines are output.
5645
5646
B A string containing the perl-code definition that makes that data structure.
5647
The input reference (first input argument) can be to an array, hash or a string.
5648
Those can contain other refs and strings in a deep data structure.
5649
5650
Limitations:
5651
5652
- Code refs are not handled (just returns C)
5653
5654
- Regex, class refs and circular recursive structures are also not handled.
5655
5656
B
5657
5658
$a = 'test';
5659
@b = (1,2,3);
5660
%c = (1=>2, 2=>3, 3=>5, 4=>7, 5=>11);
5661
%d = (1=>2, 2=>3, 3=>\5, 4=>7, 5=>11, 6=>[13,17,19,{1,2,3,'asdf\'\\\''}],7=>'x');
5662
print serialize(\$a,'a');
5663
print serialize(\@b,'tab');
5664
print serialize(\%c,'c');
5665
print serialize(\%d,'d');
5666
print serialize(\("test'n roll",'brb "brb"'));
5667
print serialize(\%d,'d',undef,1);
5668
5669
Prints accordingly:
5670
5671
$a='test';
5672
@tab=('1','2','3');
5673
%c=('1','2','2','3','3','5','4','7','5','11');
5674
%d=('1'=>'2','2'=>'3','3'=>\'5','4'=>'7','5'=>'11','6'=>['13','17','19',{'1'=>'2','3'=>'asdf\'\\\''}]);
5675
('test\'n roll','brb "brb"');
5676
%d=('1'=>'2',
5677
'2'=>'3',
5678
'3'=>\'5',
5679
'4'=>'7',
5680
'5'=>'11',
5681
'6'=>['13','17','19',{'1'=>'2','3'=>'asdf\'\\\''}],
5682
'7'=>'x');
5683
5684
Areas of use:
5685
5686
- Debugging (first and foremost)
5687
5688
- Storing arrays and hashes and data structures of those on file, database or sending them over the net
5689
5690
- eval earlier stored string to get back the data structure
5691
5692
Be aware of the security implications of Cing a perl code string
5693
stored somewhere that unauthorized users can change them! You are
5694
probably better of using L or L without
5695
enabling the CODE-options if you have such security issues.
5696
More on decompiling Perl-code: L or L.
5697
5698
=head2 dserialize
5699
5700
Debug-serialize, dumping data structures for you to look at.
5701
5702
Same as C but the output is given a newline every 80th character.
5703
(Every 80th or whatever C<$Acme::Tools::Dserialize_width> contains)
5704
5705
=cut
5706
5707
our $Dserialize_width=80;
5708
0
0
0
0
sub _kallstack { my $tilbake=shift||0; my @c; my $ret; $ret.=serialize(\@c,"caller$tilbake") while @c=caller(++$tilbake); $ret }
0
0
0
0
0
0
5709
0
0
1
0
sub dserialize{join "\n",serialize(@_)=~/(.{1,$Dserialize_width})/gs}
5710
sub serialize {
5711
28
28
150
no warnings;
28
48
28
127928
5712
1127
1127
1
4775
my($r,$name,$filename,$level)=@_;
5713
1127
100
3033
my @r=(undef,undef,($level||0)-1);
5714
1127
50
2122
if($filename){
5715
0
0
0
open my $fh, '>', $filename or croak("FEIL: could not open file $filename\n" . _kallstack());
5716
0
0
my $ret=serialize($r,$name,undef,$level);
5717
0
0
print $fh "$ret\n1;\n";
5718
0
0
close($fh);
5719
0
0
return $ret;
5720
}
5721
1127
100
2884
if(ref($r) eq 'SCALAR'){
100
100
100
50
0
0
0
0
5722
903
50
1580
return "\$$name=".serialize($r,@r).";\n" if $name;
5723
903
100
1692
return "undef" unless defined $$r;
5724
899
1128
my $ret=$$r;
5725
899
1410
$ret=~s/\\/\\\\/g;
5726
899
1140
$ret=~s/\'/\\'/g;
5727
899
2785
return "'$ret'";
5728
}
5729
elsif(ref($r) eq 'ARRAY'){
5730
72
100
163
return "\@$name=".serialize($r,@r).";\n" if $name;
5731
70
99
my $ret="(";
5732
70
134
for(@$r){
5733
350
819
$ret.=serialize(\$_,@r).",";
5734
350
100
1019
$ret.="\n" if $level>=0;
5735
}
5736
70
237
$ret=~s/,$//;
5737
70
131
$ret.=")";
5738
70
50
144
$ret.=";\n" if $name;
5739
70
235
return $ret;
5740
}
5741
elsif(ref($r) eq 'HASH'){
5742
31
100
250
return "\%$name=".serialize($r,@r).";\n" if $name;
5743
21
37
my $ret="(";
5744
21
105
for(sort keys %$r){
5745
73
193
$ret.=serialize(\$_,@r)."=>".serialize(\$$r{$_},@r).",";
5746
73
50
234
$ret.="\n" if $level>=0;
5747
}
5748
21
84
$ret=~s/,$//;
5749
21
33
$ret.=")";
5750
21
50
55
$ret.=";\n" if $name;
5751
21
132
return $ret;
5752
}
5753
elsif(ref($$r) eq 'ARRAY'){
5754
48
50
92
return "\@$name=".serialize($r,@r).";\n" if $name;
5755
48
63
my $ret="[";
5756
48
89
for(@$$r){
5757
100
555
$ret.=serialize(\$_,@r).",";
5758
100
50
33
487
$ret.="\n" if !defined $level or $level>=0;
5759
}
5760
48
133
$ret=~s/,$//;
5761
48
67
$ret.="]";
5762
48
50
89
$ret.=";\n" if $name;
5763
48
132
return $ret;
5764
}
5765
elsif(ref($$r) eq 'HASH'){
5766
73
50
138
return "\%$name=".serialize($r,@r).";\n" if $name;
5767
73
107
my $ret="{";
5768
73
268
for(sort keys %$$r){
5769
214
412
$ret.=serialize(\$_,@r)."=>".serialize(\$$$r{$_},@r).",";
5770
214
50
598
$ret.="\n" if $level>=0;
5771
}
5772
73
211
$ret=~s/,$//;
5773
73
93
$ret.="}";
5774
73
50
133
$ret.=";\n" if $name;
5775
73
208
return $ret;
5776
}
5777
elsif(ref($$r) eq 'SCALAR'){
5778
0
0
return "\\".serialize($$r,@r);
5779
}
5780
elsif(ref($r) eq 'LVALUE'){
5781
0
0
my $s="$$r";
5782
0
0
return serialize(\$s,@r);
5783
}
5784
elsif(ref($$r) eq 'CODE'){
5785
#warn "Tried to serialize CODE";
5786
0
0
return 'sub{croak "Can not serialize CODE-references, see perhaps B::Deparse and Storable"}'
5787
}
5788
elsif(ref($$r) eq 'GLOB'){
5789
0
0
warn "Tried to serialize a GLOB";
5790
0
0
return '\*STDERR'
5791
}
5792
else{
5793
0
0
my $tilbake;
5794
0
0
my($pakke,$fil,$linje,$sub,$hasargs,$wantarray);
5795
0
0
0
($pakke,$fil,$linje,$sub,$hasargs,$wantarray)=caller($tilbake++) until $sub ne 'serialize' || $tilbake>20;
5796
0
0
croak("serialize() argument should be reference!\n".
5797
"\$r=$r\n".
5798
"ref(\$r) = ".ref($r)."\n".
5799
"ref(\$\$r) = ".ref($$r)."\n".
5800
"kallstack:\n". _kallstack());
5801
}
5802
}
5803
5804
=head2 srlz
5805
5806
Synonym to L, but remove unnecessary single quote chars around
5807
C<< \w+ >>-keys and number values (except numbers with leading zeros). Example:
5808
5809
serialize:
5810
5811
%s=('action'=>{'del'=>'0','ins'=>'0','upd'=>'18'},'post'=>'1348','pre'=>'1348',
5812
'updcol'=>{'Laerestednr'=>'18','Studietypenr'=>'18','Undervisningssted'=>'7','Url'=>'11'},
5813
'where'=>'where 1=1');
5814
5815
srlz:
5816
5817
%s=(action=>{del=>0,ins=>0,upd=>18},post=>1348,pre=>1348,
5818
updcol=>{Laerestednr=>18,Studietypenr=>18,Undervisningssted=>7,Url=>11},
5819
where=>'where 1=1');
5820
5821
Todo: update L to do the same, but in the right way. (For now
5822
srlz runs the string from serialize() through two C<< s/// >>, this will break
5823
in certain cases). L will be kept as a synonym (or the other way around).
5824
5825
=cut
5826
5827
sub srlz {
5828
0
0
1
0
my $s=serialize(@_);
5829
0
0
$s=~s,'(\w+)'=>,$1=>,g;
5830
0
0
$s=~s,=>'((0|[1-9]\d*)(\.\d+)?(e[-+]?\d+)?)',=>$1,gi; #ikke ledende null! hm
5831
0
0
$s;
5832
}
5833
5834
5835
=head2 sys
5836
5837
Call instead of C if you want C (Carp::croak) when something fails.
5838
5839
sub sys($){ my$s=shift; my$r=system($s); $r==0 or croak"ERROR: system($s)==$r ($!) ($?)" }
5840
5841
5842
=cut
5843
5844
0
0
0
1
0
sub sys($){ my$s=shift; my$r=system($s); $r==0 or croak"ERROR: system($s)==$r ($!) ($?)" }
0
0
0
0
5845
5846
=head2 recursed
5847
5848
Returns true or false (actually 1 or 0) depending on whether the
5849
current sub has been called by itself or not.
5850
5851
sub xyz
5852
{
5853
xyz() if not recursed;
5854
5855
}
5856
5857
=cut
5858
5859
0
0
0
1
0
sub recursed {(caller(1))[3] eq (caller(2))[3]?1:0}
5860
5861
=head2 ed
5862
5863
String editor commands
5864
5865
literals: a-z 0-9 space
5866
move cursor: FBAEPN MF MB ME
5867
delete: D Md
5868
up/low/camelcase word U L C
5869
backspace: -
5870
search: S
5871
return/enter: R
5872
meta/esc/alt: M
5873
shift: T
5874
cut to eol: K
5875
caps lock: C
5876
yank: Y
5877
start and end: < >
5878
macro start/end/play: { } !
5879
times for next cmd: M (i.e. M24a inserts 24 a's)
5880
5881
(TODO: alfa...and more docs needed)
5882
5883
=cut
5884
5885
our $Edcursor;
5886
sub ed {
5887
18
18
1
4351
my($s,$cs,$p,$buf)=@_; #string, commands, point (or cursor)
5888
18
100
58
return $$s=ed($$s,$cs,$p,$buf) if ref($s);
5889
17
33
my($sh,$cl,$m,$t,@m)=(0,0,0,undef);
5890
17
37
while(length($cs)){
5891
121
148
my $n = 0;
5892
121
50
489
my $c = $cs=~s,^(M\d+|M.|""|".+?"|S.+?R|\\.|.),,s ? $1 : die;
5893
121
100
402
$p = curb($p||0,0,length($s));
5894
121
100
234
if(defined$t){$cs="".($c x $t).$cs;$t=undef;next}
1
5
1
2
1
3
5895
120
81
375
my $add=sub{substr($s,$p,0)=$_[0];$p+=length($_[0])};
81
141
81
144
5896
120
50
821
if ($c =~ /^([a-z0-9 ])/){ &$add($sh^$cl?uc($1):$1); $sh=0 }
65
100
208
65
100
80
100
100
100
100
100
50
100
100
100
100
100
50
100
100
100
50
50
50
50
50
50
50
100
100
100
50
5897
1
3
elsif($c =~ /^"(.+)"$/) { &$add($1) }
5898
1
4
elsif($c =~ /^\\(.)/) { &$add($1) }
5899
2
50
6
elsif($c =~ /^S(.+)R/) { my $i=index($s,$1,$p);$p=$i+length($1) if $i>=0 }
2
8
5900
1
3
elsif($c =~ /^M(\d+)/) { $t=$1; next }
1
6
5901
2
3
elsif($c eq 'F') { $p++ }
5902
1
2
elsif($c eq 'B') { $p-- }
5903
0
0
0
elsif($c eq 'A') { $p-- while $p>0 and substr($s,$p-1,2)!~/^\n/ }
5904
8
50
39
elsif($c eq 'E') { substr($s,$p)=~/(.*)/ and $p+=length($1) }
5905
4
5
elsif($c eq 'D') { substr($s,$p,1)='' }
5906
3
50
21
elsif($c eq 'MD'){ substr($s,$p)=~s/^(\W*\w+)// and $buf=$1 }
5907
3
50
17
elsif($c eq 'MF'){ substr($s,$p)=~/(\W*\w+)/ and $p+=length($1) }
5908
3
50
19
elsif($c eq 'MB'){ substr($s,0,$p)=~/(\w+\W*)$/ and $p-=length($1) }
5909
0
0
0
elsif($c eq '-') { substr($s,--$p,1)='' if $p }
5910
5
50
37
elsif($c eq 'M-'){ substr($s,0,$p)=~s/(\w+\W*)$// and $p-=length($buf=$1)}
5911
3
50
19
elsif($c eq 'K') { substr($s,$p)=~s/(\S.+|\s*?\n)// and $buf=$1 }
5912
12
26
elsif($c eq 'Y') { &$add($buf) }
5913
0
0
elsif($c eq 'U') { substr($s,$p)=~s/(\W*)(\w+)/$1\U$2\E/; $p+=length($1.$2) }
0
0
5914
0
0
elsif($c eq 'L') { substr($s,$p)=~s/(\W*)(\w+)/$1\L$2\E/; $p+=length($1.$2) }
0
0
5915
0
0
elsif($c eq 'C') { substr($s,$p)=~s/(\W*)(\w+)/$1\u\L$2\E/; $p+=length($1.$2) }
0
0
5916
0
0
elsif($c eq '<') { $p=0 }
5917
0
0
elsif($c eq '>') { $p=length($s) }
5918
0
0
elsif($c eq 'T') { $sh=1 }
5919
0
0
elsif($c eq 'C') { $cl^=1 }
5920
1
2
elsif($c eq '{') { $m=1; @m=() }
1
2
5921
1
2
elsif($c eq '}') { $m=0 }
5922
2
50
33
20
elsif($c eq '!') { $m||!@m and die"ed: no macro"; $cs=join("",@m).$cs }
2
5
5923
2
5
elsif($c eq '""'){ &$add('"') }
5924
0
0
else { croak "ed: Unknown cmd '$c'\n" }
5925
119
100
100
578
push @m, $c if $m and $c ne '{';
5926
#warn serialize([$c,$m,$cs],'d');
5927
}
5928
17
20
$Edcursor=$p;
5929
17
50
$s;
5930
}
5931
5932
5933
#todo: sub unbless eller sub damn
5934
#todo: ..se også: use Data::Structure::Util qw/unbless/;
5935
#todo: ...og: Acme::Damn sin damn()
5936
#todo? sub swap($$) http://www.idg.no/computerworld/article242008.ece
5937
#todo? catal
5938
#todo?
5939
#void quicksort(int t, int u) int i, m; if (t >= u) return; swap(t, randint(t, u)); m = t; for (i = t + 1; i <= u; i++) if (x[i] < x[t]) swap(++m, i); swap(t, m) quicksort(t, m-1); quicksort(m+1, u);
5940
5941
5942
=head1 JUST FOR FUN
5943
5944
=head2 brainfu
5945
5946
B one or two arguments
5947
5948
First argument: a string, source code of the brainfu
5949
language. String containing the eight charachters + - < > [ ] . ,
5950
Every other char is ignored silently.
5951
5952
Second argument: if the source code contains commas (,) the second
5953
argument is the input characters in a string.
5954
5955
B The resulting output from the program.
5956
5957
Example:
5958
5959
print brainfu(<<""); #prints "Hallo Verden!\n"
5960
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>---.+++++++++++..+++.>++.<<++++++++++++++
5961
.>----------.+++++++++++++.--------------.+.+++++++++.>+.>.
5962
5963
See L
5964
5965
=head2 brainfu2perl
5966
5967
Just as L but instead it return the perl code to which the
5968
brainfu code is translated. Just C<< eval() >> this perl code to run.
5969
5970
Example:
5971
5972
print brainfu2perl('>++++++++[<++++++++>-]<++++++++.>++++++[<++++++>-]<---.');
5973
5974
Prints this string:
5975
5976
my($c,$o,@b)=(0); sub out{$o.=chr($b[$c]) for 1..$_[0]||1}
5977
++$c;++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];
5978
while($b[$c]){--$c;++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];
5979
++$b[$c];++$c;--$b[$c];}--$c;++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];
5980
++$b[$c];++$b[$c];out;++$c;++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];
5981
while($b[$c]){--$c;++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$b[$c];++$c;--$b[$c];}
5982
--$c;--$b[$c];--$b[$c];--$b[$c];out;$o;
5983
5984
=head2 brainfu2perl_optimized
5985
5986
Just as L but optimizes the perl code. The same
5987
example as above with brainfu2perl_optimized returns this equivalent
5988
but shorter perl code:
5989
5990
$b[++$c]+=8;while($b[$c]){$b[--$c]+=8;--$b[++$c]}$b[--$c]+=8;out;$b[++$c]+=6;
5991
while($b[$c]){$b[--$c]+=6;--$b[++$c]}$b[--$c]-=3;out;$o;
5992
5993
=cut
5994
5995
3
3
1
691
sub brainfu { eval(brainfu2perl(@_)) }
5996
5997
sub brainfu2perl {
5998
6
6
1
21
my($bf,$inp)=@_;
5999
17
76
my $perl='my($c,$inp,$o,@b)=(0,\''.$inp.'\'); no warnings; sub out{$o.=chr($b[$c]) for 1..$_[0]||1}'."\n";
6000
3
100
66
22
$perl.='sub inp{$inp=~s/(.)//s and $b[$c]=ord($1)}'."\n" if $inp and $bf=~/,/;
6001
3
100
918
$perl.=join("",map/\+/?'++$b[$c];':/\-/?'--$b[$c];':/\[/?'while($b[$c]){':/\]/?'}':/>/?'++$c;':/?'--$c;':/\./?'out;':/\,/?'inp;':'',split//,$bf).'$o;';
100
100
100
100
100
100
100
6002
3
309
$perl;
6003
}
6004
6005
sub brainfu2perl_optimized {
6006
0
14
1
0
my $perl=brainfu2perl(@_);
6007
0
0
$perl=~s{(((\+|\-)\3\$b\[\$c\];){2,})}{ '$b[$c]'.$3.'='.(grep/b/,split//,$1).';' }gisex;
0
0
6008
0
0
1 while $perl=~s/\+\+\$c;\-\-\$c;//g + $perl=~s/\-\-\$c;\+\+\$c;//g;
6009
0
0
$perl=~s{((([\-\+])\3\$c;){2,})}{"\$c$3=".(grep/c/,split//,$1).';'}gisex;
0
0
6010
0
0
0
$perl=~s{((\+\+|\-\-)\$c;([^;{}]+;))}{my($o,$s)=($2,$3);$s=~s/\$c/$o\$c/?$s:$1}ge;
0
0
0
0
6011
0
0
$perl=~s/\$c(\-|\+)=(\d+);(\+\+|\-\-)\$b\[\$c\]/$3.'$b[$c'.$1.'='.$2.'];'/ge;
0
0
6012
0
0
$perl=~s{((out;){2,})}{'out('.(grep/o/,split//,$1).');'}ge;
0
0
6013
0
0
$perl=~s/;}/}/g;$perl=~s/;+/;/g;
0
0
6014
0
0
$perl;
6015
}
6016
6017
6018
=head1 BLOOM FILTER SUBROUTINES
6019
6020
Bloom filters can be used to check whether an element (a string) is a
6021
member of a large set using much less memory or disk space than other
6022
data structures. Trading speed and accuracy for memory usage. While
6023
risking false positives, Bloom filters have a very strong space
6024
advantage over other data structures for representing sets.
6025
6026
In the example below, a set of 100000 phone numbers (or any string of
6027
any length) can be "stored" in just 91230 bytes if you accept that you
6028
can only check the data structure for existence of a string and accept
6029
false positives with an error rate of 0.03 (that is three percent, error
6030
rates are given in numbers larger than 0 and smaller than 1).
6031
6032
You can not retrieve the strings in the set without using "brute
6033
force" methods and even then you would get slightly more strings than
6034
you put in because of the error rate inaccuracy.
6035
6036
Bloom Filters have many uses.
6037
6038
See also: L
6039
6040
See also: L
6041
6042
=head2 bfinit
6043
6044
Initialize a new Bloom Filter:
6045
6046
my $bf = bfinit( error_rate=>0.01, capacity=>100000 );
6047
6048
The same:
6049
6050
my $bf = bfinit( 0.01, 100000 );
6051
6052
since two arguments is interpreted as error_rate and capacity accordingly.
6053
6054
6055
=head2 bfadd
6056
6057
bfadd($bf, $_) for @phone_numbers; # Adding strings one at a time
6058
6059
bfadd($bf, @phone_numbers); # ...or all at once (faster)
6060
6061
Returns 1 on success. Dies (croaks) if more strings than capacity is added.
6062
6063
=head2 bfcheck
6064
6065
my $phone_number="97713246";
6066
if ( bfcheck($bf, $phone_number) ) {
6067
print "Yes, $phone_number was PROBABLY added\n";
6068
}
6069
else{
6070
print "No, $phone_number was DEFINITELY NOT added\n";
6071
}
6072
6073
Returns true if C<$phone_number> exists in C<@phone_numbers>.
6074
6075
Returns false most of the times, but sometimes true*), if C<$phone_number> doesn't exists in C<@phone_numbers>.
6076
6077
*) This is called a false positive.
6078
6079
Checking more than one key:
6080
6081
@bools = bfcheck($bf, @keys); # or ...
6082
@bools = bfcheck($bf, \@keys); # better, uses less memory if @keys is large
6083
6084
Returns an array the same size as @keys where each element is true or false accordingly.
6085
6086
=head2 bfgrep
6087
6088
Same as C except it returns the keys that exists in the bloom filter
6089
6090
@found = bfgrep($bf, @keys); # or ...
6091
@found = bfgrep($bf, \@keys); # better, uses less memory if @keys is large, or ...
6092
@found = grep bfcheck($bf,$_), @keys; # same but slower
6093
6094
=head2 bfgrepnot
6095
6096
Same as C except it returns the keys that do NOT exists in the bloom filter:
6097
6098
@not_found = bfgrepnot($bf, @keys); # or ...
6099
@not_found = bfgrepnot($bf, \@keys); # better, uses less memory if @keys is large, or ...
6100
@not_found = grep !bfcheck($bf,$_), @keys); # same but slower
6101
6102
=head2 bfdelete
6103
6104
Deletes from a counting bloom filter.
6105
6106
To enable deleting be sure to initialize the bloom filter with the
6107
numeric C argument. The number of bits could be 2 or 3*)
6108
for small filters with a small capacity (a small number of keys), but
6109
setting the number to 4 ensures that even very large filters with very
6110
small error rates would not overflow.
6111
6112
*) Acme::Tools do not currently support C<< counting_bits => 3 >> so 4
6113
and 8 are the only practical alternatives where 8 is almost always overkill.
6114
6115
my $bf=bfinit(
6116
error_rate => 0.001,
6117
capacity => 10000000,
6118
counting_bits => 4 # power of 2, that is 2, 4, 8, 16 or 32
6119
);
6120
bfadd( $bf, @unique_phone_numbers);
6121
bfdelete($bf, @unique_phone_numbers);
6122
6123
Example: examine the frequency of the counters with 4 bit counters and 4 million keys:
6124
6125
my $bf=bfinit( error_rate=>0.001, capacity=>4e6, counting_bits=>4 );
6126
bfadd($bf,[1e3*$_+1 .. 1e3*($_+1)]) for 0..4000-1; # adding 4 million keys one thousand at a time
6127
my %c; $c{vec($$bf{filter},$_,$$bf{counting_bits})}++ for 0..$$bf{filterlength}-1;
6128
printf "%8d counters = %d\n",$c{$_},$_ for sort{$a<=>$b}keys%c;
6129
6130
The output:
6131
6132
28689562 counters = 0
6133
19947673 counters = 1
6134
6941082 counters = 2
6135
1608250 counters = 3
6136
280107 counters = 4
6137
38859 counters = 5
6138
4533 counters = 6
6139
445 counters = 7
6140
46 counters = 8
6141
1 counters = 9
6142
6143
Even after the error_rate is changed from 0.001 to a percent of that, 0.00001, the limit of 16 (4 bits) is still far away:
6144
6145
47162242 counters = 0
6146
33457237 counters = 1
6147
11865217 counters = 2
6148
2804447 counters = 3
6149
497308 counters = 4
6150
70608 counters = 5
6151
8359 counters = 6
6152
858 counters = 7
6153
65 counters = 8
6154
4 counters = 9
6155
6156
In algorithmic terms the number of bits needed is C. Thats why 4 bits (counters up
6157
to 15) is "always" good enough except for extremely large capasities or extremely small error rates.
6158
(Except when adding the same key many times, which should be avoided, and Acme::Tools::bfadd do not
6159
check for that, perhaps in future versions).
6160
6161
Bloom filters of the counting type are not very space efficient: The tables above shows that 84%-85%
6162
of the counters are 0 or 1. This means most bits are zero-bits. This doesn't have to be a problem if
6163
a counting bloom filter is used to be sent over slow networks because they are very compressable by
6164
common compression tools like I or L and such.
6165
6166
Deletion of non-existing keys makes C die (croak).
6167
6168
=head2 bfdelete
6169
6170
Deletes from a counting bloom filter:
6171
6172
bfdelete($bf, @keys);
6173
bfdelete($bf, \@keys);
6174
6175
Returns C<$bf> after deletion.
6176
6177
Croaks (dies) on deleting a non-existing key or deleting from an previouly overflown counter in a counting bloom filter.
6178
6179
=head2 bfaddbf
6180
6181
Adds another bloom filter to a bloom filter.
6182
6183
Bloom filters has the proberty that bit-wise I-ing the bit-filters
6184
of two filters with the same capacity and the same number and type of
6185
hash functions, adds the filters:
6186
6187
my $bf1=bfinit(error_rate=>0.01,capacity=>$cap,keys=>[1..500]);
6188
my $bf2=bfinit(error_rate=>0.01,capacity=>$cap,keys=>[501..1000]);
6189
6190
bfaddbf($bf1,$bf2);
6191
6192
print "Yes!" if bfgrep($bf1, 1..1000) == 1000;
6193
6194
Prints yes since C now returns an array of all the 1000 elements.
6195
6196
Croaks if the filters are of different dimensions.
6197
6198
Works for counting bloom filters as well (C<< counting_bits=>4 >> e.g.)
6199
6200
=head2 bfsum
6201
6202
Returns the number of 1's in the filter.
6203
6204
my $percent=100*bfsum($bf)/$$bf{filterlength};
6205
printf "The filter is %.1f%% filled\n",$percent; #prints 50.0% or so if filled to capacity
6206
6207
Sums the counters for counting bloom filters (much slower than for non counting).
6208
6209
=head2 bfdimensions
6210
6211
Input, two numeric arguments: Capacity and error_rate.
6212
6213
Outputs an array of two numbers: m and k.
6214
6215
m = - n * log(p) / log(2)**2 # n = capacity, m = bits in filter (divide by 8 to get bytes)
6216
k = log(1/p) / log(2) # p = error_rate, uses perls internal log() with base e (2.718)
6217
6218
...that is: m = the best number of bits in the filter and k = the best
6219
number of hash functions optimized for the given capacity (n) and
6220
error_rate (p). Note that k is a dependent only of the error_rate. At
6221
about two percent error rate the bloom filter needs just the same
6222
number of bytes as the number of keys.
6223
6224
Storage (bytes):
6225
Capacity Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate Error-rate
6226
0.000000001 0.00000001 0.0000001 0.000001 0.00001 0.0001 0.001 0.01 0.02141585 0.1 0.5 0.99
6227
------------- ----------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
6228
10 54.48 48.49 42.5 36.51 30.52 24.53 18.53 12.54 10.56 6.553 2.366 0.5886
6229
100 539.7 479.8 419.9 360 300.1 240.2 180.3 120.4 100.6 60.47 18.6 0.824
6230
1000 5392 4793 4194 3595 2996 2397 1798 1199 1001 599.6 180.9 3.177
6231
10000 5.392e+04 4.793e+04 4.194e+04 3.594e+04 2.995e+04 2.396e+04 1.797e+04 1.198e+04 1e+04 5991 1804 26.71
6232
100000 5.392e+05 4.793e+05 4.193e+05 3.594e+05 2.995e+05 2.396e+05 1.797e+05 1.198e+05 1e+05 5.991e+04 1.803e+04 262
6233
1000000 5.392e+06 4.793e+06 4.193e+06 3.594e+06 2.995e+06 2.396e+06 1.797e+06 1.198e+06 1e+06 5.991e+05 1.803e+05 2615
6234
10000000 5.392e+07 4.793e+07 4.193e+07 3.594e+07 2.995e+07 2.396e+07 1.797e+07 1.198e+07 1e+07 5.991e+06 1.803e+06 2.615e+04
6235
100000000 5.392e+08 4.793e+08 4.193e+08 3.594e+08 2.995e+08 2.396e+08 1.797e+08 1.198e+08 1e+08 5.991e+07 1.803e+07 2.615e+05
6236
1000000000 5.392e+09 4.793e+09 4.193e+09 3.594e+09 2.995e+09 2.396e+09 1.797e+09 1.198e+09 1e+09 5.991e+08 1.803e+08 2.615e+06
6237
10000000000 5.392e+10 4.793e+10 4.193e+10 3.594e+10 2.995e+10 2.396e+10 1.797e+10 1.198e+10 1e+10 5.991e+09 1.803e+09 2.615e+07
6238
100000000000 5.392e+11 4.793e+11 4.193e+11 3.594e+11 2.995e+11 2.396e+11 1.797e+11 1.198e+11 1e+11 5.991e+10 1.803e+10 2.615e+08
6239
1000000000000 5.392e+12 4.793e+12 4.193e+12 3.594e+12 2.995e+12 2.396e+12 1.797e+12 1.198e+12 1e+12 5.991e+11 1.803e+11 2.615e+09
6240
6241
Error rate: 0.99 Hash functions: 1
6242
Error rate: 0.5 Hash functions: 1
6243
Error rate: 0.1 Hash functions: 3
6244
Error rate: 0.0214158522653385 Hash functions: 6
6245
Error rate: 0.01 Hash functions: 7
6246
Error rate: 0.001 Hash functions: 10
6247
Error rate: 0.0001 Hash functions: 13
6248
Error rate: 0.00001 Hash functions: 17
6249
Error rate: 0.000001 Hash functions: 20
6250
Error rate: 0.0000001 Hash functions: 23
6251
Error rate: 0.00000001 Hash functions: 27
6252
Error rate: 0.000000001 Hash functions: 30
6253
6254
=head2 bfstore
6255
6256
Storing and retrieving bloom filters to and from disk uses Ls C and C. This:
6257
6258
bfstore($bf,'filename.bf');
6259
6260
It the same as:
6261
6262
use Storable qw(store retrieve);
6263
...
6264
store($bf,'filename.bf');
6265
6266
=head2 bfretrieve
6267
6268
This:
6269
6270
my $bf=bfretrieve('filename.bf');
6271
6272
Or this:
6273
6274
my $bf=bfinit('filename.bf');
6275
6276
Is the same as:
6277
6278
use Storable qw(store retrieve);
6279
my $bf=retrieve('filename.bf');
6280
6281
=head2 bfclone
6282
6283
Deep copies the bloom filter data structure. (Which btw is not very deep, two levels at most)
6284
6285
This:
6286
6287
my $bfc = bfclone($bf);
6288
6289
Works just as:
6290
6291
use Storable;
6292
my $bfc=Storable::dclone($bf);
6293
6294
=head2 Object oriented interface to bloom filters
6295
6296
use Acme::Tools;
6297
my $bf=new Acme::Tools::BloomFilter(0.1,1000); # the same as bfinit, see bfinit above
6298
print ref($bf),"\n"; # prints Acme::Tools::BloomFilter
6299
$bf->add(@keys);
6300
$bf->check($keys[0]) and print "ok\n"; # prints ok
6301
$bf->grep(\@keys)==@keys and print "ok\n"; # prints ok
6302
$bf->store('filename.bf');
6303
my $bf2=bfretrieve('filename.bf');
6304
$bf2->check($keys[0]) and print "ok\n"; # still ok
6305
6306
$bf2=$bf->clone();
6307
6308
To instantiate a previously stored bloom filter:
6309
6310
my $bf = Acme::Tools::BloomFilter->new( '/path/to/stored/bloomfilter.bf' );
6311
6312
The o.o. interface has the same methods as the C-subs without the
6313
C-prefix in the names. The C is not available as a
6314
method, although C, C and
6315
C are synonyms.
6316
6317
=head2 Internals and speed
6318
6319
The internal hash-functions are C<< md5( "$key$salt" ) >> from L.
6320
6321
Since C returns 128 bits and most medium to large sized bloom
6322
filters need only a 32 bit hash function, the result from md5() are
6323
split (C-ed) into 4 parts 32 bits each and are treated as if 4
6324
hash functions was called at once (speedup). Using different salts to
6325
the key on each md5 results in different hash functions.
6326
6327
Digest::SHA512 would have been even better since it returns more bits,
6328
if it werent for the fact that it's much slower than Digest::MD5.
6329
6330
String::CRC32::crc32 is faster than Digest::MD5, but not 4 times faster:
6331
6332
time perl -e'use Digest::MD5 qw(md5);md5("asdf$_") for 1..10e6' #5.56 sec
6333
time perl -e'use String::CRC32;crc32("asdf$_") for 1..10e6' #2.79 sec, faster but not per bit
6334
time perl -e'use Digest::SHA qw(sha512);sha512("asdf$_") for 1..10e6' #36.10 sec, too slow (sha1, sha224, sha256 and sha384 too)
6335
6336
Md5 seems to be an ok choice both for speed and avoiding collitions due to skewed data keys.
6337
6338
=head2 Theory and math behind bloom filters
6339
6340
L
6341
6342
L
6343
6344
L
6345
6346
See also Scaleable Bloom Filters: L (not implemented in Acme::Tools)
6347
6348
...and perhaps L
6349
6350
=cut
6351
6352
sub bfinit {
6353
24
100
24
1
15650
return bfretrieve(@_) if @_==1;
6354
23
50
66
118
return bfinit(error_rate=>$_[0], capacity=>$_[1]) if @_==2 and 0<$_[0] and $_[0]<1 and $_[1]>1;
66
33
6355
21
0
33
61
return bfinit(error_rate=>$_[1], capacity=>$_[0]) if @_==2 and 0<$_[1] and $_[1]<1 and $_[0]>1;
33
0
6356
21
129
require Digest::MD5;
6357
21
50
54
@_%2&&croak "Arguments should be a hash of equal number of keys and values";
6358
21
85
my %arg=@_;
6359
21
69
my @ok_param=qw/error_rate capacity min_hashfuncs max_hashfuncs hashfuncs counting_bits adaptive keys/;
6360
21
84
my @not_ok=sort(grep!in($_,@ok_param),keys%arg);
6361
21
100
271
croak "Not ok param to bfinit: ".join(", ",@not_ok) if @not_ok;
6362
20
50
66
98
croak "Not an arrayref in keys-param" if exists $arg{keys} and ref($arg{keys}) ne 'ARRAY';
6363
20
50
77
croak "Not implemented counting_bits=$arg{counting_bits}, should be 2, 4, 8, 16 or 32" if !in(nvl($arg{counting_bits},1),1,2,4,8,16,32);
6364
20
50
33
73
croak "An bloom filters here can not be in both adaptive and counting_bits modes" if $arg{adaptive} and $arg{counting_bits}>1;
6365
20
176
my $bf={error_rate => 0.001, #default p
6366
capacity => 100000, #default n
6367
min_hashfuncs => 1,
6368
max_hashfuncs => 100,
6369
counting_bits => 1, #default: not counting filter
6370
adaptive => 0,
6371
%arg, #arguments
6372
key_count => 0,
6373
overflow => {},
6374
version => $Acme::Tools::VERSION,
6375
};
6376
20
100
100
384
croak "Error rate ($$bf{error_rate}) should be larger than 0 and smaller than 1" if $$bf{error_rate}<=0 or $$bf{error_rate}>=1;
6377
18
50
46
@$bf{'min_hashfuncs','max_hashfuncs'}=(map$arg{hashfuncs},1..2) if $arg{hashfuncs};
6378
18
53
@$bf{'filterlength','hashfuncs'}=bfdimensions($bf); #m and k
6379
18
776
$$bf{filter}=pack("b*", '0' x ($$bf{filterlength}*$$bf{counting_bits}) ); #hm x new empty filter
6380
$$bf{unpack}= $$bf{filterlength}<=2**16/4 ? "n*" # /4 alleviates skewing if m just slightly < 2**x
6381
18
50
57
:$$bf{filterlength}<=2**32/4 ? "N*"
100
6382
: "Q*";
6383
18
100
48
bfadd($bf,@{$arg{keys}}) if $arg{keys};
8
78
6384
16
95
return $bf;
6385
}
6386
sub bfaddbf {
6387
2
2
1
5
my($bf,$bf2)=@_;
6388
my $differror=join"\n",
6389
map "Property $_ differs ($$bf{$_} vs $$bf2{$_})",
6390
2
42
grep $$bf{$_} ne $$bf2{$_},
6391
qw/capacity counting_bits adaptive hashfuncs filterlength/; #not error_rate
6392
2
50
8
croak $differror if $differror;
6393
2
50
9
croak "Can not add adaptive bloom filters" if $$bf{adaptive};
6394
2
5
my $count=$$bf{key_count}+$$bf2{key_count};
6395
croak "Exceeded filter capacity $$bf{key_count} + $$bf2{key_count} = $count > $$bf{capacity}"
6396
2
50
10
if $count > $$bf{capacity};
6397
2
7
$$bf{key_count}+=$$bf2{key_count};
6398
2
100
8
if($$bf{counting_bits}==1){
6399
1
5
$$bf{filter} |= $$bf2{filter};
6400
#$$bf{filter} = $$bf{filter} | $$bf2{filter}; #or-ing
6401
}
6402
else {
6403
1
4
my $cb=$$bf{counting_bits};
6404
1
6
for(0..$$bf{filterlength}-1){
6405
my $sum=
6406
vec($$bf{filter}, $_,$cb)+
6407
4793
8390
vec($$bf2{filter},$_,$cb);
6408
4793
50
9761
if( $sum>2**$cb-1 ){
6409
0
0
$sum=2**$cb-1;
6410
0
0
$$bf{overflow}{$_}++;
6411
}
6412
4793
9283
vec($$bf{filter}, $_,$cb)=$sum;
6413
28
28
187
no warnings;
28
49
28
91601
6414
$$bf{overflow}{$_}+=$$bf2{overflow}{$_}
6415
0
0
and keys(%{$$bf{overflow}})>10 #hmm, arbitrary limit
6416
and croak "Too many overflows, concider doubling counting_bits from $cb to ".(2*$cb)
6417
4793
50
0
13225
if exists $$bf2{overflow}{$_};
0
6418
}
6419
}
6420
2
7
return $bf; #for convenience
6421
}
6422
sub bfsum {
6423
8
8
1
40
my($bf)=@_;
6424
8
100
89
return unpack( "%32b*", $$bf{filter}) if $$bf{counting_bits}==1;
6425
3
8
my($sum,$cb)=(0,$$bf{counting_bits});
6426
3
5708
$sum+=vec($$bf{filter},$_,$cb) for 0..$$bf{filterlength}-1;
6427
3
23
return $sum;
6428
}
6429
sub bfadd {
6430
11
11
1
2573
require Digest::MD5;
6431
11
876
my($bf,@keys)=@_;
6432
11
50
34
return if !@keys;
6433
11
100
66
45
my $keysref=@keys==1 && ref($keys[0]) eq 'ARRAY' ? $keys[0] : \@keys;
6434
11
51
my($m,$k,$up,$n,$cb,$adaptive)=@$bf{'filterlength','hashfuncs','unpack','capacity','counting_bits','adaptive'};
6435
11
37
for(@$keysref){
6436
#croak "Key should be scalar" if ref($_);
6437
15084
50
66
40952
$$bf{key_count} >= $n and croak "Exceeded filter capacity $n" or $$bf{key_count}++;
6438
15083
18626
my @h; push @h, unpack $up, Digest::MD5::md5($_,0+@h) while @h<$k;
15083
132284
6439
15083
100
66
51645
if ($cb==1 and !$adaptive) { # normal bloom filter
50
0
6440
11110
102943
vec($$bf{filter}, $h[$_] % $m, 1) = 1 for 0..$k-1;
6441
}
6442
elsif ($cb>1) { # counting bloom filter
6443
3973
7256
for(0..$k-1){
6444
11919
17176
my $pos=$h[$_] % $m;
6445
my $c=
6446
vec($$bf{filter}, $pos, $cb) =
6447
11919
29225
vec($$bf{filter}, $pos, $cb) + 1;
6448
11919
100
35642
if($c==0){
6449
26
51
vec($$bf{filter}, $pos, $cb) = -1;
6450
$$bf{overflow}{$pos}++
6451
26
100
100
134
and keys(%{$$bf{overflow}})>10 #hmm, arbitrary limit
2
244
6452
and croak "Too many overflows, concider doubling counting_bits from $cb to ".(2*$cb);
6453
}
6454
}
6455
}
6456
elsif ($adaptive) { # adaptive bloom filter
6457
0
0
my($i,$key,$bit)=(0+@h,$_);
6458
0
0
for(0..$$bf{filterlength}-1){
6459
0
0
0
$i+=push(@h, unpack $up, Digest::MD5::md5($key,$i)) if !@h;
6460
0
0
my $pos=shift(@h) % $m;
6461
0
0
$bit=vec($$bf{filter}, $pos, 1);
6462
0
0
vec($$bf{filter}, $pos, 1)=1;
6463
0
0
0
0
last if $_>=$k-1 and $bit==0;
6464
}
6465
}
6466
0
0
else {croak}
6467
}
6468
9
733
return 1;
6469
}
6470
sub bfcheck {
6471
5
5
1
83
require Digest::MD5;
6472
5
1178
my($bf,@keys)=@_;
6473
5
50
18
return if !@keys;
6474
5
50
33
26
my $keysref=@keys==1 && ref($keys[0]) eq 'ARRAY' ? $keys[0] : \@keys;
6475
5
24
my($m,$k,$up,$cb,$adaptive)=@$bf{'filterlength','hashfuncs','unpack','counting_bits','adaptive'};
6476
5
12
my $wa=wantarray();
6477
5
50
15
if(!$adaptive){ # normal bloom filter or counting bloom filter
6478
return map {
6479
5
65
my $match = 1; # match if every bit is on
24001
28811
6480
24001
28750
my @h; push @h, unpack $up, Digest::MD5::md5($_,0+@h) while @h<$k;
24001
222331
6481
24001
100
209677
vec($$bf{filter}, $h[$_] % $m, $cb) or $match=0 or last for 0..$k-1;
100
6482
24001
50
44673
return $match if !$wa;
6483
24001
51962
$match;
6484
} @$keysref;
6485
}
6486
else { # adaptive bloom filter
6487
return map {
6488
0
0
my($match,$i,$key,$bit,@h)=(1,0,$_);
0
0
6489
0
0
for(0..$$bf{filterlength}-1){
6490
0
0
0
$i+=push(@h, unpack $up, Digest::MD5::md5($key,$i)) if !@h;
6491
0
0
my $pos=shift(@h) % $m;
6492
0
0
$bit=vec($$bf{filter}, $pos, 1);
6493
0
0
0
0
$match++ if $_ > $k-1 and $bit==1;
6494
0
0
0
0
$match=0 if $_ <= $k-1 and $bit==0;
6495
0
0
0
last if $bit==0;
6496
}
6497
0
0
0
return $match if !$wa;
6498
0
0
$match;
6499
} @$keysref;
6500
}
6501
}
6502
sub bfgrep { # just a copy of bfcheck with map replaced by grep
6503
8
8
1
870
require Digest::MD5;
6504
8
24
my($bf,@keys)=@_;
6505
8
50
27
return if !@keys;
6506
8
50
33
65
my $keysref=@keys==1 && ref($keys[0]) eq 'ARRAY' ? $keys[0] : \@keys;
6507
8
34
my($m,$k,$up,$cb)=@$bf{'filterlength','hashfuncs','unpack','counting_bits'};
6508
return grep {
6509
8
29
my $match = 1; # match if every bit is on
6100
7316
6510
6100
6722
my @h; push @h, unpack $up, Digest::MD5::md5($_,0+@h) while @h<$k;
6100
40807
6511
6100
100
42786
vec($$bf{filter}, $h[$_] % $m, $cb) or $match=0 or last for 0..$k-1;
100
6512
6100
11486
$match;
6513
} @$keysref;
6514
}
6515
sub bfgrepnot { # just a copy of bfgrep with $match replaced by not $match
6516
1
1
1
9
require Digest::MD5;
6517
1
3
my($bf,@keys)=@_;
6518
1
50
5
return if !@keys;
6519
1
50
33
16
my $keysref=@keys==1 && ref($keys[0]) eq 'ARRAY' ? $keys[0] : \@keys;
6520
1
5
my($m,$k,$up,$cb)=@$bf{'filterlength','hashfuncs','unpack','counting_bits'};
6521
return grep {
6522
1
5
my $match = 1; # match if every bit is on
1000
1246
6523
1000
1149
my @h; push @h, unpack $up, Digest::MD5::md5($_,0+@h) while @h<$k;
1000
6814
6524
1000
50
7027
vec($$bf{filter}, $h[$_] % $m, $cb) or $match=0 or last for 0..$k-1;
50
6525
1000
2346
!$match;
6526
} @$keysref;
6527
}
6528
sub bfdelete {
6529
3
3
1
91
require Digest::MD5;
6530
3
17
my($bf,@keys)=@_;
6531
3
50
12
return if !@keys;
6532
3
100
100
20
my $keysref=@keys==1 && ref($keys[0]) eq 'ARRAY' ? $keys[0] : \@keys;
6533
3
11
my($m,$k,$up,$cb)=@$bf{'filterlength','hashfuncs','unpack','counting_bits'};
6534
3
50
8
croak "Cannot delete from non-counting bloom filter (use counting_bits 4 e.g.)" if $cb==1;
6535
3
7
for my $key (@$keysref){
6536
501
537
my @h; push @h, unpack $up, Digest::MD5::md5($key,0+@h) while @h<$k;
501
3437
6537
501
50
33
1432
$$bf{key_count}==0 and croak "Deleted all and then some" or $$bf{key_count}--;
6538
501
782
my($ones,$croak,@pos)=(0);
6539
501
925
for(0..$k-1){
6540
1503
2149
my $pos=$h[$_] % $m;
6541
my $c=
6542
1503
2267
vec($$bf{filter}, $pos, $cb);
6543
1503
3127
vec($$bf{filter}, $pos, $cb)=$c-1;
6544
1503
100
3244
$croak="Cannot delete a non-existing key $key" if $c==0;
6545
$croak="Cannot delete with previously overflown position. Try doubleing counting_bits"
6546
1503
50
66
6247
if $c==1 and ++$ones and $$bf{overflow}{$pos};
66
6547
}
6548
501
100
1241
if($croak){ #rollback
6549
vec($$bf{filter}, $h[$_] % $m, $cb)=
6550
1
11
vec($$bf{filter}, $h[$_] % $m, $cb)+1 for 0..$k-1;
6551
1
200
croak $croak;
6552
}
6553
}
6554
2
20
return $bf;
6555
}
6556
sub bfstore {
6557
1
1
1
22727
require Storable;
6558
1
8
Storable::store(@_);
6559
}
6560
sub bfretrieve {
6561
2
2
1
527
require Storable;
6562
2
11
my $bf=Storable::retrieve(@_);
6563
2
50
545
carp "Retrieved bloom filter was stored in version $$bf{version}, this is version $VERSION" if $$bf{version}>$VERSION;
6564
2
7
return $bf;
6565
}
6566
sub bfclone {
6567
1
1
1
30668
require Storable;
6568
1
8452
return Storable::dclone(@_); #could be faster
6569
}
6570
sub bfdimensions_old {
6571
my($n,$p,$mink,$maxk, $k,$flen,$m)=
6572
0
0
0
0
0
@_==1 ? (@{$_[0]}{'capacity','error_rate','min_hashfuncs','max_hashfuncs'},1)
0
0
0
6573
:@_==2 ? (@_,1,100,1)
6574
: croak "Wrong number of arguments (".@_."), should be 2";
6575
0
0
0
0
croak "p ($p) should be > 0 and < 1" if not ( 0<$p && $p<1 );
6576
0
0
0
$m=-1*$_*$n/log(1-$p**(1/$_)) and (!defined $flen or $m<$flen) and ($flen,$k)=($m,$_) for $mink..$maxk;
0
0
6577
0
0
$flen = int(1+$flen);
6578
0
0
return ($flen,$k);
6579
}
6580
sub bfdimensions {
6581
my($n,$p,$mink,$maxk)=
6582
18
0
18
1
48
@_==1 ? (@{$_[0]}{'capacity','error_rate','min_hashfuncs','max_hashfuncs'})
18
50
52
6583
:@_==2 ? (@_,1,100)
6584
: croak "Wrong number of arguments (".@_."), should be 2";
6585
18
66
my $k=log(1/$p)/log(2); # k hash funcs
6586
18
47
my $m=-$n*log($p)/log(2)**2; # m bits in filter
6587
18
65
return ($m+0.5,min($maxk,max($mink,int($k+0.5))));
6588
}
6589
6590
#crontab -e
6591
#01 4,10,16,22 * * * /usr/bin/perl -MAcme::Tools -e'Acme::Tools::_update_currency_file("/var/www/html/currency-rates")' > /dev/null 2>&1
6592
6593
sub _update_currency_file { #call from cron
6594
0
0
0
0
my $fn=shift()||'/var/www/html/currency-rates';
6595
0
0
0
my %exe=map+($_=>"/usr/bin/$_"),qw/curl ci/;-x$_ or die for values %exe;
0
0
6596
0
0
0
open my $F, '>', $fn or die"ERROR: Could not write file $fn ($!)\n";
6597
0
0
print $F "#-- Currency rates ".localtime()." (".time().")\n";
6598
0
0
print $F "# File generated by Acme::Tools version $VERSION\n";
6599
0
0
print $F "# Updated every 6th hour on http://calthis.com/currency-rates\n";
6600
0
0
print $F "NOK 1.000000000\n";
6601
0
0
my $amount=1000;
6602
0
0
my $data=qx($exe{curl} -s "http://www.x-rates.com/table/?from=NOK&amount=$amount");
6603
0
0
$data=~s,to=([A-Z]{3})(.)>,$2>$1 ,g;
6604
0
0
my @data=ht2t($data,"Alphabetical order"); shift @data;
0
0
6605
0
0
0
@data=map "$$_[1] ".($$_[4]>1e-2?$$_[4]:$$_[2]?sprintf("%.8f",$amount/$$_[2]):0)."\n",@data;
0
6606
0
0
my %data=map split,@data;
6607
0
0
my@tc=qx($exe{curl} -s https://btc-e.com/api/3/ticker/btc_usd-ltc_usd)=~/avg.?:(\d+\.?\d*)/g;
6608
0
0
push @data,"BTC ".($tc[0]*$data{USD})."\n";
6609
0
0
push @data,"LTC ".($tc[1]*$data{USD})."\n";
6610
0
0
print $F sort(@data);
6611
0
0
close($F);
6612
0
0
0
qx($exe{ci} -l -m. -d $fn) if -w"$fn,v";
6613
}
6614
6615
sub ftype {
6616
0
0
0
0
my $f=shift;
6617
0
0
0
0
-e $f and
0
0
0
0
0
0
0
0
6618
-f$f ? 'file' # -f File is a plain file.
6619
:-d$f ? 'dir' # -d File is a directory.
6620
:-l$f ? 'symlink' # -l File is a symbolic link.
6621
:-p$f ? 'pipe' # -p File is a named pipe (FIFO), or Filehandle is a pipe.
6622
:-S$f ? 'socket' # -S File is a socket.
6623
:-b$f ? 'blockfile' # -b File is a block special file.
6624
:-c$f ? 'charfile' # -c File is a character special file.
6625
:-t$f ? 'ttyfile' # -t Filehandle is opened to a tty.
6626
: ''
6627
or undef;
6628
}
6629
6630
=head1 COMMANDS
6631
6632
=head2 install_acme_command_tools
6633
6634
sudo perl -MAcme::Tools -e install_acme_command_tools
6635
Wrote executable /usr/local/bin/conv
6636
Wrote executable /usr/local/bin/due
6637
Wrote executable /usr/local/bin/xcat
6638
Wrote executable /usr/local/bin/freq
6639
Wrote executable /usr/local/bin/deldup
6640
Wrote executable /usr/local/bin/wipe
6641
6642
Examples of commands then made available:
6643
6644
conv 1 USD EUR #might show 0.88029 if thats the current currency rate. Uses conv()
6645
conv .5 in cm #reveals that 1/2 inch is 1.27 cm, see doc on conv() for all supported units
6646
due [-h] /path/1/ /path/2/ #like du, but show statistics on file extentions instead of subdirs
6647
xcat file #like cat, zcat, bzcat or xzcat in one. Uses file extention to decide. Uses openstr()
6648
freq file #reads file(s) or stdin and view counts of each byte 0-255
6649
deldup [-d] path1/ path2/ #reports (and optionally deletes) duplicate files NOT IMPLEMENTED YET!
6650
ccmd grep string /huge/file #caches stdout+stderr for 15 minutes (default) for much faster results later
6651
ccmd "sleep 2;echo hello" #slow first time. Note the quotes!
6652
ccmd "du -s ~/*|sort -n|tail" #ccmd store stdout+stderr in /tmp files (default)
6653
6654
=head3 due
6655
6656
Like C command but views space used by file extentions instead of dirs. Options:
6657
6658
due [-options] [dirs] [files]
6659
due -h View bytes "human readable", i.e. C<8.72 MB> instead of C<9145662 b> (bytes)
6660
due -k | -m View bytes in kilobytes | megabytes (1024 | 1048576)
6661
due -K Like -k but uses 1000 instead of 1024
6662
due -z View two extentions if .z .Z .gz .bz2 .rz or .xz (.tar.gz, not just .gz)
6663
due -M Also show min, medium and max date (mtime) of files, give an idea of their age
6664
due -P Also show 10, 50 (medium) and 90 percentile of file date
6665
due -MP Both -M and -P, shows min, 10p, 50p, 90p and max
6666
due -a Sort output alphabetically by extention (default order is by size)
6667
due -c Sort output by number of files
6668
due -i Ignore case, .GZ and .gz is the same, output in lower case
6669
due -t Adds time of day to -M and -P output
6670
due -e 'regex' Exclude files (full path) matching regex. Ex: due -e '\.git'
6671
6672
=cut
6673
6674
sub install_acme_command_tools {
6675
0
0
1
0
my $dir=(grep -d$_, @_, '/usr/local/bin', '/usr/bin')[0];
6676
0
0
for(qw( conv due xcat freq deldup ccmd )){
6677
0
0
unlink("$dir/$_");
6678
0
0
writefile("$dir/$_", "#!$^X\nuse Acme::Tools;\nAcme::Tools::cmd_$_(\@ARGV);\n");
6679
0
0
sys("/bin/chmod +x $dir/$_");
6680
0
0
print "Wrote executable $dir/$_\n";
6681
}
6682
}
6683
0
0
0
0
sub cmd_conv { print conv(@ARGV)."\n" }
6684
28
28
51697
use Data::Dumper;
28
294442
28
3305
6685
sub cmd_due { #TODO: output from tar tvf and ls and find -ls
6686
0
0
0
0
require Getopt::Std; my %o; Getopt::Std::getopts("zkKmhciMPate:" => \%o);
0
0
0
0
6687
0
0
require File::Find;
6688
28
28
189
no warnings 'uninitialized';
28
55
28
86776
6689
0
0
0
die"$0: -h, -k or -m can not be used together\n" if $o{h}+$o{k}+$o{m}>1;
6690
0
0
0
die"$0: -c and -a can not be used together\n" if $o{a}+$o{c}>1;
6691
0
0
0
die"$0: -k and -m can not be used together\n" if $o{k}+$o{m}>1;
6692
0
0
0
my @q=@ARGV; @q=('.') if !@q;
0
0
6693
0
0
my(%c,%b,$cnt,$bts,%mtime);
6694
0
0
0
my $r=$o{z} ? qr/(\.[^\.\/]{1,10}(\.(z|Z|gz|bz2|rz|xz))?)$/
6695
: qr/(\.[^\.\/]{1,10})$/;
6696
0
0
0
my $rexcl=exists$o{e}?qr/$o{e}/:0;
6697
File::Find::find({wanted =>
6698
sub {
6699
0
0
0
0
return if !-f$_;
6700
0
0
0
0
return if $rexcl and $File::Find::name=~$rexcl;
6701
0
0
my($sz,$mtime)=(stat($_))[7,9];
6702
0
0
0
my $ext=m/$r/?$1:"";
6703
0
0
0
$ext=lc($ext) if $o{i};
6704
0
0
$cnt++; $c{$ext}++;
0
0
6705
0
0
$bts+=$sz; $b{$ext}+=$sz;
0
0
6706
0
0
0
0
$mtime{$ext}.=",$mtime" if $o{M} or $o{P};
6707
0
0
1;
6708
0
0
} },@q);
6709
0
0
0
my($f,$s)=$o{k}?("%14.2f kb",sub{$_[0]/1024})
6710
0
0
0
:$o{K}?("%14.2f Kb",sub{$_[0]/1000})
6711
0
0
0
:$o{m}?("%14.2f mb",sub{$_[0]/1024**2})
6712
0
0
0
:$o{h}?("%14s", sub{bytes_readable($_[0])})
6713
0
0
0
0
: ("%14d b", sub{$_[0]});
0
0
0
0
0
6714
my @e=$o{a}?(sort(keys%c))
6715
0
0
0
:$o{c}?(sort{$c{$a}<=>$c{$b} or $a cmp $b}keys%c)
6716
0
0
0
: (sort{$b{$a}<=>$b{$b} or $a cmp $b}keys%c);
0
0
0
0
6717
0
0
0
my @p=$o{P}?(10,50,90):(50);
6718
my $perc=sub{
6719
0
0
0
0
0
$o{M} or $o{P} or return"";
6720
0
0
my @m=@_>0 ? do {grep$_, split",", $mtime{$_[0]}}
6721
0
0
0
: do {grep$_, map {split","} values %mtime};
0
0
0
0
6722
0
0
my @r=percentile(\@p,@m);
6723
0
0
0
@r=(min(@m),@r,max(@m)) if $o{M};
6724
0
0
@r=map int($_), @r;
6725
0
0
0
my $fmt='YYYY/MM/DD'; $fmt.="-MM:MI:SS" if $o{t};
0
0
6726
0
0
@r=map tms($_,$fmt), @r;
6727
0
0
" ".join(" ",@r);
6728
0
0
};
6729
0
0
printf("%-11s %8d $f %7.2f%%%s\n",$_,$c{$_},&$s($b{$_}),100*$b{$_}/$bts,&$perc($_)) for @e;
6730
0
0
printf("%-11s %8d $f %7.2f%%%s\n","Sum",$cnt,&$s($bts),100,&$perc());
6731
}
6732
sub cmd_xcat {
6733
0
0
0
0
for my $fn (@_){
6734
0
0
my $os=openstr($fn);
6735
0
0
0
0
open my $FH, $os or warn "xcat: cannot open $os ($!)\n" and next;
6736
0
0
print while <$FH>;
6737
0
0
close($FH);
6738
}
6739
}
6740
sub cmd_freq {
6741
0
0
0
0
my(@f,$i);
6742
0
0
map $f[$_]++, unpack("C*",$_) while <>;
6743
0
0
my $s=" " x 12;map{print"$_$s$_$s$_\n"}("BYTE CHAR COUNT","---- ----- -------");
0
0
0
0
6744
0
0
my %m=(145,"DOS-æ",155,"DOS-ø",134,"DOS-å",146,"DOS-Æ",157,"DOS-Ø",143,"DOS-Å",map{($_," ")}0..31);
0
0
6745
0
0
0
0
printf("%4d %5s%8d".(++$i%3?$s:"\n"),$_,$m{$_}||chr,$f[$_]) for grep$f[$_],0..255;print "\n";
0
0
6746
0
0
my @no=grep!$f[$_],0..255; print "No bytes for these ".@no.": ".join(" ",@no)."\n";
0
0
6747
}
6748
6749
sub cmd_deldup {
6750
# ~/test/deldup.pl #find and optionally delete duplicate files effiencently
6751
#http://www.commandlinefu.com/commands/view/3555/find-duplicate-files-based-on-size-first-then-md5-hash
6752
0
0
0
0
die "todo: deldup not ready yet"
6753
}
6754
6755
#http://stackoverflow.com/questions/11900239/can-i-cache-the-output-of-a-command-on-linux-from-cli
6756
our $Ccmd_cache_dir='/tmp/acme-tools-ccmd-cache';
6757
our $Ccmd_cache_expire=15*60; #default 15 minutes
6758
sub cmd_ccmd {
6759
0
0
0
0
require Digest::MD5;
6760
0
0
my $cmd=join" ",@_;
6761
0
0
my $d="$Ccmd_cache_dir/".username();
6762
0
0
makedir($d);
6763
0
0
my $md5=Digest::MD5::md5_hex($cmd);
6764
0
0
my($fno,$fne)=map"$d/cmd.$md5.std$_","out","err";
6765
0
0
0
my $too_old=sub{time()-(stat(shift))[9] >= $Ccmd_cache_expire};
0
0
6766
0
0
unlink grep &$too_old($_), <$d/*.std???>;
6767
0
0
0
0
sys("($cmd) > $fno 2> $fne") if !-e$fno or &$too_old($fno);
6768
0
0
print STDOUT "".readfile($fno);
6769
0
0
print STDERR "".readfile($fne);
6770
}
6771
6772
0
0
0
0
sub cmd_trunc { die "todo: trunc not ready yet"} #truncate a file, size 0, keep all other attr
6773
6774
sub cmd_wipe {
6775
0
0
0
0
require Getopt::Std; my %o; Getopt::Std::getopts("n:k" => \%o);
0
0
0
0
6776
0
0
wipe($_,$o{n},$o{k}) for @_;
6777
}
6778
6779
=head1 DATABASE STUFF - NOT IMPLEMENTED YET
6780
6781
Uses L. Comming soon...
6782
6783
$Dbh
6784
dlogin
6785
dlogout
6786
drow
6787
drows
6788
drowc
6789
drowsc
6790
dcols
6791
dpk
6792
dsel
6793
ddo
6794
dins
6795
dupd
6796
ddel
6797
dcommit
6798
drollback
6799
6800
=cut
6801
6802
#my$dummy=<<'SOON';
6803
sub dtype {
6804
0
0
0
0
my $connstr=shift;
6805
0
0
0
return 'SQLite' if $connstr=~/(\.sqlite|sqlite:.*\.db)$/i;
6806
0
0
0
return 'Oracle' if $connstr=~/\@/;
6807
0
0
return 'Pg' if 1==2;
6808
0
0
die;
6809
}
6810
6811
our($Dbh,@Dbh,%Sth);
6812
our %Dbattr=(RaiseError => 1, AutoCommit => 0); #defaults
6813
sub dlogin {
6814
0
0
0
0
my $connstr=shift();
6815
0
0
my %attr=(%Dbattr,@_);
6816
0
0
my $type=dtype($connstr);
6817
0
0
my($dsn,$u,$p)=('','','');
6818
0
0
0
if($type eq 'SQLite'){
0
0
6819
0
0
$dsn=$connstr;
6820
}
6821
elsif($type eq 'Oracle'){
6822
0
0
($u,$p,$dsn)=($connstr=~m,(.+?)(/.+?)?\@(.+),);
6823
}
6824
elsif($type eq 'Pg'){
6825
0
0
croak "todo";
6826
}
6827
else{
6828
0
0
croak "dblogin: unknown database type for connection string $connstr\n";
6829
}
6830
0
0
$dsn="dbi:$type:$dsn";
6831
0
0
0
push @Dbh, $Dbh if $Dbh; #local is better?
6832
0
0
require DBI;
6833
0
0
$Dbh=DBI->connect($dsn,$u,$p,\%attr); #connect_cached?
6834
}
6835
sub dlogout {
6836
0
0
0
0
$Dbh->disconnect;
6837
0
0
0
$Dbh=pop@Dbh if @Dbh;
6838
}
6839
sub drow {
6840
0
0
0
0
my($q,@b)=_dattrarg(@_);
6841
#my $sth=do{$Sth{$Dbh,$q} ||= $Dbh->prepare_cached($q)};
6842
0
0
my $sth=$Dbh->prepare_cached($q);
6843
0
0
$sth->execute(@b);
6844
0
0
my @r=$sth->fetchrow_array;
6845
0
0
0
$sth->finish if $$Dbh{Driver}{Name} eq 'SQLite';
6846
#$dbh->selectrow_array($statement);
6847
0
0
0
return @r==1?$r[0]:@r;
6848
}
6849
0
0
sub drows {
6850
}
6851
0
0
sub drowc {
6852
}
6853
0
0
sub drowsc {
6854
}
6855
0
0
sub dcols {
6856
}
6857
0
0
sub dpk {
6858
}
6859
0
0
sub dsel {
6860
}
6861
sub ddo {
6862
0
0
0
0
my @arg=_dattrarg(@_);
6863
#warn serialize(\@arg,'arg','',1);
6864
0
0
$Dbh->do(@arg); #hm cache?
6865
}
6866
0
0
sub dins {
6867
}
6868
0
0
sub dupd {
6869
}
6870
0
0
sub ddel {
6871
}
6872
0
0
0
0
sub dcommit { $Dbh->commit }
6873
0
0
0
0
sub drollback { $Dbh->rollback }
6874
6875
sub _dattrarg {
6876
0
0
0
my @arg=@_;
6877
0
0
0
splice @arg,1,0, ref($arg[-1]) eq 'HASH' ? pop(@arg) : {};
6878
0
0
@arg;
6879
}
6880
6881
=head2 self_update
6882
6883
Update Acme::Tools to newest version quick and dirty:
6884
6885
function pmview(){ ls -ld `perl -M$1 -le'$m=shift;$mi=$m;$mi=~s,::,/,g;print $INC{"$mi.pm"};warn"Version ".${$m."::VERSION"}."\n"' $1`;}
6886
6887
pmview Acme::Tools #view date and version before
6888
sudo perl -MAcme::Tools -e Acme::Tools::self_update #update to newest version
6889
pmview Acme::Tools #view date and version after
6890
6891
Does C to where Acme/Tools.pm are and then wget -N https://raw.githubusercontent.com/kjetillll/Acme-Tools/master/Tools.pm
6892
6893
=cut
6894
6895
our $Wget;
6896
our $Self_update_url='https://raw.githubusercontent.com/kjetillll/Acme-Tools/master/Tools.pm'; #todo: change site
6897
sub self_update {
6898
#in($^O,'linux','cygwin') or die"ERROR: self_update works on linux and cygwin only";
6899
0
0
0
1
0
$Wget||=(grep -x$_,map"$_/wget",'/usr/bin','/bin','/usr/local/bin','.')[0]; #hm --no-check-certificate
6900
0
0
0
-x$Wget or die"ERROR: wget ($Wget) executable not found\n";
6901
0
0
my $d=dirname(__FILE__);
6902
0
0
sys("cd $d; ls -l Tools.pm; md5sum Tools.pm");
6903
0
0
0
sys("cd $d; $Wget -N ".($ARGV[0]||$Self_update_url));
6904
0
0
sys("cd $d; ls -l Tools.pm; md5sum Tools.pm");
6905
}
6906
6907
1;
6908
6909
package Acme::Tools::BloomFilter;
6910
28
28
768
use 5.008; use strict; use warnings; use Carp;
28
28
101
28
28
141
28
28
50
28
738
28
132
28
46
28
969
28
143
28
46
28
14374
6911
2
2
307
sub new { my($class,@p)=@_; my $self=Acme::Tools::bfinit(@p); bless $self, $class }
2
9
2
11
6912
2
2
108
sub add { &Acme::Tools::bfadd }
6913
0
0
0
sub addbf { &Acme::Tools::bfaddbf }
6914
2
2
88
sub check { &Acme::Tools::bfcheck }
6915
1
1
7
sub grep { &Acme::Tools::bfgrep }
6916
0
0
0
sub grepnot { &Acme::Tools::bfgrepnot }
6917
0
0
0
sub delete { &Acme::Tools::bfdelete }
6918
0
0
0
sub store { &Acme::Tools::bfstore }
6919
0
0
0
sub retrieve { &Acme::Tools::bfretrieve }
6920
1
1
5
sub clone { &Acme::Tools::bfclone }
6921
0
0
0
sub sum { &Acme::Tools::bfsum }
6922
1;
6923
6924
# Ny versjon:
6925
# + c-s todo
6926
# + endre $VERSION
6927
# + endre Release history under HISTORY
6928
# + endre årstall under COPYRIGHT AND LICENSE
6929
# + oppd default valutakurser inkl datoen
6930
# + emacs Changes
6931
# + emacs README + aarstall
6932
# + emacs MANIFEST legg til ev nye t/*.t
6933
# + perl Makefile.PL;make test
6934
# + /usr/bin/perl Makefile.PL;make test
6935
# + perlbrew exec "perl ~/Acme-Tools/Makefile.PL ; time make test"
6936
# + perlbrew use perl-5.10.1; perl Makefile.PL; make test; perlbrew off
6937
# + test evt i cygwin og mingw-perl
6938
# + pod2html Tools.pm > Tools.html ; firefox Tools.html
6939
# + https://metacpan.org/pod/Acme::Tools
6940
# + http://cpants.cpanauthors.org/dist/Acme-Tools #kvalitee
6941
# + perl Makefile.PL ; make test && make dist
6942
# + cp -p *tar.gz /htdocs/
6943
# + ci -l -mversjon -d `cat MANIFEST`
6944
# + git add `cat MANIFEST`
6945
# + git status
6946
# + git commit -am versjon
6947
# + git push #eller:
6948
# + git push origin master
6949
# + http://pause.perl.org/
6950
# http://en.wikipedia.org/wiki/Birthday_problem#Approximations
6951
6952
# memoize_expire() http://perldoc.perl.org/Memoize/Expire.html
6953
# memoize_file_expire()
6954
# memoize_limit_size() #lru
6955
# memoize_file_limit_size()
6956
# memoize_memcached http://search.cpan.org/~dtrischuk/Memoize-Memcached-0.03/lib/Memoize/Memcached.pm
6957
# hint on http://perl.jonallen.info/writing/articles/install-perl-modules-without-root
6958
6959
# sub mycrc32 { #http://billauer.co.il/blog/2011/05/perl-crc32-crc-xs-module/ eller String::CRC32::crc32 som er 100 x raskere enn Digest::CRC::crc32
6960
# my ($input, $init_value, $polynomial) = @_;
6961
# $init_value = 0 unless (defined $init_value);
6962
# $polynomial = 0xedb88320 unless (defined $polynomial);
6963
# my @lookup_table;
6964
# for (my $i=0; $i<256; $i++) {
6965
# my $x = $i;
6966
# for (my $j=0; $j<8; $j++) {
6967
# if ($x & 1) {
6968
# $x = ($x >> 1) ^ $polynomial;
6969
# } else {
6970
# $x = $x >> 1;
6971
# }
6972
# }
6973
# push @lookup_table, $x;
6974
# }
6975
# my $crc = $init_value ^ 0xffffffff;
6976
# foreach my $x (unpack ('C*', $input)) {
6977
# $crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ];
6978
# }
6979
# $crc = $crc ^ 0xffffffff;
6980
# return $crc;
6981
# }
6982
#
6983
6984
6985
6986
=head1 HISTORY
6987
6988
Release history
6989
6990
0.172 Dec 2015 Subs: curb, openstr, pwgen, sleepms, sleepnm, srlz, tms, username,
6991
self_update, install_acme_command_tools
6992
Commands: conv, due, freq, wipe, xcat (see "Commands")
6993
0.16 Feb 2015 bigr, curb, cpad, isnum, parta, parth, read_conf, resolve_equation,
6994
roman2int, trim. Improved: conv (numbers, currency), range ("derivatives")
6995
0.15 Nov 2014 Improved doc
6996
0.14 Nov 2014 New subs, improved tests and doc
6997
0.13 Oct 2010 Non-linux test issue, resolve. improved: bloom filter, tests, doc
6998
0.12 Oct 2010 Improved tests, doc, bloom filter, random_gauss, bytes_readable
6999
0.11 Dec 2008 Improved doc
7000
0.10 Dec 2008
7001
7002
=head1 SEE ALSO
7003
7004
L
7005
7006
=head1 AUTHOR
7007
7008
Kjetil Skotheim, Ekjetil.skotheim@gmail.comE
7009
7010
=head1 COPYRIGHT
7011
7012
1995-2015, Kjetil Skotheim
7013
7014
=head1 LICENSE
7015
7016
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
7017
7018
=cut