Diff for /loncom/interface/lonsearchcat.pm between versions 1.16 and 1.58

version 1.16, 2001/03/15 17:55:59 version 1.58, 2001/03/21 03:37:43
Line 2 Line 2
 # Search Catalog  # Search Catalog
 #  #
 # 03/08/2001 Scott Harrison  # 03/08/2001 Scott Harrison
   # Scott Harrison: 03/12/2001, 03/13/2001, 03/14/2001, 03/15/2001, 03/19/2001
   # Scott Harrison: 03/20/2001
 #  #
   # Functions
   #
   # handler(server reference) : interacts with the Apache server layer
   #                             (for /adm/searchcat URLs)
   # simpletextfield(name,value) : returns HTML formatted string for simple text
   #                               field
   # simplecheckbox(name,value) : returns HTML formatted string for simple
   #                              checkbox
   # searchphrasefield(title,name,value) : returns HTML formatted string for
   #                                       a search expression phrase field
   # dateboxes(name, defaultmonth, defaultday, defaultyear) : returns HTML
   #                                                          formatted string
   #                                                          for a calendar date
   # selectbox(title,name,value,%HASH=options) : returns HTML formatted string for
   #                                             a selection box field
   # advancedsearch(server reference, environment reference) : perform a complex
   #                                  multi-field logical query
   # filled(field) : determines whether a given field has been filled
   # basicsearch(server reference, environment reference) : perform a simple
   #                               single-field logical query
   # output_blank_field_error(server reference) : outputs a message saying that
   #                                              more fields need to be filled in
   # output_results(output mode,
   #                server reference, 
   #                environment reference,
   #                reply list reference) : outputs results from search
   # build_SQL_query(field name, logic) : builds a SQL query string from a
   #                                      logical expression with AND/OR keywords
   # recursive_SQL_query_build(field name, reverse notation expression) : 
   #                 builds a SQL query string from a reverse notation expression
   #                 logical expression with AND/OR keywords
   
 package Apache::lonsearchcat;  package Apache::lonsearchcat;
   
 use strict;  use strict;
