From: Arthur Axel 'fREW' Schmidt Date: Sat, 1 May 2010 08:11:10 +0000 (-0500) Subject: initial commit X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=52d980cbfef6b53c00179db3ab2e7fc6edcbac2e;p=dbsrgits%2Fdbix-class-introduction-presentation.git initial commit --- 52d980cbfef6b53c00179db3ab2e7fc6edcbac2e diff --git a/slideshow.html b/slideshow.html new file mode 100644 index 0000000..980fe90 --- /dev/null +++ b/slideshow.html @@ -0,0 +1,920 @@ + + + + + +DBIx::Class (aka DBIC) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+ +
+

DBIX::Class (aka DBIC)

+

for (advanced) beginners

+

Leo Lapworth @ LPW 2009

+

http://leo.cuckoo.org/projects

+
+
+ +
+

assumptions

+

You know a little about Perl and using objects

+

You know a little bit about databases and using foreign keys

+
+ +
+

DBIx::Class?

+
    +
  • ORM (object relational mapper)
  • +
  • SQL <-> OO (using objects instead of SQL)
  • +
  • Simple, powerful, complex, fab and confusing
  • +
  • There are many ORMs, DBIx::Class just happens to be the best in Perl (personal opinion)
  • +
+
+ +
+

why this talk?

+
    +
  • Help avoid mistakes I made!
  • +
  • Help learn DBIx::Class faster
  • +
  • Make your coding easier
  • +
+
+ +
+

point of note

+

"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." - Brian W. Kernighan

+

This talk is about making it easy so we are less likely to get confused

+
+ +
+

table setup

+
+ +
+

example...

+
    +
  • Authors
  • +
  • Books
  • +
+
+ +
+

authors table

+
CREATE TABLE authors(
+   id   int(8) primary key auto_increment,
+   name varchar(255)
+) engine = InnoDB DEFAULT CHARSET=utf8;
+
+ +
+

tips

+

Name tables as simple plurals (add an S) - makes relationships easier to understand

+

(issue: Matt Trout "Tables should not be plural as gives you plurals for Result:: package names which represent a single row" - talk may be rewritten in future to reflect this as this is better once you understand the relationship setup - either way, consistency is important)

+

Use a character set (UTF8) from the start (for international characters)

+
+ +
+

authors table

+
CREATE TABLE authors(
+   id   int(8) primary key auto_increment,
+   name varchar(255)
+) engine = InnoDB DEFAULT CHARSET=utf8;
+
+ +
+

books table

+
CREATE TABLE books(
+   id     int(8) primary key auto_increment,
+   title  varchar(255),
+   author int(8),foreign key (author)
+      references authors(id)
+) engine = InnoDB DEFAULT CHARSET=utf8;
+
+ + +
+

tips

+

Name link fields as singular

+

Check foreign key is the same field and type and size in both tables

+
+ +
+

books table

+
CREATE TABLE books(
+   id     int(8) primary key auto_increment,
+   title  varchar(255),
+   author int(8),foreign key (author)
+      references authors(id)
+) engine = InnoDB DEFAULT CHARSET=utf8;
+
+ +
+

CRUD compared

+
    +
  • C - Create
  • +
  • R - Read
  • +
  • U - Update
  • +
  • D - Delete
  • +
+
+ +
+

Manual (SQL)

+
+ +
+

manual: create

