Mercurial > hg > Papers > 2013 > nobuyasu-jssst
changeset 46:0c6ef18bf2e8
add meeting20130802
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 02 Aug 2013 09:54:58 +0900 |
parents | b30647480e97 |
children | 533180cea89f |
files | Paper/jssst.tex meeting20130802/.DS_Store meeting20130802/index.html meeting20130802/pic/.DS_Store meeting20130802/pic/alice_topology.png meeting20130802/pic/cassandra.png meeting20130802/pic/destructive_tree.png meeting20130802/pic/distribute_jungle.png meeting20130802/pic/dsandcs.pdf meeting20130802/pic/dsandcs.png meeting20130802/pic/nodepath.png meeting20130802/pic/non_destructive_tree.png meeting20130802/pic/putChildLog.png meeting20130802/pic/putLog.png meeting20130802/pic/read_result.png meeting20130802/pic/tree_topology.png meeting20130802/pic/write_result.png meeting20130802/prettify.js meeting20130802/slides.js meeting20130802/styles.css meeting20130802/template.html |
diffstat | 21 files changed, 3474 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/Paper/jssst.tex Fri Jul 19 19:44:20 2013 +0900 +++ b/Paper/jssst.tex Fri Aug 02 09:54:58 2013 +0900 @@ -36,7 +36,7 @@ % 和文論文の場合,姓と名の間には半角スペースを入れ, % 複数の著者の間は全角スペースで区切る % -\author{大城 信康 \and 杉本 優 \and 河野 真治 +\author{大城 信康 \and 杉本 優 \and 河野 真治 \and 永山 辰巳 % % ここにタイトル英訳 (英文の場合は和訳) を書く. % @@ -47,7 +47,8 @@ % 複数著者の所属はまとめてよい. % \shozoku{Nobuyasu OSHIRO,Yu SUGIMOTO, Shinij KONO }{琉球大学大学院理工学研究科情報工学専攻並列信頼研}% -{Dept.Concurrency Reliance Laboratory, Information Engineering Course, Faculty of Engineering Graduate School of Engineering and Science, University of the Ryukyus} +{Dept.Concurrency Reliance Laboratory, Information Engineering Course, Faculty of Engineering Graduate School of Engineering and Science, University of the Ryukyus, } +\shozoku{Tatsumi NAGAYAMA}{株式会社 Symphony}{Symphony Co., LTD} % % 出典情報は \shutten とすれば出力される. %\shutten
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meeting20130802/index.html Fri Aug 02 09:54:58 2013 +0900 @@ -0,0 +1,475 @@ +<!DOCTYPE html> +<html> + <head> + <style type="text/css"> + .center { + margin-left: auto; + margin-right: auto; + text-align: center; + } + </style> + + <title>Presentation</title> + + <meta charset='utf-8'> + <script + src='./slides.js'></script> + </head> + + <style> + /* Your individual styles here, or just use inline styles if that’s + what you want. */ + + + </style> + + <body style='display: none'> + + <section class='slides layout-regular template-default'> + + <!-- Your slides (<article>s) go here. Delete or comment out the + slides below. --> + + + <article> + <h1><font size=10em> +Data Segment の分散データベースへの応用 + </font> + </h1> + <p> + 琉球大学 大城信康 + <br> + 30 July 2013 + </p> + </article> + + <article> + <h3>研究の目的と背景</h3> + <ul> + <li>当研究室では並列・分散プログラムに向いたプログラミングを目指し, + タスクを Code Segment, データを Data Segment によるプログラミング手法の提案を行なっている</li> + <li>Code Segment, Data Segment によるプログラミングの提供をする実装として分散ネットワークフレームワーク Alice + を開発をしている</li> + </ul> + </article> + + <article> + <h3>研究の目的と背景</h3> + <ul> + <li>また, 当研究室では非破壊的木構造を用いたデータベースである Jungle の開発も行なっている</li> + <li>Jungle はデータの編集を TreeOperationLog という単位で行う</li> + <li>Alice を使いこの TreeOperationLog を各ノード間で送受信することでデータの分散を行うことができる.</li> + <li>本研究では, Alice と Jungle を用いて分散データベースの実装を行う</li> + <li>さらに, 例題アプリケーションとして掲示板を作成し, 評価を行う</li> + </ul> + </article> + + <article> + <h3>分散ネットワークフレームワーク Alice</h3> + <ul> + <li>当研究室で開発している分散管理フレームワーク</li> + <li>Data Segment と Code Segment による並列・分散プログラミングを提供</li> + <br> + <li>Data Segment と Code Segment についての説明を行う</li> + </ul> + </article> + + <article> + <h3>Data Segment</h3> + <ul> + <li>計算に必要なデータ</li> + <li>Alice は Data Segment を文字列の Key で管理</li> + <li>Key 毎にリストが用意され, put された順番で Data Segment は取り出される</li> + <li>Data Segment Manager(DSM) により管理される</li> + </ul> + </article> + + <article> + <h3>Code Segment</h3> + <ul> + <li>Data Segment を受け取り計算を行うコード</li> + <li>並列プログラミングにおけるタスクにあたる</li> + <li>Code Segment は計算に使う Data Segment の Key を登録してその Key にあたる Data Segment + が用意され次第処理が実行される</li> + <p class="center"> + <img src="./pic/dsandcs.png"> + </p> + </ul> + </article> + + <article> + <h3>MessagePack</h3> + <ul> + <li>Data Segment のデータ表現には MessagePack を利用</li> + <li>Messagepack はバイナリをベースにしたシリアライズライブラリー</li> + <li>独自のクラスでも @Message アノテーションを付けることでシリアライズ可能</li> + </ul> + </article> + + + <article> + <h3>非破壊的木構造を用いたデータベース Jungle</h3> + <ul> + <li>Jungle はスケーラビリティのある CMS の開発を目指している</li> + <li>一般的なコンテンツマネジメントシステムのウェブサイトの構造は大体がき構造</li> + <br> + <li>まず破壊的木構造と, 非破壊的木構造の説明をおこなう</li> + </ul> + </article> + + <article> + <h3>破壊的木構造</h3> + <ul> + <li>木構造で保持するデータを直接書き換える</li> + <li>編集を行う際にロックをかける必要がある</li> + <p class="center"> + <img src="./pic/destructive_tree.png"> + </p> + <li>データを受け取ろうと木を走査するスレッドは編集時には書き換えの終了をまつ必要がある</li> + <li><font color=red>スケールしにくい</font></li> + </ul> + </article> + + <article> + <h3>非破壊的木構造</h3> + <ul> + <li>一度作成したデータの破壊は行わない</li> + <li>データの編集は, 編集が行われるノードまでをルートからコピーを行い新しい木構造を作ることで行う</li> + <p class="center"> + <img src="./pic/non_destructive_tree.png"> + </p> + <li>非破壊的木構造ではデータの編集中に走査をすることが可能なためスケールすると考えている</li> + </ul> + </article> + + <article> + <h3>Jungle におけるデータ編集</h3> + <ul> + <li>Jungle ではデータの編集を行う Editor を提供している</li> + <li>Editor が提供するデータ編集のメソッドは次のようなものがある</li> + <ul> + <li>Nodeの追加を行う<br>addNewChildAt(NodePath _path, int _pos)</li> + <li>Nodeの削除を行う<br>deleteChildAt(NodePath _path, int pos)</li> + <li>Nodeにattributeを追加する<br>putAttribute(NodePath _path, String _key,<br> ByteBuffer _value)</li> + <li>Nodeのattributeを削除する<br>deleteAttribute(NodePath _path, String _key)</li> + </ul> + </ul> + </article> + + <article> + <h3>Jungle におけるデータ編集</h3> + <ul> + <li>NodePath は root から編集を行う Node までの道を示す</li> + <li>例えば NodePath が -1,1,2,3 の場合は次の Node を示す</li> + <p class="center"> + <img src="./pic/nodepath.png"> + </p> + <li>Jungle におけるデータ編集はこの NodePath を Editor が提供する API に渡すことで行われる</li> + </ul> + </article> + + <article> + <h3>TreeOperationLog</h3> + <ul> + <li>Editor による編集の命令はある程度の塊で扱われる</li> + <li>この編集の塊を TreeOperatinLog という</li> + <li>今回実装した掲示板では, 書き込み時に次のような TreeOperaitonLog が作られる</li> + <pre> +[APPEND_CHILD:<-1>:pos:1] +[PUT_ATTRIBUTE:<-1,1>:key:author,value:oshiro] +[PUT_ATTRIBUTE:<-1,1>:key:mes,value:hello] +[PUT_ATTRIBUTE:<-1,1>:key:key,value:hoge] +[PUT_ATTRIBUTE:<-1,1>:key:timestamp,value:0] </pre> + <li>大文字の英字は実行した API を示す</li> + <li><>で囲まれた数字は NodePath を示す</li> + <li>key と value は attribute に格納する内容を示す</li> + </ul> + </article> + + <article> + <h3>Alice を用いた Jungle の分散実装</h3> + <ul> + <li>Alice により TreeOperationLog を Data Segment として扱うことで行う</li> + <li>他Nodeがその Data Segment にアクセスを行えるようにする</li> + <li>アクセスできるようにするためには次の作業が必要</li> + <ul> + <li>トポロジーの形成</li> + <li>TreeOperationLog を MessagePack によりシリアライズ</li> + <li>TreeOperationlog を扱う Data Segment の作成</li> + </ul> + </ul> + </article> + + <article> + <h3>トポロジーの形成</h3> + <ul> + <li>トポロジーの形成は Alice の機能を用いる</li> + <li>Alice ではトポロジー設定用ファイルに従いノード同士を接続させる</li> + <li>5ノード2分木のノードを組みたいときは次のようなファイルになる</li> + <pre style="overflow:scroll; height:300px;"> +digraph test { +node0 -> node1 +node0 -> node2 +node1 -> node0 +node1 -> node3 +node1 -> node4 +node2 -> node0 +[label="child1"] +[label="child2"] +[label="parent"] +[label="child1"] +[label="child2"] +[label="parent"] +node3 -> node1 [label="parent"] +node4 -> node1 [label="parent"] +} + </pre> + </ul> + </article> + + <article> + <h3>トポロジーの形成</h3> + <ul> + <p>生成されるトポロジー</p> + <p class="center"> + <img src="./pic/tree_topology.png"> + </p> + <li>子供となるノードは parent キーにより親の DSM にアクセスできる</li> + <li>親となるノードは child0, child1 キーにより子供のノードの DSM にアクセスできる</li> + <li><font color=blue>Alice が提供する機能により楽にトポロジーの形成と他のノードがもつデータへのアクセスができる</font></li> + </ul> + </article> + + <article> + <h3>TreeOperationLog の MessagePack によるシリアライズ</h3> + <ul> + <li>TreeOperationLog を Data Segment で扱うために MessagePack によるシリアライズ可能にする必要がある</li> + <li>MessagePack によりクラスをシリアライズするためには, そのクラスがもつフィールド全てがシリアライズできるものでないといけない</li> + <li>TreeOperationLog が保持するフィールドを全てシリアライズして保持する container を用意</li> + <li>TreeOperationLog は一度その container で Value 型へと変換されて保持されることで Data Segment として扱えるようにした</li> + </ul> + </article> + + <article> + <h3>ログを扱う Data Segment</h3> + <ul> + <li>Data Segment にされた TreeOperaiontinLog はAlice上で "log", "childLog" というキーで扱われる</li> + <li>"log" にはそのノードが行った木の編集ログが入る</li> + <li>子供となるノードは "parent" キーを使うことで親のノードの DSM にアクセスできる</li> + <p class="center"> + <img src="./pic/alice_topology.png"> + </p> + <li>子供となるノードは親の "log" を見張る Code Segment が走らせており, ログが put されると + そのデータを受け取り自身の Tree へと反映を行う</li> + </ul> + </article> + + <article> + <h3>ログを扱う Data Segment</h3> + <ul> + <li>"childLog" には子供となるノードが行った編集のログが入れられる</li> + <li>各ノードでは "childLog" を見張る Code Segment が走っており, データが put され次第 + Tree へのログの反映が行われる</li> + <li>親ノードの "log" と自身がもつ "childLog" を Code Segment でみはることでデータの分散を + 行う</li> + <table> + <tr style="width:100%;"> + <td style="width:50%;"> + <p> + <img src="./pic/putLog.png"> + </p> + </td> + <td style="width:50%;"> + <p> + <img src="./pic/putChildLog.png"> + </p> + </td> + </tr> + </table> + </ul> + </article> + + <article> + <h3>Merge algorithm の設計</h3> + <ul> + <li>Jungle はログの衝突が起きた場合に Merge を行うことで衝突を解決する</li> + <li>今回実装した掲示板における Merge algorithm は単純な実装</li> + <li>書き込むデータと既に書き込まれたデータのタイムスタンプをみてMergeを行う</li> + <br> + <li>掲示板においてのMergeはそれで十分だが, ブログやWikiといったCMSを設計するさいには + もっと複雑なMergeになる</li> + <li>どのようにMerge algorithmを実装していくかはよく考えていかなければならない</li> + </ul> + </article> + + <article> + <h3>Cassandra との比較</h3> + <ul> + <li>Cassandra ではデータの書き込みはノードの過半数に行われるのを待つ</l> + <li>読み込みに関しても過半数のノードを調べ, 最も新しいタイムスタンプを持つデータを返す</li> + <p class="center"> + <img src="./pic/cassandra.png"> + </p> + </ul> + </article> + + <article> + <h3>Cassandra との比較: Jungle の場合</h3> + <ul> + <li>Jungle ではデータはノードが手元に持っているものを返す</li> + <li>データの編集が行われた場合は, 他ノードへとログを伝搬していく</li> + <li>ログの衝突が起きた場合は衝突を検知したノードがMergeを行い, Mergeを行ったログを伝搬させる</li> + <p class="center"> + <img src="./pic/distribute_jungle.png"> + </p> + </ul> + </article> + + <article> + <h3>Cassandra との比較</h3> + <ul> + <li>Jungle では非破壊により過去のデータを保持しているためMergeを行うことが可能</li> + <li>それにより最新のデータなくてもデータを返すことができる</li> + <li><font color=blue>ロックが少なくなりスケーラビリティに繋がると考えている</font></li> + </ul> + </article> + + <article> + <h3>掲示板によるJungleの性能評価</h3> + <ul> + <li>Jungle の例題のアプリケーションとして掲示板を作成した</li> + <li>組み込みウェブサーバである jetty をフロントエンドに実装</li> + <li>今回作成した分散バージョンと元のバージョンをシングルサーバ上で動かし, 2つの + ベンチマークをとり性能比較を行う</li> + <li>ベンチマークは学科の提供するVMのクラスタを用いる</li> + </ul> + </article> + + <article> + <h3>実験方法</h3> + <ul> + <li>複数のクラスタから並列に5000回アクセス(HTTP Request)を行い, 平均時間をとる</li> + <li>クラスタ1台から45台まで順次並列にアクセスを行った結果をグラフ化する</li> + </ul> + </article> + + + <article> + <h3>実験環境</h3> + <table style="font-size: 0.7em;"> + <tr> + <th></th><th>掲示板を動かすサーバのスペック</th> + </tr> + <tr> + <td>CPU</td> + <td>Intel(R) Xeon(R) CPU X5650@2.67GHz</td> + </tr> + <tr> + <td>コア数</td> + <td>24</td> + </tr> + <tr> + <td>Memory</td> + <td>132GB</td> + </tr> + + <table style="font-size: 0.7em"/> + <tr> + <th></th><th>VMWareクラスタ(リクエストをおくるサーバ)</th> + </tr> + <tr> + <td>台数</td><td>45</td> + </tr> + <tr> + <td>CPU</td> + <td>Intel(R) Xeon(R) CPU X5650@2.67GHz</td> + </tr> + <tr> + <td>コア数</td> + <td>4</td> + </tr> + <tr> + <td>Memory</td> + <td>8GB</td> + </tr> + <tr> + <td>OS</td> + <td>Fedora 16</td> + </tr> + <tr> + <td>HyperVisor</td> + <td>VMWare ESXi</td> + </tr> + </table> + + + + </article> + + <article> + <h3>実験結果: 読み込み</h3> + <table style="text-align:center; font-size:0.7em;"> + <tr> + <td> <img style="height:300px;" src="./pic/read_result.png"> </td> + </tr> + <tr> + <td>サーバの読み込み実験結果</td> + </tr> + </table> + <ul> + <li>今回の実装では読み込みに関する部分は無い</li> + <li>そのため分散サーバ版とシングルサーバ版もに似た結果となっている</li> + <li>グラフも両方とも平行にあがっている</li> + </ul> + </article> + + <article> + <h3>実験結果: 書き込み</h3> + <table style="text-align:center; font-size:0.7em;"> + <tr> + <td > <img style="height:300px;" src="./pic/write_result.png"> </td> + </tr> + <tr> + <td>サーバの書き込み実験結果</td> + </tr> + </table> + <ul> + <li>分散サーバ版がシングルサーバ版よりも遅い</li> + <li>これは分散版は書き込まれた内容をData Segment にする作業がはいる為とおもわれる</li> + </ul> + </article> + + <article> + <h3>まとめ</h3> + <ul> + <li>今回, Alice を用いて Jungle の分散データベースの実装を行った</li> + <li>Jungle の編集のログを Data Segment として Alice 上で他ノードへと送ることで実装</li> + <li>今回シングル版から分散版への変更は1000行程度のコードの追加で行うことができた</li> + <li>これは Alice によりトポロジーの形成部分を書く必要がなかったことがあげられる</li> + <li>Alice を用いてると比較的楽に分散プログラムの作成ができることが確認できた</li> + </ul> + </article> + + <article> + <h3>まとめ 2</h3> + <ul> + <li>また, 実装を行った分散データベースで掲示板の作成を, 元の Jungle との性能比較も行った</li> + <li>読み込み速度に差は無いが, 書き込み速度は分散版が遅いことを確認した</li> + </ul> + </article> + + <article> + <h3>今後の課題</h3> + <ul> + <li>次回は, Cassandra でも同じ分散プログラムを作り, 分散環境における性能比較を行いたい</li> + <li>そのためには分散データベースにおけるベンチマークの取り方の検証から行う必要がある</li> + <br> + <li>また, Alice 内部では java.util.concurrent.Executorを使用している</li> + <li>Alice を使用してのプログラムは Alice 自身の Thread Pool との調和も考えていく必要もある</li> + <li>Alice の Thread Pool との競合性についての懸賞も行なって行きたい</li> + </ul> + </article> + + + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meeting20130802/prettify.js Fri Aug 02 09:54:58 2013 +0900 @@ -0,0 +1,1391 @@ +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * @fileoverview + * some functions for browser-side pretty printing of code contained in html. + * + * <p> + * For a fairly comprehensive set of languages see the + * <a href="http://google-code-prettify.googlecode.com/svn/trunk/README.html#langs">README</a> + * file that came with this source. At a minimum, the lexer should work on a + * number of languages including C and friends, Java, Python, Bash, SQL, HTML, + * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk + * and a subset of Perl, but, because of commenting conventions, doesn't work on + * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. + * <p> + * Usage: <ol> + * <li> include this source file in an html page via + * {@code <script type="text/javascript" src="/path/to/prettify.js"></script>} + * <li> define style rules. See the example page for examples. + * <li> mark the {@code <pre>} and {@code <code>} tags in your source with + * {@code class=prettyprint.} + * You can also use the (html deprecated) {@code <xmp>} tag, but the pretty + * printer needs to do more substantial DOM manipulations to support that, so + * some css styles may not be preserved. + * </ol> + * That's it. I wanted to keep the API as simple as possible, so there's no + * need to specify which language the code is in, but if you wish, you can add + * another class to the {@code <pre>} or {@code <code>} element to specify the + * language, as in {@code <pre class="prettyprint lang-java">}. Any class that + * starts with "lang-" followed by a file extension, specifies the file type. + * See the "lang-*.js" files in this directory for code that implements + * per-language file handlers. + * <p> + * Change log:<br> + * cbeust, 2006/08/22 + * <blockquote> + * Java annotations (start with "@") are now captured as literals ("lit") + * </blockquote> + * @requires console + */ + +// JSLint declarations +/*global console, document, navigator, setTimeout, window */ + +/** + * Split {@code prettyPrint} into multiple timeouts so as not to interfere with + * UI events. + * If set to {@code false}, {@code prettyPrint()} is synchronous. + */ +window['PR_SHOULD_USE_CONTINUATION'] = true; + +/** the number of characters between tab columns */ +window['PR_TAB_WIDTH'] = 8; + +/** Contains functions for creating and registering new language handlers. + * @type {Object} + */ +window['PR'] + +/** Pretty print a chunk of code. + * + * @param {string} sourceCodeHtml code as html + * @return {string} code as html, but prettier + */ + = window['prettyPrintOne'] +/** Find all the {@code <pre>} and {@code <code>} tags in the DOM with + * {@code class=prettyprint} and prettify them. + * @param {Function?} opt_whenDone if specified, called when the last entry + * has been finished. + */ + = window['prettyPrint'] = void 0; + + +(function () { + // Keyword lists for various languages. + var FLOW_CONTROL_KEYWORDS = + "break continue do else for if return while "; + var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " + + "double enum extern float goto int long register short signed sizeof " + + "static struct switch typedef union unsigned void volatile "; + var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " + + "new operator private protected public this throw true try typeof "; + var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " + + "concept concept_map const_cast constexpr decltype " + + "dynamic_cast explicit export friend inline late_check " + + "mutable namespace nullptr reinterpret_cast static_assert static_cast " + + "template typeid typename using virtual wchar_t where "; + var JAVA_KEYWORDS = COMMON_KEYWORDS + + "abstract boolean byte extends final finally implements import " + + "instanceof null native package strictfp super synchronized throws " + + "transient "; + var CSHARP_KEYWORDS = JAVA_KEYWORDS + + "as base by checked decimal delegate descending dynamic event " + + "fixed foreach from group implicit in interface internal into is lock " + + "object out override orderby params partial readonly ref sbyte sealed " + + "stackalloc string select uint ulong unchecked unsafe ushort var "; + var COFFEE_KEYWORDS = "all and by catch class else extends false finally " + + "for if in is isnt loop new no not null of off on or return super then " + + "true try unless until when while yes "; + var JSCRIPT_KEYWORDS = COMMON_KEYWORDS + + "debugger eval export function get null set undefined var with " + + "Infinity NaN "; + var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " + + "goto if import last local my next no our print package redo require " + + "sub undef unless until use wantarray while BEGIN END "; + var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " + + "elif except exec finally from global import in is lambda " + + "nonlocal not or pass print raise try with yield " + + "False True None "; + var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" + + " defined elsif end ensure false in module next nil not or redo rescue " + + "retry self super then true undef unless until when yield BEGIN END "; + var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " + + "function in local set then until "; + var ALL_KEYWORDS = ( + CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS + + PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS); + + // token style names. correspond to css classes + /** token style for a string literal */ + var PR_STRING = 'str'; + /** token style for a keyword */ + var PR_KEYWORD = 'kwd'; + /** token style for a comment */ + var PR_COMMENT = 'com'; + /** token style for a type */ + var PR_TYPE = 'typ'; + /** token style for a literal value. e.g. 1, null, true. */ + var PR_LITERAL = 'lit'; + /** token style for a punctuation string. */ + var PR_PUNCTUATION = 'pun'; + /** token style for a punctuation string. */ + var PR_PLAIN = 'pln'; + + /** token style for an sgml tag. */ + var PR_TAG = 'tag'; + /** token style for a markup declaration such as a DOCTYPE. */ + var PR_DECLARATION = 'dec'; + /** token style for embedded source. */ + var PR_SOURCE = 'src'; + /** token style for an sgml attribute name. */ + var PR_ATTRIB_NAME = 'atn'; + /** token style for an sgml attribute value. */ + var PR_ATTRIB_VALUE = 'atv'; + + /** + * A class that indicates a section of markup that is not code, e.g. to allow + * embedding of line numbers within code listings. + */ + var PR_NOCODE = 'nocode'; + + /** A set of tokens that can precede a regular expression literal in + * javascript. + * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full + * list, but I've removed ones that might be problematic when seen in + * languages that don't support regular expression literals. + * + * <p>Specifically, I've removed any keywords that can't precede a regexp + * literal in a syntactically legal javascript program, and I've removed the + * "in" keyword since it's not a keyword in many languages, and might be used + * as a count of inches. + * + * <p>The link a above does not accurately describe EcmaScript rules since + * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works + * very well in practice. + * + * @private + */ + var REGEXP_PRECEDER_PATTERN = function () { + var preceders = [ + "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=", + "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=", + "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";", + "<", "<<", "<<=", "<=", "=", "==", "===", ">", + ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", + "^", "^=", "^^", "^^=", "{", "|", "|=", "||", + "||=", "~" /* handles =~ and !~ */, + "break", "case", "continue", "delete", + "do", "else", "finally", "instanceof", + "return", "throw", "try", "typeof" + ]; + var pattern = '(?:^^|[+-]'; + for (var i = 0; i < preceders.length; ++i) { + pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1'); + } + pattern += ')\\s*'; // matches at end, and matches empty string + return pattern; + // CAVEAT: this does not properly handle the case where a regular + // expression immediately follows another since a regular expression may + // have flags for case-sensitivity and the like. Having regexp tokens + // adjacent is not valid in any language I'm aware of, so I'm punting. + // TODO: maybe style special characters inside a regexp as punctuation. + }(); + + + /** + * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally + * matches the union of the sets of strings matched by the input RegExp. + * Since it matches globally, if the input strings have a start-of-input + * anchor (/^.../), it is ignored for the purposes of unioning. + * @param {Array.<RegExp>} regexs non multiline, non-global regexs. + * @return {RegExp} a global regex. + */ + function combinePrefixPatterns(regexs) { + var capturedGroupIndex = 0; + + var needToFoldCase = false; + var ignoreCase = false; + for (var i = 0, n = regexs.length; i < n; ++i) { + var regex = regexs[i]; + if (regex.ignoreCase) { + ignoreCase = true; + } else if (/[a-z]/i.test(regex.source.replace( + /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) { + needToFoldCase = true; + ignoreCase = false; + break; + } + } + + function decodeEscape(charsetPart) { + if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); } + switch (charsetPart.charAt(1)) { + case 'b': return 8; + case 't': return 9; + case 'n': return 0xa; + case 'v': return 0xb; + case 'f': return 0xc; + case 'r': return 0xd; + case 'u': case 'x': + return parseInt(charsetPart.substring(2), 16) + || charsetPart.charCodeAt(1); + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + return parseInt(charsetPart.substring(1), 8); + default: return charsetPart.charCodeAt(1); + } + } + + function encodeEscape(charCode) { + if (charCode < 0x20) { + return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16); + } + var ch = String.fromCharCode(charCode); + if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') { + ch = '\\' + ch; + } + return ch; + } + + function caseFoldCharset(charSet) { + var charsetParts = charSet.substring(1, charSet.length - 1).match( + new RegExp( + '\\\\u[0-9A-Fa-f]{4}' + + '|\\\\x[0-9A-Fa-f]{2}' + + '|\\\\[0-3][0-7]{0,2}' + + '|\\\\[0-7]{1,2}' + + '|\\\\[\\s\\S]' + + '|-' + + '|[^-\\\\]', + 'g')); + var groups = []; + var ranges = []; + var inverse = charsetParts[0] === '^'; + for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) { + var p = charsetParts[i]; + switch (p) { + case '\\B': case '\\b': + case '\\D': case '\\d': + case '\\S': case '\\s': + case '\\W': case '\\w': + groups.push(p); + continue; + } + var start = decodeEscape(p); + var end; + if (i + 2 < n && '-' === charsetParts[i + 1]) { + end = decodeEscape(charsetParts[i + 2]); + i += 2; + } else { + end = start; + } + ranges.push([start, end]); + // If the range might intersect letters, then expand it. + if (!(end < 65 || start > 122)) { + if (!(end < 65 || start > 90)) { + ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]); + } + if (!(end < 97 || start > 122)) { + ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]); + } + } + } + + // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]] + // -> [[1, 12], [14, 14], [16, 17]] + ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); }); + var consolidatedRanges = []; + var lastRange = [NaN, NaN]; + for (var i = 0; i < ranges.length; ++i) { + var range = ranges[i]; + if (range[0] <= lastRange[1] + 1) { + lastRange[1] = Math.max(lastRange[1], range[1]); + } else { + consolidatedRanges.push(lastRange = range); + } + } + + var out = ['[']; + if (inverse) { out.push('^'); } + out.push.apply(out, groups); + for (var i = 0; i < consolidatedRanges.length; ++i) { + var range = consolidatedRanges[i]; + out.push(encodeEscape(range[0])); + if (range[1] > range[0]) { + if (range[1] + 1 > range[0]) { out.push('-'); } + out.push(encodeEscape(range[1])); + } + } + out.push(']'); + return out.join(''); + } + + function allowAnywhereFoldCaseAndRenumberGroups(regex) { + // Split into character sets, escape sequences, punctuation strings + // like ('(', '(?:', ')', '^'), and runs of characters that do not + // include any of the above. + var parts = regex.source.match( + new RegExp( + '(?:' + + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]' // a character set + + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape + + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape + + '|\\\\[0-9]+' // a back-reference or octal escape + + '|\\\\[^ux0-9]' // other escape sequence + + '|\\(\\?[:!=]' // start of a non-capturing group + + '|[\\(\\)\\^]' // start/emd of a group, or line start + + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters + + ')', + 'g')); + var n = parts.length; + + // Maps captured group numbers to the number they will occupy in + // the output or to -1 if that has not been determined, or to + // undefined if they need not be capturing in the output. + var capturedGroups = []; + + // Walk over and identify back references to build the capturedGroups + // mapping. + for (var i = 0, groupIndex = 0; i < n; ++i) { + var p = parts[i]; + if (p === '(') { + // groups are 1-indexed, so max group index is count of '(' + ++groupIndex; + } else if ('\\' === p.charAt(0)) { + var decimalValue = +p.substring(1); + if (decimalValue && decimalValue <= groupIndex) { + capturedGroups[decimalValue] = -1; + } + } + } + + // Renumber groups and reduce capturing groups to non-capturing groups + // where possible. + for (var i = 1; i < capturedGroups.length; ++i) { + if (-1 === capturedGroups[i]) { + capturedGroups[i] = ++capturedGroupIndex; + } + } + for (var i = 0, groupIndex = 0; i < n; ++i) { + var p = parts[i]; + if (p === '(') { + ++groupIndex; + if (capturedGroups[groupIndex] === undefined) { + parts[i] = '(?:'; + } + } else if ('\\' === p.charAt(0)) { + var decimalValue = +p.substring(1); + if (decimalValue && decimalValue <= groupIndex) { + parts[i] = '\\' + capturedGroups[groupIndex]; + } + } + } + + // Remove any prefix anchors so that the output will match anywhere. + // ^^ really does mean an anchored match though. + for (var i = 0, groupIndex = 0; i < n; ++i) { + if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; } + } + + // Expand letters to groups to handle mixing of case-sensitive and + // case-insensitive patterns if necessary. + if (regex.ignoreCase && needToFoldCase) { + for (var i = 0; i < n; ++i) { + var p = parts[i]; + var ch0 = p.charAt(0); + if (p.length >= 2 && ch0 === '[') { + parts[i] = caseFoldCharset(p); + } else if (ch0 !== '\\') { + // TODO: handle letters in numeric escapes. + parts[i] = p.replace( + /[a-zA-Z]/g, + function (ch) { + var cc = ch.charCodeAt(0); + return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']'; + }); + } + } + } + + return parts.join(''); + } + + var rewritten = []; + for (var i = 0, n = regexs.length; i < n; ++i) { + var regex = regexs[i]; + if (regex.global || regex.multiline) { throw new Error('' + regex); } + rewritten.push( + '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')'); + } + + return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g'); + } + + + /** + * Split markup into a string of source code and an array mapping ranges in + * that string to the text nodes in which they appear. + * + * <p> + * The HTML DOM structure:</p> + * <pre> + * (Element "p" + * (Element "b" + * (Text "print ")) ; #1 + * (Text "'Hello '") ; #2 + * (Element "br") ; #3 + * (Text " + 'World';")) ; #4 + * </pre> + * <p> + * corresponds to the HTML + * {@code <p><b>print </b>'Hello '<br> + 'World';</p>}.</p> + * + * <p> + * It will produce the output:</p> + * <pre> + * { + * source: "print 'Hello '\n + 'World';", + * // 1 2 + * // 012345678901234 5678901234567 + * spans: [0, #1, 6, #2, 14, #3, 15, #4] + * } + * </pre> + * <p> + * where #1 is a reference to the {@code "print "} text node above, and so + * on for the other text nodes. + * </p> + * + * <p> + * The {@code} spans array is an array of pairs. Even elements are the start + * indices of substrings, and odd elements are the text nodes (or BR elements) + * that contain the text for those substrings. + * Substrings continue until the next index or the end of the source. + * </p> + * + * @param {Node} node an HTML DOM subtree containing source-code. + * @return {Object} source code and the text nodes in which they occur. + */ + function extractSourceSpans(node) { + var nocode = /(?:^|\s)nocode(?:\s|$)/; + + var chunks = []; + var length = 0; + var spans = []; + var k = 0; + + var whitespace; + if (node.currentStyle) { + whitespace = node.currentStyle.whiteSpace; + } else if (window.getComputedStyle) { + whitespace = document.defaultView.getComputedStyle(node, null) + .getPropertyValue('white-space'); + } + var isPreformatted = whitespace && 'pre' === whitespace.substring(0, 3); + + function walk(node) { + switch (node.nodeType) { + case 1: // Element + if (nocode.test(node.className)) { return; } + for (var child = node.firstChild; child; child = child.nextSibling) { + walk(child); + } + var nodeName = node.nodeName; + if ('BR' === nodeName || 'LI' === nodeName) { + chunks[k] = '\n'; + spans[k << 1] = length++; + spans[(k++ << 1) | 1] = node; + } + break; + case 3: case 4: // Text + var text = node.nodeValue; + if (text.length) { + if (!isPreformatted) { + text = text.replace(/[ \t\r\n]+/g, ' '); + } else { + text = text.replace(/\r\n?/g, '\n'); // Normalize newlines. + } + // TODO: handle tabs here? + chunks[k] = text; + spans[k << 1] = length; + length += text.length; + spans[(k++ << 1) | 1] = node; + } + break; + } + } + + walk(node); + + return { + source: chunks.join('').replace(/\n$/, ''), + spans: spans + }; + } + + + /** + * Apply the given language handler to sourceCode and add the resulting + * decorations to out. + * @param {number} basePos the index of sourceCode within the chunk of source + * whose decorations are already present on out. + */ + function appendDecorations(basePos, sourceCode, langHandler, out) { + if (!sourceCode) { return; } + var job = { + source: sourceCode, + basePos: basePos + }; + langHandler(job); + out.push.apply(out, job.decorations); + } + + /** Given triples of [style, pattern, context] returns a lexing function, + * The lexing function interprets the patterns to find token boundaries and + * returns a decoration list of the form + * [index_0, style_0, index_1, style_1, ..., index_n, style_n] + * where index_n is an index into the sourceCode, and style_n is a style + * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to + * all characters in sourceCode[index_n-1:index_n]. + * + * The stylePatterns is a list whose elements have the form + * [style : string, pattern : RegExp, DEPRECATED, shortcut : string]. + * + * Style is a style constant like PR_PLAIN, or can be a string of the + * form 'lang-FOO', where FOO is a language extension describing the + * language of the portion of the token in $1 after pattern executes. + * E.g., if style is 'lang-lisp', and group 1 contains the text + * '(hello (world))', then that portion of the token will be passed to the + * registered lisp handler for formatting. + * The text before and after group 1 will be restyled using this decorator + * so decorators should take care that this doesn't result in infinite + * recursion. For example, the HTML lexer rule for SCRIPT elements looks + * something like ['lang-js', /<[s]cript>(.+?)<\/script>/]. This may match + * '<script>foo()<\/script>', which would cause the current decorator to + * be called with '<script>' which would not match the same rule since + * group 1 must not be empty, so it would be instead styled as PR_TAG by + * the generic tag rule. The handler registered for the 'js' extension would + * then be called with 'foo()', and finally, the current decorator would + * be called with '<\/script>' which would not match the original rule and + * so the generic tag rule would identify it as a tag. + * + * Pattern must only match prefixes, and if it matches a prefix, then that + * match is considered a token with the same style. + * + * Context is applied to the last non-whitespace, non-comment token + * recognized. + * + * Shortcut is an optional string of characters, any of which, if the first + * character, gurantee that this pattern and only this pattern matches. + * + * @param {Array} shortcutStylePatterns patterns that always start with + * a known character. Must have a shortcut string. + * @param {Array} fallthroughStylePatterns patterns that will be tried in + * order if the shortcut ones fail. May have shortcuts. + * + * @return {function (Object)} a + * function that takes source code and returns a list of decorations. + */ + function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) { + var shortcuts = {}; + var tokenizer; + (function () { + var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns); + var allRegexs = []; + var regexKeys = {}; + for (var i = 0, n = allPatterns.length; i < n; ++i) { + var patternParts = allPatterns[i]; + var shortcutChars = patternParts[3]; + if (shortcutChars) { + for (var c = shortcutChars.length; --c >= 0;) { + shortcuts[shortcutChars.charAt(c)] = patternParts; + } + } + var regex = patternParts[1]; + var k = '' + regex; + if (!regexKeys.hasOwnProperty(k)) { + allRegexs.push(regex); + regexKeys[k] = null; + } + } + allRegexs.push(/[\0-\uffff]/); + tokenizer = combinePrefixPatterns(allRegexs); + })(); + + var nPatterns = fallthroughStylePatterns.length; + var notWs = /\S/; + + /** + * Lexes job.source and produces an output array job.decorations of style + * classes preceded by the position at which they start in job.source in + * order. + * + * @param {Object} job an object like {@code + * source: {string} sourceText plain text, + * basePos: {int} position of job.source in the larger chunk of + * sourceCode. + * } + */ + var decorate = function (job) { + var sourceCode = job.source, basePos = job.basePos; + /** Even entries are positions in source in ascending order. Odd enties + * are style markers (e.g., PR_COMMENT) that run from that position until + * the end. + * @type {Array.<number|string>} + */ + var decorations = [basePos, PR_PLAIN]; + var pos = 0; // index into sourceCode + var tokens = sourceCode.match(tokenizer) || []; + var styleCache = {}; + + for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) { + var token = tokens[ti]; + var style = styleCache[token]; + var match = void 0; + + var isEmbedded; + if (typeof style === 'string') { + isEmbedded = false; + } else { + var patternParts = shortcuts[token.charAt(0)]; + if (patternParts) { + match = token.match(patternParts[1]); + style = patternParts[0]; + } else { + for (var i = 0; i < nPatterns; ++i) { + patternParts = fallthroughStylePatterns[i]; + match = token.match(patternParts[1]); + if (match) { + style = patternParts[0]; + break; + } + } + + if (!match) { // make sure that we make progress + style = PR_PLAIN; + } + } + + isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5); + if (isEmbedded && !(match && typeof match[1] === 'string')) { + isEmbedded = false; + style = PR_SOURCE; + } + + if (!isEmbedded) { styleCache[token] = style; } + } + + var tokenStart = pos; + pos += token.length; + + if (!isEmbedded) { + decorations.push(basePos + tokenStart, style); + } else { // Treat group 1 as an embedded block of source code. + var embeddedSource = match[1]; + var embeddedSourceStart = token.indexOf(embeddedSource); + var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length; + if (match[2]) { + // If embeddedSource can be blank, then it would match at the + // beginning which would cause us to infinitely recurse on the + // entire token, so we catch the right context in match[2]. + embeddedSourceEnd = token.length - match[2].length; + embeddedSourceStart = embeddedSourceEnd - embeddedSource.length; + } + var lang = style.substring(5); + // Decorate the left of the embedded source + appendDecorations( + basePos + tokenStart, + token.substring(0, embeddedSourceStart), + decorate, decorations); + // Decorate the embedded source + appendDecorations( + basePos + tokenStart + embeddedSourceStart, + embeddedSource, + langHandlerForExtension(lang, embeddedSource), + decorations); + // Decorate the right of the embedded section + appendDecorations( + basePos + tokenStart + embeddedSourceEnd, + token.substring(embeddedSourceEnd), + decorate, decorations); + } + } + job.decorations = decorations; + }; + return decorate; + } + + /** returns a function that produces a list of decorations from source text. + * + * This code treats ", ', and ` as string delimiters, and \ as a string + * escape. It does not recognize perl's qq() style strings. + * It has no special handling for double delimiter escapes as in basic, or + * the tripled delimiters used in python, but should work on those regardless + * although in those cases a single string literal may be broken up into + * multiple adjacent string literals. + * + * It recognizes C, C++, and shell style comments. + * + * @param {Object} options a set of optional parameters. + * @return {function (Object)} a function that examines the source code + * in the input job and builds the decoration list. + */ + function sourceDecorator(options) { + var shortcutStylePatterns = [], fallthroughStylePatterns = []; + if (options['tripleQuotedStrings']) { + // '''multi-line-string''', 'single-line-string', and double-quoted + shortcutStylePatterns.push( + [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, + null, '\'"']); + } else if (options['multiLineStrings']) { + // 'multi-line-string', "multi-line-string" + shortcutStylePatterns.push( + [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/, + null, '\'"`']); + } else { + // 'single-line-string', "single-line-string" + shortcutStylePatterns.push( + [PR_STRING, + /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/, + null, '"\'']); + } + if (options['verbatimStrings']) { + // verbatim-string-literal production from the C# grammar. See issue 93. + fallthroughStylePatterns.push( + [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]); + } + var hc = options['hashComments']; + if (hc) { + if (options['cStyleComments']) { + if (hc > 1) { // multiline hash comments + shortcutStylePatterns.push( + [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']); + } else { + // Stop C preprocessor declarations at an unclosed open comment + shortcutStylePatterns.push( + [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/, + null, '#']); + } + fallthroughStylePatterns.push( + [PR_STRING, + /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/, + null]); + } else { + shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); + } + } + if (options['cStyleComments']) { + fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); + fallthroughStylePatterns.push( + [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); + } + if (options['regexLiterals']) { + var REGEX_LITERAL = ( + // A regular expression literal starts with a slash that is + // not followed by * or / so that it is not confused with + // comments. + '/(?=[^/*])' + // and then contains any number of raw characters, + + '(?:[^/\\x5B\\x5C]' + // escape sequences (\x5C), + + '|\\x5C[\\s\\S]' + // or non-nesting character sets (\x5B\x5D); + + '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+' + // finally closed by a /. + + '/'); + fallthroughStylePatterns.push( + ['lang-regex', + new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')') + ]); + } + + var keywords = options['keywords'].replace(/^\s+|\s+$/g, ''); + if (keywords.length) { + fallthroughStylePatterns.push( + [PR_KEYWORD, + new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]); + } + + shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']); + fallthroughStylePatterns.push( + // TODO(mikesamuel): recognize non-latin letters and numerals in idents + [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null], + [PR_TYPE, /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null], + [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null], + [PR_LITERAL, + new RegExp( + '^(?:' + // A hex number + + '0x[a-f0-9]+' + // or an octal or decimal number, + + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)' + // possibly in scientific notation + + '(?:e[+\\-]?\\d+)?' + + ')' + // with an optional modifier like UL for unsigned long + + '[a-z]*', 'i'), + null, '0123456789'], + // Don't treat escaped quotes in bash as starting strings. See issue 144. + [PR_PLAIN, /^\\[\s\S]?/, null], + [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#\\]*/, null]); + + return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns); + } + + var decorateSource = sourceDecorator({ + 'keywords': ALL_KEYWORDS, + 'hashComments': true, + 'cStyleComments': true, + 'multiLineStrings': true, + 'regexLiterals': true + }); + + /** + * Given a DOM subtree, wraps it in a list, and puts each line into its own + * list item. + * + * @param {Node} node modified in place. Its content is pulled into an + * HTMLOListElement, and each line is moved into a separate list item. + * This requires cloning elements, so the input might not have unique + * IDs after numbering. + */ + function numberLines(node, opt_startLineNum) { + var nocode = /(?:^|\s)nocode(?:\s|$)/; + var lineBreak = /\r\n?|\n/; + + var document = node.ownerDocument; + + var whitespace; + if (node.currentStyle) { + whitespace = node.currentStyle.whiteSpace; + } else if (window.getComputedStyle) { + whitespace = document.defaultView.getComputedStyle(node, null) + .getPropertyValue('white-space'); + } + // If it's preformatted, then we need to split lines on line breaks + // in addition to <BR>s. + var isPreformatted = whitespace && 'pre' === whitespace.substring(0, 3); + + var li = document.createElement('LI'); + while (node.firstChild) { + li.appendChild(node.firstChild); + } + // An array of lines. We split below, so this is initialized to one + // un-split line. + var listItems = [li]; + + function walk(node) { + switch (node.nodeType) { + case 1: // Element + if (nocode.test(node.className)) { break; } + if ('BR' === node.nodeName) { + breakAfter(node); + // Discard the <BR> since it is now flush against a </LI>. + if (node.parentNode) { + node.parentNode.removeChild(node); + } + } else { + for (var child = node.firstChild; child; child = child.nextSibling) { + walk(child); + } + } + break; + case 3: case 4: // Text + if (isPreformatted) { + var text = node.nodeValue; + var match = text.match(lineBreak); + if (match) { + var firstLine = text.substring(0, match.index); + node.nodeValue = firstLine; + var tail = text.substring(match.index + match[0].length); + if (tail) { + var parent = node.parentNode; + parent.insertBefore( + document.createTextNode(tail), node.nextSibling); + } + breakAfter(node); + if (!firstLine) { + // Don't leave blank text nodes in the DOM. + node.parentNode.removeChild(node); + } + } + } + break; + } + } + + // Split a line after the given node. + function breakAfter(lineEndNode) { + // If there's nothing to the right, then we can skip ending the line + // here, and move root-wards since splitting just before an end-tag + // would require us to create a bunch of empty copies. + while (!lineEndNode.nextSibling) { + lineEndNode = lineEndNode.parentNode; + if (!lineEndNode) { return; } + } + + function breakLeftOf(limit, copy) { + // Clone shallowly if this node needs to be on both sides of the break. + var rightSide = copy ? limit.cloneNode(false) : limit; + var parent = limit.parentNode; + if (parent) { + // We clone the parent chain. + // This helps us resurrect important styling elements that cross lines. + // E.g. in <i>Foo<br>Bar</i> + // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>. + var parentClone = breakLeftOf(parent, 1); + // Move the clone and everything to the right of the original + // onto the cloned parent. + var next = limit.nextSibling; + parentClone.appendChild(rightSide); + for (var sibling = next; sibling; sibling = next) { + next = sibling.nextSibling; + parentClone.appendChild(sibling); + } + } + return rightSide; + } + + var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0); + + // Walk the parent chain until we reach an unattached LI. + for (var parent; + // Check nodeType since IE invents document fragments. + (parent = copiedListItem.parentNode) && parent.nodeType === 1;) { + copiedListItem = parent; + } + // Put it on the list of lines for later processing. + listItems.push(copiedListItem); + } + + // Split lines while there are lines left to split. + for (var i = 0; // Number of lines that have been split so far. + i < listItems.length; // length updated by breakAfter calls. + ++i) { + walk(listItems[i]); + } + + // Make sure numeric indices show correctly. + if (opt_startLineNum === (opt_startLineNum|0)) { + listItems[0].setAttribute('value', opt_startLineNum); + } + + var ol = document.createElement('OL'); + ol.className = 'linenums'; + var offset = Math.max(0, ((opt_startLineNum - 1 /* zero index */)) | 0) || 0; + for (var i = 0, n = listItems.length; i < n; ++i) { + li = listItems[i]; + // Stick a class on the LIs so that stylesheets can + // color odd/even rows, or any other row pattern that + // is co-prime with 10. + li.className = 'L' + ((i + offset) % 10); + if (!li.firstChild) { + li.appendChild(document.createTextNode('\xA0')); + } + ol.appendChild(li); + } + + node.appendChild(ol); + } + + /** + * Breaks {@code job.source} around style boundaries in {@code job.decorations} + * and modifies {@code job.sourceNode} in place. + * @param {Object} job like <pre>{ + * source: {string} source as plain text, + * spans: {Array.<number|Node>} alternating span start indices into source + * and the text node or element (e.g. {@code <BR>}) corresponding to that + * span. + * decorations: {Array.<number|string} an array of style classes preceded + * by the position at which they start in job.source in order + * }</pre> + * @private + */ + function recombineTagsAndDecorations(job) { + var isIE = /\bMSIE\b/.test(navigator.userAgent); + var newlineRe = /\n/g; + + var source = job.source; + var sourceLength = source.length; + // Index into source after the last code-unit recombined. + var sourceIndex = 0; + + var spans = job.spans; + var nSpans = spans.length; + // Index into spans after the last span which ends at or before sourceIndex. + var spanIndex = 0; + + var decorations = job.decorations; + var nDecorations = decorations.length; + // Index into decorations after the last decoration which ends at or before sourceIndex. + var decorationIndex = 0; + + // Simplify decorations. + var decPos = 0; + for (var i = 0; i < nDecorations;) { + // Skip over any zero-length decorations. + var startPos = decorations[i]; + var start = i; + while (start + 2 < nDecorations && decorations[start + 2] === startPos) { + start += 2; + } + // Conflate all adjacent decorations that use the same style. + var startDec = decorations[start + 1]; + var end = start + 2; + while (end + 2 <= nDecorations + && (decorations[end + 1] === startDec + || decorations[end] === decorations[end + 2])) { + end += 2; + } + decorations[decPos++] = startPos; + decorations[decPos++] = startDec; + i = end; + } + + // Strip any zero-length decoration at the end. + if (decPos && decorations[decPos - 2] === sourceLength) { decPos -= 2; } + nDecorations = decorations.length = decPos; + + var decoration = null; + while (spanIndex < nSpans) { + var spanStart = spans[spanIndex]; + var spanEnd = spans[spanIndex + 2] || sourceLength; + + var decStart = decorations[decorationIndex]; + var decEnd = decorations[decorationIndex + 2] || sourceLength; + + var end = Math.min(spanEnd, decEnd); + + var textNode = spans[spanIndex + 1]; + if (textNode.nodeType !== 1) { // Don't muck with <BR>s or <LI>s + var styledText = source.substring(sourceIndex, end); + // This may seem bizarre, and it is. Emitting LF on IE causes the + // code to display with spaces instead of line breaks. + // Emitting Windows standard issue linebreaks (CRLF) causes a blank + // space to appear at the beginning of every line but the first. + // Emitting an old Mac OS 9 line separator makes everything spiffy. + if (isIE) { styledText = styledText.replace(newlineRe, '\r'); } + textNode.nodeValue = styledText; + var document = textNode.ownerDocument; + var span = document.createElement('SPAN'); + span.className = decorations[decorationIndex + 1]; + var parentNode = textNode.parentNode; + parentNode.replaceChild(span, textNode); + span.appendChild(textNode); + if (sourceIndex < spanEnd) { // Split off a text node. + spans[spanIndex + 1] = textNode + // TODO: Possibly optimize by using '' if there's no flicker. + = document.createTextNode(source.substring(end, spanEnd)); + parentNode.insertBefore(textNode, span.nextSibling); + } + } + + sourceIndex = end; + + if (sourceIndex >= spanEnd) { + spanIndex += 2; + } + if (sourceIndex >= decEnd) { + decorationIndex += 2; + } + } + } + + + /** Maps language-specific file extensions to handlers. */ + var langHandlerRegistry = {}; + /** Register a language handler for the given file extensions. + * @param {function (Object)} handler a function from source code to a list + * of decorations. Takes a single argument job which describes the + * state of the computation. The single parameter has the form + * {@code { + * source: {string} as plain text. + * decorations: {Array.<number|string>} an array of style classes + * preceded by the position at which they start in + * job.source in order. + * The language handler should assigned this field. + * basePos: {int} the position of source in the larger source chunk. + * All positions in the output decorations array are relative + * to the larger source chunk. + * } } + * @param {Array.<string>} fileExtensions + */ + function registerLangHandler(handler, fileExtensions) { + for (var i = fileExtensions.length; --i >= 0;) { + var ext = fileExtensions[i]; + if (!langHandlerRegistry.hasOwnProperty(ext)) { + langHandlerRegistry[ext] = handler; + } else if ('console' in window) { + console['warn']('cannot override language handler %s', ext); + } + } + } + function langHandlerForExtension(extension, source) { + if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) { + // Treat it as markup if the first non whitespace character is a < and + // the last non-whitespace character is a >. + extension = /^\s*</.test(source) + ? 'default-markup' + : 'default-code'; + } + return langHandlerRegistry[extension]; + } + registerLangHandler(decorateSource, ['default-code']); + registerLangHandler( + createSimpleLexer( + [], + [ + [PR_PLAIN, /^[^<?]+/], + [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/], + [PR_COMMENT, /^<\!--[\s\S]*?(?:-\->|$)/], + // Unescaped content in an unknown language + ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/], + ['lang-', /^<%([\s\S]+?)(?:%>|$)/], + [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/], + ['lang-', /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i], + // Unescaped content in javascript. (Or possibly vbscript). + ['lang-js', /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i], + // Contains unescaped stylesheet content + ['lang-css', /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i], + ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i] + ]), + ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']); + registerLangHandler( + createSimpleLexer( + [ + [PR_PLAIN, /^[\s]+/, null, ' \t\r\n'], + [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\''] + ], + [ + [PR_TAG, /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i], + [PR_ATTRIB_NAME, /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], + ['lang-uq.val', /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/], + [PR_PUNCTUATION, /^[=<>\/]+/], + ['lang-js', /^on\w+\s*=\s*\"([^\"]+)\"/i], + ['lang-js', /^on\w+\s*=\s*\'([^\']+)\'/i], + ['lang-js', /^on\w+\s*=\s*([^\"\'>\s]+)/i], + ['lang-css', /^style\s*=\s*\"([^\"]+)\"/i], + ['lang-css', /^style\s*=\s*\'([^\']+)\'/i], + ['lang-css', /^style\s*=\s*([^\"\'>\s]+)/i] + ]), + ['in.tag']); + registerLangHandler( + createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']); + registerLangHandler(sourceDecorator({ + 'keywords': CPP_KEYWORDS, + 'hashComments': true, + 'cStyleComments': true + }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']); + registerLangHandler(sourceDecorator({ + 'keywords': 'null true false' + }), ['json']); + registerLangHandler(sourceDecorator({ + 'keywords': CSHARP_KEYWORDS, + 'hashComments': true, + 'cStyleComments': true, + 'verbatimStrings': true + }), ['cs']); + registerLangHandler(sourceDecorator({ + 'keywords': JAVA_KEYWORDS, + 'cStyleComments': true + }), ['java']); + registerLangHandler(sourceDecorator({ + 'keywords': SH_KEYWORDS, + 'hashComments': true, + 'multiLineStrings': true + }), ['bsh', 'csh', 'sh']); + registerLangHandler(sourceDecorator({ + 'keywords': PYTHON_KEYWORDS, + 'hashComments': true, + 'multiLineStrings': true, + 'tripleQuotedStrings': true + }), ['cv', 'py']); + registerLangHandler(sourceDecorator({ + 'keywords': PERL_KEYWORDS, + 'hashComments': true, + 'multiLineStrings': true, + 'regexLiterals': true + }), ['perl', 'pl', 'pm']); + registerLangHandler(sourceDecorator({ + 'keywords': RUBY_KEYWORDS, + 'hashComments': true, + 'multiLineStrings': true, + 'regexLiterals': true + }), ['rb']); + registerLangHandler(sourceDecorator({ + 'keywords': JSCRIPT_KEYWORDS, + 'cStyleComments': true, + 'regexLiterals': true + }), ['js']); + registerLangHandler(sourceDecorator({ + 'keywords': COFFEE_KEYWORDS, + 'hashComments': 3, // ### style block comments + 'cStyleComments': true, + 'multilineStrings': true, + 'tripleQuotedStrings': true, + 'regexLiterals': true + }), ['coffee']); + registerLangHandler(createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']); + + function applyDecorator(job) { + var opt_langExtension = job.langExtension; + + try { + // Extract tags, and convert the source code to plain text. + var sourceAndSpans = extractSourceSpans(job.sourceNode); + /** Plain text. @type {string} */ + var source = sourceAndSpans.source; + job.source = source; + job.spans = sourceAndSpans.spans; + job.basePos = 0; + + // Apply the appropriate language handler + langHandlerForExtension(opt_langExtension, source)(job); + + // Integrate the decorations and tags back into the source code, + // modifying the sourceNode in place. + recombineTagsAndDecorations(job); + } catch (e) { + if ('console' in window) { + console['log'](e && e['stack'] ? e['stack'] : e); + } + } + } + + /** + * @param sourceCodeHtml {string} The HTML to pretty print. + * @param opt_langExtension {string} The language name to use. + * Typically, a filename extension like 'cpp' or 'java'. + * @param opt_numberLines {number|boolean} True to number lines, + * or the 1-indexed number of the first line in sourceCodeHtml. + */ + function prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) { + var container = document.createElement('PRE'); + // This could cause images to load and onload listeners to fire. + // E.g. <img onerror="alert(1337)" src="nosuchimage.png">. + // We assume that the inner HTML is from a trusted source. + container.innerHTML = sourceCodeHtml; + if (opt_numberLines) { + numberLines(container, opt_numberLines); + } + + var job = { + langExtension: opt_langExtension, + numberLines: opt_numberLines, + sourceNode: container + }; + applyDecorator(job); + return container.innerHTML; + } + + function prettyPrint(opt_whenDone) { + function byTagName(tn) { return document.getElementsByTagName(tn); } + // fetch a list of nodes to rewrite + var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')]; + var elements = []; + for (var i = 0; i < codeSegments.length; ++i) { + for (var j = 0, n = codeSegments[i].length; j < n; ++j) { + elements.push(codeSegments[i][j]); + } + } + codeSegments = null; + + var clock = Date; + if (!clock['now']) { + clock = { 'now': function () { return (new Date).getTime(); } }; + } + + // The loop is broken into a series of continuations to make sure that we + // don't make the browser unresponsive when rewriting a large page. + var k = 0; + var prettyPrintingJob; + + function doWork() { + var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ? + clock.now() + 250 /* ms */ : + Infinity); + for (; k < elements.length && clock.now() < endTime; k++) { + var cs = elements[k]; + if (cs.className && cs.className.indexOf('prettyprint') >= 0) { + // If the classes includes a language extensions, use it. + // Language extensions can be specified like + // <pre class="prettyprint lang-cpp"> + // the language extension "cpp" is used to find a language handler as + // passed to PR.registerLangHandler. + var langExtension = cs.className.match(/\blang-(\w+)\b/); + if (langExtension) { langExtension = langExtension[1]; } + + // make sure this is not nested in an already prettified element + var nested = false; + for (var p = cs.parentNode; p; p = p.parentNode) { + if ((p.tagName === 'pre' || p.tagName === 'code' || + p.tagName === 'xmp') && + p.className && p.className.indexOf('prettyprint') >= 0) { + nested = true; + break; + } + } + if (!nested) { + // Look for a class like linenums or linenums:<n> where <n> is the + // 1-indexed number of the first line. + var lineNums = cs.className.match(/\blinenums\b(?::(\d+))?/); + lineNums = lineNums + ? lineNums[1] && lineNums[1].length ? +lineNums[1] : true + : false; + if (lineNums) { numberLines(cs, lineNums); } + + // do the pretty printing + prettyPrintingJob = { + langExtension: langExtension, + sourceNode: cs, + numberLines: lineNums + }; + applyDecorator(prettyPrintingJob); + } + } + } + if (k < elements.length) { + // finish up in a continuation + setTimeout(doWork, 250); + } else if (opt_whenDone) { + opt_whenDone(); + } + } + + doWork(); + } + + window['prettyPrintOne'] = prettyPrintOne; + window['prettyPrint'] = prettyPrint; + window['PR'] = { + 'createSimpleLexer': createSimpleLexer, + 'registerLangHandler': registerLangHandler, + 'sourceDecorator': sourceDecorator, + 'PR_ATTRIB_NAME': PR_ATTRIB_NAME, + 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE, + 'PR_COMMENT': PR_COMMENT, + 'PR_DECLARATION': PR_DECLARATION, + 'PR_KEYWORD': PR_KEYWORD, + 'PR_LITERAL': PR_LITERAL, + 'PR_NOCODE': PR_NOCODE, + 'PR_PLAIN': PR_PLAIN, + 'PR_PUNCTUATION': PR_PUNCTUATION, + 'PR_SOURCE': PR_SOURCE, + 'PR_STRING': PR_STRING, + 'PR_TAG': PR_TAG, + 'PR_TYPE': PR_TYPE + }; +})();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meeting20130802/slides.js Fri Aug 02 09:54:58 2013 +0900 @@ -0,0 +1,635 @@ +/* + Google HTML5 slides template + + Authors: Luke Mahé (code) + Marcin Wichary (code and design) + + Dominic Mazzoni (browser compatibility) + Charles Chen (ChromeVox support) + + URL: http://code.google.com/p/html5slides/ +*/ + +// var PERMANENT_URL_PREFIX = 'http://html5slides.googlecode.com/svn/trunk/'; +var PERMANENT_URL_PREFIX = './'; + +var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next']; + +var PM_TOUCH_SENSITIVITY = 15; + +var curSlide; + +/* ---------------------------------------------------------------------- */ +/* classList polyfill by Eli Grey + * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */ + +if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { + +(function (view) { + +var + classListProp = "classList" + , protoProp = "prototype" + , elemCtrProto = (view.HTMLElement || view.Element)[protoProp] + , objCtr = Object + strTrim = String[protoProp].trim || function () { + return this.replace(/^\s+|\s+$/g, ""); + } + , arrIndexOf = Array[protoProp].indexOf || function (item) { + for (var i = 0, len = this.length; i < len; i++) { + if (i in this && this[i] === item) { + return i; + } + } + return -1; + } + // Vendors: please allow content code to instantiate DOMExceptions + , DOMEx = function (type, message) { + this.name = type; + this.code = DOMException[type]; + this.message = message; + } + , checkTokenAndGetIndex = function (classList, token) { + if (token === "") { + throw new DOMEx( + "SYNTAX_ERR" + , "An invalid or illegal string was specified" + ); + } + if (/\s/.test(token)) { + throw new DOMEx( + "INVALID_CHARACTER_ERR" + , "String contains an invalid character" + ); + } + return arrIndexOf.call(classList, token); + } + , ClassList = function (elem) { + var + trimmedClasses = strTrim.call(elem.className) + , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] + ; + for (var i = 0, len = classes.length; i < len; i++) { + this.push(classes[i]); + } + this._updateClassName = function () { + elem.className = this.toString(); + }; + } + , classListProto = ClassList[protoProp] = [] + , classListGetter = function () { + return new ClassList(this); + } +; +// Most DOMException implementations don't allow calling DOMException's toString() +// on non-DOMExceptions. Error's toString() is sufficient here. +DOMEx[protoProp] = Error[protoProp]; +classListProto.item = function (i) { + return this[i] || null; +}; +classListProto.contains = function (token) { + token += ""; + return checkTokenAndGetIndex(this, token) !== -1; +}; +classListProto.add = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.push(token); + this._updateClassName(); + } +}; +classListProto.remove = function (token) { + token += ""; + var index = checkTokenAndGetIndex(this, token); + if (index !== -1) { + this.splice(index, 1); + this._updateClassName(); + } +}; +classListProto.toggle = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.add(token); + } else { + this.remove(token); + } +}; +classListProto.toString = function () { + return this.join(" "); +}; + +if (objCtr.defineProperty) { + var classListPropDesc = { + get: classListGetter + , enumerable: true + , configurable: true + }; + try { + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } catch (ex) { // IE 8 doesn't support enumerable:true + if (ex.number === -0x7FF5EC54) { + classListPropDesc.enumerable = false; + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } + } +} else if (objCtr[protoProp].__defineGetter__) { + elemCtrProto.__defineGetter__(classListProp, classListGetter); +} + +}(self)); + +} +/* ---------------------------------------------------------------------- */ + +/* Slide movement */ + +function getSlideEl(no) { + if ((no < 0) || (no >= slideEls.length)) { + return null; + } else { + return slideEls[no]; + } +}; + +function updateSlideClass(slideNo, className) { + var el = getSlideEl(slideNo); + + if (!el) { + return; + } + + if (className) { + el.classList.add(className); + } + + for (var i in SLIDE_CLASSES) { + if (className != SLIDE_CLASSES[i]) { + el.classList.remove(SLIDE_CLASSES[i]); + } + } +}; + +function updateSlides() { + for (var i = 0; i < slideEls.length; i++) { + switch (i) { + case curSlide - 2: + updateSlideClass(i, 'far-past'); + break; + case curSlide - 1: + updateSlideClass(i, 'past'); + break; + case curSlide: + updateSlideClass(i, 'current'); + break; + case curSlide + 1: + updateSlideClass(i, 'next'); + break; + case curSlide + 2: + updateSlideClass(i, 'far-next'); + break; + default: + updateSlideClass(i); + break; + } + } + + triggerLeaveEvent(curSlide - 1); + triggerEnterEvent(curSlide); + + window.setTimeout(function() { + // Hide after the slide + disableSlideFrames(curSlide - 2); + }, 301); + + enableSlideFrames(curSlide - 1); + enableSlideFrames(curSlide + 2); + + if (isChromeVoxActive()) { + speakAndSyncToNode(slideEls[curSlide]); + } + + updateHash(); +}; + +function buildNextItem() { + var toBuild = slideEls[curSlide].querySelectorAll('.to-build'); + + if (!toBuild.length) { + return false; + } + + toBuild[0].classList.remove('to-build', ''); + + if (isChromeVoxActive()) { + speakAndSyncToNode(toBuild[0]); + } + + return true; +}; + +function prevSlide() { + if (curSlide > 0) { + curSlide--; + + updateSlides(); + } +}; + +function nextSlide() { + if (buildNextItem()) { + return; + } + + if (curSlide < slideEls.length - 1) { + curSlide++; + + updateSlides(); + } +}; + +/* Slide events */ + +function triggerEnterEvent(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var onEnter = el.getAttribute('onslideenter'); + if (onEnter) { + new Function(onEnter).call(el); + } + + var evt = document.createEvent('Event'); + evt.initEvent('slideenter', true, true); + evt.slideNumber = no + 1; // Make it readable + + el.dispatchEvent(evt); +}; + +function triggerLeaveEvent(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var onLeave = el.getAttribute('onslideleave'); + if (onLeave) { + new Function(onLeave).call(el); + } + + var evt = document.createEvent('Event'); + evt.initEvent('slideleave', true, true); + evt.slideNumber = no + 1; // Make it readable + + el.dispatchEvent(evt); +}; + +/* Touch events */ + +function handleTouchStart(event) { + if (event.touches.length == 1) { + touchDX = 0; + touchDY = 0; + + touchStartX = event.touches[0].pageX; + touchStartY = event.touches[0].pageY; + + document.body.addEventListener('touchmove', handleTouchMove, true); + document.body.addEventListener('touchend', handleTouchEnd, true); + } +}; + +function handleTouchMove(event) { + if (event.touches.length > 1) { + cancelTouch(); + } else { + touchDX = event.touches[0].pageX - touchStartX; + touchDY = event.touches[0].pageY - touchStartY; + } +}; + +function handleTouchEnd(event) { + var dx = Math.abs(touchDX); + var dy = Math.abs(touchDY); + + if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) { + if (touchDX > 0) { + prevSlide(); + } else { + nextSlide(); + } + } + + cancelTouch(); +}; + +function cancelTouch() { + document.body.removeEventListener('touchmove', handleTouchMove, true); + document.body.removeEventListener('touchend', handleTouchEnd, true); +}; + +/* Preloading frames */ + +function disableSlideFrames(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var frames = el.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + disableFrame(frame); + } +}; + +function enableSlideFrames(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var frames = el.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + enableFrame(frame); + } +}; + +function disableFrame(frame) { + frame.src = 'about:blank'; +}; + +function enableFrame(frame) { + var src = frame._src; + + if (frame.src != src && src != 'about:blank') { + frame.src = src; + } +}; + +function setupFrames() { + var frames = document.querySelectorAll('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + frame._src = frame.src; + disableFrame(frame); + } + + enableSlideFrames(curSlide); + enableSlideFrames(curSlide + 1); + enableSlideFrames(curSlide + 2); +}; + +function setupInteraction() { + /* Clicking and tapping */ + + var el = document.createElement('div'); + el.className = 'slide-area'; + el.id = 'prev-slide-area'; + el.addEventListener('click', prevSlide, false); + document.querySelector('section.slides').appendChild(el); + + var el = document.createElement('div'); + el.className = 'slide-area'; + el.id = 'next-slide-area'; + el.addEventListener('click', nextSlide, false); + document.querySelector('section.slides').appendChild(el); + + /* Swiping */ + + document.body.addEventListener('touchstart', handleTouchStart, false); +} + +/* ChromeVox support */ + +function isChromeVoxActive() { + if (typeof(cvox) == 'undefined') { + return false; + } else { + return true; + } +}; + +function speakAndSyncToNode(node) { + if (!isChromeVoxActive()) { + return; + } + + cvox.ChromeVox.navigationManager.switchToStrategy( + cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); + cvox.ChromeVox.navigationManager.syncToNode(node); + cvox.ChromeVoxUserCommands.finishNavCommand(''); + var target = node; + while (target.firstChild) { + target = target.firstChild; + } + cvox.ChromeVox.navigationManager.syncToNode(target); +}; + +function speakNextItem() { + if (!isChromeVoxActive()) { + return; + } + + cvox.ChromeVox.navigationManager.switchToStrategy( + cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); + cvox.ChromeVox.navigationManager.next(true); + if (!cvox.DomUtil.isDescendantOfNode( + cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ + var target = slideEls[curSlide]; + while (target.firstChild) { + target = target.firstChild; + } + cvox.ChromeVox.navigationManager.syncToNode(target); + cvox.ChromeVox.navigationManager.next(true); + } + cvox.ChromeVoxUserCommands.finishNavCommand(''); +}; + +function speakPrevItem() { + if (!isChromeVoxActive()) { + return; + } + + cvox.ChromeVox.navigationManager.switchToStrategy( + cvox.ChromeVoxNavigationManager.STRATEGIES.LINEARDOM, 0, true); + cvox.ChromeVox.navigationManager.previous(true); + if (!cvox.DomUtil.isDescendantOfNode( + cvox.ChromeVox.navigationManager.getCurrentNode(), slideEls[curSlide])){ + var target = slideEls[curSlide]; + while (target.lastChild){ + target = target.lastChild; + } + cvox.ChromeVox.navigationManager.syncToNode(target); + cvox.ChromeVox.navigationManager.previous(true); + } + cvox.ChromeVoxUserCommands.finishNavCommand(''); +}; + +/* Hash functions */ + +function getCurSlideFromHash() { + var slideNo = parseInt(location.hash.substr(1)); + + if (slideNo) { + curSlide = slideNo - 1; + } else { + curSlide = 0; + } +}; + +function updateHash() { + location.replace('#' + (curSlide + 1)); +}; + +/* Event listeners */ + +function handleBodyKeyDown(event) { + switch (event.keyCode) { + case 39: // right arrow + case 13: // Enter + case 32: // space + case 34: // PgDn + nextSlide(); + event.preventDefault(); + break; + + case 37: // left arrow + case 8: // Backspace + case 33: // PgUp + prevSlide(); + event.preventDefault(); + break; + + case 40: // down arrow + if (isChromeVoxActive()) { + speakNextItem(); + } else { + nextSlide(); + } + event.preventDefault(); + break; + + case 38: // up arrow + if (isChromeVoxActive()) { + speakPrevItem(); + } else { + prevSlide(); + } + event.preventDefault(); + break; + } +}; + +function addEventListeners() { + document.addEventListener('keydown', handleBodyKeyDown, false); +}; + +/* Initialization */ + +function addPrettify() { + var els = document.querySelectorAll('pre'); + for (var i = 0, el; el = els[i]; i++) { + if (!el.classList.contains('noprettyprint')) { + el.classList.add('prettyprint'); + } + } + + var el = document.createElement('script'); + el.type = 'text/javascript'; + el.src = PERMANENT_URL_PREFIX + 'prettify.js'; + el.onload = function() { + prettyPrint(); + } + document.body.appendChild(el); +}; + +function addFontStyle() { + var el = document.createElement('link'); + el.rel = 'stylesheet'; + el.type = 'text/css'; + el.href = 'http://fonts.googleapis.com/css?family=' + + 'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono'; + + document.body.appendChild(el); +}; + +function addGeneralStyle() { + var el = document.createElement('link'); + el.rel = 'stylesheet'; + el.type = 'text/css'; + el.href = PERMANENT_URL_PREFIX + 'styles.css'; + document.body.appendChild(el); + + var el = document.createElement('meta'); + el.name = 'viewport'; + el.content = 'width=1100,height=750'; + document.querySelector('head').appendChild(el); + + var el = document.createElement('meta'); + el.name = 'apple-mobile-web-app-capable'; + el.content = 'yes'; + document.querySelector('head').appendChild(el); +}; + +function makeBuildLists() { + for (var i = curSlide, slide; slide = slideEls[i]; i++) { + var items = slide.querySelectorAll('.build > *'); + for (var j = 0, item; item = items[j]; j++) { + if (item.classList) { + item.classList.add('to-build'); + } + } + } +}; + +function handleDomLoaded() { + slideEls = document.querySelectorAll('section.slides > article'); + + setupFrames(); + + addFontStyle(); + addGeneralStyle(); + addPrettify(); + addEventListeners(); + + updateSlides(); + + setupInteraction(); + makeBuildLists(); + + document.body.classList.add('loaded'); +}; + +function initialize() { + getCurSlideFromHash(); + + if (window['_DEBUG']) { + PERMANENT_URL_PREFIX = '../'; + } + + if (window['_DCL']) { + handleDomLoaded(); + } else { + document.addEventListener('DOMContentLoaded', handleDomLoaded, false); + } +} + +// If ?debug exists then load the script relative instead of absolute +if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) { + document.addEventListener('DOMContentLoaded', function() { + // Avoid missing the DomContentLoaded event + window['_DCL'] = true + }, false); + + window['_DEBUG'] = true; + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = '../slides.js'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(script, s); + + // Remove this script + s.parentNode.removeChild(s); +} else { + initialize(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meeting20130802/styles.css Fri Aug 02 09:54:58 2013 +0900 @@ -0,0 +1,612 @@ +/* + Google HTML5 slides template + + Authors: Luke Mahé (code) + Marcin Wichary (code and design) + + Dominic Mazzoni (browser compatibility) + Charles Chen (ChromeVox support) + + URL: http://code.google.com/p/html5slides/ +*/ + +/* Framework */ + +html { + height: 100%; +} + +body { + margin: 0; + padding: 0; + + display: block !important; + + height: 100%; + min-height: 740px; + + overflow-x: hidden; + overflow-y: auto; + + background: rgb(215, 215, 215); + background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190))); + + -webkit-font-smoothing: antialiased; +} + +.slides { + width: 100%; + height: 100%; + left: 0; + top: 0; + + position: absolute; + + -webkit-transform: translate3d(0, 0, 0); +} + +.slides > article { + display: block; + + position: absolute; + overflow: hidden; + + width: 900px; + height: 700px; + + left: 50%; + top: 50%; + + margin-left: -450px; + margin-top: -350px; + + padding: 40px 60px; + + box-sizing: border-box; + -o-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + background-color: white; + + box-shadow: 0 2px 6px rgba(0, 0, 0, .1); + border: 1px solid rgba(0, 0, 0, .3); + + transition: transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + -moz-transition: -moz-transform .3s ease-out; + -webkit-transition: -webkit-transform .3s ease-out; +} +.slides.layout-widescreen > article { + margin-left: -550px; + width: 1100px; +} +.slides.layout-faux-widescreen > article { + margin-left: -550px; + width: 1100px; + + padding: 40px 160px; +} + +.slides.template-default > article:not(.nobackground):not(.biglogo) { +/* background: url(images/google-logo-small.png) 710px 625px no-repeat; */ + + background-color: white; +} + +.slides.template-io2011 > article:not(.nobackground):not(.biglogo) { + background: url(images/colorbar.png) 0 600px repeat-x, + url(images/googleio-logo.png) 640px 625px no-repeat; + + background-size: 100%, 225px; + + background-color: white; +} +.slides.layout-widescreen > article:not(.nobackground):not(.biglogo), +.slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) { + background-position-x: 0, 840px; +} + +/* Clickable/tappable areas */ + +.slide-area { + z-index: 1000; + + position: absolute; + left: 0; + top: 0; + width: 150px; + height: 700px; + + left: 50%; + top: 50%; + + cursor: pointer; + margin-top: -350px; + + tap-highlight-color: transparent; + -o-tap-highlight-color: transparent; + -moz-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; +} +#prev-slide-area { + margin-left: -550px; +} +#next-slide-area { + margin-left: 400px; +} +.slides.layout-widescreen #prev-slide-area, +.slides.layout-faux-widescreen #prev-slide-area { + margin-left: -650px; +} +.slides.layout-widescreen #next-slide-area, +.slides.layout-faux-widescreen #next-slide-area { + margin-left: 500px; +} + +/* Slide styles */ + +.slides.template-default article.biglogo { + background: white url(images/google-logo.png) 50% 50% no-repeat; +} + +.slides.template-io2011 article.biglogo { + background: white url(images/googleio-logo.png) 50% 50% no-repeat; + + background-size: 600px; +} + +/* Slides */ + +.slides > article { + display: none; +} +.slides > article.far-past { + display: block; + transform: translate(-2040px); + -o-transform: translate(-2040px); + -moz-transform: translate(-2040px); + -webkit-transform: translate3d(-2040px, 0, 0); +} +.slides > article.past { + display: block; + transform: translate(-1020px); + -o-transform: translate(-1020px); + -moz-transform: translate(-1020px); + -webkit-transform: translate3d(-1020px, 0, 0); +} +.slides > article.current { + display: block; + transform: translate(0); + -o-transform: translate(0); + -moz-transform: translate(0); + -webkit-transform: translate3d(0, 0, 0); +} +.slides > article.next { + display: block; + transform: translate(1020px); + -o-transform: translate(1020px); + -moz-transform: translate(1020px); + -webkit-transform: translate3d(1020px, 0, 0); +} +.slides > article.far-next { + display: block; + transform: translate(2040px); + -o-transform: translate(2040px); + -moz-transform: translate(2040px); + -webkit-transform: translate3d(2040px, 0, 0); +} + +.slides.layout-widescreen > article.far-past, +.slides.layout-faux-widescreen > article.far-past { + display: block; + transform: translate(-2260px); + -o-transform: translate(-2260px); + -moz-transform: translate(-2260px); + -webkit-transform: translate3d(-2260px, 0, 0); +} +.slides.layout-widescreen > article.past, +.slides.layout-faux-widescreen > article.past { + display: block; + transform: translate(-1130px); + -o-transform: translate(-1130px); + -moz-transform: translate(-1130px); + -webkit-transform: translate3d(-1130px, 0, 0); +} +.slides.layout-widescreen > article.current, +.slides.layout-faux-widescreen > article.current { + display: block; + transform: translate(0); + -o-transform: translate(0); + -moz-transform: translate(0); + -webkit-transform: translate3d(0, 0, 0); +} +.slides.layout-widescreen > article.next, +.slides.layout-faux-widescreen > article.next { + display: block; + transform: translate(1130px); + -o-transform: translate(1130px); + -moz-transform: translate(1130px); + -webkit-transform: translate3d(1130px, 0, 0); +} +.slides.layout-widescreen > article.far-next, +.slides.layout-faux-widescreen > article.far-next { + display: block; + transform: translate(2260px); + -o-transform: translate(2260px); + -moz-transform: translate(2260px); + -webkit-transform: translate3d(2260px, 0, 0); +} + +/* Styles for slides */ + +.slides > article { + font-family: 'Open Sans', Arial, sans-serif; + + color: rgb(102, 102, 102); + text-shadow: 0 1px 1px rgba(0, 0, 0, .1); + + font-size: 30px; + line-height: 36px; + + letter-spacing: -1px; +} + +b { + font-weight: 600; +} + +.blue { + color: rgb(0, 102, 204); +} +.yellow { + color: rgb(255, 211, 25); +} +.green { + color: rgb(0, 138, 53); +} +.red { + color: rgb(255, 0, 0); +} +.black { + color: black; +} +.white { + color: white; +} + +a { + color: rgb(0, 102, 204); +} +a:visited { + color: rgba(0, 102, 204, .75); +} +a:hover { + color: black; +} + +p { + margin: 0; + padding: 0; + + margin-top: 20px; +} +p:first-child { + margin-top: 0; +} + +h1 { + font-size: 60px; + line-height: 60px; + + padding: 0; + margin: 0; + margin-top: 200px; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -3px; + + color: rgb(51, 51, 51); +} + +h2 { + font-size: 45px; + line-height: 45px; + + position: absolute; + bottom: 150px; + + padding: 0; + margin: 0; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -2px; + + color: rgb(51, 51, 51); +} + +h3 { + font-size: 30px; + line-height: 36px; + + padding: 0; + margin: 0; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -1px; + + color: rgb(51, 51, 51); +} + +article.fill h3 { + background: rgba(255, 255, 255, .75); + padding-top: .2em; + padding-bottom: .3em; + margin-top: -.2em; + margin-left: -60px; + padding-left: 60px; + margin-right: -60px; + padding-right: 60px; +} + +ul { + list-style: none; + margin: 0; + padding: 0; + + margin-top: 40px; + + margin-left: .75em; +} +ul:first-child { + margin-top: 0; +} +ul ul { + margin-top: .5em; +} +li { + padding: 0; + margin: 0; + + margin-bottom: .5em; +} +li::before { + content: '·'; + + width: .75em; + margin-left: -.75em; + + position: absolute; +} + +pre { + font-family: 'Droid Sans Mono', 'Courier New', monospace; + + font-size: 20px; + line-height: 28px; + padding: 5px 10px; + + letter-spacing: -1px; + + margin-top: 40px; + margin-bottom: 40px; + + color: black; + background: rgb(240, 240, 240); + border: 1px solid rgb(224, 224, 224); + box-shadow: inset 0 2px 6px rgba(0, 0, 0, .1); + + overflow: hidden; +} + +code { + font-size: 95%; + font-family: 'Droid Sans Mono', 'Courier New', monospace; + + color: black; +} + +iframe { + width: 100%; + + height: 620px; + + background: white; + border: 1px solid rgb(192, 192, 192); + margin: -1px; + /*box-shadow: inset 0 2px 6px rgba(0, 0, 0, .1);*/ +} + +h3 + iframe { + margin-top: 40px; + height: 540px; +} + +article.fill iframe { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + + border: 0; + margin: 0; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + z-index: -1; +} + +article.fill img { + position: absolute; + left: 0; + top: 0; + min-width: 100%; + min-height: 100%; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + z-index: -1; +} +img.centered { + margin: 0 auto; + display: block; +} + +table { + width: 100%; + border-collapse: collapse; + margin-top: 40px; +} +th { + font-weight: 600; + text-align: left; +} +td, +th { + border: 1px solid rgb(224, 224, 224); + padding: 5px 10px; + vertical-align: top; +} + +.source { + position: absolute; + left: 60px; + top: 644px; + padding-right: 175px; + + font-size: 15px; + letter-spacing: 0; + line-height: 18px; +} + +q { + display: block; + font-size: 60px; + line-height: 72px; + + margin-left: 20px; + + margin-top: 100px; + margin-right: 150px; +} +q::before { + content: '“'; + + position: absolute; + display: inline-block; + margin-left: -2.1em; + width: 2em; + text-align: right; + + font-size: 90px; + color: rgb(192, 192, 192); +} +q::after { + content: '”'; + + position: absolute; + margin-left: .1em; + + font-size: 90px; + color: rgb(192, 192, 192); +} +div.author { + text-align: right; + font-size: 40px; + + margin-top: 20px; + margin-right: 150px; +} +div.author::before { + content: '—'; +} + +/* Size variants */ + +article.smaller p, +article.smaller ul { + font-size: 20px; + line-height: 24px; + letter-spacing: 0; +} +article.smaller table { + font-size: 20px; + line-height: 24px; + letter-spacing: 0; +} +article.smaller pre { + font-size: 15px; + line-height: 20px; + letter-spacing: 0; +} +article.smaller q { + font-size: 40px; + line-height: 48px; +} +article.smaller q::before, +article.smaller q::after { + font-size: 60px; +} + +/* Builds */ + +.build > * { + transition: opacity 0.5s ease-in-out 0.2s; + -o-transition: opacity 0.5s ease-in-out 0.2s; + -moz-transition: opacity 0.5s ease-in-out 0.2s; + -webkit-transition: opacity 0.5s ease-in-out 0.2s; +} + +.to-build { + opacity: 0; +} + +/* Pretty print */ + +.prettyprint .str, /* string content */ +.prettyprint .atv { /* a markup attribute value */ + color: rgb(0, 138, 53); +} +.prettyprint .kwd, /* a keyword */ +.prettyprint .tag { /* a markup tag name */ + color: rgb(0, 102, 204); +} +.prettyprint .com { /* a comment */ + color: rgb(127, 127, 127); + font-style: italic; +} +.prettyprint .lit { /* a literal value */ + color: rgb(127, 0, 0); +} +.prettyprint .pun, /* punctuation, lisp open bracket, lisp close bracket */ +.prettyprint .opn, +.prettyprint .clo { + color: rgb(127, 127, 127); +} +.prettyprint .typ, /* a type name */ +.prettyprint .atn, /* a markup attribute name */ +.prettyprint .dec, +.prettyprint .var { /* a declaration; a variable name */ + color: rgb(127, 0, 127); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/meeting20130802/template.html Fri Aug 02 09:54:58 2013 +0900 @@ -0,0 +1,358 @@ +<!DOCTYPE html> + +<html> + <head> + <title>Presentation</title> + + <meta charset='utf-8'> + <script + src='./slides.js'></script> + </head> + + <style> + /* Your individual styles here, or just use inline styles if that’s + what you want. */ + + + </style> + + <body style='display: none'> + + <section class='slides layout-regular template-default'> + + <!-- Your slides (<article>s) go here. Delete or comment out the + slides below. --> + + + + <article class='biglogo'> + </article> + + <article> + <h1> + Title Goes Here Up + <br> + To Two Lines + </h1> + <p> + Sergey Brin + <br> + May 10, 2011 + </p> + </article> + + <article> + <p> + This is a slide with just text. This is a slide with just text. + This is a slide with just text. This is a slide with just text. + This is a slide with just text. This is a slide with just text. + </p> + <p> + There is more text just underneath. + </p> + </article> + + <article> + <h3> + Simple slide with header and text + </h3> + <p> + This is a slide with just text. This is a slide with just text. + This is a slide with just text. This is a slide with just text. + This is a slide with just text. This is a slide with just text. + </p> + <p> + There is more text just underneath with a <code>code sample: 5px</code>. + </p> + </article> + + <article class='smaller'> + <h3> + Simple slide with header and text (small font) + </h3> + <p> + This is a slide with just text. This is a slide with just text. + This is a slide with just text. This is a slide with just text. + This is a slide with just text. This is a slide with just text. + </p> + <p> + There is more text just underneath with a <code>code sample: 5px</code>. + </p> + </article> + + <article> + <h3> + Slide with bullet points and a longer title, just because we + can make it longer + </h3> + <ul> + <li> + Use this template to create your presentation + </li> + <li> + Use the provided color palette, box and arrow graphics, and + chart styles + </li> + <li> + Instructions are provided to assist you in using this + presentation template effectively + </li> + <li> + At all times strive to maintain Google's corporate look and feel + </li> + </ul> + </article> + + <article> + <h3> + Slide with bullet points that builds + </h3> + <ul class="build"> + <li> + This is an example of a list + </li> + <li> + The list items fade in + </li> + <li> + Last one! + </li> + </ul> + + <div class="build"> + <p>Any element with child nodes can build.</p> + <p>It doesn't have to be a list.</p> + </div> + </article> + + <article class='smaller'> + <h3> + Slide with bullet points (small font) + </h3> + <ul> + <li> + Use this template to create your presentation + <li> + Use the provided color palette, box and arrow graphics, and + chart styles + <li> + Instructions are provided to assist you in using this + presentation template effectively + <li> + At all times strive to maintain Google's corporate look and feel + </ul> + </article> + + <article> + <h3> + Slide with a table + </h3> + + <table> + <tr> + <th> + Name + <th> + Occupation + <tr> + <td> + Luke Mahé + <td> + V.P. of Keepin’ It Real + <tr> + <td> + Marcin Wichary + <td> + The Michael Bay of Doodles + </table> + </article> + + <article class='smaller'> + <h3> + Slide with a table (smaller text) + </h3> + + <table> + <tr> + <th> + Name + <th> + Occupation + <tr> + <td> + Luke Mahé + <td> + V.P. of Keepin’ It Real + <tr> + <td> + Marcin Wichary + <td> + The Michael Bay of Doodles + </table> + </article> + + <article> + <h3> + Styles + </h3> + <ul> + <li> + <span class='red'>class="red"</span> + <li> + <span class='blue'>class="blue"</span> + <li> + <span class='green'>class="green"</span> + <li> + <span class='yellow'>class="yellow"</span> + <li> + <span class='black'>class="black"</span> + <li> + <span class='white'>class="white"</span> + <li> + <b>bold</b> and <i>italic</i> + </ul> + </article> + + <article> + <h2> + Segue slide + </h2> + </article> + + <article> + <h3> + Slide with an image + </h3> + <p> + <img style='height: 500px' src='images/example-graph.png'> + </p> + <div class='source'> + Source: Sergey Brin + </div> + </article> + + <article> + <h3> + Slide with an image (centered) + </h3> + <p> + <img class='centered' style='height: 500px' src='images/example-graph.png'> + </p> + <div class='source'> + Source: Larry Page + </div> + </article> + + <article class='fill'> + <h3> + Image filling the slide (with optional header) + </h3> + <p> + <img src='images/example-cat.jpg'> + </p> + <div class='source white'> + Source: Eric Schmidt + </div> + </article> + + <article> + <h3> + This slide has some code + </h3> + <section> + <pre> +<script type='text/javascript'> + // Say hello world until the user starts questioning + // the meaningfulness of their existence. + function helloWorld(world) { + for (var i = 42; --i >= 0;) { + alert('Hello ' + String(world)); + } + } +</script> +<style> + p { color: pink } + b { color: blue } + u { color: 'umber' } +</style> +</pre> + </section> + </article> + + <article class='smaller'> + <h3> + This slide has some code (small font) + </h3> + <section> + <pre> +<script type='text/javascript'> + // Say hello world until the user starts questioning + // the meaningfulness of their existence. + function helloWorld(world) { + for (var i = 42; --i >= 0;) { + alert('Hello ' + String(world)); + } + } +</script> +<style> + p { color: pink } + b { color: blue } + u { color: 'umber' } +</style> +</pre> + </section> + </article> + + <article> + <q> + The best way to predict the future is to invent it. + </q> + <div class='author'> + Alan Kay + </div> + </article> + + <article class='smaller'> + <q> + A distributed system is one in which the failure of a computer + you didn’t even know existed can render your own computer unusable. + </q> + <div class='author'> + Leslie Lamport + </div> + </article> + + <article class='nobackground'> + <h3> + A slide with an embed + title + </h3> + + <iframe src='http://www.google.com/doodle4google/history.html'></iframe> + </article> + + <article class='nobackground'> + <iframe src='http://www.google.com/doodle4google/history.html'></iframe> + </article> + + <article class='fill'> + <h3> + Full-slide embed with (optional) slide title on top + </h3> + <iframe src='http://www.google.com/doodle4google/history.html'></iframe> + </article> + + <article> + <h3> + Thank you! + </h3> + + <ul> + <li> + <a href='http://www.google.com'>google.com</a> + </ul> + </article> + + </section> + + </body> +</html>