Line 10  use Apache::Constants qw(:common); Line 44  use Apache::Constants qw(:common);
 use Apache::lonnet();  use Apache::lonnet();
 use Apache::File();  use Apache::File();
 use CGI qw(:standard);  use CGI qw(:standard);
   use Text::Query;
   
 my %language;  my %language;
 my $scrout;  my $scrout;
 my %metadatafields;  my %metadatafields;
 my %cprtag;  my %cprtag;
 my %mimetag;  my %mimetag;
   my $closebutton;
   my $basicviewselect=<<END;
   <select name='basicviewselect'>
   <option value='Detailed Citation View'>Detailed Citation View</option>
   <option value='Summary View'>Summary View</option>
   <option value='Fielded Format'>Fielded Format</option>
   <option value='XML/SGML'>XML/SGML</option>
   </select>
   END
   my $advancedviewselect=<<END;
   <select name='advancedviewselect'>
   <option value='Detailed Citation View'>Detailed Citation View</option>
   <option value='Summary View'>Summary View</option>
   <option value='Fielded Format'>Fielded Format</option>
   <option value='XML/SGML'>XML/SGML</option>
   </select>
   END
   
 sub handler {  sub handler {
     my $r = shift;      my $r = shift;
Line 41  sub handler { Line 93  sub handler {
 <input type='hidden' name='catalogmode' value='interactive'>  <input type='hidden' name='catalogmode' value='interactive'>
 END  END
   
       $closebutton=<<END if $ENV{'form.catalogmode'} eq 'interactive';
   <input type="button" name="close" value="CLOSE" onClick="self.close()">
   END
   
 # ------------------------------------------------ First, check out environment  # ------------------------------------------------ First, check out environment
     $metadatafields{'owner'}=$ENV{'user.name'}.'@'.$ENV{'user.domain'};      $metadatafields{'owner'}=$ENV{'user.name'}.'@'.$ENV{'user.domain'};
   
Line 51  END Line 107  END
     {      {
  my $fh=Apache::File->new($r->dir_config('lonTabDir').'/language.tab');   my $fh=Apache::File->new($r->dir_config('lonTabDir').'/language.tab');
  map {   map {
     $_=~/(\w+)\s+([\w\s\-]+)/;      $_=~/(\w+)\s+([\w\s\-]+)/; chomp;
     $language{$1}=$2;      $language{$1}=$2;
  } <$fh>;   } <$fh>;
     }      }
Line 61  END Line 117  END
     {      {
  my $fh=Apache::File->new($r->dir_config('lonIncludes').'/copyright.tab');   my $fh=Apache::File->new($r->dir_config('lonIncludes').'/copyright.tab');
  map {   map {
     $_=~/(\w+)\s+([\w\s\-]+)/;      $_=~/(\w+)\s+([\w\s\-]+)/; chomp;
     $cprtag{$1}=$2;      $cprtag{$1}=$2;
  } <$fh>;   } <$fh>;
     }      }
Line 71  END Line 127  END
     {      {
  my $fh=Apache::File->new($r->dir_config('lonTabDir').'/filetypes.tab');   my $fh=Apache::File->new($r->dir_config('lonTabDir').'/filetypes.tab');
  map {   map {
     $_=~/(\w+)\s+(\w+)\s+([\w\s\-]+)/;      $_=~/(\w+)\s+(\w+)\s+([\w\s\-]+)/; chomp;
     $mimetag{$1}=".$1 $3";      $mimetag{$1}=".$1 $3";
  } <$fh>;   } <$fh>;
     }      }
   
     if ($ENV{'form.basicsubmit'} eq 'SEARCH') {      if ($ENV{'form.basicsubmit'} eq 'SEARCH') {
  return &basicsearch($r,$ENV{'form.basicexp'});   return &basicsearch($r,\%ENV);
       }
       elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {
    return &advancedsearch($r,\%ENV);
     }      }
   
     $scrout=''; # building a part of screen output      $scrout=''; # building a part of screen output
Line 210  ENDDOCUMENT Line 269  ENDDOCUMENT
 <br>  <br>
 <input type="submit" name="basicsubmit" value="SEARCH">  <input type="submit" name="basicsubmit" value="SEARCH">
 <input type="reset" name="reset" value="RESET">  <input type="reset" name="reset" value="RESET">
 <input type="button" name="close" value="CLOSE" onClick="self.close()">  $closebutton
   $basicviewselect
 </p>  </p>
 <hr>  <hr>
 <h3>Advanced Search</h3>  <h3>Advanced Search</h3>
Line 218  $scrout Line 278  $scrout
 <p>  <p>
 <input type="submit" name="advancedsubmit" value="SEARCH">  <input type="submit" name="advancedsubmit" value="SEARCH">
 <input type="reset" name="reset" value="RESET">  <input type="reset" name="reset" value="RESET">
 <input type="button" name="close" value="CLOSE" onClick="self.close()">  $closebutton
   $advancedviewselect
 </p>  </p>
 </form>  </form>
 </body>  </body>
Line 229  ENDDOCUMENT Line 290  ENDDOCUMENT
   
 # --------------------------------------------------------- Various form fields  # --------------------------------------------------------- Various form fields
   
 sub textfield {  
     my ($title,$name,$value)=@_;  
     return "\n<p><b>$title:</b><br>".  
            '<input type=text name="'.$name.'" size=80 value="'.$value.'">';  
 }  
   
 sub simpletextfield {  sub simpletextfield {
     my ($name,$value)=@_;      my ($name,$value)=@_;
     return '<input type=text name="'.$name.'" size=20 value="'.$value.'">';      return '<input type=text name="'.$name.'" size=20 value="'.$value.'">';
Line 416  sub selectbox { Line 471  sub selectbox {
     return $selout.'</select>';      return $selout.'</select>';
 }  }
   
 # --------------------------------------------------- Performing a basic search  # ----------------------------------------------- Performing an advanced search
 sub basicsearch {  sub advancedsearch {
     my ($r,$expression)=@_;      my ($r,$envhash)=@_;
       my %ENV=%{$envhash};
   
       my $fillflag=0;
       for my $field ('title','author','subject','keywords','url','version',
      'notes','abstract','mime','language','owner',
      'custommetadata') {
    if (&filled($ENV{"form.$field"})) {
       $fillflag++;
    }
       }
   
     my $query=$expression;      unless ($fillflag) {
     $query="select * from metadata where concat(title,\"    \",author) like '\%$expression\%'";   &output_blank_field_error($r);
 #    my $reply=&Apache::lonnet::reply("querysend:$query",'msul3');   return OK;
     my $reply=&Apache::lonnet::metadata_query($query);      }
   
     my @results;      my $query='';
   
     my $replyfile='';      my @queries;
     $reply=~/^([\.\w]+)$/; # must do since 'use strict' checks for tainting      # Go through logical expression AND/OR/NOT phrase fields.
     $replyfile=$r->dir_config('lonDaemons').'/tmp/'.$1;  
     $reply=~/(.*?)\_/;  
     my $hostname=$1;  
   
     {      foreach my $field ('title','author','subject','notes','abstract','url',
  while (1) {         'keywords','version','owner') {
     last if -e $replyfile;   if ($ENV{'form.'.$field}) {
     sleep 1;      push @queries,&build_SQL_query($field,$ENV{'form.'.$field});
  }   }
  # QUESTION: how should I handle this error condition..  
  # I'm sure there is syntax elsewhere I can use..  
  my $fh=Apache::File->new($replyfile) or  
        ($r->print('file cannot be opened') and return OK);  
        @results=<$fh>;  
     }      }
       if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {
    push @queries,"language like $ENV{'form.language'}";
       }
       if ($ENV{'form.mime'} and $ENV{'form.mime'} ne 'any') {
    push @queries,"mime like $ENV{'form.mime'}";
       }
       if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') {
    push @queries,"copyright like $ENV{'form.copyright'}";
       }
       if (@queries) {
    $query=join(" AND ",@queries);
    $query="select * from metadata where $query";
    my $reply=&Apache::lonnet::metadata_query($query);
    &output_results('Advanced',$r,$envhash,$query,$reply);
       }
       else {
    &output_results('Advanced',$r,$envhash,$query);
       }
       return OK;
   }
   
     my $compiledresult='';  # ---------------------------------------------------- see if a field is filled
   sub filled {
     foreach my $result (@results) {      my ($field)=@_;
  my ($title,$author,$subject,$url,$keywords,$version,      if ($field=~/\S/) {
     $notes,$abstract,$mime,$lang,   return 1;
     $creationdate,$lastrevisiondate,$owner,$copyright      }
     )=map {&Apache::lonnet::unescape($_)} (split(/\,/,$result));      else {
  my $shortabstract=$abstract;   return 0;
  $shortabstract=substr($abstract,0,200) if length($abstract)>200;      }
  $compiledresult.=<<END;  
 <p>  
 END  
  $compiledresult.=<<END if $ENV{'form.catalogmode'} eq 'interactive';  
 <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"  
 onClick="javascript:select_data('$title','$url')">  
 </font>  
 <br>  
 END  
         $compiledresult.=<<END;  
 <b>URL: </b> <A HREF='http://spock.lite.msu.edu/res/msu/shh1/poobah1.html' TARGET='search_preview'>$url</A><br>  
 <b>Title:</b> $title<br>  
 <b>Author(s):</b> $author<br>  
 <b>Subject:</b> $subject<br>  
 <b>Keyword(s):</b> $keywords<br>  
 <b>Notes:</b> $notes<br>  
 <b>Abstract:</b> $shortabstract<br>  
 <b>MIME Type:</b> $mimetag{$mime}<br>  
 <b>Language:</b> $language{$lang}<br>  
 <b>Creation Date:</b> $creationdate<br>  
 <b>Last Revision Date:</b> $lastrevisiondate<br>  
 <b>Publisher/Owner:</b> $owner<br>  
 <b>Copyright/Distribution:</b> $copyright<br>  
 <b>Repository Location:</b> $hostname  
 </p>  
 END  
 }  }
   
     unless ($compiledresult) {  # --------------------------------------------------- Performing a basic search
  $compiledresult="There were no results that matched your query";  sub basicsearch {
       my ($r,$envhash)=@_;
       my %ENV=%{$envhash};
   
       unless (&filled($ENV{'form.basicexp'})) {
    &output_blank_field_error($r);
    return OK;
     }      }
   
       my $query='';
       my $concatarg=join(',"    ",',
          ('title', 'author', 'subject', 'notes', 'abstract'));
   
       $query="select * from metadata where concat($concatarg) like '\%$ENV{'form.basicexp'}\%'";
       my $reply=&Apache::lonnet::metadata_query($query);
       &output_results('Basic',$r,$envhash,$query,$reply);
       return OK;
   }
   
   # ---------------- Message to output when there are not enough fields filled in
   sub output_blank_field_error {
       my ($r)=@_;
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
     my $persistent='';      my $persistent='';
     map {      map {
Line 504  END Line 574  END
 <head>  <head>
 <title>The LearningOnline Network with CAPA</title>  <title>The LearningOnline Network with CAPA</title>
 BEGINNING  BEGINNING
     $r->print(<<SCRIPT) if $ENV{'form.catalogmode'} eq 'interactive';      $r->print(<<RESULTS);
   </head>
   <body bgcolor="#ffffff">
   <img align=right src=/adm/lonIcons/lonlogos.gif>
   <h1>Search Catalog</h1>
   <form method="post" action="/adm/searchcat">
   $persistent
   <input type='button' value='Revise search request'
   onClick='this.form.submit();'>
   $closebutton
   <hr>
   <h3>Helpful Message</h3>
   <p>
   Incorrect search query due to blank entry fields.
   You need to fill in the relevant
   fields on the search page in order for a query to be
   processed.
   </p>
   </body>
   </html>
   RESULTS
   }
   
   # ----------------------------- format and output results based on a reply list
   sub output_results {
       my ($mode,$r,$envhash,$query,@replylist)=@_;
       my %ENV=%{$envhash};
       my $compiledresult='';
   
       foreach my $reply (@replylist) {
   
    my @results;
   
    my $replyfile='';
    $reply=~/^([\.\w]+)$/; # must do since 'use strict' checks for tainting
    $replyfile=$r->dir_config('lonDaemons').'/tmp/'.$1;
    $reply=~/(.*?)\_/;
    my $hostname=$1;
    sleep 3; # temporary fix, need to check for completion and status
    {
       while (1) {
    last if -e $replyfile;
    sleep 1;
       }
       # QUESTION: how should I handle this error condition..
       # I'm sure there is syntax elsewhere I can use..
       my $fh=Apache::File->new($replyfile) or
    ($r->print('file cannot be opened') and return OK);
       @results=<$fh>;
    }
   
    foreach my $result (@results) {
       my @fields=map
                      {&Apache::lonnet::unescape($_)}
                      (split(/\,/,$result));
       my ($title,$author,$subject,$url,$keywords,$version,
    $notes,$abstract,$mime,$lang,
    $creationdate,$lastrevisiondate,$owner,$copyright)=@fields;
       my $shortabstract=$abstract;
       $shortabstract=substr($abstract,0,200) if length($abstract)>200;
       $fields[7]=$shortabstract;
       $compiledresult.=<<END;
   <p>
   END
               $compiledresult.=<<END if $ENV{'form.catalogmode'} eq 'interactive';
   <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"
   onClick="javascript:select_data('$title','$url')">
   </font>
   <br>
   END
               my $httphost=$ENV{'HTTP_HOST'};
   
       my $viewselect;
       if ($mode eq 'Basic') {
    $viewselect=$ENV{'form.basicviewselect'};
       }
       elsif ($mode eq 'Advanced') {
    $viewselect=$ENV{'form.advancedviewselect'};
       }
   
               if ($viewselect eq 'Detailed Citation View') {
    $compiledresult.=&detailed_citation_view(@fields,
    $hostname,$httphost);
       }
               elsif ($viewselect eq 'Summary View') {
    $compiledresult.=&summary_view(@fields,$hostname,$httphost);
       }
               elsif ($viewselect eq 'Fielded Format') {
    $compiledresult.=&fielded_format_view(@fields,$hostname,
         $httphost);
       }
               elsif ($viewselect eq 'XML/SGML') {
    $compiledresult.=&xml_sgml_view(@fields,$hostname,$httphost);
       }
   
           }
   
    unless ($compiledresult) {
       $compiledresult="There were no results that matched your query";
    }
   
    # make query information persistent to allow for subsequent revision
    my $persistent='';
    map {
       if (/^form\./ && !/submit/) {
    my $name=$_;
    my $key=$name;
    $name=~s/^form\.//;
    $persistent.=<<END;
   <INPUT TYPE='hidden' NAME='$name' VALUE='$ENV{$key}'>
   END
               }
    } (keys %ENV);
   
    $r->print(<<BEGINNING);
   <html>
   <head>
   <title>The LearningOnline Network with CAPA</title>
   BEGINNING
           $r->print(<<SCRIPT) if $ENV{'form.catalogmode'} eq 'interactive';
 <script>  <script>
     function select_data(title,url) {      function select_data(title,url) {
  changeTitle(title);   changeTitle(title);
Line 522  BEGINNING Line 711  BEGINNING
     }      }
 </script>  </script>
 SCRIPT  SCRIPT
     $r->print(<<RESULTS);          $r->print(<<RESULTS);
 </head>  </head>
 <body bgcolor="#ffffff">  <body bgcolor="#ffffff">
 <img align=right src=/adm/lonIcons/lonlogos.gif>  <img align=right src=/adm/lonIcons/lonlogos.gif>
Line 530  SCRIPT Line 719  SCRIPT
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 <input type='button' value='Revise search request'  <input type='button' value='Revise search request'
 onClick='this.form.submit();'>  onClick='this.form.submit();'>
 <input type='button' value='CLOSE'  $closebutton
 onClick='self.close();'>  
 $persistent  $persistent
 <hr>  <hr>
 <h3>Search Query</h3>  <h3>Search Query</h3>
   RESULTS
       if ($mode eq 'Basic') {
    $r->print(<<RESULTS);
 <p>  <p>
 <b>Basic search:</b> $expression  <b>Basic search:</b> $ENV{'form.basicexp'}
 </p>  </p>
   RESULTS
       }
       elsif ($mode eq 'Advanced') {
    $r->print(<<RESULTS);
   <p>
   <b>Advanced search</b>
   $query
   </p>
   RESULTS
       }
    $r->print(<<RESULTS);
 <h3>Search Results</h3>  <h3>Search Results</h3>
 $compiledresult  $compiledresult
 </body>  </body>
 </html>  </html>
 RESULTS  RESULTS
       }
   }
   
     return OK;  # ------------------------------------------------------------- build_SQL_query
   sub build_SQL_query {
       my ($field_name,$logic_statement)=@_;
       my $q=new Text::Query('abc',
     -parse => 'Text::Query::ParseAdvanced',
     -build => 'Text::Query::Build');
       $q->prepare($logic_statement);
       my $matchexp=${$q}{'matchexp'}; chomp $matchexp;
       my $sql_query=&recursive_SQL_query_build($field_name,$matchexp);
       return $sql_query;
   }
   
   # - Recursively parse a reverse notation expression into a SQL query expression
   sub recursive_SQL_query_build {
       my ($dkey,$pattern)=@_;
       my @matches=($pattern=~/(\[[^\]|\[]*\])/g);
       return $pattern unless @matches;
       foreach my $match (@matches) {
    $match=~/\[ (\w+)\s(.*) \]/;
    my ($key,$value)=($1,$2);
    my $replacement='';
    if ($key eq 'literal') {
       $replacement="($dkey like \"\%$value\%\")";
    }
    elsif ($key eq 'and') {
       $value=~/(.*[\"|\)]) ([|\(|\^].*)/;
       $replacement="($1 AND $2)";
    }
    elsif ($key eq 'or') {
       $value=~/(.*[\"|\)]) ([|\(|\^].*)/;
       $replacement="($1 OR $2)";
    }
    substr($pattern,
          index($pattern,$match),
          length($match),
          $replacement
          );
       }
       &recursive_SQL_query_build($dkey,$pattern);
   }
   
   # ------------------------------------------------------ Detailed Citation View
   sub detailed_citation_view {
       my ($title,$author,$subject,$url,$keywords,$version,
    $notes,$shortabstract,$mime,$lang,
    $creationdate,$lastrevisiondate,$owner,$copyright,
    $hostname,$httphost)=@_;
       my $result=<<END;
   <i>$owner</i>, last revised $lastrevisiondate
   <h3><A HREF="http://$httphost$url" TARGET='search_preview'>$title</A></h3>
   <h3>$author</h3>
   </p>
   <p>
   <b>Subject:</b> $subject<br>
   <b>Keyword(s):</b> $keywords<br>
   <b>Notes:</b> $notes<br>
   <b>MIME Type:</b> $mimetag{$mime}<br>
   <b>Language:</b> $language{$lang}<br>
   <b>Copyright/Distribution:</b> $cprtag{$copyright}<br>
   $shortabstract
   </p>
   END
       return $result;
   }
   
   # ---------------------------------------------------------------- Summary View
   sub summary_view {
       my ($title,$author,$subject,$url,$keywords,$version,
    $notes,$shortabstract,$mime,$lang,
    $creationdate,$lastrevisiondate,$owner,$copyright,
    $hostname,$httphost)=@_;
       my $result=<<END;
   <a href="http://$httphost$url" TARGET='search_preview'>$author</a><br />
   $title<br />
   $owner -- $lastrevisiondate<br />
   $cprtag{$copyright}<br />
   </p>
   END
       return $result;
   }
   
   # -------------------------------------------------------------- Fielded Format
   sub fielded_format_view {
       my ($title,$author,$subject,$url,$keywords,$version,
    $notes,$shortabstract,$mime,$lang,
    $creationdate,$lastrevisiondate,$owner,$copyright,
    $hostname,$httphost)=@_;
       my $result=<<END;
   <b>URL: </b> <A HREF="http://$httphost$url" TARGET='search_preview'>$url</A>
   <br />
   <b>Title:</b> $title<br />
   <b>Author(s):</b> $author<br />
   <b>Subject:</b> $subject<br />
   <b>Keyword(s):</b> $keywords<br />
   <b>Notes:</b> $notes<br />
   <b>MIME Type:</b> $mimetag{$mime}<br />
   <b>Language:</b> $language{$lang}<br />
   <b>Creation Date:</b> $creationdate<br />
   <b>Last Revision Date:</b> $lastrevisiondate<br />
   <b>Publisher/Owner:</b> $owner<br />
   <b>Copyright/Distribution:</b> $cprtag{$copyright}<br />
   <b>Repository Location:</b> $hostname<br />
   <b>Abstract:</b> $shortabstract<br />
   </p>
   END
       return $result;
   }
   
   # -------------------------------------------------------------------- XML/SGML
   sub xml_sgml_view {
       my ($title,$author,$subject,$url,$keywords,$version,
    $notes,$shortabstract,$mime,$lang,
    $creationdate,$lastrevisiondate,$owner,$copyright,
    $hostname,$httphost)=@_;
       my $result=<<END;
   <pre>
   &lt;LonCapaResource&gt;
   &lt;url&gt;$url&lt;/url&gt;
   &lt;title&gt;$title&lt;/title&gt;
   &lt;author&gt;$author&lt;/author&gt;
   &lt;subject&gt;$subject&lt;/subject&gt;
   &lt;keywords&gt;$keywords&lt;/keywords&gt;
   &lt;notes&gt;$notes&lt;/notes&gt;
   &lt;mimeInfo&gt;
   &lt;mime&gt;$mime&lt;/mime&gt;
   &lt;mimetag&gt;$mimetag{$mime}&lt;/mimetag&gt;
   &lt;/mimeInfo&gt;
   &lt;languageInfo&gt;
   &lt;language&gt;$lang&lt;/language&gt;
   &lt;languagetag&gt;$language{$lang}&lt;/languagetag&gt;
   &lt;/languageInfo&gt;
   &lt;creationdate&gt;$creationdate&lt;/creationdate&gt;
   &lt;lastrevisiondate&gt;$lastrevisiondate&lt;/lastrevisiondate&gt;
   &lt;owner&gt;$owner&lt;/owner&gt;
   &lt;copyrightInfo&gt;
   &lt;copyright&gt;$copyright&lt;/copyright&gt;
   &lt;copyrighttag&gt;$cprtag{$copyright}&lt;/copyrighttag&gt;
   &lt;/copyrightInfo&gt;
   &lt;repositoryLocation&gt;$hostname&lt;/repositoryLocation&gt;
   &lt;shortabstract&gt;$shortabstract&lt;/shortabstract&gt;
   &lt;/LonCapaResource&gt;
   </pre>
   END
       return $result;
 }  }
   
 1;  1;

Removed from v.1.16  
changed lines
  Added in v.1.58


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>