Index: perl/modules/Facebook/lib/Facebook/Graph.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,583 @@
+package Facebook::Graph;
+BEGIN {
+  $Facebook::Graph::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use MIME::Base64::URLSafe;
+use JSON;
+use Facebook::Graph::AccessToken;
+use Facebook::Graph::Authorize;
+use Facebook::Graph::Query;
+use Facebook::Graph::Picture;
+use Facebook::Graph::Publish::Post;
+use Facebook::Graph::Publish::Checkin;
+use Facebook::Graph::Publish::Like;
+use Facebook::Graph::Publish::Comment;
+use Facebook::Graph::Publish::Note;
+use Facebook::Graph::Publish::Link;
+use Facebook::Graph::Publish::Event;
+use Facebook::Graph::Publish::RSVPMaybe;
+use Facebook::Graph::Publish::RSVPAttending;
+use Facebook::Graph::Publish::RSVPDeclined;
+use Ouch;
+
+has app_id => (
+    is      => 'ro',
+);
+
+has secret => (
+    is          => 'ro',
+    predicate   => 'has_secret',
+);
+
+has postback => (
+    is      => 'ro',
+);
+
+has access_token => (
+    is          => 'rw',
+    predicate   => 'has_access_token',
+);
+
+
+sub parse_signed_request {
+    my ($self, $signed_request) = @_;
+    require Digest::SHA;
+    my ($encoded_sig, $payload) = split(/\./, $signed_request);
+
+	my $sig = urlsafe_b64decode($encoded_sig);
+    my $data = JSON->new->decode(urlsafe_b64decode($payload));
+
+    if (uc($data->{'algorithm'}) ne "HMAC-SHA256") {
+        ouch '500', 'Unknown algorithm. Expected HMAC-SHA256';
+    }
+
+    my $expected_sig = Digest::SHA::hmac_sha256($payload, $self->secret);
+    if ($sig ne $expected_sig) {
+        ouch '500', 'Bad Signed JSON signature!';
+    }
+    return $data;
+}
+
+sub request_access_token {
+    my ($self, $code) = @_;
+    my $token = Facebook::Graph::AccessToken->new(
+        code            => $code,
+        postback        => $self->postback,
+        secret          => $self->secret,
+        app_id          => $self->app_id,
+    )->request;
+    $self->access_token($token->token);
+    return $token;
+}
+
+sub convert_sessions {
+    my ($self, $sessions) = @_;
+    return Facebook::Graph::Session->new(
+        secret          => $self->secret,
+        app_id          => $self->app_id,
+        sessions        => $sessions,
+        )
+        ->request
+        ->as_hashref;
+}
+
+sub authorize { 
+    my ($self) = @_;
+    return Facebook::Graph::Authorize->new(
+        app_id          => $self->app_id,
+        postback        => $self->postback,
+    );
+}
+
+sub fetch {
+    my ($self, $object_name) = @_;
+    return $self->query->find($object_name)->request->as_hashref;
+}
+
+sub query {
+    my ($self) = @_;
+    my %params;
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Query->new(%params);
+}
+
+sub picture {
+    my ($self, $object_name) = @_;
+    return Facebook::Graph::Picture->new( object_name => $object_name );
+}
+
+sub add_post {
+    my ($self, $object_name) = @_;
+    my %params;
+    if ($object_name) {
+        $params{object_name} = $object_name;
+    }
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Post->new( %params );
+}
+
+sub add_checkin {
+    my ($self, $object_name) = @_;
+    my %params;
+    if ($object_name) {
+        $params{object_name} = $object_name;
+    }
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Checkin->new( %params );
+}
+
+sub add_like {
+    my ($self, $object_name) = @_;
+    my %params = (
+        object_name => $object_name,
+    );
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Like->new( %params );
+}
+
+sub add_comment {
+    my ($self, $object_name) = @_;
+    my %params = (
+        object_name => $object_name,
+    );
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Comment->new( %params );
+}
+
+sub add_note {
+    my ($self) = @_;
+    my %params;
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Note->new( %params );
+}
+
+sub add_link {
+    my ($self) = @_;
+    my %params;
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Link->new( %params );
+}
+
+sub add_event {
+    my ($self, $object_name) = @_;
+    my %params;
+    if ($object_name) {
+        $params{object_name} = $object_name;
+    }
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::Event->new( %params );
+}
+
+sub rsvp_maybe {
+    my ($self, $object_name) = @_;
+    my %params = (
+        object_name => $object_name,
+    );
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::RSVPMaybe->new( %params );
+}
+
+sub rsvp_attending {
+    my ($self, $object_name) = @_;
+    my %params = (
+        object_name => $object_name,
+    );
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::RSVPAttending->new( %params );
+}
+
+sub rsvp_declined {
+    my ($self, $object_name) = @_;
+    my %params = (
+        object_name => $object_name,
+    );
+    if ($self->has_access_token) {
+        $params{access_token} = $self->access_token;
+    }
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Publish::RSVPDeclined->new( %params );
+}
+
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+=head1 NAME
+
+Facebook::Graph - A fast and easy way to integrate your apps with Facebook.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+ my $sarah_bownds = $fb->fetch('sarahbownds');
+ my $perl_page = $fb->fetch('16665510298');
+ 
+Or better yet:
+
+ my $sarah_bownds = $fb->query
+    ->find('sarahbownds')
+    ->include_metadata
+    ->select_fields(qw( id name picture ))
+    ->request
+    ->as_hashref;
+    
+ my $sarahs_picture_uri = $fb->picture('sarahbownds')->get_large->uri_as_string;
+
+Or fetching a response from a URI you already have:
+
+ my $response = $fb->query
+    ->request('https://graph.facebook.com/btaylor')
+    ->as_hashref;
+ 
+ 
+=head2 Building A Privileged App
+
+ my $fb = Facebook::Graph->new(
+    app_id          => $facebook_application_id,
+    secret          => $facebook_application_secret,
+    postback        => 'https://www.yourapplication.com/facebook/oauth/postback',
+ );
+
+Get the user to authorize your app (only needed if you want to fetch non-public information or publish stuff):
+
+ my $uri = $fb
+    ->authorize
+    ->extend_permissions(qw(offline_access publish_stream))
+    ->uri_as_string;
+
+ # redirect the user's browser to $uri
+
+Handle the Facebook authorization code postback:
+
+ my $q = Plack::Request->new($env);
+ $fb->request_access_token($q->query_param('code'));
+ 
+Or if you already had the access token:
+
+ $fb->access_token($token);
+ 
+Get some info:
+
+ my $user = $fb->fetch('me');
+ my $friends = $fb->fetch('me/friends');
+ my $sarah_bownds = $fb->fetch('sarahbownds');
+
+=head1 DESCRIPTION
+
+This is a Perl interface to the Facebook Graph API L<http://developers.facebook.com/docs/api>. With this module you can currently query public Facebook data, query privileged Facebook data, and build a privileged Facebook application. See the TODO for all that this module cannot yet do.
+
+For example code, see L<Facebook::Graph::Cookbook>.
+
+B<WARNING:> The work on this module has only just begun because the Graph API itself isn't very new, and I'm only working on it as I have some tuits. Therefore things are potentially subject to change drastically with each release.
+
+
+=head1 METHODS
+
+=head2 new ( [ params ] )
+
+The constructor.
+
+=head3 params
+
+A hash of base parameters, just so you don't have to pass them around. If you only want to do public queries then these params are not needed.
+
+=over
+
+=item access_token
+
+An access token string used to make Facebook requests as a privileged user. Required if you want to make privileged queries or perform privileged actions on Facebook objects.
+
+=item app_id
+
+The application id that you get from Facebook after registering (L<http://developers.facebook.com/setup/>) your application on their site. Required if you'll be calling the C<request_access_token>, C<convert_sessions>, or C<authorize> methods.
+
+=item secret
+
+The application secret that you get from Facebook after registering your application. Required if you'll be calling the C<request_access_token> or C<convert_sessions> methods.
+
+=item postback
+
+The URI that Facebook should post your authorization code back to. Required if you'll be calling the C<request_access_token> or C<authorize> methods.
+
+B<NOTE:> It must be a sub URI of the URI that you put in the Application Settings > Connect > Connect URL field of your application's profile on Facebook.
+
+=back
+
+
+=head2 authorize ( )
+
+Creates a L<Facebook::Graph::Authorize> object, which can be used to get permissions from a user for your application.
+
+
+=head2 request_access_token ( code )
+
+Creates a L<Facebook::Graph::AccessToken> object and fetches an access token from Facebook, which will allow everything you do with Facebook::Graph to work within user privileges rather than through the public interface. Returns a L<Facebook::Graph::AccessToken::Response> object, and also sets the C<access_token> property in the Facebook::Graph object.
+
+=head3 code
+
+An authorization code string that you should have gotten by going through the C<authorize> process.
+
+
+=head2 query ( )
+
+Creates a L<Facebook::Graph::Query> object, which can be used to fetch and search data from Facebook.
+
+
+=head2 fetch ( id )
+
+Returns a hash reference of an object from facebook. A quick way to grab an object from Facebook. These two statements are identical:
+
+ my $sarah = $fb->fetch('sarahbownds');
+ 
+ my $sarah = $fb->query->find('sarahbownds')->request->as_hashref;
+
+=head3 id
+
+An profile id like C<sarahbownds> or an object id like C<16665510298> for the Perl page.
+
+
+=head2 picture ( id )
+
+Returns a L<Facebook::Graph::Picture> object, which can be used to generate the URLs of the pictures of any object on Facebook.
+
+=head3 id
+
+An profile id like C<sarahbownds> or an object id like C<16665510298> for the Perl page.
+
+
+
+=head2 add_post ( [ id ] )
+
+Creates a L<Facebook::Graph::Publish::Post> object, which can be used to publish data to a user's feed/wall.
+
+=head3 id
+
+Optionally provide an object id to place it on. Requires that you have administrative access to that page/object.
+
+
+=head2 add_checkin ( [ id ] )
+
+Creates a L<Facebook::Graph::Publish::Checkin> object, which can be used to publish a checkin to a location.
+
+=head3 id
+
+Optionally provide an user id to check in. Requires that you have administrative access to that user.
+
+
+=head2 add_like ( id )
+
+Creates a L<Facebook::Graph::Publish::Like> object to tell everyone about a post you like.
+
+=head3 id
+
+The id of a post you like.
+
+
+=head2 add_comment ( id )
+
+Creates a L<Facebook::Graph::Publish::Comment> object that you can use to comment on a note.
+
+=head3 id
+
+The id of the post you want to comment on.
+
+
+=head2 add_note ( )
+
+Creates a L<Facebook::Graph::Publish::Note> object, which can be used to publish notes.
+
+
+=head2 add_link ( )
+
+Creates a L<Facebook::Graph::Publish::Link> object, which can be used to publish links.
+
+
+=head2 add_event ( [id] )
+
+Creates a L<Facebook::Graph::Publish::Event> object, which can be used to publish events.
+
+=head3 id
+
+Optionally provide an object id to place it on. Requires that you have administrative access to that page/object.
+
+
+
+=head2 rsvp_maybe ( id )
+
+RSVP as 'maybe' to an event.
+
+=head3 id
+
+The id of an event.
+
+=head2 rsvp_attending ( id )
+
+RSVP as 'attending' to an event.
+
+=head3 id
+
+The id of an event.
+
+=head2 rsvp_declined ( id )
+
+RSVP as 'declined' to an event.
+
+=head3 id
+
+The id of an event.
+
+
+
+=head2 convert_sessions ( sessions )
+
+A utility method to convert old sessions into access tokens that can be used with the Graph API. Returns an array reference of hash references of access tokens.
+
+ [
+   {
+     "access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+     "expires": 1271649600,
+   },
+   ...
+ ]
+
+See also L<Facebook::Graph::Session>.
+
+=head3 sessions
+
+An array reference of session ids from the old Facebook API.
+
+
+=head2 parse_signed_request ( signed_request )
+
+Allows the decoding of signed requests for canvas applications to ensure data passed back from Facebook isn't tampered with. You can read more about this at L<http://developers.facebook.com/docs/authentication/canvas>.
+
+=head3 signed_request
+
+A signature string passed from Facebook. To capture a signed request your app must be displayed within the Facebook canvas page and then you must pull the query parameter called C<signed_request> from the query string.
+
+B<NOTE:> To get this passed to your app you must enable it in your migration settings for your app (L<http://www.facebook.com/developers/>).
+
+=head1 EXCEPTIONS
+
+This module throws exceptions when it encounters a problem. It uses L<Ouch> to throw the exception, and the Exception typically takes 3 parts: code, message, and a data portion that is the URI that was originally requested. For example:
+
+ eval { $fb->call_some_method };
+ if (kiss 500) {
+   say "error: ". $@->message;
+   say "uri: ".$@->data;
+ }
+ else {
+   throw $@; # rethrow the error
+ }
+
+
+=head1 TODO
+
+I still need to add publishing albums/photos, deleting of content, impersonation, and analytics to have a feature complete API. In addition, the module could use a lot more tests.
+
+
+=head1 PREREQS
+
+L<Any::Moose>
+L<JSON>
+L<LWP>
+L<LWP::Protocol::https>
+L<Mozilla::CA>
+L<URI>
+L<DateTime>
+L<DateTime::Format::Strptime>
+L<MIME::Base64::URLSafe>
+L<URI::Encode>
+L<Ouch>
+
+=head2 Optional
+
+L<Digest::SHA> is used for signed requests. If you don't plan on using the signed request feature, then you do not need to install Digest::SHA.
+
+=head1 SUPPORT
+
+=over
+
+=item Repository
+
+L<http://github.com/rizen/Facebook-Graph>
+
+=item Bug Reports
+
+L<http://github.com/rizen/Facebook-Graph/issues>
+
+=back
+
+
+=head1 SEE ALSO
+
+If you're looking for a fully featured Facebook client in Perl I highly recommend L<WWW::Facebook::API>. It does just about everything, it just uses the old Facebook API.
+
+=head1 AUTHOR
+
+JT Smith <jt_at_plainblack_dot_com>
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/AccessToken.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/AccessToken.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/AccessToken.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,93 @@
+package Facebook::Graph::AccessToken;
+BEGIN {
+  $Facebook::Graph::AccessToken::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use Facebook::Graph::AccessToken::Response;
+with 'Facebook::Graph::Role::Uri';
+use LWP::UserAgent;
+
+has app_id => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has secret => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has postback => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has code => (
+    is      => 'ro',
+    required=> 1,
+);
+
+sub uri_as_string {
+    my ($self) = @_;
+    my $uri = $self->uri;
+    $uri->path('oauth/access_token');
+    $uri->query_form(
+        client_id       => $self->app_id,
+        client_secret   => $self->secret,
+        redirect_uri    => $self->postback,
+        code            => $self->code,
+    );
+    return $uri->as_string;
+}
+
+sub request {
+    my ($self) = @_;
+    my $response = LWP::UserAgent->new->get($self->uri_as_string);
+    return Facebook::Graph::AccessToken::Response->new(response => $response);
+}
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::AccessToken - Acquire an access token from Facebook.
+
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new(
+    secret      => $facebook_application_secret,
+    app_id      => $facebook_application_id,
+    postback    => 'https://www.yourapplication.com/facebook/postback',
+ );
+ my $token_response_object = $fb->request_access_token($code_from_authorize_postback);
+
+ my $token_string = $token_response_object->token;
+ my $token_expires_epoch = $token_response_object->expires;
+
+=head1 DESCRIPTION
+
+Allows you to request an access token from Facebook so you can make privileged requests on the Graph API.
+
+=head1 METHODS
+
+=head2 uri_as_string ()
+
+Returns the URI that will be called to fetch the token as a string. Mostly useful for debugging and testing.
+
+=head2 request ()
+
+Makes a request to Facebook to fetch an access token. Returns a L<Facebook::Graph::AccessToken::Response> object.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/AccessToken/Response.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/AccessToken/Response.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/AccessToken/Response.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,79 @@
+package Facebook::Graph::AccessToken::Response;
+BEGIN {
+  $Facebook::Graph::AccessToken::Response::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use URI;
+use URI::QueryParam;
+use Ouch;
+
+has response => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has token => (
+    is      => 'ro',
+    lazy    => 1,
+    default => sub {
+        my $self = shift;
+        my $response = $self->response;
+        if ($response->is_success) {
+            return URI->new('?'.$response->content)->query_param('access_token');
+        }
+        else {
+            ouch $response->code, 'Could not fetch access token: '.$response->message, $response->request->uri->as_string;
+        }
+    }
+);
+
+has expires => (
+    is      => 'ro',
+    lazy    => 1,
+    default => sub {
+        my $self = shift;
+        my $response = $self->response;
+        if ($response->is_success) {
+            return URI->new('?'.$response->content)->query_param('expires');
+        }
+        else {
+            ouch $response->code, 'Could not fetch access token: '.$response->message, $response->request->uri->as_string;
+        }
+    }
+);
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+=head1 NAME
+
+Facebook::Graph::AccessToken::Response - The Facebook access token request response.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 Description
+
+You'll be given one of these as a result of calling the C<request> method from a L<Facebook::Graph::AccessToken> object.
+
+=head1 METHODS
+
+=head2 token ()
+
+Returns the token string.
+
+=head2 expires ()
+
+Returns the time alotted to this token. If undefined then the token is forever.
+
+=head2 response ()
+
+Direct access to the L<HTTP::Response> object.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Authorize.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Authorize.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Authorize.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,119 @@
+package Facebook::Graph::Authorize;
+BEGIN {
+  $Facebook::Graph::Authorize::VERSION = '1.0300';
+}
+
+use Any::Moose;
+with 'Facebook::Graph::Role::Uri';
+
+has app_id => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has postback => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has permissions => (
+    is          => 'rw',
+    lazy        => 1,
+    predicate   => 'has_permissions',
+    default     => sub { [] },
+);
+
+has display => (
+    is      => 'rw',
+    default => 'page',
+);
+
+sub extend_permissions {
+    my ($self, @permissions) = @_;
+    push @{$self->permissions}, @permissions;
+    return $self;
+}
+
+sub set_display {
+    my ($self, $display) = @_;
+    $self->display($display);
+    return $self;
+}
+
+sub uri_as_string {
+    my ($self) = @_;
+    my $uri = $self->uri;
+    $uri->path('oauth/authorize');
+    my %query = (
+        client_id       => $self->app_id,
+        redirect_uri    => $self->postback,
+        display         => $self->display,
+    );
+    if ($self->has_permissions) {
+        $query{scope} = join(',', @{$self->permissions});
+    }
+    $uri->query_form(%query);
+    return $uri->as_string;
+}
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Authorize - Authorizing an app with Facebook
+
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new(
+    secret      => $facebook_application_secret,
+    app_id      => $facebook_application_id,
+    postback    => 'https://www.yourapplication.com/facebook/postback',
+ );
+
+ my $uri = $fb->authorize
+    ->extend_permissions(qw( email publish_stream ))
+    ->set_display('popup')
+    ->uri_as_string;
+
+=head1 DESCRIPTION
+
+Get an authorization code from Facebook so that you can request an access token to make privileged requests. The result of this package is to give you a URI to redirect a user to Facebook so they can log in, and approve whatever permissions you are requesting.
+
+=head1 METHODS
+
+=head2 extend_permissions ( permissions )
+
+Ask for extra permissions for your app. By default, if you do not request extended permissions your app will have access to only general information that any Facebook user would have. Returns a reference to self for method chaining.
+
+=head3 permissions
+
+An array of permissions. See L<http://developers.facebook.com/docs/authentication/permissions> for more information about what's available.
+
+
+=head2 set_display ( type )
+
+Sets the display type for the authorization screen that a user will see.
+
+=head3 type
+
+Defaults to C<page>. Valid types are C<page>, C<popup>, C<wap>, and C<touch>. See B<Dialog Form Factors> in L<http://developers.facebook.com/docs/authentication/> for details.
+
+
+=head2 uri_as_string ( )
+
+Returns a URI string to redirect the user back to Facebook.
+
+
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Cookbook.pod
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Cookbook.pod	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Cookbook.pod	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,32 @@
+=head1 NAME
+
+Facebook::Graph::Cookbook - A cookbook for Facebook::Graph
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 DESCRIPTION
+
+The goal of this document is to provide a set of common recipies for success. The L<Facebook::Graph> API is relatively easy to use, but there are just enough tricks to it that it can throw you off if you don't have a little insider information. Hopefully this document will help you overcome those hurdles.
+
+=head1 RECIPIES
+
+=over
+
+=item L<Facebook::Graph::Cookbook::Recipe1>
+
+Shows you how to set up a privileged application using nothing more than L<Plack>. This is very much a step by step tutorial.
+
+=item L<Facebook::Graph::Cookbook::Recipe2>
+
+A fully functional Facebook::Graph app that publishes data to Facebook and reads data from it. Uses a full application server and lots of other modules. This is a working example, without a lot of explaination.
+
+=back
+
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Cookbook/Recipe1.pod
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Cookbook/Recipe1.pod	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Cookbook/Recipe1.pod	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,208 @@
+=head1 NAME
+
+Facebook::Graph::Cookbook::Recipe1 - Building Privileged Applications
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 DESCRIPTION
+
+Let's build a privileged Facebook application from nothing.
+
+=head2 Things To Think About
+
+Though templating systems such as L<Template::Toolkit> and web frameworks such as L<Dancer> and content management systems such as WebGUI L<http://www.webgui.org/> are out of scope for this document, when you build your own application, you should definitely consider using them.
+
+For simplicity sake, in this recipe we'll be storing important information directly in the code. This is a terrible practice. Instead use a config file system like L<Config::JSON> to store your settings.
+
+=head2 Assumptions
+
+This recipe assumes that you know and have L<Plack> installed and that you have a Facebook (L<http://www.facebook.com>) account.
+
+You'll also have to be able to point a domain name to a server that is accessible from the Internet. DNS and server configuration are way beyond the scope of this document.
+
+=head1 RECIPE
+
+=head2 Step 1: Set up the developer application on Facebook.
+
+Go to L<http://apps.facebook.com/developer>.
+
+Click "Allow".
+
+=head2 Step 2: Create your application.
+
+Go to L<http://www.facebook.com/developers/createapp.php> or click "Set Up New Application" from the developer application.
+
+Fill in an application name. The only restriction is that it can't use a Facebook trademark or be similar to official Facebook application names.
+
+Agree to the terms of servce.
+
+Click "Create Application".
+
+=head2 Step 3: The Connect tab.
+
+After creating your application, go to the "Connect" tab.
+
+Fill in the "Connect URL" field. It should be something like C<http://www.yourapplication.com/facebook/>. It is the base URL to where you'll be deploying your application. The trailing slash is required.
+
+Click "save".
+
+=head2 Step 4: Note your application settings.
+
+You either want to make note of your "Application ID" and your "Application Secret" or bookmark this page so you can come back to it. You'll need these later.
+
+=head2 Step 5: Create app.psgi.
+
+Create a file called C<app.psgi>. Start it off like this:
+
+ use strict;
+ use Plack::App::URLMap;
+ use Plack::Request;
+ use Facebook::Graph;
+ use URI;
+
+ my $urlmap = Plack::App::URLMap->new;
+ 
+ # your code will go here
+
+ $urlmap->to_app;
+
+All the code we have you add should go in the C<# your code will go here> block, in the order that we have you add it. 
+ 
+=head2 Step 6: Create your Facebook::Graph object.
+
+Now we can finally start building L<Facebook::Graph> into our app.
+
+ my $fb = Facebook::Graph->new(
+    postback    => 'http://www.yourapplication.com/facebook/postback',
+    app_id      => 'Put Your Application ID Here',
+    secret      => 'Put Your Application Secret Here',
+ );
+ 
+Now you need the URL you entered in step 3, and the application ID and secret you got in step 4.
+
+On the end of the url, add C<postback>. This could be anything really, but it needs to be separate from the Connect URL.
+
+=head2 Step 7: Create your application's connect page.
+
+Now we need to create the authorization redirect. This is where we tell Facebook what permissions we want. There is a complete list of permissions documented at L<http://developers.facebook.com/docs/authentication/permissions>.
+
+If we only wanted basic permissions we can leave the C<extend_permissions> call out. But for this app let's say we want access to the user's email address and we want to be able to interact with the user's account even when they aren't online.
+
+ my $connect = sub {
+    my $env = shift;
+    my $request = Plack::Request->new( $env );
+    my $response = $request->new_response;
+    $response->redirect(
+        $fb
+        ->authorize
+        ->extend_permissions( qw(email offline_access) )
+        ->uri_as_string
+    );
+    return $response->finalize;
+ };
+
+ $urlmap->map("/facebook" => $connect);
+
+We map the subroutine we created to C</facebook> because we'll likely have other things we want to display at C</>. If we wanted to display something else at C</facebook> we could have mapped this function to C</facebook/authorize>. It really doesn't matter what URL we use here, all that matters is that when we want our users to authenticate against Facebook, this is the URL that we're going to send them to in our application.
+
+=head2 Step 8: Create the Facebook access token postback page.
+
+Our connect/authorization page will redirect the user to Facebook to authorize our app. Now we need to create the page that the user will be redirected back to from Facebook. This is the C<postback> that we created in step 6.
+
+ my $postback = sub {
+    my $env = shift;
+    my $request = Plack::Request->new( $env );
+
+    # turn our authorization code into an access token
+    $fb->request_access_token($request->param('code'));
+
+    # store our access token to a database, a cookie, or pass it throuh the URL
+    my $uri = URI->new('http://www.yourapplication.com/search');
+    $uri->query_form( access_token => $fb->access_token );
+
+    my $response = $request->new_response;
+    $response->redirect( $uri->as_string );
+    return $response->finalize;
+ };
+
+ $urlmap->map("/facebook/postback" => $postback);
+
+It's really stupid of us to pass our access token along the URL especially since we requested C<offline_access>. We're only doing it here to demonstrate the usage of it. If you're requesting offline access, you should keep the access token locked away in a secure database. If you want to pass it along the URL, or store it in a cookie, you should B<not> request C<offline_access>.
+
+=head2 Step 9: Let's do something already!
+
+So now that we finally have an access token we can start making privileged requests. That works like this:
+
+ my $search = sub {
+    my $env = shift;
+    my $request = Plack::Request->new( $env );
+
+    # display a search
+    my $out = '<html>
+    <body>
+    <form>
+    <input type="hidden" name="access_token" value="'. $request->param('access_token') .'">
+    <input type="text" name="q" value="'. $request->param('q') .'">
+    <input type="submit" value="Search">
+    </form>
+    <pre>
+    ';
+
+    # display the results if a search is made
+    if ($request->param('q')) {
+        $fb->access_token( $request->param('access_token') );
+        my $response = $fb->query
+            ->search($request->param('q'), 'user')
+            ->limit_results(10)
+            ->request;
+        $out .= eval{$response->as_json};
+        if ($@) {
+            $out .= 'ERROR: '.$@->[1];
+        }
+    }
+
+    # close everything up
+    $out .= '
+    </pre>
+    </body>
+    </html>
+    ';
+
+    my $response = $request->new_response;
+    $response->status(200);
+    $response->content_type('text/html');
+    $response->body($out);
+    return $response->finalize;
+ };
+
+ $urlmap->map("/search" => $search);
+
+
+=head2 Step 10: Start the application and let's test this puppy out.
+
+On your server (the one that www.yourapplication.com points to) run the following command (assuming you're in the folder with app.psgi).
+
+ sudo plackup --port 80 app.psgi
+ 
+Now we point our browser to:
+
+ http://www.yourapplication.com/facebook
+ 
+Voila! You have created an authenticated Facebook app. If you would like to see this full program check out C<eg/recipe1.psgi> inside this distribution of L<Facebook::Graph>.
+
+
+=head1 CAVEATS
+
+You should never design an application using all the poor stuff we've done here, like using a shared L<Facebook::Graph> object, not using a Framework/CMS or at least L<Plack::Builder>, not using a templating system, passing the offline access token through the URL, etc. We've made comments about these things as we did them to warn you. These choices were made here B<only> because this is example code who's primary purpose is to show you how to use L<Facebook::Graph>, and not best practices for web development. 
+
+=head1 SEE ALSO
+
+For more recipes, check out the L<Facebook::Graph::Cookbook>.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Cookbook/Recipe2.pod
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Cookbook/Recipe2.pod	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Cookbook/Recipe2.pod	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,104 @@
+=head1 NAME
+
+Facebook::Graph::Cookbook::Recipe2 - Building a Full Web App
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 DESCRIPTION
+
+A full working web app for those people who like to start hacking from a working example and make it their own.
+
+=head2 Prerequisite Modules
+
+You'll need to have all of the following modules installed in order to run this app (in addition to L<Facebook::Graph>):
+
+L<DateTime::Format::ICal> L<Dancer> L<Template> L<Data::ICal> L<XML::FeedPP> 
+
+=head2 Assumptions
+
+This recipe assumes that that you have a Facebook (L<http://www.facebook.com>) account.
+
+You'll also have to be able to point a domain name to a server that is accessible from the Internet. DNS and server configuration are way beyond the scope of this document.
+
+In order to edit this web app you're either going to have to know or be willing to learn L<Dancer>. It's a good little web app server. You can find out more at L<http://perldancer.org>.
+
+=head1 RECIPE
+
+=head2 Step 1: Set up the developer application on Facebook.
+
+Go to L<http://apps.facebook.com/developer>.
+
+Click "Allow".
+
+=head2 Step 2: Create your application.
+
+Go to L<http://www.facebook.com/developers/createapp.php> or click "Set Up New Application" from the developer application.
+
+Fill in an application name. The only restriction is that it can't use a Facebook trademark or be similar to official Facebook application names.
+
+Agree to the terms of servce.
+
+Click "Create Application".
+
+=head2 Step 3: The Connect tab.
+
+After creating your application, go to the "Connect" tab.
+
+Fill in the "Connect URL" field. It should be C<http://www.yourapplication.com/>. It is the base URL to where you'll be deploying your application. The trailing slash is required.
+
+Click "save".
+
+=head2 Step 4: Note your application settings.
+
+You either want to make note of your "Application ID" and your "Application Secret" or bookmark this page so you can come back to it. You'll need these later.
+
+=head2 Step 5: Copy files.
+
+If you don't already have it downloaded, download a tarball of Facebook::Graph and extract it:
+
+ tar xfz Facebook-Graph-0.0700.tar.gz
+
+And copy the files from C<eg/recipe2> where ever you want to deploy your app. For this example we'll assume you want to deploy from C</opt/webapp>.
+
+ mkdir -p /opt/webapp
+ cp -Rfp Facebook-Graph/eg/recipe2/* /opt/webapp
+ 
+=head2 Step 6: Configure your app.
+
+Before we can run the app we need to edit the config file.
+
+ cd /opt/webapp
+ vi config.yml
+
+Specifically we need to set the C<app_id> and C<secret> fields with information from our Facebook application settings page. And we need to update the C<postback> with the domain pointing to our server. 
+
+=head2 Step 7: Start it.
+
+To start the app just type the following command:
+
+ cd /opt/webapp
+ perl app.pl
+
+=head2 Step 8: Play with it.
+
+Go use the web app. See what it does. Point your browser to:
+
+ http://www.yourapplication.com/
+
+=head2 Step 9: Start tinkering.
+
+Now that you know you have a working app, start tinkering. Make it do what you want it to do.
+
+=head1 SEE ALSO
+
+If you would like a step by step as to how this app was created, download the PDF presentation (L<http://www.madmongers.org/talks/writing-facebook-apps-in-10-minutes-or-less>) I gave of this app at MadMongers (L<http://www.madmongers.org>).
+
+For more recipes, check out the L<Facebook::Graph::Cookbook>.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Picture.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Picture.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Picture.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,122 @@
+package Facebook::Graph::Picture;
+BEGIN {
+  $Facebook::Graph::Picture::VERSION = '1.0300';
+}
+
+use Any::Moose;
+with 'Facebook::Graph::Role::Uri';
+
+has type => (
+    is          => 'rw',
+    predicate   => 'has_type',
+);
+
+has object_name => (
+    is          => 'rw',
+    default     => '',
+);
+
+sub get_small {
+    my ($self) = @_;
+    $self->type('small');
+    return $self;
+}
+
+sub get_square {
+    my ($self) = @_;
+    $self->type('square');
+    return $self;
+}
+
+sub get_large {
+    my ($self) = @_;
+    $self->type('large');
+    return $self;
+}
+
+sub uri_as_string {
+    my ($self) = @_;
+    my %query;
+    if ($self->has_type) {
+        $query{type} = $self->type;
+    }
+    my $uri = $self->uri;
+    $uri->path($self->object_name . '/picture');
+    $uri->query_form(%query);
+    return $uri->as_string;
+}
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Picture - Get the URI for the picture of any object.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+ 
+ my $default_picture =  $fb->picture('16665510298')->uri_as_string;
+ my $large_picture = $fb->picture('16665510298')->get_large->uri_as_string;
+ my $small_picture = $fb->picture('16665510298')->get_small->uri_as_string;
+ my $square_picture = $fb->picture('16665510298')->get_square->uri_as_string;
+
+=head1 DESCRIPTION
+
+This module allows you to generate the URL needed to fetch a picture for any object on Facebook.
+
+=head1 METHODS
+
+
+=head2 get_large ( id )
+
+Get a large picture. 200 pixels wide by a variable height.
+
+=head3 id
+
+The unique id or object name of an object.
+
+B<Example:> For user "Sarah Bownds" you could use either her profile id C<sarahbownds> or her object id C<767598108>.
+
+
+=head2 get_small ( id )
+
+Get a small picture. 50 pixels wide by a variable height.
+
+=head3 id
+
+The unique id or object name of an object.
+
+B<Example:> For user "Sarah Bownds" you could use either her profile id C<sarahbownds> or her object id C<767598108>.
+
+
+=head2 get_square ( id )
+
+Get a square picture. 50 pixels wide by 50 pixels tall.
+
+=head3 id
+
+The unique id or object name of an object.
+
+B<Example:> For user "Sarah Bownds" you could use either her profile id C<sarahbownds> or her object id C<767598108>.
+
+
+
+
+=head2 uri_as_string ()
+
+Returns a URI string based upon all the methods you've called so far on the query. You can throw the resulting URI right into an <img> tag.
+
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,75 @@
+package Facebook::Graph::Publish;
+BEGIN {
+  $Facebook::Graph::Publish::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use Facebook::Graph::Response;
+with 'Facebook::Graph::Role::Uri';
+use LWP::UserAgent;
+use URI::Encode qw(uri_decode);
+
+has secret => (
+    is          => 'ro',
+    required    => 0,
+    predicate   => 'has_secret',
+);
+
+has access_token => (
+    is          => 'ro',
+    predicate   => 'has_access_token',
+);
+
+has object_name => (
+    is          => 'rw',
+    default     => 'me',
+);
+
+sub to {
+    my ($self, $object_name) = @_;
+    $self->object_name($object_name);
+    return $self;
+}
+
+sub get_post_params {
+    my $self = shift;
+    my @post;
+    if ($self->has_access_token) {
+        push @post, access_token => uri_decode($self->access_token);
+    }
+    return \@post;
+}
+
+sub publish {
+    my ($self) = @_;
+    my $uri = $self->uri;
+    $uri->path($self->object_name.$self->object_path);
+    my $response = LWP::UserAgent->new->post($uri, $self->get_post_params);
+    my %params = (response => $response);
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Response->new(%params);
+}
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish - A base class for publishing various things to facebook.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 DESCRIPTION
+
+This module shouldn't be used by you directly for any purpose. 
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Checkin.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Checkin.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Checkin.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,189 @@
+package Facebook::Graph::Publish::Checkin;
+BEGIN {
+  $Facebook::Graph::Publish::Checkin::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/checkins';
+
+has message => (
+    is          => 'rw',
+    predicate   => 'has_message',
+);
+
+sub set_message {
+    my ($self, $message) = @_;
+    $self->message($message);
+    return $self;
+}
+
+has place => (
+    is          => 'rw',
+    predicate   => 'has_place',
+);
+
+sub set_place {
+    my ($self, $value) = @_;
+    $self->place($value);
+    return $self;
+}
+
+has longitude => (
+    is          => 'rw',
+    isa         => 'Num',
+    predicate   => 'has_longitude',
+);
+
+sub set_longitude {
+    my ($self, $value) = @_;
+    $self->longitude($value);
+    return $self;
+}
+
+has latitude => (
+    is          => 'rw',
+    isa         => 'Num',
+    predicate   => 'has_latitude',
+);
+
+sub set_latitude {
+    my ($self, $value) = @_;
+    $self->latitude($value);
+    return $self;
+}
+
+has tags => (
+    is          => 'rw',
+    isa         => 'ArrayRef',
+    predicate   => 'has_tags',
+    lazy        => 1,
+    default     => sub {[]},
+);
+
+sub set_tags {
+    my ($self, $value) = @_;
+    $self->tags($value);
+    return $self;
+}
+
+
+around get_post_params => sub {
+    my ($orig, $self) = @_;
+    my $post = $orig->($self);
+    if ($self->has_message) {
+        push @$post, message => $self->message;
+    }
+    if ($self->has_place) {
+        push @$post, place => $self->place;
+    }
+    if ($self->has_tags) {
+        push @$post, tags => join(', ',@{$self->tags});
+    }
+    if ($self->has_latitude && $self->has_longitude) {
+        push @$post, coordinates => JSON->new->encode({ latitude => $self->latitude, longitude => $self->longitude });
+    }
+   return $post;
+};
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Checkin - Publish a location checkin.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->add_checkin
+    ->set_place(222047056390)
+    ->publish;
+
+ my $response = $fb->add_checkin
+    ->set_place(222047056390)
+    ->set_message('Mmm...pizza.')
+    ->set_tags([qw(sarah.bownds 1647395831)])
+    ->set_latitude()
+    ->set_longitude()
+    ->publish;
+
+
+=head1 DESCRIPTION
+
+This module gives you quick and easy access to publish user checkins to locations.
+
+B<ATTENTION:> You must have the C<user_checkins> privilege to use this module, and C<friends_checkins> to get friends checkins.
+
+=head1 METHODS
+
+=head2 to ( id )
+
+Specify a profile id to post to. Defaults to 'me', which is the currently logged in user.
+
+
+=head2 set_message ( message )
+
+Sets the text to post to the wall.
+
+=head3 message
+
+A string of text.
+
+
+=head2 set_place ( id )
+
+Sets the id of the place you are checking in to.
+
+=head3 id
+
+The id of a page for a place. For example C<222047056390> is the id of Pete's Pizza and Pub in Milwaukee, WI.
+
+
+=head2 set_latitude ( coord )
+
+Sets sets the coords of your location. See also C<set_longitude>
+
+=head3 coord
+
+The decimal latitude of your current location.
+
+
+=head2 set_longitude ( coord )
+
+Sets sets the coords of your location. See also C<set_latitude>
+
+=head3 coord
+
+The decimal longitude of your current location.
+
+
+=head2 set_tags ( list )
+
+Sets the list of users at the location.
+
+=head3 list
+
+An array reference of Facebook user ids that are currently at this location with you.
+
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain the id:
+
+ {"id":"1647395831_130068550371568"}
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Comment.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Comment.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Comment.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,83 @@
+package Facebook::Graph::Publish::Comment;
+BEGIN {
+  $Facebook::Graph::Publish::Comment::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/comments';
+
+has message => (
+    is          => 'rw',
+    predicate   => 'has_message',
+);
+
+sub set_message {
+    my ($self, $message) = @_;
+    $self->message($message);
+    return $self;
+}
+
+
+
+around get_post_params => sub {
+    my ($orig, $self) = @_;
+    my $post = $orig->($self);
+    if ($self->has_message) {
+        push @$post, message => $self->message;
+    }
+    return $post;
+};
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Comment - Publish a comment on a post.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->add_comment($comment_id)
+    ->set_message('Why so serious?')
+    ->publish;
+
+
+=head1 DESCRIPTION
+
+This module gives you quick and easy access to publish comments on posts.
+
+B<ATTENTION:> You must have the C<publish_stream> privilege to use this module.
+
+=head1 METHODS
+
+=head2 set_message ( message )
+
+Sets the text to post to the wall.
+
+=head3 message
+
+A string of text.
+
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain the id:
+
+ {"id":"1647395831_130068550371568"}
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Event.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Event.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Event.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,195 @@
+package Facebook::Graph::Publish::Event;
+BEGIN {
+  $Facebook::Graph::Publish::Event::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+use DateTime;
+use DateTime::Format::Strptime;
+
+use constant object_path => '/events';
+
+has name => (
+    is          => 'rw',
+    predicate   => 'has_name',
+);
+
+sub set_name {
+    my ($self, $input) = @_;
+    $self->name($input);
+    return $self;
+}
+
+has description => (
+    is          => 'rw',
+    predicate   => 'has_description',
+);
+
+sub set_description {
+    my ($self, $input) = @_;
+    $self->description($input);
+    return $self;
+}
+
+has location => (
+    is          => 'rw',
+    predicate   => 'has_location',
+);
+
+sub set_location {
+    my ($self, $input) = @_;
+    $self->location($input);
+    return $self;
+}
+
+has start_time => (
+    is          => 'rw',
+    isa         => 'DateTime',
+    predicate   => 'has_start_time',
+);
+
+sub set_start_time {
+    my ($self, $start_time) = @_;
+    $self->start_time($start_time);
+    return $self;
+}
+
+has end_time => (
+    is          => 'rw',
+    isa         => 'DateTime',
+    predicate   => 'has_end_time',
+);
+
+sub set_end_time {
+    my ($self, $end_time) = @_;
+    $self->end_time($end_time);
+    return $self;
+}
+
+
+
+around get_post_params => sub {
+    my ($orig, $self) = @_;
+    my $post = $orig->($self);
+    unless ($self->object_name eq 'me') {
+        push @$post, page_id => $self->object_name;
+    }
+    if ($self->has_name) {
+        push @$post, name => $self->name;
+    }
+    if ($self->has_description) {
+        push @$post, description => $self->description;
+    }
+    if ($self->has_location) {
+        push @$post, location => $self->location;
+    }
+    my $strp = DateTime::Format::Strptime->new(pattern => '%FT %T%z');
+    if ($self->has_start_time) {
+        push @$post, start_time => $strp->format_datetime($self->start_time);
+    }
+    if ($self->has_end_time) {
+        push @$post, end_time => $strp->format_datetime($self->end_time);
+    }
+    return $post;
+};
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Event - Add an event.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ my $start = DateTime->new( month=>10, day=>31, year => 2010, hour=>20 );
+ $fb->add_event
+    ->set_start_time($start)
+    ->set_end_time($start->clone->add(hours => 6))
+    ->set_name('Halloween Party')
+    ->publish;
+
+
+=head1 DESCRIPTION
+
+This module gives you quick and easy access to publish events.
+
+B<ATTENTION:> You must have the C<create_event> privilege to use this module.
+
+=head1 METHODS
+
+=head2 to ( id )
+
+Specify a profile id to post to. Defaults to 'me', which is the currently logged in user.
+
+
+=head2 set_name ( name )
+
+Sets the name of the event.
+
+=head3 name
+
+A string of text.
+
+
+=head2 set_description ( description )
+
+Sets the description of the event. Tell people what's going on.
+
+=head3 description
+
+A string of text.
+
+
+=head2 set_location ( location )
+
+Sets a general description of where the event will take place.
+
+=head3 location
+
+A string of text.
+
+
+=head2 set_start_time ( datetime )
+
+Sets the start of the event.
+
+=head3 datetime
+
+A L<DateTime> object.
+
+
+=head2 set_end_time ( datetime )
+
+Sets the end of the event.
+
+=head3 datetime
+
+A L<DateTime> object.
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain the id:
+
+ {"id":"1647395831_130068550371568"}
+ 
+ 
+=head1 TODO
+
+Add venue and privacy as described on L<http://developers.facebook.com/docs/reference/api/event>.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Like.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Like.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Like.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,47 @@
+package Facebook::Graph::Publish::Like;
+BEGIN {
+  $Facebook::Graph::Publish::Like::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/likes';
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Like - Mark a post as something you like.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->add_like($post_id)
+    ->publish;
+
+=head1 DESCRIPTION
+
+Marks a post as something you like.
+
+B<ATTENTION:> You must have the C<publish_stream> privilege to use this module.
+
+=head1 METHODS
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain a string of either 'true' or 'false'.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Link.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Link.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Link.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,112 @@
+package Facebook::Graph::Publish::Link;
+BEGIN {
+  $Facebook::Graph::Publish::Link::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/links';
+
+has message => (
+    is          => 'rw',
+    predicate   => 'has_message',
+);
+
+sub set_message {
+    my ($self, $message) = @_;
+    $self->message($message);
+    return $self;
+}
+
+has link_uri => (
+    is          => 'rw',
+    predicate   => 'has_link_uri',
+);
+
+sub set_link_uri {
+    my ($self, $link_uri) = @_;
+    $self->link_uri($link_uri);
+    return $self;
+}
+
+
+
+around get_post_params => sub {
+    my ($orig, $self) = @_;
+    my $post = $orig->($self);
+    if ($self->has_message) {
+        push @$post, message => $self->message;
+    }
+    if ($self->has_link_uri) {
+        push @$post, link => $self->link_uri;
+    }
+    return $post;
+};
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Link - Add a link.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->add_link
+    ->set_link_uri('http://www.plainblack.com')
+    ->set_message('Plain Black')
+    ->publish;
+
+
+=head1 DESCRIPTION
+
+This module gives you quick and easy access to publish notes.
+
+B<ATTENTION:> You must have the C<publish_stream> privilege to use this module.
+
+=head1 METHODS
+
+=head2 to ( id )
+
+Specify a profile id to post to. Defaults to 'me', which is the currently logged in user.
+
+
+=head2 set_message ( message )
+
+Sets the description of the link.
+
+=head3 message
+
+A string of text.
+
+
+=head2 set_link_uri ( uri )
+
+Sets the URI to link to.
+
+=head3 uri
+
+A a URI.
+
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain the id:
+
+ {"id":"1647395831_130068550371568"}
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Note.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Note.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Note.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,112 @@
+package Facebook::Graph::Publish::Note;
+BEGIN {
+  $Facebook::Graph::Publish::Note::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/notes';
+
+has message => (
+    is          => 'rw',
+    predicate   => 'has_message',
+);
+
+sub set_message {
+    my ($self, $message) = @_;
+    $self->message($message);
+    return $self;
+}
+
+has subject => (
+    is          => 'rw',
+    predicate   => 'has_subject',
+);
+
+sub set_subject {
+    my ($self, $subject) = @_;
+    $self->subject($subject);
+    return $self;
+}
+
+
+
+around get_post_params => sub {
+    my ($orig, $self) = @_;
+    my $post = $orig->($self);
+    if ($self->has_message) {
+        push @$post, message => $self->message;
+    }
+    if ($self->has_subject) {
+        push @$post, subject => $self->subject;
+    }
+    return $post;
+};
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Note - Add a note to a user's list of notes.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->add_note
+    ->set_subject('Things I Like')
+    ->set_message('I like beer.')
+    ->publish;
+
+
+=head1 DESCRIPTION
+
+This module gives you quick and easy access to publish notes.
+
+B<ATTENTION:> You must have the C<publish_stream> privilege to use this module.
+
+=head1 METHODS
+
+=head2 to ( id )
+
+Specify a profile id to post to. Defaults to 'me', which is the currently logged in user.
+
+
+=head2 set_message ( message )
+
+Sets the body text of the note.
+
+=head3 message
+
+A string of text.
+
+
+=head2 set_subject ( subject )
+
+Sets the title to identify the note from others.
+
+=head3 subject
+
+A string of text.
+
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain the id:
+
+ {"id":"1647395831_130068550371568"}
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/Post.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/Post.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/Post.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,479 @@
+package Facebook::Graph::Publish::Post;
+BEGIN {
+  $Facebook::Graph::Publish::Post::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/feed';
+
+has message => (
+    is          => 'rw',
+    predicate   => 'has_message',
+);
+
+sub set_message {
+    my ($self, $message) = @_;
+    $self->message($message);
+    return $self;
+}
+
+has picture_uri => (
+    is          => 'rw',
+    predicate   => 'has_picture_uri',
+);
+
+sub set_picture_uri {
+    my ($self, $picture) = @_;
+    $self->picture_uri($picture);
+    return $self;
+}
+
+
+has link_uri => (
+    is          => 'rw',
+    predicate   => 'has_link_uri',
+);
+
+sub set_link_uri {
+    my ($self, $source) = @_;
+    $self->link_uri($source);
+    return $self;
+}
+
+
+has link_name => (
+    is          => 'rw',
+    predicate   => 'has_link_name',
+);
+
+sub set_link_name {
+    my ($self, $source) = @_;
+    $self->link_name($source);
+    return $self;
+}
+
+
+has link_caption => (
+    is          => 'rw',
+    predicate   => 'has_link_caption',
+);
+
+sub set_link_caption {
+    my ($self, $source) = @_;
+    $self->link_caption($source);
+    return $self;
+}
+
+
+has link_description => (
+    is          => 'rw',
+    predicate   => 'has_link_description',
+);
+
+sub set_link_description {
+    my ($self, $source) = @_;
+    $self->link_description($source);
+    return $self;
+}
+
+has target_countries => (
+    is          => 'rw',
+    default     => sub {[]},
+    lazy        => 1,
+    isa         => 'ArrayRef',
+    predicate   => 'has_target_countries',
+);
+
+sub set_target_countries {
+    my ($self, $source) = @_;
+    $self->target_countries($source);
+    return $self;
+}
+
+has target_cities => (
+    is          => 'rw',
+    default     => sub {[]},
+    lazy        => 1,
+    isa         => 'ArrayRef',
+    predicate   => 'has_target_cities',
+);
+
+sub set_target_cities {
+    my ($self, $source) = @_;
+    $self->target_cities($source);
+    return $self;
+}
+
+has target_regions => (
+    is          => 'rw',
+    default     => sub {[]},
+    lazy        => 1,
+    isa         => 'ArrayRef',
+    predicate   => 'has_target_regions',
+);
+
+sub set_target_regions {
+    my ($self, $source) = @_;
+    $self->target_regions($source);
+    return $self;
+}
+
+has target_locales => (
+    is          => 'rw',
+    default     => sub {[]},
+    lazy        => 1,
+    isa         => 'ArrayRef',
+    predicate   => 'has_target_locales',
+);
+
+sub set_target_locales {
+    my ($self, $source) = @_;
+    $self->target_locales($source);
+    return $self;
+}
+
+has source => (
+    is          => 'rw',
+    predicate   => 'has_source',
+);
+
+sub set_source {
+    my ($self, $source) = @_;
+    $self->source($source);
+    return $self;
+}
+
+has actions => (
+    is          => 'rw',
+    default     => sub {[]},
+    lazy        => 1,
+    isa         => 'ArrayRef',
+    predicate   => 'has_actions',
+);
+
+sub set_actions {
+    my ($self, $actions) = @_;
+    $self->actions($actions);
+    return $self;
+}
+
+sub add_action {
+    my ($self, $name, $link) = @_;
+    my $actions = $self->actions;
+    push @$actions, { name => $name, link => $link };
+    $self->actions($actions);
+    return $self;
+}
+
+has privacy => (
+    is          => 'rw',
+    predicate   => 'has_privacy',
+);
+
+has privacy_options => (
+    is          => 'rw',
+    isa         => 'HashRef',
+    default     => sub {{}},
+);
+
+sub set_privacy {
+    my ($self, $privacy, $options) = @_;
+    $self->privacy($privacy);
+    $self->privacy_options($options);
+    return $self;
+}
+
+has 'properties' => (
+    is          => 'rw',
+    predicate   => 'has_properties'
+);
+
+sub set_properties {
+    my $self = shift;
+    my $properties = @_ % 2 ? shift @_ : { @_ };
+    $self->properties($properties);
+    return $self;
+}
+
+around get_post_params => sub {
+    my ($orig, $self) = @_;
+    my $post = $orig->($self);
+    if ($self->has_message) {
+        push @$post, message => $self->message;
+    }
+    if ($self->has_link_uri) {
+        push @$post, link => $self->link_uri;
+    }
+    if ($self->has_link_name) {
+        push @$post, name => $self->link_name;
+    }
+    if ($self->has_link_caption) {
+        push @$post, caption => $self->link_caption;
+    }
+    if ($self->has_link_description) {
+        push @$post, description => $self->link_description;
+    }
+    if ($self->has_picture_uri) {
+        push @$post, picture => $self->picture_uri;
+    }
+    if ($self->has_source) {
+        push @$post, source => $self->source;
+    }
+    if ($self->has_actions) {
+        foreach my $action (@{$self->actions}) {
+            push @$post, actions => JSON->new->encode($action);
+        }
+    }
+    if ($self->has_privacy) {
+        my %privacy = %{$self->privacy_options};
+        $privacy{value} = $self->privacy;
+        push @$post, privacy => JSON->new->encode(\%privacy);
+    }
+    if ($self->has_properties) {
+        push @$post, properties => JSON->new->encode($self->properties);
+    }
+    return $post;
+};
+
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::Post - Publish to a user's wall.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->add_post
+    ->set_message('I like beer.')
+    ->publish;
+
+ my $response = $fb->add_post
+    ->set_message('I like Perl.')
+    ->set_picture_uri('http://www.perl.org/i/camel_head.png')
+    ->set_link_uri('http://www.perl.org/')
+    ->set_link_name('Perl.org')
+    ->set_link_caption('Perl is a programming language.')
+    ->set_link_description('A link to the Perl web site.')
+    ->publish;
+
+
+=head1 DESCRIPTION
+
+This module gives you quick and easy access to publish to a user's Facebook feed.
+
+B<ATTENTION:> You must have the C<publish_stream> privilege to use this module.
+
+B<TIP:> Facebook seems to use these terms interchangibly: Feed, Post, News, Wall. So if you want to publish to a user's wall, this is the mechanism you use to do that.
+
+=head1 METHODS
+
+=head2 to ( id )
+
+Specify a profile id to post to. Defaults to 'me', which is the currently logged in user.
+
+
+=head2 set_message ( message )
+
+Sets the text to post to the wall.
+
+=head3 message
+
+A string of text.
+
+
+=head2 set_picture_uri ( uri )
+
+Sets the URI of a picture to be displayed in the message.
+
+=head3 uri
+
+A URI to a picture.
+
+
+=head2 set_link_uri ( uri )
+
+Sets the URI of a link that viewers can click on for more information about whatever you posted in C<set_message>.
+
+=head3 uri
+
+A URI to a site.
+
+
+=head2 set_link_name ( name )
+
+If you want to give the link you set in C<set_link_uri> a human friendly name, use this method.
+
+=head2 name
+
+A text string to be used as the name of the link.
+
+
+=head2 set_link_caption ( caption )
+
+Sets a short blurb to be displayed below the link/picture.
+
+=head3 caption
+
+A text string.
+
+
+=head2 set_link_description ( description )
+
+Sets a longer description of the site you're linking to. Can also be a portion of the article you're linking to.
+
+=head3 description
+
+A text string.
+
+
+=head2 set_source ( uri )
+
+Sets a source URI for a flash or video file.
+
+=head3 uri
+
+The URI you wish to set. For example if you wanted to include a YouTube video:
+
+ $post->set_source('http://www.youtube.com/watch?v=efsJRdJ6dog');
+
+
+=head2 set_actions ( actions )
+
+Sets a list of actions (or links) that should go in the post as things people can do with the post. This allows for integration of the post with third party sites.
+
+=head3 actions
+
+An array reference of hash references containing C<name> / C<link> pairs.
+
+ $post->actions([
+    {
+        name    => 'Click Me!',
+        link    => 'http://www.somesite.com/click',
+    },
+    ...
+ ]);
+
+=head2 add_action ( name, link )
+
+Adds an action to the list of actions set either by previously calling C<add_action> or by calling C<set_actions>.
+
+=head3 name
+
+The name of the action (the clickable label).
+
+=head3 link
+
+The URI of the action.
+
+
+
+=head2 set_privacy ( setting, options )
+
+A completely optional privacy setting. 
+
+=head2 set_properties ( properties )
+
+"property" values assigned when the post is published. This is typically rendered as a list of links.
+
+    $post->set_properties( { "search engine:" => { "text" => "Google", "href" => "http://www.google.com/" } } );
+
+=head3 setting
+
+The privacy setting. Choose from: EVERYONE, CUSTOM, ALL_FRIENDS, NETWORKS_FRIENDS, and FRIENDS_OF_FRIENDS. See L<http://developers.facebook.com/docs/reference/api/post> for changes in this list.
+
+=head3 options
+
+A hash reference of options to tweak the privacy setting. Some options are required depending on what privacy setting you chose. See L<http://developers.facebook.com/docs/reference/api/post> for details.
+
+ $post->set_privacy('CUSTOM', { friends => 'SOME_FRIENDS', allow => [qw( 119393 993322 )] });
+
+=over
+
+=item friends
+
+A string that must be one of EVERYONE, NETWORKS_FRIENDS, FRIENDS_OF_FRIENDS, ALL_FRIENDS, SOME_FRIENDS, SELF, or NO_FRIENDS.
+
+=item networks
+
+An array reference of network ids.
+
+=item allow
+
+An array reference of user ids.
+
+=item deny.
+
+An array reference of user ids.
+
+=back
+
+
+=head2 set_target_countries ( countries )
+
+Makes a post only available to viewers in certain countries.
+
+ $post->set_target_countries( ['US'] );
+ 
+=head3 countries
+
+An array reference of two letter country codes (upper case). You can find a list of country codes in the list of city ids here: L<http://developers.facebook.com/attachment/all_cities_final.csv>.
+
+
+=head2 set_target_regions ( regions )
+
+Makes a post only available to viewers in certain regions.
+
+ $post->set_target_regions( [6,53] );
+ 
+=head3 regions
+
+An array reference of region numbers however Facebook defines that. I've got no idea because their documentation sucks. I'm not even sure what a region is. Is it a region of a country? Of a continent? No idea. I do know it is an integer, but that's about it.
+
+
+
+=head2 set_target_cities ( cities )
+
+Makes a post only available to viewers in certain cities.
+
+ $post->set_target_cities( [2547804] );
+ 
+=head3 cities
+
+An array reference of cities ids. In the example above I've listed Madison, WI. You can find a list of their cities here: L<http://developers.facebook.com/attachment/all_cities_final.csv>
+
+
+
+=head2 set_target_locales ( locales )
+
+Makes a post only available to viewers in certain locales.
+
+ $post->set_target_locales( [6] );
+ 
+=head3 locales
+
+An array reference of locales ids. You can find their list of locales here: L<http://developers.facebook.com/attachment/locales_final.csv>
+
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain the id:
+
+ {"id":"1647395831_130068550371568"}
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPAttending.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPAttending.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPAttending.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,47 @@
+package Facebook::Graph::Publish::RSVPAttending;
+BEGIN {
+  $Facebook::Graph::Publish::RSVPAttending::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/attending';
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::RSVPAttending - RSVP attending to an event.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->rsvp_attending($event_id)
+    ->publish;
+
+=head1 DESCRIPTION
+
+RSVP's "Attending" to an event.
+
+B<ATTENTION:> You must have the C<rsvp_event> privilege to use this module.
+
+=head1 METHODS
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain a string of either 'true' or 'false'.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPDeclined.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPDeclined.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPDeclined.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,47 @@
+package Facebook::Graph::Publish::RSVPDeclined;
+BEGIN {
+  $Facebook::Graph::Publish::RSVPDeclined::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/declined';
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::RSVPDeclined - RSVP declined to an event.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->rsvp_declined($event_id)
+    ->publish;
+
+=head1 DESCRIPTION
+
+RSVP's "Declined" to an event.
+
+B<ATTENTION:> You must have the C<rsvp_event> privilege to use this module.
+
+=head1 METHODS
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain a string of either 'true' or 'false'.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPMaybe.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPMaybe.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Publish/RSVPMaybe.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,47 @@
+package Facebook::Graph::Publish::RSVPMaybe;
+BEGIN {
+  $Facebook::Graph::Publish::RSVPMaybe::VERSION = '1.0300';
+}
+
+use Any::Moose;
+extends 'Facebook::Graph::Publish';
+
+use constant object_path => '/maybe';
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Publish::RSVPMaybe - RSVP maybe to an event.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+
+ $fb->rsvp_maybe($event_id)
+    ->publish;
+
+=head1 DESCRIPTION
+
+RSVP's "Maybe" to an event.
+
+B<ATTENTION:> You must have the C<rsvp_event> privilege to use this module.
+
+=head1 METHODS
+
+
+=head2 publish ( )
+
+Posts the data and returns a L<Facebook::Graph::Response> object. The response object should contain a string of either 'true' or 'false'.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Query.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Query.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Query.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,413 @@
+package Facebook::Graph::Query;
+BEGIN {
+  $Facebook::Graph::Query::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use Facebook::Graph::Response;
+with 'Facebook::Graph::Role::Uri';
+use LWP::UserAgent;
+use URI::Encode qw(uri_decode);
+
+has secret => (
+    is          => 'ro',
+    required    => 0,
+    predicate   => 'has_secret',
+);
+
+has access_token => (
+    is          => 'ro',
+    predicate   => 'has_access_token',
+);
+
+has ids => (
+    is          => 'rw',
+    predicate   => 'has_ids',
+    lazy        => 1,
+    default     => sub { [] },
+);
+
+has fields => (
+    is          => 'rw',
+    predicate   => 'has_fields',
+    lazy        => 1,
+    default     => sub { [] },
+);
+
+has metadata => (
+    is          => 'rw',
+    predicate   => 'has_metadata',
+);
+
+has limit => (
+    is          => 'rw',
+    predicate   => 'has_limit',
+);
+
+has offset => (
+    is          => 'rw',
+    predicate   => 'has_offset',
+);
+
+has search_query => (
+    is          => 'rw',
+    predicate   => 'has_search_query',
+);
+
+has search_type => (
+    is          => 'rw',
+    predicate   => 'has_search_type',
+);
+
+has object_name => (
+    is          => 'rw',
+    default     => '',
+);
+
+has until => (
+    is          => 'rw',
+    predicate   => 'has_until',
+);
+
+has since => (
+    is          => 'rw',
+    predicate   => 'has_since',
+);
+
+
+sub limit_results {
+    my ($self, $limit) = @_;
+    $self->limit($limit);
+    return $self;    
+}
+
+sub find {
+    my ($self, $object_name) = @_;
+    $self->object_name($object_name);
+    return $self;
+}
+
+sub search {
+    my ($self, $query, $type) = @_;
+    $self->search_query($query);
+    return ($type) ? $self->from($type) : $self;
+}
+
+sub from {
+    my ($self, $type) = @_;
+    if ($type eq 'my_news') {
+        $self->object_name('me/home');
+    }
+    else {
+        $self->object_name('search');
+        $self->search_type($type);
+    }
+    return $self;
+}
+
+sub offset_results {
+    my ($self, $offset) = @_;
+    $self->offset($offset);
+    return $self;    
+}
+
+sub include_metadata {
+    my ($self, $include) = @_;
+    $include = 1 unless defined $include;
+    $self->metadata($include);
+    return $self;
+}
+
+sub select_fields {
+    my ($self, @fields) = @_;
+    push @{$self->fields}, @fields;
+    return $self;
+}
+
+sub where_ids {
+    my ($self, @ids) = @_;
+    push @{$self->ids}, @ids;
+    return $self;
+}
+
+sub where_until {
+    my ($self, $date) = @_;
+    $self->until($date);
+    return $self;
+}
+
+sub where_since {
+    my ($self, $date) = @_;
+    $self->since($date);
+    return $self;
+}
+
+sub uri_as_string {
+    my ($self) = @_;
+    my %query;
+    if ($self->has_access_token) {
+        $query{access_token} = uri_decode($self->access_token);
+    }
+    if ($self->has_limit) {
+        $query{limit} = $self->limit;
+        if ($self->has_offset) {
+            $query{offset} = $self->offset;
+        }
+    }
+    if ($self->has_search_query) {
+        $query{q} = $self->search_query;
+        if ($self->has_search_type) {
+            $query{type} = $self->search_type;
+        }
+    }
+    if ($self->has_until) {
+        $query{until} = $self->until;
+    }
+    if ($self->has_since) {
+        $query{since} = $self->since;
+    }
+    if ($self->has_metadata) {
+        $query{metadata} = $self->metadata;
+    }
+    if ($self->has_fields) {
+        $query{fields} = join(',', @{$self->fields});
+    }
+    if ($self->has_ids) {
+        $query{ids} = join(',', @{$self->ids});
+    }
+    my $uri = $self->uri;
+    $uri->path($self->object_name);
+    $uri->query_form(%query);
+    return $uri->as_string;
+}
+
+sub request {
+    my ($self, $uri) = @_;
+    $uri ||= $self->uri_as_string;
+    my $response = LWP::UserAgent->new->get($uri);
+    my %params = (response => $response);
+    if ($self->has_secret) {
+        $params{secret} = $self->secret;
+    }
+    return Facebook::Graph::Response->new(%params);
+}
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Query - Simple and fast searching and fetching of Facebook data.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new;
+ 
+ my $perl_page = $fb->find('16665510298')
+    ->include_metadata
+    ->request
+    ->as_hashref;
+ 
+ my $sarah_bownds = $fb->find('sarahbownds')
+    ->select_fields(qw(id name))
+    ->request
+    ->as_hashref;
+
+ # this one would require an access token
+ my $new_years_posts = $fb->query
+    ->from('posts')
+    ->where_since('1 January 2011')
+    ->where_until('2 January 2011')
+    ->limit(25)
+    ->request
+    ->as_hashref;
+
+ # this one would require an access token
+ my $new_car_posts = $fb->query
+    ->search('car', 'my_news')
+    ->where_since('yesterday')
+    ->request
+    ->as_hashref;
+
+
+=head1 DESCRIPTION
+
+This module presents a programatic approach to building the queries necessary to search and retrieve Facebook data. It provides an almost SQL like way of writing queries using code. For example:
+
+ my $results = $fb
+    ->select_fields(qw(id name))
+    ->search('Dave','user')
+    ->where_since('yesterday')
+    ->limit_results(25)
+    ->request
+    ->as_hashref;
+    
+The above query, if you were read it like text, says: "Give me the user ids and full names of all users named Dave that have been created since yesterday, and limit the result set to the first 25."
+
+
+=head1 METHODS
+
+=head2 find ( id )
+
+Fetch a single item.
+
+=head3 id
+
+The unique id or object name of an object.
+
+B<Example:> For user "Sarah Bownds" you could use either her profile id C<sarahbownds> or her object id C<767598108>.
+
+
+
+
+=head2 from ( context )
+
+
+
+If you prefer to search by keyword see the C<search> method.
+
+=head3 context
+
+One of the following contexts:
+
+=over
+
+=item my_news
+
+The current user's news feed (home page). Requires that you have an access_token so you know who the current user is.
+
+=item post
+
+All public posts.
+
+=item user
+
+All people.
+
+=item page
+
+All pages.
+
+=item event
+
+All events.
+
+=item group
+
+All groups.
+
+
+
+
+=head2 search ( query, context )
+
+Perform a keyword search on a group of items. 
+
+If you prefer not to search by keyword see the C<from> method.
+
+=head3 query
+
+They keywords to search by.
+
+=head3 context
+
+See the C<context> param in the C<from> method.
+
+=back
+
+
+
+=head2 limit_results ( amount )
+
+The result set will only return a certain number of records when this is set. Useful for paging result sets. Returns C<$self> for method chaining.
+
+=head3 amount
+
+An integer representing the number of records to be returned.
+
+
+
+=head2 offset_results ( amount )
+
+Skips ahead the result set by the amount. Useful for paging result sets. Is only applied when used in combination with C<limit_results>. Returns C<$self> for method chaining.
+
+=head3 amount
+
+An integer representing the amount to offset the results by.
+
+
+
+=head2 include_metadata ( [ include ] )
+
+Adds metadata to the result set including things like connections to other objects and the object type being returned. Returns C<$self> for method chaining.
+
+=head3 include
+
+Defaults to 1 when the method is called, but defaults to 0 if the method is never called. You may set it specifically by passing in a 1 or 0.
+
+
+=head2 select_fields ( fields )
+
+Limit the result set to only include the specific fields if they exist in the objects in the result set. Returns C<$self> for method chaining. May be called multiple times to add more fields.
+
+=head3 fields
+
+An array of fields you want in the result set.
+
+B<Example:> 'id', 'name', 'picture'
+
+
+=head2 where_ids ( ids )
+
+Limit the result set to these specifically identified objects. Returns C<$self> for method chaining. May be called multiple times to add more ids.
+
+=head3 ids
+
+An array of object ids, object names, or URIs.
+
+B<Example:> 'http://www.thegamecrafter.com/', 'sarahbownds', '16665510298'
+
+
+=head2 where_until ( date )
+
+Include only records that were created before C<date>. Returns C<$self> for method chaining.
+
+=head3 date
+
+Anything accepted by PHP's strtotime function L<http://php.net/manual/en/function.strtotime.php>.
+
+
+=head2 where_since ( date )
+
+Include only records that have been created since C<date>. Returns C<$self> for method chaining.
+
+=head3 date
+
+Anything accepted by PHP's strtotime function L<http://php.net/manual/en/function.strtotime.php>.
+
+
+=head2 uri_as_string ()
+
+Returns a URI string based upon all the methods you've called so far on the query. Mainly useful for debugging. Usually you want to call C<request> and have it fetch the data for you.
+
+
+
+=head2 request ( [ uri ] )
+
+Forms a URI string based on every method you've called so far, and fetches the data. Returns a L<Facebook::Graph::Response> object.
+
+=head3 uri
+
+Optionally pass in your own URI string and all the other options will be ignored. This is mainly useful with metadata connections. See C<include_metadata> for details.
+
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Response.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Response.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Response.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,93 @@
+package Facebook::Graph::Response;
+BEGIN {
+  $Facebook::Graph::Response::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use JSON;
+use Ouch;
+
+has response => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has as_string => (
+    is      => 'ro',
+    lazy    => 1,
+    default => sub {
+        my $self = shift;
+        return $self->response->content;
+    },
+);
+
+has as_json => (
+    is      => 'ro',
+    lazy    => 1,
+    default => sub {
+        my $self = shift;
+        my $response = $self->response;
+        if ($response->is_success) {
+            return $response->content;
+        }
+        else {
+            my $message = $response->message;
+            my $error = eval { JSON->new->decode($response->content) };
+            unless ($@) {
+                $message = $error->{error}{type} . ' - ' . $error->{error}{message};
+            }
+            ouch $response->code, 'Could not execute request ('.$response->request->uri->as_string.'): '.$message, $response->request->uri->as_string;
+        }
+    },
+);
+
+has as_hashref => (
+    is      => 'ro',
+    lazy    => 1,
+    default => sub {
+        my $self = shift;
+        return JSON->new->decode($self->as_json);
+    },
+);
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+=head1 NAME
+
+Facebook::Graph::Response - Handling of a Facebook::Graph response documents.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 DESCRIPTION
+
+You'll be given one of these as a result of calling the C<request> method on a C<Facebook::Graph::Query> or others.
+
+
+=head1 METHODS
+
+Returns the response as a string. Does not throw an exception of any kind.
+
+=head2 as_json ()
+
+Returns the response from Facebook as a JSON string.
+
+=head2 as_hashref ()
+
+Returns the response from Facebook as a hash reference.
+
+=head2 as_string ()
+
+No processing what so ever. Just returns the raw body string that was received from Facebook.
+
+=head2 response ()
+
+Direct access to the L<HTTP::Response> object.
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Role/Uri.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Role/Uri.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Role/Uri.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,32 @@
+package Facebook::Graph::Role::Uri;
+BEGIN {
+  $Facebook::Graph::Role::Uri::VERSION = '1.0300';
+}
+
+use Any::Moose 'Role';
+use URI;
+
+sub uri {
+    return URI->new('https://graph.facebook.com')
+}
+
+
+1;
+
+=head1 NAME
+
+Facebook::Graph::Role::Uri - The base URI for the Facebook Graph API.
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 DESCRIPTION
+
+Provides a C<uri> method in any class which returns a L<URI> object that points to the Facebook Graph API. 
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
Index: perl/modules/Facebook/lib/Facebook/Graph/Session.pm
===================================================================
--- perl/modules/Facebook/lib/Facebook/Graph/Session.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
+++ perl/modules/Facebook/lib/Facebook/Graph/Session.pm	(revision cfca7617b887d45beec949c4a3098c89447c7b9f)
@@ -0,0 +1,87 @@
+package Facebook::Graph::Session;
+BEGIN {
+  $Facebook::Graph::Session::VERSION = '1.0300';
+}
+
+use Any::Moose;
+use Facebook::Graph::Response;
+with 'Facebook::Graph::Role::Uri';
+use LWP::UserAgent;
+
+has app_id => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has secret => (
+    is      => 'ro',
+    required=> 1,
+);
+
+has sessions => (
+    is      => 'ro',
+    required=> 1,
+);
+
+sub uri_as_string {
+    my ($self) = @_;
+    my $uri = $self->uri;
+    $uri->path('oauth/access_token');
+    $uri->query_form(
+        type            => 'client_cred',
+        client_id       => $self->app_id,
+        client_secret   => $self->secret,
+        sessions        => join(',', @{$self->sessions})
+    );
+    return $uri->as_string;
+}
+
+sub request {
+    my ($self) = @_;
+    my $response = LWP::UserAgent->new->get($self->uri_as_string);
+    return Facebook::Graph::Response->new(response => $response);
+}
+
+no Any::Moose;
+__PACKAGE__->meta->make_immutable;
+
+
+=head1 NAME
+
+Facebook::Graph::Session - Convert old API sessions into Graph API access_tokens.
+
+
+=head1 VERSION
+
+version 1.0300
+
+=head1 SYNOPSIS
+
+ my $fb = Facebook::Graph->new(
+    secret      => $facebook_application_secret,
+    app_id      => $facebook_application_id,
+    postback    => 'https://www.yourapplication.com/facebook/postback',
+ );
+ my $tokens = $fb->session(\@session_ids)->request->as_hashref;
+
+=head1 DESCRIPTION
+
+Allows you to request convert your old sessions into access tokens.
+
+B<NOTE:> If you're writing your application from scratch using L<Facebook::Graph> then you'll never need this module.
+
+=head1 METHODS
+
+=head2 uri_as_string ()
+
+Returns the URI that will be called to fetch the token as a string. Mostly useful for debugging and testing.
+
+=head2 request ()
+
+Makes a request to Facebook to fetch an access token. Returns a L<Facebook::Graph::Response> object. Example JSON response:
+
+=head1 LEGAL
+
+Facebook::Graph is Copyright 2010 Plain Black Corporation (L<http://www.plainblack.com>) and is licensed under the same terms as Perl itself.
+
+=cut
