| 1 | package Vee::Utils; |
|---|
| 2 | |
|---|
| 3 | use Socket qw//; |
|---|
| 4 | use List::Util qw/first/; |
|---|
| 5 | use Digest::SHA1 qw/sha1_hex/; |
|---|
| 6 | |
|---|
| 7 | =head1 NAME |
|---|
| 8 | |
|---|
| 9 | Vee::Utils - Assorted utility functions |
|---|
| 10 | |
|---|
| 11 | =head1 SYNOPSIS |
|---|
| 12 | |
|---|
| 13 | Coming soon |
|---|
| 14 | |
|---|
| 15 | =head1 DESCRIPTION |
|---|
| 16 | |
|---|
| 17 | Just a collection of small C<sub>s I've written that tend to be more useful |
|---|
| 18 | than I expected. |
|---|
| 19 | |
|---|
| 20 | =head1 FUNCTIONS |
|---|
| 21 | |
|---|
| 22 | Coming soon |
|---|
| 23 | |
|---|
| 24 | =cut |
|---|
| 25 | |
|---|
| 26 | sub hsv2rgb { |
|---|
| 27 | my ($h, $s, $v) = @_; |
|---|
| 28 | $h /= 360; $s /= 256; $v /= 256; |
|---|
| 29 | |
|---|
| 30 | if ($s <= 0.0) { return tohex(int $v * 256) x 3 } |
|---|
| 31 | else { |
|---|
| 32 | if ($h >= 1.0) { $h = 0.0 } |
|---|
| 33 | $h *= 6; |
|---|
| 34 | my $f = $h - int $h; |
|---|
| 35 | my $p = int(256 * $v * (1.0 - $s)); |
|---|
| 36 | my $q = int(256 * $v * (1.0 - ($s * $f))); |
|---|
| 37 | my $t = int(256 * $v * (1.0 - ($s * (1.0 - $f)))); |
|---|
| 38 | $v = int(256 * $v); |
|---|
| 39 | if (int $h == 0) { return hexcolor($v, $t, $p) } |
|---|
| 40 | elsif (int $h == 1) { return hexcolor($q, $v, $p) } |
|---|
| 41 | elsif (int $h == 2) { return hexcolor($p, $v, $t) } |
|---|
| 42 | elsif (int $h == 3) { return hexcolor($p, $q, $v) } |
|---|
| 43 | elsif (int $h == 4) { return hexcolor($t, $p, $v) } |
|---|
| 44 | elsif (int $h == 5) { return hexcolor($v, $p, $q) } |
|---|
| 45 | } |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | # get the postrank for a postcount |
|---|
| 49 | # IN: user post count, OUT: post rank based on user post count |
|---|
| 50 | |
|---|
| 51 | sub postrank { |
|---|
| 52 | my ($post_count) = @_; |
|---|
| 53 | $post_count ||= 0; |
|---|
| 54 | for my $rank ( |
|---|
| 55 | sort { $b <=> $a } |
|---|
| 56 | keys %{ Vee->config->{site}->{post_ranks} } |
|---|
| 57 | ) { |
|---|
| 58 | return Vee->config->{site}->{post_ranks}->{$rank} if $rank <= $post_count; |
|---|
| 59 | } |
|---|
| 60 | return "ERRORZ0RZ"; |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | # get the percent width of the postbar for a given postcount |
|---|
| 64 | # XXX: decide the best way to do this, preferably a smooth log curve |
|---|
| 65 | sub post_width { |
|---|
| 66 | my ($post_count) = @_; |
|---|
| 67 | return $post_count / 1000; |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | # converts input to Linux-style newlines |
|---|
| 71 | sub fix_newlines { |
|---|
| 72 | my $text = shift; |
|---|
| 73 | $text =~ s/\x0d\x0a?/\x0a/g; |
|---|
| 74 | $text =~ s/^\x0a+|\x0a+$//g; |
|---|
| 75 | return $text; |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | # remove all HTML |
|---|
| 79 | sub cleanse { |
|---|
| 80 | my $text = shift; |
|---|
| 81 | return undef unless defined $text; |
|---|
| 82 | $text =~ s/&/&/g; |
|---|
| 83 | $text =~ s/&(#x?[0-9a-f]+;)/&$1/gi; |
|---|
| 84 | $text =~ s/</</g; |
|---|
| 85 | $text =~ s/>/>/g; |
|---|
| 86 | $text =~ s/\"/"/g; |
|---|
| 87 | $text =~ s:\x0D\x0A:<br/>:g; |
|---|
| 88 | $text =~ s:\x0D|\x0A:<br/>:g; |
|---|
| 89 | return $text; |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | # URL-validation regex |
|---|
| 93 | # Inferred from the W3's BNF: http://www.w3.org/Addressing/URL/5_BNF.html |
|---|
| 94 | # n.b.: Technically, the BNF says hostname parts (as delimited by dots) |
|---|
| 95 | # should begin with a letter, but given that 'xalpha' includes dot this was |
|---|
| 96 | # a bit clumsy to pull off in practice, so I left it lazy. |
|---|
| 97 | my $url_xalphas = qr/[-_@.&+!*"'(),a-zA-Z0-9\$]/; |
|---|
| 98 | our $IsValidURL = qr/ ^ |
|---|
| 99 | (?: http | https | ftp ) :\/\/ # protocol |
|---|
| 100 | (?: |
|---|
| 101 | [a-zA-Z] $url_xalphas* # hostname |
|---|
| 102 | | (?: \d{1,3} \. ){3} \d{1,3} # IP |
|---|
| 103 | ) |
|---|
| 104 | (?: : [0-9]+ )? # port |
|---|
| 105 | (?: \/ # path: leading slash |
|---|
| 106 | (?: $url_xalphas* # path: path part name |
|---|
| 107 | | %[a-fA-F][a-fA-F] )* # path: escape |
|---|
| 108 | )* # path: as many as you want |
|---|
| 109 | (?: \? $url_xalphas+ )? # query string |
|---|
| 110 | (?: \# $url_xalphas+ )? # anchor |
|---|
| 111 | $ /x; |
|---|
| 112 | |
|---|
| 113 | |
|---|
| 114 | sub pad { sprintf "%0$_[1]d", $_[0] } |
|---|
| 115 | sub round { $_[1] ||= 0; return int($_[0] * 10 ** $_[1] + .5) / 10 ** $_[1]; } |
|---|
| 116 | sub hexcolor { return tohex($_[0]).tohex($_[1]).tohex($_[2]); } |
|---|
| 117 | sub tohex { return sprintf("%02x", $_[0]); } |
|---|
| 118 | sub isnum { return (defined $_[0] and $_[0] =~ /^ [+-]? \d+ (?:\. [0-9]*)? $/x) } |
|---|
| 119 | sub max { my ($i, $max); while (!defined $max) { $max = shift; } for $i (@_) { next unless defined $i; if ($i > $max) { $max = $i } } return $max; } |
|---|
| 120 | sub min { my ($i, $min); while (!defined $min) { $min = shift; } for $i (@_) { next unless defined $i; if ($i < $min) { $min = $i } } return $min; } |
|---|
| 121 | sub sum { my $x; $x += $_ for (@_); return $x; } |
|---|
| 122 | sub num { return (&isnum($_[0])) ? $_[0] : 0 } |
|---|
| 123 | sub wordcap { my $text = $_[0]; $text =~ s#\b(.*?)\b#ucfirst $1#eg; return $text; } |
|---|
| 124 | sub in { my $tmp = shift; for (@_) { return 1 if $tmp eq $_ } return 0 } |
|---|
| 125 | sub urlencode { my $str = shift; $str =~ s/([^-_a-zA-Z0-9])/'%' . tohex(ord $1)/ge; return $str; } |
|---|
| 126 | sub array { ref $_[0] ? @{ $_[0] } : ( $_[0] ) } |
|---|
| 127 | |
|---|
| 128 | sub inet_ntoa { Socket::inet_ntoa(pack 'N*', shift) } |
|---|
| 129 | sub inet_aton { unpack 'N*', Socket::inet_aton(shift) } |
|---|
| 130 | |
|---|
| 131 | # name comes from what imageboards do, but really it's just a short hash |
|---|
| 132 | sub tripcode { substr sha1_hex(shift), 0, 12 } |
|---|
| 133 | |
|---|
| 134 | =head1 AUTHOR |
|---|
| 135 | |
|---|
| 136 | Maintainer: Alex "Eevee" Munroe (C<veekun@veekun.com>) |
|---|
| 137 | |
|---|
| 138 | See the included F<AUTHORS> file for a full list of contributers. |
|---|
| 139 | |
|---|
| 140 | =head1 LICENSE |
|---|
| 141 | |
|---|
| 142 | See the included F<LICENSE> file. |
|---|
| 143 | |
|---|
| 144 | =cut |
|---|
| 145 | |
|---|
| 146 | 1; |
|---|