Merge branch 'topic/2009-conferences' of gitmo@git.moose.perl.org:moose-website
[gitmo/moose-website.git] / hosted-presentations / 2008 / nothingmuch-NPW / practical_moose.s5
CommitLineData
720accfe 1Title: Moose
2Location: YAPC::Asia::2008
3Presenter: Yuval Kogman
4Date: 2008
5Theme: moose
6
7Moose Is Not
8============
9
10* Experimental
11* A toy
12* Just another accessor builder
13* A source filter
14* Perl black magic
15* Perl 6 in Perl 5
16
17✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
18
19Moose Is
20========
21
22* A complete modern object framework for Perl
23
24✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
25
26Moose Is
27========
28
29* Syntactic Sugar for `Class::MOP`
30* Rich ancestry
31 * CLOS (Common Lisp Object System)
32 * Smalltalk
33 * Alces latifrons
34 * Perl 6
35 * …
36* Stable & Production ready
37* Polite, incremental
38
39✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
40
41A Simple Example
42================
43
44<pre><code>
45package Person;
46
47use strict;
48use warnings;
49
50sub new {
51 my ( $class, @args ) = @_;
52
53 @args = %{$args[0]} if @args == 1;
54
55 return bless {
56 @args,
57 }, $class;
58}
59
60sub name {
61 my ($self, @args) = @_;
62 $self->{name} = $args[0] if @args;
63 return $self->{name};
64}
65
66sub age {
67 my ($self, @args) = @_;
68 $self->{age} = $args[0] if @args;
69 return $self->{age};
70}
71
721;
73</code></pre>
74
75✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
76
77A Simple Moose Example
78======================
79
80<pre><code>
81package Person;
82use Moose;
83
84has name => (is => 'rw');
85has age => (is => 'rw');
86
871;
88</code></pre>
89
90✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
91
92A Simple Moose Example (cont.)
93==============================
94
95* `use Moose;`
96 * imports keywords
97 * `use strict; use warnings;`
98 * `@ISA = qw(Moose::Object) unless @ISA`
99
100✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
101
102A Simple Moose Example (cont.)
103==============================
104
105* `has` declares attributes
106 * generates accessors
107 * `is => 'rw'` → read/write accessor
108 * `is => 'ro'` → read only accessor
109 * `writer`, `reader`
110
111* `new` inherited from `Moose::Object`
112
113
114##########
115
116Now we're going to discuss more features of the attributes
117
118✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
119
120Variations on a Moose Example
121=============================
122
123<pre><code>
124package Manager;
125use Moose;
126
127has name => (
128 is => 'rw',
129 isa => 'Str',
130 default => 'Bob'
131);
132
133has staff => (
134 is => 'ro',
135 isa => 'ArrayRef',
136 lazy => 1,
137 default => sub { [qw(Bob Alice Tim)] },
138);
139</code></pre>
140##########
141
142Adds default, isa
143
144✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
145
146Variations on a Moose Example (cont.)
147=====================================
148
149* `default` is a
150 * code reference
151 * or non-reference (numbers, strings)
152 * used when no parameter is given to `new`
153
154* `lazy` delays `default`
155 * called on first usage of `$object->staff`
156 * not inside `new`
157
158##########
159discusses default
160
161non refs make accidental sharing hard
162
163✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
164
165Variations on a Moose Example (cont.)
166=====================================
167
168* `isa` specifies a type
169 * `Moose::Util::TypeConstraints`
170 * `Any, Item, Bool, Undef, Defined, Value, Num, Int, Str, Ref, ScalarRef, ArrayRef, HashRef, CodeRef, RegexpRef, GlobRef, FileHandle, Object and Role`
171 * Types don't need to exist
172<pre><code>
173 has 'date' => (isa => 'DateTime'); # DWIM
174</code></pre>
175##########
176
177isa, type constraints
178
179✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
180
181Typical Family
182==============
183
184* Types have a hierarchy
185 * `Item` ⊃ `Defined` ⊃ `Ref` ⊃ `Object`
186
187<pre><code>
188 subtype 'Ref'
189 => as 'Defined'
190 => where { ref($_) };
191
192 subtype 'Object'
193 => as 'Ref'
194 => where { blessed($_) }
195</code></pre>
196##########
197
198type hierarchy
199
200✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
201
202Conventional Delegates
203======================
204
205<pre><code>
206package Employee;
207use Moose;
208extends qw(Person);
209
210has manager => (
211 is => 'ro',
212 isa => 'Manager',
213 handles => {
214 manager_name => 'name',
215 coworkers => 'staff',
216 }
217);
218</code></pre>
219
220* manager `handles` certain methods for `Employee`
221 * `$emp->coworkers` == `$emp->manager->staff `
222
223✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
224
225Conventional Delegates (cont.)
226==============================
227
228<pre><code>
229has phone => (
230 ...
231 handles => [qw(number extension)],
232);
233</code></pre>
234
235✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
236
237Conventional Delegates (cont.)
238==============================
239
240<pre><code>
241has phone => (
242 ...
243 isa => "Phone",
244 handles => qr/^[a-z]\w+$/,
245);
246</code></pre>
247
248✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
249
250Conventional Delegates (cont.)
251==============================
252
253<pre><code>
254has phone => (
255 ...
256 handles => "Dialing", # a role
257);
258</code></pre>
259
260✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
261
262UnConventional Delegates
263========================
264
265<pre><code>
266package Company;
267use Moose;
268use MooseX::AttributeHelpers;
269
270has employees => (
271 metaclass => 'Collection::Array',
272 isa => 'ArrayRef[Employees]',
273 is => 'rw',
274 provides => {
275 push => 'add_employee',
276 pop => 'remove_employee',
277 count => 'number_of_employees',
278 empty => 'any_employees',
279 },
280);
281</code></pre>
282✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
283
284Modified Methods
285================
286
287<pre><code>
288before 'employees' => sub { warn 'calling employees' };
289
290after 'employees' => sub { warn 'finished calling employees' };
291</code></pre>
292
293* Pre/Post hooks
294 * Get a copy of `@_`
295 * Return value is ignored
296
297✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
298
299Modified Methods (cont.)
300========================
301
302<pre><code>
303around 'employees' => sub {
304 my ($next, $self, @args) = @_;
305 ...
306 my @return = $self->$next(@args);
307 ...
308 return @return;
309};
310</code></pre>
311
312✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
313
314Modified Methods (cont.)
315========================
316
317<pre><code>
318package Employee;
319use Moose;
320
321sub do_work {
322 my $self = shift;
323
324 $self->punch_in;
325
326 inner(); # call subclass here
327
328 $self->punch_out;
329}
330</code></pre>
331
332✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
333
334Modified Methods (cont.)
335========================
336
337<pre><code>
338package Employee::Chef;
339use Moose;
340
341extends qw(Employee);
342
343augment do_work => sub {
344 my $self = shift;
345
346 while ( @burgers ) {
347 $self->flip_burger(shift @burgers);
348 }
349};
350
351$chef->do_work; # punch in, flip burgers, punch out
352</code></pre>
353✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
354
355Some Type of Coercion
356=====================
357
358<pre><code>
359package Employee;
360use Moose;
361use Moose::Util::TypeConstraints;
362extends qw(Person);
363
364class_type 'Manager';
365
366coerce 'Manager' => (
367 from 'Str' => via { Manager->new( name => $_ ) },
368);
369
370has manager => (
371 is => 'ro',
372 isa => 'Manager',
373 required => 1,
374 coerce => 1,
375);
376</code></pre>
377
378✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
379
380Some Type of Coercion (cont.)
381=============================
382
383<pre><code>
384# import type constraint keywords
385use Moose::Util::TypeConstraints;
386
387
388# define Manager, a subtype of Object
389class_type "Manager";
390
391
392# define the conversion
393... via { Manager->new( name => $_ ) }
394
395
396# enable it per attribute
397has manager => (
398 ...
399 coerce => 1,
400);
401</code></pre>
402
403##########
404
405breakdown of the example
406
407class types are automatically created for all Moose classes
408
409✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
410
411Some Type of Digression
412=======================
413
414<pre><code>
415has employees => (
416 is => 'rw',
417 isa => 'ArrayRef[Employee]',
418);
419
420has shopping_carts => (
421 is => 'rw',
422 isa => 'ArrayRef[ArrayRef[ShinyBead]]'
423);
424</code></pre>
425
426##########
427
428Going to go into features of the type system for a bit
429
430Parametrized types
431
432✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
433Some Type of Digression (cont.)
434===============================
435
436<pre><code>
437has language => (
438 is => 'rw',
439 isa => 'English | Welsh | Scots | Gaelic',
440);
441
442has member => (
443 is => 'rw',
444 isa => 'Employee | ArrayRef[ Employee | Group ]',
445);
446</code></pre>
447
448##########
449
450Union types
451
452✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
453
454Some Type of Digression (cont.)
455===============================
456
457<pre><code>
458package Foo;
459use Moose;
460use Moose::Util::TypeConstraints;
461
462use Test::Deep qw(eq_deeply ...);
463
464type 'SomethingTricky' => where {
465 eq_deeply( $_, ... );
466};
467
468has 'bar' => (
469 is => 'rw',
470 isa => 'SomethingTricky',
471);
472</code></pre>
473
474##########
475
476Test::Deep custom validator
477
478Can use any validation from the CPAN
479
480✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
481
482Some Parametrized Type of Coercion
483==================================
484
485<pre><code>
486use Moose::Util::TypeConstraints;
487
488subtype 'ArrayRef[Employee]' => as 'ArrayRef';
489
490coerce 'ArrayRef[Employee]' => (
491 from 'ArrayRef[Str]' via {
492 [ map { Employee->new( name => $_ ) } @$_ ]
493 },
494);
495
496has staff => (
497 isa => 'ArrayRef[Employee]',
498 coerce => 1,
499);
500</code></pre>
501
502##########
503
504coerce parametrized ArrayRef[Employee] from ArrayRef[Str]
505
506✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
507
508Role of the Moose
509=================
510
511* A role is like a…
512 * Java Interface: safe
513 * mixin: useful
514* A role is for small reusable behaviors
515 * better than using a multiple inheritence
516
517✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
518
519Role of the Moose (cont.)
520=========================
521
522* Roles on the CPAN:
523 * `MooseX::Clone` - Flexible `clone` method
524 * `MooseX::Storage` - Flexible serialization
525 * `MooseX::Getopt` - `@ARGV` aware constructor
526 * `MooseX::LogDispatch` - `$self->logger->info("something happenned")`
527 * `MooseX::Param` - `param` method like `CGI.pm`'s,
528
529##########
530
531Some examples of small reusable behaviors
532
533Param is good for interacting with e.g. CGI::Expand or similar modules
534
535✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
536
537Role of the Moose (cont.)
538=========================
539
540<pre><code>
541package Minion;
542use Moose;
543
544extends qw(Employee);
545
546with qw(Salaried::Hourly);
547
548
549package Boss;
550use Moose;
551
552extends qw(Employee);
553
554with qw(Salaried::Monthly);
555
556</code></pre>
557
558* `with` adds roles into your class
559 * `Salaried::Hourly` was added to `Minion`
560
561✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
562
563Role of the Moose (cont.)
564=========================
565
566<pre><code>
567package Salaried;
568use Moose::Role;
569
570requires 'paycheck_amount';
571</code></pre>
572
573* Just an interface
574
575✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
576
577Role of the Moose (cont.)
578=========================
579
580<pre><code>
581package Salaried::Hourly;
582use Moose::Role;
583
584with qw(Salaried);
585
586has hourly_rate => (
587 isa => "Num",
588 is => "rw",
589 required => 1,
590);
591
592has logged_hours => (
593 isa => "Num",
594 is => "rw",
595 default => 0,
596);
597
598# satisfy the Salaried interface:
599sub paycheck_amount {
600 my $self = shift;
601 $self->logged_hours * $self->hourly_rate;
602}
603
604</code></pre>
605
606* More than an interface
607
608✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
609
610Role of the Moose (cont.)
611=========================
612
613* More than Java Interfaces
614 * Interfaces are behavior "contracts"
615 * Roles can also have code
616
617##########
618roles can have attributes and methods
619roles provide behavior, not just interface
620
621✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
622
623Role of the Moose (cont.)
624=========================
625
626* Role Composition
627 * Not inheritence
628 * Symmetric
629 * Unordered
630
631✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
632
633Role of the Moose (cont.)
634=========================
635
636* Role Composition
637 * Less ambiguity
638 * Compile time errors
639 * …And ways to fix them
640
641##########
642symmetric composition means no precedence - if two roles try to define the same thing you get a compile time error that needs to be resolved
643multiple inheritence silently assumes you want the first class
644
645roles cause errors at compile time, unlike multiple inheritence
646
647roles also provide easy ways to fix the errors
648
649✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
650
651Role of the Moose (cont.)
652=========================
653
654<pre><code>
655package Ballet;
656use Moose::Role;
657
658sub dance {
659 pirouette();
660}
661
662package Punk;
663use Moose::Role
664
665sub dance {
666 MOSH!!!11one();
667}
668
669package Foo;
670use Moose;
671
672# KABOOM:
673with qw(
674 Punk
675 Ballet
676);
677</code></pre>
678
679##########
680
681conflicts
682
683✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
684
685Role of the Moose (cont.)
686=========================
687
688<pre><code>
689package Ent::Puppy;
690use Moose;
691
692with (
693 Tree => {
694 alias => {
695 bark => "tree_bark",
696 },
697 },
698 Dog => {
699 alias => {
700 bark => "bark_sound",
701 }
702 },
703);
704
705sub bark {
706 my $self = shift;
707
708 if ( $condition ) {
709 $self->tree_bark;
710 } else {
711 $self->bark_sound;
712 }
713}
714</code></pre>
715
716* Not that common in practice
717
718##########
719
720Composition parameters
721Easier conflict resolution
722Finer grained control
723
724✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
725
726MOPs Mean Cleanliness
727=====================
728
729* Moose is based on `Class::MOP`
730 * Metaobject Protocol for Perl 5
731 * "makes an object for everything"
732
733<pre><code>
734my $class = $obj->meta; # $obj's metaclass
735my $meta = MyApp->meta; # MyApp's metaclass
736my $emo = $obj->meta->meta; # even more meta!
737
738warn $obj->meta->name;
739</code></pre>
740
741✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
742
743Looking in From the Inside
744===========================
745
746<pre><code>
747my $metaclass = $self->meta;
748
749$metaclass->superclasses;
750
751$metaclass->linearized_isa;
752
753$metaclass->has_method("foo");
754
755$metaclass->compute_all_applicable_attributes;
756
757# … lots more
758</code></pre>
759##########
760
761simple introspection
762
763✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
764
765Looking in From the Inside (cont.)
766==================================
767
768<pre><code>
769Moose::Meta::Class->create( Bar =>
770 version => '0.01',
771 superclasses => [ 'Foo' ],
772 attributes => [
773 Moose::Meta::Attribute->new( bar => ... ),
774 Moose::Meta::Attribute->new( baz => ... ),
775 ],
776 methods => {
777 calculate_bar => sub { ... },
778 construct_baz => sub { ... }
779 },
780);
781
782my $anon_meta = Moose::Meta::Class->create_anon_class( ... );
783</code></pre>
784
785##########
786
787Classes can be created programmatically
788✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
789
790Looking in From the Inside (cont.)
791==================================
792
793<pre><code>
794has foo => ( is => "rw" );
795
796__PACKAGE__->meta->add_attribute(
797 "foo",
798 is => "rw",
799);
800</code></pre>
801
802* Moose is just sugar
803 * The MOP does the hard work
804
805✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
806
807The Metaclass Tango
808===================
809
810* Metaclassses control class behavior
811
812<pre><code>
813has employees => (
814 metaclass => 'Collection::Array',
815 ...
816);
817</code></pre>
818
819* custom attribute metaclasses
820 * change how attributes work
821* Many customizable parts
822 * `Moose::Meta::Class`, `Moose::Meta::Attribute, ``Moose::Meta::Method`, `Moose::Meta::Method::Accessor` `Moose::Meta::Instance`, `Moose::Meta::Role`, `Moose::Meta::TypeConstraint`, …,
823
824✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
825
826Working in the Meta Frame
827=========================
828
829* `$work` project:
830* CMS for a flash website
831* Content is in XML
832
833✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
834
835Working in the Meta Frame (cont.)
836=================================
837
838* Step 1. use Moose
839* Step 2. ???
840* Step 3. Profit!
841
842✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
843
844Working in the Meta Frame (cont.)
845=================================
846
847* Step 2.1. Client's XML schemas → Moose classes
848 * Automatic class definitions
849 * High level objects in runtime
850 * XML storage backed
851 * SAX → Moose
852 * Moose → SAX
853
854✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
855
856Working in the Meta Frame (cont.)
857=================================
858
859* Step 2.2. Meta descriptions
860 * Extend the metaclasses
861 * Embed additional information
862 * field types
863 * access control
864
865✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
866
867Working in the Meta Frame (cont.)
868=================================
869
870* Step 2.3 Introspection goodness
871 * Generic web frontend
872 * Object introspection based
873 * HTML view
874 * Editing widgets
875 * Clean, extensible
876
877✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
878
879Drawbacks of Moose
880==================
881
882* Load time
883 * `MooseX::Compile` is in the works
884* Some features are slow
885 * but you only pay for what you use
886* Extending non-Hash based classes is tricky.
887 * but possible: `MooseX::GlobRef::Object`
888
889✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
890
891Benefits of Moose
892=================
893
894* Less boilerplate
895 * attribute storage/access
896 * construction
897 * destruction
898 * verification
899 * …
900
901✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
902
903Benefits of Moose (cont.)
904=========================
905
906* Shorter
907 * less reading
908 * less writing
909 * less code means fewer bugs
910
911✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
912
913Benefits of Moose (cont.)
914=========================
915
916* Less testing
917 * Moose is very well tested
918 * no need to check accessor behavior, etc
919 * focus on your code's purpose
920 * not that it is "assembled" correctly
921 * http://c2.com/cgi/wiki?IntentionNotAlgorithm
922
923✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
924
925Benefits of Moose (cont.)
926=========================
927
928* More readable
929 * declarative style is self documenting
930 * good signal to noise ratio
931
932✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
933
934Benefits of Moose (cont.)
935=========================
936
937* Meta object protocol
938 * Cleans up Perl's OO
939 * Provides introspection
940 * Enables powerful abstractions
941
942✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
943
944Benefits of Moose (cont.)
945=========================
946
947* It's the new black
948 * All the cool kids hang out on #moose
949 * Smart sounding buzzwords
950 * Chicks dig antlers
951 * Ruby is so 2007
952
953✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
954
955Bonus Material
956==============
957
958✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
959
960Autobox
961=======
962
963<pre><code>
964package Units::Bytes;
965use Moose::Role;
966use Moose::Autobox;
967
968sub bytes { $_[0] }
969sub kilobytes { $_[0] * 1024 }
970sub megabytes { $_[0] * 1024->kilobytes }
971sub gigabytes { $_[0] * 1024->megabytes }
972sub terabytes { $_[0] * 1024->gigabytes }
973
974Moose::Autobox->mixin_additional_role(
975 SCALAR => 'Units::Bytes',
976);
977</code></pre>
978
979✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
980
981Autobox (cont.)
982===============
983
984<pre><code>
985use Units::Bytes;
986use Moose::Autobox; # autoboxing is lexical
987
988is(5->bytes, 5, '... got 5 bytes');
989is(5->kilobytes, 5120, '... got 5 kilobytes');
990is(2->megabytes, 2097152, '... got 2 megabytes');
991is(1->gigabytes, 1073741824, '... got 1 gigabyte');
992is(2->terabytes, 2199023255552, '... got 2 terabytes');
993</code></pre>
994
995✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
996
997perl -Moose
998===========
999
1000* Moose One Liners with `oose.pm`
1001
1002<pre><code>
1003perl -Moose -e 'has foo => ( is=> "rw" ); Class->new( foo => 1 )'
1004</code></pre>
1005
1006* Useful for testing if something works
1007* Helpful on IRC
1008* `Devel::REPL` is cooler though ;-)
1009
1010✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
1011
1012MooseX::POE
1013===========
1014
1015<pre><code>
1016package Counter;
1017use MooseX::POE;
1018use MooseX::AttributeHelpers;
1019
1020has count => (
1021 traits => [qw(Counter)],
1022 provides => { inc => "increment_count" },
1023);
1024
1025sub START {
1026 shift->yield('increment');
1027}
1028
1029event increment => sub {
1030 my $self = shift;
1031
1032 warn "Count is now " . $self->count;
1033
1034 $self->increment_count;
1035 $self->yield('increment') unless $self->count > 3;
1036};
1037
1038Counter->new( count => 0 );
1039POE::Kernel->run();
1040</code></pre>
1041
1042* PoCos made easy
1043* Every object has a `POE::Session`
1044* `event` declares POE object states
1045
1046✂------✂------✂------✂------✂------✂------✂------✂------✂------✂------
1047
1048Fin
1049===
1050
1051* Slides written by:
1052 * Chris Prather
1053 * Stevan Little
1054 * Robert Boone
1055
1056* Slides deleted by:
1057 * Yuval Kogman