f9e1583c891eaeddaa850f806275cfc4edd8c1bd
[android-command-line.git] / index.html
1 <!DOCTYPE html> 
2 <!--
3   Copyright 2010 Google Inc.
4  
5   Licensed under the Apache License, Version 2.0 (the "License");
6   you may not use this file except in compliance with the License.
7   You may obtain a copy of the License at
8  
9      http://www.apache.org/licenses/LICENSE-2.0
10  
11   Unless required by applicable law or agreed to in writing, software
12   distributed under the License is distributed on an "AS IS" BASIS,
13   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   See the License for the specific language governing permissions and
15   limitations under the License.
16  
17   Original slides: Marcin Wichary (mwichary@google.com)
18   Modifications: Ernest Delgado (ernestd@google.com)
19                  Alex Russell (slightlyoff@chromium.org)
20                  Brad Neuberg
21 --> 
22 <html manifest="cache.manifest"> 
23   <head> 
24     <!--[if gte IE 9]>
25       <meta http-equiv="X-UA-Compatible" content="IE=edge" />
26     <![endif]--> 
27     
28     <!--[if lt IE 9]>
29       <meta http-equiv="X-UA-Compatible" content="IE=edge;chrome=1" />
30     <![endif]--> 
31  
32     <meta charset="utf-8" /> 
33     <title>Dobrica Pavlinušić: Android from source in command-line</title> 
34     <link href="http://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono" rel="stylesheet" type="text/css" /> 
35  
36     <style>      
37       body {
38         font: 20px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
39         padding: 0;
40         margin: 0;
41         width: 100%;
42         height: 100%;
43         position: absolute;
44         left: 0px; top: 0px;
45       }
46       
47       .presentation {
48         position: absolute;
49         height: 100%;
50         width: 100%;
51         left: 0px;
52         top: 0px;
53         display: block;
54         overflow: hidden;
55         background: #778;
56       }
57       
58       .slides {
59         width: 100%;
60         height: 100%;
61         left: 0;
62         top: 0;
63         position: absolute;
64         display: block;
65         -webkit-transition: -webkit-transform 1s ease-in-out;
66         -moz-transition: -moz-transform 1s ease-in-out;
67         -o-transition: -o-transform 1s ease-in-out;
68         transition: transform 1s ease-in-out;
69         
70         /* so it's visible in the iframe. */
71         -webkit-transform: scale(0.8);
72         -moz-transform: scale(0.8);
73         -o-transform: scale(0.8);
74         transform: scale(0.8);
75         
76       }
77       
78       .slide {
79         display: none;
80         position: absolute;
81         overflow: hidden;
82         width: 900px;
83         height: 700px;
84         left: 50%;
85         top: 50%;
86         margin-top: -350px;
87         background-color: #eee;
88         background: -webkit-gradient(linear, left bottom, left top, from(#bbd), to(#fff));
89         background: -moz-linear-gradient(bottom, #bbd, #fff);
90         background: linear-gradient(bottom, #bbd, #fff);
91         -webkit-transition: all 0.25s ease-in-out;
92         -moz-transition: all 0.25s ease-in-out;
93         -o-transition: all 0.25s ease-in-out;
94         transition: all 0.25s ease-in-out;
95         -webkit-transform: scale(1);
96         -moz-transform: scale(1);
97         -o-transform: scale(1);
98         transform: scale(1);
99       }
100       
101       .slide:nth-child(even) {
102         -moz-border-radius: 20px 0;
103         -khtml-border-radius: 20px 0;
104         border-radius: 20px 0; /* includes Opera 10.5+ */
105         -webkit-border-top-left-radius: 20px;
106         -webkit-border-bottom-right-radius: 20px;
107       }
108       
109       .slide:nth-child(odd) {
110         -moz-border-radius: 0 20px;
111         -khtml-border-radius: 0 20px;
112         border-radius: 0 20px;
113         -webkit-border-top-right-radius: 20px;
114         -webkit-border-bottom-left-radius: 20px;
115       }
116  
117       .slide p, .slide textarea {
118         font-size: 120%;
119       }
120  
121       .slide .counter {
122         color: #999999;
123         position: absolute;
124         left: 20px;
125         bottom: 20px;
126         display: block;
127         font-size: 70%;
128       }
129  
130       .slide.title > .counter,
131       .slide.segue > .counter,
132       .slide.mainTitle > .counter {
133         display: none;
134       }
135  
136       .force-render {
137         display: block;
138         visibility: hidden;
139       }
140       
141       .slide.far-past {
142         display: block;
143         margin-left: -2400px;
144       }
145       
146       .slide.past {
147         visibility: visible;
148         display: block;
149         margin-left: -1400px;
150       }
151       
152       .slide.current {
153         visibility: visible;
154         display: block;
155         margin-left: -450px;
156       }
157       
158       .slide.future {
159         visibility: visible;
160         display: block;
161         margin-left: 500px;
162       }
163       
164       .slide.far-future {
165         display: block;
166         margin-left: 1500px;
167       }
168       
169       body.three-d div.slides {
170         -webkit-transform: translateX(50px) scale(0.8) rotateY(10deg);
171         -moz-transform: translateX(50px) scale(0.8) rotateY(10deg);
172         -o-transform: translateX(50px) scale(0.8) rotateY(10deg);
173         transform: translateX(50px) scale(0.8) rotateY(10deg);
174       }
175       
176       /* Content */
177       
178       @font-face { font-family: 'Junction'; src: url(src/Junction02.otf); }
179       @font-face { font-family: 'LeagueGothic'; src: url(src/LeagueGothic.otf); }
180       
181       header {
182         font-family: 'Droid Sans';
183         font-weight: normal;
184         letter-spacing: -.05em;
185         text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px;
186         left: 30px;
187         top: 25px;
188         margin: 0;
189         padding: 0;
190         font-size: 140%;
191       }
192       
193       h1 {
194         font-size: 140%;
195         display: inline;
196         font-weight: normal;
197         padding: 0;
198         margin: 0;
199       }
200       
201       h2 {
202         font-family: 'Droid Sans';
203         color: black;
204         font-size: 120%;
205         padding: 0;
206         margin: 20px 0;
207       }
208             
209       h2:first-child {
210         margin-top: 0;
211       }
212  
213       section, footer {
214         font-family: 'Droid Sans';
215         color: #3f3f3f;
216         text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px;
217         margin: 100px 30px 0;
218         display: block;
219         overflow: hidden;
220       }
221       
222       footer {
223         font-size: 100%;
224         margin: 20px 0 0 30px;
225       }
226  
227       a {
228         color: inherit;
229         display: inline-block;
230         text-decoration: none;
231         line-height: 110%;
232         border-bottom: 2px solid #3f3f3f;
233       }
234  
235       ul {
236         margin: 0;
237         padding: 0;
238       }
239  
240       button {
241         font-size: 100%;
242       }
243       
244       pre button {
245         margin: 2px;
246       }
247       
248       section.left {
249         float: left;
250         width: 390px;
251       }
252       
253       section.small {
254         font-size: 24px;
255       }
256       
257       section.small ul {
258         margin: 0 0 0 15px;
259         padding: 0;
260       }
261       
262       section.small li {
263         padding-bottom: 0;
264       }
265             
266       section.middle {
267         line-height: 2em;
268         text-align: center;
269         display: table-cell;
270         vertical-align: middle;
271         height: 700px;
272         width: 900px;
273       }
274       
275       pre {
276         text-align: left;
277         font-family: 'Droid Sans Mono', Courier;
278         font-size: 80%;
279         padding: 10px 20px;
280         background: rgba(255, 0, 0, 0.05);
281         -webkit-border-radius: 8px;
282         -khtml-border-radius: 8px;
283         -moz-border-radius: 8px;
284         border-radius: 8px;
285         border: 1px solid rgba(255, 0, 0, 0.2);
286       }
287       
288       pre select {
289         font-family: Monaco, Courier;
290         border: 1px solid #c61800;
291       }
292         
293       input {
294         font-size: 100%;
295         margin-right: 10px;
296         font-family: Helvetica;
297         padding: 3px;
298       }
299       input[type="range"] {
300         width: 100%;
301       }
302       
303       button {
304         margin: 20px 10px 0 0;
305         font-family: Verdana;
306       }
307       
308       button.large {
309         font-size: 32px;
310       }
311         
312       pre b {
313         font-weight: normal;
314         color: #c61800;
315         text-shadow: #c61800 0 0 1px;
316         /*letter-spacing: -1px;*/
317       }
318       pre em {
319         font-weight: normal;
320         font-style: normal;
321         color: #18a600;
322         text-shadow: #18a600 0 0 1px;
323       }
324       pre input[type="range"] {
325         height: 6px;
326         cursor: pointer;
327         width: auto;
328       }
329       
330       div.example {
331         display: block;
332         padding: 10px 20px;
333         color: black;
334         background: rgba(255, 255, 255, 0.4);
335         -webkit-border-radius: 8px;
336         -khtml-border-radius: 8px;
337         -moz-border-radius: 8px;
338         border-radius: 8px;
339         margin-bottom: 10px;
340         border: 1px solid rgba(0, 0, 0, 0.2);
341       }
342       
343       video {
344         -moz-border-radius: 8px;
345         -khtml-border-radius: 8px;
346         -webkit-border-radius: 8px;
347         border-radius: 8px;
348         border: 1px solid rgba(0, 0, 0, 0.2);
349       }
350       
351       .key {
352         font-family: 'Droid Sans';
353         color: black;
354         display: inline-block;
355         padding: 6px 10px 3px 10px;
356         font-size: 100%;
357         line-height: 30px;
358         text-shadow: none;
359         letter-spacing: 0;
360         bottom: 10px;
361         position: relative;
362         -moz-border-radius: 10px;
363         -khtml-border-radius: 10px;
364         -webkit-border-radius: 10px;
365         border-radius: 10px;
366         background: white;
367         box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px;
368         -webkit-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px;
369         -moz-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px;
370         -o-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px;
371       }
372       
373       .key { font-family: Arial; }
374       
375       :not(header) > .key {
376         margin: 0 5px;
377         bottom: 4px;
378       }
379  
380       .two-column {
381         -webkit-column-count: 2;
382         -moz-column-count: 2;
383         column-count: 2;
384       }
385  
386       .stroke {
387         -webkit-text-stroke-color: red;
388         -webkit-text-stroke-width: 1px;
389       } /* currently webkit-only */
390       
391       .center {
392         text-align: center;
393       }
394       
395       #presentation-counter {
396         color: #ccc;
397         font-size: 70%;
398         letter-spacing: 1px;
399         position: absolute;
400         top: 40%;
401         left: 0;
402         width: 100%;
403         text-align: center;
404       }
405       
406       div:not(.current).reduced {
407         -webkit-transform: scale(0.8);
408         -moz-transform: scale(0.8);
409         -o-transform: scale(0.8);
410         transform: scale(0.8);
411       } 
412       
413       .no-transitions {
414         -webkit-transition: none;
415         -moz-transition: none;
416         -o-transition: none;
417         transition: none;
418       }
419  
420       .no-gradients {
421         background: none;
422         background-color: #fff;
423       }
424       
425       ul.bulleted {
426         padding-left: 30px;
427       }
428       
429     </style> 
430     
431   </head> 
432   <body> 
433     <div class="presentation"> 
434       <div id="presentation-counter"></div> 
435       <div class="slides"> 
436
437 <!--
438
439 Android
440 from
441 source
442 in
443 command-line
444
445 Android vs iPhone
446 TOC
447
448 Compile own ROM
449 CyanogenMod
450 Binary blobs from phone using adb pull
451 Android-x86
452 Downloads somewhat working (EeePC 701)
453 USB networking broken
454 http://github.com/dpavlin/android-adb-usb-tether
455
456 Debug from command-line
457 Do we need FLOSS app market?
458
459 -->
460
461         <div class="slide"> 
462           <section class="middle"> 
463             <h2>Android from source in command-line</h2>
464                         <img src="android-fastboot.png">
465                         <p>
466                                 Dobrica Pavlinušić
467                                 <br><a href="http://blog.rot13.org">http://blog.rot13.org/</a>
468                         </p>
469           </section> 
470         </div>
471
472         <div class="slide"> 
473           <section> 
474             <header> 
475               <h1>TOC</h1> 
476             </header> 
477               <h2>Compile Android from source code</h2> 
478               <h2>Command-line usage</h2> 
479               <h2>/system/bin</h2> 
480               <h2>Do we need FLOSS app market?</h2> 
481           </section> 
482         </div> 
483
484 <!--
485                 <div class="slide"> 
486                         <section class="middle"> 
487                                 <h2></h2> 
488                         </section> 
489                 </div>
490 -->
491                 <div class="slide"> 
492                         <section>
493                         <header>
494                         <h1>Compile Android from source</h1> 
495                         </header>
496
497                         <h2>Why is source important?</h2>
498                         <p>
499                         Lookup how is something implemented
500                         - <a href="http://github.com/dpavlin/android-adb-usb-tether">and find out why usb networking doesn't work for Google apps</a>
501                         </p>
502                         <p>Lastest Android released on abandoned hardware (Froyo on G1)</p>
503
504                         <h2>Ability to install your own ROM</h2>
505                         <p>
506                         severly udermined by attempts to provide full signature security from hardware to userspace
507                         </p>
508                         <p>
509                                 SPL
510                                 <span class="key">&gt;</span>
511                                 recovery
512                                 <span class="key">&gt;</span>
513                                 system
514                         </p>
515                         
516                         <h2>Porting to other devices</h2>
517                 </div>
518
519                 <div class="slide"> 
520                         <section>
521
522                         <header>
523                         <h1>Compile Android from source</h1> 
524                         </header>
525
526                         <h2>CyanogenMod</h2>
527
528             <ul class="bulleted"> 
529                                 <li>only for <b>rooted</b> phones (targets developers)
530                                 <li>binary blobs from phone using <tt>adb pull</tt></li>
531                                 <li><a href="http://wiki.cyanogenmod.com/index.php?title=Compile_CyanogenMod_for_Dream_%26_Sapphire">compile for your phone</a></li>
532 <pre>
533 dpavlin@android:/srv/cyanogen$ <b>. build/envsetup.sh</b>
534 dpavlin@android:/srv/cyanogen$ <b>lunch</b>
535 dpavlin@android:/srv/cyanogen$ <b>make -j8</b>
536 </pre>
537                                 <li>fastboot or sdcard <tt>update.zip</tt> flashing
538                                 <li><a href="http://github.com/CyanogenMod/android_vendor_cyanogen/blob/froyo/CHANGELOG.mkdn">additional features</a> on top of Google release
539             </ul>
540                         </section>
541         </div>
542
543                 <div class="slide"> 
544                         <section>
545
546                         <header>
547                         <h1>Compile Android from source</h1> 
548                         </header>
549
550                         <h2>Android-x86</h2>
551
552             <ul class="bulleted"> 
553                                 <li>Latest release <a href="http://android-x86.googlecode.com/files/android-x86-1.6-r2.iso">1.6r2</a> works on EeePC 701, VrtualBox and kvm</li>
554                                 <li><a href="http://www.android-x86.org/getsourcecode">compile source</a></li>
555                                 <li>Froyo (2.2) and Eclair (2.1) in various stages of <em>working</em>
556                                 <li>networking in kvm: boot in <b>debug</b> mode and in first prompt load network module:
557 <pre>
558 # <b>modprobe 8139cp</b>
559 </pre>
560                                 <li>add <tt>vga=788</tt> to kernel line in <tt>grub</tt> to make kvm happy
561             </ul>
562                         </section>
563         </div>
564
565
566
567                 <div class="slide"> 
568                         <section>
569                         <header>
570                         <h1>adb</h1> 
571                         </header>
572                         <h2>shell</h2>
573 <pre>
574 dpavlin@x200:/virtual/android$ <b>adb shell</b>
575 # <b>uname -a</b>
576 Linux localhost 2.6.35.4-cyanogenmod #57 PREEMPT Fri Sep 10 00:11:46 UTC 2010 armv6l GNU/Linux
577 </pre>
578
579                         <h2>logcat</h2>
580                         <p>Everything your Android is storing into log, <b>multiple buffers!</b></p>
581 <pre>
582 dpavlin@x200:/virtual/android$ <b>adb logcat -b events</b>
583 </pre>
584
585                         <h2>multiple devices</h2>
586 <pre>
587 dpavlin@x200:~$ <b>export ANDROID_SERIAL=127.0.0.1:5555</b>
588 </pre>
589
590                         </section>
591         </div>
592
593
594         <div class="slide"> 
595           <section class="middle"> 
596             <h1>Android userland</h1>
597                         <h2>/system/bin</h2>
598                         <a href="http://github.com/dpavlin/android-command-line">http://github.com/dpavlin/android-command-line</a>
599           </section> 
600         </div>
601
602
603                 <div class="slide"> 
604                         <section>
605                         <header>
606                         <h1>Dump debugging informations</h1> 
607                         </header>
608                         <h2>dumpstate</h2>
609                         <p>Big and verbose state of your device</p>
610 <pre>
611 dpavlin@x200:~$ <b>adb shell dumpstate > dumpstate.txt</b>
612 </pre>
613
614
615                         <h2>dumpsys</h2>
616                         <p>Who is listening to those intents?</p>
617 <pre>
618 dpavlin@x200:~$ <b>adb shell dumpsys > dumpsys.txt
619 </pre>
620
621                         </section>
622         </div>
623
624                 <div class="slide"> 
625                         <section>
626                         <header>
627                         <h1>service</h1> 
628                         </header>
629                         <h2>Make phone calls from command line</h2>
630 <pre>
631 # <b>service call phone 2 s16 "+31611530555"</b>
632 </pre>
633
634                         <p>
635                         Where did <b>2</b> came from?
636                         <a href="http://www.androidjavadoc.com/1.0_r1_src/constant-values.html#com.android">com.android.internal.telephony.ITelephony.Stub</a>
637                         </p>
638
639                         <h2>Rotate screen in emulator</h2>
640 <pre>
641 $ <b>service call window 18 i32 1</b> # landscape
642 $ <b>service call window 18 i32 0</b> # portrait
643 </pre>
644
645                         </section>
646         </div>
647
648                 <div class="slide"> 
649                         <section>
650                         <header>
651                         <h1>am</h1> 
652                         </header>
653                         <h2>Browser</h2>
654 <pre>
655 # <b>am start -a android.intent.action.MAIN -n com.android.browser/.BrowserActivity</b>
656 </pre>
657
658                         <h2>Settings</h2>
659 <pre>
660 # <b>am start -a android.intent.action.MAIN -n com.android.settings/.Settings</b>
661 </pre>
662                         </section>
663                         </section>
664         </div>
665
666                 <div class="slide"> 
667                         <section>
668                         <header>
669                         <h1>pm</h1> 
670                         </header>
671
672 <p>
673 Install application from phone to other device
674 </p>
675
676 <pre>
677 dpavlin@x200:~$ <b>adb shell pm list packages | grep replica</b>
678 package:com.replica.replicaisland
679 dpavlin@x200:~$ <b>adb shell pm path com.replica.replicaisland</b>
680 package:/mnt/asec/com.replica.replicaisland-1/pkg.apk
681 dpavlin@x200:~$ <b>adb pull /mnt/asec/com.replica.replicaisland-1/pkg.apk</b>
682 1373 KB/s (5144485 bytes in 3.658s)
683 dpavlin@x200:~$ <b>ANDROID_SERIAL=192.168.1.32:5555 adb install pkg.apk</b>
684 779 KB/s (5144485 bytes in 6.446s)
685         pkg: /data/local/tmp/pkg.apk
686 Success
687 </pre>
688                         </section>
689         </div>
690
691                 <div class="slide"> 
692                         <section>
693                         <header>
694                         <h1>Do we need FLOSS app market?</h1> 
695                         </header>
696 <p>
697 <a href="http://lwn.net/Articles/373128/">Jonathan Corbet of LWM fame</a> think we do and I agree.
698 </p>
699                         <h2>Working idea</h2>
700
701             <ul class="bulleted"> 
702                                 <li>FLOSS licence</li>
703                                 <li>source code repository (git)</li>
704                                 <li>all source searchable (gitweb?)</li>
705                                 <li>automatic builds (x86 NDK?)</li>
706                                 <li><b>download links from web!</b></li>
707                                 <li>backup apps to cloud (CouchDB?)</li>
708                         </ul>
709
710                         <p>Anybody interested in something like that?</p>
711
712                         </section>
713         </div>
714
715
716 <!-- extra slides -->
717
718         <div class="slide"> 
719           <section class="middle"> 
720             <h2>The Difference Between Android And iPhone</h2> 
721                         <p><a href="http://www.androidpolice.com/2010/09/16/comic-the-difference-between-android-and-iphone-this-pretty-much-sums-it-up/">This Pretty Much Sums It Up</a>
722           </section> 
723         </div>
724
725         <div class="slide"> 
726           <section class="middle"> 
727             <h2>Android</h2> 
728                         <img src="commic-Android.png">
729           </section> 
730         </div> 
731
732         <div class="slide"> 
733           <section class="middle"> 
734             <h2>iPhone</h2> 
735                         <img src="commic-iPhone.png">
736           </section> 
737         </div> 
738
739         <div class="slide"> 
740           <section class="middle"> 
741             <h1>Questions? Comments?</h1> 
742                         <h2>More information</h2>
743                         <p>this presentation: <a href="http://dpavlin.github.com/android-command-line/">http://dpavlin.github.com/android-command-line/</a></p>
744                         <p>repository: <a href="http://github.com/dpavlin/android-command-line/">http://github.com/dpavlin/android-command-line/</a></p>
745                         <p>my blog: <a href="http://blog.rot13.org">http://dpavlin.github.com/android-command-line/</a></p>
746                         </ul>
747           </section> 
748         </div> 
749
750         <div class="slide"> 
751           <section class="middle"> 
752           </section> 
753         </div> 
754
755         <div class="slide"> 
756           <section class="middle"> 
757             <h2>Slides template</h2> 
758             <p>Click here, Press <span class="key">&rarr;</span> key to advance.</p> 
759           </section> 
760         </div> 
761         
762
763         <div class="slide"> 
764           <section class="middle"> 
765             <h2> 
766               Attached Events
767             </h2> 
768             <ul> 
769               <li>[arrow keys] to go next and previous</p></li> 
770               <li>[mouse scroll wheel] to go next and previous</p></li> 
771               <li>[Ctrl or Command] + [+/-] to zoom in and out</p></li> 
772               <li>[touch gestures] for mobile devices</p></li> 
773             </ul> 
774           </section> 
775         </div> 
776  
777         <div class="slide"> 
778           <section class="middle"> 
779             <h2> 
780               Options
781             </h2> 
782             <ul> 
783               <li><input type="checkbox" id="toggle-size" /><label for="toggle-size"><span>Grow</span></label></li> 
784               <li><input type="checkbox" id="toggle-transitions" checked /><label for="toggle-transitions"><span>Transitions</span></label></li> 
785               <li><input type="checkbox" id="toggle-gradients" checked /><label for="toggle-gradients"><span>Gradients</span></label></li> 
786               <li><input type="checkbox" id="toggle-counter" checked /><label for="toggle-counter"><span>Slide numbers</span></label></li> 
787             </ul> 
788           </section> 
789         </div> 
790
791 <!--
792  
793         <div class="slide"> 
794           <section> 
795             <header> 
796               <h2>Placeholder content</h2> 
797             </header> 
798 <pre>// some sample code
799 &lt;canvas id="canvas" width="838" height="220"&gt;&lt;/canvas&gt;
800  
801 &lt;script&gt;
802   var canvasContext = document.getElementById("canvas").<b>getContext</b>("2d");
803   canvasContext.<b>fillRect</b>(250, 25, 150, 100);
804  
805   canvasContext.<b>beginPath</b>();
806   canvasContext.<b>arc</b>(450, 110, 100, Math.PI * 1/2, Math.PI * 3/2);
807   canvasContext.<b>lineWidth</b> = 15;
808   canvasContext.<b>lineCap</b> = 'round';
809   canvasContext.<b>strokeStyle</b> = 'rgba(255, 127, 0, 0.5)';
810   canvasContext.<b>stroke</b>();
811 &lt;/script&gt;
812 </pre> 
813             <ul class="bulleted"> 
814               <li>point 1</li> 
815               <li>point 2</li> 
816               <li>point 3</li> 
817             </ul> 
818           </section> 
819         </div> 
820
821 -->
822  
823       </div> <!-- slides --> 
824  
825     </div> <!-- presentation --> 
826  
827     <script> 
828       (function() {
829         var doc = document;
830         var disableBuilds = true;
831  
832         var ctr = 0;
833         var spaces = /\s+/, a1 = [''];
834  
835         var toArray = function(list) {
836           return Array.prototype.slice.call(list || [], 0);
837         };
838  
839         var byId = function(id) {
840           if (typeof id == 'string') { return doc.getElementById(id); }
841           return id;
842         };
843  
844         var query = function(query, root) {
845           if (!query) { return []; }
846           if (typeof query != 'string') { return toArray(query); }
847           if (typeof root == 'string') {
848             root = byId(root);
849             if(!root){ return []; }
850           }
851  
852           root = root || document;
853           var rootIsDoc = (root.nodeType == 9);
854           var doc = rootIsDoc ? root : (root.ownerDocument || document);
855  
856           // rewrite the query to be ID rooted
857           if (!rootIsDoc || ('>~+'.indexOf(query.charAt(0)) >= 0)) {
858             root.id = root.id || ('qUnique' + (ctr++));
859             query = '#' + root.id + ' ' + query;
860           }
861           // don't choke on something like ".yada.yada >"
862           if ('>~+'.indexOf(query.slice(-1)) >= 0) { query += ' *'; }
863  
864           return toArray(doc.querySelectorAll(query));
865         };
866  
867         var strToArray = function(s) {
868           if (typeof s == 'string' || s instanceof String) {
869             if (s.indexOf(' ') < 0) {
870               a1[0] = s;
871               return a1;
872             } else {
873               return s.split(spaces);
874             }
875           }
876           return s;
877         };
878  
879         var addClass = function(node, classStr) {
880           classStr = strToArray(classStr);
881           var cls = ' ' + node.className + ' ';
882           for (var i = 0, len = classStr.length, c; i < len; ++i) {
883             c = classStr[i];
884             if (c && cls.indexOf(' ' + c + ' ') < 0) {
885               cls += c + ' ';
886             }
887           }
888           node.className = cls.trim();
889         };
890  
891         var removeClass = function(node, classStr) {
892           var cls;
893           if (classStr !== undefined) {
894             classStr = strToArray(classStr);
895             cls = ' ' + node.className + ' ';
896             for (var i = 0, len = classStr.length; i < len; ++i) {
897               cls = cls.replace(' ' + classStr[i] + ' ', ' ');
898             }
899             cls = cls.trim();
900           } else {
901             cls = '';
902           }
903           if (node.className != cls) {
904             node.className = cls;
905           }
906         };
907  
908         var toggleClass = function(node, classStr) {
909           var cls = ' ' + node.className + ' ';
910           if (cls.indexOf(' ' + classStr.trim() + ' ') >= 0) {
911             removeClass(node, classStr);
912           } else {
913             addClass(node, classStr);
914           }
915         };
916  
917         var ua = navigator.userAgent;
918         var isFF = parseFloat(ua.split('Firefox/')[1]) || undefined;
919         var isWK = parseFloat(ua.split('WebKit/')[1]) || undefined;
920         var isOpera = parseFloat(ua.split('Opera/')[1]) || undefined;
921  
922         var canTransition = (function() {
923           var ver = parseFloat(ua.split('Version/')[1]) || undefined;
924           // test to determine if this browser can handle CSS transitions.
925           var cachedCanTransition = 
926             (isWK || (isFF && isFF > 3.6 ) || (isOpera && ver >= 10.5));
927           return function() { return cachedCanTransition; }
928         })();
929  
930         //
931         // Slide class
932         //
933         var Slide = function(node, idx) {
934           this._node = node;
935           if (idx >= 0) {
936             this._count = idx + 1;
937           }
938           if (this._node) {
939             addClass(this._node, 'slide distant-slide');
940           }
941           this._makeCounter();
942           this._makeBuildList();
943         };
944  
945         Slide.prototype = {
946           _node: null,
947           _count: 0,
948           _buildList: [],
949           _visited: false,
950           _currentState: '',
951           _states: [ 'distant-slide', 'far-past',
952                      'past', 'current', 'future',
953                      'far-future', 'distant-slide' ],
954           setState: function(state) {
955             if (typeof state != 'string') {
956               state = this._states[state];
957             }
958             if (state == 'current' && !this._visited) {
959               this._visited = true;
960               this._makeBuildList();
961             }
962             removeClass(this._node, this._states);
963             addClass(this._node, state);
964             this._currentState = state;
965  
966             // delay first auto run. Really wish this were in CSS.
967             /*
968             this._runAutos();
969             */
970             var _t = this;
971             setTimeout(function(){ _t._runAutos(); } , 400);
972           },
973           _makeCounter: function() {
974             if(!this._count || !this._node) { return; }
975             var c = doc.createElement('span');
976             c.innerHTML = this._count;
977             c.className = 'counter';
978             this._node.appendChild(c);
979           },
980           _makeBuildList: function() {
981             this._buildList = [];
982             if (disableBuilds) { return; }
983             if (this._node) {
984               this._buildList = query('[data-build] > *', this._node);
985             }
986             this._buildList.forEach(function(el) {
987               addClass(el, 'to-build');
988             });
989           },
990           _runAutos: function() {
991             if (this._currentState != 'current') {
992               return;
993             }
994             // find the next auto, slice it out of the list, and run it
995             var idx = -1;
996             this._buildList.some(function(n, i) {
997               if (n.hasAttribute('data-auto')) {
998                 idx = i;
999                 return true;
1000               }
1001               return false;
1002             });
1003             if (idx >= 0) {
1004               var elem = this._buildList.splice(idx, 1)[0];
1005               var transitionEnd = isWK ? 'webkitTransitionEnd' : (isFF ? 'mozTransitionEnd' : 'oTransitionEnd');
1006               var _t = this;
1007               if (canTransition()) {
1008                 var l = function(evt) {
1009                   elem.parentNode.removeEventListener(transitionEnd, l, false);
1010                   _t._runAutos();
1011                 };
1012                 elem.parentNode.addEventListener(transitionEnd, l, false);
1013                 removeClass(elem, 'to-build');
1014               } else {
1015                 setTimeout(function() {
1016                   removeClass(elem, 'to-build');
1017                   _t._runAutos();
1018                 }, 400);
1019               }
1020             }
1021           },
1022           buildNext: function() {
1023             if (!this._buildList.length) {
1024               return false;
1025             }
1026             removeClass(this._buildList.shift(), 'to-build');
1027             return true;
1028           },
1029         };
1030  
1031         //
1032         // SlideShow class
1033         //
1034         var SlideShow = function(slides) {
1035           this._slides = (slides || []).map(function(el, idx) {
1036             return new Slide(el, idx);
1037           });
1038  
1039           var h = window.location.hash;
1040           try {
1041             this.current = parseInt(h.split('#slide')[1], 10);
1042           }catch (e) { /* squeltch */ }
1043           this.current = isNaN(this.current) ? 1 : this.current;
1044           var _t = this;
1045           doc.addEventListener('keydown', 
1046               function(e) { _t.handleKeys(e); }, false);
1047           doc.addEventListener('mousewheel', 
1048               function(e) { _t.handleWheel(e); }, false);
1049           doc.addEventListener('DOMMouseScroll', 
1050               function(e) { _t.handleWheel(e); }, false);
1051           doc.addEventListener('touchstart', 
1052               function(e) { _t.handleTouchStart(e); }, false);
1053           doc.addEventListener('touchend', 
1054               function(e) { _t.handleTouchEnd(e); }, false);
1055           window.addEventListener('popstate', 
1056               function(e) { _t.go(e.state); }, false);
1057           this._update();          
1058         };
1059  
1060         SlideShow.prototype = {
1061           _slides: [],
1062           _update: function(dontPush) {
1063             document.querySelector('#presentation-counter').innerText = this.current;
1064             if (history.pushState) {
1065               if (!dontPush) {
1066                 history.pushState(this.current, 'Slide ' + this.current, '#slide' + this.current);
1067               }
1068             } else {
1069               window.location.hash = 'slide' + this.current;
1070             }
1071             for (var x = this.current-1; x < this.current + 7; x++) {
1072               if (this._slides[x-4]) {
1073                 this._slides[x-4].setState(Math.max(0, x-this.current));
1074               }
1075             }
1076           },
1077  
1078           current: 0,
1079           next: function() {
1080             if (!this._slides[this.current-1].buildNext()) {
1081               this.current = Math.min(this.current + 1, this._slides.length);
1082               this._update();
1083             }
1084           },
1085           prev: function() {
1086             this.current = Math.max(this.current-1, 1);
1087             this._update();
1088           },
1089           go: function(num) {
1090             if (history.pushState && this.current != num) {
1091               history.replaceState(this.current, 'Slide ' + this.current, '#slide' + this.current);
1092             }
1093             this.current = num;
1094             this._update(true);
1095           },
1096  
1097           _notesOn: false,
1098           showNotes: function() {
1099             var isOn = this._notesOn = !this._notesOn;
1100             query('.notes').forEach(function(el) {
1101               el.style.display = (notesOn) ? 'block' : 'none';
1102             });
1103           },
1104           switch3D: function() {
1105             toggleClass(document.body, 'three-d');
1106           },
1107           handleWheel: function(e) {
1108             var delta = 0;
1109             if (e.wheelDelta) {
1110               delta = e.wheelDelta/120;
1111               if (isOpera) {
1112                 delta = -delta;
1113               }
1114             } else if (e.detail) {
1115               delta = -e.detail/3;
1116             }
1117  
1118             if (delta > 0 ) {
1119               this.prev();
1120               return;
1121             }
1122             if (delta < 0 ) {
1123               this.next();
1124               return;
1125             }
1126           },
1127           handleKeys: function(e) {
1128             
1129             if (/^(input|textarea)$/i.test(e.target.nodeName)) return;
1130             
1131             switch (e.keyCode) {
1132               case 37: // left arrow
1133                 this.prev(); break;
1134               case 39: // right arrow
1135               case 32: // space
1136                 this.next(); break;
1137               case 50: // 2
1138                 this.showNotes(); break;
1139               case 51: // 3
1140                 this.switch3D(); break;
1141             }
1142           },
1143           _touchStartX: 0,
1144           handleTouchStart: function(e) {
1145             this._touchStartX = e.touches[0].pageX;
1146           },
1147           handleTouchEnd: function(e) {
1148             var delta = this._touchStartX - e.changedTouches[0].pageX;
1149             var SWIPE_SIZE = 150;
1150             if (delta > SWIPE_SIZE) {
1151               this.next();
1152             } else if (delta< -SWIPE_SIZE) {
1153               this.prev();
1154             }
1155           },
1156         };
1157  
1158         // Initialize
1159         var slideshow = new SlideShow(query('.slide'));
1160         
1161         
1162         
1163         
1164         
1165         document.querySelector('#toggle-counter').addEventListener('click', toggleCounter, false);
1166         document.querySelector('#toggle-size').addEventListener('click', toggleSize, false);
1167         document.querySelector('#toggle-transitions').addEventListener('click', toggleTransitions, false);
1168         document.querySelector('#toggle-gradients').addEventListener('click', toggleGradients, false);
1169  
1170  
1171         var counters = document.querySelectorAll('.counter');
1172         var slides = document.querySelectorAll('.slide');
1173  
1174         function toggleCounter() {
1175           toArray(counters).forEach(function(el) {
1176             el.style.display = (el.offsetHeight) ? 'none' : 'block';
1177           });
1178         }
1179         
1180         function toggleSize() {
1181           toArray(slides).forEach(function(el) {
1182             if (!/reduced/.test(el.className)) {
1183               addClass(el, 'reduced');
1184             }
1185             else {
1186               removeClass(el, 'reduced');
1187             }
1188           });
1189         }
1190  
1191         function toggleTransitions() {
1192           toArray(slides).forEach(function(el) {
1193             if (!/no-transitions/.test(el.className)) {
1194               addClass(el, 'no-transitions');
1195             }
1196             else {
1197               removeClass(el, 'no-transitions');
1198             }
1199           });
1200         }
1201         
1202         function toggleGradients() {
1203           toArray(slides).forEach(function(el) {
1204             if (!/no-gradients/.test(el.className)) {
1205               addClass(el, 'no-gradients');
1206             }
1207             else {
1208               removeClass(el, 'no-gradients');
1209             }
1210           });
1211         }
1212         
1213         
1214         
1215         
1216         
1217       })();
1218       
1219       
1220       
1221     </script> 
1222  
1223     <!--[if lt IE 9]>
1224     <script 
1225       src="http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js">
1226     </script>
1227                 <script>CFInstall.check({ mode: "overlay" });</script>
1228     <![endif]--> 
1229     
1230   </body> 
1231 </html>