NAME
LJ::Simple - Simple Perl to access LiveJournal
SYNOPSIS
use LJ::Simple;
## Variables - defaults are shown and normally you'll
## not have to set any of the following.
# Do we show debug info ?
$LJ::Simple::debug = 0;
# Do we show the LJ protocol ?
$LJ::Simple::protocol = 0;
# Do we use version 1 of the LJ protocol and thus support UTF-8 ?
$LJ::Simple::UTF = 0;
# Where error messages are placed
$LJ::Simple::error = "";
# The timeout on reading from sockets in seconds - default is 5 minutes
$LJ::Simple::timeout = 500;
# How much data to read from the socket in one read()
$LJ::Simple::buffer = 8192;
## Object creation
my $lj = new LJ::Simple ( {
user => "username",
pass => "password",
} );
my $lj = new LJ::Simple ( {
user => "username",
pass => "password",
site => "hostname[:port]",
proxy => "hostname[:port]",
moods => 0 | 1,
pics => 0 | 1,
fast => 0 | 1,
} );
my $lj = LJ::Simple->login ( {
user => "username",
pass => "password",
site => "hostname[:port]",
proxy => "hostname[:port]",
moods => 0 | 1,
pics => 0 | 1,
fast => 0 | 1,
} );
## Routines which pull information from the login data
$lj->message()
$lj->moods($hash_ref)
$lj->communities()
$lj->MemberOf($community)
$lj->groups($hash_ref)
$lj->MapGroupToId($group_name)
$lj->MapIdToGroup($id)
$lj->pictures($hash_ref)
$lj->user()
$lj->fastserver()
## Routines which pull data from the LJ server
$lj->GetFriendOf()
$lj->GetFriends()
$lj->CheckFriends()
$lj->GetDayCounts()
$lj->GetFriendGroups()
## Routines for handling journal entries
# Top level journal access routines
$lj->UseJournal($event,$journal)
$lj->NewEntry($event)
$lj->PostEntry($event)
$lj->EditEntry($event)
$lj->DeleteEntry($item_id)
$lj->SyncItems($time_t)
$lj->GetEntries($hash_ref,$journal,$type,@opt)
# Routines which do more than just set a value within
# a new journal entry
$lj->SetDate($event,$time_t)
$lj->SetMood($event,$mood)
# Routines for setting subject and journal contents
$lj->SetSubject($event,$subject)
$lj->SetEntry($event,@entry)
$lj->AddToEntry($event,@entry)
# Routines for setting permissions on the entry
$lj->SetProtectFriends($event)
$lj->SetProtectGroups($event,$group1, $group2, ... $groupN)
$lj->SetProtectPrivate($event)
# Setting properties for the entry
$lj->Setprop_backdate($event,$onoff)
$lj->Setprop_current_mood($event,$mood)
$lj->Setprop_current_mood_id($event,$id)
$lj->Setprop_current_music($event,$music)
$lj->Setprop_preformatted($event,$onoff)
$lj->Setprop_nocomments($event,$onoff)
$lj->Setprop_picture_keyword($event,$keyword)
$lj->Setprop_noemail($event,$onoff)
$lj->Setprop_unknown8bit($event,$onoff)
# Routines which do more than just get a value from
# a journal entry
$lj->GetDate($event)
$lj->GetItemId($event)
$lj->GetURL($event)
# Routines for getting subject and journal contents
$lj->GetSubject($event)
$lj->GetEntry($event)
# Routines for getting permissions on an entry
$lj->GetProtect($event)
# Getting properties for an entry
$lj->Getprop_backdate($event)
$lj->Getprop_current_mood($event)
$lj->Getprop_current_mood_id($event)
$lj->Getprop_current_music($event)
$lj->Getprop_preformatted($event)
$lj->Getprop_nocomments($event)
$lj->Getprop_picture_keyword($event)
$lj->Getprop_noemail($event)
$lj->Getprop_unknown8bit($event)
REQUIREMENTS
This module requires nothing other than the modules which come with the standard perl 5.6.1 distribution. The only modules it requires are POSIX
and Socket
.
If you have the Digest::MD5
module available then the code will make use of encrypted passwords automatically. However Digest::MD5
is not required for this module to work.
DESCRIPTION
LJ::Simple is a trival API to access LiveJournal. Currently all that it does is:
- Login
-
Log into the LiveJournal system
- Post
-
Post a new journal entry in the LiveJournal system
- Synchronise
-
Returns a list of journal entries created or modified from a given date.
- Edit
-
Edit the contents of an existing entry within the LiveJournal system
- Delete
-
Delete an existing post from the LiveJournal system
Variables available are:
- $LJ::Simple::debug
-
If set to 1, debugging messages are sent to stderr.
- $LJ::Simple::protocol
-
If set to 1 the protocol used to talk to the remote server is sent to stderr.
- $LJ::Simple::UTF
-
If set to 1 the LiveJournal server is told to expect UTF-8 encoded characters. If you enable this the module will attempt to use the utf8 perl module.
- $LJ::Simple::error
-
Holds error messages, is set with a blank string at the start of each method. Whilst the messages are relatively free-form, there are some prefixes which are sometimes used:
CODE: An error in the code calling the API INTERNAL: An internal error in this module
- $LJ::Simple::timeout
-
The time - specified in seconds - to wait for data from the server. If given a value of
undef
the API will block until data is avaiable. - $LJ::Simple::buffer
-
The number of bytes to try and read in on each
sysread()
call.
The actual methods available are:
login
Logs into the LiveJournal system.
## Simplest logon method
my $lj = new LJ::Simple ( {
user => "username",
pass => "password",
} );
## Login with options
my $lj = new LJ::Simple ( {
user => "username",
pass => "password",
site => "hostname[:port]",
proxy => "hostname[:port]",
moods => 0 | 1,
pics => 0 | 1,
fast => 0 | 1,
} );
## Login by using login()
my $lj = LJ::Simple->login ( {
user => "username",
pass => "password",
site => "hostname[:port]",
proxy => "hostname[:port]",
moods => 0 | 1,
pics => 0 | 1,
fast => 0 | 1,
} );
Where:
user is the username to use
pass is the password associated with the username
site is the remote site to use
proxy is the HTTP proxy site to use
moods is set to 0 if we do not want to download the mood
list. Defaults to 1
pics is set to 0 if we do not want to download the user
picture information. Defaults to 1
fast is set to 1 if we want to perform a fast login.
Default is 0. See below for details of this.
Sites defined in site
or proxy
are a hostname with an optional port number, separated by a :
, i.e.:
www.livejournal.com
www.livejournal.com:80
If site
is given undef
then the code assumes that you wish to connect to www.livejournal.com:80
. If no port is given then port 80
is the default.
If proxy
is given undef
then the code will go directly to the $site
. If no port is given then port 3128
is the default.
If moods
is set to 0
then the mood list will not be pulled from the LiveJournal server and the following functions will be affected:
o moods() will always return undef (error)
o Setprop_current_mood_id() will not validate the mood_id
given to it.
o SetMood() will not attempt to convert the string it is
given into a given mood_id
If pics
is set to 0
then the data on the user pictures will not be pulled from the LiveJournal server and the following functions will be affected:
o pictures() will always return undef (error)
o Setprop_picture_keyword() will blindly set the picture keyword
you give it - no validation will be performed.
If fast
is set to 1
then we will perform a fast login. Essentially all this does is to set up the various entries in the object hash which the routines called after login
expect to see; at no time does it talk to the LiveJournal servers. What this means is that it is very fast. However it also means that when you use parts of the API which do talk to the LiveJournal servers its quite possible that you will get back errors associated with authentication errors, network outages, etc. In other words, in fast
mode the login will always succeed, no matter what the state the LiveJournal server we're talking is in. It should be noted that the following functions will be affected if you enable the fast login:
o moods() will always return undef (error)
o Setprop_current_mood_id() will not validate the mood_id
given to it
o SetMood() will not attempt to convert the string it is
given into a given mood_id
o pictures() will always return undef (error)
o Setprop_picture_keyword() will blindly set the picture keyword
you give it - no validation will be performed
o communities() will always return an empty list
o MemberOf() will always return 0 (error)
o UseJournal() will not validate the shared journal name you
give it
o groups() will always return undef (error)
o MapGroupToId() will always undef (error)
o MapIdToGroup() will always undef (error)
o SetProtectGroups() will always 0 (error)
o message() will always return undef (error)
o The key of "groups" in the list of hashes returned by
GetFriends() will always point to an empty list
o CheckFriends() will return undef (error) if you give it a
list of groups
On success this sub-routine returns an LJ::Simple
object. On failure it returns undef
with the reason for the failure being placed in $LJ::Simple::error
.
Example code:
## Simple example, going direct to www.livejournal.com:80
my $lj = new LJ::Simple ({ user => "someuser", pass => "somepass" });
(defined $lj) ||
die "$0: Failed to access LiveJournal - $LJ::Simple::error\n";
## More complex example, going via a proxy server on port 3000 to a
## a LiveJournal system available on port 8080 on the machine
## www.somesite.com.
my $lj = new LJ::Simple ({
user => "someuser",
pass => "somepass",
site => "www.somesite.com:8080",
proxy => "proxy.internal:3000",
});
(defined $lj) ||
die "$0: Failed to access LiveJournal - $LJ::Simple::error\n";
## Another complex example, this time saying that we do not want
## the mood list or user pictures downloaded
my $lj = new LJ::Simple ({
user => "someuser",
pass => "somepass",
pics => 0,
moods => 0,
});
(defined $lj) ||
die "$0: Failed to access LiveJournal - $LJ::Simple::error\n";
## Final example - this one shows the use of the fast logon
my $lj = new LJ::Simple ({
user => "someuser",
pass => "somepass",
fast => 1,
});
(defined $lj) ||
die "$0: Failed to access LiveJournal - $LJ::Simple::error\n";
$lj->message()
Returns back a message set in the LiveJournal system. Either returns back the message or undef
if no message is set.
Example code:
my $msg = $lj->message();
(defined $msg) &&
print "LJ Message: $msg\n";
$lj->moods($hash_ref)
Takes a reference to a hash and fills it with information about the moods returned back by the server. Either returns back the same hash reference or undef
on error.
Note that if the LiveJournal object was created with either moods
set to 0
or with fast
set to 1
then this function will always return an error.
The hash the given reference is pointed to is emptied before it is used and after a successful call the hash given will contain:
%hash = (
list => [ list of mood names, alphabetical ]
moods => {
mood_name => mood_id
}
idents => {
mood_id => mood_name
}
)
Example code:
my %Moods=();
if (!defined $lj->moods(\%Moods)) {
die "$0: LJ error - $LJ::Simple::error";
}
foreach (@{$Moods{list}}) {
print "$_ -> $Moods{moods}->{$_}\n";
}
$lj->communities()
Returns a list of shared access communities the user logged in can post to. Returns an empty list if no communities are available
Example code:
my @communities = $lj->communities();
print join("\n",@communities),"\n";
$lj->MemberOf($community)
Returns 1
if the user is a member of the named community. Returns 0
otherwise.
Example code:
if ($lj->MemberOf("some_community")) {
:
:
:
}
$lj->groups($hash_ref)
Takes a reference to a hash and fills it with information about the friends groups the user has configured for themselves. Either returns back the hash reference or undef
on error.
The hash the given reference points to is emptied before it is used and after a successful call the hash given will contain the following:
%hash = (
"name" => {
"Group name" => {
id => "Number of the group",
sort => "Sort order",
name => "Group name (copy of key)",
},
},
"id" => {
"Id" => "Group name",
},
);
Example code:
my %Groups=();
if (!defined $lj->groups(\%Groups)) {
die "$0: LJ error - $LJ::Simple::error";
}
my ($id,$name)=(undef,undef);
while(($id,$name)=each %{$Groups{id}}) {
my $srt=$Groups{name}->{$name}->{sort};
print "$id\t=> $name [$srt]\n";
}
$lj->MapGroupToId($group_name)
Used to map a given group name to its identity. On success returns the identity for the group name. On failure it returns undef
and sets $LJ::Simple::error
.
$lj->MapIdToGroup($id)
Used to map a given identity to its group name. On success returns the group name for the identity. On failure it returns undef
and sets $LJ::Simple::error
.
$lj->pictures($hash_ref)
Takes a reference to a hash and fills it with information about the pictures the user has configured for themselves. Either returns back the hash reference or undef
on error. Note that the user has to have defined picture keywords for this to work.
Note that if the LiveJournal object was created with either pics
set to 0
or with fast
set to 1
then this function will always return an error.
The hash the given reference points to is emptied before it is used and after a successful call the hash given will contain the following:
%hash = (
"keywords" => "URL of picture",
);
Example code:
my %pictures=();
if (!defined $lj->pictures(\%pictures)) {
die "$0: LJ error - $LJ::Simple::error";
}
my ($keywords,$url)=(undef,undef);
while(($keywords,$url)=each %pictures) {
print "\"$keywords\"\t=> $url\n";
}
$lj->user()
Returns the username used to log into LiveJournal
Example code:
my $user = $lj->user();
$lj->fastserver()
Used to tell if the user which was logged into the LiveJournal system can use the fast servers or not. Returns 1
if the user can use the fast servers, 0
otherwise.
Example code:
if ($lj->fastserver()) {
print STDERR "Using fast server for ",$lj->user(),"\n";
}
$lj->GetFriendOf()
Returns a list of the other LiveJournal users who list the current user as a friend. The list returned contains a least one entry, the number of entries in the list. This value can range from 0 to however many users are in the list. In the event of a failure this value is undefined.
The list of friends is a list of hash references which contain data about the users who list the current user as a friend. Each hash referenced will contain the following:
{
user => The LiveJournal username
name => The full name of the user
fg => The foreground colour which represents the user
bg => The background colour which represents the user
status => The status of the user
type => The type of the user
}
Both the bg
and fg
values are stored in the format of "#
RRGGBB" where the RR, GG, BB values are given as two digit hexadecimal numbers which range from 00
to ff
.
The status
of a user can be one of "active
", "deleted
", "suspended
" or "purged
".
The type
of a user can either be "user
" which means that the user is a normal LiveJournal user or it can be "community
" which means that the user is actually a community which the current LJ user is a member of.
It should be noted that any of the values in the hash above can be undefined if that value was not returned from the LiveJournal server.
The returned list is ordered by the LiveJournal login names of the users.
Example code:
my ($num_friends_of,@FriendOf)=$lj->GetFriendOf();
(defined $num_friends_of) ||
die "$0: Failed to get friends of user - $LJ::Simple::error\n";
print "LJ login\tReal name\tfg\tbg\tStatus\tType\n";
foreach (@FriendOf) {
print "$_->{user}\t",
"$_->{name}\t",
"$_->{fg}\t",
"$_->{bg}\t",
"$_->{status}\t",
"$_->{type}\n";
}
$lj->GetFriends()
Returns a list of the other LiveJournal user who are listed as friends of the current user. The list returned contains a least one entry, the number of entries in the list. This value can range from 0 to however many users are in the list. In the event of a failure this value is undefined.
The list of friends is a list of hash references which contain data about the users who list the current user as a friend. Each hash referenced will contain the following:
{
user => The LiveJournal username
name => The full name of the user
fg => The foreground colour which represents the user
bg => The background colour which represents the user
dob => The date of birth for the user
birthday => The birthday of the user
groups => The list of friends groups this user is in
groupmask => The actual group mask for this user
status => The status of the user
type => The type of the user
}
Both the bg
and fg
values are stored in the format of "#
RRGGBB" where the RR, GG, BB values are given as two digit hexadecimal numbers which range from 00
to ff
.
The dob
value is stored as a Unix timestamp; that is seconds since epoch. If the user has no date of birth defined or they have only given their birthday then this value will be undef
.
The birthday
value is the date of the user's next birthday given as a Unix timestamp.
The groups
value is a reference to a list of the friends group this user is a member of. It should be noted that to have any items in the list the user must be a member of a friends group and the login()
method must not have been called with the fast login option.
The groupmask
value is the actual group mask for the user. This is used to build the groups
list. It is a 32-bit number where each bit represents membership of a given friends group. Bits 0 and 31 are reserved; all other bits can be used. The bit a group corresponds to is taken by bit-shifting 1 by the group id number.
The status
of a user can be one of "active
", "deleted
", "suspended
" or "purged
".
The type
of a user can either be "user
" which means that the user is a normal LiveJournal user or it can be "community
" which means that the user is actually a community which the current LJ user is a member of.
It should be noted that any of the values in the hash above can be undefined if that value was not returned from the LiveJournal server.
The returned list is ordered by the LiveJournal login names of the users.
Example code:
use POSIX;
my ($num_friends,@Friends)=$lj->GetFriends();
(defined $num_friends) ||
die "$0: Failed to get friends - $LJ::Simple::error\n";
my $f=undef;
foreach $f (@Friends) {
foreach (qw(dob birthday)) {
(defined $f->{$_}) || next;
$f->{$_}=strftime("%Y/%m/%d",gmtime($f->{$_}));
}
my ($k,$v)=(undef,undef);
while(($k,$v)=each %{$f}) {
(!defined $v) && ($f->{$k}="[undefined]");
}
print "$f->{user}\n";
print " Name : $f->{name}\n";
print " Colors : fg->$f->{fg} bg->$f->{bg}\n";
print " DOB : $f->{dob}\n";
print " Next birthday: $f->{birthday}\n";
print " Status : $f->{status}\n";
print " Type : $f->{type}\n";
if ($#{$f->{groups}}>-1) {
print " Friend groups:\n";
print " + ",join("\n + ",@{$f->{groups}}),"\n";
} else {
print " Friend groups: [none]\n";
}
print "\n";
}
$lj->CheckFriends(@groups)
This routine is used to poll the LiveJournal server to see if your friends list has been updated or not. This routine returns a list. The first item in the list is a value which holds 1
if there has been an update to your friends list and 0
if not. The second item in the list holds the number of seconds you must wait before calling CheckFriends()
again. In the event of an error undef
is returned in the first item of the list.
The routine can be given an optional list of friends group to check instead of just looking at all of the friends for the user.
Example code:
while(1) {
my ($new_friends,$next_update)=$lj->CheckFriends();
(defined $new_friends) ||
die "$0: Failed to check friends - $LJ::Simple::error\n";
($new_friends) && print "Friends list updated\n";
sleep($next_update+1);
}
$lj->GetDayCounts($hash_ref,$journal)
This routine is given a reference to hash which it fills with information on the journal entries posted to the LiveJournal we are currently associated with. On success the reference to the hash will be returned. On error undef
is returned.
There is an optional argument - $journal
- which can be used to gather this data for a shared journal the user has access to. If not required then this value should be undef
or an empty string.
The key to the hash is a date, given as seconds since epoch (i.e. time_t
) and the value is the number of entries made on that day. Only dates which have journal entries made against them will have values in the hash; thus it can be assumed that if a date is not in the hash then no journal entries were made on that day.
The hash will be emptied before use.
Example code:
use POSIX;
(defined $lj->GetDayCounts(\%gdc_hr,undef))
|| die "$0: Failed to get day counts - $LJ::Simple::error\n";
foreach (sort {$a<=>$b} keys %gdc_hr) {
printf("%s %03d\n",strftime("%Y/%m/%d",gmtime($_)),$gdc_hr{$_});
}
$lj->GetFriendGroups($hash_ref)
This routine is given a reference to a hash which it fills with information on the friends groups the user has defined. On success the reference to the hash will be returned. On error undef
is returned.
The hash key is the id number of the friends group as it is possible to have multiple friends groups with the same name. Each hash value is a hash reference which points to the following hash:
{
id => Id of the group; used to create permission masks
name => Name of the group
sort => Sort order number from 0 to 255
public => Public group ? 1 for yes, 0 for no
}
The hash given will be emptied before use.
Example code:
my %fg=();
(defined $lj->GetFriendGroups(\%fg)) ||
die "$0: Failed to get groups - $LJ::Simple::error\n";
my $format="| %-4s | %-2s | %-6s | %-40s |\n";
my $line=sprintf($format,"","","","");
$line=~s/\|/+/go;
$line=~s/ /-/go;
print $line;
printf($format,"Sort","Id","Public","Group");
print $line;
foreach (sort {$fg{$a}->{sort}<=>$gfg_hr{$b}->{sort}} keys %gfg_hr) {
my $hr=$fg{$_};
my $pub="No";
$hr->{public} && ($pub="Yes");
printf($format,$hr->{sort},$hr->{id},$pub,$hr->{name});
}
print $line;
In case you're wondering, the above code outputs something similar to the following:
+------+----+--------+------------------------------------------+
| Sort | Id | Public | Group |
+------+----+--------+------------------------------------------+
| 5 | 1 | Yes | Good Friends |
| 10 | 2 | No | Communities |
+------+----+--------+------------------------------------------+
$lj->NewEntry($event)
Prepares for a new journal entry to be sent into the LiveJournal system. Takes a reference to a hash which will be emptied and prepared for use by the other routines used to prepare a journal entry for posting.
On success returns 1
, on failure returns 0
Example code:
my %Entry=();
$lj->NewEntry(\%Entry)
|| die "$0: Failed to prepare new post - $LJ::Simple::error\n";
$lj->SetDate($event,$time_t)
Sets the date for the event being built from the given time_t
(i.e. seconds since epoch) value. Bare in mind that you may need to call $lj-<gt
Setprop_backdate(\%Event,1)> to backdate the journal entry if the journal being posted to has events more recent than the date being set here. Returns 1
on success, 0
on failure.
If the value given for time_t
is undef
then the current time is used. If the value given for time_t
is negative then it is taken to be relative to the current time, i.e. a value of -3600
is an hour earlier than the current time.
Note that localtime()
is called to convert the time_t
value into the year, month, day, hours and minute values required by LiveJournal. Thus the time given to LiveJournal will be the local time as shown on the machine the code is running on.
Example code:
## Set date to current time
$lj->SetDate(\%Event,undef)
|| die "$0: Failed to set date of entry - $LJ::Simple::error\n";
## Set date to Wed Aug 14 11:56:42 2002 GMT
$lj->SetDate(\%Event,1029326202)
|| die "$0: Failed to set date of entry - $LJ::Simple::error\n";
## Set date to an hour ago
$lj->SetDate(\%Event,-3600)
|| die "$0: Failed to set date of entry - $LJ::Simple::error\n";
$lj->SetMood($event,$mood)
Given a mood this routine sets the mood for the journal entry. Unlike the more direct $lj-<gt
Setprop_current_mood()> and $lj-<gt
Setprop_current_mood_id(\%Event,)> routines, this routine will attempt to first attempt to find the mood given to it in the mood list returned by the LiveJournal server. If it is unable to find a suitable mood then it uses the text given.
Note that if the LiveJournal object was created with either moods
set to 0
or with fast
set to 1
then this function will not attempt to find the mood name given in $mood
in the mood list.
Returns 1
on success, 0
otherwise.
Example code:
$lj->SetMood(\%Event,"happy")
|| die "$0: Failed to set mood - $LJ::Simple::error\n";
$lj->UseJournal($event,$journal)
The journal entry will be posted into the shared journal given as an argument rather than the default journal for the user.
Returns 1
on success, 0
otherwise.
Example code:
$lj->UseJournal(\%Event,"some_community")
|| die "$0: Failed to - $LJ::Simple::error\n";
$lj->SetSubject($event,$subject)
Sets the subject for the journal entry. The subject has the following limitations:
o Limited to a length of 255 characters
o No newlines are allowed
Returns 1
on success, 0
otherwise.
Example code:
$lj->SetSubject(\%Event,"Some subject")
|| die "$0: Failed to set subject - $LJ::Simple::error\n";
$lj->SetEntry($event,@entry)
Sets the entry for the journal; takes a list of strings. It should be noted that this list will be join()
ed together with a newline between each list entry.
If the list is null or undef
then any existing entry is removed.
Returns 1
on success, 0
otherwise.
Example code:
# Single line entry
$lj->SetEntry(\%Event,"Just a simple entry")
|| die "$0: Failed to set entry - $LJ::Simple::error\n";
# Three lines of text
my @stuff=(
"Line 1",
"Line 2",
"Line 3",
);
$lj->SetEntry(\%Event,@stuff)
|| die "$0: Failed to set entry - $LJ::Simple::error\n";
# Clear the entry
$lj->SetEntry(\%Event,undef)
|| die "$0: Failed to set entry - $LJ::Simple::error\n";
$lj->SetEntry(\%Event)
|| die "$0: Failed to set entry - $LJ::Simple::error\n";
$lj->AddToEntry($event,@entry)
Adds a string to the existing journal entry being worked on. The new data will be appended to the existing entry with a newline separating them. It should be noted that as with $lj-<gt
SetEntry()> the list given to this routine will be join()
ed together with a newline between each list entry.
If $lj-<gt
SetEntry()> has not been called then $lj-<gt
AddToEntry()> acts in the same way as $lj-<gt
SetEntry()>.
If $lj-<gt
SetEntry()> has already been called then calling $lj-<gt
AddToEntry()> with a null list or a list which starts with undef
is a NOP.
Returns 1
on success, 0
otherwise.
Example code:
# Single line entry
$lj->AddToEntry(\%Event,"Some more text")
|| die "$0: Failed to set entry - $LJ::Simple::error\n";
# Three lines of text
my @stuff=(
"Line 5",
"Line 6",
"Line 7",
);
$lj->AddToEntry(\%Event,@stuff)
|| die "$0: Failed to set entry - $LJ::Simple::error\n";
$lj->SetProtectFriends($event)
Sets the current post so that only friends can read the journal entry. Returns 1
on success, 0
otherwise.
Example code:
$lj->SetProtectFriends(\%Event)
|| die "$0: Failed to protect via friends - $LJ::Simple::error\n";
$lj->SetProtectGroups($event,$group1, $group2, ... $groupN)
Takes a list of group names and sets the current entry so that only those groups can read the journal entry. Returns 1
on success, 0
otherwise.
Example code:
$lj->SetProtectGroups(\%Event,"foo","bar")
|| die "$0: Failed to protect via group - $LJ::Simple::error\n";
$lj->SetProtectPrivate($event)
Sets the current post so that the owner of the journal only can read the journal entry. Returns 1
on success, 0
otherwise.
Example code:
$lj->SetProtectPrivate(\%Event)
|| die "$0: Failed to protect via private - $LJ::Simple::error\n";
$lj->Setprop_backdate($event,$onoff)
Used to indicate if the journal entry being written should be back dated or not. Back dated entries do not appear on the friends view of your journal entries. The $onoff
value takes either 1
for switching the property on or 0
for switching the property off. Returns 1
on success, 0
on failure.
You will need to set this value if the journal entry you are sending has a date earlier than other entries in your journal.
Example code:
$lj->Setprop_backdate(\%Event,1) ||
die "$0: Failed to set back date property - $LJ::Simple::error\n";
$lj->Setprop_current_mood($event,$mood)
Used to set the current mood for the journal being written. This takes a string which describes the mood.
It is better to use $lj-<gt
SetMood()> as that will automatically use a mood known to the LiveJournal server if it can.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_current_mood(\%Event,"Happy, but tired") ||
die "$0: Failed to set current_mood property - $LJ::Simple::error\n";
$lj->Setprop_current_mood_id($event,$id)
Used to set the current mood_id for the journal being written. This takes a number which refers to a mood_id the LiveJournal server knows about.
Note that if the LiveJournal object was created with either moods
set to 0
or with fast
set to 1
then this function will not attempt to validate the mood_id
given to it.
It is better to use $lj-<gt
SetMood()> as that will automatically use a mood known to the LiveJournal server if it can.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_current_mood_id(\%Event,15) ||
die "$0: Failed to set current_mood_id property - $LJ::Simple::error\n";
$lj->Setprop_current_music($event,$music)
Used to set the current music for the journal entry being written. This takes a string.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_current_music(\%Event,"Collected euphoric dance") ||
die "$0: Failed to set current_music property - $LJ::Simple::error\n";
$lj->Setprop_preformatted($event,$onoff)
Used to set if the text for the journal entry being written is preformatted in HTML or not. This takes a boolean value of 1
for true and 0
for false.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_preformatted(\%Event,1) ||
die "$0: Failed to set property - $LJ::Simple::error\n";
$lj->Setprop_nocomments($event,$onoff)
Used to set if the journal entry being written can be commented on or not. This takes a boolean value of 1
for true and 0
for false. Thus if you use a value of 1
(true) then comments will not be allowed.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_nocomments(\%Event,1) ||
die "$0: Failed to set property - $LJ::Simple::error\n";
$lj->Setprop_picture_keyword($event,$keyword)
Used to set the picture keyword for the journal entry being written. This takes a string. We check to make sure that the picture keyword exists.
Note that if the LiveJournal object was created with either pics
set to 0
or with fast
set to 1
then this function will not validate the picture keyword before setting it.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_picture_keyword(\%Event,"Some photo") ||
die "$0: Failed to set property - $LJ::Simple::error\n";
$lj->Setprop_noemail($event,$onoff)
Used to say that comments on the journal entry being written should not be emailed. This takes boolean value of 1
for true and 0
for false.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_noemail(\%Event,1) ||
die "$0: Failed to set property - $LJ::Simple::error\n";
$lj->Setprop_unknown8bit($event,$onoff)
Used say that there is 8-bit data which is not in UTF-8 in the journal entry being written. This takes a boolean value of 1
for true and 0
for false.
Returns 1
on success, 0
on failure.
Example code:
$lj->Setprop_unknown8bit(\%Event,1) ||
die "$0: Failed to set property - $LJ::Simple::error\n";
$lj->PostEntry($event)
Submit a journal entry into the LiveJournal system. This requires you to have set up the journal entry with $lj-<gt
NewEntry()> and to have at least called $lj-<gt
SetEntry()>.
On success a list containing the following is returned:
o The item_id as returned by the LiveJournal server
o The anum as returned by the LiveJournal server
o The item_id of the posted entry as used in HTML - that is the
value of C<($item_id * 256) + $anum)>
On failure undef
is returned.
# Build the new entry
my %Event;
$lj->NewEntry(\%Event) ||
die "$0: Failed to create new journal entry - $LJ::Simple::error\n";
# Set the journal entry
$lj->SetEntry(\%Event,"foo") ||
die "$0: Failed set journal entry - $LJ::Simple::error\n";
# And post it
my ($item_id,$anum,$html_id)=$lj->PostEntry(\%Event);
defined $item_id ||
die "$0: Failed to submit new journal entry - $LJ::Simple::error\n";
$lj->EditEntry($event)
Edit an entry from the LiveJournal system which has the givem item_id
. The entry should have been fetched from LiveJournal using the $lj-<gt
GetEntries()> function and then adjusted using the various $lj-<gt
Set...()> functions.
It should be noted that this function can be used to delete a journal entry by setting the entry to a blank string, i.e. by using $lj-<gt
SetEntry(\%Event,undef)>
Returns 1
on success, 0
on failure.
Example:
# Fetch the most recent event
my %Events = ();
(defined $lj->GetEntries(\%Events,undef,"one",-1)) ||
die "$0: Failed to get entries - $LJ::Simple::error\n";
# Mark it as private
foreach (values %Entries) {
$lj->SetProtectPrivate($_);
$lj->EditEntry($_) ||
die "$0: Failed to edit entry - $LJ::Simple::error\n";
}
# Alternatively we could just delete it...
my $event=(values %Entries)[0];
$lj->SetEntry($event,undef);
$lj->EditEntry($event) ||
die "$0: Failed to edit entry - $LJ::Simple::error\n";
$lj->DeleteEntry($item_id)
Delete an entry from the LiveJournal system which has the given item_id
. On success 1
is returned; on failure 0
is returned.
Example:
$lj->DeleteEntry($some_item_id) ||
die "$0: Failed to delete journal entry - $LJ::Simple::error\n";
$lj->SyncItems($timestamp)
This routine returns a list of all of the items (journal entries, to-do items, comments) which have been created or updated on LiveJournal. There is an optional timestamp value for specifying the time you last synchronised with the server. This timestamp value can either be a Unix-style time_t
value or a previously returned timestamp from this routine. If not used specify the undefined value undef
.
When specifying the time you must take into account the fact that the modification or creation times of the entries in the LiveJournal database are stored as the time local to the computer running the database rather than GMT. Due to this it is safest to use the time from the latest item downloaded from the LiveJournal from a previous SyncItems()
call.
On success this routine will return a list which contains first the number of valid items in the list and then a list of hashes which contain the details of the items found. This routine can return an empty list which signifies that no new items could be found. On failure undef
is returned.
The format of the returned list is as follows. The list of hashes is ordered by the timestamps of the entries, oldest to newest.
@list = (
number of items returned,
{
item_id => Item_id of the entry changed
type => Type of entry
action => What happened to the entry
time_t => Time of change in Unix time (see note below)
timestamp => Timestamp from server
},
);
The type
of entry can be one of the following letters:
L: Journal entries
C: Comments
T: To-do items
It should be noted that currently the LiveJournal system will only ever return "L
" types due to the C
and T
types not having been implemented in the LiveJournal code yet.
The action
of the entry can be either create
for a new entry, update
for an entry which has been modified or del
for a deleted entry.
The time_t
value is probably going to be wrong; as far as the author of this code can tell, you can not get the timezone of the server which is serving out the request. This means that converting the timestamps returned by the server from their format of YYYY-MM-DD hh:mm:ss
into a Unix time_t
value is inaccurate at best since time_t
is defined as the number of seconds since 00:00 1st January 1970 GMT. Functions like mktime()
which can be used to create time_t
values have to assume that the data they are being given is valid for the timezone the machine it is running on is actually in. Given the nature of the net this is rarely the case. sigh I wish that the LJ developers had stored timestamps in pure time_t
in the database... and if they have done they should provide a way for developers to get access to this as its much more useful IMHO.
Given the above you're probably wondering why I included the time_t
value. Well, whilst the value isn't much use when it really comes down to it, it is useful when it comes to sorting the list of entries as all of the entries from the same server will be inaccurate to the same amount.
The timestamp
from server takes the format of YYYY-MM-DD hh:mm:ss
It should be noted that this routine can take a long time to return if there are large numbers of entries to be returned. This is especially true if you give undef
as the timestamp.
Example code:
# All entries in the last day or so; this is fudged due to timezone
# differences (WTF didn't they store stuff in GMT ?)
my ($num_of_items,@lst)=$lj->SyncItems(time() - (86400 * 2));
(defined $num_of_items) ||
die "$0: Failed to sync - $LJ::Simple::error\n";
my $hr=undef;
print "Number of items: $num_of_items\n";
print "Item_id\tType\tAction\tTime_t\t\tTimestamp\n";
foreach $hr (@lst) {
print "$hr->{item_id}\t" .
"$hr->{type}\t" .
"$hr->{action}\t" .
"$hr->{time_t}\t" .
"$hr->{timestamp}\n";
}
$lj->GetEntries($hash_ref,$journal,$type,@opt)
This routine allows you to pull events from the user's LiveJournal. There are several different ways for this routine to work depending on the value given in the $type
argument.
The first argument - $hash_ref
is a reference to a hash which will be filled with the details of the journal entries downloaded. The key to this hash is the item_id
of the journal entries. The value is a hash reference which points to a hash of the same type created by NewPost()
and used by PostEntry()
and EditEntry()
. The most sensible way to access this hash is to use the various Get*()
routines.
The second argument - $journal
- is an optional argument set if the journal to be accessed is a shared journal. If not required set this to undef
.
The third argument - $type
- specifies how the journal entries are to be pulled down. The contents of the fourth argument - @opt
- will depend on the value in the $type
variable. Thus:
+-------+------------+------------------------------------------+
| $type | @opt | Comments |
+-------+------------+------------------------------------------+
| day | $timestamp | Download a single day. $timestamp is a |
| | | Unix timestamp for the required day |
+-------+------------+------------------------------------------+
| lastn |$num,$before| Download a number of entries. $num has a |
| | | maximum value of 50. If $num is undef |
| | | then the default of 20 is used. $before |
| | | is an optional value which specifies a |
| | | date before which all entries must occur.|
| | | The date is specified as a Unix |
| | | timestamp. If not specified the value |
| | | should be undef. |
+-------+------------+------------------------------------------+
| one | $item_id | The unique ItemID for the entry to be |
| | | downloaded. A value of -1 means to |
| | | download the most recent entry |
+-------+------------+------------------------------------------+
| sync | $date | Get journal entries since the given date.|
| | | The date should be specified as a Unix |
| | | timestamp. |
+-------+------------+------------------------------------------+
Example code:
The following code only uses a single $type
from the above list; "one
". However the hash of hashes returned is the same in every $type
used. The code below shows how to pull down the last journal entry posted and then uses all of the various Get*()
routines to decode the hash returned.
use POSIX;
my %Entries=();
(defined $lj->GetEntries(\%Entries,undef,"one",-1)) ||
die "$0: Failed to get entries - $LJ::Simple::error\n";
my $Entry=undef;
my $Format="%-20s: %s\n";
foreach $Entry (values %Entries) {
# Get URL
my $url=$lj->GetURL($Entry);
(defined $url) && print "$url\n";
# Get ItemId
my ($item_id,$anum,$html_id)=$lj->GetItemId($Entry);
(defined $item_id) && printf($Format,"Item_id",$item_id);
# Get the subject
my $subj=$lj->GetSubject($Entry);
(defined $subj) && printf($Format,"Subject",$subj);
# Get the date entry was posted
my $timet=$lj->GetDate($Entry);
if (defined $timet) {
printf($Format,"Date",
strftime("%Y-%m-%d %H:%M:%S",gmtime($timet)));
}
# Is entry protected ?
my $EntProt="";
my ($protect,@prot_opt)=$lj->GetProtect($Entry);
if (defined $protect) {
if ($protect eq "public") {
$EntProt="public";
} elsif ($protect eq "friends") {
$EntProt="friends only";
} elsif ($protect eq "groups") {
$EntProt=join("","only groups - ",join(", ",@prot_opt));
} elsif ($protect eq "private") {
$EntProt="private";
}
printf($Format,"Journal access",$EntProt);
}
## Properties
# Backdated ?
my $word="no";
my $prop=$lj->Getprop_backdate($Entry);
if ((defined $prop) && ($prop==1)) { $word="yes" }
printf($Format,"Backdated",$word);
# Preformatted ?
$word="no";
$prop=$lj->Getprop_preformatted($Entry);
if ((defined $prop) && ($prop==1)) { $word="yes" }
printf($Format,"Preformatted",$word);
# No comments allowed ?
$word="no";
$prop=$lj->Getprop_nocomments($Entry);
if ((defined $prop) && ($prop==1)) { $word="yes" }
printf($Format,"No comments",$word);
# Do not email comments ?
$word="no";
$prop=$lj->Getprop_noemail($Entry);
if ((defined $prop) && ($prop==1)) { $word="yes" }
printf($Format,"No emailed comments",$word);
# Unknown 8-bit ?
$word="no";
$prop=$lj->Getprop_unknown8bit($Entry);
if ((defined $prop) && ($prop==1)) { $word="yes" }
printf($Format,"Any 8 bit, non UTF-8",$word);
# Current music
$word="[None]";
$prop=$lj->Getprop_current_music($Entry);
if ((defined $prop) && ($prop ne "")) { $word=$prop }
printf($Format,"Current music",$word);
# Current mood [text]
$word="[None]";
$prop=$lj->Getprop_current_mood($Entry);
if ((defined $prop) && ($prop ne "")) { $word=$prop }
printf($Format,"Current mood",$word);
# Current mood [id]
$word="[None]";
$prop=$lj->Getprop_current_mood_id($Entry);
if ((defined $prop) && ($prop ne "")) { $word=$prop }
printf($Format,"Current mood_id",$word);
# Picture keyword
$word="[None]";
$prop=$lj->Getprop_picture_keyword($Entry);
if ((defined $prop) && ($prop ne "")) { $word=$prop }
printf($Format,"Picture keyword",$word);
# Finally output the actual journal entry
printf($Format,"Journal entry","");
my $text=$lj->GetEntry($Entry);
(defined $text) &&
print " ",join("\n ",split(/\n/,$text)),"\n\n";
}
$lj->GetDate($event)
Gets the date for the event given. The date is returned as a time_t
(i.e. seconds since epoch) value. Returns undef
on failure.
Example code:
use POSIX; # For strftime()
## Get date
my $timet=$lj->GetDate(\%Event);
(defined $timet)
|| die "$0: Failed to set date of entry - $LJ::Simple::error\n";
# Get time list using gmtime()
my @tm=gmtime($timet);
($#tm<0) &&
die "$0: Failed to run gmtime() on time_t $timet\n";
# Format date in the normal way used by LJ "YYYY-MM-DD hh:mm:ss"
my $jtime=strftime("%Y-%m-%d %H:%M:%S",@tm);
$lj->GetItemId($event)
Returns a list which contains the real item_id
, anum
and HTMLised item_id
which can be used to contruct a URL suitable for accessing the item via the web. Returns undef
on failure. Note that you must only use this routine on entries which have been returned by the GetEntries()
routine.
Example code:
my ($item_id,$anum,$html_id)=$lj->GetItemId(\%Event);
(defined $item_id)
|| die "$0: Failed to get item id - $LJ::Simple::error\n";
$lj->GetURL($event)
Returns the URL which can be used to access the journal entry via a web browser. Returns undef
on failure. Note that you must only use this routine on entries which have been returned by the GetEntries()
routine.
Example code:
my $url=$lj->GetURL(\%Event);
(defined $url)
|| die "$0: Failed to get URL - $LJ::Simple::error\n";
system("netscape -remote 'openURL($url)'");
$lj->GetSubject($event)
Gets the subject for the journal entry. Returns the subject if it is available, undef
otherwise.
Example code:
my $subj=$lj->GetSubject(\%Event)
if (defined $subj) {
print "Subject: $subj\n";
}
$lj->GetEntry($event)
Gets the entry for the journal. Returns either a single string which contains the entire journal entry or undef
on failure.
Example code:
my $ent = $lj->GetEntry(\%Event);
(defined $ent)
|| die "$0: Failed to get entry - $LJ::Simple::error\n";
print "Entry: $ent\n";
$lj->GetProtect($event)
Gets the protection information on the event given. Returns a list with details of the protection set on the post. On failure undef
is returned.
There are several different types of protection which can be returned for a journal entry. These include public, friends only, specific friends groups and private. The list returned will always have the type of protection listed first followed by any details of that protection. Thus the list can contain:
("public")
A publically accessable journal entry
("friends")
Only friends may read the entry
("groups","group1" ...)
Only users listed in the friends groups given after the "groups"
may read the entry
("private")
Only the owner of the journal may read the entry
Example code:
my ($protect,@prot_opt)=$lj->GetProtect(\%Event);
(defined $protect) ||
die "$0: Failed to get entry protection type - $LJ::Simple::error\n";
if ($protect eq "public") {
print "Journal entry is public\n";
} elsif ($protect eq "friends") {
print "Journal entry only viewable by friends\n";
} elsif ($protect eq "groups") {
print "Journal entry only viewable by friends in the following groups:\n";
print join(", ",@prot_opt),"\n";
} elsif ($protect eq "private") {
print "Journal entry only viewable by the journal owner\n";
}
$lj->Getprop_backdate($event)
Indicates if the journal entry is back dated or not. Back dated entries do not appear on the friends view of your journal entries. Returns 1
if the entry is backdated, 0
if it is not. undef
is returned in the event of an error.
Example code:
my $prop=$lj->Getprop_backdate(\%Event);
(defined $prop) ||
die "$0: Failed to get property - $LJ::Simple::error\n";
if ($prop) {
print STDERR "Journal is backdated\n";
} else {
print STDERR "Journal is not backdated\n";
}
$lj->Getprop_current_mood($event)
Used to get the current mood for the journal being written. This returns the mood if one exists, an empty string if none exists or undef
in the event of an error.
Example code:
my $prop=$lj->Getprop_current_mood(\%Event);
(defined $prop) ||
die "$0: Failed to get property - $LJ::Simple::error\n";
if ($prop ne "") {
print STDERR "Journal has mood of $prop\n";
} else {
print STDERR "Journal has no mood set\n";
}
$lj->Getprop_current_mood_id($event)
Used to get the current mood_id for the journal being written. Will return the mood_id if one is set, a null string is one is not set and undef
in the event of an error.
Example code:
my $prop=$lj->Getprop_current_mood_id(\%Event);
(defined $prop) ||
die "$0: Failed to get property - $LJ::Simple::error\n";
if ($prop ne "") {
print STDERR "Journal has mood_id of $prop\n";
} else {
print STDERR "Journal has no mood_id set\n";
}
$lj->Getprop_current_music($event)
Used to get the current music for the journal entry being written. Returns the music if one is set, a null string is one is not set and undef
in the event of an error.
Example code:
my $prop=$lj->Getprop_current_music(\%Event);
(defined $prop) ||
die "$0: Failed to get property - $LJ::Simple::error\n";
if ($prop) {
print STDERR "Journal has the following music: $prop\n";
} else {
print STDERR "Journal has no music set for it\n";
}
$lj->Getprop_preformatted($event)
Used to see if the text for the journal entry being written is preformatted in HTML or not. This returns true (1
) if so, false (0
) if not.
Example code:
$lj->Getprop_preformatted(\%Event) &&
print "Journal entry is preformatted\n";
$lj->Getprop_nocomments($event)
Used to see if the journal entry being written can be commented on or not. This returns true (1
) if so, false (0
) if not.
Example code:
$lj->Getprop_nocomments(\%Event) &&
print "Journal entry set to disallow comments\n";
$lj->Getprop_picture_keyword($event)
Used to get the picture keyword for the journal entry being written. Returns the picture keyword if one is set, a null string is one is not set and undef
in the event of an error.
Example code:
my $prop=$lj->Getprop_picture_keyword(\%Event);
(defined $prop) ||
die "$0: Failed to get property - $LJ::Simple::error\n";
if ($prop) {
print STDERR "Journal has picture keyword $prop set\n";
} else {
print STDERR "Journal has no picture keyword set\n";
}
$lj->Getprop_noemail($event)
Used to see if comments on the journal entry being written should be emailed or not. This returns true (1
) if so comments should not be emailed and false (0
) if they should be emailed.
Example code:
$lj->Getprop_noemail(\%Event) &&
print "Comments to journal entry not emailed\n";
$lj->Getprop_unknown8bit($event)
Used see if there is 8-bit data which is not in UTF-8 in the journal entry being written. This returns true (1
) if so, false (0
) if not.
Example code:
$lj->Getprop_unknown8bit(\%Event) &&
print "Journal entry contains 8-bit data not in UTF-8 format\n";
EXAMPLE
The following simple example logs into the LiveJournal server and posts a simple comment.
use LJ::Simple;
# Log into the server
my $lj = new LJ::Simple ({
user => "test",
pass => "test",
site => undef,
proxy => undef,
});
(defined $lj)
|| die "$0: Failed to log into LiveJournal: $LJ::Simple::error\n";
# Prepare the event
my %Event=();
$lj->NewEntry(\%Event) ||
die "$0: Failed to create new entry: $LJ::Simple::error\n";
# Put in the entry
my $entry=<<EOF;
A simple entry made using <tt>LJ::Simple</tt> version $LJ::Simple::VERSION
EOF
$lj->SetEntry(\%Event,$entry)
|| die "$0: Failed to set entry: $LJ::Simple::error\n";
# Say we are happy
$lj->SetMood(\%Event,"happy")
|| die "$0: Failed to set mood: $LJ::Simple::error\n";
# Don't allow comments
# Note that to allow comments you can just remove this call to
# Setprop_nocomments() completely - the default is to allow comments.
$lj->Setprop_nocomments(\%Event,1);
my ($item_id,$anum,$html_id)=$lj->PostEntry(\%Event);
(defined $item_id)
|| die "$0: Failed to post journal entry: $LJ::Simple::error\n";
AUTHOR
Simon Burr <simes@bpfh.net>
SEE ALSO
perl
LICENSE
Copyright (c) 2002, Simon Burr <simes@bpfh.net> All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 258:
You can't have =items (as at line 266) unless the first thing after the =over is an =item