biblesearch / mojo / lib / Mojolicious.pm /
Newer Older
957 lines | 21.881kb
add files
Yuki Kimoto authored on 2014-03-26
1
package Mojolicious;
2
use Mojo::Base 'Mojo';
3

            
4
# "Fry: Shut up and take my money!"
5
use Carp 'croak';
6
use Mojo::Exception;
7
use Mojo::Util qw(decamelize deprecated);
8
use Mojolicious::Commands;
9
use Mojolicious::Controller;
10
use Mojolicious::Plugins;
11
use Mojolicious::Renderer;
12
use Mojolicious::Routes;
13
use Mojolicious::Sessions;
14
use Mojolicious::Static;
15
use Mojolicious::Types;
16
use Mojolicious::Validator;
17
use Scalar::Util qw(blessed weaken);
18
use Time::HiRes 'gettimeofday';
19

            
20
has commands => sub {
21
  my $commands = Mojolicious::Commands->new(app => shift);
22
  weaken $commands->{app};
23
  return $commands;
24
};
25
has controller_class => 'Mojolicious::Controller';
26
has mode => sub { $ENV{MOJO_MODE} || $ENV{PLACK_ENV} || 'development' };
27
has moniker  => sub { decamelize ref shift };
28
has plugins  => sub { Mojolicious::Plugins->new };
29
has renderer => sub { Mojolicious::Renderer->new };
30
has routes   => sub { Mojolicious::Routes->new };
31
has secret   => sub {
32
  my $self = shift;
33

            
34
  # Warn developers about insecure default
35
  $self->log->debug('Your secret passphrase needs to be changed!!!');
36

            
37
  # Default to moniker
38
  return $self->moniker;
39
};
40
has sessions  => sub { Mojolicious::Sessions->new };
41
has static    => sub { Mojolicious::Static->new };
42
has types     => sub { Mojolicious::Types->new };
43
has validator => sub { Mojolicious::Validator->new };
44

            
45
our $CODENAME = 'Top Hat';
46
our $VERSION  = '4.57';
47

            
48
sub AUTOLOAD {
49
  my $self = shift;
50

            
51
  my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
52
  croak "Undefined subroutine &${package}::$method called"
53
    unless blessed $self && $self->isa(__PACKAGE__);
54

            
55
  # Call helper with fresh controller
56
  croak qq{Can't locate object method "$method" via package "$package"}
57
    unless my $helper = $self->renderer->helpers->{$method};
58
  return $self->controller_class->new(app => $self)->$helper(@_);
59
}
60

            
61
sub DESTROY { }
62

            
63
sub new {
64
  my $self = shift->SUPER::new(@_);
65

            
66
  my $home = $self->home;
67
  push @{$self->renderer->paths}, $home->rel_dir('templates');
68
  push @{$self->static->paths},   $home->rel_dir('public');
69

            
70
  # Default to application namespace
71
  my $r = $self->routes->namespaces([ref $self]);
72

            
73
  # Hide controller attributes/methods and "handler"
74
  $r->hide(qw(app continue cookie finish flash handler match on param));
75
  $r->hide(qw(redirect_to render render_exception render_later render_maybe));
76
  $r->hide(qw(render_not_found render_static rendered req res respond_to));
77
  $r->hide(qw(send session signed_cookie stash tx url_for validation write));
78
  $r->hide(qw(write_chunk));
79

            
80
  # Check if we have a log directory
81
  my $mode = $self->mode;
82
  $self->log->path($home->rel_file("log/$mode.log"))
83
    if -w $home->rel_file('log');
84

            
85
  $self->plugin($_)
86
    for qw(HeaderCondition DefaultHelpers TagHelpers EPLRenderer EPRenderer);
87

            
88
  # Exception handling should be first in chain
89
  $self->hook(around_dispatch => \&_exception);
90

            
91
  # Reduced log output outside of development mode
92
  $self->log->level('info') unless $mode eq 'development';
93

            
94
  # DEPRECATED in Top Hat!
95
  if (my $sub = $self->can("${mode}_mode")) {
96
    deprecated qq{"sub ${mode}_mode {...}" in application class is DEPRECATED};
97
    $self->$sub;
98
  }
99

            
100
  $self->startup;
101

            
102
  return $self;
103
}
104

            
105
sub build_tx {
106
  my $self = shift;
107
  my $tx   = Mojo::Transaction::HTTP->new;
108
  $self->plugins->emit_hook(after_build_tx => $tx, $self);
109
  return $tx;
110
}
111

            
112
sub defaults { shift->_dict(defaults => @_) }
113

            
114
sub dispatch {
115
  my ($self, $c) = @_;
116

            
117
  # Prepare transaction
118
  my $tx = $c->tx;
119
  $tx->res->code(undef) if $tx->is_websocket;
120
  $self->sessions->load($c);
121
  my $plugins = $self->plugins->emit_hook(before_dispatch => $c);
122

            
123
  # Try to find a static file
124
  $self->static->dispatch($c) and $plugins->emit_hook(after_static => $c)
125
    unless $tx->res->code;
126

            
127
  # Start timer (ignore static files)
128
  my $stash = $c->stash;
129
  unless ($stash->{'mojo.static'} || $stash->{'mojo.started'}) {
130
    my $req    = $c->req;
131
    my $method = $req->method;
132
    my $path   = $req->url->path->to_abs_string;
133
    $self->log->debug(qq{$method "$path".});
134
    $stash->{'mojo.started'} = [gettimeofday];
135
  }
136

            
137
  # Routes
138
  $plugins->emit_hook(before_routes => $c);
139
  my $res = $tx->res;
140
  return if $res->code;
141
  if (my $code = ($tx->req->error)[1]) { $res->code($code) }
142
  elsif ($tx->is_websocket) { $res->code(426) }
143
  $c->render_not_found unless $self->routes->dispatch($c) || $tx->res->code;
144
}
145

            
146
sub handler {
147
  my ($self, $tx) = @_;
148

            
149
  # Embedded application
150
  my $stash = {};
151
  if (my $sub = $tx->can('stash')) { ($stash, $tx) = ($tx->$sub, $tx->tx) }
152
  $stash->{'mojo.secret'} //= $self->secret;
153

            
154
  # Build default controller
155
  my $defaults = $self->defaults;
156
  @{$stash}{keys %$defaults} = values %$defaults;
157
  my $c
158
    = $self->controller_class->new(app => $self, stash => $stash, tx => $tx);
159
  weaken $c->{$_} for qw(app tx);
160

            
161
  # Dispatcher has to be last in the chain
162
  ++$self->{dispatch}
163
    and $self->hook(around_action   => sub { $_[2]->($_[1]) })
164
    and $self->hook(around_dispatch => sub { $_[1]->app->dispatch($_[1]) })
165
    unless $self->{dispatch};
166

            
167
  # Process with chain
168
  $self->plugins->emit_chain(around_dispatch => $c);
169

            
170
  # Delayed response
171
  $self->log->debug('Nothing has been rendered, expecting delayed response.')
172
    unless $tx->is_writing;
173
}
174

            
175
sub helper {
176
  my ($self, $name, $cb) = @_;
177
  my $r = $self->renderer;
178
  $self->log->debug(qq{Helper "$name" already exists, replacing.})
179
    if exists $r->helpers->{$name};
180
  $r->add_helper($name => $cb);
181
}
182

            
183
sub hook { shift->plugins->on(@_) }
184

            
185
sub plugin {
186
  my $self = shift;
187
  $self->plugins->register_plugin(shift, $self, @_);
188
}
189

            
190
sub start { shift->commands->run(@_ ? @_ : @ARGV) }
191

            
192
sub startup { }
193

            
194
sub _exception {
195
  my ($next, $c) = @_;
196
  local $SIG{__DIE__}
197
    = sub { ref $_[0] ? CORE::die($_[0]) : Mojo::Exception->throw(@_) };
198
  $c->render_exception($@) unless eval { $next->(); 1 };
199
}
200

            
201
1;
202

            
203
=encoding utf8
204

            
205
=head1 NAME
206

            
207
Mojolicious - Real-time web framework
208

            
209
=head1 SYNOPSIS
210

            
211
  # Application
212
  package MyApp;
213
  use Mojo::Base 'Mojolicious';
214

            
215
  # Route
216
  sub startup {
217
    my $self = shift;
218
    $self->routes->get('/hello')->to('foo#hello');
219
  }
220

            
221
  # Controller
222
  package MyApp::Foo;
223
  use Mojo::Base 'Mojolicious::Controller';
224

            
225
  # Action
226
  sub hello {
227
    my $self = shift;
228
    $self->render(text => 'Hello World!');
229
  }
230

            
231
=head1 DESCRIPTION
232

            
233
Take a look at our excellent documentation in L<Mojolicious::Guides>!
234

            
235
=head1 HOOKS
236

            
237
L<Mojolicious> will emit the following hooks in the listed order.
238

            
239
=head2 after_build_tx
240

            
241
Emitted right after the transaction is built and before the HTTP request gets
242
parsed.
243

            
244
  $app->hook(after_build_tx => sub {
245
    my ($tx, $app) = @_;
246
    ...
247
  });
248

            
249
This is a very powerful hook and should not be used lightly, it makes some
250
rather advanced features such as upload progress bars possible. Note that this
251
hook will not work for embedded applications. (Passed the transaction and
252
application object)
253

            
254
=head2 before_dispatch
255

            
256
Emitted right before the static file server and router start their work.
257

            
258
  $app->hook(before_dispatch => sub {
259
    my $c = shift;
260
    ...
261
  });
262

            
263
Very useful for rewriting incoming requests and other preprocessing tasks.
264
(Passed the default controller object)
265

            
266
=head2 after_static
267

            
268
Emitted after a static file response has been generated by the static file
269
server.
270

            
271
  $app->hook(after_static => sub {
272
    my $c = shift;
273
    ...
274
  });
275

            
276
Mostly used for post-processing static file responses. (Passed the default
277
controller object)
278

            
279
=head2 before_routes
280

            
281
Emitted after the static file server determined if a static file should be
282
served and before the router starts its work.
283

            
284
  $app->hook(before_routes => sub {
285
    my $c = shift;
286
    ...
287
  });
288

            
289
Mostly used for custom dispatchers and collecting metrics. (Passed the default
290
controller object)
291

            
292
=head2 around_action
293

            
294
Emitted right before an action gets invoked and wraps around it, so you have
295
to manually forward to the next hook if you want to continue the chain.
296
Default action dispatching is the last hook in the chain, yours will run
297
before it.
298

            
299
  $app->hook(around_action => sub {
300
    my ($next, $c, $action, $last) = @_;
301
    ...
302
    return $next->();
303
  });
304

            
305
This is a very powerful hook and should not be used lightly, it allows you for
306
example to pass additional arguments to actions or handle return values
307
differently. (Passed a callback leading to the next hook, the current
308
controller object, the action callback and a flag indicating if this action is
309
an endpoint)
310

            
311
=head2 after_render
312

            
313
Emitted after content has been generated by the renderer that is not partial.
314
Note that this hook can trigger out of order due to its dynamic nature, and
315
with embedded applications will only work for the application that is
316
rendering.
317

            
318
  $app->hook(after_render => sub {
319
    my ($c, $output, $format) = @_;
320
    ...
321
  });
322

            
323
Mostly used for post-processing dynamically generated content. (Passed the
324
current controller object, a reference to the content and the format)
325

            
326
=head2 after_dispatch
327

            
328
Emitted in reverse order after a response has been rendered. Note that this
329
hook can trigger out of order due to its dynamic nature, and with embedded
330
applications will only work for the application that is rendering.
331

            
332
  $app->hook(after_dispatch => sub {
333
    my $c = shift;
334
    ...
335
  });
336

            
337
Useful for rewriting outgoing responses and other post-processing tasks.
338
(Passed the current controller object)
339

            
340
=head2 around_dispatch
341

            
342
Emitted right before the L</"before_dispatch"> hook and wraps around the whole
343
dispatch process, so you have to manually forward to the next hook if you want
344
to continue the chain. Default exception handling with
345
L<Mojolicious::Controller/"render_exception"> is the first hook in the chain
346
and a call to L</"dispatch"> the last, yours will be in between.
347

            
348
  $app->hook(around_dispatch => sub {
349
    my ($next, $c) = @_;
350
    ...
351
    $next->();
352
    ...
353
  });
354

            
355
This is a very powerful hook and should not be used lightly, it allows you for
356
example to customize application wide exception handling, consider it the
357
sledgehammer in your toolbox. (Passed a callback leading to the next hook and
358
the default controller object)
359

            
360
=head1 ATTRIBUTES
361

            
362
L<Mojolicious> inherits all attributes from L<Mojo> and implements the
363
following new ones.
364

            
365
=head2 commands
366

            
367
  my $commands = $app->commands;
368
  $app         = $app->commands(Mojolicious::Commands->new);
369

            
370
Command line interface for your application, defaults to a
371
L<Mojolicious::Commands> object.
372

            
373
  # Add another namespace to load commands from
374
  push @{$app->commands->namespaces}, 'MyApp::Command';
375

            
376
=head2 controller_class
377

            
378
  my $class = $app->controller_class;
379
  $app      = $app->controller_class('Mojolicious::Controller');
380

            
381
Class to be used for the default controller, defaults to
382
L<Mojolicious::Controller>.
383

            
384
=head2 mode
385

            
386
  my $mode = $app->mode;
387
  $app     = $app->mode('production');
388

            
389
The operating mode for your application, defaults to a value from the
390
MOJO_MODE and PLACK_ENV environment variables or C<development>. Right before
391
calling L</"startup">, L<Mojolicious> will pick up the current mode, name the
392
log file after it and raise the log level from C<debug> to C<info> if it has a
393
value other than C<development>.
394

            
395
=head2 moniker
396

            
397
  my $moniker = $app->moniker;
398
  $app        = $app->moniker('foo_bar');
399

            
400
Moniker of this application, often used as default filename for configuration
401
files and the like, defaults to decamelizing the application class with
402
L<Mojo::Util/"decamelize">.
403

            
404
=head2 plugins
405

            
406
  my $plugins = $app->plugins;
407
  $app        = $app->plugins(Mojolicious::Plugins->new);
408

            
409
The plugin manager, defaults to a L<Mojolicious::Plugins> object. See the
410
L</"plugin"> method below if you want to load a plugin.
411

            
412
  # Add another namespace to load plugins from
413
  push @{$app->plugins->namespaces}, 'MyApp::Plugin';
414

            
415
=head2 renderer
416

            
417
  my $renderer = $app->renderer;
418
  $app         = $app->renderer(Mojolicious::Renderer->new);
419

            
420
Used in your application to render content, defaults to a
421
L<Mojolicious::Renderer> object. The two main renderer plugins
422
L<Mojolicious::Plugin::EPRenderer> and L<Mojolicious::Plugin::EPLRenderer>
423
contain more information.
424

            
425
  # Add another "templates" directory
426
  push @{$app->renderer->paths}, '/home/sri/templates';
427

            
428
  # Add another class with templates in DATA section
429
  push @{$app->renderer->classes}, 'Mojolicious::Plugin::Fun';
430

            
431
=head2 routes
432

            
433
  my $routes = $app->routes;
434
  $app       = $app->routes(Mojolicious::Routes->new);
435

            
436
The router, defaults to a L<Mojolicious::Routes> object. You use this in your
437
startup method to define the url endpoints for your application.
438

            
439
  # Add routes
440
  my $r = $app->routes;
441
  $r->get('/foo/bar')->to('test#foo', title => 'Hello Mojo!');
442
  $r->post('/baz')->to('test#baz');
443

            
444
  # Add another namespace to load controllers from
445
  push @{$app->routes->namespaces}, 'MyApp::Controller';
446

            
447
=head2 secret
448

            
449
  my $secret = $app->secret;
450
  $app       = $app->secret('passw0rd');
451

            
452
A secret passphrase used for signed cookies and the like, defaults to the
453
L</"moniker"> of this application, which is not very secure, so you should
454
change it!!! As long as you are using the insecure default there will be debug
455
messages in the log file reminding you to change your passphrase.
456

            
457
=head2 sessions
458

            
459
  my $sessions = $app->sessions;
460
  $app         = $app->sessions(Mojolicious::Sessions->new);
461

            
462
Signed cookie based session manager, defaults to a L<Mojolicious::Sessions>
463
object. You can usually leave this alone, see
464
L<Mojolicious::Controller/"session"> for more information about working with
465
session data.
466

            
467
  # Change name of cookie used for all sessions
468
  $app->sessions->cookie_name('mysession');
469

            
470
=head2 static
471

            
472
  my $static = $app->static;
473
  $app       = $app->static(Mojolicious::Static->new);
474

            
475
For serving static files from your C<public> directories, defaults to a
476
L<Mojolicious::Static> object.
477

            
478
  # Add another "public" directory
479
  push @{$app->static->paths}, '/home/sri/public';
480

            
481
  # Add another class with static files in DATA section
482
  push @{$app->static->classes}, 'Mojolicious::Plugin::Fun';
483

            
484
=head2 types
485

            
486
  my $types = $app->types;
487
  $app      = $app->types(Mojolicious::Types->new);
488

            
489
Responsible for connecting file extensions with MIME types, defaults to a
490
L<Mojolicious::Types> object.
491

            
492
  # Add custom MIME type
493
  $app->types->type(twt => 'text/tweet');
494

            
495
=head2 validator
496

            
497
  my $validator = $app->validator;
498
  $app          = $app->validator(Mojolicious::Validator->new);
499

            
500
Validate form data, defaults to a L<Mojolicious::Validator> object.
501

            
502
=head1 METHODS
503

            
504
L<Mojolicious> inherits all methods from L<Mojo> and implements the following
505
new ones.
506

            
507
=head2 new
508

            
509
  my $app = Mojolicious->new;
510

            
511
Construct a new L<Mojolicious> application, calling C<${mode}_mode> and
512
L</"startup"> in the process. Will automatically detect your home directory
513
and set up logging based on your current operating mode. Also sets up the
514
renderer, static file server, a default set of plugins and an
515
L</"around_dispatch"> hook with the default exception handling.
516

            
517
=head2 build_tx
518

            
519
  my $tx = $app->build_tx;
520

            
521
Transaction builder, defaults to building a L<Mojo::Transaction::HTTP>
522
object.
523

            
524
=head2 defaults
525

            
526
  my $hash = $app->defaults;
527
  my $foo  = $app->defaults('foo');
528
  $app     = $app->defaults({foo => 'bar'});
529
  $app     = $app->defaults(foo => 'bar');
530

            
531
Default values for L<Mojolicious::Controller/"stash">, assigned for every new
532
request.
533

            
534
  # Remove value
535
  my $foo = delete $app->defaults->{foo};
536

            
537
=head2 dispatch
538

            
539
  $app->dispatch(Mojolicious::Controller->new);
540

            
541
The heart of every L<Mojolicious> application, calls the L</"static"> and
542
L</"routes"> dispatchers for every request and passes them a
543
L<Mojolicious::Controller> object.
544

            
545
=head2 handler
546

            
547
  $app->handler(Mojo::Transaction::HTTP->new);
548
  $app->handler(Mojolicious::Controller->new);
549

            
550
Sets up the default controller and calls process for every request.
551

            
552
=head2 helper
553

            
554
  $app->helper(foo => sub {...});
555

            
556
Add a new helper that will be available as a method of the controller object
557
and the application object, as well as a function in C<ep> templates.
558

            
559
  # Helper
560
  $app->helper(cache => sub { state $cache = {} });
561

            
562
  # Controller/Application
563
  $self->cache->{foo} = 'bar';
564
  my $result = $self->cache->{foo};
565

            
566
  # Template
567
  % cache->{foo} = 'bar';
568
  %= cache->{foo}
569

            
570
=head2 hook
571

            
572
  $app->hook(after_dispatch => sub {...});
573

            
574
Extend L<Mojolicious> with hooks, which allow code to be shared with all
575
requests indiscriminately, for a full list of available hooks see L</"HOOKS">.
576

            
577
  # Dispatchers will not run if there's already a response code defined
578
  $app->hook(before_dispatch => sub {
579
    my $c = shift;
580
    $c->render(text => 'Skipped static file server and router!')
581
      if $c->req->url->path->to_route =~ /do_not_dispatch/;
582
  });
583

            
584
=head2 plugin
585

            
586
  $app->plugin('some_thing');
587
  $app->plugin('some_thing', foo => 23);
588
  $app->plugin('some_thing', {foo => 23});
589
  $app->plugin('SomeThing');
590
  $app->plugin('SomeThing', foo => 23);
591
  $app->plugin('SomeThing', {foo => 23});
592
  $app->plugin('MyApp::Plugin::SomeThing');
593
  $app->plugin('MyApp::Plugin::SomeThing', foo => 23);
594
  $app->plugin('MyApp::Plugin::SomeThing', {foo => 23});
595

            
596
Load a plugin, for a full list of example plugins included in the
597
L<Mojolicious> distribution see L<Mojolicious::Plugins/"PLUGINS">.
598

            
599
=head2 start
600

            
601
  $app->start;
602
  $app->start(@ARGV);
603

            
604
Start the command line interface for your application, for a full list of
605
commands available by default see L<Mojolicious::Commands/"COMMANDS">.
606

            
607
  # Always start daemon and ignore @ARGV
608
  $app->start('daemon', '-l', 'http://*:8080');
609

            
610
=head2 startup
611

            
612
  $app->startup;
613

            
614
This is your main hook into the application, it will be called at application
615
startup. Meant to be overloaded in a subclass.
616

            
617
  sub startup {
618
    my $self = shift;
619
    ...
620
  }
621

            
622
=head1 HELPERS
623

            
624
In addition to the attributes and methods above you can also call helpers on
625
L<Mojolicious> objects. This includes all helpers from
626
L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
627
Note that application helpers are always called with a new default controller
628
object, so they can't depend on or change controller state, which includes
629
request, response and stash.
630

            
631
  $app->log->debug($app->dumper({foo => 'bar'}));
632

            
633
=head1 BUNDLED FILES
634

            
635
The L<Mojolicious> distribution includes a few files with different licenses
636
that have been bundled for internal use.
637

            
638
=head2 Mojolicious Artwork
639

            
640
  Copyright (C) 2010-2013, Sebastian Riedel.
641

            
642
Licensed under the CC-SA License, Version 3.0
643
L<http://creativecommons.org/licenses/by-sa/3.0>.
644

            
645
=head2 jQuery
646

            
647
  Copyright (C) 2005, 2013 jQuery Foundation, Inc.
648

            
649
Licensed under the MIT License, L<http://creativecommons.org/licenses/MIT>.
650

            
651
=head2 prettify.js
652

            
653
  Copyright (C) 2006, 2013 Google Inc.
654

            
655
Licensed under the Apache License, Version 2.0
656
L<http://www.apache.org/licenses/LICENSE-2.0>.
657

            
658
=head1 CODE NAMES
659

            
660
Every major release of L<Mojolicious> has a code name, these are the ones that
661
have been used in the past.
662

            
663
4.0, C<Top Hat> (u1F3A9)
664

            
665
3.0, C<Rainbow> (u1F308)
666

            
667
2.0, C<Leaf Fluttering In Wind> (u1F343)
668

            
669
1.4, C<Smiling Face With Sunglasses> (u1F60E)
670

            
671
1.3, C<Tropical Drink> (u1F379)
672

            
673
1.1, C<Smiling Cat Face With Heart-Shaped Eyes> (u1F63B)
674

            
675
1.0, C<Snowflake> (u2744)
676

            
677
0.999930, C<Hot Beverage> (u2615)
678

            
679
0.999927, C<Comet> (u2604)
680

            
681
0.999920, C<Snowman> (u2603)
682

            
683
=head1 SPONSORS
684

            
685
Some of the work on this distribution has been sponsored by
686
L<The Perl Foundation|http://www.perlfoundation.org>, thank you!
687

            
688
=head1 PROJECT FOUNDER
689

            
690
Sebastian Riedel, C<sri@cpan.org>
691

            
692
=head1 CORE DEVELOPERS
693

            
694
Current members of the core team in alphabetical order:
695

            
696
=over 2
697

            
698
Abhijit Menon-Sen, C<ams@cpan.org>
699

            
700
Glen Hinkle, C<tempire@cpan.org>
701

            
702
Joel Berger, C<jberger@cpan.org>
703

            
704
Marcus Ramberg, C<mramberg@cpan.org>
705

            
706
=back
707

            
708
=head1 CREDITS
709

            
710
In alphabetical order:
711

            
712
=over 2
713

            
714
Adam Kennedy
715

            
716
Adriano Ferreira
717

            
718
Al Newkirk
719

            
720
Alex Efros
721

            
722
Alex Salimon
723

            
724
Alexey Likhatskiy
725

            
726
Anatoly Sharifulin
727

            
728
Andre Vieth
729

            
730
Andreas Jaekel
731

            
732
Andreas Koenig
733

            
734
Andrew Fresh
735

            
736
Andrey Khozov
737

            
738
Andy Grundman
739

            
740
Aristotle Pagaltzis
741

            
742
Ashley Dev
743

            
744
Ask Bjoern Hansen
745

            
746
Audrey Tang
747

            
748
Ben van Staveren
749

            
750
Benjamin Erhart
751

            
752
Bernhard Graf
753

            
754
Breno G. de Oliveira
755

            
756
Brian Duggan
757

            
758
Brian Medley
759

            
760
Burak Gursoy
761

            
762
Ch Lamprecht
763

            
764
Charlie Brady
765

            
766
Chas. J. Owens IV
767

            
768
Christian Hansen
769

            
770
chromatic
771

            
772
Curt Tilmes
773

            
774
Daniel Kimsey
775

            
776
Danijel Tasov
777

            
778
Danny Thomas
779

            
780
David Davis
781

            
782
David Webb
783

            
784
Diego Kuperman
785

            
786
Dmitriy Shalashov
787

            
788
Dmitry Konstantinov
789

            
790
Dominik Jarmulowicz
791

            
792
Dominique Dumont
793

            
794
Douglas Christopher Wilson
795

            
796
Eugene Toropov
797

            
798
Gisle Aas
799

            
800
Graham Barr
801

            
802
Henry Tang
803

            
804
Hideki Yamamura
805

            
806
Ian Goodacre
807

            
808
Ilya Chesnokov
809

            
810
James Duncan
811

            
812
Jan Henning Thorsen
813

            
814
Jan Jona Javorsek
815

            
816
Jan Schmidt
817

            
818
Jaroslav Muhin
819

            
820
Jesse Vincent
821

            
822
Johannes Plunien
823

            
824
John Kingsley
825

            
826
Jonathan Yu
827

            
828
Josh Leder
829

            
830
Kazuhiro Shibuya
831

            
832
Kevin Old
833

            
834
Kitamura Akatsuki
835

            
836
Lars Balker Rasmussen
837

            
838
Leon Brocard
839

            
840
Magnus Holm
841

            
842
Maik Fischer
843

            
844
Mark Stosberg
845

            
846
Marty Tennison
847

            
848
Matthew Lineen
849

            
850
Maksym Komar
851

            
852
Maxim Vuets
853

            
854
Michael Harris
855

            
856
Mike Magowan
857

            
858
Mirko Westermeier
859

            
860
Mons Anderson
861

            
862
Moritz Lenz
863

            
864
Neil Watkiss
865

            
866
Nic Sandfield
867

            
868
Nils Diewald
869

            
870
Oleg Zhelo
871

            
872
Pascal Gaudette
873

            
874
Paul Evans
875

            
876
Paul Tomlin
877

            
878
Pavel Shaydo
879

            
880
Pedro Melo
881

            
882
Peter Edwards
883

            
884
Pierre-Yves Ritschard
885

            
886
Quentin Carbonneaux
887

            
888
Rafal Pocztarski
889

            
890
Randal Schwartz
891

            
892
Robert Hicks
893

            
894
Robin Lee
895

            
896
Roland Lammel
897

            
898
Ryan Jendoubi
899

            
900
Sascha Kiefer
901

            
902
Scott Wiersdorf
903

            
904
Sergey Zasenko
905

            
906
Simon Bertrang
907

            
908
Simone Tampieri
909

            
910
Shu Cho
911

            
912
Skye Shaw
913

            
914
Stanis Trendelenburg
915

            
916
Stephane Este-Gracias
917

            
918
Tatsuhiko Miyagawa
919

            
920
Terrence Brannon
921

            
922
Tomas Znamenacek
923

            
924
Ulrich Habel
925

            
926
Ulrich Kautz
927

            
928
Uwe Voelker
929

            
930
Viacheslav Tykhanovskyi
931

            
932
Victor Engmark
933

            
934
Viliam Pucik
935

            
936
Wes Cravens
937

            
938
Yaroslav Korshak
939

            
940
Yuki Kimoto
941

            
942
Zak B. Elep
943

            
944
=back
945

            
946
=head1 COPYRIGHT AND LICENSE
947

            
948
Copyright (C) 2008-2013, Sebastian Riedel.
949

            
950
This program is free software, you can redistribute it and/or modify it under
951
the terms of the Artistic License version 2.0.
952

            
953
=head1 SEE ALSO
954

            
955
L<Mojolicious::Guides>, L<http://mojolicio.us>.
956

            
957
=cut