The Internet Archive discovers and captures web pages through many different web crawls.
At any given time several distinct crawls are running, some for months, and some every day or longer.
View the web archive through the Wayback Machine.
Thanks to Lars D?????? for coordinating entries into the Plat_Forms 2012 web development contest. This annual contest pits some of the best developers of frameworks and languages against each other to solve real problems. Perl developers have participated for several years. Teams using Catalyst, Dancer, and Mojolicious have all demonstrated their platform strengths and weaknesses.
No Perl team has won the contest—yet. With the rise of modern Perl 5, the extra energy from competition between all of the great platforms, and (of course) the power of the CPAN, we all expect great things. Consider entering and showing what we can do.
Perl makes writing Twilio telephony applications simple and enjoyable. My
previous article, Automating Telephony with Perl and
Twilio
showed how to use
WWW::Twilio::API to make a
phone survey using Twilio's text-to-speech synthesizer as well as send an SMS
message to a phone number of your choice.
To begin, install WWW::Twilio::TwiML and Mojolicious using your favorite
method (see the previous article for
more ideas). You'll need a Twilio account (it's free
to create an account, plus Twilio gives new users US $30 for calls--plenty for
several weeks of testing). The previous article covers installation and getting
setup with a Twilio account in more detail. With WWW::Twilio::TwiML and
Mojolicious installed and a Twilio account active, it's a great time to get a
little more familiar with Twilio's Dashboard.
Twilio Dashboard
The Twilio Dashboard is where to find
your Twilio sandbox information. The sandbox section of the dashboard is
located below the fold of the dashboard page:
You should see the sandbox number and pin. You can set our inbound voice and
inbound SMS handler URLs there (I'll explain those soon.) First, a primer on
how Twilio works.
TwiML in the Twilio flow
Twilio's basic flow goes something like:
(This diagram is not an official Twilio diagram; it merely describes the author's mental model of how Twilio works and may differ wildly from Twilio's actual implementation.)
The caller dials (or sends an SMS to) "555-867-5309" on their phone--this is your Twilio sandbox or purchased number. Twilio's inbound call dispatcher receives the call or text.
Once the connection is made, the dispatcher makes an HTTP GET or POST to
the Voice or SMS URL specified given for this number. Remember the Voice URL in
the Sandbox App of the Twilio Dashboard shown above? That's the one. For
purchased Twilio numbers, you set the voice and SMS URLs under the "Numbers"
tab in the Dashboard.
The Voice or SMS URL specified in the Sandbox App responds to the Twilio
request with a TwiML document. Twilio's TwiML parser reads this document,
then executes the "verbs" specified in the TwiML document. For example, if the
TwiML document contained a <Say> verb, Twilio's
text-to-speech synthesizer would "read" the text to the caller. If the document
specified a <Dial> verb and number, Twilio would dial the
number and connect the caller to it. <Redirect> verbs tell
Twilio to fetch another TwiML document.
You may recall an example in the previous article which used Twilio's
voicemail TwiML handler to conduct
a brief phone survey. While you can sometimes manipulate third-party TwiML
applications to do what you want, TwiML is so simple to use that you'll find
it's often easier to write your own.
TwiML basics
TwiML is a subset of XML. Here is a TwiML document that when read by Twilio's
parser, will say to the caller, "Foosball at 10 o'clock!" using the
text-to-speech synthesizer:
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Gather action="/menu.cgi" numDigits="1" method="GET">
<Say voice="man">
Ping pong at high noon!
Hit 1 if you're with me.
Hit 2 if you're a loser.
</Say>
</Gather>
<Say>You must make a choice!</Say>
</Response>
The <Gather> verb tells Twilio to start gathering key
presses. Meanwhile, Twilio will hand off the contents of the
<Say> verb to the text-to-speech handler. Nesting the
<Say> inside of the <Gather> lets the
caller push a key anytime during the <Say> verb to interrupt
it and process your choice. The final <Say> element only
executes if the <Gather> fails (e.g., the caller doesn't
press a key).
Twilio's excellent documentation details all of the available TwiML
verbs. Armed with a little knowledge,
you're dangerouly close to making something useful.
Simple phone menu
You've been asked to build a phone menu system for a young urban professional
and his family. The application should accept an incoming call, prompt the
caller with a numeric menu, and connect the caller with the number of their
choice.
No problem. Start with a simple static TwiML document called menu.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Gather method="GET" action="/menu_handler" numDigits="1">
<Say>Press 1 for Ryan</Say>
<Say>Press 2 for Liz</Say>
<Say>Press 3 for Jason</Say>
<Say>Press 4 for Erin</Say>
<Say>Press 5 for Rachel</Say>
<Say>Press 6 for Gilligan</Say>
<Say>Press 7 for Potsie</Say>
</Gather>
</Response>
You can put this file on the web and update the URL in the "Voice URL" field of
the Sandbox section of the Dashboard. Anyone who dials the sandbox number, will
hear a Twilio's text-to-speech voice reading the menu options. Anybody remember
the "S.A.M." speech synthesizer from the mid 80's (Commodore 64 or Atari 800)?
You've come a long way, baby!
While this static TwiML file would work, it does mean you'll have two files to
update when a phone number changes. Fix that by consolidating the
/menu and /menu_handler "routes" (the Mojolicious
word for URL handlers) into a single program to generate TwiML dynamically.
WWW::Twilio::TwiML, briefly
WWW::Twilio::TwiML is a special-purpose XML generator and supports several
programming styles. For example, the following two code snippets create this
TwiML document:
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Say voice="man">Kilroy was here</Say>
</Response>
Snippet number 1:
my $say = WWW::Twilio::TwiML->new();
$say−>name('Say');
$say−>content("Kilroy was here");
$say−>attributes({voice => "man"});
my $resp = WWW::Twilio::TwiML->new();
$resp−>name('Response');
$resp−>content($say);
my $tw = WWW::Twilio::TwiML->new();
$tw−>content($resp);
print $tw−>to_string;
And snippet number 2:
my $tw = WWW::Twilio::TwiML->new();
$tw−>Response−>Say({voice => "man"}, "Kilroy was here");
print $tw−>to_string;
The second snippet uses a technique called "method chaining"; if you've used
the jQuery module for Javascript, you may already know how powerful chaining
object methods can be in certain contexts. WWW::Twilio::TwiML makes chaining
possible because each TwiML verb method is a constructor of another
WWW::Twilio::TwiML object.
When you chain TwiML objects like this:
$tw->Response->Say("Eat at Joe'");
The Response object is created as a child of the top
$tw object. The Say object is created as the child of
the Response object. When the $tw object's
to_string method is invoked, like this:
print $tw->to_string;
WWW:Twilio::TwiML crawls down $tw's list of children,
recursively invoking to_string until the last child. The whole
process creates this output:
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Say>Eat at Joe'</Say>
</Response>
It's may look a little foreign, but it makes for concise and readable TwiML.
Getting your mojo on
Now that you have a feel for creating TwiML documents, you need a way to serve
them from the web.
Mojolicious is an easy-to-use web application
framework. Just a few lines and you have a sweet little web app to serve TwiML.
Feel free to read a little of the Mojolicious documentation. This author highly
recommends going through the
Mojolicious::Lite documentation
first: almost everything you learn in Mojolicious::Lite also applies to the
larger Mojolicious application framework.
To write just enough Mojolicious to do what you've already done with the static
TwiML document, you need only two modules for this entire application. (Neither
has any dependencies--you're welcome.) Keep in mind that Mojolicious::Lite
enables 'warnings' and 'strict' by default: no sloppy programming allowed!
This application implements a Mojolicious handler for the /menu
route which is only called when the application receives an HTTP GET to the
/menu URI.
#!/usr/bin/env perl
use Mojolicious::Lite;
use WWW::Twilio::TwiML;
get '/menu' => sub {
my $self = shift;
$self->render(format => 'xml',
text => <<'_TWIML_');
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Gather method="GET" action="/menu_handler" numDigits="1">
<Say>Press 1 for Ryan</Say>
<Say>Press 2 for Liz</Say>
<Say>Press 3 for Jason</Say>
<Say>Press 4 for Erin</Say>
<Say>Press 5 for Rachel</Say>
<Say>Press 6 for Gilligan</Say>
<Say>Press 7 for Potsie</Say>
</Gather>
</Response>
_TWIML_
};
app->start;
That's all it takes for a Mojolicious application (source here).
Mojolicious packs a full stack HTTP 1.1 web server, making tests easy. In one
shell, start your Mojolicious program as a daemon (use Ctrl-c to stop when
finished):
$ perl menu_part daemon
[Mon Nov 14 21:41:34 2011] [info] Server listening (http://*:3000)
Server available at http://127.0.0.1:3000.
In another shell, pretend you're Twilio's application server and fetch the
TwiML:
$ curl http://localhost:3000/menu
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Gather method="GET" action="/menu_handler" numDigits="1">
<Say>Press 1 for Ryan</Say>
<Say>Press 2 for Liz</Say>
<Say>Press 3 for Jason</Say>
<Say>Press 4 for Erin</Say>
<Say>Press 5 for Rachel</Say>
<Say>Press 6 for Gilligan</Say>
<Say>Press 7 for Potsie</Say>
</Gather>
</Response>
Is this progress? This is same TwiML as in menu.xml, but now it's
created with Mojolicious. At this point you can upload your app to a publicly
accessible server, and, assuming Mojolicious is also installed there, you can
start your application. Then go to the Twilio Dashboard and replace the
existing Voice URL with:
http://your.server.org:3000/menu
Important note about Mojolicious and HTTP GET
Mojolicious's get method only responds to HTTP GET method
requests. Make sure that when you set the Voice URL in the Twilio Dashboard,
you also change the HTTP method to GET. Alternatively, you could use
Mojolicious's post method, which only responds to HTTP POST, or
the any method, which accepts both GET and POST (as well as
PUT and DELETE), but making Twilio use HTTP GET seems more appropriate.
Putting it all together
Now it's time to improve the program because it still serves static TwiML. It
also needs a programmatic way tell Twilio what to do when the caller presses a
key.
Start over and make a hash for the phone menu. This could be put into a
separate file--and probably should be--but it wouldn't be a proper tutorial
without something left as an exercise.
#!/usr/bin/env perl
use Mojolicious::Lite;
use WWW::Twilio::TwiML;
my %list = ( 1 => { name => 'Ryan',
number => '+19165557720' },
2 => { name => 'Liz',
number => '+19165551211' },
3 => { name => 'Jason',
number => '+19285550122' },
4 => { name => 'Erin',
number => '+19285551729' },
5 => { name => 'Rachel',
number => '+18015553992' },
6 => { name => 'Gilligan',
recording => 'http://www.televisiontunes.com/'
. 'themesongs/Gilligans%20Island.mp3' },
7 => { name => 'Potsie',
recording => 'http://www.televisiontunes.com/'
. 'themesongs/Happy%20Days%20-%20Season%202.mp3' },
);
get '/menu' => sub {
my $self = shift;
This should looks mostly familiar so far. Now create $msg which
holds all of the text you want Twilio to "Say" to the caller:
my $msg = join '. ',
map { "Press $_ for $list{$_}->{name}" }
sort keys %list;
It's time to build the TwiML document, and this could use some error handling
in case the caller doesn't press a key. Finally, print everything via
Mojolicious's render() method:
my $tw = WWW::Twilio::TwiML->new();
my $resp = $tw->Response;
$resp->Gather({action => $self->url_for('/menu_handler'),
method => 'GET',
numDigits => 1})
->Say({voice => 'woman'}, $msg);
$resp->Say("You need to make a choice or hang up.");
$resp->Redirect("/menu");
$self->render(format => 'xml',
text => $tw->to_string);
};
Remember to start Mojolicious's event loop; this code should always go at the
end of your application, as it never returns:
app->start;
(Source here). If declarative-style programming is new to you,
don't fret: under the hood, Mojolicious simply creates a map for itself that
says "when I receive an HTTP GET for '/menu', I should execute this
subroutine". The app->start routine begins a loop that waits
for said request, then handles it as you've defined (declared) it.
The menu handler route
Most of the hard work is done now. As specified in the Gather's
action attribute above, when the caller presses a key, Twilio will
perform an HTTP GET on /menu_handler. Add one more Mojolicious
route:
get '/menu_handler' => sub {
my $self = shift;
my $choice = $self->param('Digits') || 0;
my $tw = WWW::Twilio::TwiML->new();
my $resp = $tw->Response;
unless( exists $list{$choice} ) {
$resp->Say({voice => 'woman'},
"Sorry, that's not a valid option.");
$resp->Redirect({method => 'GET'}, "/menu");
$self->render(format => 'xml',
text => $tw->to_string);
return;
}
Twilio always passes a Digits parameter to URLs it fetches as a
result of a Gather action (see Twilio's Gather verb
documentation);
Digits contains the digit or digits pressed by the caller. HTTP
GET (and POST) parameters are available to Mojolicious through the
param() method.
The code then checks to see if the option the caller has selected exists. If it
doesn't, it generates a TwiML response to tell Twilio to Say to
the caller "Sorry, that's not a valid option." then sends a redirect back to
the main menu.
It's polite to let the caller know what's going on, so add a status message:
$resp->Say({voice => 'woman'},
"I'll try connecting you now.");
Remember that all this code does is build the TwiML response object; only
when the complete, stringified TwiML object is sent to Twilio's application
server does the document have any effect on the application flow.
The next step is to look up the caller's choice in the %list hash.
If the caller's selection had a phone number associated with it, create a
Dial, Play, or Say TwiML object,
depending on whether %list specifies a number to call, a URL to an
audio file to fetch and play, or neither (respectively):
Finally, invoke Mojolicious's render() method to create an XML
Content-type header and send the stringified TwiML object to
stdout (which Twilio's application server will read):
$self->render(format => 'xml',
text => $tw->to_string);
};
Here is the full source for your enjoyment. If you've already set
Twilio's Voice URL in uour Sandbox, nothing further needs to be done on
Twilio's side. Just upload the new application to the web server and start it
(Mojolicious supports a variety of deployment
options
including Morbo, CGI, FastCGI, or Plack).
You've made a simple phone menu here, but you've only learned a few of
Twilio's TwiML verbs. With
WWW::Twilio::API,
WWW::Twilio::TwiML, and
Mojolicious you can also create conference rooms, make
voice recordings, send and receive SMS messages, reject calls from unwanted
numbers, and do other useful actions in just a few lines of code.
Twilio allows developers to write applications that
can make and receive voice calls or SMS messages (though Twilio can do many
other interesting telephony things). Twilio’s RESTful API, text-to-speech
synthesizer, speech transcription services, and Javascript client make it easy
to knock out a conference call application, an in-browser customer service
voice application, a weather-by-SMS application, reminder by
phone—anything, really—in minutes. This article shows how to make a
couple of small applications, one to help you pronounce words correctly and the
other to transcribe awkward condiment phone survey answers.
Twilio Setup
First, head over to Twilio.com and click the
“Try Twilio Free” link. While inbound calls cost US $0.01 per minute
and outbound calls cost US $0.02 per minute, Twilio has historically
given new users a generous account balance to start with for free
(currently US $30)—it’s plenty of credit to kick the tires and take it
for a spin.
Go ahead and register (I’ll wait here). When you’ve finished, you’ll
have an account SID (beginning with “AC”) and an auth token, available
from your Twilio Dashboard. These are your Twilio API username and
password; you’ll need them for any API application you write.
Twilio Basics
The Twilio website is full of well-organized documentation and sample
applications. I recommend starting with “How It Works” (one of the
main navigation links on the home page). Browse the documentation
under “Docs” as well.
H. H. Munroe said, “A little inaccuracy sometimes saves tons of
explanation.” Keeping that in mind, inbound calls (calls to a Twilio
number) work like this:
Inbound calls to a Twilio number
1) the user calls “555-867-5309” on their phone
2) Twilio accepts the call, then makes an HTTP POST to
http://example.com/jenny.xml
3) example.com responds with a “TwiML” document (TwiML is a simple XML
language that describes how Twilio will interact with callers):
<?xml version="1.0" encoding="UTF-8" ?>
<Response>
<Say voice="woman">This is Jenny!</Say>
</Response>
4) Twilio’s TwiML parser and text-to-speech synthesizer read this
document and then says to the user (in a voice from the uncanny
valley), “This is Jenny!”
When you setup a sandbox number, you tell Twilio to map a URL to that
number. Twilio will GET/POST to that URL when receiving calls.
Outbound calls (calls from a Twilio number) work like this:
Outbound calls from a Twilio number
1) An application makes an HTTP POST to Twilio’s “Calls” API with the
parameters:
3) Once the user answers, Twilio retrieves the URL specified in the
POST (which should return a TwiML document)
4) Twilio parses the TwiML document and passes it to the
text-to-speech synthesizer
5) The synthesizer says to the user “This is Jenny!”
Twilio can also record voice input, transcribe it, send and receive
SMS messages, make conference calls, and a few other useful things,
all using the same familiar RESTful API and TwiML.
Twilio, meet Perl
CPAN makes writing Twilio applications easy, thanks to
WWW::Twilio::API. My
(current) favorite way to install CPAN modules comes from the Mojolicious
project:
curl -L cpanmin.us | perl - WWW::Twilio::API
cpanmin.us returns a Perl program which handles all of the build dependencies
for you. If you’re leery of running code from a website directly on the command
line, install App::cpanminus
and use its cpanm program instead.
If you’re like me and don’t want to mess up your clean development
environment, tell cpanmin.us or cpanm to install things into a
temporary location:
Notice the “401”? If you’re familiar with HTTP
status codes,
you might remember that 401 means “Unauthorized”. You either didn’t
present any authorization information, or it was incorrect. In this
case, it usually means the AccountSid or AuthToken are incorrect. Log
into Twilio.com, go to the Dashboard and make sure your AccountSid and
AuthToken are correct.
What else can we do?
Everything depends on what you put in for the Url parameter. You can
browse some of the free applications at Twilio
Labs, though most of those are for
inbound calls.
Here’s a silly example of using the voicemail Twimlet to conduct a
brief phone survey and have the callee’s response transcribed and
emailed. Start by changing the Url line in the POST:
my $email = 'you@example.com'; ## your email
my $msg = 'Please+tell+us+what+you+think+of+Tabasco+sauce';
my $response = $twilio->POST( 'Calls',
To => '+15556667777',
From => '+12223334444',
Url => "http://twimlets.com/voicemail?"
. "Email=$email&Message=$msg" );
Note that this Twimlet’s arguments are case-sensitive. ‘Email’ and
‘Message’ are not the same as ‘email’ and ‘message’. Make sure you use
the correct case.
Also, be sure to substitute your phone number for the To parameter and
your Twilio Sandbox phone number (also found on your Twilio Dashboard)
for the From parameter. Twilio phone numbers always use the
international calling prefix (e.g., United States numbers use “+1”
followed by the three digit area code followed by the seven digit
phone number).
When you run this, you’ll get a call from Twilio asking you to share
your insights into Tabasco sauce. Please be honest. Once you’ve given
your opinion, Twilio will then transcribe your message and email it to
the email address you specified.
I’m sending out an SMS
SMS messages are even easier: no TwiML needed. Instead of the Calls
API, use the SMS/Messages API:
my $response = $twilio->POST( 'SMS/Messages',
To => '+15556667777',
From => '+12223334444',
Body => 'Rescue me before '
. 'I fall into despair' );
That’s all you have to do to send an SMS message using Twilio (though
the 160 character limit applies).
Conclusion
Twilio and Perl make a potent pair: so much is possible with so little code.
The next installment will cover writing larger applications with TwiML.
Visit the home of the Perl programming language: Perl.org