File Coverage

blib/lib/WWW/Shorten/Bitly.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             # $Id: Bitly.pm 110 2009-03-22 21:04:27Z pankaj $
2             # $Author: pankaj $
3             # $Date: 2009-03-23 02:34:27 +0530 (Mon, 23 Mar 2009) $
4             # Author: Pankaj Jain
5             ################################################################################################################################
6             package WWW::Shorten::Bitly;
7              
8 1     1   229236 use warnings;
  1         6  
  1         91  
9 1     1   10 use strict;
  1         3  
  1         55  
10 1     1   10 use Carp;
  1         9  
  1         158  
11              
12 1     1   8 use base qw( WWW::Shorten::generic Exporter );
  1         3  
  1         5663  
13             use JSON::Any;
14              
15             require XML::Simple;
16             require Exporter;
17              
18             our %EXPORT_TAGS = ( 'all' => [ qw() ] );
19             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
20             our @EXPORT = qw(new version);
21              
22             my @ISA = qw(Exporter);
23              
24             use vars qw( @ISA @EXPORT );
25              
26             use constant BASE_JMP => 'http://api.j.mp';
27             use constant BASE_BLY => 'http://api.bitly.com';
28              
29             =head1 NAME
30              
31             WWW::Shorten::Bitly - Interface to shortening URLs using L
32              
33             =head1 VERSION
34              
35             $Revision: 1.17 $
36              
37             =cut
38              
39             BEGIN {
40             our $VERSION = do { my @r = (q$Revision: 1.17 $ =~ /\d+/g); sprintf "%1d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
41             $WWW::Shorten::Bitly::VERBOSITY = 2;
42             }
43              
44             # ------------------------------------------------------------
45              
46              
47             =head1 SYNOPSIS
48              
49             WWW::Shorten::Bitly provides an easy interface for shortening URLs using http://bitly.com. In addition to shortening URLs, you can pull statistics that bitly.com gathers regarding each shortened
50             WWW::Shorten::Bitly uses XML::Simple to convert the xml response and JSON::Any to convert JSON responses for the meta info and click stats to create a hashref of the results.
51              
52             WWW::Shorten::Bitly provides two interfaces. The first is the common C and C that WWW::Shorten provides. However, due to the way the bitly.com API works, additional arguments are required. The second provides a better way of retrieving additional information and statistics about a bitly.com URL.
53              
54             use WWW::Shorten::Bitly;
55              
56             my $url = "http://www.example.com";
57              
58             my $tmp = makeashorterlink($url, 'MY_BITLY_USERNAME', 'MY_BITLY_API_KEY');
59             my $tmp1 = makealongerlink($tmp, 'MY_BITLY_USERNAME', 'MY_BITLY_API_KEY');
60              
61             or
62              
63             use WWW::Shorten::Bitly;
64              
65             my $url = "http://www.example.com";
66             my $bitly = WWW::Shorten::Bitly->new(URL => $url,
67             USER => "my_user_id",
68             APIKEY => "my_api_key");
69              
70             $bitly->shorten(URL => $url);
71             print "shortened URL is $bitly->{bitlyurl}\n";
72              
73             $bitly->expand(URL => $bitly->{bitlyurl});
74             print "expanded/original URL is $bitly->{longurl}\n";
75              
76             my $info = $bitly->info();
77             say "Title of the page is " . $info->{title};
78             say "Created by " . $info->{created_by};
79              
80             my $clicks = $bitly->clicks();
81             say "Total number of clicks received: " . $clicks->{user_clicks};
82             say "Total number of global clicks received are: " . $clicks->{global_clicks};
83              
84             Please remember to check out C for more details on V3 of the Bitly.com API
85              
86             =head1 FUNCTIONS
87              
88             =head2 new
89              
90             Create a new bitly.com object using your bitly.com user id and bitly.com api key.
91              
92             my $bitly = WWW::Shorten::Bitly->new(URL => "http://www.example.com/this_is_one_example.html",
93             USER => "bitly_user_id",
94             APIKEY => "bitly_api_key");
95              
96             to use bitly.com's new j.mp service, just construct the bitly object like this:
97             my $bitly = WWW::Shorten::Bitly->new(URL => "http://www.example.com/this_is_one_example.html",
98             USER => "bitly_user_id",
99             APIKEY => "bitly_api_key",
100             jmp => 1);
101              
102             =cut
103              
104             sub new {
105             my ($class) = shift;
106             my %args = @_;
107             $args{source} ||= "perlteknatusbitly";
108             $args{jmp} ||= 0;
109             use File::Spec;
110             my $bitlyrc = $^O =~/Win32/i ? File::Spec->catfile($ENV{HOME}, "_bitly") : File::Spec->catfile($ENV{HOME}, ".bitly");
111             if (-r $bitlyrc){
112             open my $fh, "<", $bitlyrc or die "can't open .bitly file $!";
113             while(<$fh>){
114             $args{USER} ||= $1 if m{^USER=(.*)};
115             $args{APIKEY} ||= $1 if m{^APIKEY=(.*)};
116             }
117             close $fh;
118             }
119             if (!defined $args{USER} || !defined $args{APIKEY}) {
120             carp("USER and APIKEY are both required parameters.\n");
121             return -1;
122             }
123             my $bitly;
124             $bitly->{USER} = $args{USER};
125             $bitly->{APIKEY} = $args{APIKEY};
126             if ($args{jmp} == 1) {
127             $bitly->{BASE} = BASE_JMP;
128             } else {
129             $bitly->{BASE} = BASE_BLY;
130             }
131             $bitly->{json} = JSON::Any->new;
132             $bitly->{browser} = LWP::UserAgent->new(agent => $args{source});
133             $bitly->{xml} = new XML::Simple(SuppressEmpty => 1);
134             my ($self) = $bitly;
135             bless $self, $class;
136             }
137              
138              
139             =head2 makeashorterlink
140              
141             The function C will call the bitly.com API site passing it
142             your long URL and will return the shorter bitly.com version.
143              
144             bitly.com requires the use of a user id and API key to shorten links.
145              
146             j.mp is not currently supported for makeashorterlink
147              
148             =cut
149              
150             sub makeashorterlink #($;%)
151             {
152             my $url = shift or croak('No URL passed to makeashorterlink');
153             my ($user, $apikey) = @_ or croak('No username or apikey passed to makeshorterlink');
154             if (!defined $url || !defined $user || !defined $apikey ) {
155             croak("url, user and apikey are required for shortening a URL with bitly.com - in that specific order");
156             &help();
157             }
158             my $ua = __PACKAGE__->ua();
159             my $bitly;
160             $bitly->{json} = JSON::Any->new;
161             $bitly->{xml} = new XML::Simple(SuppressEmpty => 1);
162             my $biturl = BASE_BLY . '/v3/shorten';
163             $bitly->{response} = $ua->post($biturl, [
164             'format' => 'json',
165             'history' => '1',
166             'version' => '3.0.0',
167             'longUrl' => $url,
168             'login' => $user,
169             'apiKey' => $apikey,
170             ]);
171             $bitly->{response}->is_success || die 'Failed to get bitly.com link: ' . $bitly->{response}->status_line;
172             $bitly->{bitlyurl} = $bitly->{json}->jsonToObj($bitly->{response}->{_content})->{data}->{url};
173             return unless $bitly->{response}->is_success;
174             return $bitly->{bitlyurl};
175             }
176              
177             =head2 makealongerlink
178              
179             The function C does the reverse. C
180             will accept as an argument either the full bitly.com URL or just the
181             bitly.com identifier. bitly.com requires the use of a user name and API
182             Key when using the API.
183              
184             If anything goes wrong, then the function will return C.
185              
186             j.mp is not currently supported for makealongerlink
187              
188             =cut
189              
190             sub makealongerlink #($,%)
191             {
192             my $url = shift or croak('No shortened bitly.com URL passed to makealongerlink');
193             my ($user, $apikey) = @_ or croak('No username or apikey passed to makealongerlink');
194             my $ua = __PACKAGE__->ua();
195             my $bitly;
196             my @foo = split(/\//, $url);
197             $bitly->{json} = JSON::Any->new;
198             $bitly->{xml} = new XML::Simple(SuppressEmpty => 1);
199             $bitly->{response} = $ua->post(BASE_BLY . '/v3/expand', [
200             'version' => '3.0.0',
201             'shortUrl' => $url,
202             'login' => $user,
203             'apiKey' => $apikey,
204             ]);
205             $bitly->{response}->is_success || die 'Failed to get bitly.com link: ' . $bitly->{response}->status_line;
206             $bitly->{longurl} = $bitly->{json}->jsonToObj($bitly->{response}->{_content})->{data}->{long_url};
207             return undef unless $bitly->{response}->is_success;
208             my $content = $bitly->{response}->content;
209             # return undef if $content eq 'ERROR';
210             return $bitly->{longurl};
211             }
212              
213             =head2 shorten
214              
215             Shorten a URL using http://bitly.com. Calling the shorten method will return the shortened URL but will also store it in bitly.com object until the next call is made.
216              
217             my $url = "http://www.example.com";
218             my $shortstuff = $bitly->shorten(URL => $url);
219              
220             print "biturl is " . $bitly->{bitlyurl} . "\n";
221             or
222             print "biturl is $shortstuff\n";
223              
224             =cut
225              
226              
227             sub shorten {
228             my $self = shift;
229             my %args = @_;
230             if (!defined $args{URL}) {
231             croak("URL is required.\n");
232             return -1;
233             }
234             $self->{response} = $self->{browser}->post($self->{BASE} . '/v3/shorten', [
235             'history' => '1',
236             'version' => '3.0.0',
237             'longUrl' => $args{URL},
238             'login' => $self->{USER},
239             'apiKey' => $self->{APIKEY},
240             ]);
241             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
242             return undef if ( $self->{json}->jsonToObj($self->{response}->{_content})->{status_code} != 200 );
243             $self->{bitlyurl} = $self->{json}->jsonToObj($self->{response}->{_content})->{data}->{url};
244             return $self->{bitlyurl} if ( $self->{json}->jsonToObj($self->{response}->{_content})->{status_code} == 200 );
245             }
246              
247             =head2 expand
248              
249             Expands a shortened bitly.com URL to the original long URL.
250              
251             =cut
252             sub expand {
253             my $self = shift;
254             my %args = @_;
255             if (!defined $args{URL}) {
256             croak("URL is required.\n");
257             return -1;
258             }
259             # my @foo = split(/\//, $args{URL});
260             $self->{response} = $self->{browser}->post($self->{BASE} . '/v3/expand', [
261             'history' => '1',
262             'version' => '3.0.0',
263             'shortUrl' => $args{URL},
264             'login' => $self->{USER},
265             'apiKey' => $self->{APIKEY},
266             ]);
267             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
268             return undef if ( $self->{json}->jsonToObj($self->{response}->{_content})->{status_code} != 200 );
269             $self->{longurl} = $self->{json}->jsonToObj($self->{response}->{_content})->{data}->{expand}[0]->{long_url};
270             return $self->{longurl} if ( $self->{json}->jsonToObj($self->{response}->{_content})->{status_code} == 200 );
271             }
272              
273             =head2 info
274              
275             Get info about a shortened bitly.com URL. By default, the method will use the value that's stored in $bitly->{bitlyurl}. To be sure you're getting info on the correct URL, it's a good idea to set this value before getting any info on it.
276              
277             $bitly->{bitlyurl} = "http://bitly.com/jmv6";
278             my $info = $bitly->info();
279              
280             say "Title of the page is " . $info->{title};
281             say "Created by " . $info->{created_by};
282              
283             =cut
284              
285              
286             sub info {
287             my $self = shift;
288             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/info?shortUrl=' . $self->{bitlyurl} . '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
289             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
290             $self->{$self->{bitlyurl}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
291             if ($self->{$self->{bitlyurl}}->{content}->{status_code} == 200 ) {
292             $self->{$self->{bitlyurl}}->{info} = $self->{$self->{bitlyurl}}->{content}->{data}->{info}[0];
293             return $self->{$self->{bitlyurl}}->{info};
294             } else {
295             return;
296             }
297             }
298              
299              
300              
301             =head2 clicks
302              
303             Get click thru information for a shortened bitly.com URL. By default, the method will use the value that's stored in $bitly->{bitlyurl}. To be sure you're getting info on the correct URL, it's a good idea to set this value before getting any info on it.
304              
305             $bitly->{bitlyurl} = "http://bitly.com/jmv6";
306             my $clicks = $bitly->clicks();
307              
308             say "Total number of clicks received: " . $clicks->{user_clicks};
309             say "Total number of global clicks received are: " . $clicks->{global_clicks};
310              
311             =cut
312              
313             sub clicks {
314             my $self = shift;
315             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/clicks?shortUrl=' . $self->{bitlyurl} . '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
316             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
317             $self->{$self->{bitlyurl}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
318             # $self->{$self->{bitlyurl}}->{errorCode} = $self->{$self->{bitlyurl}}->{content}->{status_txt};
319             if ($self->{$self->{bitlyurl}}->{content}->{status_code} == 200 ) {
320             # $self->{$self->{bitlyurl}}->{clicks} = $self->{$self->{bitlyurl}}->{content}->{results};
321             $self->{$self->{bitlyurl}}->{clicks} = $self->{$self->{bitlyurl}}->{content}->{data}->{clicks}[0];
322             return $self->{$self->{bitlyurl}}->{clicks};
323             } else {
324             return;
325             }
326             }
327              
328             =head2 errors
329              
330             =cut
331              
332             sub errors {
333             my $self = shift;
334             warn "errors - deprecated from BitLy API. It will no longer be supported" if (1.14 > $WWW::Shorten::Bitly::VERSION);
335             return;
336             $self->{response} = $self->{browser}->post($self->{BASE} . '/v3/errors', [
337             'version' => '3.0.0',
338             'login' => $self->{USER},
339             'apiKey' => $self->{APIKEY},
340             ]);
341             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
342             $self->{$self->{bitlyurl}}->{content} = $self->{xml}->XMLin($self->{response}->{_content});
343             $self->{$self->{bitlyurl}}->{errorCode} = $self->{$self->{bitlyurl}}->{content}->{status_txt};
344             if ($self->{$self->{bitlyurl}}->{status_code} == 200 ) {
345             $self->{$self->{bitlyurl}}->{clicks} = $self->{$self->{bitlyurl}}->{content}->{results};
346             return $self->{$self->{bitlyurl}}->{clicks};
347             } else {
348             return;
349             }
350             }
351              
352             =head2 version
353              
354             Gets the module version number
355              
356             =cut
357             sub version {
358             my $self = shift;
359             my($version) = shift;# not sure why $version isn't being set. need to look at it
360             warn "Version $version is later then $WWW::Shorten::Bitly::VERSION. It may not be supported" if (defined ($version) && ($version > $WWW::Shorten::Bitly::VERSION));
361             return $WWW::Shorten::Bitly::VERSION;
362             }#version
363              
364              
365             =head2 referrers
366              
367             Returns an array of hashes
368              
369             my @ref = $bitly->referrers();
370             say "Referrers for " . $bitly->{bitlyurl};
371             foreach my $r (@ref) {
372             foreach my $f (@{$r}) {
373             say $f->{clicks} . ' from ' . $f->{referrer};
374             }
375             }
376              
377             =cut
378              
379             sub referrers {
380             my $self = shift;
381             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/referrers?shortUrl=' . $self->{bitlyurl} . '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
382             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
383             $self->{$self->{bitlyurl}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
384             if ($self->{$self->{bitlyurl}}->{content}->{status_code} == 200 ) {
385             $self->{$self->{bitlyurl}}->{referrers} = $self->{$self->{bitlyurl}}->{content}->{data}->{referrers};
386             return $self->{$self->{bitlyurl}}->{referrers};
387             } else {
388             return;
389             }
390             }
391              
392              
393             =head2 countries {
394              
395             Returns an array of hashesh
396              
397             my @countries = $bitly->countries();
398             foreach my $r (@countries) {
399             foreach my $f (@{$r}) {
400             say $f->{clicks} . ' from ' . $f->{country};
401             }
402             }
403              
404             =cut
405              
406             sub countries {
407             my $self = shift;
408             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/countries?shortUrl=' . $self->{bitlyurl} . '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
409             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
410             $self->{$self->{bitlyurl}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
411             if ($self->{$self->{bitlyurl}}->{content}->{status_code} == 200 ) {
412             $self->{$self->{bitlyurl}}->{countries} = $self->{$self->{bitlyurl}}->{content}->{data}->{countries};
413             return $self->{$self->{bitlyurl}}->{countries};
414             } else {
415             return;
416             }
417             }
418              
419             =head2 clicks_by_day {
420              
421             Returns an array of hashes
422              
423             my @c = $bitly->clicks_by_day();
424             say "Clicks by Day for " . $bitly->{bitlyurl};
425             foreach my $r (@c) {
426             foreach my $f (@{$r}) {
427             say $f->{clicks} . ' on ' . $f->{day_start};
428             }
429             }
430              
431             day_start is the timecode as specified by Bitly.com. You can use the following to turn it into a DateTime Object
432              
433             use DateTime;
434             $dt = DateTime->from_epoch( epoch => $epoch );
435              
436             =cut
437              
438             sub clicks_by_day {
439             my $self = shift;
440             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/clicks_by_day?shortUrl=' . $self->{bitlyurl} . '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
441             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
442             $self->{$self->{bitlyurl}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
443             if ($self->{$self->{bitlyurl}}->{content}->{status_code} == 200 ) {
444             $self->{$self->{bitlyurl}}->{clicks_by_day} = $self->{$self->{bitlyurl}}->{content}->{data}->{clicks_by_day}[0]->{clicks};
445             return $self->{$self->{bitlyurl}}->{clicks_by_day};
446             } else {
447             return;
448             }
449             }
450              
451              
452             =head2 qr_code
453              
454             Returns the URL for the QR Code
455              
456             =cut
457             sub qr_code {
458             my $self = shift;
459             my %args = @_;
460             $self->{bitlyurl} ||= $args{shorturl};
461             return $self->{bitlyurl} . '.qrcode';
462             }
463              
464             =head2 validate
465              
466             For any given a bitly user login and apiKey, you can validate that the pair is active.
467              
468             =cut
469              
470             sub validate {
471             my $self = shift;
472             my %args = @_;
473             $self->{USER} ||= $args{user};
474             $self->{APIKEY} ||= $args{apikey};
475              
476             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/validate?x_login=' . $self->{USER} . '&x_apiKey=' . $self->{APIKEY}. '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
477             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
478             $self->{$self->{USER}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
479             if ($self->{json}->jsonToObj($self->{response}->{_content})->{data}->{valid} == 1) {
480             $self->{$self->{USER}}->{valid} = $self->{$self->{USER}}->{content}->{data}->{valid};
481             return $self->{$self->{USER}}->{valid};
482             } else {
483             return;
484             }
485             }
486              
487             =head2 bitly_pro_domain
488              
489             Will return true or false whether the URL specified is a Bitly Pro Domain
490              
491             my $bpd = $bitly->bitly_pro_domain(url => 'http://nyti.ms');
492             say "This is a Bitly Pro Domain: " . $bpd;
493              
494             my $bpd2 = $bitly->bitly_pro_domain(url => 'http://example.com');
495             say "This is a Bitly Pro Domain: " . $bpd2;
496              
497             =cut
498              
499             sub bitly_pro_domain {
500             my $self = shift;
501             my %args = @_;
502             $self->{USER} ||= $args{user};
503             $self->{APIKEY} ||= $args{apikey};
504             if ($args{url} !~ /bit\.ly/ || $args{url} !~ /j\.mp/) {
505             my @foo = split(/\//, $args{url});
506             my $domain = $foo[2];
507             $self->{response} = $self->{browser}->get($self->{BASE} . '/v3/bitly_pro_domain?domain=' . $domain . '&login=' . $self->{USER} . '&apiKey=' . $self->{APIKEY});
508             $self->{response}->is_success || die 'Failed to get bitly.com link: ' . $self->{response}->status_line;
509             $self->{$args{url}}->{content} = $self->{json}->jsonToObj($self->{response}->{_content});
510             if ($self->{$args{url}}->{content}->{status_code} == 200 ) {
511             $self->{$args{url}}->{bitly_pro_domain} = $self->{$args{url}}->{content}->{data}->{bitly_pro_domain};
512             return $self->{$args{url}}->{bitly_pro_domain};
513             } else {
514             return;
515             }
516             } else {
517             return 1;
518             }
519             }
520              
521             =head2 lookup
522              
523             =cut
524             sub lookup {
525             my $self = shift;
526             }
527              
528              
529             =head2 clicks_by_minute
530              
531             This part of the Bitly APi isn't being implemented because it's virtually impossible to know exactly which minute a clicks is attributed to. ya know, network lag, etc. I'll implement this when Bitly puts some sort of a time code into the results.
532              
533             =cut
534              
535              
536              
537             =head1 FILES
538              
539             $HOME/.bitly or _bitly on Windows Systems.
540              
541             You may omit USER and APIKEY in the constructor if you set them in the .bitly config file on separate lines using the syntax:
542              
543             USER=username
544             APIKEY=apikey
545              
546              
547             =head1 AUTHOR
548              
549             Pankaj Jain, C<< >>
550              
551             =head1 BUGS
552              
553             Please report any bugs or feature requests to C, or through
554             the web interface at L. I will
555             be notified, and then you'll automatically be notified of progress on your bug as I make changes.
556              
557              
558             =head1 SUPPORT
559              
560             You can find documentation for this module with the perldoc command.
561              
562             perldoc WWW::Shorten::Bitly
563              
564              
565             You can also look for information at:
566              
567             =over 4
568              
569             =item * RT: CPAN's request tracker
570              
571             L
572              
573             =item * AnnoCPAN: Annotated CPAN documentation
574              
575             L
576              
577             =item * CPAN Ratings
578              
579             L
580              
581             =item * Search CPAN
582              
583             L
584              
585             =back
586              
587              
588             =head1 ACKNOWLEDGEMENTS
589              
590             =over
591              
592             =item http://bitly.com for a wonderful service.
593              
594             =item Larry Wall, Damian Conway, and all the amazing folks giving us Perl and continuing to work on it over the years.
595              
596             =item Mizar, C<< >>, Peter Edwards, C< >>, Joerg Meltzer, C<< >> for great patches.
597              
598             =item Thai Thanh Nguyen, C<< >> for patches to support the Bitly.com v3 API
599              
600             =back
601              
602             =head1 COPYRIGHT & LICENSE
603              
604             =over
605              
606             =item Copyright (c) 2009-2010 Pankaj Jain, All Rights Reserved L.
607              
608             =item Copyright (c) 2009-2010 Teknatus Solutions LLC, All Rights Reserved
609             L.
610              
611             =back
612              
613             This program is free software; you can redistribute it and/or modify it
614             under the same terms as Perl itself.
615              
616             =head1 DISCLAIMER OF WARRANTY
617              
618             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
619             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
620             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
621             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
622             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
623             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
624             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
625             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
626             NECESSARY SERVICING, REPAIR, OR CORRECTION.
627              
628             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
629             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
630             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
631             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
632             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
633             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
634             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
635             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
636             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
637             SUCH DAMAGES.
638              
639             =head1 SEE ALSO
640              
641             L, L, L.
642              
643             =cut
644              
645             1; # End of WWW::Shorten::Bitly