+
my $sth = $dbh->prepare('
+   INSERT INTO books
+   (title, author)
+   values (?,?)
+');
+
+$sth->execute(
+  'A book title', $author_id
+);
+
+ +
+

manual: create

+
my $sth = $dbh->prepare('
+   INSERT INTO books
+   (title, author)
+   values (?,?)
+');
+
+$sth->execute(
+  'A book title', $author_id
+);
+
+ +
+

manual: retrieve

+
my $sth = $dbh->prepare('
+   SELECT title,
+   authors.name as author_name
+   FROM books, authors
+   WHERE books.author = authors.id
+');
+
+ +
+

manual: retrieve

+
while( my $book = $sth->fetchrow_hashref() ) {
+  print 'Author of '
+     . $book->{title}
+     . ' is '
+     . $book->{author_name}
+     . "\n";
+}
+
+ +
+

manual: update

+
my $update = $dbh->prepare('
+   UPDATE books
+   SET title = ?
+   WHERE id = ?
+');
+
+$update->execute(
+  'New title',$book_id
+);
+
+ +
+

manual: delete

+
my $delete = $dbh->prepare('
+   DELETE FROM books
+   WHERE id = ?
+');
+
+$delete->execute($book_id);
+
+ +
+

DBIx::Class

+
+ +
+

DBIC: create

+
my $book = $book_model->create({
+   title  => 'A book title',
+   author => $author_id,
+});
+

Look ma, no SQL!

+

Tip: do not pass in primary_key field, even if it's empty/undef as the object returned will have an empty id, even if your field is auto increment.

+
+ +
+

DBIC: create

+
my $book = $book_model->create({
+   title  => 'A book title',
+   author => $author_id,
+});
+
+ +
+

DBIC: create

+
my $pratchett = $author_model->create({
+   name => 'Terry Pratchett',
+});
+
+ +
+

DBIC: create

+
my $book = $pratchett->create_related(
+  books => {
+   title => 'Another Discworld book',
+});
+or +
my $book = $pratchett->add_to_books({
+   title => 'Another Discworld book',
+});
+
+ +
+

DBIC: create

+
my $book = $pratchett->create_related(
+  books => {
+   title => 'Another Discworld book',
+});
+or +
my $book = $pratchett->add_to_books({
+   title => 'Another Discworld book',
+});
+
+ +
+

DBIC: retrieve

+

DBIx::Class - Lots of ways to do the same thing...

+

"There is more than one way to do it (TIMTOWTDI, usually pronounced "Tim Toady") is a Perl motto"

+
+ +
+

DBIC: retrieve

+
my $book = $book_model->find($book_id);
+
+my $book = $book_model->search({
+   title => 'A book title',
+})->single;
+
+my @books = $book_model->search({
+   author => $author_id,
+})->all;
+
+ +
+

DBIC: retrieve

+
while( my $book = $books_rs->next() ) {
+ print 'Author of '
+    . $book->title
+    . ' is '
+    . $book->author->name
+    . "\n";
+}
+
+ +
+

DBIC: retrieve

+
my $books_rs = $book_model->search({
+   author => $author_id,
+});
+

Search takes SQL::Abstract formatted queries

+
> perldoc SQL::Abstract

+
+ +
+

DBIC: update

+
$book->update({
+  title => 'New title',
+});
+
+ +
+

DBIC: delete

+
$book->delete;
+
+ +
+

Creating models

+
+ +
+
Example of a DBIC Result
+
+ +
+
Example of a DBIC Result
+
+ +
+

too much typing! too much maintenance!

+

too much maintenance!

+
+ +
+

Schema::Loader

+
code for S::L here
+
+ +
+

splitting logic cleanly

+

LPW::DBIC::Result::Foo = an individual row

+

LPW::DBIC::ResultSet::Foo = searches / results

+
+ +
+

using your Schema

+
example usage code goes here
+
+ +
+

DEBUGGING

+
DBIC_TRACE=1 ./your_script.pl
+
+ +
+

Schema::Loader

+
LPW::DBIC::Result::Authors->table("authors");
+LPW::DBIC::Result::Authors->add_columns(
+   id => {
+      data_type     => "INT",
+      default_value => undef,
+      is_nullable   => 0,
+      size          => 8
+   },
+   title => {
+      data_type     => "VARCHAR",
+      default_value => undef,
+      is_nullable   => 1,
+      size          => 255,
+   },
+);
+LPW::DBIC::Result::Authors->set_primary_key("id");
+
+ +
+

Schema::Loader

+
LPW::DBIC::Result::Books->table("books");
+LPW::DBIC::Result::Books->add_columns(
+   id => {
+      data_type     => "INT",
+      default_value => undef,
+      is_nullable   => 0,
+      size          => 8
+   },
+   name => {
+      data_type     => "VARCHAR",
+      default_value => undef,
+      is_nullable   => 1,
+      size          => 255,
+   },
+   author => {
+      data_type     => "INT",
+      default_value => undef,
+      is_nullable   => 1,
+      size          => 8
+   },
+);
+LPW::DBIC::Result::Books->set_primary_key("id");
+
+ +
+

Schema::Loader

+
LPW::DBIC::Result::Authors->has_many(books => "LPW::DBIC::Books",
+   { "foreign.author" => "self.id" });
+
+LPW::DBIC::Result::Books->belongs_to(author => "LPW::DBIC::Authors",
+   { id => "author" });
+
+ +
+

SQL - debugging

+
INSERT INTO authors (name)
+   VALUES (?): 'Douglas Adams'
+
+INSERT INTO books (author, title)
+   VALUES (?, ?): '5', '42'
+
+ +
+

overloading

+
LPW::DBIC::Result::Books
+LPW::DBIC::ResultSet::Books
+LPW::DBIC::Result::Authors
+LPW::DBIC::ResultSet::Books
+
+ +
+

Result::

+
package LPW::DBIC::Result::Books;
+use base 'DBIx::Class';
+use strict;
+use warnings;
+
+sub isbn {
+   my $self = shift;
+
+   # search amazon or something
+   my $api = Amazon::API->book({
+      title => $self->title
+   });
+
+   return $api->isbn;
+}
+
+1;
+
+ +
+

Result::

+
print $book->isbn;
+
+ +
+

Result:: (inflating)

+
package LPW::DBIC::Result::Books;
+use base 'DBIx::Class';
+use strict;
+use warnings;
+
+use DateTime::Format::MySQL;
+
+__PACKAGE__->inflate_column(
+   date_published => {
+      inflate => sub { DateTime::Format::MySQL->parse_date(shift) },
+      deflate => sub { shift->ymd},
+   }
+);
+# Automatic see: DBIx::Class::InflateColumn::DateTime
+
+ +
+

Result:: (inflating)

+
package LPW::DBIC::Result::Books;
+use base 'DBIx::Class';
+use strict;
+use warnings;
+
+use DateTime::Format::MySQL;
+
+__PACKAGE__->inflate_column(
+   date_published => {
+      inflate => sub { DateTime::Format::MySQL->parse_date(shift) },
+      deflate => sub { shift->ymd},
+   }
+);
+# Automatic see: DBIx::Class::InflateColumn::DateTime
+# Automatic see: DBIx::Class::InflateColumn::DateTime
+# Automatic see: DBIx::Class::InflateColumn::DateTime
+
+ +
+

Result:: (deflating)

+
$book->date_published(DateTime->now);
+$book->update;
+
+ +
+

Result:: (inflating)

+
my $date_published = $book->date_published;
+print $date_published->month_abbr;
+ +Nov +
+ +
+

ResultSets::

+
package LPW::DBIC::ResultSet::Books;
+use base 'DBIx::Class::ResultSet';
+sub the_ultimate_books {
+   my $self = shift;
+   return $self->search({ title => { -like => '%42%' } });
+}
+sub by_author {
+   my ( $self, $author ) = @_;
+   return $self->search({ author => $author->id })
+}
+
+1;
+
+ +
+

ResultSets::

+
package LPW::DBIC::ResultSet::Books;
+use base 'DBIx::Class::ResultSet';
+sub the_ultimate_books {
+   my $self = shift;
+   return $self->search({ title => { -like => '%42%' } })
+}
+sub by_author {
+   my ( $self, $author ) = @_;
+   return $self->search({ author => $author->id })
+}
+
+1;
+
+ +
+

ResultSets::

+
package LPW::DBIC::ResultSet::Books;
+use base 'DBIx::Class::ResultSet';
+sub the_ultimate_books {
+   my $self = shift;
+   return $self->search({ title => { -like => '%42%' } });
+}
+sub by_author {
+   my ( $self, $author ) = @_;
+   return $self->search({ author => $author->id })
+}
+
+1;
+
+ +
+

ResultSets::

+
use LPW::DBIC;
+my $book_model = LPW::DBIC->resultset('Books');
+my $book_rs    = $book_model->the_ultimate_books;
+my @books      = $book_rs->all;
+
+ +
+

ResultSets::chaining

+
use LPW::DBIC;
+my $book_model   = LPW::DBIC->resultset('Books');
+my $author_model = LPW::DBIC->resultset('Authors');
+my $author       = $author_model->search({ name => 'Douglas Adams' })->single;
+my $book_rs      = $book_model->the_ultimate_books->by_author($author);
+my @books        = $book_rs->all;
+
+ +
+

ResultSets::chaining

+
my $book_rs = $book_model
+  ->the_ultimate_books
+  ->by_author($author);
+or + +
my $book_rs = $book_model
+  ->the_ultimate_books();
+$book_rs = $book_rs->by_author($author);
+
# Debug (SQL):
+
+# SELECT me.id, me.title, me.date_published, me.author
+#   FROM books me
+#   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
+#   WHERE ( ( ( author = ? ) AND ( title LIKE ? ) ) ): '5', '%42%'
+
+ +
+

ResultSets::chaining

+
my $rs = $book_model
+  ->category('childrens')
+  ->by_author($author)
+  ->published_after('1812')
+  ->first_page_contains('once upon')
+  ->rating_greater_than(4);
+
+my @books = $rs->all;
+
+ +
+

overloading before new record

+
+ +
+

overloading before new record

+
package LPW::DBIC::Result::Authors;
+use base 'DBIx::Class';
+
+sub new {
+   my ( $class, $attrs ) = @_;
+   # Mess with $attrs
+   my $new = $class->next::method($attrs);
+   return $new
+}
+
+1;
+ +
+

relationships

+
+ +
+

multiple authors

+
+ +
+

a few relationships

+ (authors -- author_link_to_book -- books) +
+ +
+

a few relationships

+ ! +
+ +
+

new join table

+
CREATE TABLE author_and_books(
+  id      int(8)    primary key auto_increment,
+  book    int(8),
+  author  int(8),
+  foreign key (book)     references books(id),
+  foreign key (author)   references authors(id)
+) engine = InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE `books` DROP `author`
+
+ +
+

new join table

+
CREATE TABLE author_and_books(
+  id      int(8)    primary key auto_increment,
+  book    int(8),
+  author  int(8),
+  foreign key (book)     references books(id),
+  foreign key (author)   references authors(id)
+) engine = InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE `books` DROP `author`
+
+ +
+

has_many

+
+ +
+

has_many

+
package LPW::DBIC::Result::Books;
+
+__PACKAGE__->has_many( author_and_books => "LPW::DBIC::Result::AuthorAndBooks",
+    { "foreign.book" => "self.id" },
+);
+
+# This is auto generated by Schema::Loader
+
+ +
+

has_many

+
package LPW::DBIC::Result::Books;
+
+__PACKAGE__->has_many(
+author_and_books => # name of accessor
+"LPW::DBIC::Result::AuthorAndBooks", # related class
+    { "foreign.book" => "self.id" } # Relationship (magic often works if not
+                                        # specified, but avoid!)
+);
+
+
+ +
+

belongs_to

+
+ +
+

belongs_to

+
package LPW::DBIC::Result::AuthorAndBooks;
+
+__PACKAGE__->belongs_to(
+   book => # Accessor name
+   "LPW::DBIC::Result::Books", # Related class
+   { id => "book" } # relationship
+);
+
+
+ +
+

same for Authors

+
+ +
+

with no coding...

+
+ +
+

many_to_many

+
+ +
+

many_to_many

+
package LPW::DBIC::Result::Books;
+use base 'DBIx::Class';
+
+__PACKAGE__->many_to_many(
+   authors => "author_and_books", 'author'
+);
+
+1;
+
+ # This is NOT auto generated by Schema::Loader 
+
+ +
+

many_to_many

+
package LPW::DBIC::Result::Books;
+use base 'DBIx::Class';
+
+__PACKAGE__->many_to_many(
+   authors # Accessor name
+   => "author_and_books", # has_many
+   'author' # foreign relationship name
+);
+
+1;
+
+ +
+

many_to_many

+
package LPW::DBIC::Result::Authors;
+use base 'DBIx::Class';
+
+__PACKAGE__->many_to_many(
+   "books" # Accessor Name
+   => "author_and_books", # has_many accessor_name
+   'book' # foreign relationship name
+);
+
+1;
+
+# This is NOT auto generated by Schema::Loader
+
+ +
+

using many_to_many

+
#!/usr/bin/perl
+
+use LPW::DBIC;
+
+my $author_model = LPW::DBIC->resultset('Authors');
+my $author       = $author_model->search({
+   name => 'Douglas Adams',
+})->single;
+$author->add_to_books({
+   title => 'A new book',
+});
+
+ +
+

using many_to_many

+
my $author = $author_model->search({
+   name => 'Douglas Adams',
+})->single;
+$author->add_to_books({
+   title => 'A new book',
+});
+
+# SELECT me.id, me.name FROM authors me
+#     WHERE ( name = ? ): 'Douglas Adams';
+# INSERT INTO books (title) VALUES (?): 'A new book';
+# INSERT INTO author_and_books (author, book)
+#     VALUES (?, ?): '5', '2';
+
+ +
+

using many_to_many

+
$author->add_to_books($book);
+
+$book->add_to_authors($author_1);
+$book->add_to_authors($author_2);
+
+ +
+

in 16 lines of code

+
+ +
+

errors

+

Read them closely!

+
+ +
+

error messages

+
DBIx::Class::Schema::Loader::connection(): Failed to load external class definition for 'LPW::DBIC::Result::Authors': Can't locate object method "many_to_many" via package "LPW::DBIC::Result::Author" at lib/LPW/DBIC/Result/Authors.pm line 9.Compilation failed in require at /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.
+
+ +
+

error messages

+
DBIx::Class::Schema::Loader::connection(): Failed to load external class definition for 'LPW::DBIC::Result::Authors': Can't locate object method "many_to_many" via package "LPW::DBIC::Result::Author" at lib/LPW/DBIC/Result/Authors.pm line 9.Compilation failed in require at /Library/Perl/5.8.8/DBIx/Class/Schema/Loader/Base.pm line 292.
+
+ +
+

errors

+
    +
  • Turn on debugging
  • +
  • Read error messages (sometimes useful!)
  • +
  • Check field names
  • +
  • Check package names
  • +
  • Check which database you are connected to (dev/test/live?) - repeat above
  • +
+
+ +
+

bonus slides!

+
+ +
+

Template Toolkit

+
    +
  • [% author.books.count %]
    not working?
  • +
  • TT all methods are called in list context
  • +
  • [% author.books_rs.count %]
    scalar context
  • +
  • Available for all relationships
  • +
+
+ +
+

Catalyst

+
package Your::App::Model::LPW;
+use base qw(Catalyst::Model::DBIC::Schema);
+
+use strict;
+use warnings;
+
+__PACKAGE__->config(
+  schema_class => 'LPW::DBIC',
+);
+
+1;
+

Keep your Schema in a separate package to your Catalyst application

+
+ +
+

Catalyst

+
sub action_name : Local {
+  my ($self, $c) = @_;
+
+  my $model = $c->model('DBIC::LPW');
+  my $author_model = $model->resultset('Authors');
+
+}
+
+1;
+
+ +
+ + diff --git a/ui/graphic_support/blank.gif b/ui/graphic_support/blank.gif new file mode 100644 index 0000000..75b945d Binary files /dev/null and b/ui/graphic_support/blank.gif differ diff --git a/ui/graphic_support/finish.gif b/ui/graphic_support/finish.gif new file mode 100644 index 0000000..55e1ff9 Binary files /dev/null and b/ui/graphic_support/finish.gif differ diff --git a/ui/graphic_support/fixed.js b/ui/graphic_support/fixed.js new file mode 100644 index 0000000..118ae70 --- /dev/null +++ b/ui/graphic_support/fixed.js @@ -0,0 +1 @@ +// fixed.js: fix fixed positioning and fixed backgrounds in IE/Win // version 1.8, 08-Aug-2003 // written by Andrew Clover , use freely /*@cc_on @if (@_win32 && @_jscript_version>4) var fixed_positions= new Array(); var fixed_backgrounds= new Array(); var fixed_viewport; // Initialisation. Called when the tag arrives. Set up viewport so the // rest of the script knows we're going, and add a measurer div, used to detect // font size changes and measure image sizes for backgrounds later function fixed_init() { fixed_viewport= (document.compatMode=='CSS1Compat') ? document.documentElement : document.body; var el= document.createElement('div'); el.setAttribute('id', 'fixed-measure'); el.style.position= 'absolute'; el.style.top= '0'; el.style.left= '0'; el.style.overflow= 'hidden'; el.style.visibility= 'hidden'; el.style.fontSize= 'xx-large'; el.style.height= '5em'; el.style.setExpression('width', 'fixed_measureFont()'); document.body.insertBefore(el, document.body.firstChild); } // Binding. Called every time an element is added to the document, check it // for fixed features, if found add to our lists and set initial props function fixed_bind(el) { var needLayout= false; var tag= el.tagName.toLowerCase(); var st= el.style; var cst= el.currentStyle; var anc; // find fixed-position elements if (cst.position=='fixed') { needLayout= true; fixed_positions[fixed_positions.length]= el; // store original positioning as we'll overwrite it st.position= 'absolute'; st.fixedPLeft= cst.left; st.fixedPTop= cst.top; st.fixedPRight= cst.right; st.fixedPBottom= cst.bottom; st.fixedPWidth= fixed_parseLength(cst.width); st.fixedPHeight= fixed_parseLength(cst.height); // find element that will act as containing box, for convenience later st.fixedCB= null; for (anc= el; (anc= anc.parentElement).parentElement;) { if (anc.currentStyle.position!='static') { st.fixedCB= anc; break; } } // detect nested fixed positioning (only ancestor need move) st.fixedNest= false; for (anc= el; anc= anc.parentElement;) { if (anc.style.fixedNest!=null) st.fixedNest= true; break; } } // find fixed-background elements (not body/html which IE already gets right) if (cst.backgroundAttachment=='fixed' && tag!='body' && tag!='html') { needLayout= true; fixed_backgrounds[fixed_backgrounds.length]= el; // get background offset, converting from keyword if necessary st.fixedBLeft= fixed_parseLength(cst.backgroundPositionX); st.fixedBTop= fixed_parseLength(cst.backgroundPositionY); // if it's a non-zero %age, need to know size of image for layout if (st.fixedBLeft[1]=='%' || st.fixedBTop[1]=='%') { st.fixedBWidth= 0; st.fixedBHeight= 0; fixed_measureBack(el); } } if (needLayout) fixed_layout(); } // Layout. On every window or font size change, recalculate positioning // Request re-layout at next free moment var fixed_delaying= false; function fixed_delayout() { if (fixed_delaying) return; fixed_delaying= true; window.setTimeout(fixed_layout, 0); } var fixed_ARBITRARY= 200; function fixed_layout() { fixed_delaying= false; if (!fixed_viewport) return; var i, el, st, j, pr, tmp, A= 'auto'; var cb, cbLeft, cbTop, cbRight, cbBottom, oLeft, oTop, oRight, oBottom; var vpWidth=fixed_viewport.clientWidth, vpHeight=fixed_viewport.clientHeight; // calculate initial position for fixed-position elements [black magic] for (i= fixed_positions.length; i-->0;) { el= fixed_positions[i]; st= el.style; // find positioning of containing block cb= st.fixedCB; if (!cb) cb= fixed_viewport; cbLeft= fixed_pageLeft(cb); cbTop= fixed_pageTop(cb); if (cb!=fixed_viewport) { cbLeft+= cb.clientLeft; cbTop+= cb.clientTop; } cbRight= fixed_viewport.clientWidth-cbLeft-cb.clientWidth; cbBottom= fixed_viewport.clientHeight-cbTop-cb.clientHeight; // if size is in %, must recalculate relative to viewport if (st.fixedPWidth[1]=='%') st.width= Math.round(vpWidth*st.fixedPWidth[0]/100)+'px'; if (st.fixedPHeight[1]=='%') st.height= Math.round(vpHeight*st.fixedPHeight[0]/100)+'px'; // find out offset values at max size, to account for margins st.left= A; st.right= '0'; st.top= A; st.bottom= '0'; oRight= el.offsetLeft+el.offsetWidth; oBottom= el.offsetTop+el.offsetHeight; st.left= '0'; st.right= A; st.top= '0'; st.bottom= A; oLeft= el.offsetLeft; oTop= el.offsetTop; // use this to convert all edges to pixels st.left= A; st.right= st.fixedPRight; st.top= A; st.bottom= st.fixedPBottom; oRight-= el.offsetLeft+el.offsetWidth; oBottom-= el.offsetTop+el.offsetHeight; st.left= st.fixedPLeft; st.top= st.fixedPTop; oLeft= el.offsetLeft-oLeft; oTop= el.offsetTop-oTop; // edge positioning fix if (st.fixedPWidth[1]==A && st.fixedPLeft!=A && st.fixedPRight!=A) { tmp= el.offsetLeft; st.left= A; st.width= fixed_ARBITRARY+'px'; tmp= fixed_ARBITRARY+el.offsetLeft-tmp+cbLeft+cbRight; st.left= st.fixedPLeft; st.width= ((tmp<1)?1:tmp)+'px'; } if (st.fixedPHeight[1]==A && st.fixedPTop!=A && st.fixedPBottom!=A) { tmp= el.offsetTop; st.top= A; st.height= fixed_ARBITRARY+'px'; tmp= fixed_ARBITRARY+el.offsetTop-tmp+cbTop+cbBottom; st.top= st.fixedPTop; st.height= ((tmp<1)?1:tmp)+'px'; } // move all non-auto edges relative to the viewport st.fixedCLeft= (st.fixedPLeft=='auto') ? oLeft : oLeft-cbLeft; st.fixedCTop= (st.fixedPTop=='auto') ? oTop : oTop-cbTop; st.fixedCRight= (st.fixedPRight=='auto') ? oRight : oRight-cbRight; st.fixedCBottom= (st.fixedPBottom=='auto') ? oBottom : oBottom-cbBottom; // remove left-positioning of right-positioned elements if (st.fixedPLeft=='auto' && st.fixedPRight!='auto') st.fixedCLeft= 'auto'; if (st.fixedPTop=='auto' && st.fixedPBottom!='auto') st.fixedCTop= 'auto'; } // calculate initial positioning of fixed backgrounds for (i= fixed_backgrounds.length; i-->0;) { el= fixed_backgrounds[i]; st= el.style; tmp= st.fixedBImage; if (tmp) { if (tmp.readyState!='uninitialized') { st.fixedBWidth= tmp.offsetWidth; st.fixedBHeight= tmp.offsetHeight; st.fixedBImage= window.undefined; } } st.fixedBX= fixed_length(el, st.fixedBLeft, vpWidth-st.fixedBWidth); st.fixedBY= fixed_length(el, st.fixedBTop, vpHeight-st.fixedBHeight); } // now call scroll() to set the positions from the values just calculated fixed_scroll(); } // Scrolling. Offset fixed elements relative to viewport scrollness var fixed_lastX, fixed_lastY; var fixed_PATCHDELAY= 300; var fixed_patching= false; // callback function after a scroll, because incorrect scroll position is // often reported first go! function fixed_patch() { fixed_patching= false; var scrollX= fixed_viewport.scrollLeft, scrollY= fixed_viewport.scrollTop; if (scrollX!=fixed_lastX && scrollY!=fixed_lastY) fixed_scroll(); } function fixed_scroll() { if (!fixed_viewport) return; var i, el, st, viewportX, viewportY; var scrollX= fixed_viewport.scrollLeft, scrollY= fixed_viewport.scrollTop; fixed_lastX= scrollX; fixed_lastY= scrollY; // move non-nested fixed-position elements for (i= fixed_positions.length; i-->0;) { st= fixed_positions[i].style; viewportX= (st.fixedNest) ? 0 : scrollX; viewportY= (st.fixedNest) ? 0 : scrollY; if (st.fixedCLeft!='auto') st.left= (st.fixedCLeft+viewportX)+'px'; if (st.fixedCTop!='auto') st.top= (st.fixedCTop+viewportY)+'px'; viewportX= (st.fixedCB==null || st.fixedCB==fixed_viewport) ? 0 : viewportX; viewportY= (st.fixedCB==null || st.fixedCB==fixed_viewport) ? 0 : viewportY; st.right= (st.fixedCRight-viewportX+1)+'px'; st.right= (st.fixedCRight-viewportX)+'px'; st.bottom= (st.fixedCBottom-viewportY+1)+'px'; st.bottom= (st.fixedCBottom-viewportY)+'px'; } // align fixed backgrounds to viewport for (i= fixed_backgrounds.length; i-->0;) { el= fixed_backgrounds[i]; st= el.style; viewportX= scrollX; viewportY= scrollY; while (el.offsetParent) { viewportX-= el.offsetLeft+el.clientLeft; viewportY-= el.offsetTop +el.clientTop; el= el.offsetParent; } st.backgroundPositionX= (st.fixedBX+viewportX)+'px'; st.backgroundPositionY= (st.fixedBY+viewportY)+'px'; } // call back again in a tic if (!fixed_patching) { fixed_patching= true; window.setTimeout(fixed_patch, fixed_PATCHDELAY); } } // Measurement. Load bg-image into an invisible element on the page, when // loaded write the width/height to an element's style for layout use; detect // when font size changes function fixed_measureBack(el) { var measure= document.getElementById('fixed-measure'); var img= document.createElement('img'); img.setAttribute('src', fixed_parseURL(el.currentStyle.backgroundImage)); measure.appendChild(img); el.style.fixedBImage= img; if (img.readyState=='uninitialized') img.attachEvent('onreadystatechange', fixed_measureBackImage_ready); } function fixed_measureBackImage_ready() { var img= event.srcElement; if (img && img.readyState!='uninitialized') { img.detachEvent('onreadystatechange', fixed_measureBackImage_ready); fixed_layout(); } } var fixed_fontsize= 0; function fixed_measureFont() { var fs= document.getElementById('fixed-measure').offsetHeight; if (fixed_fontsize!=fs && fixed_fontsize!=0) fixed_delayout(); fixed_fontsize= fs; return '5em'; } // Utility. General-purpose functions // parse url() to get value inside function fixed_parseURL(v) { v= v.substring(4, v.length-1); if (v.charAt(0)=='"' && v.charAt(v.length-1)=='"' || v.charAt(0)=="'" && v.charAt(v.length-1)=="'") return v.substring(1, v.length-1); else return v; } // parse length or auto or background-position keyword into number and unit var fixed_numberChars= '+-0123456789.'; var fixed_ZERO= new Array(0, 'px'); var fixed_50PC= new Array(50, '%'); var fixed_100PC= new Array(100, '%'); var fixed_AUTO= new Array(0, 'auto'); function fixed_parseLength(v) { var num, i; if (v=='left' || v=='top') return fixed_ZERO; if (v=='right' || v=='bottom') return fixed_100PC; if (v=='center') return fixed_50PC; if (v=='auto') return fixed_AUTO; i= 0; while (i arrives, then call main init. Pass any new elements // found on each scan to be bound var fixed_SCANDELAY= 500; function fixed_scan() { if (!document.body) return; if (!fixed_viewport) fixed_init(); var el; for (var i= 0; i + + + + \ No newline at end of file diff --git a/ui/graphic_support/numeric.png b/ui/graphic_support/numeric.png new file mode 100644 index 0000000..8f911e7 Binary files /dev/null and b/ui/graphic_support/numeric.png differ diff --git a/ui/graphic_support/progress.gif b/ui/graphic_support/progress.gif new file mode 100644 index 0000000..1323684 Binary files /dev/null and b/ui/graphic_support/progress.gif differ diff --git a/ui/s5-notes.html b/ui/s5-notes.html new file mode 100644 index 0000000..d4da758 --- /dev/null +++ b/ui/s5-notes.html @@ -0,0 +1,157 @@ + + + + +Notes + + + + + + + +
+

+Elapsed Time +

+
    +
  • +

    Presentation

    +00:00:00 +
  • +
  • +

    Current Slide

    +00:00:00 +
  • +
+
+|< +
+
+ +
+

+Remaining Time +

+

+- +00:00:00 ++ +

+
+
+ +|| +|< +
+
+
+ +

...

+
+ +

...

+
+ + + diff --git a/ui/scala_utf/framing.css b/ui/scala_utf/framing.css new file mode 100644 index 0000000..bfd20bb --- /dev/null +++ b/ui/scala_utf/framing.css @@ -0,0 +1,22 @@ +/* The following styles size, place, and layer the slide components. + Edit these if you want to change the overall slide layout. + The commented lines can be uncommented (and modified, if necessary) + to help you with the rearrangement process. */ + +/* target = 1024x768 */ + +div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} +div#header {top: 0; height: 3em; z-index: 1;} +div#footer {top: auto; bottom: 0; height: 0.5em; z-index: 5;} +.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;} +div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} +div#controls form {text-align: right; width: 100%; margin: 0;} +#currentSlide {position: absolute; width: 12%; left: 44%; bottom: 1em; z-index: 10;} +html>body #currentSlide {position: fixed;} + +/* +div#header {background: #FCC;} +div#footer {background: #CCF;} +div#controls {background: #BBD;} +div#currentSlide {background: #FFC;} +*/ diff --git a/ui/scala_utf/opera.css b/ui/scala_utf/opera.css new file mode 100644 index 0000000..9e9d2a3 --- /dev/null +++ b/ui/scala_utf/opera.css @@ -0,0 +1,7 @@ +/* DO NOT CHANGE THESE unless you really want to break Opera Show */ +.slide { + visibility: visible !important; + position: static !important; + page-break-before: always; +} +#slide0 {page-break-before: avoid;} diff --git a/ui/scala_utf/outline.css b/ui/scala_utf/outline.css new file mode 100644 index 0000000..962acab --- /dev/null +++ b/ui/scala_utf/outline.css @@ -0,0 +1,13 @@ +/* don't change this unless you want the layout stuff to show up in the outline view! */ + +.hide, .layout div, #footer *, #controlForm * {display: none;} +#footer, #controls, #controlForm, #navLinks, #sheet {display: block; visibility: visible; margin: 0; padding: 0;} +#sheet {float: right; padding: 0.5em;} +html>body #sheet {position: fixed; top: 0; right: 0;} + +/* making the outline look pretty-ish */ + +#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} +#slide0 h1 {padding-top: 1.5em;} +.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em; border-top: 1px solid #888; border-bottom: 1px solid #AAA;} +#sheet {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} diff --git a/ui/scala_utf/pattern.png b/ui/scala_utf/pattern.png new file mode 100644 index 0000000..6258f02 Binary files /dev/null and b/ui/scala_utf/pattern.png differ diff --git a/ui/scala_utf/pretty.css b/ui/scala_utf/pretty.css new file mode 100644 index 0000000..dbc70cc --- /dev/null +++ b/ui/scala_utf/pretty.css @@ -0,0 +1,96 @@ +/* Following are the presentation styles -- edit away! */ + +body {background: #000; color: #fff; font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 2.25em;} +a:link, a:visited {text-decoration: none; color: #F93;} +/* a:focus, a:hover {color: #f33 !important;} */ + +h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} +h1 {background-color: transparent;} + +ul, pre {margin: 0; line-height: 1em;} +html, body {margin: 0; padding: 0;} + +blockquote, q {font-style: italic;} +blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em; text-align: center; font-size: 1em;} +blockquote p {margin: 0;} +blockquote i {font-style: normal;} +blockquote b {display: block; margin-top: 0.5em; font-weight: normal; font-size: smaller; font-style: normal;} +blockquote b i {font-style: italic;} + +img {border: 0; } +kbd {font-weight: bold; font-size: 1em;} +sup {font-size: smaller; line-height: 1px;} + +.slide code {padding: 2px 0.25em; font-weight: bold; color: #f30;} +.slide code.bad, code del {color: red;} +.slide code.old {color: silver;} +.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #f30; font-size: 90%;} +.slide pre code {display: block;} +.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;} +.slide li {margin-top: 0.75em; margin-right: 0;} +.slide ul ul {line-height: 1;} +.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;} +.slide img.leader {display: block; margin: 0 auto;} + +div#header, div#footer {color: #666; font-family: Verdana, Arial, Helvetica, sans-serif;} +div#header {background-color: transparent; line-height: 1px;} +div#footer {background-color: transparent; font-size: 0.5em; font-weight: bold; padding: 1em 0;} +#footer h1, #footer h2 {border: none; display: block; padding: 0; position:absolute; bottom:0.5em;} +#footer h1 {left:1em; color: #666;} +#footer h2 {right:1em; color: #666; font-style: italic;} + +div.long {font-size: 0.75em;} +.slide h1 {position: absolute; top: 0.9em; left: 1.25em; z-index: 1; margin: 0.35em 0 0 50px; padding: 0; white-space: nowrap; font: bold 150%/1em Tahoma, Verdana, Arial, Helvetica, sans-serif; text-transform: capitalize; color: #fff; border-bottom: solid 0.1em red; background-color: transparent;} +.slide h3 {font-size: 130%;} +h1 abbr {font-variant: small-caps;} + +div#controls {position: absolute; left: 25%; bottom: 0; width: 50%; text-align: center; font: bold 1em Verdana, Arial, Helvetica, sans-serif;} +html>body div#controls {background: transparent; position: fixed; padding: 0; top: auto; text-align: center;} +#controls #sheet {display: none;} +#controls #controlForm {height: 3.0em; text-align: center; vertical-align: middle;} +#controls #navLinks {padding: 0 0 0.2em 0; margin: 0; background: url(pattern.png) gray bottom repeat-x; border: 2px outset gray; border-top-color: silver; border-left-color: silver; text-align: center; vertical-align: middle; white-space: nowrap;} +#controls #navLinks a {text-shadow: #444 0.1em 0.1em 0.1em; padding: 0; margin: 0em 0.36em; background: transparent; border: none; color: white; cursor: pointer;} +#controls #navLinks a:focus, #controls #navLinks a:hover {text-decoration: none; color: black !important;} +#controls #navLinks a:link, #controls #navLinks a:visited {text-decoration: none; color: white;} +#controls #navLinks .subLinks {display: inline; border: 1px inset gray; border-bottom-color: silver; border-right-color: silver; font-size: 75%; padding: 0 0.25em; margin: -0.2em 0 0 0; background-color: #666; text-align: center; vertical-align: middle; white-space: nowrap;} +#controls #navLinks .subLinks a {text-shadow: none; font-weight: normal; padding: 0; margin: 0; border: none; color: white; cursor: pointer;} + +#jumplist, #volumelist {padding: 0; margin: 0; width: 1.5em; height: 2.25em; cursor: pointer;} + +#currentSlide {white-space: nowrap; text-align: center; margin-bottom: -0.5em; font-size: 0.5em; background-color: transparent; color: #666;} + +#guru {position: absolute; visibility: visible; left: 0px; top: 0px; padding: 4px; width: 99%; height: auto; text-align: center; background-color: black; z-index: 10;} +#guru div {border: solid 3px red; padding: 4px; font-family: monospace; font-size: 60%; width: auto; height: auto; color: red; text-align: center;} + +#slide0 {padding-top: 3.5em; font-size: 90%;} +#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; border: none; font: bold 3em Verdana, Arial, Helvetica, sans-serif; font-variant: small-caps; white-space: normal; color: #fff; background-color: transparent;} +#slide0 h2 {font: bold italic 1em Arial, Helvetica, sans-serif; margin: 0.25em;} +#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} +#slide0 h4 {margin-top: 0; font-size: 1em;} + +ul.urls {list-style: none; display: inline; margin: 0;} +.urls li {display: inline; margin: 0;} +.note {display: none;} +.external {border-bottom: 1px dotted gray;} +html>body .external {border-bottom: none;} +.external:after {content: " \274F"; font-size: smaller; color: #F93;} + +.incremental, .incremental *, .incremental *:after {color: #999; visibility: visible;} +img.incremental, canvas.incremental {visibility: hidden;} +.slide .current {color: #ff0;} + +/* diagnostics +li:after {content: " [" attr(class) "]"; color: #F88;} +*/ + +table.piechart, table.barchart, table.linechart { border-spacing: 0.3em 0.15em; } +table.piechart tr th, table.barchart tr th, table.linechart tr th { white-space: nowrap; } +table.piechart tr td, table.barchart tr td, table.linechart tr td { vertical-align: top; white-space: nowrap; } +table.piechart tr td.col, table.barchart tr td.col, table.linechart tr td.col { border-bottom: 1px solid #555; border-right: 1px solid #555; } +table.fs90 tr td, table.fs90 tr th, div.fs90, pre.fs90, p.fs90 ,ul.fs90 {font-size: 0.9em; } +table.fs75 tr td, table.fs75 tr th, div.fs75, pre.fs75, p.fs75 ,ul.fs75 {font-size: 0.75em; } +table.fs66 tr td, table.fs66 tr th, div.fs66, pre.fs66, p.fs66 ,ul.fs66 {font-size: 0.66em; } +table.fs50 tr td, table.fs50 tr th, div.fs50, pre.fs50, p.fs50 ,ul.fs50 {font-size: 0.5em; } + +#soundmanager-debug {position:fixed; top:0px; right:0px; width:30em; height:20em; overflow:auto; border:1px solid red; padding:1em; margin:2em; font-family:"sans serif"; font-size: 12px;color: black; background-color:#f6f6f6; z-index: 100;} +#soundmanager-debug code {font-size: 11px;} \ No newline at end of file diff --git a/ui/scala_utf/print.css b/ui/scala_utf/print.css new file mode 100644 index 0000000..5affe5d --- /dev/null +++ b/ui/scala_utf/print.css @@ -0,0 +1,3 @@ +/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ .slide, ul, p {page-break-inside: avoid; visibility: visible !important;} h1 {page-break-after: avoid;} +img {page-break-inside: avoid; page-break-after: avoid;} +/*.slide {page-break-after: always;}*/ body {font-size: 12pt; background: white;} * {color: black;} #slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} #slide0 h3 {margin: 0; padding: 0;} #slide0 h4 {margin: 0 0 0.5em; padding: 0;} #slide0 {margin-bottom: 3em;} h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;} .extra {background: transparent !important;} div.extra, pre.extra, .example {font-size: 10pt; color: #333;} ul.extra a {font-weight: bold;} p.example {display: none;} #header {display: none;} #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} #footer h2, #controls {display: none;} /* The following rule keeps the layout stuff out of print. Remove at your own risk! */ .hide, .layout, .layout * {display: none !important;} \ No newline at end of file diff --git a/ui/scala_utf/s5-core.css b/ui/scala_utf/s5-core.css new file mode 100644 index 0000000..8ed9c1e --- /dev/null +++ b/ui/scala_utf/s5-core.css @@ -0,0 +1,8 @@ +/* Do not edit or override these styles! The system will likely break if you do. */ + +div#header, div#footer, div#controls, .slide {position: absolute;} +html>body div#header, html>body div#footer, html>body div#controls, html>body .slide {position: fixed;} +.handout, .notes, .hide {display: none;} +.layout {display: block;} +.slide, .hideme, .incremental {visibility: hidden;} +#slide0 {visibility: visible;} diff --git a/ui/scala_utf/slides.css b/ui/scala_utf/slides.css new file mode 100644 index 0000000..0786d7d --- /dev/null +++ b/ui/scala_utf/slides.css @@ -0,0 +1,3 @@ +@import url(s5-core.css); /* required to make the slide show run at all */ +@import url(framing.css); /* sets basic placement and size of slide components */ +@import url(pretty.css); /* stuff that makes the slides look better than blah */ \ No newline at end of file diff --git a/ui/scala_utf/slides.js b/ui/scala_utf/slides.js new file mode 100644 index 0000000..ef9f4c5 --- /dev/null +++ b/ui/scala_utf/slides.js @@ -0,0 +1,2665 @@ +// S5 1.3beta7 (18-Apr-2007) advanced version by C. Effenberger +// Please see http://s5.netzgesta.de/ for more information +// based on S5 v1.2a1 slides.js -- released into the Public Domain +// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information +// about all the wonderful and talented contributors to this code! +// audio extension: soundmanager2 is NOT Public Domain +// Please see http://www.schillmania.com/projects/soundmanager2/ for information + +var undef; +var slideCSS = ''; +var snum = 0; +var smax = 1; +var incpos = 0; +var number = undef; +var firstTime = 1; +var s5mode = true; +var helpmode = false; +var defaultView = 'slideshow'; //outline +var controlVis = 'visible'; + +// scalable images extension +var empx = 0; +var images = new Array(); +var canvas = new Array(); +var medias = new Array(); +var piecharts = new Array(); +var barcharts = new Array(); +var linecharts = new Array(); +// scalable images extension + +// transition extension +var tranSitions = false; +var fadeModus = false; +var fadeDuration = 500; +var incrDuration = 250; +var opac = 1; +var cid = ''; +var nid = ''; +var tid = ''; +var jl = ''; +// transition extension + +// autoplay extension +var autoMatic = false; +var playLoop = false; +var playPause = false; +var autoRun = false; +var playDelay = 5000; +var remainDer = 0; +var incrDelay = 0; +// autoplay extension + +// audio extension +var sound = new Array(); +var audioSupport = false; +var audioVolume = 100; +var audioError = false; +var swfUnloaded = true; +var bgSoundItem = 9999; +var curSoundID = -1; +// audio extension + +// panel extension +var highLight = "rgb(255, 204, 0)"; +// panel extension + +// canvas chart extension +var canvasSupport = false; +var ChartData = new Array(); +var colorSlice = new Array(); +var font = document.createElement("img"); +font.setAttribute("src", "ui/graphic_support/numeric.png"); +signs = { + '0': {sx: 0, sy: 0, sw: 48, sh: 64}, + '1': {sx: 48, sy: 0, sw: 48, sh: 64}, + '2': {sx: 96, sy: 0, sw: 48, sh: 64}, + '3': {sx: 144, sy: 0, sw: 48, sh: 64}, + '4': {sx: 192, sy: 0, sw: 48, sh: 64}, + '5': {sx: 240, sy: 0, sw: 48, sh: 64}, + '6': {sx: 288, sy: 0, sw: 48, sh: 64}, + '7': {sx: 336, sy: 0, sw: 48, sh: 64}, + '8': {sx: 384, sy: 0, sw: 48, sh: 64}, + '9': {sx: 432, sy: 0, sw: 48, sh: 64}, + '%': {sx: 480, sy: 0, sw: 48, sh: 64}, + '.': {sx: 528, sy: 0, sw: 24, sh: 64} +}; +var colorNames= new Array(); +colorNames["black"]="#000000"; colorNames["maroon"]="#800000"; colorNames["green"]="#008000"; colorNames["olive"]="#808000"; colorNames["navy"]="#000080"; colorNames["purple"]="#800080"; colorNames["teal"]="#008080"; colorNames["gray"]="#808080"; colorNames["silver"]="#C0C0C0"; colorNames["red"]="#FF0000"; colorNames["lime"]="#00FF00"; colorNames["yellow"]="#FFFF00"; colorNames["blue"]="#0000FF"; colorNames["fuchsia"]="#FF00FF"; colorNames["aqua"]="#00FFFF"; colorNames["white"]="#FFFFFF"; colorNames["aliceblue"]="#F0F8FF"; colorNames["antiquewhite"]="#FAEBD7"; colorNames["aquamarine"]="#7FFFD4"; colorNames["azure"]="#F0FFFF"; colorNames["beige"]="#F5F5DC"; colorNames["blueviolet"]="#8A2BE2"; colorNames["brown"]="#A52A2A"; colorNames["burlywood"]="#DEB887"; colorNames["cadetblue"]="#5F9EA0"; colorNames["chartreuse"]="#7FFF00"; colorNames["chocolate"]="#D2691E"; colorNames["coral"]="#FF7F50"; colorNames["cornflowerblue"]="#6495ED"; colorNames["cornsilk"]="#FFF8DC"; colorNames["crimson"]="#DC143C"; colorNames["darkblue"]="#00008B"; colorNames["darkcyan"]="#008B8B"; colorNames["darkgoldenrod"]="#B8860B"; colorNames["darkgray"]="#A9A9A9"; colorNames["darkgreen"]="#006400"; colorNames["darkkhaki"]="#BDB76B"; colorNames["darkmagenta"]="#8B008B"; colorNames["darkolivegreen"]="#556B2F"; colorNames["darkorange"]="#FF8C00"; colorNames["darkorchid"]="#9932CC"; colorNames["darkred"]="#8B0000"; colorNames["darksalmon"]="#E9967A"; colorNames["darkseagreen"]="#8FBC8F"; colorNames["darkslateblue"]="#483D8B"; colorNames["darkslategray"]="#2F4F4F"; colorNames["darkturquoise"]="#00CED1"; colorNames["darkviolet"]="#9400D3"; colorNames["deeppink"]="#FF1493"; colorNames["deepskyblue"]="#00BFFF"; colorNames["dimgray"]="#696969"; colorNames["dodgerblue"]="#1E90FF"; colorNames["firebrick"]="#B22222"; colorNames["floralwhite"]="#FFFAF0"; colorNames["forestgreen"]="#228B22"; colorNames["gainsboro"]="#DCDCDC"; colorNames["ghostwhite"]="#F8F8FF"; colorNames["gold"]="#FFD700"; colorNames["goldenrod"]="#DAA520"; colorNames["greenyellow"]="#ADFF2F"; colorNames["honeydew"]="#F0FFF0"; colorNames["hotpink"]="#FF69B4"; colorNames["indianred"]="#CD5C5C"; colorNames["indigo"]="#4B0082"; colorNames["ivory"]="#FFFFF0"; colorNames["khaki"]="#F0E68C"; colorNames["lavender"]="#E6E6FA"; colorNames["lavenderblush"]="#FFF0F5"; colorNames["lawngreen"]="#7CFC00"; colorNames["lemonchiffon"]="#FFFACD"; colorNames["lightblue"]="#ADD8E6"; colorNames["lightcoral"]="#F08080"; colorNames["lightcyan"]="#E0FFFF"; colorNames["lightgoldenrodyellow"]="#FAFAD2"; colorNames["lightgreen"]="#90EE90"; colorNames["lightgrey"]="#D3D3D3"; colorNames["lightpink"]="#FFB6C1"; colorNames["lightsalmon"]="#FFA07A"; colorNames["lightseagreen"]="#20B2AA"; colorNames["lightskyblue"]="#87CEFA"; colorNames["lightslategray"]="#778899"; colorNames["lightsteelblue"]="#B0C4DE"; colorNames["lightyellow"]="#FFFFE0"; colorNames["limegreen"]="#32CD32"; colorNames["linen"]="#FAF0E6"; colorNames["mediumaquamarine"]="#66CDAA"; colorNames["mediumblue"]="#0000CD"; colorNames["mediumorchid"]="#BA55D3"; colorNames["ediumpurple"]="#9370D"; colorNames["mediumseagreen"]="#3CB371"; colorNames["mediumslateblue"]="#7B68EE"; colorNames["mediumspringgreen"]="#00FA9A"; colorNames["mediumturquoise"]="#48D1CC"; colorNames["mediumvioletred"]="#C71585"; colorNames["midnightblue"]="#191970"; colorNames["mintcream"]="#F5FFFA"; colorNames["mistyrose"]="#FFE4E1"; colorNames["moccasin"]="#FFE4B5"; colorNames["navajowhite"]="#FFDEAD"; colorNames["oldlace"]="#FDF5E6"; colorNames["olivedrab"]="#6B8E23"; colorNames["orange"]="#FFA500"; colorNames["orangered"]="#FF4500"; colorNames["orchid"]="#DA70D6"; colorNames["palegoldenrod"]="#EEE8AA"; colorNames["palegreen"]="#98FB98"; colorNames["paleturquoise"]="#AFEEEE"; colorNames["palevioletred"]="#DB7093"; colorNames["papayawhip"]="#FFEFD5"; colorNames["peachpuff"]="#FFDAB9"; colorNames["peru"]="#CD853F"; colorNames["pink"]="#FFC0CB"; colorNames["plum"]="#DDA0DD"; colorNames["powderblue"]="#B0E0E6"; colorNames["rosybrown"]="#BC8F8F"; colorNames["royalblue"]="#4169E1"; colorNames["saddlebrown"]="#8B4513"; colorNames["salmon"]="#FA8072"; colorNames["sandybrown"]="#F4A460"; colorNames["seagreen"]="#2E8B57"; colorNames["seashell"]="#FFF5EE"; colorNames["sienna"]="#A0522D"; colorNames["skyblue"]="#87CEEB"; colorNames["slateblue"]="#6A5ACD"; colorNames["slategray"]="#708090"; colorNames["snow"]="#FFFAFA"; colorNames["springgreen"]="#00FF7F"; colorNames["steelblue"]="#4682B4"; colorNames["tan"]="#D2B48C"; colorNames["thistle"]="#D8BFD8"; colorNames["tomato"]="#FF6347"; colorNames["turquoise"]="#40E0D0"; colorNames["violet"]="#EE82EE"; colorNames["wheat"]="#F5DEB3"; colorNames["whitesmoke"]="#F5F5F5"; colorNames["yellowgreen"]="#9ACD32"; +var canvas_bgcolor = ""; +var canvas_width = 200; +var canvas_height = 200; +var canvas_noshade = 0; +var canvas_nofill = 0; +var canvas_noshadow = 0; +var canvas_htmltext = 0; +var canvas_imgtext = 0; +var canvas_notext = 0; +// canvas chart extension + +var s5NotesWindow; +var s5NotesWindowLoaded = false; +var previousSlide = 0; +var presentationStart = new Date(); +var slideStart = new Date(); + +var countdown = { + timer: 0, + state: 'pause', + start: new Date(), + end: 0, + remaining: 0 +}; + +var isIE = navigator.appName == 'Microsoft Internet Explorer' && navigator.userAgent.indexOf('Opera') < 1 ? 1 : 0; +if(isIE) var notIE7 = parseInt(navigator.appVersion) < 7 ? 1 : 0; +var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; +var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; +var isS2 = navigator.userAgent.indexOf('Safari') >= 2 ? 1 : 0; + +function hasClass(object, className) { + if (!object.className) return false; + return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); +} + +function hasValue(object, value) { + if (!object) return false; + return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); +} + +function removeClass(object,className) { + if (!object || !hasClass(object,className)) return; + object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); +} + +function addClass(object,className) { + if (!object || hasClass(object, className)) return; + if (object.className) { + object.className += ' '+className; + } else { + object.className = className; + } +} + +function changeClass(object,className) { + if (!object) return; + object.firstChild.className = className; +} + +function GetElementsWithClassName(elementName,className) { + var allElements = document.getElementsByTagName(elementName); + var elemColl = new Array(); + for (var i = 0; i< allElements.length; i++) { + if (hasClass(allElements[i], className)) { + elemColl[elemColl.length] = allElements[i]; + } + } + return elemColl; +} + +function isParentOrSelf(element, id) { + if (element == null || element.nodeName=='BODY') return false; + else if (element.id == id) return true; + else return isParentOrSelf(element.parentNode, id); +} + +function nodeValue(node) { + var result = ""; + if (node.nodeType == 1) { + var children = node.childNodes; + for (var i = 0; i < children.length; ++i) { + result += nodeValue(children[i]); + } + } + else if (node.nodeType == 3) { + result = node.nodeValue; + } + return(result); +} + +function slideLabel() { + var slideColl = GetElementsWithClassName('*','slide'); + var list = document.getElementById('jumplist'); + smax = slideColl.length; + for (var n = 0; n < smax; n++) { + var obj = slideColl[n]; + var did = 'slide' + n.toString(); + obj.setAttribute('id',did); + var otext = ''; + var menu = obj.firstChild; + if (!menu) continue; // to cope with empty slides + while (menu && menu.nodeType == 3) { + menu = menu.nextSibling; + } + if (!menu) continue; // to cope with slides with only text nodes + var menunodes = menu.childNodes; + for (var o = 0; o < menunodes.length; o++) { + otext += nodeValue(menunodes[o]); + } + list.options[list.length] = new Option(n + ' : ' + otext, n); + } +} + +function currentSlide() { + var cs, at, fd, ss; + if (document.getElementById) { + cs = document.getElementById('currentSlide'); + } else { + cs = document.currentSlide; + } + fd = fadeModus?"F":"–"; + ss = audioSupport?"S":"–"; + at = (autoMatic?(playPause?"||":(playLoop?">0":">|")):"––"); + cs.innerHTML = '