diff --git a/lib/Telegram/Bot.pm b/lib/Telegram/Bot.pm
new file mode 100644
index 0000000..be9b43b
--- /dev/null
+++ b/lib/Telegram/Bot.pm
@@ -0,0 +1,90 @@
+package Telegram::Bot;
+$Telegram::Bot::VERSION = '0.021';
+use strict;
+use warnings;
+
+# ABSTRACT: A base class to make your very own Telegram bot
+
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot - A base class to make your very own Telegram bot
+
+=head1 VERSION
+
+version 0.021
+
+=head1 SYNOPSIS
+
+NOTE: This API should not yet be considered stable.
+
+Creating a bot is easy:
+
+ package MyBot;
+
+ use Mojo::Base 'Telegram::Bot::Brain';
+
+ has token => 'YOURTOKENHERE';
+
+ # send a polite reply, to either a group or a single user,
+ # depending on where we were addressed from
+ sub _be_polite {
+ my ($self, $msg) = @_;
+
+ return unless $msg->text =~ /hello/;
+
+ # is this a 1-on-1 ?
+ if ($msg->chat->is_user) {
+ $msg->reply("hello there");
+
+ # send them a picture as well
+ $self->sendPhoto({chat_id => $msg->chat->id, photo => $image_filename});
+ }
+ # group chat
+ else {
+ $msg->reply("hello to everyone!");
+ }
+ }
+
+ # setup our bot
+ sub init {
+ my $self = shift;
+ $self->add_listener(\&_be_polite);
+ }
+
+ 1;
+
+Now just:
+
+ perl -MMyBot -E 'MyBot->new->think'
+
+and you've got yourself a stew, baby! Or a bot, anyway.
+
+Note that for the bot to see messages that do not start with a leading '/', you will need to use
+the C<'/setprivacy'> command on Telegram's C<@botfather> interface to change the privacy settings.
+
+=head1 EXAMPLES
+
+This distribution's C directory contains some complete examples that may be
+instructive to look at.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Brain.pm b/lib/Telegram/Bot/Brain.pm
new file mode 100644
index 0000000..3a3123e
--- /dev/null
+++ b/lib/Telegram/Bot/Brain.pm
@@ -0,0 +1,395 @@
+package Telegram::Bot::Brain;
+$Telegram::Bot::Brain::VERSION = '0.021';
+# ABSTRACT: A base class to make your very own Telegram bot
+
+
+use Mojo::Base -base;
+
+use strict;
+use warnings;
+
+use Mojo::IOLoop;
+use Mojo::UserAgent;
+use Carp qw/croak/;
+use Log::Any;
+use Data::Dumper;
+
+use Telegram::Bot::Object::Message;
+
+# base class for building telegram robots with Mojolicious
+has longpoll_time => 60;
+has ua => sub { Mojo::UserAgent->new->inactivity_timeout(shift->longpoll_time + 15) };
+has token => sub { croak "you need to supply your own token"; };
+
+has tasks => sub { [] };
+has listeners => sub { [] };
+
+has log => sub { Log::Any->get_logger };
+
+
+sub add_repeating_task {
+ my $self = shift;
+ my $seconds = shift;
+ my $task = shift;
+
+ my $repeater = sub {
+
+ # Perform operation every $seconds seconds
+ my $last_check = time();
+ Mojo::IOLoop->recurring(0.1 => sub {
+ my $loop = shift;
+ my $now = time();
+ return unless ($now - $last_check) >= $seconds;
+ $last_check = $now;
+ $task->($self);
+ });
+ };
+
+ # keep a copy
+ push @{ $self->tasks }, $repeater;
+
+ # kick it off
+ $repeater->();
+}
+
+
+sub add_listener {
+ my $self = shift;
+ my $coderef = shift;
+
+ push @{ $self->listeners }, $coderef;
+}
+
+sub init {
+ die "init was not overridden!";
+}
+
+
+sub think {
+ my $self = shift;
+ $self->init();
+
+ $self->_add_getUpdates_handler;
+ Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
+}
+
+
+
+sub getMe {
+ my $self = shift;
+ my $token = $self->token || croak "no token?";
+
+ my $url = "https://api.telegram.org/bot${token}/getMe";
+ my $api_response = $self->_post_request($url);
+
+ return Telegram::Bot::Object::User->create_from_hash($api_response, $self);
+}
+
+
+sub sendMessage {
+ my $self = shift;
+ my $args = shift || {};
+
+ my $send_args = {};
+ croak "no chat_id supplied" unless $args->{chat_id};
+ $send_args->{chat_id} = $args->{chat_id};
+
+ croak "no text supplied" unless $args->{text};
+ $send_args->{text} = $args->{text};
+
+ # these are optional, send if they are supplied
+ $send_args->{parse_mode} = $args->{parse_mode} if exists $args->{parse_mode};
+ $send_args->{disable_web_page_preview} = $args->{disable_web_page_preview} if exists $args->{disable_web_page_preview};
+ $send_args->{disable_notification} = $args->{disable_notification} if exists $args->{disable_notification};
+ $send_args->{reply_to_message_id} = $args->{reply_to_message_id} if exists $args->{reply_to_message_id};
+
+ # check reply_markup is the right kind
+ if (exists $args->{reply_markup}) {
+ my $reply_markup = $args->{reply_markup};
+ die "bad reply_markup supplied"
+ if ( ref($reply_markup) ne 'Telegram::Bot::Object::InlineKeyboardMarkup' &&
+ ref($reply_markup) ne 'Telegram::Bot::Object::ReplyKeyboardMarkup' &&
+ ref($reply_markup) ne 'Telegram::Bot::Object::ReplyKeyboardRemove' &&
+ ref($reply_markup) ne 'Telegram::Bot::Object::ForceReply' );
+ $send_args->{reply_markup} = $reply_markup;
+ }
+
+ my $token = $self->token || croak "no token?";
+ my $url = "https://api.telegram.org/bot${token}/sendMessage";
+ my $api_response = $self->_post_request($url, $send_args);
+
+ return Telegram::Bot::Object::Message->create_from_hash($api_response, $self);
+}
+
+
+sub forwardMessage {
+ my $self = shift;
+ my $args = shift || {};
+ my $send_args = {};
+ croak "no chat_id supplied" unless $args->{chat_id};
+ $send_args->{chat_id} = $args->{chat_id};
+
+ croak "no from_chat_id supplied" unless $args->{from_chat_id};
+ $send_args->{from_chat_id} = $args->{from_chat_id};
+
+ croak "no message_id supplied" unless $args->{message_id};
+ $send_args->{message_id} = $args->{message_id};
+
+ # these are optional, send if they are supplied
+ $send_args->{disable_notification} = $args->{disable_notification} if exists $args->{disable_notification};
+
+ my $token = $self->token || croak "no token?";
+ my $url = "https://api.telegram.org/bot${token}/forwardMessage";
+ my $api_response = $self->_post_request($url, $send_args);
+
+ return Telegram::Bot::Object::Message->create_from_hash($api_response, $self);
+}
+
+
+sub sendPhoto {
+ my $self = shift;
+ my $args = shift || {};
+ my $send_args = {};
+
+ croak "no chat_id supplied" unless $args->{chat_id};
+ $send_args->{chat_id} = $args->{chat_id};
+
+ # photo can be a string (which might be either a URL for telegram servers
+ # to fetch, or a file_id string) or a file on disk to upload - we need
+ # to handle that last case here as it changes the way we create the HTTP
+ # request
+ croak "no photo supplied" unless $args->{photo};
+ if (-e $args->{photo}) {
+ $send_args->{photo} = { photo => { file => $args->{photo} } };
+ }
+ else {
+ $send_args->{photo} = $args->{photo};
+ }
+
+ my $token = $self->token || croak "no token?";
+ my $url = "https://api.telegram.org/bot${token}/sendPhoto";
+ my $api_response = $self->_post_request($url, $send_args);
+
+ return Telegram::Bot::Object::Message->create_from_hash($api_response, $self);
+}
+
+
+sub _add_getUpdates_handler {
+ my $self = shift;
+
+ my $http_active = 0;
+ my $last_update_id = -1;
+ my $token = $self->token;
+
+ Mojo::IOLoop->recurring(0.1 => sub {
+ # do nothing if our previous longpoll is still going
+ return if $http_active;
+
+ my $offset = $last_update_id + 1;
+ my $updateURL = "https://api.telegram.org/bot${token}/getUpdates?offset=${offset}&timeout=60";
+ $http_active = 1;
+
+ $self->ua->get($updateURL => sub {
+ my ($ua, $tx) = @_;
+ my $res = $tx->res->json;
+ my $items = $res->{result};
+ foreach my $item (@$items) {
+ $last_update_id = $item->{update_id};
+ $self->_process_message($item);
+ }
+
+ $http_active = 0;
+ });
+ });
+}
+
+# process a message which arrived via getUpdates
+sub _process_message {
+ my $self = shift;
+ my $item = shift;
+
+ my $update_id = $item->{update_id};
+ # There can be several types of responses. But only one response.
+ # https://core.telegram.org/bots/api#update
+ my $update;
+ $update = Telegram::Bot::Object::Message->create_from_hash($item->{message}, $self) if $item->{message};
+ $update = Telegram::Bot::Object::Message->create_from_hash($item->{edited_message}, $self) if $item->{edited_message};
+ $update = Telegram::Bot::Object::Message->create_from_hash($item->{channel_post}, $self) if $item->{channel_post};
+ $update = Telegram::Bot::Object::Message->create_from_hash($item->{edited_channel_post}, $self) if $item->{edited_channel_post};
+
+ # if we got to this point without creating a response, it must be a type we
+ # don't handle yet
+ if (! $update) {
+ die "Do not know how to handle this update: " . Dumper($item);
+ }
+
+ foreach my $listener (@{ $self->listeners }) {
+ # call the listener code, supplying ourself and the update
+ $listener->($self, $update);
+ }
+}
+
+
+sub _post_request {
+ my $self = shift;
+ my $url = shift;
+ my $form_args = shift || {};
+
+ my $res = $self->ua->post($url, form => $form_args)->result;
+ if ($res->is_success) { return $res->json->{result}; }
+ elsif ($res->is_error) { die "Failed to post: " . $res->message; }
+ else { die "Not sure what went wrong"; }
+}
+
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Brain - A base class to make your very own Telegram bot
+
+=head1 VERSION
+
+version 0.021
+
+=head1 SYNOPSIS
+
+ package MyApp::Coolbot;
+
+ use Mojo::Base 'Telegram::Bot::Brain';
+
+ has token => 'token-you-got-from-@botfather';
+
+ sub init {
+ my $self = shift;
+ $self->add_repeating_task(600, \&timed_task);
+ $self->add_listener(\&respond_to_messages);
+ }
+
+Elsewhere....
+
+ my $bot = MyApp::Coolbot->new();
+ $bot->think; # this will block unless there is already an event
+ # loop running
+
+=head1 DESCRIPTION
+
+This base class makes it easy to create your own Bot classes that
+interface with the Telegram Bot API.
+
+Internally it uses the Mojo::IOLoop event loop to provide non-blocking
+access to the Bot API, allowing your bot to listen for events via the
+longpoll getUpdates API method and also trigger timed events that can
+run without blocking.
+
+As with any bot framework, the principle is that the framework allows you
+to interact with other users on Telegram. The Telegram API provides a rich
+set of typed objects. This framework will allow you to create those objects
+to send into the API (for instance, sending text messages, sending photos,
+and more) as well as call your code (via L when your bot
+receives messages (which might be text, or images, and so on).
+
+How bots work with Telegram is out of scope for this document, a good
+starting place is L.
+
+=head1 METHODS
+
+=head2 add_repeating_task
+
+This method will add a sub to run every C<$seconds> seconds. Pass this method
+two parameters, the number of seconds between executions, and the coderef to
+execute.
+
+Your coderef will be passed the L object when it is
+executed.
+
+=head2 add_listener
+
+Respond to messages we receive. It takes a single argument, a coderef to execute
+for each update that is sent to us. These are *typically* C
+objects, though that is not the only type of update that may be sent (see
+L).
+
+Multiple listeners can be added, they will receive the incoming update in the order
+that they are registered.
+
+Any or all listeners can choose to ignore or take action on any particular update.
+
+=head2 think
+
+Start this bot thinking.
+
+Calls your init method and then enters a blocking loop (unless a Mojo::IOLoop
+is already running).
+
+=head2 getMe
+
+This is the wrapper around the C API method. See
+L.
+
+Takes no arguments, and returns the L that
+represents this bot.
+
+=head2 sendMessage
+
+See L.
+
+Returns a L object.
+
+=head2 forwardMessage
+
+See L.
+
+Returns a L object.
+
+=head2 sendPhoto
+
+See L.
+
+Returns a L object.
+
+=head1 SEE ALSO
+
+=over 4
+
+=item *
+
+L
+
+=item *
+
+L
+
+=back
+
+=head1 Telegram Bot API methods
+
+The following methods are relatively thin wrappers around the various
+methods available in the Telgram Bot API to send messages and perform other
+updates.
+
+L
+
+They all return immediately with the corresponding Telegram::Bot::Object
+subclass - consult the documenation for each below to see what to expect.
+
+Note that not all methods have yet been implemented.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Animation.pm b/lib/Telegram/Bot/Object/Animation.pm
new file mode 100644
index 0000000..ed3a625
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Animation.pm
@@ -0,0 +1,58 @@
+package Telegram::Bot::Object::Animation;
+$Telegram::Bot::Object::Animation::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'Animation' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::PhotoSize;
+use Carp qw/croak/;
+
+has 'file_id';
+has 'width';
+has 'height';
+has 'duration';
+has 'thumb'; #PhotoSize
+has 'file_name';
+has 'mime_type';
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id width height duration file_name mime_type file_size/],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/thumb/],
+ };
+}
+
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Animation - The base class for Telegram message 'Animation' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Audio.pm b/lib/Telegram/Bot/Object/Audio.pm
new file mode 100644
index 0000000..0e31238
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Audio.pm
@@ -0,0 +1,54 @@
+package Telegram::Bot::Object::Audio;
+$Telegram::Bot::Object::Audio::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Audio' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'file_id';
+has 'duration';
+has 'performer';
+has 'title';
+has 'mime_type';
+has 'file_size';
+has 'thumb'; #PhotoSize
+
+sub fields {
+ return { scalar => [qw/file_id duration performer title mime_type file_size/],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/thumb/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Audio - The base class for Telegram 'Audio' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Base.pm b/lib/Telegram/Bot/Object/Base.pm
new file mode 100644
index 0000000..503e7f0
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Base.pm
@@ -0,0 +1,180 @@
+package Telegram::Bot::Object::Base;
+$Telegram::Bot::Object::Base::VERSION = '0.021';
+# ABSTRACT: The base class for all Telegram::Bot::Object objects.
+
+
+use Mojo::Base -base;
+
+has '_brain'; # a reference to our brain
+
+
+sub arrays { qw// } # override if needed
+sub _field_is_array {
+ my $self = shift;
+ my $field = shift;
+ if (grep /^$field$/, $self->arrays) {
+ return 1;
+ }
+ return;
+}
+
+
+sub array_of_arrays { qw// } #override if needed
+sub _field_is_array_of_arrays {
+ my $self = shift;
+ my $field = shift;
+ if (grep /^$field$/, $self->array_of_arrays) {
+ return 1;
+ }
+ return;
+}
+
+
+# create an object from a hash. Needs to deal with the nested types, and
+# arrays
+sub create_from_hash {
+ my $class = shift;
+ my $hash = shift;
+ my $brain = shift || die "no brain supplied";
+ my $obj = $class->new(_brain => $brain);
+
+ # deal with each type of field
+ foreach my $type (keys %{ $class->fields }) {
+ my @fields_of_this_type = @{ $class->fields->{$type} };
+
+ foreach my $field (@fields_of_this_type) {
+
+ # ignore fields for which we have no value in the hash
+ next if (! defined $hash->{$field} );
+
+ # warn "type: $type field $field\n";
+ if ($type eq 'scalar') {
+ if ($obj->_field_is_array($field)) {
+ # simple scalar array ref, so just copy it
+ my $val = $hash->{$field};
+ # deal with boolean stuff so we don't pollute our object
+ # with JSON
+ if (ref($val) eq 'JSON::PP::Boolean') {
+ $val = !!$val;
+ }
+ $obj->$field($val);
+ }
+ elsif ($obj->_field_is_array_of_arrays) {
+ die "not yet implemented for scalars";
+ }
+ else {
+ my $val = $hash->{$field};
+ if (ref($val) eq 'JSON::PP::Boolean') {
+ $val = 0+$val;
+
+ }
+ $obj->$field($val);
+ }
+ }
+
+ else {
+ if ($obj->_field_is_array($field)) {
+ my @sub_array;
+ foreach my $data ( @{ $hash->{$field} } ) {
+ push @sub_array, $type->create_from_hash($data, $brain);
+ }
+ $obj->$field(\@sub_array);
+ }
+ elsif ($obj->_field_is_array_of_arrays) {
+ die "not yet implemented for scalars";
+ }
+ else {
+ $obj->$field($type->create_from_hash($hash->{$field}, $brain));
+ }
+
+ }
+ }
+ }
+
+ return $obj;
+}
+
+
+sub as_hashref {
+ my $self = shift;
+ my $hash = {};
+ # add the simple scalar values
+ foreach my $type ( keys %{ $self->fields }) {
+ my @fields = @{ $self->fields->{$type} };
+ foreach my $field (@fields) {
+ if ($type eq 'scalar') {
+ $hash->{$field} = $self->$field;
+ }
+ else {
+ # non array types
+ $hash->{$field} = $self->$field->as_hashref
+ if (ref($self->$field) ne 'ARRAY' && defined $self->$field);
+ # array types
+ $hash->{$field} = [
+ map { $_->as_hashref } @{ $self->$field }
+ ] if (ref($self->$field) eq 'ARRAY');
+ }
+ }
+ }
+ return $hash;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Base - The base class for all Telegram::Bot::Object objects.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+This class should not be instantiated itself. Instead, instantiate a sub-class.
+
+You should generally not need to instantiate objects of sub-classes of L,
+instead the appropriate objects will be created from an incoming request via
+L.
+
+You can then use the methods referenced below on those objects.
+
+=head1 METHODS
+
+=head2 arrays
+
+Should be overridden by subclasses, returning an array listing of which fields
+for the object are arrays.
+
+=head2 array_of_arrays
+
+Should be overridden by subclasses, returning an array listing od which fields
+for the object are arrays of arrays.
+
+=head2 create_from_hash
+
+Create an object of the appropriate class, including any sub-objects of
+other types, as needed.
+
+=head2 as_hashref
+
+Return this object as a hashref.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/CallbackGame.pm b/lib/Telegram/Bot/Object/CallbackGame.pm
new file mode 100644
index 0000000..f9eddd1
--- /dev/null
+++ b/lib/Telegram/Bot/Object/CallbackGame.pm
@@ -0,0 +1,47 @@
+package Telegram::Bot::Object::CallbackGame;
+$Telegram::Bot::Object::CallbackGame::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'CallbackGame' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+# https://core.telegram.org/bots/api#callbackgame
+# "A placeholder, currently holds no information. Use BotFather to set up your game"
+
+sub fields {
+ return { },
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::CallbackGame - The base class for Telegram message 'CallbackGame' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Chat.pm b/lib/Telegram/Bot/Object/Chat.pm
new file mode 100644
index 0000000..d894c6e
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Chat.pm
@@ -0,0 +1,87 @@
+package Telegram::Bot::Object::Chat;
+$Telegram::Bot::Object::Chat::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Chat' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::ChatPhoto;
+use Telegram::Bot::Object::Message;
+
+has 'id';
+has 'type';
+has 'title';
+has 'username';
+has 'first_name';
+has 'last_name';
+has 'all_members_are_administrators';
+has 'photo'; #ChatPhoto
+has 'description';
+has 'invite_link';
+has 'pinned_message'; #Message
+has 'sticker_set_name';
+has 'can_set_sticker_set';
+
+sub fields {
+ return {
+ 'scalar' => [qw/id type title username first_name
+ last_name all_members_are_administrators
+ description invite_link sticker_set_name
+ can_set_sticker_set/],
+ 'Telegram::Bot::Object::ChatPhoto' => [qw/photo/],
+ 'Telegram::Bot::Object::Message' => [qw/pinned_message/],
+ };
+}
+
+
+sub is_user {
+ shift->id > 0;
+}
+
+
+sub is_group {
+ shift->id < 0;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Chat - The base class for Telegram 'Chat' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 METHODS
+
+=head2 is_user
+
+Returns true is this is a chat is a single user.
+
+=head2 is_group
+
+Returns true if this is a chat is a group.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/ChatPhoto.pm b/lib/Telegram/Bot/Object/ChatPhoto.pm
new file mode 100644
index 0000000..e4bb2ae
--- /dev/null
+++ b/lib/Telegram/Bot/Object/ChatPhoto.pm
@@ -0,0 +1,49 @@
+package Telegram::Bot::Object::ChatPhoto;
+$Telegram::Bot::Object::ChatPhoto::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'ChatPhoto' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'small_file_id';
+has 'big_file_id';
+
+sub fields {
+ return {
+ 'scalar' => [qw/small_file_id big_file_id/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::ChatPhoto - The base class for Telegram 'ChatPhoto' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Contact.pm b/lib/Telegram/Bot/Object/Contact.pm
new file mode 100644
index 0000000..444d97e
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Contact.pm
@@ -0,0 +1,50 @@
+package Telegram::Bot::Object::Contact;
+$Telegram::Bot::Object::Contact::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Contact' objects.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'phone_number';
+has 'first_name';
+has 'last_name';
+has 'user_id';
+
+sub fields {
+ return { scalar => [qw/phone_number first_name last_name user_id/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Contact - The base class for Telegram 'Contact' objects.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Document.pm b/lib/Telegram/Bot/Object/Document.pm
new file mode 100644
index 0000000..505ff5e
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Document.pm
@@ -0,0 +1,54 @@
+package Telegram::Bot::Object::Document;
+$Telegram::Bot::Object::Document::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Document' objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+use Telegram::Bot::Object::PhotoSize;
+
+has 'file_id';
+has 'thumb'; #PhotoSize
+has 'file_name';
+has 'mime_type';
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id file_name mime_type file_size/],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/thumb/]
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Document - The base class for Telegram 'Document' objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/EncryptedCredentials.pm b/lib/Telegram/Bot/Object/EncryptedCredentials.pm
new file mode 100644
index 0000000..c2425d8
--- /dev/null
+++ b/lib/Telegram/Bot/Object/EncryptedCredentials.pm
@@ -0,0 +1,48 @@
+package Telegram::Bot::Object::EncryptedCredentials;
+$Telegram::Bot::Object::EncryptedCredentials::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'EncryptedCredentials' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'data';
+has 'hash';
+has 'secret';
+
+sub fields {
+ return { 'scalar' => [qw/ data hash secret/] };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::EncryptedCredentials - The base class for Telegram 'EncryptedCredentials' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/EncryptedPassportElement.pm b/lib/Telegram/Bot/Object/EncryptedPassportElement.pm
new file mode 100644
index 0000000..5eac539
--- /dev/null
+++ b/lib/Telegram/Bot/Object/EncryptedPassportElement.pm
@@ -0,0 +1,56 @@
+package Telegram::Bot::Object::EncryptedPassportElement;
+$Telegram::Bot::Object::EncryptedPassportElement::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'EncryptedPassportElement' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+# XXX Implement rest of this
+# https://core.telegram.org/bots/api#encryptedpassportelement
+
+has 'type';
+has 'data';
+has 'phone_number';
+has 'email';
+
+# XXX more here
+
+sub fields {
+ return { 'scalar' => [qw/type data phone_number email/] };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::EncryptedPassportElement - The base class for Telegram 'EncryptedPassportElement' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+Note that this type is not yet fully implemented.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Game.pm b/lib/Telegram/Bot/Object/Game.pm
new file mode 100644
index 0000000..0a99e9d
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Game.pm
@@ -0,0 +1,60 @@
+package Telegram::Bot::Object::Game;
+$Telegram::Bot::Object::Game::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'Game' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::PhotoSize;
+use Telegram::Bot::Object::Animation;
+use Telegram::Bot::Object::MessageEntity;
+
+has 'title';
+has 'description';
+has 'photo'; # Array of PhotoSize
+has 'text';
+has 'text_entities'; #Array of MessageEntity
+has 'animation'; #Animation
+
+sub fields {
+ return { scalar => [qw/title description text/],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/photo/],
+ 'Telegram::Bot::Object::MessageEntity' => [qw/text_entities/],
+ 'Telegram::Bot::Object::Animation' => [qw/animation/],
+ };
+}
+
+sub arrays { qw/photo text_entities/ }
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Game - The base class for Telegram message 'Game' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/InlineKeyboardButton.pm b/lib/Telegram/Bot/Object/InlineKeyboardButton.pm
new file mode 100644
index 0000000..6f02559
--- /dev/null
+++ b/lib/Telegram/Bot/Object/InlineKeyboardButton.pm
@@ -0,0 +1,60 @@
+package Telegram::Bot::Object::InlineKeyboardButton;
+$Telegram::Bot::Object::InlineKeyboardButton::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'InlineKeyboardButton' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::LoginUrl;
+use Telegram::Bot::Object::CallbackGame;
+
+has 'text';
+has 'url';
+has 'login_url'; #LoginUrl
+has 'callback_data';
+has 'switch_inline_query';
+has 'switch_inline_query_current_chat';
+has 'callback_game'; # CallbackGame
+has 'pay';
+
+sub fields {
+ return { 'scalar' => [qw/text url callback_data switch_inline_query
+ switch_inline_query_current_chat switch_inline_query_current_chat
+ pay/],
+ 'Telegram::Bot::Object::LoginUrl' => [qw/login_url/],
+ 'Telegram::Bot::Object::CallbackGame'=> [qw/callback_game/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::InlineKeyboardButton - The base class for Telegram 'InlineKeyboardButton' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/InlineKeyboardMarkup.pm b/lib/Telegram/Bot/Object/InlineKeyboardMarkup.pm
new file mode 100644
index 0000000..03e4c87
--- /dev/null
+++ b/lib/Telegram/Bot/Object/InlineKeyboardMarkup.pm
@@ -0,0 +1,52 @@
+package Telegram::Bot::Object::InlineKeyboardMarkup;
+$Telegram::Bot::Object::InlineKeyboardMarkup::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'InlineKeyboardMarkup' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::InlineKeyboardButton;
+
+has 'inline_keyboard';
+
+sub fields {
+ return { 'Telegram::Bot::Object::InlineKeyboardButton' => [qw/inline_keyboard/],
+ };
+}
+
+sub array_of_arrays {
+ qw/inline_keyboard/;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::InlineKeyboardMarkup - The base class for Telegram 'InlineKeyboardMarkup' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Invoice.pm b/lib/Telegram/Bot/Object/Invoice.pm
new file mode 100644
index 0000000..c90de67
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Invoice.pm
@@ -0,0 +1,51 @@
+package Telegram::Bot::Object::Invoice;
+$Telegram::Bot::Object::Invoice::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Invoice' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'title';
+has 'description';
+has 'start_parameter';
+has 'currency';
+has 'total_amount';
+
+sub fields {
+ return { scalar => [qw/title description start_parameter currency total_amount/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Invoice - The base class for Telegram 'Invoice' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Location.pm b/lib/Telegram/Bot/Object/Location.pm
new file mode 100644
index 0000000..4799290
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Location.pm
@@ -0,0 +1,48 @@
+package Telegram::Bot::Object::Location;
+$Telegram::Bot::Object::Location::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'Location' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'longitude';
+has 'latitude';
+
+sub fields {
+ return { scalar => [qw/longitude latitude/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Location - The base class for Telegram message 'Location' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/LoginUrl.pm b/lib/Telegram/Bot/Object/LoginUrl.pm
new file mode 100644
index 0000000..a498dad
--- /dev/null
+++ b/lib/Telegram/Bot/Object/LoginUrl.pm
@@ -0,0 +1,49 @@
+package Telegram::Bot::Object::LoginUrl;
+$Telegram::Bot::Object::LoginUrl::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'LoginUrl' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'url';
+has 'forward_text';
+has 'bot_username';
+has 'request_write_access';
+
+sub fields {
+ return { 'scalar' => [qw/url forward_text bot_username request_write_access/] };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::LoginUrl - The base class for Telegram 'LoginUrl' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Message.pm b/lib/Telegram/Bot/Object/Message.pm
new file mode 100644
index 0000000..9fe3d10
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Message.pm
@@ -0,0 +1,178 @@
+package Telegram::Bot::Object::Message;
+$Telegram::Bot::Object::Message::VERSION = '0.021';
+# ABSTRACT: The base class for the Telegram type "Message".
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+use Telegram::Bot::Object::User;
+use Telegram::Bot::Object::Chat;
+use Telegram::Bot::Object::MessageEntity;
+use Telegram::Bot::Object::Audio;
+use Telegram::Bot::Object::Document;
+use Telegram::Bot::Object::Animation;
+use Telegram::Bot::Object::Game;
+use Telegram::Bot::Object::PhotoSize;
+use Telegram::Bot::Object::Sticker;
+use Telegram::Bot::Object::Video;
+use Telegram::Bot::Object::Voice;
+use Telegram::Bot::Object::VideoNote;
+use Telegram::Bot::Object::Contact;
+use Telegram::Bot::Object::Location;
+use Telegram::Bot::Object::Poll;
+use Telegram::Bot::Object::Location;
+use Telegram::Bot::Object::PhotoSize;
+use Telegram::Bot::Object::Invoice;
+use Telegram::Bot::Object::Venue;
+use Telegram::Bot::Object::SuccessfulPayment;
+use Telegram::Bot::Object::PassportData;
+use Telegram::Bot::Object::InlineKeyboardMarkup;
+
+use Data::Dumper;
+
+# basic message stuff
+has 'message_id';
+has 'from'; # User
+has 'date';
+has 'chat'; # Chat
+
+has 'forward_from'; # User
+has 'forward_from_chat'; # Chat
+has 'forward_from_message_id';
+has 'forward_signature';
+has 'forward_sender_name';
+has 'forward_date';
+
+has 'reply_to_message'; # Message
+has 'edit_date';
+has 'media_group_id';
+has 'author_signature';
+has 'text';
+has 'entities'; # Array of MessageEntity
+
+has 'caption_entities'; # Array of MessageEntity
+
+has 'audio'; # Audio
+has 'document'; # Document
+has 'animation'; # Animation
+has 'game'; # Game
+has 'photo'; # Array of PhotoSize
+has 'sticker'; # Sticker
+has 'video'; # Video
+has 'voice'; # Voice
+has 'video_note'; # VideoNote
+has 'caption';
+has 'contact'; # Contact
+has 'location'; # Location
+has 'venue'; # Venue
+has 'poll'; # Poll
+has 'new_chat_members'; # Array of User
+has 'left_chat_member'; # User
+has 'new_chat_title';
+has 'new_chat_photo'; # Array of PhotoSize
+has 'delete_chat_photo';
+has 'group_chat_created';
+has 'supergroup_chat_created';
+has 'channel_chat_created';
+has 'migrate_to_chat_id';
+has 'migrate_from_chat_id';
+has 'pinned_message'; # Message
+has 'invoice'; # Invoice
+has 'successful_payment'; # SuccessfulPayment
+has 'connected_website';
+has 'passport_data'; # PassportData
+has 'reply_markup'; # Array of InlineKeyboardMarkup
+
+sub fields {
+ return {
+ 'scalar' => [qw/message_id date forward_from_message_id
+ forward_signature forward_sender_name
+ forward_date edit_date media_group_id
+ author_signature text caption
+ new_chat_title delete_chat_photo
+ group_chat_created supergroup_chat_created
+ channel_chat_created migrate_to_chat_id
+ migrate_from_chat_id connected_website/],
+ 'Telegram::Bot::Object::User' => [qw/from forward_from new_chat_members left_chat_member /],
+
+ 'Telegram::Bot::Object::Chat' => [qw/chat forward_from_chat/],
+ 'Telegram::Bot::Object::Message' => [qw/reply_to_message pinned_message/],
+ 'Telegram::Bot::Object::MessageEntity' => [qw/entities caption_entities /],
+
+ 'Telegram::Bot::Object::Audio' => [qw/audio/],
+ 'Telegram::Bot::Object::Document' => [qw/document/],
+ 'Telegram::Bot::Object::Animation' => [qw/animation/],
+ 'Telegram::Bot::Object::Game' => [qw/game/],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/photo new_chat_photo/],
+ 'Telegram::Bot::Object::Sticker' => [qw/sticker/],
+ 'Telegram::Bot::Object::Video' => [qw/video/],
+ 'Telegram::Bot::Object::Voice' => [qw/voice/],
+ 'Telegram::Bot::Object::VideoNote' => [qw/video_note/],
+
+ 'Telegram::Bot::Object::Contact' => [qw/contact/],
+ 'Telegram::Bot::Object::Location' => [qw/location/],
+ 'Telegram::Bot::Object::Venue' => [qw/venue/],
+
+ 'Telegram::Bot::Object::Poll' => [qw/poll/],
+
+ 'Telegram::Bot::Object::Invoice' => [qw/invoice/],
+ 'Telegram::Bot::Object::SuccessfulPayment' => [qw/successful_payment/],
+ 'Telegram::Bot::Object::PassportData' => [qw/passport_data/],
+ 'Telegram::Bot::Object::InlineKeyboardMarkup' => [qw/reply_markup/],
+
+ };
+}
+
+sub arrays {
+ qw/photo entities caption_entities new_chat_members new_chat_photo/
+}
+
+
+sub reply {
+ my $self = shift;
+ my $text = shift;
+ return $self->_brain->sendMessage({chat_id => $self->chat->id, text => $text});
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Message - The base class for the Telegram type "Message".
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 METHODS
+
+=head2
+
+A convenience method to reply to a message with text.
+
+Will return the L object representing the message
+sent.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/MessageEntity.pm b/lib/Telegram/Bot/Object/MessageEntity.pm
new file mode 100644
index 0000000..a3c3979
--- /dev/null
+++ b/lib/Telegram/Bot/Object/MessageEntity.pm
@@ -0,0 +1,54 @@
+package Telegram::Bot::Object::MessageEntity;
+$Telegram::Bot::Object::MessageEntity::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'MessageEntity' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::User;
+
+has 'type';
+has 'offset';
+has 'length';
+has 'url';
+has 'user'; #User
+
+sub fields {
+ return {
+ 'scalar' => [qw/type offset length url/],
+ 'Telegram::Bot::Object::User' => [qw/user/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::MessageEntity - The base class for Telegram 'MessageEntity' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/PassportData.pm b/lib/Telegram/Bot/Object/PassportData.pm
new file mode 100644
index 0000000..be76af6
--- /dev/null
+++ b/lib/Telegram/Bot/Object/PassportData.pm
@@ -0,0 +1,54 @@
+package Telegram::Bot::Object::PassportData;
+$Telegram::Bot::Object::PassportData::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'PassportData' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::EncryptedPassportElement;
+use Telegram::Bot::Object::EncryptedCredentials;
+
+has 'data'; # Array of EncryptedPassportElement
+has 'credentials'; # EncryptedCredentials
+
+sub fields {
+ return { 'Telegram::Bot::Object::EncryptedPassportElement' => [qw/data/],
+ 'Telegram::Bot::Object::EncryptedCredentials' => [qw/credentials/],
+ };
+}
+sub arrays {
+ qw/data/;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::PassportData - The base class for Telegram 'PassportData' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/PhotoSize.pm b/lib/Telegram/Bot/Object/PhotoSize.pm
new file mode 100644
index 0000000..12af197
--- /dev/null
+++ b/lib/Telegram/Bot/Object/PhotoSize.pm
@@ -0,0 +1,51 @@
+package Telegram::Bot::Object::PhotoSize;
+$Telegram::Bot::Object::PhotoSize::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'PhotoSize' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Carp qw/croak/;
+
+has 'file_id';
+has 'width';
+has 'height';
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id width height file_size/]
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::PhotoSize - The base class for Telegram message 'PhotoSize' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Poll.pm b/lib/Telegram/Bot/Object/Poll.pm
new file mode 100644
index 0000000..13f0489
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Poll.pm
@@ -0,0 +1,58 @@
+package Telegram::Bot::Object::Poll;
+$Telegram::Bot::Object::Poll::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Poll' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::PollOption;
+
+
+has 'id';
+has 'question';
+has 'options'; # Array of PollOption
+has 'is_closed';
+
+sub fields {
+ return { scalar => [qw/id question is_closed/],
+ 'Telegram::Bot::Object::PollOption' => [qw/options /],
+
+ };
+}
+
+sub arrays {
+ qw/options/;
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Poll - The base class for Telegram 'Poll' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/PollOption.pm b/lib/Telegram/Bot/Object/PollOption.pm
new file mode 100644
index 0000000..347b537
--- /dev/null
+++ b/lib/Telegram/Bot/Object/PollOption.pm
@@ -0,0 +1,48 @@
+package Telegram::Bot::Object::PollOption;
+$Telegram::Bot::Object::PollOption::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'PollOption' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'text';
+has 'voter_count';
+
+sub fields {
+ return { scalar => [qw/text voter_count/],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::PollOption - The base class for Telegram 'PollOption' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Sticker.pm b/lib/Telegram/Bot/Object/Sticker.pm
new file mode 100644
index 0000000..12d3e23
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Sticker.pm
@@ -0,0 +1,57 @@
+package Telegram::Bot::Object::Sticker;
+$Telegram::Bot::Object::Sticker::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'Sticker' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::PhotoSize;
+
+has 'file_id';
+has 'width';
+has 'height';
+has 'thumb'; # PhotoSize
+has 'emoji';
+has 'set_name';
+# has 'mask_position'; # XXX TODO
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id width height emoji
+ set_name file_size /],
+ 'Telegram::Bot::Object::PhotoSize' => [ qw/thumb/ ],
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Sticker - The base class for Telegram message 'Sticker' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/SuccessfulPayment.pm b/lib/Telegram/Bot/Object/SuccessfulPayment.pm
new file mode 100644
index 0000000..f637908
--- /dev/null
+++ b/lib/Telegram/Bot/Object/SuccessfulPayment.pm
@@ -0,0 +1,57 @@
+package Telegram::Bot::Object::SuccessfulPayment;
+$Telegram::Bot::Object::SuccessfulPayment::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'SuccessfulPayment' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+# use Telegram::Bot::Object::OrderInfo;
+
+has 'currency';
+has 'total_amount';
+has 'invoice_payload';
+has 'shipping_option_id';
+# has 'order_info'; #OrderInfo XXX
+has 'telegram_payment_charge_id';
+has 'provider_payment_charge_id';
+
+sub fields {
+ return { scalar => [qw/currency total_amount invoice_payload shipping_option_id
+ telegram_payment_charge_id provider_payment_charge_id/],
+ # 'Telegram::Bot::Object::OrderInfo' => [qw/order_info/],
+
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::SuccessfulPayment - The base class for Telegram 'SuccessfulPayment' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/User.pm b/lib/Telegram/Bot/Object/User.pm
new file mode 100644
index 0000000..78dfe4f
--- /dev/null
+++ b/lib/Telegram/Bot/Object/User.pm
@@ -0,0 +1,52 @@
+package Telegram::Bot::Object::User;
+$Telegram::Bot::Object::User::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram message 'User' type.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'id';
+has 'is_bot';
+has 'first_name';
+has 'last_name'; # optional
+has 'username'; # optional
+has 'language_code'; # optional
+
+sub fields {
+ return { scalar => [qw/id is_bot first_name last_name username language_code/]
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::User - The base class for Telegram message 'User' type.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Venue.pm b/lib/Telegram/Bot/Object/Venue.pm
new file mode 100644
index 0000000..369e2b7
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Venue.pm
@@ -0,0 +1,54 @@
+package Telegram::Bot::Object::Venue;
+$Telegram::Bot::Object::Venue::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'LoginUrl' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::Location;
+
+has 'location'; #Location
+has 'title';
+has 'address';
+has 'foursquare_id';
+has 'foursquare_type';
+
+sub fields {
+ return { 'scalar' => [qw/title address
+ foursquare_id foursquare_type/],
+ 'Telegram::Bot::Object::Location' => [qw/location/] };
+
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Venue - The base class for Telegram 'LoginUrl' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Video.pm b/lib/Telegram/Bot/Object/Video.pm
new file mode 100644
index 0000000..891db9b
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Video.pm
@@ -0,0 +1,56 @@
+package Telegram::Bot::Object::Video;
+$Telegram::Bot::Object::Video::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Video' object.
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::PhotoSize;
+
+has 'file_id';
+has 'width';
+has 'height';
+has 'duration';
+has 'thumb'; #PhotoSize
+has 'mime_type';
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id width height duration
+ mime_type file_size /],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/thumb/]
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Video - The base class for Telegram 'Video' object.
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/VideoNote.pm b/lib/Telegram/Bot/Object/VideoNote.pm
new file mode 100644
index 0000000..acd31c6
--- /dev/null
+++ b/lib/Telegram/Bot/Object/VideoNote.pm
@@ -0,0 +1,55 @@
+package Telegram::Bot::Object::VideoNote;
+$Telegram::Bot::Object::VideoNote::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'VideoNote' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+use Telegram::Bot::Object::PhotoSize;
+
+has 'file_id';
+has 'length';
+has 'duration';
+has 'mime_type';
+has 'thumb'; #PhotoSize
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id length duration mime_type file_size/],
+ 'Telegram::Bot::Object::PhotoSize' => [qw/thumb /],
+
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::VideoNote - The base class for Telegram 'VideoNote' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
diff --git a/lib/Telegram/Bot/Object/Voice.pm b/lib/Telegram/Bot/Object/Voice.pm
new file mode 100644
index 0000000..f56fc10
--- /dev/null
+++ b/lib/Telegram/Bot/Object/Voice.pm
@@ -0,0 +1,50 @@
+package Telegram::Bot::Object::Voice;
+$Telegram::Bot::Object::Voice::VERSION = '0.021';
+# ABSTRACT: The base class for Telegram 'Voice' type objects
+
+
+use Mojo::Base 'Telegram::Bot::Object::Base';
+
+has 'file_id';
+has 'duration';
+has 'mime_type';
+has 'file_size';
+
+sub fields {
+ return { scalar => [qw/file_id duration mime_type file_size/]
+ };
+}
+
+1;
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Telegram::Bot::Object::Voice - The base class for Telegram 'Voice' type objects
+
+=head1 VERSION
+
+version 0.021
+
+=head1 DESCRIPTION
+
+See L for details of the
+attributes available for L objects.
+
+=head1 AUTHOR
+
+Justin Hawkins
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2019 by Justin Hawkins.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut