--- /dev/null
+;; This buffer is for notes you don't want to save, and for Lisp evaluation.
+;; If you want to create a file, visit that file with C-x C-f,
+;; then enter the text in that file's own buffer.
+
+CVS
+*.gz
+blib
+*.tar
+old
+*~
+
--- /dev/null
+package CMS::Simple ;
+
+use warnings ;
+use strict ;
+
+use Carp ;
+use Data::Dumper ;
+
+use CMS::Simple::Parse ;
+use Template::Simple ;
+use File::Slurp ;
+
+
+our $VERSION = '0.01' ;
+
+
+my %defaults = (
+
+###
+# use File::Path and other modules to make paths clean and portable
+###
+
+ working_dir => '.',
+ content_paths => ['content'],
+ templates_dir => 'templates',
+ output_dir => 'output',
+
+# this is for timestamps
+
+ published_dir => 'published',
+
+ template_args => {},
+) ;
+
+my %parsers = (
+
+ cont => \&CMS::Simple::Parse::parse_content,
+ csv => \&CMS::Simple::Parse::parse_csv,
+ pl => \&_parse_perl,
+# yaml => \&parse_yaml,
+) ;
+
+sub new {
+
+ my( $class, $args ) = @_ ;
+
+ my $self = bless { %defaults, %{$args} }, $class ;
+
+ $self->_invert_filter_tags() ;
+
+ $self->_make_dirs() ;
+
+# rename/clean dirs??
+
+ $self->_load_content() ;
+
+####
+# add template path arg
+
+ $self->{tmpl_obj} = Template::Simple->new( %{$self->{template_args}} ) ;
+
+ return $self ;
+}
+
+
+sub _load_content {
+
+ my( $self ) = @_ ;
+
+ my $contents = $self->{contents} ;
+
+#print Dumper $contents ;
+
+ while( my( $name, $file ) = each %{$contents} ) {
+
+######
+# ADD BETTER DIRECTORY STUFF
+######
+
+ my $file_path = "$self->{content_paths}[0]/$file" ;
+
+ my $content_text = read_file( $file_path ) ;
+
+ my ($suffix) = $file_path =~ /\.(\w+)$/ ;
+
+ my $parser = $parsers{ $suffix } ;
+
+ $parser or die "unknown suffix '$suffix'" ;
+
+ my $parsed = $parser->( $content_text ) ;
+
+ $contents->{$name} = {
+
+ file => $file,
+ text => $content_text,
+ parsed => $parsed,
+ } ;
+ }
+#print Dumper $contents ;
+
+}
+
+sub build_all_pages {
+
+ my( $self ) = @_ ;
+
+ foreach my $page_name ( keys %{$self->{pages}} ) {
+
+ $self->build_page( $page_name ) ;
+ }
+}
+
+
+sub build_page {
+
+ my( $self, $page_name ) = @_ ;
+
+#print "BUILD $page_name\n" ;
+
+ my $page = $self->{pages}{$page_name} ;
+
+ return if $page->{skip} ;
+
+ $page->{name} = $page_name ;
+
+ $self->_get_page_content( $page ) ;
+
+#print Dumper $page ;
+
+ $self->_filter_page_content( $page ) ;
+
+
+ $self->_render_page( $page ) ;
+#print ${$page->{rendered}} ;
+
+ $self->_output_page( $page ) ;
+}
+
+sub _get_page_content {
+
+ my( $self, $page ) = @_ ;
+
+#######
+# FIX so a page contents can override values and not just whole maps
+# ADD contents maps to have multilevel keys
+#######
+
+ my $all_contents = $self->{contents} ;
+
+ my $page_contents = $page->{contents} || {} ;
+
+# loop over the default (common) and page specific content maps
+
+ foreach my $contents_map (
+ $self->{default_contents_map},
+ $page->{contents_map} ) {
+
+#print "MAP ", Dumper $contents_map ;
+
+ while( my( $name, $location ) = each %{$contents_map} ) {
+
+# get the contents for this content name
+
+ my $contents = $all_contents->{$name}{parsed} ;
+
+ $self->_add_page_contents(
+ $page_contents,
+ $location,
+ $contents
+ ) ;
+ }
+ }
+
+ print Dumper $page_contents if $page->{dump} ;
+
+ $page->{contents} = $page_contents ;
+}
+
+sub _add_page_contents {
+
+ my( $self, $page_contents, $location, $contents ) = @_ ;
+
+#########
+# this needs to handle multilevel content location
+#########
+
+# if we have a location, just store the contents there
+
+ if ( $location ) {
+
+ my @loc_keys = split /:/, $location ;
+#print "LOC @loc_keys\n" ;
+
+ my $loc_ref = \$page_contents->{ shift @loc_keys } ;
+
+#print "LOC $loc_ref\n" ;
+
+# descend into the page contents based on the location keys
+
+ $loc_ref = \${$loc_ref}->{$_} for @loc_keys ;
+
+ ${$loc_ref} = deep_copy( $contents ) ;
+
+ return ;
+ }
+
+# no location so store all the top level contents in the top level of
+# the page
+
+ @{$page_contents}{keys %{$contents}} = values %{$contents} ;
+}
+
+sub _filter_page_content {
+
+ my( $self, $page ) = @_ ;
+
+# NOTE content must be a hash at the top
+
+ $self->_filter_content_hash( $page->{contents} ) ;
+
+#print Dumper $page->{contents} ;
+}
+
+sub _filter_content_hash {
+
+ my( $self, $href, $path ) = @_ ;
+
+ while( my( $tag, $val ) = each %{$href} ) {
+
+ my @new_val =
+ $self->_filter_content_tag( $tag, $val, $path ) ;
+
+ next unless @new_val ;
+ $href->{$tag} = $new_val[0] ;
+ }
+}
+
+sub _filter_content_array {
+
+ my( $self, $tag, $aref, $path ) = @_ ;
+
+#print "ARRAY: ", Dumper \$tag, $aref ;
+
+ my @new_vals ;
+
+ foreach my $val ( @{$aref} ) {
+
+ push @new_vals,
+ $self->_filter_content_tag( $tag, $val, $path ) ;
+ }
+
+ @{$aref} = @new_vals ;
+
+#print Dumper $aref ;
+
+}
+
+sub _filter_content_tag {
+
+ my( $self, $tag, $val, $path ) = @_ ;
+
+ my $ref_type = ref $val ;
+
+ if ( $ref_type eq 'HASH' ) {
+
+ $self->_filter_content_hash( $val, $path ) ;
+ return $val ;
+ }
+
+ if ( $ref_type eq 'ARRAY' ) {
+
+ $self->_filter_content_array( $tag, $val, $path ) ;
+ return $val ;
+ }
+
+ my @new_val = $self->_filter_content_value( $tag, $val, $path ) ;
+
+ return unless @new_val ;
+
+ $val = $new_val[0] ;
+
+ $self->_filter_content_tag( $tag, $val, $path ) if ref $val ;
+
+ return $val ;
+}
+
+sub _filter_content_value {
+
+ my( $self, $tag, $val, $path ) = @_ ;
+
+ my $filters = $self->{tag_to_filters}{$tag} ;
+
+ return unless $filters ;
+
+ my @new_val ;
+
+ foreach my $filter ( @{$filters} ) {
+
+#print "FILTER $filter->{name}\n" ;
+
+#print "TAG $tag [$val]\n" unless defined $val;
+
+$val = '' unless defined $val || $tag ne 'text' ;
+
+ @new_val = $filter->{code}->( $tag, $val, $path ) ;
+
+ next unless @new_val ;
+
+ $val = $new_val[0] ;
+ }
+
+#print "TAG: $tag: ", Dumper \$val ;
+
+# return if nothing was changed
+
+ return unless @new_val ;
+
+ return $val ;
+}
+
+sub _render_page {
+
+ my( $self, $page ) = @_ ;
+
+ my $tmpl_obj = $self->{tmpl_obj} ;
+
+# NOTE: using internal method. will fix template::simple to expose it
+
+ my $tmpl_name = $page->{template} || $self->{default_template} ;
+
+ my $template = $tmpl_obj->_get_template( $tmpl_name ) ;
+
+#print Dumper $page->{contents} ;
+
+ my $rendered = $tmpl_obj->render( $template, $page->{contents} ) ;
+
+ $page->{rendered} = $rendered ;
+}
+
+
+
+sub _output_page {
+
+ my( $self, $page ) = @_ ;
+
+##########
+# use file::path stuff to make this portable
+##########
+
+ my $output_path =
+ "$self->{'output_dir'}/$page->{name}$self->{'output_suffix'}" ;
+
+ $page->{'output_path'} = $output_path ;
+
+ write_file( $output_path, $page->{rendered} ) ;
+}
+
+sub publish_output {
+
+ my( $self ) = @_ ;
+
+ while ( my($name, $page) = each %{$self->{'pages'}} ) {
+
+ my $output_file = $self->{'pages'}{$name}{'output_file'} ;
+
+ my $remote_host = $self->{'remote_host'} ;
+ my $remote_user = $self->{'remote_user'} ;
+ my $remote_directory = $self->{'remote_directory'} ;
+
+ # Strip trailing slash if there is one, then replace it...
+ # so that dir always ends in slash whether or not one is passed:
+ # (Note: not portable outside Linux/unix!)
+
+ $remote_directory =~ s/^(.*)\/$/$1/ ;
+
+ my $scp = Net::SCP->new() ;
+
+ die "Unable to construct remote destination" unless
+ ( $remote_host && $remote_user && $remote_directory ) ;
+
+ # Construct remote destination from class attributes:
+ my $destination = "${remote_user}\@${remote_host}:${remote_directory}/" ;
+
+ # Use 'iscp' for interactive scp:
+ $scp->iscp( $output_file, $destination ) or die $scp->{errstr};
+
+ }
+}
+
+sub _parse_perl {
+
+ my( $text ) = @_ ;
+
+ return eval $text ;
+}
+
+
+# change
+sub deep_copy {
+
+ my( $val ) = @_ ;
+
+ return $val unless ref $val ;
+
+ return [ map deep_copy( $_ ), @{$val} ] if ref $val eq 'ARRAY' ;
+
+ return { map { $_, deep_copy( $val->{$_} ) } keys %{$val} }
+ if ref $val eq 'HASH' ;
+
+ die "$val is not a scalar, ARRAY or HASH" ;
+}
+
+
+sub _make_dirs {
+
+ my( $self ) = @_ ;
+
+############
+# use File::Path to make deep dirs
+###########
+
+ mkdir( $self->{output_dir} ) ;
+ mkdir( $self->{published_dir} ) ;
+}
+
+sub _invert_filter_tags {
+
+ my( $self) = @_ ;
+
+ my %tag_to_filters ;
+
+ foreach my $filter ( @{$self->{filters}} ) {
+
+ push @{$tag_to_filters{$_}}, $filter for @{$filter->{tags}} ;
+ }
+
+#print Dumper \%tag_to_filters ;
+
+ $self->{tag_to_filters} = \%tag_to_filters ;
+}
+
+1 ;
--- /dev/null
+
+package CMS::Simple::Filter::Markup ;
+
+use strict ;
+use warnings ;
+
+my %markup_to_code = (
+
+ l => \&make_link,
+ link => \&make_link,
+ email => \&make_email,
+ image => \&make_image,
+ image_link => \&make_image_link,
+ ilink => \&make_image_link,
+ nbsp => sub { ' ' },
+ em_dash => sub { '—' },
+ eacute => sub { 'é' },
+ copy => sub { '©' },
+ p => sub { '<p>' },
+ br => sub { '<br/>' },
+ gmap => \&google_map,
+) ;
+
+sub filter_markup {
+
+ my( $tag, $text ) = @_ ;
+
+#print "TEXT $text\n" ;
+
+ return unless $text =~
+ s{(?<!\\)\[([a-z_]+)(?:\s+([^]]+)\s*)?\]}
+ {replace_markup(lc $1, $2)}gie
+ ||
+ $text =~ s{\\\[}{[}g ;
+
+ return $text ;
+}
+
+sub replace_markup {
+
+ my( $key, $text ) = @_ ;
+
+#print "KEY $key [$text]\n" ;
+
+ my $code = $markup_to_code{ $key } ;
+
+ $code or die "unknown markup key '$key'" ;
+
+ return $code->($text) ;
+}
+
+sub make_link {
+
+ my( $text ) = @_ ;
+
+ my( $url, $url_text ) = split /\|/, $text ;
+
+ $url_text ||= $url ;
+
+ return qq{<A href="$url">$url_text</A>} ;
+}
+
+sub google_map {
+
+ my( $text ) = @_ ;
+
+ ( my $url_text = $text ) =~ tr/ \t\n\r/+/s ;
+
+ return
+qq{<A href="http://maps.google.com/maps?f=q&hl=en&q=$url_text">$text</A>} ;
+}
+
+sub make_email {
+
+ my( $text ) = @_ ;
+
+ my( $user, $domain ) = split /\@/, $text ;
+
+ return <<EMAIL ;
+<script>
+document.write('<a href="mailto:$user' + '\@' +
+ '$domain">$user AT $domain</a>')
+</script>
+<noscript>
+$user AT $domain
+</noscript>
+EMAIL
+
+}
+
+sub make_image_link {
+
+ my( $text ) = @_ ;
+
+ my( $url, $image_url ) = split /\|/, $text ;
+
+ return qq{<A href="$url"><IMG src="$image_url"></A>} ;
+}
+
+sub make_image {
+
+ my( $text ) = @_ ;
+
+ return qq{<IMG src="$text">} ;
+}
--- /dev/null
+package CMS::Simple::Parse ;
+
+
+use strict ;
+use warnings ;
+
+use Data::Dumper ;
+
+sub parse_content {
+
+ my( $text ) = @_ ;
+
+#print $text ;
+
+ my $lines = [ $text =~ m{(.*?$/)}sg ] ;
+
+ return parse_lines( {}, $lines ) ;
+}
+
+sub parse_lines {
+
+ my( $curr_hash, $lines ) = @_ ;
+
+ my $content = '' ;
+ my $scalar_tag ;
+
+ while( my $line = shift @{$lines} ) {
+
+# skip blank lines
+
+# next unless $line =~ /\S/ ;
+
+# look for tag:: lines and parse them out.
+# ignore leading white space, grad for a word followed by 1 or 2 :'s.
+# also grab any optional content following the tag
+
+ unless( $line =~ /^\s*(\w+)(::?)\s+(.*)\z/s ) {
+
+# no tag found so just add this line to the current scalar content
+
+ $content .= $line ;
+ next ;
+ }
+
+ my $tag = $1 ;
+
+# save any existing scalar as we found a new tag entry
+
+ if ( $scalar_tag ) {
+ _store_value( $curr_hash, $scalar_tag, $content ) ;
+ $scalar_tag = '' ;
+ }
+
+# see we at the end of a structure. if so, return what we have parsed
+
+ return $curr_hash if $tag eq 'END' ;
+
+# see if this a start of a structure. if so, recursively parse and
+# store it any content on the structure tag line is ignored. its value
+# is always a hash ref of the structure data.
+
+ if( $2 eq '::' ) {
+
+ my $new_val = parse_lines( {}, $lines ) ;
+ _store_value( $curr_hash, $tag, $new_val ) ;
+ next ;
+ }
+
+# now it must be a new scalar entry. save any new content on this line
+
+ $scalar_tag = $tag ;
+ $content = $3 ;
+ }
+
+#print "TAG $scalar_tag\n" ;
+ _store_value( $curr_hash, $scalar_tag, $content ) if $scalar_tag ;
+
+#print Dumper $curr_hash ;
+
+ return $curr_hash ;
+}
+
+sub _store_value {
+
+ my( $curr_ref, $tag, $val ) = @_ ;
+
+# NOTE: always chomping scalar content
+
+ chomp $val unless ref $val ;
+
+ my $curr_val = $curr_ref->{$tag} ;
+
+
+ unless( defined $curr_val ) {
+
+#print "NEW TAG $tag [$val]\n" ;
+
+ $curr_ref->{$tag} = $val ;
+ return ;
+ }
+
+ if ( ref $curr_val eq 'ARRAY' ) {
+
+#print "PUSH TAG $tag [$val]\n" ;
+
+ push( @{$curr_val}, $val ) ;
+
+ return ;
+ }
+
+#print "ARRAY TAG $tag [$val]\n" ;
+ $curr_ref->{$tag} = [ $curr_val, $val ] ;
+
+}
+
+# cheapo csv tab file parser
+
+sub parse_csv {
+
+ my( $text ) = @_ ;
+
+ my @lines = split m{(?<=$/)}, $text ;
+
+ chomp @lines ;
+
+ return [ map [ split /\t/ ], @lines ] ;
+}
+
+1 ;
--- /dev/null
+#!/usr/local/bin/perl
+
+use strict ;
+use warnings ;
+
+use CMS::Simple ;
+use Data::Dumper ;
+
+my $content = CMS::Simple::Parse::parse_content( <<CONT ) ;
+foo: bar
+foo::
+ baz: jfdjdfj
+END:
+foo: more
+foo:: more2
+ aaa: 4
+END:
+CONT
+
+print Dumper $content ;
--- /dev/null
+#!/usr/local/bin/perl
+
+use strict ;
+use warnings ;
+
+use CMS::Simple ;
+use CMS::Simple::Filter::Markup ;
+
+use HTML::Entities;
+use File::Slurp ;
+use Data::Dumper ;
+
+
+my $cont_file = shift @ARGV || 'compshare.cont' ;
+
+
+my @filters = (
+# {
+# name => 'html_escape',
+# tags => [ qw( code ) ],
+# code => \&html_escape,
+# },
+ {
+ name => 'markup',
+ tags => [ qw( text email image ) ],
+ code => \&CMS::Simple::Filter::Markup::filter_markup,
+ },
+) ;
+
+
+my $conf = {
+
+ output_suffix => '.html',
+
+ contents => {
+
+# page_header => 'header.cont',
+# page_footer => 'footer.cont',
+# book => 'compshare.cont',
+ },
+
+ filters => \@filters,
+
+ default_template => 'base_page',
+
+# this maps loaded contents to location in this page's data tree.
+# the location will be multilevel later on
+
+# the page key name is the base name for the output file
+
+ pages => {
+
+ chapters => {
+ template => 'chapters',
+ },
+
+ index => {
+
+ template => 'index',
+ },
+ },
+} ;
+
+
+load_book_content( $conf, $cont_file ) ;
+
+#print Dumper $conf ;
+#print Dumper $conf->{pages} ;
+
+my $cms = CMS::Simple->new( $conf ) ;
+
+$cms->build_all_pages() ;
+
+exit ;
+
+
+sub load_book_content {
+
+ my( $conf, $cont_file ) = @_ ;
+
+ my $cont_text = read_file( "contents/$cont_file" ) ;
+ my $content = CMS::Simple::Parse::parse_content( $cont_text ) ;
+
+ process_book_content( $conf, $content ) ;
+
+#print Dumper $content ;
+
+}
+
+sub process_book_content {
+
+ my( $conf, $book_cont ) = @_ ;
+
+ my $book_title = $book_cont->{book}{title} ;
+
+ my $chap_conts = $book_cont->{chapter} ;
+ $chap_conts = [ $chap_conts ] unless ref $chap_conts eq 'ARRAY' ;
+
+ my $chap_num = '01' ;
+
+ foreach my $chap_cont ( @{$chap_conts} ) {
+
+ $chap_cont->{number} = $chap_num++ ;
+ $chap_cont->{book_title} = $book_title ;
+
+ process_chap_content( $conf, $chap_cont ) ;
+ }
+
+ process_index_page( $conf, $chap_conts ) ;
+
+#print Dumper $conf ;
+
+}
+
+sub process_index_page {
+
+ my( $conf, $chap_conts ) = @_ ;
+
+ my $index_cont = $conf->{pages}{index}{contents} ||= {} ;
+
+ foreach my $chap_cont ( @{$chap_conts} ) {
+
+ my $page_titles = $chap_cont->{page_title} ;
+
+ push( @{$index_cont->{chapter}}, {
+
+ chap_title => $chap_cont->{title},
+ chap_num => $chap_cont->{number},
+ page => $page_titles,
+ } ) ;
+ }
+
+print Dumper $index_cont ;
+
+}
+
+
+
+sub process_chap_content {
+
+ my( $conf, $chap_data ) = @_ ;
+
+ my $chap_title = $chap_data->{title} ;
+
+ my $chap_page_cont = $conf->{pages}{chapters}{contents} ||= {} ;
+
+ push( @{$chap_page_cont->{chap_title}}, {
+ number => $chap_data->{number},
+ title => $chap_title
+ } ) ;
+
+ my $page_conts = $chap_data->{page} ;
+ $page_conts = [ $page_conts ] unless ref $page_conts eq 'ARRAY' ;
+
+ my $page_num = '01' ;
+
+ foreach my $page_cont ( @{$page_conts} ) {
+
+ $page_cont->{number} = $page_num++ ;
+
+#print Dumper $page_cont ;
+
+ process_page_content( $conf, $chap_data, $page_cont ) ;
+ }
+}
+
+
+sub process_page_content {
+
+ my( $conf, $chap_data, $page_data ) = @_ ;
+
+ my $chap_title = $chap_data->{title} ;
+ my $page_title = $page_data->{title} ;
+
+
+#print "TITLE $page_title\n" ;
+
+ my $chap_num = $chap_data->{number} ;
+ my $page_num = $page_data->{number} ;
+
+ my $page_name = "page-$chap_num$page_num" ;
+ my $page_url = "$page_name.html" ;
+
+ push( @{$chap_data->{page_title}}, {
+ number => $page_num,
+ title => $page_title,
+ page_link => $page_url,
+ } ) ;
+
+ my $page = {
+
+ name => $page_name,
+ template => 'page',
+ } ;
+
+ my $header_cont = {
+
+ header_title => {
+ text => $page_title,
+ },
+
+ book_title => $chap_data->{book_title} || 'FOO',
+ index_link => {
+ text => 'index.html',
+ },
+ chap_link => 'chapters.html',
+ } ;
+
+ if ( $page_num > 1 ) {
+
+ my $prev_page_num = sprintf "%02d", $page_num - 1 ;
+ $header_cont->{prev_link} = {
+ prev_page => "page-$chap_num$prev_page_num.html",
+ } ;
+ }
+
+ if ( $page_num < 50 ) {
+
+ my $next_page_num = sprintf "%02d", $page_num + 1 ;
+ $header_cont->{next_link} = {
+ next_page => "page-$chap_num$next_page_num.html",
+ } ;
+ }
+
+
+#print Dumper $page_data ;
+
+ my $items = process_page_items( $page_data ) ;
+
+ my $page_cont = {
+ page => {
+ item => $items,
+ },
+ } ;
+
+ set_page_header_data( $page_cont, $header_cont ) ;
+
+ $page->{contents} = $page_cont ;
+#print Dumper $page_cont ;
+
+ $conf->{pages}{$page_name} = $page ;
+
+}
+
+sub process_page_items {
+
+ my( $page_data ) = @_ ;
+
+ my $items = $page_data->{item} ;
+ $items = [ $items ] unless ref $items eq 'ARRAY' ;
+
+ foreach my $item ( @{$items} ) {
+
+
+ if ( ref $item ) {
+
+ $item->{title} = {
+ text => $item->{title},
+ } ;
+ }
+ else {
+
+ $item = {
+ title => {
+ text => $item,
+ },
+ } ;
+ }
+
+ process_subitems( $item ) ;
+ process_code( $item ) ;
+ }
+
+#print Dumper $items ;
+
+ return $items ;
+}
+
+sub process_subitems {
+
+ my( $item ) = @_ ;
+
+ my $subitems = $item->{subitem} ;
+
+ return unless $subitems ;
+
+ $subitems = [ $subitems ] unless ref $subitems eq 'ARRAY' ;
+
+ $item->{subitems} = [
+ map {
+
+ subitem => {
+ text => $_
+ }
+ }, @{$subitems}
+ ] ;
+}
+
+sub process_code {
+
+ my( $item ) = @_ ;
+
+ my $code = $item->{code} ;
+
+ return unless $code ;
+
+# append a newline if needed - scalar content loses a trailing newline
+
+#print "CODE: [$code]\n" ;
+
+ $code =~ s/(?<!\n)\z/\n/ ;
+ $code =~ s/^/\n\n/ ;
+
+ $code = encode_entities( $code, '<>&"') ;
+
+ $item->{code} = {
+ text => $code
+ } ;
+}
+
+
+
+sub set_page_header_data {
+
+ my( $page_cont, $data ) = @_ ;
+
+ for my $header ( qw( html_header page_header page_footer ) ) {
+
+ @{$page_cont->{$header}}{keys %{$data}} = values %{$data} ;
+ }
+}
+
--- /dev/null
+#!/usr/local/bin/perl
+
+use strict ;
+use warnings ;
+
+use Data::Dumper ;
+
+use Template::Simple ;
+use CMS::Simple::Parse ;
+use File::Slurp ;
+
+
+
+my $cont_file = shift || 'slides.cont' ;
+
+my $cont_text = read_file( $cont_file ) ;
+
+my $content = CMS::Simple::Parse::parse_content( $cont_text ) ;
+
+print Dumper $content ;
--- /dev/null
+#!/usr/local/bin/perl -w
+
+use strict ;
+
+use Carp ;
+use YAML ;
+
+my @slides ;
+
+my %book_values ;
+my ( $chap_title, $chap_abbrev ) ;
+
+my $page_num = 0 ; # number as read in
+my $slide_num = 0 ; # slide within a chapter
+my $chap_num = 0 ;
+
+my %part2sub = (
+
+ 'book' => \&process_book,
+ 'title' => \&process_title,
+ 'chapter' => \&process_chapter,
+ 'code' => \&process_code,
+ 'code2' => \&process_code2,
+ '*' => \&process_bullet,
+ '**' => \&process_bullet2,
+ 'haiku' => \&process_haiku,
+ 'html' => \&process_html,
+) ;
+
+
+read_parse_pages() ;
+
+make_index() ;
+
+make_slides() ;
+
+#print Dump \@slides ;
+
+exit ;
+
+sub read_parse_pages {
+
+ local( $/ ) = "PAGE_END\n" ;
+
+ while ( my $page = <> ) {
+
+ chomp( $page ) ;
+
+ next unless $page =~ /\S/ ;
+
+ push @slides, parse_page( $page ) ;
+ }
+
+ $book_values{'TOTAL_PAGES'} = $page_num ;
+}
+
+sub parse_page {
+
+ my ( $page_text ) = @_ ;
+
+ my $slide = {
+ 'PAGE_NUM' => ++$page_num,
+ 'SLIDE_NUM' => ++$slide_num,
+ 'CHAP_NUM' => $chap_num,
+ } ;
+
+ foreach my $part ( split( /(?=^(?:\w+|\*+|):)/m, $page_text ) ) {
+
+ next unless $part =~ /\S/ ;
+
+ my ( $part_type, $part_body ) = split /:/, $part, 2 ;
+
+ my $part_sub = $part2sub{ lc $part_type } or die
+ "unknown slide part '$part_type'\n$page_text" ;
+
+ $part_sub->( $slide, $part_body ) ;
+ }
+
+ return $slide ;
+}
+
+
+sub process_book {
+
+ my( $slide, $book_text ) = @_ ;
+
+ $book_values{'BOOK_NAME'} = $book_text ;
+}
+
+sub process_chapter {
+
+ my( $slide, $chapter_text ) = @_ ;
+
+ ( $chap_title, $chap_abbrev ) = split( /\n/, $chapter_text ) ;
+
+ $chap_title =~ tr/\n / /s ;
+ $slide->{'CHAPTER'} = $chap_title ;
+
+ if ( $chap_abbrev ) {
+ $chap_abbrev =~ tr/\n / /s ;
+ $slide->{'CHAP_ABBREV'} = $chap_abbrev ;
+ }
+
+ $chap_num++ ;
+ $slide_num = 1 ;
+ $slide->{'SLIDE_NUM'} = $slide_num ;
+ $slide->{'CHAP_NUM'} = $chap_num ;
+}
+
+sub process_title {
+
+ my( $slide, $title_text ) = @_ ;
+
+ $title_text =~ tr/\n / /s ;
+
+ $slide->{'TITLE'} = $title_text ;
+
+ $slide->{'CHAPTER'} = $chap_title ;
+ $slide->{'CHAP_ABBREV'} = $chap_abbrev ;
+}
+
+sub process_bullet {
+
+ my( $slide, $bullet_text ) = @_ ;
+
+ my ( $bullet, @paras ) = split /\n{2,}/, $bullet_text ;
+# escape_entities( $_ ) for $bullet, @paras;
+ escape_entities( $_ ) for @paras;
+
+ push( @{$slide->{'html_parts'}},
+ apply_template( 'bullet', { 'TEXT' => $bullet } ),
+ map apply_template( 'para', { 'TEXT' => $_ } ), @paras ) ;
+}
+
+sub process_bullet2 {
+
+ my( $slide, $bullet_text ) = @_ ;
+
+ my ( $bullet, @paras ) = split /\n{2,}/, $bullet_text ;
+# escape_entities( $_ ) for $bullet, @paras;
+ escape_entities( $_ ) for @paras;
+
+ push( @{$slide->{'html_parts'}}, "<UL>\n",
+ apply_template( 'bullet2', { 'TEXT' => $bullet } ),
+ map( apply_template( 'para', { 'TEXT' => $_ } ), @paras ),
+ "</UL>\n",
+ ) ;
+}
+
+sub process_code {
+
+ my( $slide, $code_text ) = @_ ;
+
+ $code_text =~ s/^\n// ;
+ escape_entities( $code_text ) ;
+
+ $code_text =~ s/<blue>/<font color="#0000ff">/gi ;
+
+ push( @{$slide->{'html_parts'}},
+ apply_template( 'code', { 'TEXT' => $code_text } ) ) ;
+}
+
+# sub process_code2 {
+
+# my( $slide, $code_text ) = @_ ;
+
+# $code_text =~ s/^\n// ;
+# escape_entities( $code_text ) ;
+
+# push( @{$slide->{'html_parts'}},
+# apply_template( 'code2', { 'TEXT' => $code_text } ) ) ;
+# }
+
+sub escape_entities {
+
+print caller() if $_[0] =~ /IMG/ ;
+
+ $_[0] =~ s/&/&/g ;
+ $_[0] =~ s/</</g ;
+ $_[0] =~ s/>/>/g ;
+}
+
+sub process_haiku {
+
+ my( $slide, $haiku_text ) = @_ ;
+
+ $haiku_text =~ tr/\n / /s ;
+
+ my @lines = split m{:}, $haiku_text ;
+
+ push( @{$slide->{'html_parts'}},
+ apply_template(
+ 'haiku',
+ { LINE1 => $lines[0],
+ LINE2 => $lines[1],
+ LINE3 => $lines[2] }
+ )
+ ) ;
+}
+
+sub process_html {
+
+ my( $slide, $html_text ) = @_ ;
+
+ push( @{$slide->{'html_parts'}}, $html_text ) ;
+}
+
+sub make_slides {
+
+ foreach my $slide ( @slides ) {
+
+ my $page_num = $slide->{'PAGE_NUM'} ;
+
+ if ( $page_num > 1 ) {
+
+ my $prev_slide = $slides[$page_num - 2] ;
+ $slide->{'PREV_FILE'} = $prev_slide->{'slide_file'} ;
+ $slide->{'PREV_TITLE'} = $prev_slide->{'TITLE'} ;
+ }
+
+ if ( $page_num < $book_values{'TOTAL_PAGES'} ) {
+
+ my $next_slide = $slides[$page_num] ;
+ $slide->{'NEXT_FILE'} = $next_slide->{'slide_file'} ;
+ $slide->{'NEXT_TITLE'} = $next_slide->{'TITLE'} ;
+ }
+
+
+ my $header = apply_template( 'header', $slide ) ;
+ my $footer = apply_template( 'footer', $slide ) ;
+
+ my $slide_file = "slides/$slide->{'slide_file'}" ;
+
+ write_file( $slide_file,
+ $header,
+ "<UL>\n",
+ @{$slide->{'html_parts'}},
+ "</UL>\n",
+ $footer,
+ ) ;
+ }
+}
+
+sub make_index {
+
+ my $name = $book_values{'BOOK_NAME'} || 'Empty' ;
+
+ my $index_html = <<HTML ;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<TITLE>Index of $name</TITLE>
+</HEAD>
+<H2>Index of $name</H2>
+<P>
+<UL STYLE="list-style-type:none">
+HTML
+
+ my $toc_html = <<HTML ;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<TITLE>Table of Contents for $name</TITLE>
+</HEAD>
+<H2>Table of Contents for $name</H2>
+<P>
+<UL STYLE="list-style-type:none">
+HTML
+
+ foreach my $slide ( @slides ) {
+
+ my $chap_num = $slide->{'CHAP_NUM'} ;
+ my $slide_num = $slide->{'SLIDE_NUM'} ;
+
+ my $slide_file = sprintf( "slide-%02d%02d.html",
+ $chap_num,
+ $slide_num ) ;
+
+ $slide->{'slide_file'} = $slide_file ;
+
+ if ( $slide_num == 1 ) {
+
+ my $chapter = $slide->{'CHAPTER'} || '' ;
+
+ $index_html .= "</UL>\n" if $chap_num > 1 ;
+
+ $index_html .= <<HTML ;
+ <LI>$chap_num. <A href="$slide_file">$chapter</A>
+ <UL STYLE="list-style-type:none">
+HTML
+
+
+ $toc_html .= <<HTML ;
+ <LI>$chap_num. <A href="$slide_file">$chapter</A>
+HTML
+
+ }
+
+ $index_html .= <<HTML ;
+ <LI>$chap_num.$slide_num <A href="$slide_file">$slide->{'TITLE'}</A>
+HTML
+
+ }
+
+ $index_html .= <<HTML ;
+</UL>
+</HTML>
+HTML
+
+ $toc_html .= <<HTML ;
+</UL>
+</HTML>
+HTML
+
+
+ write_file( 'slides/index.html', $index_html ) ;
+ $book_values{'INDEX'} = 'index.html' ;
+
+ write_file( 'slides/toc.html', $toc_html ) ;
+ $book_values{'TOC'} = 'toc.html' ;
+}
+
+my %templates ;
+
+sub apply_template {
+
+ my( $tmpl_name, $add_values ) = @_ ;
+
+ my $template = $templates{ $tmpl_name } ;
+
+ unless( $template ) {
+
+ $template = read_file( "templates/$tmpl_name.tmpl" ) ;
+
+ $templates{ $tmpl_name } = $template ;
+ }
+
+ my %tmpl_values = ( %book_values, %{$add_values} ) ;
+
+ $template =~ s/<%(\w+?)%>/$tmpl_values{$1} || ''/ge ;
+
+ $template =~ s[<A HREF="">(.+?)</A>][$1]i ;
+
+ return $template ;
+}
+
+sub read_file {
+
+ my( $file_name ) = shift ;
+
+ my( $buf ) ;
+
+ local( *FH ) ;
+
+ open( FH, $file_name ) || croak "can't open $file_name $!" ;
+
+ return <FH> if wantarray ;
+
+ read( FH, $buf, -s FH ) ;
+ return $buf ;
+}
+
+sub write_file {
+
+ my( $file_name ) = shift ;
+
+ local( *FH ) ;
+
+ open( FH, ">$file_name" ) || croak "can't create $file_name $!" ;
+
+ print FH @_ ;
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
+ "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
+<HTML xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
+<HEAD>
+
+</HEAD>
+
+
+<BODY id="" >
+ <div id="header_enclosure">
+
+
+
+ </div>
+
+
+ <div class="chap_num">01.</div>
+ <div class="chap_link">
+ <A href="">Packages Homework
+</A>
+ </div>
+
+
+ <div id="footer_enclosure">
+
+
+
+ </div>
+</BODY>
+
+</HTML>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
+ "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
+<HTML xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
+<HEAD>
+
+</HEAD>
+
+
+<BODY id="" >
+ <div id="header_enclosure">
+
+
+
+
+ </div>
+
+
+ <div class="chap_num">.</div>
+ <div class="chap_title"></div>
+
+
+
+ <div class="page_title">01. <A href="page-0101.html">Donna's Homework
+</A></div>
+
+
+ <div class="page_title">02. <A href="page-0102.html">David Toal's Homework
+</A></div>
+
+
+
+
+ <div id="footer_enclosure">
+
+
+
+ </div>
+</BODY>
+
+</HTML>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
+ "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
+<HTML xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
+<HEAD>
+
+<TITLE></TITLE>
+<LINK REL="stylesheet" HREF="book.css" TYPE="text/css">
+
+</HEAD>
+
+
+<BODY id="" >
+ <div id="header_enclosure">
+
+
+
+
+
+ <H1>
+ <div align="center" id="page_header_title">Donna's Homework
+</div>
+ </H1>
+
+
+
+
+
+ <A id=next_link href="page-0102.html">Next</A>
+
+
+
+ <A id=index_link href="index.html">Index</A>
+
+
+
+
+
+
+
+<HR>
+
+
+
+ </div>
+
+ <div id="body_enclosure">
+
+
+
+
+ <UL>
+
+
+ <div class="item">
+ <LI>
+
+ <div class="item_title"></div>
+
+
+
+
+
+
+
+
+
+
+ <div class="code">
+ <font size=+1><PRE>
+
+
+# 3. CallMain1.pl
+
+package CallMain1;
+
+# This version imports the subs with explict args to use command
+
+use strict;
+use Data::Dumper;
+
+use NewArray1 qw( loadarr printarr);
+
+my $data_file= "data.txt";
+
+my $AofA = loadarr($data_file);
+
+my ($aref, $hold) = printarr($AofA);
+
+print "\nThe row with the largest number is: \n" ;
+print Dumper $aref;
+
+print "\nThe largest number is: \n" ;
+print Dumper $hold;
+
+print "\nProgram Complete: Array of Array's \n" ;
+
+use NewHash1 qw( loadhash printhash);
+
+my $hdata_file= "hdata.txt";
+
+my $HofH = loadhash($hdata_file);
+
+printhash($HofH);
+
+
+# 4. NewArray1.pm
+
+package NewArray1;
+
+use strict;
+use Data::Dumper;
+
+use base 'Exporter';
+use vars '@EXPORT_OK';
+
+@EXPORT_OK = qw( loadarr printarr );
+
+sub loadarr {
+
+ my ($fh) = @_;
+
+ open DAT, "$fh" || die "Could not open file! ($!)";
+
+ print "\nProgram Homework1: Array of Array's \n" ;
+
+ my $AofA ;
+ my $hold = 0;
+ my $aref;
+
+ while (my $line = <DAT>) {
+ push @{$AofA}, [split(" ", $line)];
+ }
+ print "\nThe Array of Array's contains: \n" ;
+ print Dumper @{$AofA};
+
+ return ($AofA);
+}
+
+sub printarr {
+
+ my $hold;
+ my $ele;
+ my $aref;
+
+ my ($AofA) = @_;
+
+ foreach my $Arr ( @{$AofA} ) {
+ foreach my $ele ( @{$Arr} ) {
+ if ($ele > $hold) {
+ $aref = $Arr;
+ $hold = $ele;
+ }
+ }
+ }
+
+ return ($aref, $hold);
+
+}
+
+# 5. NewHash1.pm
+
+package NewHash1;
+
+use strict;
+use Data::Dumper;
+
+use base 'Exporter';
+use vars '@EXPORT_OK';
+
+@EXPORT_OK = qw( loadhash printhash );
+
+sub loadhash {
+
+my ($fh) = @_;
+
+open DAT, "$fh" || die "Could not open file! ($!)";
+
+print "\nProgram Homework1: Two Level Hash \n\n" ;
+
+my $HofH;
+
+my $team;
+my $last;
+my $first;
+
+ while (my $line = <DAT>) {
+ ($team, $first, $last) = split(" ", $line);
+ $HofH->{$team}{$first} = $last;
+ }
+
+ print Dumper %{$HofH};
+
+ return ($HofH);
+
+}
+
+sub printhash {
+
+ my ($HofH) = @_;
+
+ my %dispatch = (
+ 'stooge' => \&stooge,
+ 'marx' => \&marx,
+ 'more' => \&more,
+ );
+
+ foreach my $team_name (keys %{$HofH}) {
+ print "\nComedy Team: $team_name\n" ;
+ my $code_ref = $dispatch{ $team_name };
+ $code_ref or die "Can't find $team_name in dispatch table" ;
+
+ foreach my $first_name (sort keys %{ $HofH->{$team_name} } ) {
+ my $last_name = $HofH->{$team_name}->{$first_name} ;
+ print "\nFirst Name : $first_name \n" ;
+ $code_ref->($first_name);
+ }
+ }
+
+ sub stooge {
+ my $nameref = shift;
+ print "Last Name : $HofH->{'stooge'}->{$nameref}\n";
+ }
+
+ sub marx {
+ my $nameref = shift;
+ print "Last Name : $HofH->{'marx'}->{$nameref}\n";
+ }
+
+ sub more {
+ print Dumper "not found";
+ }
+
+}
+
+# 3. CallMain2.pl
+
+package CallArray2;
+
+# This version imports the subs with an %EXPORT_TAGS tag
+
+use strict;
+use Data::Dumper;
+
+use NewArray2 qw( :Both);
+
+my $data_file= "data.txt";
+
+my $AofA = loadarr($data_file);
+
+my ($aref, $hold) = printarr($AofA);
+
+print "\nThe row with the largest number is: \n" ;
+print Dumper $aref;
+
+print "\nThe largest number is: \n" ;
+print Dumper $hold;
+
+print "\nProgram Complete: Array of Array's \n" ;
+
+use NewHash2 qw( :Both);
+
+my $hdata_file= "hdata.txt";
+
+my $HofH = loadhash($hdata_file);
+
+printhash($HofH);
+
+
+# 4. NewArray2.pm
+
+package NewArray2;
+
+use strict;
+use Data::Dumper;
+
+use base 'Exporter';
+use vars qw '@EXPORT_OK %EXPORT_TAGS';
+@EXPORT_OK = qw( loadarr printarr );
+%EXPORT_TAGS = ( Both =>[qw(loadarr printarr)]);
+
+sub loadarr {
+
+ my ($fh) = @_;
+
+ open DAT, "$fh" || die "Could not open file! ($!)";
+
+ print "\nProgram Homework2: Array of Array's \n" ;
+
+ my $AofA ;
+ my $hold = 0;
+ my $aref;
+
+ while (my $line = <DAT>) {
+ push @{$AofA}, [split(" ", $line)];
+ }
+ print "\nThe Array of Array's contains: \n" ;
+ print Dumper @{$AofA};
+
+ return ($AofA);
+}
+
+sub printarr {
+
+ my $hold;
+ my $ele;
+ my $aref;
+
+ my ($AofA) = @_;
+
+ foreach my $Arr ( @{$AofA} ) {
+ foreach my $ele ( @{$Arr} ) {
+ if ($ele > $hold) {
+ $aref = $Arr;
+ $hold = $ele;
+ }
+ }
+ }
+
+ return ($aref, $hold);
+
+}
+
+# 5. NewHash2.pm
+
+package NewHash2;
+
+use strict;
+use Data::Dumper;
+
+use base 'Exporter';
+use vars qw '@EXPORT_OK %EXPORT_TAGS';
+@EXPORT_OK = qw( loadhash printhash );
+%EXPORT_TAGS = ( Both =>[qw(loadhash printhash)]);
+
+sub loadhash {
+
+my ($fh) = @_;
+
+open DAT, "$fh" || die "Could not open file! ($!)";
+
+print "\nProgram Homework2: Two Level Hash \n\n" ;
+
+my $HofH;
+
+my $team;
+my $last;
+my $first;
+
+ while (my $line = <DAT>) {
+ ($team, $first, $last) = split(" ", $line);
+ $HofH->{$team}{$first} = $last;
+ }
+
+ print Dumper %{$HofH};
+
+ return ($HofH);
+
+}
+
+sub printhash {
+
+ my ($HofH) = @_;
+
+ my %dispatch = (
+ 'stooge' => \&stooge,
+ 'marx' => \&marx,
+ 'more' => \&more,
+ );
+
+ foreach my $team_name (keys %{$HofH}) {
+ print "\nComedy Team: $team_name\n" ;
+ my $code_ref = $dispatch{ $team_name };
+ $code_ref or die "Can't find $team_name in dispatch table" ;
+
+ foreach my $first_name (sort keys %{ $HofH->{$team_name} } ) {
+ my $last_name = $HofH->{$team_name}->{$first_name} ;
+ print "\nFirst Name : $first_name \n" ;
+ $code_ref->($first_name);
+ }
+ }
+
+ sub stooge {
+ my $nameref = shift;
+ print "Last Name : $HofH->{'stooge'}->{$nameref}\n";
+ }
+
+ sub marx {
+ my $nameref = shift;
+ print "Last Name : $HofH->{'marx'}->{$nameref}\n";
+ }
+
+ sub more {
+ print Dumper "not found";
+ }
+
+}
+
+# 3. CallMain3.pl
+
+package CallArray3;
+
+# This version will not import but will call the subs with Fully Qualified Names
+
+use strict;
+use Data::Dumper;
+
+use NewArray3;
+
+my $data_file= "data.txt";
+
+my $AofA = NewArray3::loadarr($data_file);
+
+my ($aref, $hold) = NewArray3::printarr($AofA);
+
+print "\nThe row with the largest number is: \n" ;
+print Dumper $aref;
+
+print "\nThe largest number is: \n" ;
+print Dumper $hold;
+
+print "\nProgram Complete: Array of Array's \n" ;
+
+use NewHash3;
+
+my $hdata_file= "hdata.txt";
+
+my $HofH = NewHash3::loadhash($hdata_file);
+
+NewHash3::printhash($HofH)
+
+
+4. NewArray3.pm --- application/octet-stream; NewArray3.pm]...
+
+package NewArray3;
+
+use strict;
+use Data::Dumper;
+
+sub loadarr {
+
+ my ($fh) = @_;
+
+ open DAT, "$fh" || die "Could not open file! ($!)";
+
+ print "\nProgram Homework3: Array of Array's \n" ;
+
+ my $AofA ;
+ my $hold = 0;
+ my $aref;
+
+ while (my $line = <DAT>) {
+ push @{$AofA}, [split(" ", $line)];
+ }
+ print "\nThe Array of Array's contains: \n" ;
+ print Dumper @{$AofA};
+
+ return ($AofA);
+}
+
+sub printarr {
+
+ my $hold;
+ my $ele;
+ my $aref;
+
+ my ($AofA) = @_;
+
+ foreach my $Arr ( @{$AofA} ) {
+ foreach my $ele ( @{$Arr} ) {
+ if ($ele > $hold) {
+ $aref = $Arr;
+ $hold = $ele;
+ }
+ }
+ }
+
+ return ($aref, $hold);
+
+}
+
+return ('TRUE');
+
+
+# 5. NewHash3.pm
+
+package NewHash3;
+
+use strict;
+use Data::Dumper;
+
+sub loadhash {
+
+my ($fh) = @_;
+
+open DAT, "$fh" || die "Could not open file! ($!)";
+
+print "\nProgram Homework3: Two Level Hash \n\n" ;
+
+my $HofH;
+
+my $team;
+my $last;
+my $first;
+
+ while (my $line = <DAT>) {
+ ($team, $first, $last) = split(" ", $line);
+ $HofH->{$team}{$first} = $last;
+ }
+
+ print Dumper %{$HofH};
+
+ return ($HofH);
+
+}
+
+sub printhash {
+
+ my ($HofH) = @_;
+
+ my %dispatch = (
+ 'stooge' => \&stooge,
+ 'marx' => \&marx,
+ 'more' => \&more,
+ );
+
+ foreach my $team_name (keys %{$HofH}) {
+ print "\nComedy Team: $team_name\n" ;
+ my $code_ref = $dispatch{ $team_name };
+ $code_ref or die "Can't find $team_name in dispatch table" ;
+
+ foreach my $first_name (sort keys %{ $HofH->{$team_name} } ) {
+ my $last_name = $HofH->{$team_name}->{$first_name} ;
+ print "\nFirst Name : $first_name \n" ;
+ $code_ref->($first_name);
+ }
+ }
+
+ sub stooge {
+ my $nameref = shift;
+ print "Last Name : $HofH->{'stooge'}->{$nameref}\n";
+ }
+
+ sub marx {
+ my $nameref = shift;
+ print "Last Name : $HofH->{'marx'}->{$nameref}\n";
+ }
+
+ sub more {
+ print Dumper "not found";
+ }
+
+}
+return ('TRUE');
+</PRE></font>
+ </div>
+
+
+ </LI>
+ </div>
+
+
+ </UL>
+
+
+
+ </div>
+
+ <div id="footer_enclosure">
+
+
+
+<HR>
+
+
+
+
+ <A id=next_link href="page-0102.html">Next</A>
+
+
+
+ <A id=index_link href="index.html">Index</A>
+
+
+
+
+
+
+
+
+
+
+
+ </div>
+</BODY>
+
+</HTML>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
+ "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
+<HTML xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
+<HEAD>
+
+<TITLE></TITLE>
+<LINK REL="stylesheet" HREF="book.css" TYPE="text/css">
+
+</HEAD>
+
+
+<BODY id="" >
+ <div id="header_enclosure">
+
+
+
+
+
+ <H1>
+ <div align="center" id="page_header_title">David Toal's Homework
+</div>
+ </H1>
+
+
+
+ <A id=prev_link href="page-0101.html">Prev</A>
+
+
+
+ <A id=next_link href="page-0103.html">Next</A>
+
+
+
+ <A id=index_link href="index.html">Index</A>
+
+
+
+
+
+
+
+<HR>
+
+
+
+ </div>
+
+ <div id="body_enclosure">
+
+
+
+
+ <UL>
+
+
+ <div class="item">
+ <LI>
+
+ <div class="item_title"></div>
+
+
+
+
+
+
+
+
+
+
+ <div class="code">
+ <font size=+1><PRE>
+
+
+package ArrayUtils;
+
+
+use Exporter;
+
+@ISA = qw( Exporter );
+
+
+use FindArrayMax qw( &find_max_val &find_max_row );
+
+@EXPORT = qw( &load_array &find_max_val &find_max_row );
+# if this is commented out, only fully qualified calls work
+
+@EXPORT_OK = qw( load_array find_max_val find_max_row );
+
+
+sub load_array {
+
+ print "ArrayUtils::load_array\n";
+
+ my $fh = shift;
+
+ my @array;
+
+ while (<$fh>) {
+
+ # print "read from file $_";
+
+ my @values = split;
+
+ push @array, \@values;
+
+ }
+
+ return \@array;
+
+}
+
+
+1;
+
+
+
+package ArrayUtils;
+
+
+use Exporter;
+
+@ISA = qw( Exporter );
+
+
+@EXPORT_OK = qw( &find_max_val &find_max_row );
+
+
+sub find_max_val {
+
+ print "ArrayUtils::find_max_val\n";
+
+ my $matrix = shift;
+
+ my $max_val;
+
+ foreach my $row (@{$matrix}) {
+ foreach my $val (@{$row}) {
+ $max_val = $val if ($val > $max_val);
+ }
+ }
+
+ return $max_val;
+
+}
+
+
+
+sub find_max_row {
+
+ print "ArrayUtils::find_max_row\n";
+
+ my $matrix = shift;
+
+ my $max_row;
+ my $max_val;
+
+ foreach my $row (@{$matrix}) {
+ foreach my $val (@{$row}) {
+ $max_row = $row, $max_val = $val if ($val > $max_val);
+ }
+ }
+
+ return $max_row;
+
+}
+
+
+1;
+
+
+
+package HashDispatch;
+
+use Exporter;
+
+@ISA = qw( Exporter );
+
+@EXPORT = qw( &dispatch_table );
+
+
+my $DEBUG = 1;
+print "HashDispatch::DEBUG set\n" if ($DEBUG);
+
+sub dispatch_table {
+
+ print "HashDispatch::dispatch_table\n" if ($DEBUG);
+
+ my $dispatch = {
+ 'stooge' => \&stooges ,
+ 'marx' => \&marxes
+ };
+
+ return $dispatch;
+
+}
+
+
+sub stooges {
+ my ($name, $team) = @_;
+ return "$name, last name is $team->{'stooge'}->{$name}";
+}
+
+
+sub marxes {
+ my ($name, $team) = @_;
+ return "$name, real name is $team->{'marx'}->{$name}";
+}
+
+1;
+
+
+
+ # my $dispatch = {
+ # 'stooge' => \sub { my ($name, $hash) = @_; print "stooge name is $name\n"; } ,
+ # 'marx' => \sub { my ($name, $hash) = @_; print "marx name is $name\n"; }
+ # };
+
+
+
+package HashUtils;
+
+use FileHandle;
+
+use Exporter;
+
+@ISA = qw( Exporter );
+
+
+use HashDispatch;
+
+@EXPORT = qw( &load_hash &dispatch_table );
+
+# @EXPORT_OK = qw( &load_hash &dispatch_table );
+
+
+
+my $DEBUG = 1;
+
+print "HashUtils::DEBUG set\n" if ($DEBUG);
+
+
+sub load_hash {
+
+ print "HashUtils::load_hash\n" if ($DEBUG);
+
+ my $fh = shift;
+
+ my %hash;
+
+ while (<$fh>) {
+
+ print "line is $_" if ($DEBUG);
+
+ my ($team, $first, $second) = split;
+
+ $hash{$team}->{$first} = $second;
+
+ }
+
+ return \%hash;
+
+}
+
+
+1;
+
+4 11 7
+9 15 6 2
+1 9
+
+
+use strict;
+
+use FileHandle;
+
+use ArrayUtils;
+
+
+my $filename = "array-data.txt";
+
+
+my $fh = FileHandle->new();
+
+$fh->open("< $filename");
+
+
+my $matrix = load_array($fh);
+
+foreach my $row (@{$matrix}) {
+ foreach my $val (@{$row}) { print "$val, "; }
+ print "\n";
+}
+
+
+my $max_val = find_max_val($matrix);
+
+print "max val is $max_val\n";
+
+
+my $max_row = find_max_row($matrix);
+
+print "max row is: ";
+
+foreach my $val (@{$max_row}) {
+ print "$val, ";
+}
+
+print "\n";
+
+
+
+use strict;
+
+use FileHandle;
+
+use ArrayUtils qw( &load_array &find_max_val &find_max_row );
+
+
+my $filename = "array-data.txt";
+
+
+my $fh = FileHandle->new();
+
+$fh->open("< $filename");
+
+
+my $matrix = ArrayUtils::load_array($fh);
+
+foreach my $row (@{$matrix}) {
+ foreach my $val (@{$row}) { print "$val, "; }
+ print "\n";
+}
+
+
+my $max_val = ArrayUtils::find_max_val($matrix);
+
+print "max val is $max_val\n";
+
+
+my $max_row = ArrayUtils::find_max_row($matrix);
+
+print "max row is: ";
+
+foreach my $val (@{$max_row}) {
+ print "$val, ";
+}
+
+print "\n";
+
+marx groucho julius
+stooge moe howard
+stooge larry fine
+marx chico leonard
+marx harpo arthur
+stooge curly howard
+
+
+use strict;
+
+use Data::Dumper;
+
+use FileHandle;
+
+use HashUtils;
+
+
+my $filename = "hash-data.txt";
+
+my $fh = FileHandle->new();
+
+$fh->open("< $filename");
+
+
+my $team = load_hash($fh);
+
+print Dumper $team;
+
+
+my $table = dispatch_table();
+
+foreach my $team_name (keys(%{$team})) {
+ print "team name is $team_name\n";
+
+ foreach my $name (keys(%{ $team->{$team_name} })) {
+ my $result = $table->{$team_name}->($name, $team);
+ print "$result\n";
+ }
+
+}
+
+
+
+use strict;
+
+use Data::Dumper;
+
+use FileHandle;
+
+use HashUtils qw( &load_hash &dispatch_table );
+
+
+my $filename = "hash-data.txt";
+
+my $fh = FileHandle->new();
+
+$fh->open("< $filename");
+
+
+my $team = HashUtils::load_hash($fh);
+
+print Dumper $team;
+
+
+my $table = HashUtils::dispatch_table();
+
+foreach my $team_name (keys(%{$team})) {
+ print "team name is $team_name\n";
+
+ foreach my $name (keys(%{ $team->{$team_name} })) {
+ my $result = $table->{$team_name}->($name, $team);
+ print "$result\n";
+ }
+
+}
+
+
+
+use strict;
+
+use Data::Dumper;
+
+use FileHandle;
+
+use HashUtils;
+
+
+my $DEBUG = 1;
+print "main::DEBUG set\n" if ($DEBUG);
+
+
+my $filename = "hash-data.txt";
+
+my $fh = FileHandle->new();
+
+$fh->open("< $filename");
+
+
+my $team = load_hash($fh);
+
+print Dumper $team;
+
+
+my $table = dispatch_table();
+
+foreach my $team_name (keys(%{$team})) {
+ print "team name is $team_name\n";
+
+ foreach my $name (keys(%{ $team->{$team_name} })) {
+ my $result = $table->{$team_name}->($name, $team);
+ print "$result\n";
+ }
+
+}
+
+</PRE></font>
+ </div>
+
+
+ </LI>
+ </div>
+
+
+ </UL>
+
+
+
+ </div>
+
+ <div id="footer_enclosure">
+
+
+
+<HR>
+
+
+ <A id=prev_link href="page-0101.html">Prev</A>
+
+
+
+ <A id=next_link href="page-0103.html">Next</A>
+
+
+
+ <A id=index_link href="index.html">Index</A>
+
+
+
+
+
+
+
+
+
+
+
+ </div>
+</BODY>
+
+</HTML>
+
--- /dev/null
+<li><%TEXT%>
--- /dev/null
+<PRE><%TEXT%></PRE>
\ No newline at end of file
--- /dev/null
+<HR WIDTH="95%">
+<TABLE ALIGN="CENTER" BORDER=0 WIDTH="95%">
+ <TR>
+ <TD WIDTH="30%" ALIGN="LEFT">
+ <A HREF="<%PREV_FILE%>">Prev</A>
+ <A HREF="<%NEXT_FILE%>">Next</A>
+ <A HREF="<%INDEX%>">Index</A>
+ <TD ALIGN="CENTER">
+ <IMG SRC="images/stem_tide.gif"><BR>
+ <TD WIDTH="25%" ALIGN="RIGHT">Page <%PAGE_NUM%>/<%TOTAL_PAGES%>
+ </TR>
+
+ <TR>
+ <TD ALIGN="CENTER" COLSPAN="3">
+ <FONT SIZE="-2">© 2003 Stem Systems</FONT>
+ </TR>
+
+</TABLE>
+</HTML>
\ No newline at end of file
--- /dev/null
+<P ALIGN=CENTER>
+<TABLE BGCOLOR="FORESTGREEN"><TR><TD>
+ <TABLE BORDER=5 BGCOLOR="#CFE7CF" CELLPADDING=0 CELLSPACING=0 >
+ <TR><TD><I>
+ <%LINE1%><BR>
+ <%LINE2%><BR>
+ <%LINE3%><BR>
+ </I></TD><TR>
+ </TABLE>
+</TD></TR>
+</TABLE>
+</P>
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+<TITLE><%TITLE%></TITLE>
+</HEAD>
+<H3 ALIGN=CENTER><%CHAP_NUM%>.<%SLIDE_NUM%><%CHAP_ABBREV%>: <%TITLE%></H3>
+<TABLE ALIGN="CENTER" BORDER=0 WIDTH="95%">
+ <TR>
+ <TD WIDTH="25%" ALIGN="LEFT">
+ <A HREF="<%PREV_FILE%>">Prev</A>
+ <A HREF="<%NEXT_FILE%>">Next</A>
+ <A HREF="<%INDEX%>">Index</A>
+ <TD ALIGN="CENTER">
+
+ <TD WIDTH="25%" ALIGN="RIGHT">Page <%PAGE_NUM%>/<%TOTAL_PAGES%>
+ </TR>
+</TABLE>
+<HR WIDTH="95%">
--- /dev/null
+<p>
+<%TEXT%>
+</p>
--- /dev/null
+[%INCLUDE html_header %]
+
+<BODY id="[%page_name%]" >
+ <div id="header_enclosure">
+ [%INCLUDE page_header %]
+ </div>
+
+ [%START chap_title%]
+ <div class="chap_num">[%number%].</div>
+ <div class="chap_link">
+ <A href="[%chap_url%]">[%title%]</A>
+ </div>
+ [%END chap_title%]
+
+ <div id="footer_enclosure">
+ [%INCLUDE page_footer %]
+ </div>
+</BODY>
+
+[%INCLUDE html_footer %]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
+ "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
+<HTML xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
+<HEAD>
+[%START html_header %]
+<TITLE>[%title%]</TITLE>
+<LINK REL="stylesheet" HREF="book.css" TYPE="text/css">
+[%END html_header %]
+</HEAD>
--- /dev/null
+[%INCLUDE html_header %]
+
+<BODY id="[%page_name%]" >
+ <div id="header_enclosure">
+
+ [%INCLUDE page_header %]
+ </div>
+
+ [%START chapter%]
+ <div class="chap_num">[%number%].</div>
+ <div class="chap_title">[%title%]</div>
+
+ [%START page%]
+
+ <div class="page_title">[%number%]. <A href="[%page_link%]">[%title%]</A></div>
+ [%END page%]
+
+ [%END chapter%]
+
+ <div id="footer_enclosure">
+ [%INCLUDE page_footer %]
+ </div>
+</BODY>
+
+[%INCLUDE html_footer %]
--- /dev/null
+[%START item %]
+<div class="item">
+ [%START item_image %]
+ <div class="item_image">[%text%]</div>
+ [%END item_image %]
+
+ [%START item_title %]
+ <div class="item_title">[%text%]</div>
+ [%END item_title %]
+
+ [%START item_date %]
+ <div class="item_date">[%text%]</div>
+ [%END item_date %]
+
+ [%START item_text %]
+ <div class="item_text"><p class="item_paragraph">[%text%]</p></div>
+ [%END item_text %]
+
+ [%START item_code %]
+ <div class="item_code"><p class="item_code"><CODE>[%text%]</CODE></p></div>
+ [%END item_code %]
+
+ [%START item_list %]
+ <div class="item_list">
+ <UL>
+ [%START item_list_elem %]
+ <div class="item_list_elem"><LI>[%text%]</LI></div>
+ [%END item_list_elem %]
+ </UL>
+ </div>
+ [%END item_list %]
+
+ [%START item_sep %]
+ <div class="item_sep"></div>
+ [%END item_sep %]
+
+</div>
+[%END item %]
--- /dev/null
+[%INCLUDE html_header %]
+
+<BODY id="[%page_name%]" >
+ <div id="header_enclosure">
+
+ [%INCLUDE page_header %]
+ </div>
+
+ <div id="body_enclosure">
+
+ [%INCLUDE page_body %]
+ </div>
+
+ <div id="footer_enclosure">
+ [%INCLUDE page_footer %]
+ </div>
+</BODY>
+
+[%INCLUDE html_footer %]
--- /dev/null
+[%START page %]
+ [%START title %]
+ <div class="page_title">[%text%]</div>
+ [%END title %]
+
+ <UL>
+
+ [%START item %]
+ <div class="item">
+ <LI>
+ [%START title %]
+ <div class="item_title">[%text%]</div>
+ [%END title %]
+
+ [%START image %]
+ <div class="item_image">[%image%]</div>
+ [%END image %]
+
+ [%START text %]
+ <div class="item_text">
+ <p class="item_paragraph">[%text%]</p></div>
+ [%END text %]
+
+ [%START subitems %]
+ <div class="subitem">
+ <UL>
+ [%START subitem %]
+
+ <div class="subitem_text">
+ <LI>[%text%]</LI>
+ </div>
+ [%END subitem %]
+ </UL>
+ </div>
+ [%END subitems %]
+
+
+ [%START code %]
+ <div class="code">
+ <font size=+1><PRE>[%text%]</PRE></font>
+ </div>
+ [%END code %]
+
+ </LI>
+ </div>
+ [%END item %]
+
+ </UL>
+
+[%END page %]
--- /dev/null
+
+[%START page_footer %]
+
+<HR>
+
+ [%START prev_link %]
+ <A id=prev_link href="[%prev_page%]">Prev</A>
+ [%END prev_link %]
+
+ [%START next_link %]
+ <A id=next_link href="[%next_page%]">Next</A>
+ [%END next_link %]
+
+ [%START index_link %]
+ <A id=index_link href="[%text%]">Index</A>
+ [%END index_link %]
+
+ [%START logo %]
+ <IMG SRC="images/[%logo_file%]">
+ [%END logo %]
+
+
+ [%START page_num %]
+ <div id="page_num">
+ [%page_num%]/[%total_pages%]
+ </div>
+ [%END page_num %]
+
+ [%START copyright %]
+ <div id="copyright">
+ [%copyright%]
+ </div>
+ [%END copyright %]
+
+[%END page_footer %]
--- /dev/null
+
+[% START page_header %]
+
+ [% START header_title %]
+ <H1>
+ <div align="center" id="page_header_title">[%text%]</div>
+ </H1>
+ [% END header_title %]
+
+ [%START prev_link %]
+ <A id=prev_link href="[%prev_page%]">Prev</A>
+ [%END prev_link %]
+
+ [%START next_link %]
+ <A id=next_link href="[%next_page%]">Next</A>
+ [%END next_link %]
+
+ [%START index_link %]
+ <A id=index_link href="[%text%]">Index</A>
+ [%END index_link %]
+
+ [%START logo %]
+ <IMG SRC="images/[%logo_file%]">
+ [%END logo %]
+
+
+ [%START page_num %]
+ <div id="page_num">
+ [%page_num%]/[%total_pages%]
+ </div>
+ [%END page_num %]
+
+<HR>
+
+[% END page_header %]