#!/usr/bin/perl -w use strict; # html_it - Or, how to have fun with CGI.pm to generate a sort # of template'd page of HTML using "statistics" from # a database. :-) # # Normally, CGI.pm is used to generate CGI web pages. Here, I just # want to generate a static HTML page on occasion. The object of # this page is to present all the material I have read that is in # my personal bibliographic interest/library. This program assumes # that the data is present in the form of Data::Dumper output, # in the format produced by my Biblio-Tk program. Or rather, in one # of the first formats produced by my program. Of course, one # learns what needs to be changed as things move along. # # I suppose if a person was dominantly one-dimensional, that most # of their interests would lie in one area. As an engineer, I have # three fairly diverse areas of interest for which I claim professional # competancy. In addition, I claim to have sufficient interest in # at least 2 other areas at a level sufficient to make a living at. # Within each of those areas of interest, and for a few cases outside # those; I have various topics I am interested in. How to decide # on the topic or area of interest, should be possible by using a # good choice of keywords. # # Some people have found that if you look at the word-document space # within a certain topic, you can perform variously kinds of analyses # to determine keywords for searching. One mechanism uses Singular # Value Decomposition to find a sub-space of the word-document space # which well represents the topic. Various methods of cluster analysis # are also used. # # There is a perl module, which develops keywords from parts of speech # analysis (POS) of text (English). I am using that for a starting # point. It seems to work. Certainly it works much better than me # doing naive histogram analysis. # # Copyright 2003, Gordon Haverland, Matter Realisations. Program # covered by the same copyright/warranty as the bulk of programs # and modules found at CPAN. Copyright is typically your choice # of The Artistic License or the GPL. Warranty is none. # # Work on Conference printouts, and "old" books (B.Sc/M.Eng.). #we want to make a page of title (chapter) -> biblio entry #and a page of keywords -> biblio entry. use Data::Dumper; # For debugging use CGI qw/:html4/; # HTML level 4 (and XHTML) use Text::Aspell; # Spell checking of titles. use Lingua::EN::Keywords; # # We have some global variables. my( %MyArea, @my_areas ); my( %Area, @areas, %NArea ); my( %MyInterest, @my_interests ); my( %Interest, @interests, %NInterest ); my( %Pages, %Book_Type, %Read, $tot_pages ); my( %SpellIgnore, %Synonym, $speller ); my( @hashes, @old_hashes, @old_self_hashes ); my( $n_keys, $n_textbook, $n_reference ); my $dbase; # This comes from eval of file. # Open our file, and suck entire file into a scalar variable by # "locally" redefining the input record separator $? my $fname = "save.61"; open( IMPORT, "< $fname" ) || die "Import <$fname) $!\n"; my $file; { # Read entire file into $file local $/; $file = ; } close(IMPORT); # Now eval the string, to bring the data into this workspace. my $res = eval $file; { # Start up a spelling engine. Last call is via books_all(). $speller = Text::Aspell->new; $speller->set_option('lang', 'en_CA'); #$speller->set_option('master', './dictionary_local'); open( SPELL, "> html_it2.spell" ) || die "Spell: $!\n"; &summarize(); &keywords_anal(); &books_all(); &books_specific( \%Area, \@areas ); &books_specific( \%Interest, \@interests ); # Okay, we are done spell checking things, close that output stream. close( SPELL ); } # Print out about page, and associated stuff. &about(); exit 0; # ================== Subroutines ==================== # Summarize data dumped, and generate lead page. sub summarize { my( $title, $chapters ); # Go through each entry, looking for data. The hash is a # hexadecimal number, possibly with a colon and a decimal # number appended to it. So, we can use something else # (say a semicolon) to separate hashes in the strings. We need to # check for existance of the key and then "truth" of the value. # Note, for final stuff we want to split the stuff for B.Sc. from # Masters, from other stuff. foreach my $hash ( keys( %{$dbase} ) ) { my $bib_entry = $dbase->{$hash}; push @hashes, $hash; # Keep track of books read as part of B.Sc. if( $bib_entry->{note} =~ /B\.Sc\./i ) { push @old_hashes, $hash; } elsif( $bib_entry->{note} =~ /M\.Eng\./i ) { push @old_hashes, $hash; } elsif( $bib_entry->{Finish_Reading} =~ /\d+/ ) { if( $bib_entry->{Finish_Reading} < 1984 ) { push @old_self_hashes, $hash; } } elsif( length($bib_entry->{Finish_Reading}) > 0 ) { print "Strange Finish_Reading $hash:$bib_entry->{Finish_Reading}\n"; } # Remember the number of pages in each book if( exists( $bib_entry->{'pages'} ) && $bib_entry->{'pages'} ) { $tot_pages += $bib_entry->{'pages'}; $Pages{$bib_entry->{'pages'}} .= "$hash;"; } # Remember which books are in each major interest area if( exists( $bib_entry->{'My_Interest'} ) && $bib_entry->{'My_Interest'} ) { my $Interest = lc $bib_entry->{'My_Interest'}; $Area{$Interest} .= "$hash;"; } # Remember which books are of which types. if( exists( $bib_entry->{'Book_Type'} ) && $bib_entry->{'Book_Type'} ) { my $book_type = lc $bib_entry->{'Book_Type'}; if( $book_type =~ /text/ ) { $book_type = 'textbook'; } elsif( $book_type =~ /reference/ ) { $book_type = 'reference'; } else { $book_type = 'unknown'; } $Book_Type{$book_type} .= "$hash;"; } # Remember all the topics of Interest I'm interested in. if( exists( $bib_entry->{'Topics_'} ) && $bib_entry->{'Topics_'} ) { # This is an array of strings, maybe empty. foreach my $val (@{$bib_entry->{'Topics_'}}) { my $lc_val = lc $val; $Interest{$lc_val} .= "$hash;"; } } # Remember all the years I finished reading (Textbooks). if( exists( $bib_entry->{'Finish_Reading'} ) && $bib_entry->{'Finish_Reading'} ) { $Read{$bib_entry->{'Finish_Reading'}} .= "$hash;"; } # Keywords analysis # Might be title or booktitle if( exists( $bib_entry->{title} ) && (length( $bib_entry->{title} ) > 0 ) ) { $title = 'title'; } else { $title = 'booktitle'; } $bib_entry->{keywordphrase} = {} unless exists $bib_entry->{keywordphrase}; &check_title( $bib_entry->{$title}, $hash ); $bib_entry->{keywordtext} = [] unless exists $bib_entry->{keywordtext}; push( @{$bib_entry->{keywordtext}}, $bib_entry->{$title} ); # Some books have chapters, some have art_titles if( $title eq 'title' ) { $chapters = 'chapters'; } else { $chapters = 'art_titles'; } $chapters .= '_'; $bib_entry->{keywordphrase} = {} # was [] unless exists $bib_entry->{keywordphrase}; foreach my $item (@{$bib_entry->{$chapters}}) { &check_title( $item, $hash ); $bib_entry->{keywordtext} = [] unless exists $bib_entry->{keywordtext}; push( @{$bib_entry->{keywordtext}}, $item ); } } my $n_hashes = $#hashes + 1; # Go about, calculating what is needed to build the pages. Then # build it all in one big print statement (per file). @areas = sort keys(%Area); my $areas = join ', ', @areas; foreach my $Area (@areas) { my @x = split(/;/, $Area{$Area}); $NArea{$Area} = $#x + 1; } @interests = sort keys(%Interest); my $interests = join ', ', @interests; foreach my $Interest (@interests) { my @x = split(/;/, $Interest{$Interest}); $NInterest{$Interest} = $#x + 1; } $n_keys = $#hashes + 1; my @x = split( /;/, $Book_Type{'textbook'} ); $n_textbook = $#x + 1; @x = split( /;/, $Book_Type{'reference'} ); $n_reference = $#x + 1; # We are going to want a few pages off this. # 1) All books, alphabetical order by title. Just @required, link # to remainder. Except flag for textbook/reference. # 2) Books in an area of interest, alphabetical order. Just @required. .... # 3) Books by topic, alphabetical. Just @required. .... my $html_a = 'Breaking down the books by area of interest, we have:'; my $html_i = 'Breaking down the books by topic of interest, we have:'; # Okay, we have all of the information needed to make our HTML pages. # I'm not making CGI, just HTML. But, using CGI.pm makes this easy. # For CGI.pm > 2.69, the output HTML is XHTML, which is what I want. # I also want just HTML4. I probably should run this through tidy # anyway. I am going to generate a family of pages, not just a single # page. my $html = new CGI; my $n_old_books = $#old_hashes + 1; open( INDEX, "> index.html" ) || die "Index: $!\n"; # print $html->start_html('Gordon Haverland: Self-Study Summary'), print INDEX $html->start_html('Gordon Haverland: Self-Study Summary'), $html->h1('Gordon Haverland: Self-Study Summary'), $html->p( "A partial enumeration of Gordon Haverland's continuing", "education has $n_keys entries in it. ", "This enumeration breaks down into $n_textbook 'Textbooks' and", "$n_reference 'Reference' books and $tot_pages pages." ), $html->p( "In this case, a textbook is one which has been", "substantially studied cover to cover, while a", "reference book is just used to look up things on occasion", "(or hasn't been read yet). $n_old_books of these were", "part of formal study in university." ), $html->p( "Gordon Haverland lists materials science and engineering,", "nuclear engineering, and information technologies as his", "professional areas of expertise. This report covers the", "following areas: $areas." ), $html->p( "In addition, he has significant interests in cooking." ), $html->p( "This report covers the following topics in ASCII (roughly", "alphabetical) order: $interests." ), $html->p( "All books by title are in all.html." ), $html->p( $html_a ), $html->p( $html_i ), $html->p( "If you want to know how these files were made, see", "about.html." ), $html->end_html; close( INDEX ); } sub keywords_anal { # At this point, we've analysed what we have. The point of doing # keyword/phrase analysis, is to find out what keywords/phrases # we have missed, and to develop synonyms. # Find the largest number of hits on phrases across our biblio entries # I don't think this number is used here, but it could come into use. my $max = 0; foreach my $h (keys(%{$dbase})) { foreach my $key (keys( %{$dbase->{$h}{keywordphrase}} )) { $max = $dbase->{$h}{keywordphrase}{$key} if( $dbase->{$h}{keywordphrase}{$key} > $max ); } } # If we already use this keyword, we don't need to look for it as a new one. @my_areas = keys( %MyArea ); foreach (@my_areas) { quotemeta( lc ); }; foreach my $key (keys( %Area )) { my $qkey = quotemeta $key; unless( grep /^$qkey/i, @my_areas ) { print "$key not found in Areas\n"; } } # If we get a "substantial" match between something in @my_areas and # a keyword found in the data, we don't need to remember the keyword. # Question is, what is substantial enough? foreach my $h (keys(%{$dbase})) { foreach my $area (@my_areas) { foreach my $key (keys( %{$dbase->{$h}{keywordphrase}} )) { if( &in_each_other( $area, $key ) ) { delete( $dbase->{$h}{keywordphrase}{$key} ); } } } } # Same thing for topics of interest @my_interests = keys( %MyInterest ); foreach (@my_interests) { quotemeta( lc ); }; foreach my $key (keys( %Interest )) { my $qkey = quotemeta $key; unless( grep /^$qkey/i, @my_interests ) { print "$key not found in Interests\n"; } } foreach my $h (keys(%{$dbase})) { foreach my $int (@my_interests) { foreach my $key (keys( %{$dbase->{$h}{keywordphrase}} )) { if( &in_each_other( $int, $key ) ) { delete( $dbase->{$h}{keywordphrase}{$key} ); } } } } # And for Synonyms of things in Topics_ foreach my $h (keys(%{$dbase})) { foreach my $tp (@{$dbase->{$h}{Topics_}}) { my $int = lc $tp; if( exists( $Synonym{$int} ) ) { foreach my $synonym (@{$Synonym{$int}}) { foreach my $key (keys( %{$dbase->{$h}{keywordphrase}} )) { if( &in_each_other( $synonym, $key ) ) { delete( $dbase->{$h}{keywordphrase}{$key} ); } } } } } } # We have @keywordphrase in each dbase entry, and we have topics. foreach my $hash (@hashes) { my @misses; my $kn = $#{$dbase->{$hash}{keywordtext}} + 1; foreach my $kwp (keys(%{$dbase->{$hash}{keywordphrase}})) { # If by some analysis across a set of text, a keyword only # occurs once, or occurs every time, delete it. Since my # documents usually have a chapter title of Introduction or # similar, which shares nothing with the topic, look for this # max occurance to be $kn-1 if( $dbase->{$hash}{keywordphrase}{$kwp} < 2 ) { delete $dbase->{$hash}{keywordphrase}{$kwp}; } elsif( $dbase->{$hash}{keywordphrase}{$kwp} > ($kn-2) ) { delete $dbase->{$hash}{keywordphrase}{$kwp}; } } # Now look at the whole bit of text my $kt = join ', ', @{$dbase->{$hash}{keywordtext}}; my @kwds = keywords( $kt ); foreach my $kwd (@kwds) { next unless length( $kwd ) > 0; if( exists( $dbase->{$hash}{keywordphrase}{$kwd} ) ) { $dbase->{$hash}{keywordphrase}{$kwd} = 0.5 * ($dbase->{$hash}{keywordphrase}{$kwd} + &count_substr( $kt, $kwd ) ); } else { $dbase->{$hash}{keywordphrase}{$kwd} = &count_substr( $kt, $kwd ); } } } # What keywords/phrases have survived culling? Print them. open( KEYS, "> html_it2.keys" ) || die "Keys: $!\n"; { # Within each hash, sort by decreasing keyword score and increasing # ASCIIbetical foreach my $h (@hashes) { my @sorted = sort { $dbase->{$h}{keywordphrase}{$b} <=> $dbase->{$h}{keywordphrase}{$a} || $dbase->{$h}{keywordphrase}{$a} <=> $dbase->{$h}{keywordphrase}{$b} } keys( %{$dbase->{$h}{keywordphrase}} ); print KEYS "In $h, we have "; foreach my $k (@sorted) { print KEYS "$k($dbase->{$h}{keywordphrase}{$k}), "; } print KEYS "\n"; } } close( KEYS ); } # Generate bibliographic entries for all books sub books_all { my $html = new CGI; my @sorted = sort { my $atitle = 'title'; $atitle = 'booktitle' if( $dbase->{$a}{bib_type} eq 'conference' ); my $btitle = 'title'; $btitle = 'booktitle' if( $dbase->{$b}{bib_type} eq 'conference' ); $dbase->{$a}{$atitle} cmp $dbase->{$b}{$btitle} } @hashes; # The file containing an index to everything open( ALL, "> all.html") || die "All $!\n"; print ALL $html->start_html("Gordon-Haverland: All Documents Indexed"), $html->h1("Gordon-Haverland: All Documents Indexed"), $html->p( "This file contains a listing of every document", "indexed so far, in the Self-Study Bibliographic", "database of Gordon Haverland.", ); foreach my $hash (@sorted) { my $fname = "$hash.html"; my $type2; if( $dbase->{$hash}{'Book_Type'} =~ /text/i ) { $type2 = 'Textbook'; } elsif( $dbase->{$hash}{'Book_Type'} =~ /reference/i ) { $type2 = 'Reference'; } else { $type2 = "Unknown"; } #$$** # Most things use title, except conference my $title = 'title'; $title = 'booktitle' if( $dbase->{$hash}{bib_type} eq 'conference' ); print ALL "$type2:\t$dbase->{$hash}{$title}
"; } print ALL $html->end_html; close( ALL ); # The hash value, is a 32 digit hexadecimal number [0-9a-fA-F], possibly # followed by a colon and then a decimal number. These characters are # legal for a file name. So, the file name we store the data under is # $hash.html foreach my $hash (@hashes) { my $fname = "$hash.html"; # No spaces in $hash, so things are okay. my %label = ( title => 'Title', booktitle => 'Conf. Proc. Title', authors => 'Author(s)', editors => 'Editor(s)', publisher => 'Publisher', year => 'Year', volume => 'Volume', edition => 'Edition', ISBN => 'ISBN', # More processing required after this. chapters => 'Chapters', art_titles => 'Article Titles', My_Interest => 'My Area of Expertise', Topics => 'My Topic of Interest' ); my @labels = ( 'title', 'authors', 'editors', 'publisher', 'year', 'volume', 'edition', 'ISBN', # More processing required after this. 'chapters', 'My_Interest', 'Topics' ); # Remaining things, in order: chapters, My_Interest, Topics my $type; if( $dbase->{$hash}{'Book_Type'} =~ /text/i ) { $type = "This book is considered a textbook, in that it was " . "substantially, or completely read."; } elsif( $dbase->{$hash}{'Book_Type'} =~ /reference/i ) { $type = "This book is considered a reference book, in that it was " . "not substantially read."; } else { $type = "Unknown status: $dbase->{$hash}{'Book_Type'}"; } # Calculate the HTML table describing the bibliography entry. Or # rather, the table_rows and table_data within a row. Start with # the @required array, my order. my $trtd = ''; foreach my $entry (@labels) { if( ($entry eq 'authors') || ($entry eq 'editors') || ($entry eq 'chapters') || ($entry eq 'topics') ) { # We might need to alter entry, for chapters in conference. my $l_entry = $entry; if( ($dbase->{$hash}{bib_type} eq 'conference') && ($entry eq 'chapters') ) { $l_entry = 'art_titles'; } my $rarray = "$l_entry" . '_'; my $label = $label{$l_entry}; if( exists( $dbase->{$hash}{$rarray} ) && ($#{$dbase->{$hash}{$rarray}} > -1) ) { foreach my $item (@{$dbase->{$hash}{$rarray}}) { $trtd .= $html->Tr( [ $html->td( [ $label, $item ] ), ] ); $label = ''; # Or   ????? Undef???? } } } else { # We might need to change entry, if conference my $l_entry = $entry; if( ($dbase->{$hash}{bib_type} eq 'conference') && ($entry eq 'title') ) { $l_entry = 'booktitle'; } if( exists( $dbase->{$hash}{$l_entry} ) && $dbase->{$hash}{$l_entry} ) { $trtd .= $html->Tr( [ $html->td( [ $label{$l_entry}, $dbase->{$hash}{$l_entry} ] ), ] ); } } } # Okay, open the biblio entry file and print the entry. my $title = 'title'; $title = 'booktitle' if( $dbase->{$hash}{bib_type} eq 'conference' ); open( DOC, "> $fname") || die "DOC>$fname)$1 \n"; print DOC $html->start_html($dbase->{$hash}{$title}), $html->h1($dbase->{$hash}{$title}), $html->p($type), $html->table({-border => 1, -width => "100%" }, $trtd ), $html->end_html; close( DOC ); } } # Generate bibliographic entries for all books in a specific area, # interest or topic. The &summarize() function has links in its # main page to each $topic.html file. We want to build that # $topic.html file here. sub books_specific { my $h_specific = shift; # A hash of $Interest => $hash my $a_specific = shift; # Array of keys for above my $html = new CGI; # Sort by $dbase->{$hash}{title}, sort-of foreach my $hit (@{$a_specific}) { my $trtd2 = ''; # Each $hit is something like 'materials science and engineering' # We want to write out data to $hit.html my @hashes = split(/;/, $h_specific->{$hit}); my @sorted = sort { my $atitle = 'title'; $atitle = 'booktitle' if( $dbase->{$a}{bib_type} eq 'conference' ); my $btitle = 'title'; $btitle = 'booktitle' if( $dbase->{$b}{bib_type} eq 'conference' ); $dbase->{$a}{$atitle} cmp $dbase->{$b}{$btitle} } @hashes; # We have an area of expertise, area of topic interest, etc. and # a list of hashes (indexes) sorted ASCIIbetically by title of # document. Enough to generate HTML. Or, at least the table rows # of data. my $fname = "$hit" . '.html'; $fname =~ s/\s+/_/g; # No spaces in file name. $fname =~ s|/|-|g; # Or slashes. Or ......?? foreach my $doc (@sorted) { my $title = 'title'; $title = 'booktitle' if( $dbase->{$doc}{bib_type} eq 'conference' ); my $field = "$dbase->{$doc}{$title}"; my $type; if( $dbase->{$doc}{Book_Type} =~ /text/i ) { $type = 'Textbook'; } elsif( $dbase->{$doc}{Book_Type} =~ /reference/i ) { $type = 'Reference'; } else { $type = ''; } $trtd2 .= $html->Tr( [ $html->td( [ $field, $type ] ), ] ); # $label = ''; # Or   ??? Or undef??? } # Okay, write our $hit.html file. open( INTERESTS, "> $fname" ) || die "Interests($fname):$!\n"; $html = new CGI; print INTERESTS $html->start_html("Gordon Haverland: Self-Study: $hit"), $html->h1("Gordon Haverland: Self-Study: $hit"), $html->p( "The following documents are cataloged in", "Gordon Haverland's Self-Study bibliographic", "database as being topical to $hit.", ), $html->table({-border => 1, -width => "100%" }, $trtd2 ), $html->end_html; close( INTERESTS ); } } # While its possible that no title in a document will contain a particular # keyword, it is felt that titles are a good place to go looking for # keywords. sub check_title { my $string = shift; my $hash = shift; my( @two_words, @three_words ); # Do two things. Look at string for keywords and keyphrases, and # spell check string. my $str = $string; $str =~ s/\'s/ /g; # Suck up noun plurals/ownership $str =~ s/\W/ /g; # Punctuation $str =~ s/\s+/ /g; # Multiple spaces my @words = split( /\s+/, $str ); foreach my $word (@words) { # A kind of brain-damaged way to spell check. I have English and # American spellings, which causes problems with spell. I probably # should configure it to use a local dictionary too, as I have to put # plurals, etc. into exceptions hash too. if( exists( $SpellIgnore{$word} ) ) { # In local dictionary, so to speak # do nothing } else { unless( $speller->check( $word ) ) { my @suggestions = $speller->suggest( $word ); printf SPELL "(%s) in '%s': %s\n", $word, $string, join ' ', @suggestions; } } } # Try using Lingua::EN::Keywords. This module expects to be # handed text (sentences), and all I have are titles. It will # return at most? 6 keywords/keyphrases from that text. The text # does not have to be sentences. I'm keeping track of stuff on # a per-title basis, and then will also analyse the entire set # of titles. The first time through, I got a mixture of the longer # key phrases that occured few (once) times, and the simpler "words" # that occured the most times. Actually, implement what Keywords # uses from Tagger. # What happens when the text is # things like chemical elements? my @kwds = keywords( $string ); foreach my $kwd (@kwds) { next unless length( $kwd ) > 0; $dbase->{$hash}{keywordphrase}{$kwd} += &count_substr( $string, $kwd ); } } # Real brain damaged way to count substrings in string (non-overlapping). # It destroys a copy of the string while proceeding. Could use index, # substr, .... Any of which are faster. :-) sub count_substr { my $string = shift; my $substring = shift; $substring =~ s/([+.\?\(\)])/\\$1/g; my $count = 0; while( $string =~ s/$substring//i ) { $count++; } return( $count ); } sub in_each_other { my $string1 = shift; my $l1 = length( $string1 ); my $string2 = shift; my $l2 = length( $string2 ); # This could be more involved. Just look to see if one string is # in the other for now. if( $l2 > $l1 ) { if( index( $string2, $string1 ) > -1 ) { # It isn't enough for string1 to be inside string 2, there has to # be word boundaries at ends of string1 if( $string2 =~ /\b$string1\b/i ) { return 1; } else { return undef; } } else { return undef; } } else { # length( $string1 ) >= length( $string2 ); if( index( $string1, $string2 ) > -1 ) { if( $string1 =~ /\b$string2\b/i ) { return 1; } else { return undef; } } else { return undef; } } } sub about { # Print an about.html page my $html = new CGI; open( ABOUT, "> about.html" ) || die "About: $!\n"; print ABOUT $html->start_html('About Self-Study Summary'), $html->h1('About Self-Study Summary'), $html->p( "The HTML generated for the Self-Summary Page is largely", "the result of the perl CGI.pm module available from CPAN.", "The various pages generated are all calculated after", "eval'ing a perl (Dumper) structure that represents the", "data within the bilio-entry database. Or rather, an", "older version of the biblio-entry database.", "Changing the structure of that database will change the", "output produced by Dumper, and require changing bits and", "pieces of code throughout the program that writes the", "html html_it.pl.", "The program has the \".pl.txt\" ending so that it is easily", "interpretted as a text file. by your browser and my server.", ), $html->p( "Like a lot of good perl code, it runs with warnings turned", "on (/usr/bin/perl -w) and strict use of variables (use", "strict). This wasn't enough to keep from making the odd", "typing mistake in names of various (has) structure members,", "but it does help. The CGI.pm module is designed to help", "in generating dynamic pages and supporting CGI, but that", "certainly doesn't stop you from using it to calculate a", "static page based on something a perl program is doing.", "Dumper, is short for Data::Dumper, another module from", "CPAN. Quite useful in debugging, it can also be used", "to 'freeze' a perl structure to disk, and often was", "found used with MLDBM for making persistent perl data", "structures. Storable is probably used more for that", "now, certainly storable produces smaller output files", "in my experience. Dumper output is easier to edit with", "a text editor.", ), $html->p( "For the version of CGI I am using, and the options I set, the", "HTML I get is actually XHTML 1.0 Transitional. When I add", "manual stuff in my print statements (like anchors), I try to", "abide by XML inspired HTML and use lowercase markup that is", "properly nested and closed. Hence, the documents should", "parse as valid XML. There is no extraneous spaces in the", "HTML, which makes it a little hard for humans to work with.", ), $html->p( "I use Text::Aspell to help in spell checking the various", "titles. Titles tend to have a lot of jargon, and I support", "the jargon internally rather than trying to update some", "kind of personal dictionary file. You may need general", "aspell support in addition to the perl module.", ), $html->p( "Another module used, is Lingua::EN::Keywords, which is", "somewhat dependent on Lingua::EN::Tagger. If you are", "involved in text very much, you might want to see what", "the various Lingua modules can provide.", ), $html->p( "I am hardwiring the file name into the program which", "contains the dumper output. It probably should be a", "command line argument.", ), $html->p( "The program needs to lot of manual intervention, to", "help in spelling words (usually problems with jargon", "and names), and with keywords. The text file program", "has been edited, to remove most of this information.", "This editing cuts about half of the program out, stuff", "which is just data.", "You will also need to edit the program if you want to", "use it, to pick out your Areas, Interests, etc.", ), $html->p( "This program comes with the standard sort of OpenSource", "warranty. There is none (no warranty). It works for", "me, and if it helps you with something related to what", "I am doing, feel free to modify it. Keeping my Copyright", "in the program, of course. Please don't take email", "addresses in these sets of pages and programs to send", "spam (unsolicited email) to.", ), $html->p( "Gordon Haverland, Matter Realisations,", 'perl@materialisations.com, 2003/07/15', ), $html->end_html; close( ABOUT ); # Fun part. Parse this file (the program) as text, and copy # most of it to another file. All the stuff to be stripped # out is in the BEGIN subroutine. open( PERL, "> html_it.pl.txt" ) || die "Perl: $!\n"; open( SOURCE, "< $0" ) || die "Source: $!\n"; my( $line, $in_hash ); my $seen_BEGIN = 0; while( $line = ) { if( $seen_BEGIN == 0 ) { print PERL $line; $seen_BEGIN = 1 if( $line =~ /^BEGIN / ); } else { if( $line =~ /^\s+%/ ) { # Start of hash $in_hash = 1; print PERL $line; print PERL "\t'Example key' => 'Example Value',\n"; } elsif( $in_hash == 1 && $line =~ /^\s+\);$/ ) { $in_hash = 0; print PERL $line; } elsif( $in_hash == 0 ) { print PERL $line; } } } close( SOURCE ); close( PERL ); } BEGIN { # Initialise a bunch of data structures, which are partcular to my # particular interests in using this program. These could just as # easily be read in from a file. The "small" exception dictionary # probably should be properly set up for aspell, but this was easier. # Spelling exceptions. Names, acronyms and other stuff. # We are just checking boot/chapter/... titles. So, for the most part # everything should be capitalised (or present as lower and first # capitalized). In addition, there are LOTS of acronyms, which are # probably upper case. %SpellIgnore = ( '06' => 1, '10' => 1, '100' => 1, '12' => 1, '17' => 1, '1Ta' => 1, '20' => 1, '22' => 1, '2000' => 1, '2Cb' => 1, '2e' => 1, '21st' => 1, '25' => 1, '25wt' => 1, '27' => 1, '29' => 1, '3R' => 1, '30' => 1, '31' => 1, '38' => 1, '304' => 1, '316' => 1, '' => 1, '316L' => 1, '4V' => 1, '6Al' => 1, '67' => 1, '75' => 1, '8No' => 1, '80' => 1, '80th' => 1, '91' => 1, '101' => 1, '190' => 1, '1000' => 1, '1500' => 1, '1901' => 1, '1973' => 1, '1975' => 1, '1977' => 1, '1988' => 1, '1985' => 1, '1986' => 1, '1987' => 1, '1992' => 1, '1995' => 1, '2nd' => 1, '250T' => 1, '6XXX' => 1, '8Mo' => 1, 'A15' => 1, 'ActiveX' => 1, 'Adapter' => 1, 'ADSI' => 1, 'AEM' => 1, 'Aeolotropic' => 1, 'Aging' => 1, 'Alembert' => 1, 'Allotriomorphs' => 1, 'Alkoxides' => 1, 'alpha_1' => 1, 'Aluminum' => 1, 'Almaz' => 1, 'Amenorrhea' => 1, 'American' => 1, 'Anabolics' => 1, 'Analyses' => 1, 'Analysing' => 1, 'Anelastic' => 1, 'Anharmonic' => 1, 'Antiferromagnetic' => 1, 'Antiferromagnetism' => 1, 'API' => 1, 'APL' => 1, 'Aragonite' => 1, 'Armco' => 1, 'ARP' => 1, 'ASM' => 1, 'Athermal' => 1, 'ATM' => 1, 'Atomistics' => 1, 'Au_3Cu' => 1, 'Austempered' => 1, 'Austenite' => 1, 'Austenitic' => 1, 'Autoconfiguration' => 1, 'awk' => 1, 'Backson' => 1, 'Bainite' => 1, 'Bainitic' => 1, 'BBSPLVB' => 1, 'BCC' => 1, 'BCH' => 1, 'Behavior' => 1, 'Benefication' => 1, 'Bernoulli' => 1, 'Bernstein' => 1, 'Bessel' => 1, 'Bezier' => 1, 'BGP' => 1, 'Bidimensional' => 1, 'Biomechanics' => 1, 'Biorthogonal' => 1, 'Bismuthized' => 1, 'BOF' => 1, 'Bohr' => 1, 'Bonking' => 1, 'BOOTP' => 1, 'Brownian' => 1, 'BSPLPP' => 1, 'BSPLVD' => 1, 'BVALUE' => 1, 'BWR' => 1, 'Cadarache' => 1, 'Calcia' => 1, 'Calcic' => 1, 'CaO' => 1, 'CARICOM' => 1, 'Cartan' => 1, 'Cartesian' => 1, 'CD' => 1, 'CDF' => 1, 'CEA' => 1, 'Cementite' => 1, 'Center' => 1, 'Centers' => 1, 'CERN' => 1, 'Cesium' => 1, 'CGI' => 1, 'Chalcogens' => 1, 'Chalcogenide' => 1, 'ChAPP' => 1, 'Channeling' => 1, 'Chebyshev' => 1, 'Checkbutton' => 1, 'Cherenkov' => 1, 'CIDR' => 1, 'CIFS' => 1, 'Cislunar' => 1, 'Classful' => 1, 'Clickable' => 1, 'CNES' => 1, 'Cofunction' => 1, 'Cohomology' => 1, 'COLLOC' => 1, 'Color' => 1, 'Coloring' => 1, 'Columbium' => 1, 'Conconi' => 1, 'Convolutional' => 1, 'Coolability' => 1, 'Cooldown' => 1, 'CPAN' => 1, 'Cr_2O_3' => 1, 'CrN' => 1, 'CSS' => 1, 'CUBSPL' => 1, 'Cuyahoga' => 1, 'CVS' => 1, 'Daubechies' => 1, 'Dayhikes' => 1, 'Debye' => 1, 'Decarburization' => 1, 'Dendritic' => 1, 'Dephosphorization' => 1, 'Destructors' => 1, 'Desulfurization' => 1, 'Detraining' => 1, 'DHCP' => 1, 'Dialing' => 1, 'Diamagnetism' => 1, 'Diffractometric' => 1, 'Diffusionless' => 1, 'Dini' => 1, 'Displacive' => 1, 'Divacancy' => 1, 'DNS' => 1, 'DocBook' => 1, 'Dofasco' => 1, 'DTD' => 1, 'Duathlon' => 1, 'E10000' => 1, 'Eigensystems' => 1, 'Electroactive' => 1, 'Electrochemistry' => 1, 'Electrometallurgy' => 1, 'Electrooptical' => 1, 'Electrostriction' => 1, # 'Ents' => 1, 'eqn' => 1, 'Equilibria' => 1, 'Ergogenic' => 1, 'Ergogenics' => 1, 'Eutectics' => 1, 'Eutectoid' => 1, 'EXAFS' => 1, 'Exobiological' => 1, 'Expotition' => 1, 'Expectk' => 1, 'Extremum' => 1, 'Faraday' => 1, 'Fartlek' => 1, 'Fermat' => 1, 'Ferrimagnetism' => 1, 'Ferritic' => 1, 'Ferroalloys' => 1, 'Ferrohydrodynamic' => 1, 'Ferrohydrodynamics' => 1, 'Ferromagnetism' => 1, 'FEXPRs' => 1, 'Feynman' => 1, 'Fiber' => 1, 'Filesystems' => 1, 'FO' => 1, 'FP' => 1, 'Formulas' => 1, 'Fourier' => 1, 'Fredholm' => 1, 'Fugacities' => 1, 'Galerkin' => 1, 'Gavaskar' => 1, 'Georeferences' => 1, 'GIS' => 1, 'GLONASS' => 1, 'GPS' => 1, 'Graphitisation' => 1, 'H_x' => 1, 'Haar' => 1, 'Hamilton' => 1, 'Hamiltonian' => 1, 'Harbor' => 1, 'Hardenability' => 1, 'HCP' => 1, 'Heffalump' => 1, 'Heffalumps' => 1, 'Heva' => 1, 'Hilbert' => 1, 'Holloman' => 1, 'Homoscedasticity' => 1, 'HTGR' => 1, 'HTML' => 1, 'HTML4' => 1, 'HTTP' => 1, 'Huckingen' => 1, 'Huygen' => 1, 'HVEM' => 1, 'Hydrolytic' => 1, 'Hydrometallurgy' => 1, 'Hypergeometric' => 1, 'Hypersurfaces' => 1, 'Hyperthermia' => 1, 'IAP' => 1, 'ICMP' => 1, 'Iditarod' => 1, 'Iliotibial' => 1, 'imake' => 1, 'Imake' => 1, 'imakefile' => 1, 'Imakefile' => 1, 'imakefiles' => 1, 'Imakefiles' => 1, 'IMAP' => 1, 'Integumentary' => 1, 'Intercritical' => 1, 'Interstitials' => 1, 'Intervariant' => 1, 'Intragranular' => 1, 'IPS' => 1, 'Inextensional' => 1, 'Inline' => 1, 'INMARSAT' => 1, 'Interfacial' => 1, 'Intermetallic' => 1, 'internet' => 1, 'Internetworking' => 1, 'Interphase' => 1, 'Interpolatory' => 1, 'INTERV' => 1, 'Intimidators' => 1, 'IOR' => 1, 'IP' => 1, 'IPC' => 1, 'IPsec' => 1, 'IPv6' => 1, 'Ironman' => 1, 'ISCOR' => 1, 'Ising' => 1, 'Isoperimetric' => 1, 'Jacobi' => 1, 'Java' => 1, 'JavaScript' => 1, 'Javascript' => 1, 'JNDI' => 1, 'JumpStart' => 1, 'KD_2PO_4' => 1, 'Kinematical' => 1, 'L1_0' => 1, 'Labor' => 1, 'Lamellar' => 1, 'Laplace' => 1, 'LBE' => 1, 'LDAP' => 1, 'LDIF' => 1, 'LOCA' => 1, 'Kondo' => 1, 'Korn' => 1, 'L2APPR' => 1, 'Labeling' => 1, 'Lanczos' => 1, 'libpq' => 1, 'Liouville' => 1, 'Lipschitz' => 1, 'Listbox' => 1, 'LWP' => 1, 'Macros' => 1, 'MACROs' => 1, 'Magnetocaloric' => 1, 'Magnetostatics' => 1, 'MainWindow' => 1, 'Mallat' => 1, 'Mammas' => 1, 'Mannesmannrohren' => 1, 'Martensite' => 1, 'Martensites' => 1, 'Martensitic' => 1, 'Martensitically' => 1, 'Merwe' => 1, 'Mesoatomic' => 1, 'Mesomolecular' => 1, 'Mesoscopic' => 1, 'METAFONT' => 1, 'METAFONTbook' => 1, 'METAPOST' => 1, 'Metrology' => 1, 'Mg2Si' => 1, 'Microdensitometry' => 1, 'Microprobe' => 1, 'Microstructure' => 1, 'Microstructures' => 1, 'Microstructural' => 1, 'Microcanonical' => 1, 'Middleware' => 1, 'Minkowski' => 1, 'MnS' => 1, 'Modeled' => 1, 'Modeling' => 1, 'Monatomic' => 1, 'Monolayer' => 1, 'Monovacancy' => 1, 'MoSi2' => 1, 'MSP' => 1, 'Multicasting' => 1, 'Multicritical' => 1, 'Multiparticle' => 1, 'Multiscale' => 1, 'Multisolution' => 1, 'NH_4Br' => 1, 'NH_4Cl' => 1, 'Nanosatellite' => 1, 'NCSA' => 1, 'NDE' => 1, 'Nernst' => 1, 'Nervosa' => 1, 'Netnews' => 1, 'NEWNOT' => 1, 'Newsrc' => 1, 'NGOs' => 1, 'Ni_3Al' => 1, 'Ni_4Mo' => 1, 'NiAl' => 1, 'NiO' => 1, 'NIS' => 1, 'NiTi' => 1, 'NiTiCu' => 1, 'NiV' => 1, 'NNTP' => 1, 'NNTPClient' => 1, 'Nonautonomous' => 1, 'Nondiffusive' => 1, 'Nonhomogeneous' => 1, 'Nonisothermal' => 1, 'Nonnewtonian' => 1, 'Nonperiodic' => 1, 'NSCAA' => 1, 'Octants' => 1, 'OFX' => 1, 'Online' => 1, 'Orthopyroxene' => 1, 'OSPF' => 1, 'Overtraining' => 1, 'Oxyfuel' => 1, 'PDE' => 1, 'Pearlite' => 1, 'Perfluoropolyalkylether' => 1, 'Periodization' => 1, 'perl' => 1, 'PerLDAP' => 1, 'PFPE' => 1, 'Phebus' => 1, 'Phonons' => 1, 'Photoacoustic' => 1, 'Photoelectron' => 1, 'PHP' => 1, 'Piezoresistivity' => 1, 'Piezooptical' => 1, 'Plagioclase' => 1, 'Pluribus' => 1, 'Plutonism' => 1, 'Plyometric' => 1, 'Plyometrics' => 1, 'Polarisation' => 1, 'Polya' => 1, 'Polycomponent' => 1, 'Polycondensation' => 1, 'Polyhedra' => 1, 'Poohstick' => 1, 'PostgreSQL' => 1, 'PostScript' => 1, 'PPVALU' => 1, 'Practice' => 1, 'Practiced' => 1, 'Practices' => 1, 'Preceramic' => 1, 'Preformatted' => 1, 'Premartensitic' => 1, 'Prerace' => 1, 'Proeutectoid' => 1, 'Proven' => 1, 'Pseudopotential' => 1, 'PSTricks' => 1, 'pTk' => 1, 'PWR' => 1, 'Quadrics' => 1, 'Quasiconvex' => 1, 'Radiobutton' => 1, 'Radiotracer' => 1, 'Raman' => 1, 'Ramanujan' => 1, 'RAAM' => 1, 'RARP' => 1, 'Ratfor' => 1, 'RbNO_3' => 1, 'Regolith' => 1, 'Rentier' => 1, 'Replacive' => 1, 'Repurposing' => 1, 'Rham' => 1, 'Riemannian' => 1, 'Rlogin' => 1, 'Rolo' => 1, 'Roo' => 1, 'Rootfinding' => 1, 'ROText' => 1, 'Roundings' => 1, 'RPC' => 1, 'RTP' => 1, 'Sarcofag' => 1, 'Scaleable' => 1, 'Schemas' => 1, 'SDK' => 1, 'SDKs' => 1, 'Semiclassical' => 1, 'Semivariants' => 1, 'sendmail' => 1, 'SGML' => 1, 'Si3N4' => 1, 'SiC' => 1, 'Silceram' => 1, 'Simulant' => 1, 'Sintering' => 1, 'SLP' => 1, 'SMB' => 1, 'SNMP' => 1, 'Snowblindness' => 1, 'Solaris' => 1, 'Solmer' => 1, 'SOLVEs' => 1, 'Spectroscopies' => 1, 'SPLOPT' => 1, 'SQL' => 1, 'Starfire' => 1, 'STCP' => 1, 'Stelco' => 1, 'Steelmaking' => 1, 'Stereochemical' => 1, 'Stereomicroscopy' => 1, 'Stroh' => 1, 'Strawman' => 1, 'Stylesheet' => 1, 'Subgrain' => 1, 'Sublance' => 1, 'Sublances' => 1, 'Substitutional' => 1, 'Sunil' => 1, 'Superalloys' => 1, 'Superledges' => 1, 'Supersociation' => 1, 'SVG' => 1, 'Tabu' => 1, 'tbl' => 1, 'TAUTSP' => 1, 'Tcl' => 1, 'Termcap' => 1, 'Terminfo' => 1, 'Tetris' => 1, 'TeXbook' => 1, 'TextUndo' => 1, 'TFTP' => 1, 'Thermalhydraulic' => 1, 'Thermalhydraulics' => 1, 'Thermochemistry' => 1, 'Thermohydraulics' => 1, 'Thermostatistics' => 1, 'Tigger' => 1, 'Tinley' => 1, 'TiC' => 1, 'TiN' => 1, 'TiNi' => 1, 'Tk' => 1, 'TMI' => 1, 'Toplevel' => 1, 'Trailheads' => 1, 'Tribocorrosion' => 1, 'Tribodiagnostics' => 1, 'Tribological' => 1, 'Tribology' => 1, 'Tricritical' => 1, 'tRNA' => 1, 'TTT' => 1, 'Tundish' => 1, 'Tunneling' => 1, 'twm' => 1, 'Typeglobs' => 1, 'UDP' => 1, 'UO2' => 1, 'Ultramarathon' => 1, 'UnBounced' => 1, 'Undumping' => 1, 'Unknot' => 1, 'Unsymmetric' => 1, 'Unum' => 1, 'URIs' => 1, 'Vajda' => 1, 'Vapor' => 1, 'Vapors' => 1, 'Varifolds' => 1, 'VBScript' => 1, 'VGP' => 1, 'VLSI' => 1, 'VO_2max' => 1, 'VoiceXML' => 1, 'Voronoi' => 1, 'VPN' => 1, 'VRML' => 1, 'Vulcain' => 1, 'VVER' => 1, 'Waterjet' => 1, 'WATFIV' => 1, 'WATFOR' => 1, 'WebSite' => 1, 'Weldability' => 1, 'Werke' => 1, 'WIDL' => 1, 'Windchill' => 1, 'Woozle' => 1, 'WSB' => 1, 'Wurtzite' => 1, 'X11' => 1, 'XINU' => 1, 'XLL' => 1, 'XML' => 1, 'XOFF' => 1, 'XON' => 1, 'XPath' => 1, 'XSC' => 1, 'XSL' => 1, 'XSLT' => 1, 'XTAL' => 1, 'Zener' => 1, 'Zircalloy' => 1, 'Zirconia' => 1, 'Zr_2Al' => 1, ); %MyArea = ( 'Materials Science and Engineering' => 1, 'Nuclear Engineering' => 1, 'Information Technologies' => 1, 'Physics' => 1, 'Mathematics' => 1, 'Statistics' => 1, 'Business/Commerce' => 1, 'Sports/Fitness' => 1, # '' => 1, ); %MyInterest = ( 'Algorithms' => 0, 'Biomedical' => 0, 'C/C++' => 0, 'Calculus' => 0, 'Ceramics' => 0, 'Chemical/Physical Analysis Methods' => 0, 'Common Gateway Interface' => 0, 'Composites' => 0, 'Condensed Matter Physics' => 0, 'Crystal Physics' => 0, 'Database' => 0, 'Deformation' => 0, 'Desktop Publishing' => 0, 'Dielectrics' => 0, 'Differential Equations' => 0, 'DocBook' => 0, 'Dynamics' => 0, 'Elasticity' => 0, 'Expect' => 0, 'Extractive Metallurgy' => 0, 'Extraterrestrial Materials' => 0, 'Failure Analysis' => 0, 'Field Theory' => 0, 'FORTRAN' => 0, 'Fracture Mechanics' => 0, 'Fusion/Welding/Brazing/Soldering' => 0, 'Geographical Information Systems' => 0, 'Geometry' => 0, 'Global Positioning System' => 0, 'HTML' => 0, 'HTTP' => 0, 'Hydrodynamics' => 0, 'Information Architecture' => 0, 'Information Theory' => 0, 'In-Situ Resource Utilization' => 0, 'Interpolation/Approximation' => 0, 'Interprocess Communication' => 0, 'JavaScript' => 0, 'Kinetics' => 0, 'LDAP' => 0, 'Linear Systems' => 0, 'Magnetism' => 0, 'Mechanics/Kinematics' => 0, 'Metals' => 0, 'Mineral Processing' => 0, 'Mining' => 0, 'NDE/NDT' => 0, 'Network Administration' => 0, 'Networking' => 0, 'Nuclear Fusion' => 0, 'Nuclear Physics' => 0, 'Numerical Methods' => 0, 'Object Oriented Programming' => 0, 'Optics' => 0, 'Perl' => 0, 'PHP' => 0, 'Probability' => 0, 'Programming Language' => 0, 'Quality Control' => 0, 'Quantum Mechanics' => 0, 'Radiation Physics' => 0, 'Relativity' => 0, 'Semiconductors' => 0, 'SGML' => 0, 'Signal Processing' => 0, 'Simulation/Modeling' => 0, 'Source Code Management' => 0, 'Space Transportation' => 0, 'Statistical Mechanics' => 0, 'Statistics' => 0, 'Surface Chemistry' => 0, 'Surface Physics' => 0, 'System Administration' => 0, 'Tcl' => 0, 'Tensors' => 0, 'TeX' => 0, 'Thermodynamics' => 0, 'Tk' => 0, 'Topology' => 0, 'Transforms' => 0, 'Transport' => 0, 'UNIX/Linux' => 0, 'User Interfaces' => 0, 'Vector Analysis' => 0, 'Wavelets' => 0, 'Wood' => 0, 'XML' => 0, 'XSL-FO' => 0, ); # The following table of "Synonym"s are not synonyms in the sense that # the terms in the list can be subsituted for the key of the hash; rather # if the key in the hash is a topic of the bibliography entry, then we # might reasonably expect these other terms to also be present. %Synonym = ( # 'algorithms' => [ # ], # 'biomedical' => [ # ], 'calculus' => [ 'integral', 'integrals', 'derivative', 'derivatives', 'complex variable', 'real variable', 'functionals', ], # 'ceramics' => [ # ], 'chemical/physical analysis methods' => [ 'scanning calorimetry', 'calorimetry', ], 'common gateway interface' => [ 'cgi', ], # 'composites' => [ # ], 'condensed matter physics' => [ 'periodic lattices', 'lattices', 'crystals', 'crystalline', ], # 'crystal physics' => [ # ], 'database' => [ 'postgresql', 'postgres', 'libpq', 'mysql', 'embedded sql', 'sql', ], 'deformation' => [ 'deformable', 'strain', 'plastic deformation', ], # 'desktop publishing' => [ # ], # 'dielectrics' => [ # ], 'differential equations' => [ 'differential equation', 'ordinary differential equation', 'ordinary-differential', 'partial differential equation', 'partial-differential', 'predictor-corrector', 'boundary value problems', 'boundary value problem', ], # 'docbook' => [ # ], # 'dynamics' => [ # ], 'elasticity' => [ 'isotropic elastic', 'elastic sphere', 'elastic', ], # 'expect' => [ # ], # 'extractive metallurgy' => [ # ], # 'extraterrestrial materials' => [ # ], # 'failure analysis' => [ # ], # 'field theory' => [ # ], 'fracture mechanics' => [ 'fracture toughness', 'stress intensity', ], 'fusion/welding/brazing/soldering' => [ 'metal joining', ], 'geographical information systems' => [ 'gis applications', 'geostatistics', 'spatial databases', ], 'geometry' => [ 'analytic geometry', ], 'global positioning system' => [ 'gps', ], 'html' => [ 'hypertext markup language', ], 'http' => [ 'hypertext transport protocol', ], # 'hydrodynamics' => [ # ], # 'information architecture' => [ # ], # 'information theory' => [ # ], # 'in-situ resource utilization' => [ # ], 'interpolation/approximation' => [ 'approximations', 'interpolation', ], # 'interprocess communication' => [ # ], # 'javascript' => [ # ], # 'kinetics' => [ # ], # 'ldap' => [ # ], 'linear systems' => [ 'linear algebra', 'linear models', 'systems of linear equations', ], 'magnetism' => [ 'ferrimagnetism', 'ferromagnetism', 'anti-ferromagnetism', 'magnetic field', 'magnetic behavior', 'spin glasses', 'magnetic fluids', 'ferrohydrodynamic', 'magnetocaloric', 'magnet', ], 'mechanics/kinematics' => [ 'analytical mechanics', 'equations of motion', 'virtual work', ], 'metals' => [ 'extractive metallurgy', 'extraction metallurgy', 'hydrometallurgy', 'electrometallurgy', 'metallurgy', 'steels', 'alloys', 'aluminum', 'magnesium', 'titanium', 'copper', 'nickel', ], # 'mineral processing' => [ # ], # 'mining' => [ # ], # 'nde/ndt' => [ # ], # 'network administration' => [ # ], 'networking' => [ 'internet protocol', 'transport control protocol', 'tcp/ip', 'internet', 'ftp', 'smb/cifs', 'smb', 'cifs', 'server', 'socket', 'sockets', ], # 'nuclear fusion' => [ # ], 'nuclear physics' => [ 'nuclear scattering', 'neutron scattering', ], # 'numerical methods' => [ # ], # 'object oriented programming' => [ # ], 'optics' => [ 'refractive', 'refraction', ], 'perl' => [ 'cpan', 'modules', ], # 'php' => [ # ], # 'probability' => [ # ], # 'programming language' => [ # ], # 'quality control' => [ # ], # 'quantum mechanics' => [ # ], 'radiation physics' => [ 'scintillation', ], 'relativity' => [ 'relativistic', ], 'semiconductors' => [ 'p-n junctions', 'n-p junctions', 'p-i-n junctions', ], # 'SGML' => [ # ], # 'signal processing' => [ # ], # 'simulation' => [ # ], # 'source code management' => [ # ], 'space transportation' => [ 'x-38', ], 'statistical mechanics' => [ 'statistical physics', 'thermostatistics', 'microcanonical ensemble', 'grand canonical ensemble', 'canonical ensemble', 'fermi distribution', 'bose-einstein', 'fermi-dirac', ], 'statistics' => [ 'least squares', 'regression', 'anova', 'analysis of variance', 'variance', 'cross-classified', 'catgorical', 'goodness of fit', 'estimation of population', 'quality control', 'quality circle', 'design of experiments', ], # 'surface chemistry' => [ # ], # 'surface physics' => [ # ], 'system administration' => [ 'log files', ], # 'tcl' => [ # ], 'tensors' => [ 'tensor algebra', 'tensor analysis', ], 'thermodynamics' => [ 'helmholtz free energy', 'gibbs free energy', 'free energy', 'equilibrium', 'phase transformation', 'phase transformations', 'thermodynamic', 'entropy', 'enthalpy', ], # 'tk' => [ # ], 'topology' => [ 'crossing number', 'crossing numbers', 'measure theory', ], 'transforms' => [ 'fourier', 'laplace', ], 'transport' => [ 'laminar', 'turbulent', 'diffusion', 'diffusive', 'mass transfer', 'heat transfer', 'separation processes', 'separation process', 'hydrodynamic', 'conduction', 'convection', 'fluid mechanics', ], 'user interfaces' => [ 'widget', 'widgets', ], 'vector analysis' => [ 'vector calculus', 'stokes theorem', ], 'wavelets' => [ 'daubechies', ], 'wood' => [ 'timber', 'timbers', ], 'xml' => [ 'xpath', 'xsl', 'xslt', ], # 'xsl-fo' => [ # ], ); }