changeset 1:548a93c24e55 release_0_1jk

Tema 0.1jk - Javakonkurs edition (imported from CVS).
author Mikhail Kryshen <mikhail@kryshen.net>
date Thu, 14 Dec 2006 23:22:05 +0300 (2006-12-14)
parents 1d2fe61a3a62
children 6c41a0b43e58
files TODO build.xml dist/biotopes/biotope.template dist/biotopes/classes.template dist/biotopes/doc/article.txt dist/biotopes/doc/readme.html dist/biotopes/doc/readme.txt dist/biotopes/main.template dist/biotopes/photo.template dist/biotopes/plants.template dist/readme.html dist/readme.txt dist/tema dist/tema.bat dist/tema.properties doc/article.txt doc/manual/index.html res/kryshen/tema/demo/demo.template sample/class.xml sample/plants.xml src/kryshen/tema/Function.java src/kryshen/tema/FunctionDataParser.java src/kryshen/tema/Functions.java src/kryshen/tema/ImageConverter.java src/kryshen/tema/ReplaceWriter.java src/kryshen/tema/Tema.java src/kryshen/tema/TemplateException.java src/kryshen/tema/TemplateParser.java src/kryshen/tema/TemplateReader.java src/kryshen/tema/demo/DemoFrame.java src/kryshen/tema/demo/Hello.java src/kryshen/tema/functions/Define.java src/kryshen/tema/functions/IO.java src/kryshen/tema/functions/ImageConverter.java src/kryshen/tema/functions/Logics.java src/kryshen/tema/functions/ReplaceWriter.java src/kryshen/tema/functions/Standard.java test/Hello.class test/Hello.java test/demo test/demo.bat test/include.template test/inctest.template test/macrotest test/main.template test/tema.properties
diffstat 46 files changed, 2612 insertions(+), 1412 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TODO	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,1 @@
+if, <, >, =, +, -, *, /
--- a/build.xml	Tue May 16 18:04:09 2006 +0400
+++ b/build.xml	Thu Dec 14 23:22:05 2006 +0300
@@ -5,6 +5,7 @@
     <property name="build"    value="build"/>
     <property name="dist"     value="dist"/>
     <property name="res"      value="res"/>
+    <property name="doc"      value="doc"/>
     <property name="jar_file" value="tema.jar"/>
 
     <target name="init">
@@ -14,20 +15,30 @@
 
     <target name="compile" depends="init">
         <javac srcdir="${src}" destdir="${build}"
-               deprecation="on" optimize="on" debug="on"/>
+               deprecation="on" optimize="on" debug="on">
+          <!-- <compilerarg value="-Xlint:unchecked"/> -->
+        </javac>
     </target>
 
     <target name="dist" depends="compile">
 	<jar jarfile="${dist}/${jar_file}" manifest="${src}/Manifest.mf">
 	    <fileset dir="${build}" includes="**/*.class"/>
+	    <fileset dir="${res}" includes="**/*"/>
 	</jar>
-    </target>    
+    </target>
 
+    <target name="javadoc" depends="init">
+        <javadoc destdir="${doc}/api" sourcepath="${src}"
+                 packagenames="kryshen.tema.*">
+        </javadoc>
+    </target>
+ 
     <target name="clean">
 	<delete>
 	    <fileset dir="${build}" includes="**/*.class"/>
 	</delete>
 	<delete file="${dist}/${jar_file}"/>
+	<delete dir="${doc}/api"/>
     </target>
     
 </project>
--- a/dist/biotopes/biotope.template	Tue May 16 18:04:09 2006 +0400
+++ b/dist/biotopes/biotope.template	Thu Dec 14 23:22:05 2006 +0300
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="ISO-8859-5"?>
 <!DOCTYPE ÞߨáÐÝØÕ_ÒØÔÐ SYSTEM "brief.dtd">
-<!-- rangcode: <%xml_escape get\rangcode%> -->
+<!-- rangcode: <%xml_escape db\rangcode%> -->
 <ÞߨáÐÝØÕ_ÒØÔÐ show="0">
   <àØáãÝÚØ display="0">
-    <%optional:<ÚÐàâÐ_àÐáßàÞáâàÐÝÕÝØï ÝÞÜÕà="1" file="<%xml_escape image:maps/<%get\rangcode%>.gif maps/<%get\code%>.png png%>"/>%>
+    <%optional:<ÚÐàâÐ_àÐáßàÞáâàÐÝÕÝØï ÝÞÜÕà="1" file="<%xml_escape image:maps/<%db\rangcode%>.gif maps/<%db\code%>.png png%>"/>%>
 <%query:photo_sql [%\<%include\photo.template%>%] <%get\code%>%>
   </àØáãÝÚØ>
-  <ÝÐ×ÒÐÝØÕ><%xml_escape get\rusname%></ÝÐ×ÒÐÝØÕ>
-  <ÚÛÐáá><%xml_escape get\class0%></ÚÛÐáá>
-  <ßÞÔÚÛÐáá1><%xml_escape get\class1%></ßÞÔÚÛÐáá1>
-  <ßÞÔÚÛÐáá2><%xml_escape get\class2%></ßÞÔÚÛÐáá2>
-  <ßÞÔÚÛÐáá3><%xml_escape get\class3%></ßÞÔÚÛÐáá3>
-  <ÚàÐâÚÐï_åÐàÐÚâÕàØáâØÚÐ rows="3"><%xml_cdata get\descript%></ÚàÐâÚÐï_åÐàÐÚâÕàØáâØÚÐ>
-  <ßàØÜÕà_ÞߨáÐÝØï rows="3"><%xml_cdata get\geobotdescr%></ßàØÜÕà_ÞߨáÐÝØï>
-  <ÐÒâÞàë_ÞߨáÐÝØï><%xml_escape get\contributors%></ÐÒâÞàë_ÞߨáÐÝØï>
+  <ÝÐ×ÒÐÝØÕ><%xml_escape db\rusname%></ÝÐ×ÒÐÝØÕ>
+  <ÚÛÐáá><%xml_escape db\class0%></ÚÛÐáá>
+  <ßÞÔÚÛÐáá1><%xml_escape db\class1%></ßÞÔÚÛÐáá1>
+  <ßÞÔÚÛÐáá2><%xml_escape db\class2%></ßÞÔÚÛÐáá2>
+  <ßÞÔÚÛÐáá3><%xml_escape db\class3%></ßÞÔÚÛÐáá3>
+  <ÚàÐâÚÐï_åÐàÐÚâÕàØáâØÚÐ rows="3"><%xml_cdata db\descript%></ÚàÐâÚÐï_åÐàÐÚâÕàØáâØÚÐ>
+  <ßàØÜÕà_ÞߨáÐÝØï rows="3"><%xml_cdata db\geobotdescr%></ßàØÜÕà_ÞߨáÐÝØï>
+  <ÐÒâÞàë_ÞߨáÐÝØï><%xml_escape db\contributors%></ÐÒâÞàë_ÞߨáÐÝØï>
 </ÞߨáÐÝØÕ_ÒØÔÐ>
--- a/dist/biotopes/classes.template	Tue May 16 18:04:09 2006 +0400
+++ b/dist/biotopes/classes.template	Thu Dec 14 23:22:05 2006 +0300
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-5"?>
 <ÚÛÐááØäØÚÐæØï><%query:class_sql [%\
   <!-- rangcode: <%xml_escape get\rangcode%> -->
-  <ÚÛÐáá id="<%get\NUMBER%>"><%xml_escape get\rusname%></ÚÛÐáá>%]%>
+  <ÚÛÐáá id="<%get\NUMBER%>"><%xml_escape db\rusname%></ÚÛÐáá>%]%>
 </ÚÛÐááØäØÚÐæØï>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/biotopes/doc/article.txt	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,391 @@
+* ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÂÁÚÙ ÄÁÎÎÙÈ × XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ ÂÉÂÌÉÏÔÅËÉ.
+
+äÌÑ ÒÅÛÅÎÉÑ ÚÁÄÁÞÉ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ ÂÁÚÙ ÄÁÎÎÙÈ "íÅÓÔÏÏÂÉÔÁÎÉÑ ÷ÏÓÔÏÞÎÏÊ
+æÅÎÎÏÓËÁÎÄÉÉ" ÉÚ ÆÏÒÍÁÔÁ Microsoft Access × XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ
+ÂÉÂÌÉÏÔÅËÉ ëÁÒîã òáî ÂÙÌÁ ÒÁÚÒÁÂÏÔÁÎÁ ÐÒÏÇÒÁÍÍÎÁÑ ÓÉÓÔÅÍÁ DbReader.
+
+ðÒÏÇÒÁÍÍÁ DbReader Ñ×ÌÑÅÔÓÑ ÕÎÉ×ÅÒÓÁÌØÎÙÍ ÓÒÅÄÓÔ×ÏÍ ÄÌÑ ÐÒÅÄÓÔÁ×ÌÅÎÉÑ
+ÉÎÆÏÒÍÁÃÉÉ ÉÚ ÂÁÚ ÄÁÎÎÙÈ × ÔÅËÓÔÏ×ÙÈ ÆÏÒÍÁÔÁÈ. ðÒÏÇÒÁÍÍÁ ÏÂÒÁÂÁÔÙ×ÁÅÔ
+ÚÁÄÁÎÎÙÅ ÛÁÂÌÏÎÙ ÔÅËÓÔÏ×ÙÈ ÆÁÊÌÏ× É ÚÁÍÅÎÑÅÔ ÎÁÊÄÅÎÎÙÅ × ÎÉÈ
+ÉÎÓÔÒÕËÃÉÉ ÎÁ ÒÅÚÕÌØÔÁÔÙ ÉÈ ×ÙÐÏÌÎÅÎÉÑ. òÁÚÌÉÞÎÙÅ ÉÎÓÔÒÕËÃÉÉ ÐÏÚ×ÏÌÑÀÔ
+ÆÏÒÍÉÒÏ×ÁÔØ SQL-ÚÁÐÒÏÓÙ, ×ÙÐÏÌÎÑÔØ ÉÈ É ÏÂÒÁÂÁÔÙ×ÁÔØ ÐÏÌÕÞÅÎÎÙÅ
+ÄÁÎÎÙÅ.
+
+
+* æÏÒÍÁÔ ÉÎÓÔÒÕËÃÉÊ:
+
+    <%<ÓÐÉÓÏË_ÆÕÎËÃÉÊ>{:|\}<ÄÁÎÎÙÅ>%>
+  ÇÄÅ 
+
+<ÓÐÉÓÏË_ÆÕÎËÃÉÊ> - ÓÐÉÓÏË ÉÍÅÎ ÆÕÎËÃÉÊ, ÒÁÚÄÅÌÅÎÎÙÈ ÐÒÏÂÅÌÁÍÉ.
+    íÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ.
+<ÄÁÎÎÙÅ> - ÄÁÎÎÙÅ, ÐÅÒÅÄÁ×ÁÅÍÙÅ ÆÕÎËÃÉÉ.
+
+
+* æÏÒÍÁÔ ÄÁÎÎÙÈ:
+
+    [<ÓÐÉÓÏË_ÁÒÇÕÍÅÎÔÏ×>][<ÔÅËÓÔ>]
+  ÇÄÅ
+
+<ÓÐÉÓÏË_ÁÒÇÕÍÅÎÔÏ×> - ÓÐÉÓÏË ÁÒÇÕÍÅÎÔÏ× ÆÕÎËÃÉÉ, ÒÁÚÄÅÌÅÎÎÙÈ ÐÒÏÂÅÌÁÍÉ.
+    íÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ.
+<ÔÅËÓÔ> - ÔÅËÓÔ, ÐÅÒÅÄÁ×ÁÅÍÙÊ ÆÕÎËÃÉÉ ÂÅÚ ÒÁÚÂÉÅÎÉÑ ÎÁ ÁÒÇÕÍÅÎÔÙ.
+    íÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ. ëÏÌÉÞÅÓÔ×Ï ÁÒÇÕÍÅÎÔÏ×, ÐÏÓÌÅ ËÏÔÏÒÏÇÏ ÓÌÅÄÕÅÔ
+    ÔÅËÓÔ, ÚÁ×ÉÓÉÔ ÏÔ ÆÕÎËÃÉÉ.
+
+òÁÚÄÅÌÉÔÅÌØ ÍÅÖÄÕ ÓÐÉÓËÏÍ ÆÕÎËÃÉÊ É ÄÁÎÎÙÍÉ ÏÐÒÅÄÅÌÑÅÔ, ËÁË ÄÏÌÖÎÙ
+ÏÂÒÁÂÁÔÙ×ÁÔØÓÑ ÄÁÎÎÙÅ ÆÕÎËÃÉÉ:
+: - ÒÅËÕÒÓÉ×ÎÁÑ ÏÂÒÁÂÏÔËÁ,
+\ - ÐÅÒÅÄÁÔØ ÂÅÚ ÏÂÒÁÂÏÔËÉ.
+
+åÓÌÉ × ÓÐÉÓËÅ ÆÕÎËÃÉÊ ÚÁÄÁÎÏ Ä×Å É ÂÏÌÅÅ ÆÕÎËÃÉÉ, ÏÎÉ ×ÙÐÏÌÎÑÀÔÓÑ,
+ÎÁÞÉÎÁÑ Ó ÐÏÓÌÅÄÎÅÊ, ÔÁË ÞÔÏ ËÁÖÄÁÑ ÆÕÎËÃÉÑ ÐÏÌÕÞÁÅÔ × ËÁÞÅÓÔ×Å ÄÁÎÎÙÈ
+ÒÅÚÕÌØÔÁÔ ×ÙÐÏÌÎÅÎÉÑ ÓÌÅÄÕÀÝÅÊ ÆÕÎËÃÉÉ.
+
+ëÁÖÄÁÑ ÆÕÎËÃÉÑ ÉÍÅÅÔ ËÏÄ ×ÏÚ×ÒÁÔÁ - ÃÅÌÏÅ ÞÉÓÌÏ. ëÏÄ ×ÏÚ×ÒÁÔÁ
+ÉÎÓÔÒÕËÃÉÉ - ËÏÄ ×ÏÚ×ÒÁÔÁ ÐÅÒ×ÏÊ × ÓÐÉÓËÅ ÆÕÎËÃÉÉ. ëÏÄ ×ÏÚ×ÒÁÔÁ,
+ÐÏÌÕÞÁÅÍÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ - ÓÕÍÍÁ ËÏÄÏ× ×ÏÚ×ÒÁÔÁ ÏÂÒÁÂÏÔÁÎÎÙÈ
+ÉÎÓÔÒÕËÃÉÊ.
+
+÷ÍÅÓÔÏ ÓËÏÂÏË '<', '>' ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÓËÏÂËÉ '[', ']'.
+
+
+* òÅÁÌÉÚÏ×ÁÎÎÙÅ ÆÕÎËÃÉÉ:
+
+æÕÎËÃÉÑ:      set
+áÒÇÕÍÅÎÔÙ:    <ÉÍÑ>
+ôÅËÓÔ:        <ÚÎÁÞÅÎÉÅ>
+äÅÊÓÔ×ÉÅ:     ÕÓÔÁÎÁ×ÌÉ×ÁÅÔ ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ <ÉÍÑ>
+òÅÚÕÌØÔÁÔ:    <ÉÍÑ>
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1
+
+æÕÎËÃÉÑ:      get
+áÒÇÕÍÅÎÔÙ:    <ÉÍÑ>
+òÅÚÕÌØÔÁÔ:    ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ <ÉÍÑ>. 
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1, ÅÓÌÉ ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ ÂÙÌÏ ÕÓÔÁÎÏ×ÌÅÎÏ, 0 - ÉÎÁÞÅ.
+
+æÕÎËÃÉÑ:      prepare
+áÒÇÕÍÅÎÔÙ:    <ÉÍÑ>
+ôÅËÓÔ:        <ÚÁÐÒÏÓ>
+äÅÊÓÔ×ÉÅ:     ðÏÄÇÏÔÁ×ÌÉ×ÁÅÔ SQL-ÚÁÐÒÏÓ <ÚÁÐÒÏÓ> ÄÌÑ ×ÙÐÏÌÎÅÎÉÑ,
+              ÚÁÐÉÓÙ×ÁÅÔ ÐÏÄÇÏÔÏ×ÌÅÎÎÙÊ ÚÁÐÒÏÓ × ÐÅÒÅÍÅÎÎÕÀ <ÉÍÑ>.
+òÅÚÕÌØÔÁÔ:    <ÉÍÑ>
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1
+
+æÕÎËÃÉÑ:      query
+áÒÇÕÍÅÎÔÙ:    <ÉÍÑ_ÚÁÐÒÏÓÁ> <ÛÁÂÌÏÎ> <ÐÁÒÁÍ1> ... <ÐÁÒÁÍN>
+äÅÊÓÔ×ÉÅ:     ÷ÙÐÏÌÎÑÅÔ ÚÁÐÒÏÓ Ó ÐÁÒÁÍÅÔÒÁÍÉ, ÐÏÄÇÏÔÏ×ÌÅÎÎÙÊ Ó ÐÏÍÏÝØÀ
+              ÆÕÎËÃÉÉ prepare. úÎÁÞÅÎÉÑ ÐÁÒÁÍÅÔÒÏ× ÐÏÄÓÔÁ×ÌÑÀÔÓÑ ×
+              ÚÁÐÒÏÓ ×ÍÅÓÔÏ ÓÉÍ×ÏÌÁ '?'. úÎÁÞÅÎÉÑ ÐÏÌÅÊ ÏÔ×ÅÔÁ ÂÕÄÕÔ
+              ÚÁÐÉÓÁÎÙ, ËÁË ÐÅÒÅÍÅÎÎÙÅ ÛÁÂÌÏÎÁ <ÛÁÂÌÏÎ>. ðÒÉ ÏÂÒÁÂÏÔËÉ
+              ÛÁÂÌÏÎÁ <ÛÁÂÌÏÎ> ÔÁËÖÅ ÏÐÒÅÄÅÌÑÅÔÓÑ ÐÅÒÅÍÅÎÎÁÑ NUMBER,
+              ÓÏÄÅÒÖÁÝÁÑ ÎÏÍÅÒ ÔÅËÕÝÅÊ ÓÔÒÏËÉ ÏÔ×ÅÔÁ. ðÅÒÅÍÅÎÎÙÅ,
+              ÏÐÒÅÄÅÌÅÎÎÙÅ × ×ÙÚÙ×ÁÀÝÅÍ ÛÁÂÌÏÎÅ, ÄÏÓÔÕÐÎÙ ÉÚ ÛÁÂÌÏÎÁ
+              <ÛÁÂÌÏÎ> ÐÏ ÉÍÅÎÉ SUPER.<ÉÍÑ_ÐÅÒÅÍÅÎÎÏÊ>.
+
+òÅÚÕÌØÔÁÔ:    ÒÅÚÕÌØÔÁÔ ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ <ÛÁÂÌÏÎ> ÄÌÑ ËÁÖÄÏÊ ÓÔÒÏËÉ
+              ÏÔ×ÅÔÁ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÌÉÞÅÓÔ×Ï ÐÏÌÕÞÅÎÎÙÈ ÓÔÒÏË ÏÔ×ÅÔÁ.
+
+æÕÎËÃÉÑ:      optional
+ôÅËÓÔ:        <ÄÁÎÎÙÅ>
+òÅÚÕÌØÔÁÔ:    <ÄÁÎÎÙÅ>, ÅÓÌÉ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÄÁÎÎÙÈ ÂÙÌ ÐÏÌÕÞÅÎ
+              ËÏÄ ×ÏÚ×ÒÁÔÁ ÏÔÌÉÞÎÙÊ ÏÔ 0, ÉÎÁÞÅ - ÐÕÓÔÁÑ ÓÔÒÏËÁ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1, ÅÓÌÉ ÒÅÚÕÌØÔÁÔ - ÐÕÓÔÁÑ ÓÔÒÏËÁ, 0 - ÉÎÁÞÅ.
+
+æÕÎËÃÉÑ:      image
+áÒÇÕÍÅÎÔÙ:    <ÉÓÈ_ÆÁÊÌ> <ËÏÎ_ÆÁÊÌ> <ÆÏÒÍÁÔ> [<ÍÁËÓ_ÛÉÒÉÎÁ> [<ÍÁËÓ_×ÙÓÏÔÁ>]]
+äÅÊÓÔ×ÉÅ:     úÁÇÒÕÖÁÅÔ ÉÚÏÂÒÁÖÅÎÉÅ ÉÚ ÆÁÊÌÁ <ÉÓÈ_ÆÁÊÌ> (ÐÕÔØ ÏÐÒÅÄÅÌÑÅÔÓÑ
+              ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base") É
+              ÐÒÅÏÂÒÁÚÕÅÔ ÅÇÏ × ÕËÁÚÁÎÎÙÊ ÆÏÒÍÁÔ, ÓÏÈÒÁÎÑÑ ÒÅÚÕÌØÔÁÔ ×
+              <ËÏÎ_ÆÁÊÌ>. åÓÌÉ ÚÁÄÁÎÙ ÍÁËÓÉÍÁÌØÎÁÑ ×ÙÓÏÔÁ É ÛÉÒÉÎÁ, ÂÏÌØÛÉÅ
+              ÉÚÏÂÒÁÖÅÎÉÑ ÂÕÄÕÔ ÕÍÅÎØÛÅÎÙ. 
+òÅÚÕÌØÔÁÔ:    <ËÏÎ_ÆÁÊÌ> ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ ÓÔÒÏËÁ - ÉÎÁÞÅ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
+
+æÕÎËÃÉÑ:      copy
+áÒÇÕÍÅÎÔÙ:    <ÉÓÈ_ÆÁÊÌ> <ËÏÎ_ÆÁÊÌ>
+äÅÊÓÔ×ÉÅ:     ëÏÐÉÒÕÅÔ ÆÁÊÌ <ÉÓÈ_ÆÁÊÌ> × ÆÁÊÌ <ËÏÎ_ÆÁÊÌ>
+	      (ÐÕÔØ <ÉÓÈ_ÆÁÊÌ> ÏÐÒÅÄÅÌÑÅÔÓÑ ÏÔÎÏÓÉÔÅÌØÎÏ
+              ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base").
+òÅÚÕÌØÔÁÔ:    <ËÏÎ_ÆÁÊÌ> ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ ÓÔÒÏËÁ - ÉÎÁÞÅ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
+
+æÕÎËÃÉÑ:      write
+áÒÇÕÍÅÎÔÙ:    <ÉÍÑ_ÆÁÊÌÁ>
+ôÅËÓÔ:        <ÄÁÎÎÙÅ>
+äÅÊÓÔ×ÉÅ:     úÁÐÉÓÙ×ÁÅÔ <ÄÁÎÎÙÅ> × ÆÁÊÌ <ÉÓÈ_ÆÁÊÌ>.
+òÅÚÕÌØÔÁÔ:    <ËÏÎ_ÆÁÊÌ> ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ ÓÔÒÏËÁ - ÉÎÁÞÅ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
+
+æÕÎËÃÉÑ:      read
+ôÅËÓÔ:        <ÉÍÑ_ÆÁÊÌÁ>
+äÅÊÓÔ×ÉÅ:     þÉÔÁÅÔ ÆÁÊÌ <ÉÍÑ_ÆÁÊÌÁ>.
+òÅÚÕÌØÔÁÔ:    ÐÒÏÞÉÔÁÎÎÙÅ ÄÁÎÎÙÅ ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ
+              ÓÔÒÏËÁ - ÉÎÁÞÅ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
+
+æÕÎËÃÉÑ:      include
+ôÅËÓÔ:        <ÉÍÑ_ÆÁÊÌÁ>
+äÅÊÓÔ×ÉÅ:     ×ËÌÀÞÁÅÔ ÛÁÂÌÏÎ ÉÚ ÆÁÊÌÁ <ÉÍÑ_ÆÁÊÌÁ>.
+òÅÚÕÌØÔÁÔ:    ÒÅÚÕÌØÔÁÔ ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÛÁÂÌÏÎÁ.
+
+æÕÎËÃÉÑ:      !
+ôÅËÓÔ:        <ÄÁÎÎÙÅ>
+äÅÊÓÔ×ÉÅ:     ÎÅÔ.
+òÅÚÕÌØÔÁÔ:    ÎÅÔ.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
+
+æÕÎËÃÉÑ:      replace
+áÒÇÕÍÅÎÔÙ:    <ÓÔÒ1> <ÓÔÒ2>
+ôÅËÓÔ:        <ÄÁÎÎÙÅ>
+òÅÚÕÌØÔÁÔ:    ÄÁÎÎÙÅ, Ó ÚÁÍÅÎÅÎÎÙÍÉ ×ÈÏÖÄÅÎÉÑÍÉ ÐÏÄÓÔÒÏËÉ <ÓÔÒ1>
+	      ÎÁ <ÓÔÒ2>.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
+
+æÕÎËÃÉÑ:      xml_escape
+ôÅËÓÔ:        <ÄÁÎÎÙÅ>
+òÅÚÕÌØÔÁÔ:    ÔÅËÓÔ <ÄÁÎÎÙÅ>, × ËÏÔÏÒÏÍ  ÓÉÍ×ÏÌÙ
+              '&', '<', '>', '`', '\' ÚÁÍÅÎÅÎÙ ÎÁ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÅ
+	      ÓÕÝÎÏÓÔÉ XML.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
+
+æÕÎËÃÉÑ:      xml_cdata
+ôÅËÓÔ:        <ÄÁÎÎÙÅ>
+òÅÚÕÌØÔÁÔ:    ÄÁÎÎÙÅ × ×ÉÄÅ ÂÌÏËÁ XML CDATA.
+ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
+
+óÉÓÔÅÍÁ DbReader ÒÁÓÛÉÒÑÅÍÁ: ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÌÅÎÉÅ × ÓÉÓÔÅÍÕ ÎÏ×ÙÈ
+ÆÕÎËÃÉÊ, ÒÅÁÌÉÚÏ×ÁÎÎÙÈ × ×ÉÄÅ ËÌÁÓÓÏ× ÎÁ ÑÚÙËÅ Java.
+
+
+* ðÒÉÍÅÎÅÎÉÅ ÓÉÓÔÅÍÙ DbReader ÄÌÑ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ ÂÁÚÙ ÄÁÎÎÙÈ
+  "íÅÓÔÏÏÂÉÔÁÎÉÑ ÷ÏÓÔÏÞÎÏÊ æÅÎÎÏÓËÁÎÄÉÉ" ÉÚ ÆÏÒÍÁÔÁ Microsoft Access ×
+  XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ ÂÉÂÌÉÏÔÅËÉ ëÁÒîã òáî
+
+äÌÑ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ ÉÓÐÏÌØÚÕÀÔÓÑ Ä×Å ÔÁÂÌÉÃÙ ÂÁÚÙ ÄÁÎÎÙÈ "íÅÓÔÏÏÂÉÔÁÎÉÑ
+÷ÏÓÔÏÞÎÏÊ æÅÎÎÏÓËÁÎÄÉÉ" (ÐÅÒÅÞÉÓÌÅÎÙ ÔÏÌØËÏ ÉÓÐÏÌØÚÕÅÍÙÅ ÐÏÌÑ):
+
+biotopelist (code, rangcode, rusname, engname, descript, geobotdescr,
+             contributors, descrdate)
+
+  code - ÓÞÅÔÞÉË, ËÌÀÞÅ×ÏÅ ÐÏÌÅ;
+  rangcode - ÐÏÌÅ × ÆÏÒÍÁÔÅ ABBCCDDEE, ÇÄÅ á, BB, CC, DD, åå - ËÏÄÙ
+             ËÌÁÓÓÁ, ÐÏÄËÌÁÓÓÏ× É ÒÁÓÔÅÎÉÑ;
+  rusname, engname, descript, geobotdescr - ÔÅËÓÔÏ×ÙÅ ÐÏÌÑ;
+  descrdate - ÄÁÔÁ.
+
+photos (biotope, photo, authphoto)
+
+  biotope - ÞÉÓÌÏ, ÕËÁÚÙ×ÁÅÔ ÎÁ code × biotopelist;
+  photo - ÉÍÑ ÆÁÊÌÁ ÆÏÔÏÇÒÁÆÉÉ;
+  authphoto - ÔÅËÓÔ.
+
+ôÒÅÂÕÅÔÓÑ ÓÇÅÎÅÒÉÒÏ×ÁÔØ xml-ÆÁÊÌ ÄÌÑ ËÁÖÄÏÊ ÚÁÐÉÓÉ × biotopelist, ÆÁÊÌ
+ÓÏ ÓÐÉÓËÏÍ ËÌÁÓÓÏ×, ÆÁÊÌ ÓÏ ÓÐÉÓËÏÍ ÒÁÓÔÅÎÉÊ, ÐÏÌÎÏÒÁÚÍÅÒÎÙÅ É
+ÕÍÅÎØÛÅÎÎÙÅ ×ÅÒÓÉÉ ËÁÖÄÏÊ ÆÏÔÏÇÒÁÆÉÉ.
+
+äÌÑ ÇÅÎÅÒÁÃÉÉ xml-ÆÁÊÌÏ× Ó ÏÐÉÓÁÎÉÑÍÉ ÂÉÏÔÏÐÏ× ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÓÌÅÄÕÀÝÉÊ
+ÛÁÂÌÏÎ DbReader (ÆÁÊÌ biotope.template):
+
+----------------------------------------------------------------------
+<?xml version="1.0" encoding="ISO-8859-5"?>
+<!DOCTYPE ÏÐÉÓÁÎÉÅ_×ÉÄÁ SYSTEM "brief.dtd">
+<!-- rangcode: <%xml_escape get\rangcode%> -->
+<ÏÐÉÓÁÎÉÅ_×ÉÄÁ show="0">
+  <ÒÉÓÕÎËÉ display="0">
+    <%optional:<ËÁÒÔÁ_ÒÁÓÐÒÏÓÔÒÁÎÅÎÉÑ ÎÏÍÅÒ="1"
+    file="<%xml_escape image:maps/<%get\rangcode%>.gif maps/<%get\code%>.png png%>"/>%>
+<%query:photo_sql [%\<%include\photo.template%>%] <%get\code%>%>
+  </ÒÉÓÕÎËÉ>
+  <ÎÁÚ×ÁÎÉÅ><%xml_escape get\rusname%></ÎÁÚ×ÁÎÉÅ>
+  <ËÌÁÓÓ><%xml_escape get\class0%></ËÌÁÓÓ>
+  <ÐÏÄËÌÁÓÓ1><%xml_escape get\class1%></ÐÏÄËÌÁÓÓ1>
+  <ÐÏÄËÌÁÓÓ2><%xml_escape get\class2%></ÐÏÄËÌÁÓÓ2>
+  <ÐÏÄËÌÁÓÓ3><%xml_escape get\class3%></ÐÏÄËÌÁÓÓ3>
+  <ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ rows="3"><%xml_cdata get\descript%></ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ>
+  <ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ rows="3"><%xml_cdata get\geobotdescr%></ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ>
+  <Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ><%xml_escape get\contributors%></Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ>
+</ÏÐÉÓÁÎÉÅ_×ÉÄÁ>
+----------------------------------------------------------------------
+
+óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ, ÐÒÉ ×ÙÐÏÌÎÅÎÉÉ ËÏÔÏÒÏÇÏ ÕÓÔÁÎÁ×ÌÉ×ÁÀÔÓÑ
+ÚÎÁÞÅÎÉÑ ÐÅÒÅÍÅÎÎÙÈ ÛÁÂÌÏÎÁ rangcode, rusname, class0, class1, class2,
+class3, descript, geobotdescr É contributors (ÆÁÊÌ biotope.sql):
+
+----------------------------------------------------------------------
+SELECT t1.*,
+
+(SELECT t2.rusname FROM biotopelist AS t2
+WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1)
+AND Right(t2.rangcode, 8)  = '00000000'
+AND Right(t1.rangcode, 8) <> '00000000') AS class0,
+
+(SELECT t2.rusname FROM biotopelist AS t2
+WHERE Left(t2.rangcode, 3) = Left(t1.rangcode, 3)
+AND Right(t2.rangcode, 6)  = '000000'
+AND Right(t1.rangcode, 6) <> '000000') AS class1,
+
+(SELECT t2.rusname FROM biotopelist AS t2
+WHERE Left(t2.rangcode, 5) = Left(t1.rangcode, 5)
+AND Right(t2.rangcode, 4)  = '0000'
+AND Right(t1.rangcode, 4) <> '0000') AS class2,
+
+(SELECT t2.rusname FROM biotopelist AS t2
+WHERE Left(t2.rangcode, 7) = Left(t1.rangcode, 7)
+AND Right(t2.rangcode, 2)  = '00'
+AND Right(t1.rangcode, 2) <> '00') AS class3
+
+FROM biotopelist AS t1
+WHERE rusname
+----------------------------------------------------------------------
+
+ûÁÂÌÏÎ biotope.template ÓÏÄÅÒÖÉÔ ÉÎÓÔÒÕËÃÉÀ <%include\photo.template%>,
+×ËÌÀÞÁÀÝÕÀ ÛÁÂÌÏÎ ÏÐÉÓÁÎÉÑ ÆÏÔÏÇÒÁÆÉÉ (ÆÁÊÌ photo.template):
+
+----------------------------------------------------------------------
+    <ÆÏÔÏÇÒÁÆÉÑ num="<%xml_escape get\NUMBER%>"
+       <%optional:Á×ÔÏÒ="<%xml_escape get\authphoto%>" %>text="" 
+       file="<%xml_escape image:biotopephotos/<%get\photo%> images/<%get\SUPER.code%>_<%get\NUMBER%>.jpg jpg 300 300%>" 
+        big="<%xml_escape copy:biotopephotos/<%get\photo%> images/big/<%get\SUPER.code%>_<%get\NUMBER%>.jpg%>"/>
+----------------------------------------------------------------------
+
+óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÏÐÉÓÁÎÉÑ ÆÏÔÏÇÒÁÆÉÊ
+(photo.sql):
+
+----------------------------------------------------------------------
+SELECT * from photos WHERE biotope = ?
+----------------------------------------------------------------------
+
+ûÁÂÌÏÎ, ÇÅÎÅÒÉÒÕÀÝÉÊ ÓÐÉÓÏË ËÌÁÓÓÏ× (ÆÁÊÌ classes.template):
+
+----------------------------------------------------------------------
+<?xml version="1.0" encoding="ISO-8859-5"?>
+<ËÌÁÓÓÉÆÉËÁÃÉÑ><%query:class_sql [%\
+  <!-- rangcode: <%xml_escape get\rangcode%> -->
+  <ËÌÁÓÓ id="<%get\NUMBER%>"><%xml_escape get\rusname%></ËÌÁÓÓ>%]%>
+</ËÌÁÓÓÉÆÉËÁÃÉÑ>
+----------------------------------------------------------------------
+
+óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ (class.sql):
+
+----------------------------------------------------------------------
+SELECT t1.*
+FROM biotopelist AS t1
+WHERE rusname AND Right(t1.rangcode, 8)  = '00000000'
+  AND EXISTS
+    (SELECT NULL FROM biotopelist AS t2
+     WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1)
+     AND Right(t2.rangcode, 8) <> '00000000')
+----------------------------------------------------------------------
+
+ûÁÂÌÏÎ, ÇÅÎÅÒÉÒÕÀÝÉÊ ÓÐÉÓÏË ÒÁÓÔÅÎÉÊ (ÆÁÊÌ plants.template):
+
+----------------------------------------------------------------------
+<?xml version="1.0" encoding="ISO-8859-5"?>
+<ÒÁÓÔÅÎÉÑ><%query:plant_sql [%\
+  <!-- rangcode: <%xml_escape get\rangcode%> -->
+  <ÒÁÓÔÅÎÉÅ><%xml_escape get\rusname%></ÒÁÓÔÅÎÉÅ>%]%>
+</ÒÁÓÔÅÎÉÑ>
+----------------------------------------------------------------------
+
+óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ (plant.sql):
+
+----------------------------------------------------------------------
+SELECT t1.*
+FROM biotopelist AS t1
+WHERE rusname AND Right(t1.rangcode, 2) <> '00'
+----------------------------------------------------------------------
+
+óÉÓÔÅÍÁ DbReader ÎÁÞÉÎÁÅÔ ÒÁÂÏÔÕ Ó ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ index.template,
+ËÏÔÏÒÙÊ ÓÏÄÅÒÖÉÔ ×ÙÚÏ×Ù ÐÅÒÅÞÉÓÌÅÎÎÙÈ ×ÙÛÅ SQL-ÚÁÐÒÏÓÏ× É ×ËÌÀÞÅÎÉÑ
+ÛÁÂÌÏÎÏ×:
+
+----------------------------------------------------------------------
+<%!:
+  <%prepare:biotope_sql <%read\biotope.sql%>%>
+  <%prepare:photo_sql <%read\photo.sql%>%>
+  <%prepare:class_sql <%read\class.sql%>%>
+  <%prepare:plant_sql <%read\plant.sql%>%>
+
+  <%query:biotope_sql [%\<%write:<%get\code%>.xml <%include\biotope.template%>%> %]%>
+
+  <%write:classes.xml <%include\classes.template%>%>
+  <%write:plants.xml <%include\plants.template%>%>
+%>
+----------------------------------------------------------------------
+
+ðÒÉÍÅÒ ÓÇÅÎÅÒÉÒÏ×ÁÎÎÏÇÏ XML-ÆÁÊÌÁ:
+
+----------------------------------------------------------------------
+<?xml version="1.0" encoding="ISO-8859-5"?>
+<!DOCTYPE ÏÐÉÓÁÎÉÅ_×ÉÄÁ SYSTEM "brief.dtd">
+<!-- rangcode: E04020302 -->
+<ÏÐÉÓÁÎÉÅ_×ÉÄÁ show="0">
+  <ÒÉÓÕÎËÉ display="0">    
+    <ÆÏÔÏÇÒÁÆÉÑ num="1" Á×ÔÏÒ="ëÒÙÛÅÎØ á.í." text="" 
+                file="images/3_1.jpg" 
+                big="images/big/3_1.jpg"/>
+    <ÆÏÔÏÇÒÁÆÉÑ num="2" Á×ÔÏÒ="ëÒÙÛÅÎØ á.í." text="" 
+                file="images/3_2.jpg" 
+                big="images/big/3_2.jpg"/>
+  </ÒÉÓÕÎËÉ>
+  <ÎÁÚ×ÁÎÉÅ>Betula sp. - Avenella flexuosa - Polytrichum commune</ÎÁÚ×ÁÎÉÅ>
+  <ËÌÁÓÓ>E. óÕÈÏÄÏÌØÎÙÅ ÍÅÓÔÏÏÂÉÔÁÎÉÑ</ËÌÁÓÓ>
+  <ÐÏÄËÌÁÓÓ1>á×ÔÏÍÏÒÆÎÙÅ ×ÌÁÖÎÙÅ</ÐÏÄËÌÁÓÓ1>
+  <ÐÏÄËÌÁÓÓ2></ÐÏÄËÌÁÓÓ2>
+  <ÐÏÄËÌÁÓÓ3></ÐÏÄËÌÁÓÓ3>
+  <ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ rows="3"><![CDATA[òÁÚ×É×ÁÀÔÓÑ  ÎÁ ÌÕÇÏ×ÉËÏ×ÙÈ ×ÙÒÕÂËÁÈ ÌÅÓÏ× ÞÅÒÎÉÞÎÏÇÏ ÔÉÐÁ.  þÅÒÅÚ 5 - 7 ÌÅÔ  ÐÏÓÌÅ ÒÕÂËÉ ÐÏÒÏÓÌÅ×ÁÑ ÂÅÒÅÚÁ ×ÙÈÏÄÉÔ ÉÚ  ÑÒÕÓÁ ÔÒÁ×ÑÎÉÓÔÙÈ ÒÁÓÔÅÎÉÊ, ÅÅ ×ÌÉÑÎÉÅ ÓËÁÚÙ×ÁÅÔÓÑ, × ÐÅÒ×ÕÀ ÏÞÅÒÅÄØ, ÎÁ ×ÌÁÖÎÏÓÔÉ ÐÏÞ×Ù.]]></ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ>
+  <ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ rows="3"></ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ>
+  <Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ></Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ>
+</ÏÐÉÓÁÎÉÅ_×ÉÄÁ>
+----------------------------------------------------------------------
+
+
+* óÔÒÕËÔÕÒÁ ÐÒÏÇÒÁÍÍÙ DbReader
+
+ðÒÏÇÒÁÍÍÁ DbReader ÎÁÐÉÓÁÎÁ ÎÁ ÑÚÙËÅ ÐÒÏÇÒÁÍÍÉÒÏ×ÁÎÉÑ Java É ÓÏÓÔÏÉÔ
+ÉÚ ÓÌÅÄÕÀÝÉÈ ÏÓÎÏ×ÎÙÈ ËÌÁÓÓÏ×:
+
+ru.karrc.dbreader.DbReader: cÏÄÅÒÖÉÔ ÔÏÞËÕ ×ÈÏÄÁ ÐÒÏÇÒÁÍÍÙ. úÁÇÒÕÖÁÅÔ
+ËÏÎÆÉÇÕÒÁÃÉÀ, ÕÓÔÁÎÁ×ÌÉ×ÁÅÔ ÓÏÅÄÉÎÅÎÉÅ Ó ÉÓÔÏÞÎÉËÏÍ ÄÁÎÎÙÈ Ó ÐÏÍÏÝØÀ
+ÂÉÂÌÉÏÔÅËÉ JDBC, ÚÁÐÕÓËÁÅÔ ÏÂÒÁÂÏÔËÕ ÏÓÎÏ×ÎÏÇÏ ÛÁÂÌÏÎÁ.
+
+ru.karrc.dbreader.TemplateParser: ÏÓÕÝÅÓÔ×ÌÑÅÔ ÒÁÚÂÏÒ ÛÁÂÌÏÎÁ,
+ÏÂÒÁÂÏÔËÕ ÉÎÓÔÒÕËÃÉÊ É ×ÙÚÏ× ÆÕÎËÃÉÊ.
+
+ru.karrc.dbreader.Function: ÁÂÓÔÒÁËÔÎÙÊ ËÌÁÓÓ. òÅÁÌÉÚÁÃÉÉ ×ÓÅÈ ÆÕÎËÃÉÊ
+DbReader ÎÁÓÌÅÄÕÀÔ ÜÔÏÔ ËÌÁÓÓ.
+
+ru.karrc.dbreader.FunctionDataParser: ÏÂÒÁÂÏÔÞÉË ÄÁÎÎÙÈ
+ÆÕÎËÃÉÉ. ðÏÓ×ÏÌÑÅÔ ÐÏÌÕÞÉÔØ ÓÐÉÓÏË ÁÒÇÕÍÅÎÔÏ× É ÔÅËÓÔ, ÐÅÒÅÄÁ×ÁÅÍÙÊ
+ÆÕÎËÃÉÉ. ðÒÉ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ×ÙÚÙ×ÁÅÔ ÒÅËÕÒÓÉ×ÎÕÀ ÏÂÒÁÂÏÔËÕ ÄÁÎÎÙÈ Ó
+ÐÏÍÏÝØÀ TemplateParser.
+
+ru.karrc.dbreader.Functions: ÓÏÄÅÒÖÉÔ ÒÅÁÌÉÚÁÃÉÉ ÆÕÎËÃÉÊ × ×ÉÄÅ
+ÁÎÏÎÉÍÎÙÈ ËÌÁÓÓÏ×, ÎÁÓÌÅÄÕÀÝÉÈ Function.
+
+ru.karrc.dbreader.TemplateParser: ÉÓËÌÀÞÅÎÉÅ, ×ÙÂÒÁÓÙ×ÁÅÍÏÅ × ÓÌÕÞÁÅ
+×ÏÚÎÉËÎÏ×ÅÎÉÑ ÏÛÉÂËÉ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÛÁÂÌÏÎÁ.
+
+ëÒÏÍÅ ÔÏÇÏ, ÒÅÁÌÉÚÏ×ÁÎÏ ÎÅÓËÏÌØËÏ ×ÐÏÍÏÇÁÔÅÌØÎÙÈ ËÌÁÓÓÏ×, ËÏÔÏÒÙÅ
+ÉÓÐÏÌØÚÕÀÔÓÑ × ÒÅÁÌÉÚÁÃÉÑÈ ÆÕÎËÃÉÊ ÓÉÓÔÅÍÙ.
+
+
+* íÅÔÒÉËÉ ÒÅÁÌÉÚÏ×ÁÎÎÏÊ ÐÒÏÇÒÁÍÍÎÏÊ ÓÉÓÔÅÍÙ.
+
+ëÏÌÉÞÅÓÔ×Ï ÆÁÊÌÏ× ÉÓÈÏÄÎÏÇÏ ËÏÄÁ: 8,
+ëÏÌÉÞÅÓÔ×Ï Java-ËÌÁÓÓÏ× (×ËÌÀÞÁÑ ÁÎÏÎÉÍÎÙÅ): 27,
+ïÂÝÅÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ÉÓÈÏÄÎÏÇÏ ÔÅËÓÔÁ: 1311,
+ëÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ËÏÄÁ (ÉÓËÌÀÞÁÑ ÐÕÓÔÙÅ ÓÔÒÏËÉ É ËÏÍÍÅÎÔÁÒÉÉ): 812,
+ëÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ËÏÍÍÅÎÔÁÒÉÅ×: 180.
+
+
+* úÁËÌÀÞÅÎÉÅ
+
+á×ÔÏÒÏÍ ÂÙÌÁ ÒÁÚÒÁÂÏÔÁÎÁ ÐÒÏÇÒÁÍÍÎÁÑ ÓÉÓÔÅÍÁ DbReader, ËÏÔÏÒÁÑ
+Ñ×ÌÑÅÔÓÑ ÒÁÓÛÉÒÑÅÍÙÍ É ÕÎÉ×ÅÒÓÁÌØÎÙÍ ÓÒÅÄÓÔ×ÏÍ ÄÌÑ ÐÒÅÄÓÔÁ×ÌÅÎÉÑ
+ÉÎÆÏÒÍÁÃÉÉ ÉÚ ÂÁÚ ÄÁÎÎÙÈ × ÔÅËÓÔÏ×ÙÈ ÆÏÒÍÁÔÁÈ. ó ÐÏÍÏÝØÀ ÓÉÓÔÅÍÙ
+DbReader ÂÁÚÁ ÄÁÎÎÙÈ "íÅÓÔÏÏÂÉÔÁÎÉÑ ÷ÏÓÔÏÞÎÏÊ æÅÎÎÏÓËÁÎÄÉÉ" ÂÙÌÁ
+ÐÅÒÅ×ÅÄÅÎÁ × XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ ÂÉÂÌÉÏÔÅËÉ ëÁÒîã òáî.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/biotopes/doc/readme.html	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,86 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+          "DTD/xhtml1-transitional.dtd">
+
+<html>
+
+<head>
+  <title>DbReader</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=koi8-r" />
+</head>
+
+<body>
+<h1>DbReader</h1>
+
+<h2>õÓÔÁÎÏ×ËÁ ÐÒÏÇÒÁÍÍÙ</h2>
+<ol>
+<li>òÁÓÐÁËÏ×ÁÔØ ÁÒÈÉ×.</li>
+
+<li>õÓÔÁÎÏ×ÉÔØ ÉÓÔÏÞÎÉË ÄÁÎÎÙÈ:<br />
+× Windows 2000: ðÁÎÅÌØ ÕÐÒÁ×ÌÅÎÉÑ/áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ/éÓÔÏÞÎÉËÉ ÄÁÎÎÙÈ (ODBC), ÄÏÂÁ×ÉÔØ biotopes-data.mdb.</li>
+
+<li>îÁÓÔÒÏÉÔØ ÐÒÏÇÒÁÍÍÕ:<br />
+÷ ÆÁÊÌÅ dbreader.properties ÕËÁÚÁÔØ ÉÍÑ, ÐÒÉÓ×ÏÅÎÎÏÅ ÉÓÔÏÞÎÉËÕ ÄÁÎÎÙÈ:<br />
+    <code>resource: jdbc:odbc:<em>ÉÍÑ</em></code><br />
+É ÐÕÔØ Ë ËÁÔÁÌÏÇÕ, ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÔÏÒÏÇÏ ÐÒÏÇÒÁÍÍÁ ÂÕÄÅÔ ÉÓËÁÔØ ÉÚÏÂÒÁÖÅÎÉÑ (ÓÏÄÅÒÖÁÝÉÊ biotopephotos É maps):<br />
+    <code>resource_base: C:\\biotopes</code><br />
+(ÓÉÍ×ÏÌ '\' ÎÅÏÂÈÏÄÉÍÏ ÄÕÂÌÉÒÏ×ÁÔØ)</li>
+
+<li>úÁÐÕÓË ÐÒÏÇÒÁÍÍÙ:<br />
+<code>dbreader.bat</code> ÉÌÉ<br />
+<code>java -jar dbreader.jar</code>.<br />
+äÌÑ ÚÁÐÕÓËÁ ÎÅÏÂÈÏÄÉÍÁ Java Runtime Environment (JRE) 5.0, ÍÏÖÎÏ ÓËÁÞÁÔØ Ó <a href="http://java.sun.com/j2se/1.5.0/download.jsp">http://java.sun.com/j2se/1.5.0/download.jsp</a>. ÷ÏÚÍÏÖÎÏ, ÂÕÄÅÔ ÒÁÂÏÔÁÔØ É ÓÏ ÓÔÁÒÙÍÉ ×ÅÒÓÉÑÍÉ JRE - ÎÅ ÐÒÏ×ÅÒÑÌ.
+
+÷ÓÅ ÚÎÁÞÅÎÉÑ ÆÁÊÌÁ ËÏÎÆÉÇÕÒÁÃÉÉ ÍÏÖÎÏ ÐÅÒÅÏÐÒÅÄÅÌÑÔØ ÐÒÉ ÚÁÐÕÓËÅ ÐÒÏÇÒÁÍÍÙ:<br />
+ËÏÍÁÎÄÁ <code>java -Dru.karrc.dbreader.<em>ËÌÀÞ</em>=<em>ÚÎÁÞÅÎÉÅ</em> -jar dbreader.jar</code><br />
+(ÎÁÐÒÉÍÅÒ: <code>java -Dru.karrc.dbreader.log=dbreader.log -jar dbreader.jar</code>)</li>
+</ol>
+
+<h2>òÁÂÏÔÁ ÐÒÏÇÒÁÍÍÙ</h2>
+
+<p>ðÒÏÇÒÁÍÍÁ ×ÙÐÏÌÎÑÅÔ ÚÁÐÒÏÓ biotope.sql (ÉÌÉ ÄÒÕÇÏÊ, ÕËÁÚÁÎÎÙÊ × dbreader.properties), ÐÏÓÌÅ ÞÅÇÏ ÏÂÒÁÂÁÔÙ×ÁÅÔ ÆÁÊÌ biotope.template, ÚÁÍÅÎÑÑ ÎÁÊÄÅÎÎÙÅ × ÎÅÍ ÉÎÓÔÒÕËÃÉÉ ÎÁ ÒÅÚÕÌØÔÁÔÙ ÉÈ ×ÙÐÏÌÎÅÎÉÑ.</p>
+<p>æÏÒÍÁÔ ÉÎÓÔÒÕËÃÉÊ: <code>&lt;%<em>ÓÐÉÓÏË_ÆÕÎËÃÉÊ</em>[:|\]<em>ÄÁÎÎÙÅ</em>%&gt;</code>, <em>ÓÐÉÓÏË ÆÕÎËÃÉÊ</em> - ÉÍÅÎÁ ÆÕÎËÃÉÊ ÒÁÚÄÅÌÅÎÎÙÅ ÐÒÏÂÅÌÏÍ, ÓÐÉÓÏË ÍÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ. åÓÌÉ ÕËÁÚÁÎÏ ÎÅÓËÏÌØËÏ ÆÕÎËÃÉÊ, ÏÎÉ ×ÙÐÏÌÎÑÀÔÓÑ ÎÁÞÉÎÁÑ Ó ÐÏÓÌÅÄÎÅÊ.</p>
+
+<h3>òÁÚÄÅÌÉÔÅÌÉ ÍÅÖÄÕ ÓÐÉÓËÏÍ ÆÕÎËÃÉÊ É ÄÁÎÎÙÍÉ</h3>
+
+<ul>
+  <li><code>:</code> - ÄÁÎÎÙÅ ÂÕÄÕÔ ÏÂÒÁÂÁÔÙ×ÁÔØÓÑ ÒÅËÕÒÓÉ×ÎÏ.</li>
+  <li><code>\</code> - ÄÁÎÎÙÅ ÂÕÄÕÔ ÐÅÒÅÄÁÎÙ ÆÕÎËÃÉÉ ÂÅÚ ÏÂÒÁÂÏÔËÉ. íÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÄÌÑ ÜËÒÁÎÉÒÏ×ÁÎÉÑ ËÏÍÂÉÎÁÃÉÊ ÓÉÍ×ÏÌÏ× <code>&lt;%</code> É <code>%&gt;</code> (<code>&lt;%\&lt;%%&gt;</code> É <code>&lt;%\%%&gt;&gt;</code>).</li>
+</ul>
+
+<h3>æÕÎËÃÉÉ</h3>
+
+<ul>
+  <li><code>&lt;%get:<em>ÉÍÑ</em>%&gt;</code><br />
+  úÁÍÅÎÑÅÔÓÑ ÎÁ ÚÎÁÞÅÎÉÅ ×ÓÔÒÏÅÎÎÏÊ ÐÅÒÅÍÅÎÎÏÊ ÉÌÉ ËÏÌÏÎËÉ ÚÁÐÒÏÓÁ.</li>
+
+  <li><code>&lt;%optional:<em>ÔÅËÓÔ</em>%&gt;</code><br />
+  úÁÍÅÎÑÅÔÓÑ ÎÁ <em>ÔÅËÓÔ</em>, ÅÓÌÉ × ÎÅÍ ÎÁÊÄÅÎÙ ÉÎÓÔÒÕËÃÉÉ, ÚÁÍÅÎÉ×ÛÉÅÓÑ ÎÁ ÎÅÐÕÓÔÙÅ ÓÔÒÏËÉ, ÉÎÁÞÅ ÚÁÍÅÎÑÅÔÓÑ ÎÁ ÐÕÓÔÕÀ ÓÔÒÏËÕ.</li>
+
+  <li><code>&lt;%escape:<em>ÔÅËÓÔ</em>%&gt;</code><br />
+  úÁÍÅÎÑÅÔ × ÔÅËÓÔÅ "ÏÐÁÓÎÙÅ" ÓÉÍ×ÏÌÙ (ÔÁÂÌÉÃÁ ÚÁÍÅÎ ÚÁÄÁÅÔÓÑ × ÆÁÊÌÅ ËÏÎÆÉÇÕÒÁÃÉÉ).</li>
+
+  <li><code>&lt;%invoke:<em>ÉÍÑ</em>; <em>ÐÁÒÁÍ1</em> <em>ÐÁÒÁÍ2</em> ... <em>ÐÁÒÁÍN</em>%&gt;</code><br />
+  ÷ÙÐÏÌÎÑÅÔ ÚÁÐÒÏÓ Ó ÐÁÒÁÍÅÔÒÁÍÉ <em>ÉÍÑ</em>.sql É ÚÁÍÅÎÑÅÔÓÑ ÎÁ ÒÅÚÕÌØÔÁÔÙ ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ <em>ÉÍÑ</em>.template. úÎÁÞÅÎÉÑ ÐÁÒÁÍÅÔÒÏ× ÐÏÄÓÔÁ×ÌÑÀÔÓÑ × ÚÁÐÒÏÓ ×ÍÅÓÔÏ ÓÉÍ×ÏÌÁ '?'.</li>
+
+  <li><code>&lt;%image:<em>ÉÓÈ_ÆÁÊÌ</em> <em>ËÏÎ_ÆÁÊÌ</em> <em>ÆÏÒÍÁÔ</em> [<em>ÍÁËÓ_ÛÉÒÉÎÁ</em>] [<em>ÍÁËÓ_×ÙÓÏÔÁ</em>]%&gt;</code><br />
+  úÁÇÒÕÖÁÅÔ ÉÚÏÂÒÁÖÅÎÉÅ ÉÚ ÆÁÊÌÁ <em>ÉÓÈ_ÆÁÊÌ</em> (ÐÕÔØ ÏÐÒÅÄÅÌÑÅÔÓÑ ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base") É ÐÒÅÏÂÒÁÚÕÅÔ ÅÇÏ × ÕËÁÚÁÎÎÙÊ ÆÏÒÍÁÔ, ÓÏÈÒÁÎÑÑ ÒÅÚÕÌØÔÁÔ × <em>ËÏÎ_ÆÁÊÌ</em>. åÓÌÉ ÚÁÄÁÎÙ ÍÁËÓÉÍÁÌØÎÁÑ ×ÙÓÏÔÁ É ÛÉÒÉÎÁ, ÂÏÌØÛÉÅ ÉÚÏÂÒÁÖÅÎÉÑ ÂÕÄÕÔ ÕÍÅÎØÛÅÎÙ.
+ðÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÉÎÓÔÒÕËÃÉÑ <code>&lt;%image:...%&gt;</code> ÂÕÄÅÔ ÚÁÍÅÎÅÎÁ ÎÁ ÚÎÁÞÅÎÉÅ <em>ËÏÎ_ÆÁÊÌ</em>, ÉÎÁÞÅ - ÎÁ ÐÕÓÔÕÀ ÓÔÒÏËÕ.</li>
+
+  <li><code>&lt;%copy:<em>ÉÓÈ_ÆÁÊÌ</em> <em>ËÏÎ_ÆÁÊÌ</em>%&gt;</code><br />
+  ëÏÐÉÒÕÅÔ ÆÁÊÌ <em>ÉÓÈ_ÆÁÊÌ</em> (ÐÕÔØ ÏÐÒÅÄÅÌÑÅÔÓÑ ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base") × <em>ËÏÎ_ÆÁÊÌ</em>. ðÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÉÎÓÔÒÕËÃÉÑ <code>&lt;%copy:...%&gt;</code> ÂÕÄÅÔ ÚÁÍÅÎÅÎÁ ÎÁ ÚÎÁÞÅÎÉÅ <em>ËÏÎ_ÆÁÊÌ</em>, ÉÎÁÞÅ - ÎÁ ÐÕÓÔÕÀ ÓÔÒÏËÕ.</li>
+</ul>
+
+<h3>÷ÓÔÒÏÅÎÎÙÅ ÐÅÒÅÍÅÎÎÙÅ</h3>
+
+<p><code>NUMBER</code> - ÐÏÒÑÄËÏ×ÙÊ ÎÏÍÅÒ ÓÔÒÏËÉ ÒÅÚÕÌØÔÁÔÁ ×ÙÐÏÌÎÅÎÉÑ ÚÁÐÒÏÓÁ.
+þÔÏÂÙ ÏÂÒÁÔÉÔØÓÑ Ë ÐÅÒÅÍÅÎÎÏÊ ÚÁÐÒÏÓÁ, ÉÚ ËÏÔÏÒÏÇÏ ÏÂÒÁÂÁÔÙ×ÁÅÍÙÊ ÛÁÂÌÏÎ ÂÙÌ ×ÙÚ×ÁÎ Ó ÐÏÍÏÝØÀ ÆÕÎËÃÉÉ invoke, ÐÅÒÅÄ ÉÍÅÎÅÍ ÐÅÒÅÍÅÎÎÏÊ ÎÕÖÎÏ ÄÏÂÁ×ÉÔØ <code>SUPER.</code> (ÎÁÐÒÉÍÅÒ: <code>SUPER.NUMBER</code>).</p>
+
+<h3>ðÒÉÍÅÒ</h3>
+
+<p>óÌÅÄÕÀÝÁÑ ÉÎÓÔÒÕËÃÉÑ ÐÏÌÕÞÉÔ ÚÎÁÞÅÎÉÅ ÉÚ ÓÔÏÌÂÃÁ name É ÚÁÍÅÎÉÔ × ÎÅÍ ÓÐÅÃÉÁÌØÎÙÅ ÓÉÍ×ÏÌÙ:</p>
+<p><code>&lt;%escape get:name%&gt;</code></p>
+
+<p align="right"><i><a href="mailto:kryshen@cs.karelia.ru">íÉÈÁÉÌ ëÒÙÛÅÎØ</a></i></p>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dist/biotopes/doc/readme.txt	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,63 @@
+text/plain; charset=UTF-8
+
+Установка программы
+-------------------
+
+1. Распаковать архив.
+
+2. Установить источник данных:
+в Windows 2000: Панель управления/Администрирование/Источники данных (ODBC), добавить biotopes.mdb.
+
+3. Настроить программу:
+В файле dbreader.properties указать имя, присвоенное источнику данных:
+    "resource: jdbc:odbc:<имя>"
+и путь к каталогу, относительно которого программа будет искать изображения (содержащий biotopephotos и maps):
+    "resource_base: C:\\biotopes"
+(символ '\' необходимо дублировать)
+
+4. Запуск программы: dbreader.bat или "java -jar dbreader.jar"
+Для запуска необходима Java Runtime Environment (JRE) 5.0, можно скачать с http://java.sun.com/j2se/1.5.0/download.jsp. Возможно, будет работать и со старыми версиями JRE - не проверял.
+
+Все значения файла конфигурации можно переопределять при запуске программы:
+    команда "java -Dru.karrc.dbreader.<ключ>=<значение> -jar dbreader.jar"
+(например: "java -Dru.karrc.dbreader.log=dbreader.log -jar dbreader.jar")
+
+
+Работа программы
+----------------
+
+Программа выполняет запрос biotope.sql (или другой, указанный в dbreader.properties), после чего обрабатывает файл biotope.template, заменяя найденные в нем инструкции на результаты их выполнения.
+
+Формат инструкций: "<%список_функций[:|\]данные%>", список функций - имена функций разделенные пробелом, список может быть пустым. Если указано несколько функций, они выполняются начиная с последней.
+
+Разделители между списком функций и данными:
+':' - данные будут обрабатываться рекурсивно.
+'\' - данные будут переданы функции без обработки. Можно использовать для экранирования комбинаций символов "<%" и "%>" ("<%\<%%>" и "<%\%%>>").
+
+Функции:
+<%get:<имя>%> - заменяется на значение встроенной переменной или колонки запроса.
+
+<%optional:<текст>%>
+Заменяется на <текст>, если в нем найдены инструкции, заменившиеся на непустые строки, иначе заменяется на пустую строку.
+
+<%escape:<текст>%>
+Заменяет в тексте "опасные" символы (таблица замен задается в файле конфигурации).
+
+<%invoke:<имя> <парам1> <парам2> ... <парамN>%>
+Выполняет запрос с параметрами <имя>.sql и заменяется на результаты обработки шаблона <имя>.template. Значения параметров подставляются в запрос вместо символа '?'.
+
+<%image:<исх_файл> <кон_файл> <формат> [<макс_ширина>] [<макс_высота>]%>
+Загружает изображение из файла <исх_файл> (путь определяется относительно конфигурационного параметра "resource_base") и преобразует его в указанный формат, сохраняя результат в <кон_файл>. Если заданы максимальная высота и ширина, большие изображения будут уменьшены.
+При успешном выполнении, инструкция "<%!image ...%>" будет заменена на значение <кон_файл>, иначе - на пустую строку.
+
+<%copy:<исх_файл> <кон_файл>%>
+Копирует файл <исх_файл> (путь определяется относительно конфигурационного параметра "resource_base").
+При успешном выполнении, инструкция "<%!copy ...%>" будет заменена на значение <кон_файл>, иначе - на пустую строку.
+
+Встроенные переменные:
+NUMBER - порядковый номер строки результата выполнения запроса.
+Чтобы обратиться к переменной запроса, из которого обрабатываемый шаблон был вызван с помощью функции invoke, перед именем переменной нужно добавить "SUPER." (например: "SUPER.NUMBER").
+
+Пример:
+Следующая инструкция получит значение из столбца name и заменит в нем специальные символы:
+<%escape get:name%>
--- a/dist/biotopes/main.template	Tue May 16 18:04:09 2006 +0400
+++ b/dist/biotopes/main.template	Thu Dec 14 23:22:05 2006 +0300
@@ -4,7 +4,7 @@
   <%prepare:class_sql <%read\class.sql%>%>
   <%prepare:plant_sql <%read\plant.sql%>%>
 
-  <%query:biotope_sql [%\<%write:<%get\code%>.xml <%include\biotope.template%>%> %]%>
+  <%query:biotope_sql [%\<%write:<%db\code%>.xml <%include\biotope.template%>%> %]%>
 
   <%write:classes.xml <%include\classes.template%>%>
   <%write:plants.xml <%include\plants.template%>%>
--- a/dist/biotopes/photo.template	Tue May 16 18:04:09 2006 +0400
+++ b/dist/biotopes/photo.template	Thu Dec 14 23:22:05 2006 +0300
@@ -1,3 +1,3 @@
-    <äÞâÞÓàÐäØï num="<%xml_escape get\NUMBER%>" <%optional:ÐÒâÞà="<%xml_escape get\authphoto%>" %>text="" 
-                file="<%xml_escape image:biotopephotos/<%get\photo%> images/<%get\SUPER.code%>_<%get\NUMBER%>.jpg jpg 300 300%>" 
-                big="<%xml_escape copy:biotopephotos/<%get\photo%> images/big/<%get\SUPER.code%>_<%get\NUMBER%>.jpg%>"/>
+    <äÞâÞÓàÐäØï num="<%number\%>" <%optional:ÐÒâÞà="<%xml_escape db\authphoto%>" %>text="" 
+                file="<%xml_escape image:biotopephotos/<%db\photo%> images/<%super.db\code%>_<%number\%>.jpg jpg 300 300%>" 
+                big="<%xml_escape copy:biotopephotos/<%db\photo%> images/big/<%super.db\code%>_<%number\%>.jpg%>"/>
--- a/dist/biotopes/plants.template	Tue May 16 18:04:09 2006 +0400
+++ b/dist/biotopes/plants.template	Thu Dec 14 23:22:05 2006 +0300
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-5"?>
 <àÐáâÕÝØï><%query:plant_sql [%\
-  <!-- rangcode: <%xml_escape get\rangcode%> -->
-  <àÐáâÕÝØÕ><%xml_escape get\rusname%></àÐáâÕÝØÕ>%]%>
+  <!-- rangcode: <%xml_escape db\rangcode%> -->
+  <àÐáâÕÝØÕ><%xml_escape db\rusname%></àÐáâÕÝØÕ>%]%>
 </àÐáâÕÝØï>
--- a/dist/readme.html	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
-          "DTD/xhtml1-transitional.dtd">
-
-<html>
-
-<head>
-  <title>DbReader</title>
-  <meta http-equiv="Content-Type" content="text/html; charset=koi8-r" />
-</head>
-
-<body>
-<h1>DbReader</h1>
-
-<h2>õÓÔÁÎÏ×ËÁ ÐÒÏÇÒÁÍÍÙ</h2>
-<ol>
-<li>òÁÓÐÁËÏ×ÁÔØ ÁÒÈÉ×.</li>
-
-<li>õÓÔÁÎÏ×ÉÔØ ÉÓÔÏÞÎÉË ÄÁÎÎÙÈ:<br />
-× Windows 2000: ðÁÎÅÌØ ÕÐÒÁ×ÌÅÎÉÑ/áÄÍÉÎÉÓÔÒÉÒÏ×ÁÎÉÅ/éÓÔÏÞÎÉËÉ ÄÁÎÎÙÈ (ODBC), ÄÏÂÁ×ÉÔØ biotopes-data.mdb.</li>
-
-<li>îÁÓÔÒÏÉÔØ ÐÒÏÇÒÁÍÍÕ:<br />
-÷ ÆÁÊÌÅ dbreader.properties ÕËÁÚÁÔØ ÉÍÑ, ÐÒÉÓ×ÏÅÎÎÏÅ ÉÓÔÏÞÎÉËÕ ÄÁÎÎÙÈ:<br />
-    <code>resource: jdbc:odbc:<em>ÉÍÑ</em></code><br />
-É ÐÕÔØ Ë ËÁÔÁÌÏÇÕ, ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÔÏÒÏÇÏ ÐÒÏÇÒÁÍÍÁ ÂÕÄÅÔ ÉÓËÁÔØ ÉÚÏÂÒÁÖÅÎÉÑ (ÓÏÄÅÒÖÁÝÉÊ biotopephotos É maps):<br />
-    <code>resource_base: C:\\biotopes</code><br />
-(ÓÉÍ×ÏÌ '\' ÎÅÏÂÈÏÄÉÍÏ ÄÕÂÌÉÒÏ×ÁÔØ)</li>
-
-<li>úÁÐÕÓË ÐÒÏÇÒÁÍÍÙ:<br />
-<code>dbreader.bat</code> ÉÌÉ<br />
-<code>java -jar dbreader.jar</code>.<br />
-äÌÑ ÚÁÐÕÓËÁ ÎÅÏÂÈÏÄÉÍÁ Java Runtime Environment (JRE) 5.0, ÍÏÖÎÏ ÓËÁÞÁÔØ Ó <a href="http://java.sun.com/j2se/1.5.0/download.jsp">http://java.sun.com/j2se/1.5.0/download.jsp</a>. ÷ÏÚÍÏÖÎÏ, ÂÕÄÅÔ ÒÁÂÏÔÁÔØ É ÓÏ ÓÔÁÒÙÍÉ ×ÅÒÓÉÑÍÉ JRE - ÎÅ ÐÒÏ×ÅÒÑÌ.
-
-÷ÓÅ ÚÎÁÞÅÎÉÑ ÆÁÊÌÁ ËÏÎÆÉÇÕÒÁÃÉÉ ÍÏÖÎÏ ÐÅÒÅÏÐÒÅÄÅÌÑÔØ ÐÒÉ ÚÁÐÕÓËÅ ÐÒÏÇÒÁÍÍÙ:<br />
-ËÏÍÁÎÄÁ <code>java -Dru.karrc.dbreader.<em>ËÌÀÞ</em>=<em>ÚÎÁÞÅÎÉÅ</em> -jar dbreader.jar</code><br />
-(ÎÁÐÒÉÍÅÒ: <code>java -Dru.karrc.dbreader.log=dbreader.log -jar dbreader.jar</code>)</li>
-</ol>
-
-<h2>òÁÂÏÔÁ ÐÒÏÇÒÁÍÍÙ</h2>
-
-<p>ðÒÏÇÒÁÍÍÁ ×ÙÐÏÌÎÑÅÔ ÚÁÐÒÏÓ biotope.sql (ÉÌÉ ÄÒÕÇÏÊ, ÕËÁÚÁÎÎÙÊ × dbreader.properties), ÐÏÓÌÅ ÞÅÇÏ ÏÂÒÁÂÁÔÙ×ÁÅÔ ÆÁÊÌ biotope.template, ÚÁÍÅÎÑÑ ÎÁÊÄÅÎÎÙÅ × ÎÅÍ ÉÎÓÔÒÕËÃÉÉ ÎÁ ÒÅÚÕÌØÔÁÔÙ ÉÈ ×ÙÐÏÌÎÅÎÉÑ.</p>
-<p>æÏÒÍÁÔ ÉÎÓÔÒÕËÃÉÊ: <code>&lt;%<em>ÓÐÉÓÏË_ÆÕÎËÃÉÊ</em>[:|\]<em>ÄÁÎÎÙÅ</em>%&gt;</code>, <em>ÓÐÉÓÏË ÆÕÎËÃÉÊ</em> - ÉÍÅÎÁ ÆÕÎËÃÉÊ ÒÁÚÄÅÌÅÎÎÙÅ ÐÒÏÂÅÌÏÍ, ÓÐÉÓÏË ÍÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ. åÓÌÉ ÕËÁÚÁÎÏ ÎÅÓËÏÌØËÏ ÆÕÎËÃÉÊ, ÏÎÉ ×ÙÐÏÌÎÑÀÔÓÑ ÎÁÞÉÎÁÑ Ó ÐÏÓÌÅÄÎÅÊ.</p>
-
-<h3>òÁÚÄÅÌÉÔÅÌÉ ÍÅÖÄÕ ÓÐÉÓËÏÍ ÆÕÎËÃÉÊ É ÄÁÎÎÙÍÉ</h3>
-
-<ul>
-  <li><code>:</code> - ÄÁÎÎÙÅ ÂÕÄÕÔ ÏÂÒÁÂÁÔÙ×ÁÔØÓÑ ÒÅËÕÒÓÉ×ÎÏ.</li>
-  <li><code>\</code> - ÄÁÎÎÙÅ ÂÕÄÕÔ ÐÅÒÅÄÁÎÙ ÆÕÎËÃÉÉ ÂÅÚ ÏÂÒÁÂÏÔËÉ. íÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÄÌÑ ÜËÒÁÎÉÒÏ×ÁÎÉÑ ËÏÍÂÉÎÁÃÉÊ ÓÉÍ×ÏÌÏ× <code>&lt;%</code> É <code>%&gt;</code> (<code>&lt;%\&lt;%%&gt;</code> É <code>&lt;%\%%&gt;&gt;</code>).</li>
-</ul>
-
-<h3>æÕÎËÃÉÉ</h3>
-
-<ul>
-  <li><code>&lt;%get:<em>ÉÍÑ</em>%&gt;</code><br />
-  úÁÍÅÎÑÅÔÓÑ ÎÁ ÚÎÁÞÅÎÉÅ ×ÓÔÒÏÅÎÎÏÊ ÐÅÒÅÍÅÎÎÏÊ ÉÌÉ ËÏÌÏÎËÉ ÚÁÐÒÏÓÁ.</li>
-
-  <li><code>&lt;%optional:<em>ÔÅËÓÔ</em>%&gt;</code><br />
-  úÁÍÅÎÑÅÔÓÑ ÎÁ <em>ÔÅËÓÔ</em>, ÅÓÌÉ × ÎÅÍ ÎÁÊÄÅÎÙ ÉÎÓÔÒÕËÃÉÉ, ÚÁÍÅÎÉ×ÛÉÅÓÑ ÎÁ ÎÅÐÕÓÔÙÅ ÓÔÒÏËÉ, ÉÎÁÞÅ ÚÁÍÅÎÑÅÔÓÑ ÎÁ ÐÕÓÔÕÀ ÓÔÒÏËÕ.</li>
-
-  <li><code>&lt;%escape:<em>ÔÅËÓÔ</em>%&gt;</code><br />
-  úÁÍÅÎÑÅÔ × ÔÅËÓÔÅ "ÏÐÁÓÎÙÅ" ÓÉÍ×ÏÌÙ (ÔÁÂÌÉÃÁ ÚÁÍÅÎ ÚÁÄÁÅÔÓÑ × ÆÁÊÌÅ ËÏÎÆÉÇÕÒÁÃÉÉ).</li>
-
-  <li><code>&lt;%invoke:<em>ÉÍÑ</em>; <em>ÐÁÒÁÍ1</em> <em>ÐÁÒÁÍ2</em> ... <em>ÐÁÒÁÍN</em>%&gt;</code><br />
-  ÷ÙÐÏÌÎÑÅÔ ÚÁÐÒÏÓ Ó ÐÁÒÁÍÅÔÒÁÍÉ <em>ÉÍÑ</em>.sql É ÚÁÍÅÎÑÅÔÓÑ ÎÁ ÒÅÚÕÌØÔÁÔÙ ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ <em>ÉÍÑ</em>.template. úÎÁÞÅÎÉÑ ÐÁÒÁÍÅÔÒÏ× ÐÏÄÓÔÁ×ÌÑÀÔÓÑ × ÚÁÐÒÏÓ ×ÍÅÓÔÏ ÓÉÍ×ÏÌÁ '?'.</li>
-
-  <li><code>&lt;%image:<em>ÉÓÈ_ÆÁÊÌ</em> <em>ËÏÎ_ÆÁÊÌ</em> <em>ÆÏÒÍÁÔ</em> [<em>ÍÁËÓ_ÛÉÒÉÎÁ</em>] [<em>ÍÁËÓ_×ÙÓÏÔÁ</em>]%&gt;</code><br />
-  úÁÇÒÕÖÁÅÔ ÉÚÏÂÒÁÖÅÎÉÅ ÉÚ ÆÁÊÌÁ <em>ÉÓÈ_ÆÁÊÌ</em> (ÐÕÔØ ÏÐÒÅÄÅÌÑÅÔÓÑ ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base") É ÐÒÅÏÂÒÁÚÕÅÔ ÅÇÏ × ÕËÁÚÁÎÎÙÊ ÆÏÒÍÁÔ, ÓÏÈÒÁÎÑÑ ÒÅÚÕÌØÔÁÔ × <em>ËÏÎ_ÆÁÊÌ</em>. åÓÌÉ ÚÁÄÁÎÙ ÍÁËÓÉÍÁÌØÎÁÑ ×ÙÓÏÔÁ É ÛÉÒÉÎÁ, ÂÏÌØÛÉÅ ÉÚÏÂÒÁÖÅÎÉÑ ÂÕÄÕÔ ÕÍÅÎØÛÅÎÙ.
-ðÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÉÎÓÔÒÕËÃÉÑ <code>&lt;%image:...%&gt;</code> ÂÕÄÅÔ ÚÁÍÅÎÅÎÁ ÎÁ ÚÎÁÞÅÎÉÅ <em>ËÏÎ_ÆÁÊÌ</em>, ÉÎÁÞÅ - ÎÁ ÐÕÓÔÕÀ ÓÔÒÏËÕ.</li>
-
-  <li><code>&lt;%copy:<em>ÉÓÈ_ÆÁÊÌ</em> <em>ËÏÎ_ÆÁÊÌ</em>%&gt;</code><br />
-  ëÏÐÉÒÕÅÔ ÆÁÊÌ <em>ÉÓÈ_ÆÁÊÌ</em> (ÐÕÔØ ÏÐÒÅÄÅÌÑÅÔÓÑ ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base") × <em>ËÏÎ_ÆÁÊÌ</em>. ðÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÉÎÓÔÒÕËÃÉÑ <code>&lt;%copy:...%&gt;</code> ÂÕÄÅÔ ÚÁÍÅÎÅÎÁ ÎÁ ÚÎÁÞÅÎÉÅ <em>ËÏÎ_ÆÁÊÌ</em>, ÉÎÁÞÅ - ÎÁ ÐÕÓÔÕÀ ÓÔÒÏËÕ.</li>
-</ul>
-
-<h3>÷ÓÔÒÏÅÎÎÙÅ ÐÅÒÅÍÅÎÎÙÅ</h3>
-
-<p><code>NUMBER</code> - ÐÏÒÑÄËÏ×ÙÊ ÎÏÍÅÒ ÓÔÒÏËÉ ÒÅÚÕÌØÔÁÔÁ ×ÙÐÏÌÎÅÎÉÑ ÚÁÐÒÏÓÁ.
-þÔÏÂÙ ÏÂÒÁÔÉÔØÓÑ Ë ÐÅÒÅÍÅÎÎÏÊ ÚÁÐÒÏÓÁ, ÉÚ ËÏÔÏÒÏÇÏ ÏÂÒÁÂÁÔÙ×ÁÅÍÙÊ ÛÁÂÌÏÎ ÂÙÌ ×ÙÚ×ÁÎ Ó ÐÏÍÏÝØÀ ÆÕÎËÃÉÉ invoke, ÐÅÒÅÄ ÉÍÅÎÅÍ ÐÅÒÅÍÅÎÎÏÊ ÎÕÖÎÏ ÄÏÂÁ×ÉÔØ <code>SUPER.</code> (ÎÁÐÒÉÍÅÒ: <code>SUPER.NUMBER</code>).</p>
-
-<h3>ðÒÉÍÅÒ</h3>
-
-<p>óÌÅÄÕÀÝÁÑ ÉÎÓÔÒÕËÃÉÑ ÐÏÌÕÞÉÔ ÚÎÁÞÅÎÉÅ ÉÚ ÓÔÏÌÂÃÁ name É ÚÁÍÅÎÉÔ × ÎÅÍ ÓÐÅÃÉÁÌØÎÙÅ ÓÉÍ×ÏÌÙ:</p>
-<p><code>&lt;%escape get:name%&gt;</code></p>
-
-<p align="right"><i><a href="mailto:kryshen@cs.karelia.ru">íÉÈÁÉÌ ëÒÙÛÅÎØ</a></i></p>
-
-</body>
-</html>
--- a/dist/readme.txt	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-text/plain; charset=UTF-8
-
-Установка программы
--------------------
-
-1. Распаковать архив.
-
-2. Установить источник данных:
-в Windows 2000: Панель управления/Администрирование/Источники данных (ODBC), добавить biotopes.mdb.
-
-3. Настроить программу:
-В файле dbreader.properties указать имя, присвоенное источнику данных:
-    "resource: jdbc:odbc:<имя>"
-и путь к каталогу, относительно которого программа будет искать изображения (содержащий biotopephotos и maps):
-    "resource_base: C:\\biotopes"
-(символ '\' необходимо дублировать)
-
-4. Запуск программы: dbreader.bat или "java -jar dbreader.jar"
-Для запуска необходима Java Runtime Environment (JRE) 5.0, можно скачать с http://java.sun.com/j2se/1.5.0/download.jsp. Возможно, будет работать и со старыми версиями JRE - не проверял.
-
-Все значения файла конфигурации можно переопределять при запуске программы:
-    команда "java -Dru.karrc.dbreader.<ключ>=<значение> -jar dbreader.jar"
-(например: "java -Dru.karrc.dbreader.log=dbreader.log -jar dbreader.jar")
-
-
-Работа программы
-----------------
-
-Программа выполняет запрос biotope.sql (или другой, указанный в dbreader.properties), после чего обрабатывает файл biotope.template, заменяя найденные в нем инструкции на результаты их выполнения.
-
-Формат инструкций: "<%список_функций[:|\]данные%>", список функций - имена функций разделенные пробелом, список может быть пустым. Если указано несколько функций, они выполняются начиная с последней.
-
-Разделители между списком функций и данными:
-':' - данные будут обрабатываться рекурсивно.
-'\' - данные будут переданы функции без обработки. Можно использовать для экранирования комбинаций символов "<%" и "%>" ("<%\<%%>" и "<%\%%>>").
-
-Функции:
-<%get:<имя>%> - заменяется на значение встроенной переменной или колонки запроса.
-
-<%optional:<текст>%>
-Заменяется на <текст>, если в нем найдены инструкции, заменившиеся на непустые строки, иначе заменяется на пустую строку.
-
-<%escape:<текст>%>
-Заменяет в тексте "опасные" символы (таблица замен задается в файле конфигурации).
-
-<%invoke:<имя> <парам1> <парам2> ... <парамN>%>
-Выполняет запрос с параметрами <имя>.sql и заменяется на результаты обработки шаблона <имя>.template. Значения параметров подставляются в запрос вместо символа '?'.
-
-<%image:<исх_файл> <кон_файл> <формат> [<макс_ширина>] [<макс_высота>]%>
-Загружает изображение из файла <исх_файл> (путь определяется относительно конфигурационного параметра "resource_base") и преобразует его в указанный формат, сохраняя результат в <кон_файл>. Если заданы максимальная высота и ширина, большие изображения будут уменьшены.
-При успешном выполнении, инструкция "<%!image ...%>" будет заменена на значение <кон_файл>, иначе - на пустую строку.
-
-<%copy:<исх_файл> <кон_файл>%>
-Копирует файл <исх_файл> (путь определяется относительно конфигурационного параметра "resource_base").
-При успешном выполнении, инструкция "<%!copy ...%>" будет заменена на значение <кон_файл>, иначе - на пустую строку.
-
-Встроенные переменные:
-NUMBER - порядковый номер строки результата выполнения запроса.
-Чтобы обратиться к переменной запроса, из которого обрабатываемый шаблон был вызван с помощью функции invoke, перед именем переменной нужно добавить "SUPER." (например: "SUPER.NUMBER").
-
-Пример:
-Следующая инструкция получит значение из столбца name и заменит в нем специальные символы:
-<%escape get:name%>
--- a/dist/tema	Tue May 16 18:04:09 2006 +0400
+++ b/dist/tema	Thu Dec 14 23:22:05 2006 +0300
@@ -1,3 +1,3 @@
 #!/bin/sh
 
-java -jar tema.jar
+java -jar tema.jar "$@"
--- a/dist/tema.bat	Tue May 16 18:04:09 2006 +0400
+++ b/dist/tema.bat	Thu Dec 14 23:22:05 2006 +0300
@@ -1,1 +1,1 @@
-java -jar tema.jar
+java -jar tema.jar %1
--- a/dist/tema.properties	Tue May 16 18:04:09 2006 +0400
+++ b/dist/tema.properties	Thu Dec 14 23:22:05 2006 +0300
@@ -9,14 +9,14 @@
 main_template     : main.template
 
 # File encodings
-# input_encoding    : ISO-8859-5
-# output_encoding   : ISO-8859-5
+# input_encoding    : UTF-8
+# output_encoding   : UTF-8
 
 # Cache templates
-cache_read        : true
+# cache_read        : true
 
 # Output main_template parsing result to stderr
-#output            : stderr
+# output            : stderr
 
 # File to output error messages (redirect stderr)
-#log               : tema.log
+# log               : tema.log
--- a/doc/article.txt	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,391 +0,0 @@
-* ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÂÁÚÙ ÄÁÎÎÙÈ × XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ ÂÉÂÌÉÏÔÅËÉ.
-
-äÌÑ ÒÅÛÅÎÉÑ ÚÁÄÁÞÉ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ ÂÁÚÙ ÄÁÎÎÙÈ "íÅÓÔÏÏÂÉÔÁÎÉÑ ÷ÏÓÔÏÞÎÏÊ
-æÅÎÎÏÓËÁÎÄÉÉ" ÉÚ ÆÏÒÍÁÔÁ Microsoft Access × XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ
-ÂÉÂÌÉÏÔÅËÉ ëÁÒîã òáî ÂÙÌÁ ÒÁÚÒÁÂÏÔÁÎÁ ÐÒÏÇÒÁÍÍÎÁÑ ÓÉÓÔÅÍÁ DbReader.
-
-ðÒÏÇÒÁÍÍÁ DbReader Ñ×ÌÑÅÔÓÑ ÕÎÉ×ÅÒÓÁÌØÎÙÍ ÓÒÅÄÓÔ×ÏÍ ÄÌÑ ÐÒÅÄÓÔÁ×ÌÅÎÉÑ
-ÉÎÆÏÒÍÁÃÉÉ ÉÚ ÂÁÚ ÄÁÎÎÙÈ × ÔÅËÓÔÏ×ÙÈ ÆÏÒÍÁÔÁÈ. ðÒÏÇÒÁÍÍÁ ÏÂÒÁÂÁÔÙ×ÁÅÔ
-ÚÁÄÁÎÎÙÅ ÛÁÂÌÏÎÙ ÔÅËÓÔÏ×ÙÈ ÆÁÊÌÏ× É ÚÁÍÅÎÑÅÔ ÎÁÊÄÅÎÎÙÅ × ÎÉÈ
-ÉÎÓÔÒÕËÃÉÉ ÎÁ ÒÅÚÕÌØÔÁÔÙ ÉÈ ×ÙÐÏÌÎÅÎÉÑ. òÁÚÌÉÞÎÙÅ ÉÎÓÔÒÕËÃÉÉ ÐÏÚ×ÏÌÑÀÔ
-ÆÏÒÍÉÒÏ×ÁÔØ SQL-ÚÁÐÒÏÓÙ, ×ÙÐÏÌÎÑÔØ ÉÈ É ÏÂÒÁÂÁÔÙ×ÁÔØ ÐÏÌÕÞÅÎÎÙÅ
-ÄÁÎÎÙÅ.
-
-
-* æÏÒÍÁÔ ÉÎÓÔÒÕËÃÉÊ:
-
-    <%<ÓÐÉÓÏË_ÆÕÎËÃÉÊ>{:|\}<ÄÁÎÎÙÅ>%>
-  ÇÄÅ 
-
-<ÓÐÉÓÏË_ÆÕÎËÃÉÊ> - ÓÐÉÓÏË ÉÍÅÎ ÆÕÎËÃÉÊ, ÒÁÚÄÅÌÅÎÎÙÈ ÐÒÏÂÅÌÁÍÉ.
-    íÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ.
-<ÄÁÎÎÙÅ> - ÄÁÎÎÙÅ, ÐÅÒÅÄÁ×ÁÅÍÙÅ ÆÕÎËÃÉÉ.
-
-
-* æÏÒÍÁÔ ÄÁÎÎÙÈ:
-
-    [<ÓÐÉÓÏË_ÁÒÇÕÍÅÎÔÏ×>][<ÔÅËÓÔ>]
-  ÇÄÅ
-
-<ÓÐÉÓÏË_ÁÒÇÕÍÅÎÔÏ×> - ÓÐÉÓÏË ÁÒÇÕÍÅÎÔÏ× ÆÕÎËÃÉÉ, ÒÁÚÄÅÌÅÎÎÙÈ ÐÒÏÂÅÌÁÍÉ.
-    íÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ.
-<ÔÅËÓÔ> - ÔÅËÓÔ, ÐÅÒÅÄÁ×ÁÅÍÙÊ ÆÕÎËÃÉÉ ÂÅÚ ÒÁÚÂÉÅÎÉÑ ÎÁ ÁÒÇÕÍÅÎÔÙ.
-    íÏÖÅÔ ÂÙÔØ ÐÕÓÔÙÍ. ëÏÌÉÞÅÓÔ×Ï ÁÒÇÕÍÅÎÔÏ×, ÐÏÓÌÅ ËÏÔÏÒÏÇÏ ÓÌÅÄÕÅÔ
-    ÔÅËÓÔ, ÚÁ×ÉÓÉÔ ÏÔ ÆÕÎËÃÉÉ.
-
-òÁÚÄÅÌÉÔÅÌØ ÍÅÖÄÕ ÓÐÉÓËÏÍ ÆÕÎËÃÉÊ É ÄÁÎÎÙÍÉ ÏÐÒÅÄÅÌÑÅÔ, ËÁË ÄÏÌÖÎÙ
-ÏÂÒÁÂÁÔÙ×ÁÔØÓÑ ÄÁÎÎÙÅ ÆÕÎËÃÉÉ:
-: - ÒÅËÕÒÓÉ×ÎÁÑ ÏÂÒÁÂÏÔËÁ,
-\ - ÐÅÒÅÄÁÔØ ÂÅÚ ÏÂÒÁÂÏÔËÉ.
-
-åÓÌÉ × ÓÐÉÓËÅ ÆÕÎËÃÉÊ ÚÁÄÁÎÏ Ä×Å É ÂÏÌÅÅ ÆÕÎËÃÉÉ, ÏÎÉ ×ÙÐÏÌÎÑÀÔÓÑ,
-ÎÁÞÉÎÁÑ Ó ÐÏÓÌÅÄÎÅÊ, ÔÁË ÞÔÏ ËÁÖÄÁÑ ÆÕÎËÃÉÑ ÐÏÌÕÞÁÅÔ × ËÁÞÅÓÔ×Å ÄÁÎÎÙÈ
-ÒÅÚÕÌØÔÁÔ ×ÙÐÏÌÎÅÎÉÑ ÓÌÅÄÕÀÝÅÊ ÆÕÎËÃÉÉ.
-
-ëÁÖÄÁÑ ÆÕÎËÃÉÑ ÉÍÅÅÔ ËÏÄ ×ÏÚ×ÒÁÔÁ - ÃÅÌÏÅ ÞÉÓÌÏ. ëÏÄ ×ÏÚ×ÒÁÔÁ
-ÉÎÓÔÒÕËÃÉÉ - ËÏÄ ×ÏÚ×ÒÁÔÁ ÐÅÒ×ÏÊ × ÓÐÉÓËÅ ÆÕÎËÃÉÉ. ëÏÄ ×ÏÚ×ÒÁÔÁ,
-ÐÏÌÕÞÁÅÍÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ - ÓÕÍÍÁ ËÏÄÏ× ×ÏÚ×ÒÁÔÁ ÏÂÒÁÂÏÔÁÎÎÙÈ
-ÉÎÓÔÒÕËÃÉÊ.
-
-÷ÍÅÓÔÏ ÓËÏÂÏË '<', '>' ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ÓËÏÂËÉ '[', ']'.
-
-
-* òÅÁÌÉÚÏ×ÁÎÎÙÅ ÆÕÎËÃÉÉ:
-
-æÕÎËÃÉÑ:      set
-áÒÇÕÍÅÎÔÙ:    <ÉÍÑ>
-ôÅËÓÔ:        <ÚÎÁÞÅÎÉÅ>
-äÅÊÓÔ×ÉÅ:     ÕÓÔÁÎÁ×ÌÉ×ÁÅÔ ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ <ÉÍÑ>
-òÅÚÕÌØÔÁÔ:    <ÉÍÑ>
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1
-
-æÕÎËÃÉÑ:      get
-áÒÇÕÍÅÎÔÙ:    <ÉÍÑ>
-òÅÚÕÌØÔÁÔ:    ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ <ÉÍÑ>. 
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1, ÅÓÌÉ ÚÎÁÞÅÎÉÅ ÐÅÒÅÍÅÎÎÏÊ ÂÙÌÏ ÕÓÔÁÎÏ×ÌÅÎÏ, 0 - ÉÎÁÞÅ.
-
-æÕÎËÃÉÑ:      prepare
-áÒÇÕÍÅÎÔÙ:    <ÉÍÑ>
-ôÅËÓÔ:        <ÚÁÐÒÏÓ>
-äÅÊÓÔ×ÉÅ:     ðÏÄÇÏÔÁ×ÌÉ×ÁÅÔ SQL-ÚÁÐÒÏÓ <ÚÁÐÒÏÓ> ÄÌÑ ×ÙÐÏÌÎÅÎÉÑ,
-              ÚÁÐÉÓÙ×ÁÅÔ ÐÏÄÇÏÔÏ×ÌÅÎÎÙÊ ÚÁÐÒÏÓ × ÐÅÒÅÍÅÎÎÕÀ <ÉÍÑ>.
-òÅÚÕÌØÔÁÔ:    <ÉÍÑ>
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1
-
-æÕÎËÃÉÑ:      query
-áÒÇÕÍÅÎÔÙ:    <ÉÍÑ_ÚÁÐÒÏÓÁ> <ÛÁÂÌÏÎ> <ÐÁÒÁÍ1> ... <ÐÁÒÁÍN>
-äÅÊÓÔ×ÉÅ:     ÷ÙÐÏÌÎÑÅÔ ÚÁÐÒÏÓ Ó ÐÁÒÁÍÅÔÒÁÍÉ, ÐÏÄÇÏÔÏ×ÌÅÎÎÙÊ Ó ÐÏÍÏÝØÀ
-              ÆÕÎËÃÉÉ prepare. úÎÁÞÅÎÉÑ ÐÁÒÁÍÅÔÒÏ× ÐÏÄÓÔÁ×ÌÑÀÔÓÑ ×
-              ÚÁÐÒÏÓ ×ÍÅÓÔÏ ÓÉÍ×ÏÌÁ '?'. úÎÁÞÅÎÉÑ ÐÏÌÅÊ ÏÔ×ÅÔÁ ÂÕÄÕÔ
-              ÚÁÐÉÓÁÎÙ, ËÁË ÐÅÒÅÍÅÎÎÙÅ ÛÁÂÌÏÎÁ <ÛÁÂÌÏÎ>. ðÒÉ ÏÂÒÁÂÏÔËÉ
-              ÛÁÂÌÏÎÁ <ÛÁÂÌÏÎ> ÔÁËÖÅ ÏÐÒÅÄÅÌÑÅÔÓÑ ÐÅÒÅÍÅÎÎÁÑ NUMBER,
-              ÓÏÄÅÒÖÁÝÁÑ ÎÏÍÅÒ ÔÅËÕÝÅÊ ÓÔÒÏËÉ ÏÔ×ÅÔÁ. ðÅÒÅÍÅÎÎÙÅ,
-              ÏÐÒÅÄÅÌÅÎÎÙÅ × ×ÙÚÙ×ÁÀÝÅÍ ÛÁÂÌÏÎÅ, ÄÏÓÔÕÐÎÙ ÉÚ ÛÁÂÌÏÎÁ
-              <ÛÁÂÌÏÎ> ÐÏ ÉÍÅÎÉ SUPER.<ÉÍÑ_ÐÅÒÅÍÅÎÎÏÊ>.
-
-òÅÚÕÌØÔÁÔ:    ÒÅÚÕÌØÔÁÔ ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ <ÛÁÂÌÏÎ> ÄÌÑ ËÁÖÄÏÊ ÓÔÒÏËÉ
-              ÏÔ×ÅÔÁ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÌÉÞÅÓÔ×Ï ÐÏÌÕÞÅÎÎÙÈ ÓÔÒÏË ÏÔ×ÅÔÁ.
-
-æÕÎËÃÉÑ:      optional
-ôÅËÓÔ:        <ÄÁÎÎÙÅ>
-òÅÚÕÌØÔÁÔ:    <ÄÁÎÎÙÅ>, ÅÓÌÉ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÄÁÎÎÙÈ ÂÙÌ ÐÏÌÕÞÅÎ
-              ËÏÄ ×ÏÚ×ÒÁÔÁ ÏÔÌÉÞÎÙÊ ÏÔ 0, ÉÎÁÞÅ - ÐÕÓÔÁÑ ÓÔÒÏËÁ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1, ÅÓÌÉ ÒÅÚÕÌØÔÁÔ - ÐÕÓÔÁÑ ÓÔÒÏËÁ, 0 - ÉÎÁÞÅ.
-
-æÕÎËÃÉÑ:      image
-áÒÇÕÍÅÎÔÙ:    <ÉÓÈ_ÆÁÊÌ> <ËÏÎ_ÆÁÊÌ> <ÆÏÒÍÁÔ> [<ÍÁËÓ_ÛÉÒÉÎÁ> [<ÍÁËÓ_×ÙÓÏÔÁ>]]
-äÅÊÓÔ×ÉÅ:     úÁÇÒÕÖÁÅÔ ÉÚÏÂÒÁÖÅÎÉÅ ÉÚ ÆÁÊÌÁ <ÉÓÈ_ÆÁÊÌ> (ÐÕÔØ ÏÐÒÅÄÅÌÑÅÔÓÑ
-              ÏÔÎÏÓÉÔÅÌØÎÏ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base") É
-              ÐÒÅÏÂÒÁÚÕÅÔ ÅÇÏ × ÕËÁÚÁÎÎÙÊ ÆÏÒÍÁÔ, ÓÏÈÒÁÎÑÑ ÒÅÚÕÌØÔÁÔ ×
-              <ËÏÎ_ÆÁÊÌ>. åÓÌÉ ÚÁÄÁÎÙ ÍÁËÓÉÍÁÌØÎÁÑ ×ÙÓÏÔÁ É ÛÉÒÉÎÁ, ÂÏÌØÛÉÅ
-              ÉÚÏÂÒÁÖÅÎÉÑ ÂÕÄÕÔ ÕÍÅÎØÛÅÎÙ. 
-òÅÚÕÌØÔÁÔ:    <ËÏÎ_ÆÁÊÌ> ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ ÓÔÒÏËÁ - ÉÎÁÞÅ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
-
-æÕÎËÃÉÑ:      copy
-áÒÇÕÍÅÎÔÙ:    <ÉÓÈ_ÆÁÊÌ> <ËÏÎ_ÆÁÊÌ>
-äÅÊÓÔ×ÉÅ:     ëÏÐÉÒÕÅÔ ÆÁÊÌ <ÉÓÈ_ÆÁÊÌ> × ÆÁÊÌ <ËÏÎ_ÆÁÊÌ>
-	      (ÐÕÔØ <ÉÓÈ_ÆÁÊÌ> ÏÐÒÅÄÅÌÑÅÔÓÑ ÏÔÎÏÓÉÔÅÌØÎÏ
-              ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÐÁÒÁÍÅÔÒÁ "resource_base").
-òÅÚÕÌØÔÁÔ:    <ËÏÎ_ÆÁÊÌ> ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ ÓÔÒÏËÁ - ÉÎÁÞÅ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
-
-æÕÎËÃÉÑ:      write
-áÒÇÕÍÅÎÔÙ:    <ÉÍÑ_ÆÁÊÌÁ>
-ôÅËÓÔ:        <ÄÁÎÎÙÅ>
-äÅÊÓÔ×ÉÅ:     úÁÐÉÓÙ×ÁÅÔ <ÄÁÎÎÙÅ> × ÆÁÊÌ <ÉÓÈ_ÆÁÊÌ>.
-òÅÚÕÌØÔÁÔ:    <ËÏÎ_ÆÁÊÌ> ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ ÓÔÒÏËÁ - ÉÎÁÞÅ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
-
-æÕÎËÃÉÑ:      read
-ôÅËÓÔ:        <ÉÍÑ_ÆÁÊÌÁ>
-äÅÊÓÔ×ÉÅ:     þÉÔÁÅÔ ÆÁÊÌ <ÉÍÑ_ÆÁÊÌÁ>.
-òÅÚÕÌØÔÁÔ:    ÐÒÏÞÉÔÁÎÎÙÅ ÄÁÎÎÙÅ ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, ÐÕÓÔÁÑ
-              ÓÔÒÏËÁ - ÉÎÁÞÅ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: 1 ÐÒÉ ÕÓÐÅÛÎÏÍ ×ÙÐÏÌÎÅÎÉÉ, 0 - ÉÎÁÞÅ.
-
-æÕÎËÃÉÑ:      include
-ôÅËÓÔ:        <ÉÍÑ_ÆÁÊÌÁ>
-äÅÊÓÔ×ÉÅ:     ×ËÌÀÞÁÅÔ ÛÁÂÌÏÎ ÉÚ ÆÁÊÌÁ <ÉÍÑ_ÆÁÊÌÁ>.
-òÅÚÕÌØÔÁÔ:    ÒÅÚÕÌØÔÁÔ ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÛÁÂÌÏÎÁ.
-
-æÕÎËÃÉÑ:      !
-ôÅËÓÔ:        <ÄÁÎÎÙÅ>
-äÅÊÓÔ×ÉÅ:     ÎÅÔ.
-òÅÚÕÌØÔÁÔ:    ÎÅÔ.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
-
-æÕÎËÃÉÑ:      replace
-áÒÇÕÍÅÎÔÙ:    <ÓÔÒ1> <ÓÔÒ2>
-ôÅËÓÔ:        <ÄÁÎÎÙÅ>
-òÅÚÕÌØÔÁÔ:    ÄÁÎÎÙÅ, Ó ÚÁÍÅÎÅÎÎÙÍÉ ×ÈÏÖÄÅÎÉÑÍÉ ÐÏÄÓÔÒÏËÉ <ÓÔÒ1>
-	      ÎÁ <ÓÔÒ2>.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
-
-æÕÎËÃÉÑ:      xml_escape
-ôÅËÓÔ:        <ÄÁÎÎÙÅ>
-òÅÚÕÌØÔÁÔ:    ÔÅËÓÔ <ÄÁÎÎÙÅ>, × ËÏÔÏÒÏÍ  ÓÉÍ×ÏÌÙ
-              '&', '<', '>', '`', '\' ÚÁÍÅÎÅÎÙ ÎÁ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÅ
-	      ÓÕÝÎÏÓÔÉ XML.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
-
-æÕÎËÃÉÑ:      xml_cdata
-ôÅËÓÔ:        <ÄÁÎÎÙÅ>
-òÅÚÕÌØÔÁÔ:    ÄÁÎÎÙÅ × ×ÉÄÅ ÂÌÏËÁ XML CDATA.
-ëÏÄ ×ÏÚ×ÒÁÔÁ: ËÏÄ ×ÏÚ×ÒÁÔÁ, ÐÏÌÕÞÅÎÎÙÊ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÔÅËÓÔÁ ÄÁÎÎÙÈ.
-
-óÉÓÔÅÍÁ DbReader ÒÁÓÛÉÒÑÅÍÁ: ×ÏÚÍÏÖÎÏ ÄÏÂÁ×ÌÅÎÉÅ × ÓÉÓÔÅÍÕ ÎÏ×ÙÈ
-ÆÕÎËÃÉÊ, ÒÅÁÌÉÚÏ×ÁÎÎÙÈ × ×ÉÄÅ ËÌÁÓÓÏ× ÎÁ ÑÚÙËÅ Java.
-
-
-* ðÒÉÍÅÎÅÎÉÅ ÓÉÓÔÅÍÙ DbReader ÄÌÑ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ ÂÁÚÙ ÄÁÎÎÙÈ
-  "íÅÓÔÏÏÂÉÔÁÎÉÑ ÷ÏÓÔÏÞÎÏÊ æÅÎÎÏÓËÁÎÄÉÉ" ÉÚ ÆÏÒÍÁÔÁ Microsoft Access ×
-  XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ ÂÉÂÌÉÏÔÅËÉ ëÁÒîã òáî
-
-äÌÑ ÐÒÅÏÂÒÁÚÏ×ÁÎÉÑ ÉÓÐÏÌØÚÕÀÔÓÑ Ä×Å ÔÁÂÌÉÃÙ ÂÁÚÙ ÄÁÎÎÙÈ "íÅÓÔÏÏÂÉÔÁÎÉÑ
-÷ÏÓÔÏÞÎÏÊ æÅÎÎÏÓËÁÎÄÉÉ" (ÐÅÒÅÞÉÓÌÅÎÙ ÔÏÌØËÏ ÉÓÐÏÌØÚÕÅÍÙÅ ÐÏÌÑ):
-
-biotopelist (code, rangcode, rusname, engname, descript, geobotdescr,
-             contributors, descrdate)
-
-  code - ÓÞÅÔÞÉË, ËÌÀÞÅ×ÏÅ ÐÏÌÅ;
-  rangcode - ÐÏÌÅ × ÆÏÒÍÁÔÅ ABBCCDDEE, ÇÄÅ á, BB, CC, DD, åå - ËÏÄÙ
-             ËÌÁÓÓÁ, ÐÏÄËÌÁÓÓÏ× É ÒÁÓÔÅÎÉÑ;
-  rusname, engname, descript, geobotdescr - ÔÅËÓÔÏ×ÙÅ ÐÏÌÑ;
-  descrdate - ÄÁÔÁ.
-
-photos (biotope, photo, authphoto)
-
-  biotope - ÞÉÓÌÏ, ÕËÁÚÙ×ÁÅÔ ÎÁ code × biotopelist;
-  photo - ÉÍÑ ÆÁÊÌÁ ÆÏÔÏÇÒÁÆÉÉ;
-  authphoto - ÔÅËÓÔ.
-
-ôÒÅÂÕÅÔÓÑ ÓÇÅÎÅÒÉÒÏ×ÁÔØ xml-ÆÁÊÌ ÄÌÑ ËÁÖÄÏÊ ÚÁÐÉÓÉ × biotopelist, ÆÁÊÌ
-ÓÏ ÓÐÉÓËÏÍ ËÌÁÓÓÏ×, ÆÁÊÌ ÓÏ ÓÐÉÓËÏÍ ÒÁÓÔÅÎÉÊ, ÐÏÌÎÏÒÁÚÍÅÒÎÙÅ É
-ÕÍÅÎØÛÅÎÎÙÅ ×ÅÒÓÉÉ ËÁÖÄÏÊ ÆÏÔÏÇÒÁÆÉÉ.
-
-äÌÑ ÇÅÎÅÒÁÃÉÉ xml-ÆÁÊÌÏ× Ó ÏÐÉÓÁÎÉÑÍÉ ÂÉÏÔÏÐÏ× ÉÓÐÏÌØÚÏ×ÁÌÓÑ ÓÌÅÄÕÀÝÉÊ
-ÛÁÂÌÏÎ DbReader (ÆÁÊÌ biotope.template):
-
-----------------------------------------------------------------------
-<?xml version="1.0" encoding="ISO-8859-5"?>
-<!DOCTYPE ÏÐÉÓÁÎÉÅ_×ÉÄÁ SYSTEM "brief.dtd">
-<!-- rangcode: <%xml_escape get\rangcode%> -->
-<ÏÐÉÓÁÎÉÅ_×ÉÄÁ show="0">
-  <ÒÉÓÕÎËÉ display="0">
-    <%optional:<ËÁÒÔÁ_ÒÁÓÐÒÏÓÔÒÁÎÅÎÉÑ ÎÏÍÅÒ="1"
-    file="<%xml_escape image:maps/<%get\rangcode%>.gif maps/<%get\code%>.png png%>"/>%>
-<%query:photo_sql [%\<%include\photo.template%>%] <%get\code%>%>
-  </ÒÉÓÕÎËÉ>
-  <ÎÁÚ×ÁÎÉÅ><%xml_escape get\rusname%></ÎÁÚ×ÁÎÉÅ>
-  <ËÌÁÓÓ><%xml_escape get\class0%></ËÌÁÓÓ>
-  <ÐÏÄËÌÁÓÓ1><%xml_escape get\class1%></ÐÏÄËÌÁÓÓ1>
-  <ÐÏÄËÌÁÓÓ2><%xml_escape get\class2%></ÐÏÄËÌÁÓÓ2>
-  <ÐÏÄËÌÁÓÓ3><%xml_escape get\class3%></ÐÏÄËÌÁÓÓ3>
-  <ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ rows="3"><%xml_cdata get\descript%></ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ>
-  <ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ rows="3"><%xml_cdata get\geobotdescr%></ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ>
-  <Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ><%xml_escape get\contributors%></Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ>
-</ÏÐÉÓÁÎÉÅ_×ÉÄÁ>
-----------------------------------------------------------------------
-
-óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ, ÐÒÉ ×ÙÐÏÌÎÅÎÉÉ ËÏÔÏÒÏÇÏ ÕÓÔÁÎÁ×ÌÉ×ÁÀÔÓÑ
-ÚÎÁÞÅÎÉÑ ÐÅÒÅÍÅÎÎÙÈ ÛÁÂÌÏÎÁ rangcode, rusname, class0, class1, class2,
-class3, descript, geobotdescr É contributors (ÆÁÊÌ biotope.sql):
-
-----------------------------------------------------------------------
-SELECT t1.*,
-
-(SELECT t2.rusname FROM biotopelist AS t2
-WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1)
-AND Right(t2.rangcode, 8)  = '00000000'
-AND Right(t1.rangcode, 8) <> '00000000') AS class0,
-
-(SELECT t2.rusname FROM biotopelist AS t2
-WHERE Left(t2.rangcode, 3) = Left(t1.rangcode, 3)
-AND Right(t2.rangcode, 6)  = '000000'
-AND Right(t1.rangcode, 6) <> '000000') AS class1,
-
-(SELECT t2.rusname FROM biotopelist AS t2
-WHERE Left(t2.rangcode, 5) = Left(t1.rangcode, 5)
-AND Right(t2.rangcode, 4)  = '0000'
-AND Right(t1.rangcode, 4) <> '0000') AS class2,
-
-(SELECT t2.rusname FROM biotopelist AS t2
-WHERE Left(t2.rangcode, 7) = Left(t1.rangcode, 7)
-AND Right(t2.rangcode, 2)  = '00'
-AND Right(t1.rangcode, 2) <> '00') AS class3
-
-FROM biotopelist AS t1
-WHERE rusname
-----------------------------------------------------------------------
-
-ûÁÂÌÏÎ biotope.template ÓÏÄÅÒÖÉÔ ÉÎÓÔÒÕËÃÉÀ <%include\photo.template%>,
-×ËÌÀÞÁÀÝÕÀ ÛÁÂÌÏÎ ÏÐÉÓÁÎÉÑ ÆÏÔÏÇÒÁÆÉÉ (ÆÁÊÌ photo.template):
-
-----------------------------------------------------------------------
-    <ÆÏÔÏÇÒÁÆÉÑ num="<%xml_escape get\NUMBER%>"
-       <%optional:Á×ÔÏÒ="<%xml_escape get\authphoto%>" %>text="" 
-       file="<%xml_escape image:biotopephotos/<%get\photo%> images/<%get\SUPER.code%>_<%get\NUMBER%>.jpg jpg 300 300%>" 
-        big="<%xml_escape copy:biotopephotos/<%get\photo%> images/big/<%get\SUPER.code%>_<%get\NUMBER%>.jpg%>"/>
-----------------------------------------------------------------------
-
-óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ ÄÌÑ ÐÏÌÕÞÅÎÉÑ ÏÐÉÓÁÎÉÑ ÆÏÔÏÇÒÁÆÉÊ
-(photo.sql):
-
-----------------------------------------------------------------------
-SELECT * from photos WHERE biotope = ?
-----------------------------------------------------------------------
-
-ûÁÂÌÏÎ, ÇÅÎÅÒÉÒÕÀÝÉÊ ÓÐÉÓÏË ËÌÁÓÓÏ× (ÆÁÊÌ classes.template):
-
-----------------------------------------------------------------------
-<?xml version="1.0" encoding="ISO-8859-5"?>
-<ËÌÁÓÓÉÆÉËÁÃÉÑ><%query:class_sql [%\
-  <!-- rangcode: <%xml_escape get\rangcode%> -->
-  <ËÌÁÓÓ id="<%get\NUMBER%>"><%xml_escape get\rusname%></ËÌÁÓÓ>%]%>
-</ËÌÁÓÓÉÆÉËÁÃÉÑ>
-----------------------------------------------------------------------
-
-óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ (class.sql):
-
-----------------------------------------------------------------------
-SELECT t1.*
-FROM biotopelist AS t1
-WHERE rusname AND Right(t1.rangcode, 8)  = '00000000'
-  AND EXISTS
-    (SELECT NULL FROM biotopelist AS t2
-     WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1)
-     AND Right(t2.rangcode, 8) <> '00000000')
-----------------------------------------------------------------------
-
-ûÁÂÌÏÎ, ÇÅÎÅÒÉÒÕÀÝÉÊ ÓÐÉÓÏË ÒÁÓÔÅÎÉÊ (ÆÁÊÌ plants.template):
-
-----------------------------------------------------------------------
-<?xml version="1.0" encoding="ISO-8859-5"?>
-<ÒÁÓÔÅÎÉÑ><%query:plant_sql [%\
-  <!-- rangcode: <%xml_escape get\rangcode%> -->
-  <ÒÁÓÔÅÎÉÅ><%xml_escape get\rusname%></ÒÁÓÔÅÎÉÅ>%]%>
-</ÒÁÓÔÅÎÉÑ>
-----------------------------------------------------------------------
-
-óÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ SQL-ÚÁÐÒÏÓ (plant.sql):
-
-----------------------------------------------------------------------
-SELECT t1.*
-FROM biotopelist AS t1
-WHERE rusname AND Right(t1.rangcode, 2) <> '00'
-----------------------------------------------------------------------
-
-óÉÓÔÅÍÁ DbReader ÎÁÞÉÎÁÅÔ ÒÁÂÏÔÕ Ó ÏÂÒÁÂÏÔËÉ ÛÁÂÌÏÎÁ index.template,
-ËÏÔÏÒÙÊ ÓÏÄÅÒÖÉÔ ×ÙÚÏ×Ù ÐÅÒÅÞÉÓÌÅÎÎÙÈ ×ÙÛÅ SQL-ÚÁÐÒÏÓÏ× É ×ËÌÀÞÅÎÉÑ
-ÛÁÂÌÏÎÏ×:
-
-----------------------------------------------------------------------
-<%!:
-  <%prepare:biotope_sql <%read\biotope.sql%>%>
-  <%prepare:photo_sql <%read\photo.sql%>%>
-  <%prepare:class_sql <%read\class.sql%>%>
-  <%prepare:plant_sql <%read\plant.sql%>%>
-
-  <%query:biotope_sql [%\<%write:<%get\code%>.xml <%include\biotope.template%>%> %]%>
-
-  <%write:classes.xml <%include\classes.template%>%>
-  <%write:plants.xml <%include\plants.template%>%>
-%>
-----------------------------------------------------------------------
-
-ðÒÉÍÅÒ ÓÇÅÎÅÒÉÒÏ×ÁÎÎÏÇÏ XML-ÆÁÊÌÁ:
-
-----------------------------------------------------------------------
-<?xml version="1.0" encoding="ISO-8859-5"?>
-<!DOCTYPE ÏÐÉÓÁÎÉÅ_×ÉÄÁ SYSTEM "brief.dtd">
-<!-- rangcode: E04020302 -->
-<ÏÐÉÓÁÎÉÅ_×ÉÄÁ show="0">
-  <ÒÉÓÕÎËÉ display="0">    
-    <ÆÏÔÏÇÒÁÆÉÑ num="1" Á×ÔÏÒ="ëÒÙÛÅÎØ á.í." text="" 
-                file="images/3_1.jpg" 
-                big="images/big/3_1.jpg"/>
-    <ÆÏÔÏÇÒÁÆÉÑ num="2" Á×ÔÏÒ="ëÒÙÛÅÎØ á.í." text="" 
-                file="images/3_2.jpg" 
-                big="images/big/3_2.jpg"/>
-  </ÒÉÓÕÎËÉ>
-  <ÎÁÚ×ÁÎÉÅ>Betula sp. - Avenella flexuosa - Polytrichum commune</ÎÁÚ×ÁÎÉÅ>
-  <ËÌÁÓÓ>E. óÕÈÏÄÏÌØÎÙÅ ÍÅÓÔÏÏÂÉÔÁÎÉÑ</ËÌÁÓÓ>
-  <ÐÏÄËÌÁÓÓ1>á×ÔÏÍÏÒÆÎÙÅ ×ÌÁÖÎÙÅ</ÐÏÄËÌÁÓÓ1>
-  <ÐÏÄËÌÁÓÓ2></ÐÏÄËÌÁÓÓ2>
-  <ÐÏÄËÌÁÓÓ3></ÐÏÄËÌÁÓÓ3>
-  <ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ rows="3"><![CDATA[òÁÚ×É×ÁÀÔÓÑ  ÎÁ ÌÕÇÏ×ÉËÏ×ÙÈ ×ÙÒÕÂËÁÈ ÌÅÓÏ× ÞÅÒÎÉÞÎÏÇÏ ÔÉÐÁ.  þÅÒÅÚ 5 - 7 ÌÅÔ  ÐÏÓÌÅ ÒÕÂËÉ ÐÏÒÏÓÌÅ×ÁÑ ÂÅÒÅÚÁ ×ÙÈÏÄÉÔ ÉÚ  ÑÒÕÓÁ ÔÒÁ×ÑÎÉÓÔÙÈ ÒÁÓÔÅÎÉÊ, ÅÅ ×ÌÉÑÎÉÅ ÓËÁÚÙ×ÁÅÔÓÑ, × ÐÅÒ×ÕÀ ÏÞÅÒÅÄØ, ÎÁ ×ÌÁÖÎÏÓÔÉ ÐÏÞ×Ù.]]></ËÒÁÔËÁÑ_ÈÁÒÁËÔÅÒÉÓÔÉËÁ>
-  <ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ rows="3"></ÐÒÉÍÅÒ_ÏÐÉÓÁÎÉÑ>
-  <Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ></Á×ÔÏÒÙ_ÏÐÉÓÁÎÉÑ>
-</ÏÐÉÓÁÎÉÅ_×ÉÄÁ>
-----------------------------------------------------------------------
-
-
-* óÔÒÕËÔÕÒÁ ÐÒÏÇÒÁÍÍÙ DbReader
-
-ðÒÏÇÒÁÍÍÁ DbReader ÎÁÐÉÓÁÎÁ ÎÁ ÑÚÙËÅ ÐÒÏÇÒÁÍÍÉÒÏ×ÁÎÉÑ Java É ÓÏÓÔÏÉÔ
-ÉÚ ÓÌÅÄÕÀÝÉÈ ÏÓÎÏ×ÎÙÈ ËÌÁÓÓÏ×:
-
-ru.karrc.dbreader.DbReader: cÏÄÅÒÖÉÔ ÔÏÞËÕ ×ÈÏÄÁ ÐÒÏÇÒÁÍÍÙ. úÁÇÒÕÖÁÅÔ
-ËÏÎÆÉÇÕÒÁÃÉÀ, ÕÓÔÁÎÁ×ÌÉ×ÁÅÔ ÓÏÅÄÉÎÅÎÉÅ Ó ÉÓÔÏÞÎÉËÏÍ ÄÁÎÎÙÈ Ó ÐÏÍÏÝØÀ
-ÂÉÂÌÉÏÔÅËÉ JDBC, ÚÁÐÕÓËÁÅÔ ÏÂÒÁÂÏÔËÕ ÏÓÎÏ×ÎÏÇÏ ÛÁÂÌÏÎÁ.
-
-ru.karrc.dbreader.TemplateParser: ÏÓÕÝÅÓÔ×ÌÑÅÔ ÒÁÚÂÏÒ ÛÁÂÌÏÎÁ,
-ÏÂÒÁÂÏÔËÕ ÉÎÓÔÒÕËÃÉÊ É ×ÙÚÏ× ÆÕÎËÃÉÊ.
-
-ru.karrc.dbreader.Function: ÁÂÓÔÒÁËÔÎÙÊ ËÌÁÓÓ. òÅÁÌÉÚÁÃÉÉ ×ÓÅÈ ÆÕÎËÃÉÊ
-DbReader ÎÁÓÌÅÄÕÀÔ ÜÔÏÔ ËÌÁÓÓ.
-
-ru.karrc.dbreader.FunctionDataParser: ÏÂÒÁÂÏÔÞÉË ÄÁÎÎÙÈ
-ÆÕÎËÃÉÉ. ðÏÓ×ÏÌÑÅÔ ÐÏÌÕÞÉÔØ ÓÐÉÓÏË ÁÒÇÕÍÅÎÔÏ× É ÔÅËÓÔ, ÐÅÒÅÄÁ×ÁÅÍÙÊ
-ÆÕÎËÃÉÉ. ðÒÉ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ×ÙÚÙ×ÁÅÔ ÒÅËÕÒÓÉ×ÎÕÀ ÏÂÒÁÂÏÔËÕ ÄÁÎÎÙÈ Ó
-ÐÏÍÏÝØÀ TemplateParser.
-
-ru.karrc.dbreader.Functions: ÓÏÄÅÒÖÉÔ ÒÅÁÌÉÚÁÃÉÉ ÆÕÎËÃÉÊ × ×ÉÄÅ
-ÁÎÏÎÉÍÎÙÈ ËÌÁÓÓÏ×, ÎÁÓÌÅÄÕÀÝÉÈ Function.
-
-ru.karrc.dbreader.TemplateParser: ÉÓËÌÀÞÅÎÉÅ, ×ÙÂÒÁÓÙ×ÁÅÍÏÅ × ÓÌÕÞÁÅ
-×ÏÚÎÉËÎÏ×ÅÎÉÑ ÏÛÉÂËÉ ÐÒÉ ÏÂÒÁÂÏÔËÅ ÛÁÂÌÏÎÁ.
-
-ëÒÏÍÅ ÔÏÇÏ, ÒÅÁÌÉÚÏ×ÁÎÏ ÎÅÓËÏÌØËÏ ×ÐÏÍÏÇÁÔÅÌØÎÙÈ ËÌÁÓÓÏ×, ËÏÔÏÒÙÅ
-ÉÓÐÏÌØÚÕÀÔÓÑ × ÒÅÁÌÉÚÁÃÉÑÈ ÆÕÎËÃÉÊ ÓÉÓÔÅÍÙ.
-
-
-* íÅÔÒÉËÉ ÒÅÁÌÉÚÏ×ÁÎÎÏÊ ÐÒÏÇÒÁÍÍÎÏÊ ÓÉÓÔÅÍÙ.
-
-ëÏÌÉÞÅÓÔ×Ï ÆÁÊÌÏ× ÉÓÈÏÄÎÏÇÏ ËÏÄÁ: 8,
-ëÏÌÉÞÅÓÔ×Ï Java-ËÌÁÓÓÏ× (×ËÌÀÞÁÑ ÁÎÏÎÉÍÎÙÅ): 27,
-ïÂÝÅÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ÉÓÈÏÄÎÏÇÏ ÔÅËÓÔÁ: 1311,
-ëÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ËÏÄÁ (ÉÓËÌÀÞÁÑ ÐÕÓÔÙÅ ÓÔÒÏËÉ É ËÏÍÍÅÎÔÁÒÉÉ): 812,
-ëÏÌÉÞÅÓÔ×Ï ÓÔÒÏË ËÏÍÍÅÎÔÁÒÉÅ×: 180.
-
-
-* úÁËÌÀÞÅÎÉÅ
-
-á×ÔÏÒÏÍ ÂÙÌÁ ÒÁÚÒÁÂÏÔÁÎÁ ÐÒÏÇÒÁÍÍÎÁÑ ÓÉÓÔÅÍÁ DbReader, ËÏÔÏÒÁÑ
-Ñ×ÌÑÅÔÓÑ ÒÁÓÛÉÒÑÅÍÙÍ É ÕÎÉ×ÅÒÓÁÌØÎÙÍ ÓÒÅÄÓÔ×ÏÍ ÄÌÑ ÐÒÅÄÓÔÁ×ÌÅÎÉÑ
-ÉÎÆÏÒÍÁÃÉÉ ÉÚ ÂÁÚ ÄÁÎÎÙÈ × ÔÅËÓÔÏ×ÙÈ ÆÏÒÍÁÔÁÈ. ó ÐÏÍÏÝØÀ ÓÉÓÔÅÍÙ
-DbReader ÂÁÚÁ ÄÁÎÎÙÈ "íÅÓÔÏÏÂÉÔÁÎÉÑ ÷ÏÓÔÏÞÎÏÊ æÅÎÎÏÓËÁÎÄÉÉ" ÂÙÌÁ
-ÐÅÒÅ×ÅÄÅÎÁ × XML-ÆÏÒÍÁÔ ÜÌÅËÔÒÏÎÎÏÊ ÂÉÂÌÉÏÔÅËÉ ëÁÒîã òáî.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manual/index.html	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,358 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+          "DTD/xhtml1-transitional.dtd">
+
+<html>
+
+<head>
+  <title>Макропроцессор TEMA</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+
+<body>
+<h1>Макропроцессор TEMA</h1>
+
+Макропроцессор TEMA обрабатывает заданные шаблоны текстовых файлов и
+заменяет найденные в них инструкции на результаты их выполнения.
+
+<p><b>Формат инструкций</b></p>
+
+<blockquote>
+  <code>&lt;%<i>список_функций</i>{:|\|`}<i>данные</i>%&gt;</code>  
+</blockquote>
+<p>
+где<br />
+
+<code><i>список_функций</i></code> - список имен функций, разделенных
+    пробелами. Может быть пустым.<br />
+<code><i>данные</i></code> - данные, передаваемые функции.
+</p>
+
+<p><b>Формат данных</b></p>
+
+<blockquote>
+  <code>
+    [<i>список_аргументов</i>][<i>текст</i>]
+  </code>
+</blockquote>
+<p>
+где<br />
+
+<code><i>список_аргументов</i></code> - список аргументов функции, разделенных пробелами.
+    Может быть пустым.<br />
+<code><i>текст</i></code> - текст, передаваемый функции без разбиения на аргументы.
+    Может быть пустым. Количество аргументов, после которого следует
+    текст, зависит от функции.
+</p><p>
+Разделитель между списком функций и данными определяет, как должны
+обрабатываться данные функции:
+</p><p>
+<code>:</code> - рекурсивная обработка,<br />
+<code>\</code> или <code>`</code> - передать без обработки.
+</p><p>
+Если в списке функций задано две и более функции, они выполняются,
+начиная с последней, так что каждая функция получает в качестве данных
+результат выполнения следующей функции.
+</p><p>
+Каждая функция имеет код возврата - целое число. Код возврата
+инструкции - код возврата первой в списке функции. Код возврата,
+получаемый при обработке текста - сумма кодов возврата обработанных
+инструкций (как правило, смысл этого значения - количество инструкций,
+замененных на непустой текст).
+</p><p>
+Кроме скобок '&lt;', '&gt;', можно использовать скобки '[', ']'.
+</p>
+
+
+<h2>Функции</h2>
+
+<p><code><b>set</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Текст:</td>
+<td><i>значение</i></td></tr>
+
+<tr><td>Действие:</td>
+<td>Устанавливает значение переменной <i>имя</i>.</td></tr>
+
+<tr><td>Результат:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Код возврата:</td>
+<td>1</td></tr>
+</table>
+
+<p><code><b>define</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Текст:</td>
+<td><i>шаблон</i></td></tr>
+
+<tr><td>Действие:</td><td>Определяет новую функцию <i>имя</i>, при
+вызове которой обрабатывается <i>шаблон</i>. При обработке доступны
+функции <code>nextarg</code> для получения очередного аргумента
+вызываемой функции и <code>data</code> для получения текста.</td></tr>
+
+<tr><td>Результат:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Код возврата:</td>
+<td>1</td></tr>
+</table>
+
+<p><code><b>load</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td>
+<td><i>имя</i> <i>имя_класса</i></td></tr>
+
+<tr><td>Действие:</td>
+
+<td>Определяет новую функцию <i>имя</i>. Реализация функции определена
+Java-классом <i>имя_класса</i>, наследующим класс
+<code>kryshen.tema.Function</code>.</td></tr>
+
+<tr><td>Результат:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Код возврата:</td>
+<td>1</td></tr>
+</table>
+
+<p><code><b>prepare</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Текст:</td>
+<td><i>запрос</i></td></tr>
+
+<tr><td>Действие:</td>
+<td>Подготавливает SQL-запрос <i>запрос</i> для выполнения, записывает
+подготовленный запрос в переменную <i>имя</i>.</td></tr>
+
+<tr><td>Результат:</td>
+<td><i>имя</i></td></tr>
+
+<tr><td>Код возврата:</td>
+<td>1</td></tr>
+</table>
+
+<p><code><b>query</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td>
+<td><i>имя_запроса</i> <i>шаблон</i> <i>парам1</i> ... <i>парамN</i></td></tr>
+
+<tr><td>Действие:</td>
+<td>Выполняет запрос с параметрами, подготовленный с помощью функции
+prepare. Значения параметров подставляются в запрос вместо символа
+'?'. Значения полей ответа доступны с помощью функции <code>db</code>,
+как переменные шаблона <i>шаблон</i>. При обработки шаблона также
+определяется переменная <code>number</code>, содержащая номер текущей
+строки ответа.</td></tr>
+
+<tr><td>Результат:</td>
+<td>результат обработки шаблона <i>шаблон</i> для каждой строки
+ответа.</td></tr>
+
+<tr><td>Код возврата:</td>
+<td>Количество полученных строк ответа.</td></tr>
+</table>
+
+<p><code><b>optional</b></code></p>
+
+<table>
+<tr><td>Текст:</td>
+<td><i>данные</i></td></tr>
+
+<tr><td>Результат:</td><td><i>данные</i>, если при обработке данных
+был получен код возврата отличный от 0, иначе - пустая
+строка.</td></tr>
+
+<tr><td>Код возврата:</td>
+<td>1, если результат - пустая строка, 0 - иначе.</td></tr>
+</table>
+
+<p><code><b>image</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td>
+<td><i>исх_файл</i> <i>кон_файл</i> <i>формат</i> [<i>макс_ширина</i>
+[<i>макс_высота</i>]]</td></tr>
+
+<tr><td>Действие:</td>
+<td>Загружает изображение из файла <i>исх_файл</i> (путь определяется
+относительно конфигурационного параметра "resource_base") и
+преобразует его в указанный формат, сохраняя результат в
+<i>кон_файл</i>. Если заданы максимальная высота и ширина, большие
+изображения будут уменьшены.</td></tr>
+
+<tr><td>Результат:</td>
+<td><i>кон_файл</i> при успешном выполнении, пустая строка - иначе.</td></tr>
+
+<tr><td>Код возврата:</td>
+<td>1 при успешном выполнении, 0 - иначе.</td></tr>
+</table>
+
+
+<p><code><b>copy</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td><td><i>исх_файл</i> <i>кон_файл</i></td></tr>
+
+<tr><td>Действие:</td><td>Копирует файл <i>исх_файл</i> в файл
+<i>кон_файл</i> (путь <i>исх_файл</i> определяется относительно
+конфигурационного параметра "resource_base").</td></tr>
+
+<tr><td>Результат:</td><td><i>кон_файл</i> при успешном выполнении,
+пустая строка - иначе.</td></tr>
+
+<tr><td>Код возврата:</td><td>1 при успешном выполнении, 0 -
+иначе.</td></tr>
+</table>
+
+<p><code><b>write</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td><td><i>имя_файла</i></td></tr>
+
+<tr><td>Текст:</td><td><i>данные</i></td></tr>
+
+<tr><td>Действие:</td><td>Записывает <i>данные</i> в файл
+<i>исх_файл</i>.</td></tr>
+
+<tr><td>Результат:</td><td><i>кон_файл</i> при успешном выполнении,
+пустая строка - иначе.</td></tr>
+
+<tr><td>Код возврата:</td><td>1 при успешном выполнении, 0 -
+иначе.</td></tr>
+</table>
+
+<p><code><b>read</b></code></p>
+
+<table>
+<tr><td>Текст:</td><td><i>имя_файла</i></td></tr>
+<tr><td>Действие:</td><td>Читает файл <i>имя_файла</i>.</td></tr>
+<tr><td>Результат:</td><td>прочитанные данные при успешном выполнении,
+  пустая строка - иначе.</td></tr>
+<tr><td>Код возврата:</td><td>1 при успешном выполнении, 0 -
+иначе.</td></tr>
+</table>
+
+<p><code><b>include</b></code></p>
+
+<table>
+<tr><td>Текст:</td><td><i>имя_файла</i></td></tr>
+<tr><td>Действие:</td><td>включает шаблон из файла
+<i>имя_файла</i>.</td></tr>
+<tr><td>Результат:</td><td>результат обработки шаблона.</td></tr>
+<tr><td>Код возврата:</td><td>код возврата, полученный при обработке
+шаблона.</td></tr>
+</table>
+
+<p><code><b>!</b></code></p>
+
+<table>
+<tr><td>Текст:</td><td><i>данные</i></td></tr>
+
+<tr><td>Действие:</td><td>нет.</td></tr>
+
+<tr><td>Результат:</td><td>нет.</td></tr>
+
+<tr><td>Код возврата:</td><td>код возврата, полученный при обработке
+текста данных.</td></tr>
+</table>
+
+<p><code><b>replace</b></code></p>
+
+<table>
+<tr><td>Аргументы:</td><td><i>стр1</i> <i>стр2</i></td></tr>
+
+<tr><td>Текст:</td><td><i>данные</i></td></tr>
+
+<tr><td>Результат:</td><td>данные, с замененными вхождениями подстроки
+<i>стр1</i> на <i>стр2</i>.</td></tr>
+
+<tr><td>Код возврата:</td><td> код возврата, полученный при обработке
+текста данных.</td></tr>
+</table>
+
+<p><code><b>xml_escape</b></code></p>
+
+<table>
+<tr><td>Текст:</td><td><i>данные</i></td></tr>
+<tr><td>Результат:</td><td>текст <i>данные</i>, в котором символы
+'&amp;', '&lt;', '&gt;', '`', '\' заменены на соответствующие сущности
+XML.</td></tr>
+
+<tr><td>Код возврата:</td><td> код возврата, полученный при обработке
+текста данных.</td></tr>
+</table>
+
+<p><code><b>xml_cdata</b></code></p>
+
+<table>
+<tr><td>Текст:</td><td><i>данные</i></td></tr>
+
+<tr><td>Результат:</td><td>данные в виде блока XML CDATA.</td></tr>
+
+<tr><td>Код возврата:</td><td> код возврата, полученный при обработке
+текста данных.  </td></tr>
+</table>
+
+<p>
+Макропроцессор TEMA расширяем: возможно добавление в систему новых
+функций, реализованных в виде классов на языке Java.
+</p>
+
+<h2>Запуск</h2>
+
+<p>java -jar tema.jar [<i>опции</i>]
+</p><p>
+Опции:
+</p>
+<table>
+<tr><td>-d[emo]</td><td>Демонстрационный режим</td></tr>
+<tr><td>-v[ersion]</td><td>Вывод версии</td></tr>
+<tr><td>-h[help] -u[sage]</td><td>Вывод справки</td></tr>
+</table>
+
+<p>
+При запуске читается файл "tema.properties" из текущего каталога.<br />
+Пример файла "tema.properties":
+</p>
+
+<pre>
+# Настройка источника данных
+# resource          : jdbc:odbc:database
+# driver            : sun.jdbc.odbc.JdbcOdbcDriver
+
+# Базовый каталог ресурсов
+# resource_base     : .
+
+# Шаблон, с которого начинается обработка
+main_template     : main.template
+
+# Кодировки файлов
+# input_encoding    : UTF-8
+# output_encoding   : UTF-8
+
+# Кэширование шаблонов
+# cache_read        : true
+
+# Вывод результата разбора шаблона main.template в stderr
+# output            : stderr
+
+# Вывод сообщений об ошибках в файл
+# log               : dbreader.log
+</pre>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/kryshen/tema/demo/demo.template	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,25 @@
+[%!\ TEMA demo template %]
+
+Вывод текста:
+test text
+
+Вывод специальных символов:
+[%\<%test%>%]
+
+Объявление функции:
+<%define\test test arg1:[%nextarg:%], test arg2:[%nextarg:%], test data:[%data:%].%>   
+
+Вызов новой функции:
+<%test:1 2 3%>
+
+Загрузка функции из класса:
+<%load\hello kryshen.tema.demo.Hello%>
+
+Выполенение загруженной функции:
+<%hello\TEMA%>
+
+Условное выполнение:
+<%optional:<%true:%>True%> <%optional:<%false:%>False%>
+
+Тестирование xml_escape:
+<%xml_escape\x < a & b%>
--- a/sample/class.xml	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-5"?>
-<ÚÛÐááØäØÚÐæØï>
-  <ÚÛÐáá id="1">°ÝâàÞßÞÓÕÝÝëÕ ÜÕáâÞÞÑØâÐÝØï</ÚÛÐáá>
-  <ÚÛÐáá id="2">¼Þàï Ø ÜÞàáÚØÕ ßÞÑÕàÕÖìï</ÚÛÐáá>
-  <ÚÛÐáá id="3">¾×ÕàÐ Ø ßàØÑàÕÖÝëÕ ÜÕáâÞÞÑØâÐÝØï</ÚÛÐáá>
-  <ÚÛÐáá id="4">ÀÕÚØ, àãçìØ Ø ßàØÑàÕÖÝëÕ ÜÕáâÞÞÑØâÐÝØï</ÚÛÐáá>
-  <ÚÛÐáá id="5">±ÞÛÞâÐ Ø ×ÐÑÞÛÞçÕÝÝëÕ ×ÕÜÛØ</ÚÛÐáá>
-  <ÚÛÐáá id="6">ÁãåÞÔÞÛìÝëÕ ÜÕáâÞÞÑØâÐÝØï</ÚÛÐáá>
-</ÚÛÐááØäØÚÐæØï>
--- a/sample/plants.xml	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-5"?>
-<àÐáâÕÝØï>
-  <àÐáâÕÝØÕ>Betula sp.</àÐáâÕÝØÕ>
-  <àÐáâÕÝØÕ>Calamagrostis arundinacea</àÐáâÕÝØÕ>
-  <àÐáâÕÝØÕ>Geranium sylvaticum</àÐáâÕÝØÕ>
-</àÐáâÕÝØï>
--- a/src/kryshen/tema/Function.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/Function.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: Function.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Function.java,v 1.5 2006/12/14 14:39:22 mikhail Exp $
  */
 
 package kryshen.tema;
@@ -10,13 +24,19 @@
 import java.util.*;
 import java.sql.ResultSet;
 
+/**
+ * Abstact class for TEMA functions.
+ *
+ * @author Mikhail A. Kryshen
+ */
 public abstract class Function {
-    public final String name;
 
-    protected Function(String name) {
-	this.name = name;
-    }
-
+    /**
+     * Invoke the function.
+     *
+     * @param fdp FunctionDataParser to access function arguments.
+     * @param out Writer for the function output.
+     */
     public abstract int invoke(FunctionDataParser fdp, Writer out)
         throws IOException, TemplateException;
 }
--- a/src/kryshen/tema/FunctionDataParser.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/FunctionDataParser.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: FunctionDataParser.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: FunctionDataParser.java,v 1.5 2006/12/14 14:39:22 mikhail Exp $
  */
 
 package kryshen.tema;
@@ -23,13 +37,13 @@
 
     private TemplateParser tp;
     private FunctionData fd;
-    private Reader in;
+    private TemplateReader in;
 
     private boolean available = true;
     private boolean first = true;
 
     FunctionDataParser(TemplateParser tp, FunctionData fd,
-                       Reader in) {
+                       TemplateReader in) {
         this.tp = tp;
         this.fd = fd;
         this.in = in;
@@ -40,7 +54,7 @@
         
         if (!available)
             throw new TemplateException
-		("Unexpected end of instruction data.");
+		("Unexpected end of instruction data.", in);
 
         TemplateParser.Result r;
 
@@ -53,11 +67,11 @@
                          argument ? ARG_SEPARATORS : null,
                          (argument || !first) ? ARG_SEPARATORS : null);
         } else if (fd == FunctionData.SUBFUNCTION && argument) {
-            /* Subfunction can pass a list of arguments */
+            // Subfunction can pass a list of arguments
             StringWriter sw = new StringWriter();
             tp.parseFunction(in, sw);
             sw.close();
-            in = new StringReader(sw.toString());
+            in = new TemplateReader(new StringReader(sw.toString()), in);
             fd = FunctionData.NONRECURSIVE;
             r = parseData(out, true);
         } else if (fd == FunctionData.SUBFUNCTION) {
@@ -74,7 +88,7 @@
     }
 
     public int parseData(Writer out) throws IOException, TemplateException {
-        return parseData(out, false).substitutions; 
+        return parseData(out, false).retCode; 
     }
 
     public String getData() throws IOException, TemplateException {        
@@ -92,7 +106,7 @@
             r = parseData(out, true);
         }
 
-        return r.substitutions;
+        return r.retCode;
     }
 
     public String getNextArg() throws IOException, TemplateException {        
@@ -119,4 +133,8 @@
     public TemplateParser getTemplateParser() {
         return tp;
     }
+    
+    public TemplateReader getTemplateReader() {
+        return in;
+    }
 }
--- a/src/kryshen/tema/Functions.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/Functions.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: Functions.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Functions.java,v 1.11 2006/12/14 19:44:31 mikhail Exp $
  */
 
 package kryshen.tema;
@@ -9,328 +23,48 @@
 import java.io.*;
 import java.util.*;
 
-import java.sql.SQLException;
-import java.sql.PreparedStatement;
-
 import kryshen.tema.functions.*;
 
+/**
+ * Standard TEMA functions.
+ *
+ * @author Mikhail A. Kryshen
+ */
 public class Functions {
-    public static final Function GET =
-        new Function("get") {
-            public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-		String name = fdp.getData();
-                return fdp.getTemplateParser().parseVariable(name, out);
-            }
-        };
-
-    public static final Function SET =
-        new Function("set") {
-            public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-                String arg0 = fdp.getNextArg();
-                String arg1 = fdp.getData();
-                
-                fdp.getTemplateParser().setValue(arg0, arg1);
-                
-		out.write(arg0);
-                return 1;
-            }
-        };
-
-    /* prepare:qury_name sql_statement */
-    public static final Function PREPARE =
-        new Function("prepare") {
-            public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-                String arg0 = fdp.getNextArg();
-                String data = fdp.getData();
-
-		PreparedStatement statement;
-
-		try {
-		    statement = Tema.connection.prepareStatement(data);
-		} catch (SQLException e) {
-		    throw new TemplateException(e.getMessage(), e);
-		}
-                
-                fdp.getTemplateParser().setValue(arg0, statement);   
-             
-		out.write(arg0);
-                return 1;
-            }
-        };
-
-    public static final Function OPTIONAL =
-        new Function("optional") {
-            public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-                StringWriter sw = new StringWriter();
-                int s = fdp.parseData(sw);
-                sw.close();
-                String data = sw.toString();
-
-                if (s > 0) {
-                    out.write(data);
-                    return 1;
-                } else {
-                    return 0;
-                }
-            }
-        };
-
-    public static final Function IMAGE =
-        new Function("image") {
-            public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-                String arg0 = fdp.getNextArg();
-                String arg1 = fdp.getNextArg();
-                String arg2 = fdp.getNextArg();
-                int arg3 = fdp.hasMoreData() ? 
-		    Integer.parseInt(fdp.getNextArg()) : -1;
-                int arg4 = fdp.hasMoreData() ? 
-		    Integer.parseInt(fdp.getNextArg()) : -1;
-
-                File source = new File
-                    (Tema.getProperty("resource_base"), arg0);
-
-                try {
-                    ImageConverter.convert
-                        (source,                  /* source file */
-                         new File(arg1),          /* dest file */
-                         arg2,                    /* format */
-                         arg3,                    /* max width */
-                         arg4);                   /* max height */
-                } catch (Exception e) {
-                    System.err.println(e);
-                    return 0;
-                }
-
-                out.write(arg1);
-                return 1;
-            }
-        };
-
-    public static final Function COPY =
-        new Function("copy") {
-           public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-                String arg0 = fdp.getNextArg();
-                String arg1 = fdp.getNextArg();
-
-                File source = new File
-                    (Tema.getProperty("resource_base"), arg0);
-                File dest = new File(arg1);
-                
-                try {
-                    copyFile(source, dest);
-                } catch (IOException e) {
-                    System.err.println(e);
-                    return 0;
-                }
-                out.write(arg1);
-                return 1;
-            }
-        };
-
-    /* query:sql_query template arg1 arg2 ... argN */
-    public static final Function QUERY =
-        new Function("query") {
-           public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-                
-                String arg0 = fdp.getNextArg();
-                String arg1 = fdp.getNextArg();
-		List<String> args = fdp.getArgs();				
-
-		TemplateParser tp = fdp.getTemplateParser();
-
-		try {
-		    return Tema.query
-			(arg1, (PreparedStatement)tp.getValue(arg0),
-			 args, tp, out);
-		} catch (SQLException e) {
-		    throw new TemplateException(e.getMessage(), e);
-		}
-            }
-        };
-
-    public static final Function WRITE =
-        new Function("write") {
-           public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-
-                String arg0 = fdp.getNextArg();
-
-		System.err.println("Writing " + arg0 + "...");
-
-                Writer fw;
+    // TODO: arithmetics, conditions
 
-                try {
-		    fw = Tema.createFileWriter(arg0);
-                } catch (IOException e) {
-                    System.err.println(e);
-                    return 0;
-                }
-                
-                try {
-		    fdp.parseData(fw);
-                } finally {
-                    fw.close();
-                }
-
-                out.write(arg0);
-		
-		System.err.println("Saved " + arg0 + ".");
-                return 1;
-            }
-        };
-
-    public static final Function READ =
-        new Function("read") {
-           public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
+    /**
+     * Register all standard functions.
+     *
+     * @param p TemplateParser to register functions in.
+     */
+    static void registerAllFunctions(TemplateParser p) {
+        p.registerFunction("!",          Standard.NULL_OUTPUT);
+        p.registerFunction("set",        Standard.SET);
+        p.registerFunction("load",       Standard.LOAD);
+        p.registerFunction("query",      Standard.QUERY);
+        p.registerFunction("prepare",    Standard.PREPARE);
+        p.registerFunction("replace",    Standard.REPLACE);
+        p.registerFunction("xml_escape", Standard.XML_ESCAPE);
+        p.registerFunction("xml_cdata",  Standard.XML_CDATA);
 
-	       String filename = fdp.getData();
-	       String file;
-	       
-                try {
-                    file = Tema.readFile(new File(filename));
-                } catch (IOException e) {
-                    System.err.println(e);
-                    return 0;
-                }
-		
-                out.write(file);
-                return 1;
-            }
-        };
-
-    public static final Function INCLUDE =
-        new Function("include") {
-           public int invoke(FunctionDataParser fdp, Writer out)
-                throws IOException, TemplateException {
-                
-                String filename = fdp.getData();
-                
-                Reader fin = new BufferedReader
-		    (Tema.createCachedFileReader(new File(filename)));
-                
-                int r = fdp.getTemplateParser().parse(fin, out);
-
-                fin.close();
-                return r;
-            }
-        };
-
-    public static final Function NULL_OUTPUT =
-        new Function("!") {
-	    public int invoke(FunctionDataParser fdp, Writer out)
-		throws IOException, TemplateException {		
-
-		/* Write nothing. */
-		return fdp.parseData(new Writer() {
-                    public void close() {}
-                    public void flush() {}
-                    public void write(char[] cbuf, int off, int len) {}
-                });
-            }
-        };
-
-    public static final Function REPLACE =
-        new Function("replace") {
-	    public int invoke(FunctionDataParser fdp, Writer out)
-		throws IOException, TemplateException {		
-
-                String arg0 = fdp.getNextArg();
-                String arg1 = fdp.getNextArg();
+        p.registerFunction("define",     Define.DEFINE);
 
-                ReplaceWriter rw = new ReplaceWriter(out, arg0, arg1);
-
-                int ret = fdp.parseData(rw);
-                rw.finish();
-                return ret;
-            }
-        };
-
-    public static final Function XML_ESCAPE =
-        new Function("xml_escape") {
-	    public int invoke(FunctionDataParser fdp, Writer out)
-		throws IOException, TemplateException {		
-
-                final String[] chars = {"&", "<", ">", "`", "\""};
-                final String[] escape = {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"};
-
-                ReplaceWriter rw = new ReplaceWriter(out, chars, escape);
-
-                int ret = fdp.parseData(rw);
-                rw.finish();
-                return ret;
-            }
-        };
-
-    public static final Function XML_CDATA =
-        new Function("xml_cdata") {
-	    public int invoke(FunctionDataParser fdp, Writer out)
-		throws IOException, TemplateException {		
-
-                ReplaceWriter rw = new ReplaceWriter
-                    (out, "]]>", "]]]><![CDATA[]>", "<![CDATA[", "]]>");
-
-                int ret = fdp.parseData(rw);
-                rw.finish();
-                return ret;
-            }
-        };
-    
-    public static final Function DEFINE = new Define();
+        p.registerFunction("write",      IO.WRITE);
+        p.registerFunction("read",       IO.READ);
+        p.registerFunction("include",    IO.INCLUDE);
+        p.registerFunction("copy",       IO.COPY);
 
-    private static void copyFile(File src, File dest) throws IOException {
-	System.err.print("Copying " + src + "... ");
-	
-	if (src.lastModified() < dest.lastModified()) {
-	    System.err.println(dest + " is up to date.");
-	    return;
-	}
+	p.registerFunction("false",      Logics.FALSE);
+	p.registerFunction("true",       Logics.TRUE);
+        p.registerFunction("optional",   Logics.OPTIONAL);
 
-	File parent = dest.getParentFile();
-	if (parent != null) parent.mkdirs();
+        p.registerFunction("image",      ImageConverter.IMAGE);
 
-        InputStream in = new FileInputStream(src);
-        OutputStream out = new FileOutputStream(dest);
-        
-        byte[] buffer = new byte[1024];
-        int len;
-        while ((len = in.read(buffer)) > 0) {
-            out.write(buffer, 0, len);
-        }
-        in.close();
-        out.close();
-
-	System.err.println("saved " + dest + ".");
-    }
-
-    static void registerAllFunctions(TemplateParser p) {
-        p.registerFunction(GET);
-        p.registerFunction(SET);
-        p.registerFunction(OPTIONAL);
-        p.registerFunction(IMAGE);
-        p.registerFunction(COPY);
-        p.registerFunction(QUERY);
-        p.registerFunction(PREPARE);
-        p.registerFunction(WRITE);
-        p.registerFunction(READ);
-        p.registerFunction(INCLUDE);
-        p.registerFunction(NULL_OUTPUT);
-        p.registerFunction(REPLACE);
-        p.registerFunction(XML_ESCAPE);
-        p.registerFunction(XML_CDATA);
-        p.registerFunction(DEFINE);
+	/* 
+	   Other functuons:
+	   db - defined in Tema.query().
+	   nextarg, data - defined in Define.invoke().
+	*/
     }
 }
--- a/src/kryshen/tema/ImageConverter.java	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Mikhail A. Kryshen
- *
- * $Id: ImageConverter.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
- */
-
-package kryshen.tema;
-
-import java.util.*;
-import java.io.*;
-import java.awt.*;
-import java.awt.image.*;
-import java.awt.geom.AffineTransform;
-import javax.imageio.*;
-import javax.imageio.stream.*;
-
-/**
- * Class defines static method to convert images to specified format.
- *
- * @author Mikhail A. Kryshen
- */
-class ImageConverter {    
-
-    static void convert(File source, File dest, String format,
-		 int maxWidth, int maxHeight) 
-	throws IOException, InterruptedException {
-	
-	System.err.print("Converting image " + source + "... ");
-
-	if (source.lastModified() < dest.lastModified()) {
-	    System.err.println(dest + " is up to date.");
-	    return;
-	}
-
-	BufferedImage image = ImageIO.read(source);
-
-	//int type = image.getType();
-	//final int type = BufferedImage.TYPE_INT_RGB;
-	//ColorModel cm = image.getColorModel();
-
-        int w = image.getWidth(null);
-        int h = image.getHeight(null);
-
-	//boolean scale = false;
-
-	float scale = 1f;
-
-	if (maxWidth > 0 && w > maxWidth)
-	    scale = (float)maxWidth / w;
-	
-	if (maxHeight > 0 && h * scale > maxHeight)
-	    scale = (float)maxHeight / h;
-
-	if (scale != 1f) {
-	    w *= scale; h *= scale;
-
-// 	    ColorModel cm = image.getColorModel();	    
-// 	    boolean alphaPremultiplied = cm.isAlphaPremultiplied();
-// 	    WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
-// 	    BufferedImage scaled = new BufferedImage
-// 		(cm, raster, alphaPremultiplied, null);
-
-// 	    BufferedImage scaled = new BufferedImage(w, h, image.getType());
-	    
-
- 	    Image scaled = image.getScaledInstance(w, h, Image.SCALE_SMOOTH);
-
- 	    ColorModel cm = image.getColorModel();	    
- 	    boolean alphaPremultiplied = image.isAlphaPremultiplied();
- 	    WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
- 	    image = new BufferedImage(cm, raster, alphaPremultiplied, null);
-
-	    Graphics g = image.getGraphics();
-	    g.drawImage(scaled, 0, 0, null);
-	    g.dispose();
-
-//	    image = scale(image, scaled, scale);
-//	    Graphics2D g = scaled.createGraphics();
-//	    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-// 			       RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-// 	    System.err.print(" " + g.drawImage(image, 0, 0, w, h, null) + " ");
-// 	    g.dispose();
-// 	    image = scaled;
-	}
-       
-	File parent = dest.getParentFile();
-	if (parent != null) parent.mkdirs();
-
- 	ImageIO.write(image, format, dest);
-	System.err.println("saved " + dest + ".");	
-    }
-
-//     public static ColorModel getColorModel(Image image) 
-// 	throws InterruptedException {
-
-// 	PixelGrabber grabby = new PixelGrabber(image, 0, 0, 1, 1, false);
-// 	if (!grabby.grabPixels())
-// 	    throw new RuntimeException("pixel grab fails");
-// 	return grabby.getColorModel();
-//     }
-
-//     private static BufferedImage scale(BufferedImage image, 
-// 				       BufferedImage dest, 
-// 				       float scale) {
-
-// 	AffineTransform tx = new AffineTransform();
-// 	tx.scale(scale, scale);
-
-//  	AffineTransformOp op = new AffineTransformOp
-//  	    (tx, AffineTransformOp.TYPE_BILINEAR);
-
-// 	return op.filter(image, dest);
-//     }
-
-    // TEST
-    
-    public static void main(String[] args) 
-	throws IOException, InterruptedException {
-
-	convert(new File(args[0]), new File(args[1]), "png", 300, 300);
-    }
-
-
-//     public static BufferedImage toBufferedImage(Image image, ColorModel cm) {
-// 	if (image instanceof BufferedImage)
-// 	    return (BufferedImage)image;
-
-// 	int w = image.getWidth(null);
-// 	int h = image.getHeight(null);
-
-// 	boolean alphaPremultiplied = cm.isAlphaPremultiplied();
-// 	WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
-// 	BufferedImage result = new BufferedImage(cm, raster, alphaPremultiplied, null);
-// 	Graphics2D g = result.createGraphics();
-
-// 	g.drawImage(image, 0, 0, null);
-// 	g.dispose();
-
-// 	return result;
-//     }
-}
-
-
-// This is how I'd recommend it in JDK1.4 using javax.imageio.ImageIO to
-// do the reading/writing and Java2D to do the scaling.
-
-// // read in the original image
-// BufferedImage in = ImageIO.read(new File("in.jpg"));
-
-// // create a new image of the smaller size
-// BufferedImage out = new BufferedImage(newWidth, newHeight);
-
-// // get the graphics associated with the new image
-// Graphics g = out.getGraphics();
-
-// // draw the original image into the new image, scaling
-// // on the fly
-// g.drawImage(in, newWidth, newHeight, null);
-
-// // dispose the graphics object
-// g.dispose();
-
-// // write out the new image
-// ImagIO.write("out.jpg", "jpeg", new File("out.jpg"));
-
-// ------------------------------------------
-
-// For nicer scaling, you could add a rendering hint to the graphics
-// object before painting.
-
-// ie.
-
-// Graphics2D g2d = (Graphics2D)g;
-// g2d.setRenderingHint(RenderingHints.KEY_INTEPOLATION,
-//                      RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-
-// or use VALUE_INTERPOLATION_BICUBIC for the best.
-
-// But as you can guess, nicer == slower.
-
-// Shannon Hickey
-// shann...@swingteam.com
-// Swing Team  http://TheSwingConnection.com  http://TheJavaTutorial.com
-// Java Software,  a division of Sun Microsystems, Inc. 
--- a/src/kryshen/tema/ReplaceWriter.java	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2006 Mikhail A. Kryshen
- *
- * $Id: ReplaceWriter.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
- */
-
-package kryshen.tema;
-
-import java.io.Writer;
-import java.io.FilterWriter;
-import java.io.IOException;
-
-import java.util.LinkedList;
-import java.util.Iterator;
-
-/**
- * FilterWriter which replaces characters with escape strings.
- *
- * @author Mikhail A. Kryshen
- */
-class ReplaceWriter extends FilterWriter {
-    private String[] patterns;
-    private String[] replaces;
-
-    private String prefix;
-    private String postfix;
-
-    private int maxPatternLength = 0;
-
-    /** Had this Writer processed any data? */
-    private boolean processedData = false;
-
-    private StringBuffer buffer = new StringBuffer();
-
-    public ReplaceWriter(Writer w, String pattern, String replace) {
-        this(w, new String[]{pattern}, new String[]{replace});
-    }
-
-    public ReplaceWriter(Writer w, String pattern, String replace,
-                         String prefix, String postfix) {
-
-        this(w, new String[]{pattern}, new String[]{replace}, 
-             prefix, postfix);
-    }
-
-    public ReplaceWriter(Writer w, String[] patterns, String[] replaces) {
-        this(w, patterns, replaces, null, null);
-    }
-
-    public ReplaceWriter(Writer w, String[] patterns, String[] replaces, 
-                         String prefix, String postfix) {
-	super(w);
-        
-	this.patterns = patterns;
-	this.replaces = replaces;
-        
-        this.prefix = prefix;
-        this.postfix = postfix;
-        
-	for (int i = 0; i < patterns.length; i++) {
-	    int length = patterns[i].length();
-	    if (length > maxPatternLength)
-		maxPatternLength = length;
-	}
-    }
-
-    private boolean processBuffer(int minLength) throws IOException {
-        if (buffer.length() == 0) return false;
-
-        if (!processedData) {
-            if (prefix != null)
-                super.write(prefix, 0, prefix.length());
-            processedData = true;
-        }
-
-        int k;
-	for (k = 0; minLength + k < buffer.length(); k++) {
-	    for (int i = 0; i < patterns.length; i++) {
-		String pattern = patterns[i];
-		int length = pattern.length();
-
-                if (length + k > buffer.length())
-                    continue;
-
-		boolean match = true;
-
-		for (int j = 0; j < length; j++) {
-		    if (pattern.charAt(j) != buffer.charAt(j + k)) {
-			match = false;
-                        break;
-		    }
-		}
-
-		if (match) {
-                    super.write(buffer.substring(0, k), 0, k);
-                    buffer.delete(0, k + length);
-                    super.write(replaces[i], 0, replaces[i].length());
-		    return true;
-		}
-	    }
-	}
-
-        super.write(buffer.substring(0, k), 0, k);
-        buffer.delete(0, k);
-
-        return false;
-    }
-
-    public void write(int c) throws IOException {
-	buffer.append((char)c);
-	processBuffer(maxPatternLength);
-    }
-
-    public void write(char[] cbuf, int off, int len) throws IOException {
-	for (int i = off; i < off + len; i++) {
-	    buffer.append(cbuf[i]);
-	}
-	processBuffer(maxPatternLength);
-    }
-
-    public void write(String str, int off, int len) throws IOException {
-        buffer.append(str.substring(off, off + len));
-	processBuffer(maxPatternLength);
-    }
-
-    public void finish() throws IOException {
-        while (processBuffer(0));
-
-//         super.write(buffer.toString(), 0, buffer.length());
-//         buffer.delete(0, buffer.length());
-
-        if (processedData && postfix != null)
-            super.write(postfix, 0, postfix.length());
-    }
-
-    public void close() throws IOException {
-        finish();
-        super.close();
-    }
-}
--- a/src/kryshen/tema/Tema.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/Tema.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: Tema.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Tema.java,v 1.17 2006/12/14 19:44:31 mikhail Exp $
  */
 
 package kryshen.tema;
@@ -23,31 +37,135 @@
 
 import java.io.*;
 
+import kryshen.tema.demo.DemoFrame;
+
 /**
  * Tema main class.
  *
  * @author Mikhail A. Kryshen
  */
 public class Tema {
+    public static final String TITLE = "TEMA";
+    public static final String VERSION = "0.1";
+    public static final String AUTHOR = "Mikhail A. Kryshen";
+
     private static final String CONFIG_FILE = "tema.properties";
     private static final String ENV_PREFIX = "kryshen.tema.";
 
     private static Properties config = new Properties();
-    static Connection connection = null;
+    private static Connection connection = null;
 
     private static String inputEncoding;
     private static String outputEncoding;
 
-    static Map<File, String> fileCache = null;
+    private static Map<File, String> fileCache = null;
 
     public static void main(String[] args) 
-	throws IOException, TemplateException, SQLException,
+	throws IOException, SQLException,
 	       ClassNotFoundException, InstantiationException, 
 	       IllegalAccessException {
 	
+        boolean demo = false;
+        boolean version = false;
+        boolean help = false;
+
+        // Parse arguments.
+        for (int i = 0; i < args.length; i++) {
+            if ("-demo".equals(args[i]) || 
+                "-d".equals(args[i])) {
+                demo = true;
+            } else if ("-version".equals(args[i]) ||
+                       "-v".equals(args[i])) {
+                version = true;
+            } else if ("-help".equals(args[i]) ||
+                       "-h".equals(args[i]) ||
+                       "-usage".equals(args[i]) ||
+                       "-u".equals(args[i])) {
+                help = true;
+            } else {
+                System.err.println("Invalid option: " + args[i]);
+                return;
+            }
+        }
+
+        if (version || help) {
+            System.err.println(TITLE + " " + VERSION + " by " + AUTHOR);        
+
+            if (help) {
+                PrintStream err = System.err;
+                
+                err.println();
+                err.println("Usage: tema [OPTIONS]");
+                err.println();
+                err.println("Options:");
+                err.println("  -d[emo]             Demo mode");
+                err.println("  -v[ersion]          Print version");
+                err.println("  -h[help] -u[sage]   Print this help message");
+            }
+            return;
+        }
+
+        if (demo) {
+            // Run in demo mode.
+            DemoFrame df = new DemoFrame();
+            df.pack();
+            df.setVisible(true);
+            return;
+        }
+
+        process();
+    }
+
+    /**
+     * Standard execution.
+     */
+    private static void process()
+        throws IOException, SQLException,
+               ClassNotFoundException, InstantiationException, 
+               IllegalAccessException {
+
         InputStream configIn = new FileInputStream(CONFIG_FILE);
         config.load(configIn);
         configIn.close();
+        
+        configure();
+	
+	String main = getProperty("main_template");
+	String output = getProperty("output");
+	
+	Writer out;
+
+	if ("stderr".equals(output))
+	    out = new OutputStreamWriter(System.err);
+	else
+	    out = new OutputStreamWriter(System.out);
+
+        TemplateReader in = createTemplateReader(new File(main));
+        TemplateParser p = new TemplateParser();
+        TemplateException te = null;
+
+	try {
+	    p.parse(in, out);
+        } catch (TemplateException e) {
+            te = e;
+	} finally {
+	    in.close();
+	    out.flush();
+	}  
+
+        if (te != null) {
+            System.err.println(te.getMessage());
+            if (te.getCause() != null) {
+                System.err.println("Caused by " + te.getCause());
+            }
+        } else {
+            System.err.println("Done");
+        }
+    }
+
+    private static void configure() 
+        throws IOException, SQLException, IllegalAccessException,
+               ClassNotFoundException, InstantiationException {
 
         String logFile = getProperty("log");
         if (logFile != null && logFile.length() > 0)
@@ -71,51 +189,14 @@
 	    // Open connection.
 	    connection = DriverManager.getConnection(resourceProperty);
 	}
-	
-// 	String maxFilesString = getProperty("max_output_files");
-// 	int maxFiles = -1;
-// 	if (maxFilesString != null)
-// 	    maxFiles = Integer.parseInt(maxFilesString);
-
-	String main = getProperty("main_template");
-	String output = getProperty("output");
-	
-	Writer out;
-
-	if ("stderr".equals(output))
-	    out = new OutputStreamWriter(System.err);
-	else
-	    out = new OutputStreamWriter(System.out);
-
-	InputStream is = new FileInputStream(main);
-        Reader in = new BufferedReader(new InputStreamReader(is, inputEncoding));
-
-        TemplateParser p = new TemplateParser();
-	try {
-	    p.parse(in, out);
-	} finally {
-	    in.close();
-	    out.flush();
-	}  
-
-	System.err.println("Done");
     }
 
-//     private static void readEscapes() {
-// 	for (int i = 1;; i++) {
-// 	    String pattern = getProperty("escape_char_" + i);
-
-// 	    if (pattern == null) break;
-
-// 	    escapes.put(pattern.charAt(0),
-// 			getProperty("escape_string_" + i));
-// 	}
-//     }
+    
 
     /**
      * Get configuration property.
      */
-    static String getProperty(String name) {
+    public static String getProperty(String name) {
         String value = System.getProperty(ENV_PREFIX + name);
         if (value != null) return value;
         return config.getProperty(name);
@@ -124,16 +205,17 @@
     /**
      * Get configuration property.
      */
-    static String getProperty(String name, String fallback) {
+    public static String getProperty(String name, String fallback) {
 	String value = getProperty(name);
 	if (value != null) return value;
 	return fallback;
     }
 
     /**
-     * Process subquery and template.
+     * Process database query.
      *
-     * @param template template to fill with data.
+     * @param templateReader reader for the template 
+     *                       to fill with data.
      * @param ps query statement to execute.
      * @param args list of query parameters.
      * @param superParser invoking object.
@@ -141,14 +223,13 @@
      *
      * @return number of processed rows in query result.
      */
-    static int query(String template, PreparedStatement ps,
-		     List<String> args,
-		     TemplateParser superParser, 
-                     Writer out)
+    public static int query(TemplateReader templateReader,
+                            PreparedStatement ps,
+                            List<String> args,
+                            TemplateParser superParser, 
+                            Writer out)
 	throws IOException, SQLException, TemplateException {
 
-	StringReader templateReader = new StringReader(template);
-
 	int i = 1;
 
 	for (String arg : args) {
@@ -165,21 +246,34 @@
 	    names[j] = rm.getColumnName(j + 1);
 	}
 
-	TemplateParser p = new TemplateParser(superParser);
-	
+	final TemplateParser p = new TemplateParser(superParser);
+	final HashMap<String, Object> fields = new HashMap<String, Object>();
+
+        p.registerFunction("db", new Function() {
+                public int invoke(FunctionDataParser fdp, 
+                                  final Writer out)
+                    throws IOException, TemplateException {
+                    
+                    String name = fdp.getData();
+                    Object value = fields.get(name);
+		    
+                    return p.parseValue(value, out);
+                }
+            });
+
 	for (i = 1; r.next(); i++) {
-	    p.clearValues();
 
 	    for (int j = 0; j < columnCount; j++) {
 		Object value = r.getObject(j + 1);
 		if (r.wasNull()) value = null;
-
-		p.setValue(names[j], value);
+                
+		fields.put(names[j], value);
 	    }
 
-	    p.setValue("NUMBER", i);
+	    p.setValue("number", i);
             p.parse(templateReader, out);
 	    templateReader.reset();
+            fields.clear();
 	}
 
 	r.close();
@@ -187,32 +281,56 @@
 	return i - 1;
     }
 
-    static Writer createFileWriter(String filename) throws IOException {
+    public static BufferedWriter createFileWriter(String filename) 
+        throws IOException {
+
 	OutputStream os = new FileOutputStream(filename);
-	return new OutputStreamWriter(os, Tema.outputEncoding);
+	return new BufferedWriter
+            (new OutputStreamWriter(os, Tema.outputEncoding));
+    }
+
+    public static BufferedReader createFileReader(File file)
+        throws IOException {
+
+	InputStream is = new FileInputStream(file);
+	return new BufferedReader
+            (new InputStreamReader(is, Tema.inputEncoding));
     }
 
-    static Reader createFileReader(File file) throws IOException {
-	InputStream is = new FileInputStream(file);
-	return new InputStreamReader(is, Tema.inputEncoding);
+    public static TemplateReader createTemplateReader(File file)
+        throws IOException {
+
+        return new TemplateReader
+            (new LineNumberReader(createCachedFileReader(file)), file.getPath());
     }
 
-    static Reader createCachedFileReader(File file) throws IOException {
+    /**
+     * Creates StringReader for a cached file if caching is enabled or
+     * a BufferedReader.
+     *
+     * @param file File to read.
+     * @return Reader for a file.
+     */
+    public static Reader createCachedFileReader(File file) 
+        throws IOException {
+        
 	if (fileCache != null) return new StringReader(readFile(file));
 	else return createFileReader(file);
     }
 
     /**
      * Read text file.
+     *
+     * @return file contents.
      */
-    static String readFile(File file) throws IOException {
+    public static String readFile(File file) throws IOException {
 	String data;
-
+        
 	if (fileCache != null) {
 	    data = fileCache.get(file);	    
 	    if (data != null) return data;
 	}
-
+        
         Reader r = new BufferedReader(createFileReader(file));
 
         // FIXME: possible overflow (long -> int).
@@ -234,4 +352,13 @@
 
 	return data;
     }
+
+    /**
+     * Get database connection.
+     *
+     * @return database connection if any was configured.
+     */
+    public static Connection getDbConnection() {
+        return connection;
+    }
 }
--- a/src/kryshen/tema/TemplateException.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/TemplateException.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: TemplateException.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: TemplateException.java,v 1.5 2006/12/14 14:39:22 mikhail Exp $
  */
 
 package kryshen.tema;
@@ -12,13 +26,36 @@
  * @author Mikhail A. Kryshen
  */
 public class TemplateException extends Exception {
-    // TODO: store the number of template line with error.
+    //private String source;
+    //private int line;
+
+//     public TemplateException(String message) {
+// 	super(message);
+//     }
 
-    public TemplateException(String message) {
-	super(message);
+//     public TemplateException(String message, Throwable cause) {
+// 	super(message, cause);
+//     }
+
+    public TemplateException(String message, Throwable cause,
+                             TemplateReader tr) {
+        this(message, cause, tr.getSource(), tr.getLineNumber() + 1);
     }
 
-    public TemplateException(String message, Throwable cause) {
-	super(message, cause);
+    public TemplateException(String message, TemplateReader tr) {
+        this(message, tr.getSource(), tr.getLineNumber() + 1);
+    }
+
+    public TemplateException(String message, Throwable cause,
+                             String source, int line) {
+        super(source + ":" + line + ": " + message, cause);
+        //this.source = source;
+        //this.line = line;
+    }
+    
+    public TemplateException(String message, String source, int line) {
+        super(source + ":" + line + ": " + message);
+        //this.source = source;
+        //this.line = line;
     }
 }
--- a/src/kryshen/tema/TemplateParser.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/TemplateParser.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: TemplateParser.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: TemplateParser.java,v 1.11 2006/12/14 19:44:31 mikhail Exp $
  */
 
 package kryshen.tema;
@@ -10,12 +24,14 @@
 import java.util.*;
 
 /**
- * Parser for DbReader templates.
+ * Parser for TEMA templates.
  *
  * @author Mikhail A. Kryshen
  */
 public class TemplateParser {
-    static final String SUPER = "SUPER.";
+    // TODO: report non-critical errors and warnings.
+
+    static final String SUPER_PREFIX = "super.";
 
     /* Brackets. */
     static final char[] BR_LEFT = {'<', '['};
@@ -28,6 +44,9 @@
     static final char[] NONREC_DATA_SEPARATORS = {'\\', '`'}; 
     static final char[] LIST_SEPARATORS = {' ', '\t', '\r', '\n'};
 
+    /**
+     * Methods of parsing function arguments and data.
+     */
     static enum FunctionData {
 	SUBFUNCTION, RECURSIVE, NONRECURSIVE;
     };
@@ -38,24 +57,22 @@
 
     static class Result {
 	Terminator terminator;
-	int substitutions;
+	int retCode;
 
         /** No text had been parsed. */
         boolean empty; 
 
-	Result(Terminator terminator, int substitutions, boolean empty) {
+	Result(Terminator terminator, int retCode, boolean empty) {
             this.terminator = terminator;
-            this.substitutions = substitutions;
+            this.retCode = retCode;
             this.empty = empty;
         }
 
         Result() {
-            this(null, 0, true);
+            this(null, -1, true);
         }       
     };    
 
-    private Map<String, Function> functions = new HashMap<String, Function>();
-
     private Map<String, Object> variables = new HashMap<String, Object>();
     private TemplateParser superParser;
 
@@ -71,26 +88,26 @@
         Functions.registerAllFunctions(this);
     }
 
-    public void registerFunction(Function f) {
-        functions.put(f.name, f);
+    public void registerFunction(String name, Function f) {
+        variables.put(name, f);
     }
 
-    public int parse(Reader in, Writer out) 
+    public int parse(TemplateReader in, Writer out) 
 	throws IOException, TemplateException {
 	
-	return parse(in, out, true, null, null).substitutions;
+	return parse(in, out, true, null, null).retCode;
     }
 
     /**
      *  Parse template.
      *
-     * @param in Reader to read template data.
+     * @param in TemplateReader to read template data.
      * @param out Writer to write processed data.
      * @param recursive enables recursive processing.
      * @param separators characters which terminate parsing block.
      * @param leading characters to ignore at the beginning of the block.
      */
-    Result parse(Reader in, Writer out, boolean recursive, 
+    Result parse(TemplateReader in, Writer out, boolean recursive, 
                  char[] separators, char[] leading)
 	throws IOException, TemplateException {
 
@@ -117,10 +134,13 @@
 
 	    if (recursive && leftBracket && c == BR_IN) {
 		
+                if (result.retCode < 0)
+                    result.retCode = 0;
+
 		lc = -1;
                 int tb = termBracket;
                 termBracket = BR_RIGHT[index];
-		result.substitutions += parseFunction(in, out);
+		result.retCode += parseFunction(in, out);
                 termBracket = tb;
 		
 	    } else if (lc == BR_IN && c == termBracket) {
@@ -151,22 +171,6 @@
 	return result;
     }
 
-    int parseVariable(String name, Writer out) 
-	throws IOException, TemplateException {
-
-        Object ovalue = getValue(name);
-        if (ovalue == null)
-            return 0;
-
-	String svalue = ovalue.toString();
-
-	if (svalue == null || svalue.length() == 0)
-	    return 0;
-       
-	out.write(svalue);
-	return 1;
-    }
-
     boolean isSeparator(int c, char[] separators) {
         for (char p : separators) {
             if (c == p) return true;
@@ -175,7 +179,7 @@
         return false;
     }
 
-    int parseFunction(Reader in, Writer out)
+    int parseFunction(TemplateReader in, Writer out)
 	throws IOException, TemplateException {
         
 	StringBuffer sb = new StringBuffer();
@@ -196,16 +200,28 @@
 				      FunctionData.NONRECURSIVE, 
 				      in, out);
             } else if (c < 0) {
-		System.err.println("Error: unexpected end of file.");
-		return 0;
+		throw new TemplateException("Unexpected end of file.", in);
             } else {
 		sb.append((char)c);
 	    }
 	}
     }
 
+    int parseValue(Object value, Writer out) throws IOException {
+        if (value == null)
+            return 0;
+
+        String svalue = value.toString();
+        
+        if (svalue == null || svalue.length() == 0)
+            return 0;
+
+        out.write(svalue);
+        return 1;
+    }
+
     private int invokeFunction(String name, FunctionData fd,
-			       Reader in, Writer out)
+			       TemplateReader in, Writer out)
 	throws IOException, TemplateException {
 
         FunctionDataParser fdp = new FunctionDataParser(this, fd, in);
@@ -214,14 +230,15 @@
             return fdp.parseData(out);
 	}
         
-        Function f = getFunction(name);
+        Object value = getValue(name);
+        int r;
 
-        if (f == null) {
-	    throw new TemplateException("Unknown function: " + name);
+        if (value instanceof Function) {            
+            r = ((Function) value).invoke(fdp, out);           
+        } else { 
+            r = parseValue(value, out);
         }
 
-        int r = f.invoke(fdp, out);
-
 	if (fdp.hasMoreData()) {
 	    /* Skip remaining function data. */
 	    fdp.parseData(new Writer() {
@@ -234,27 +251,14 @@
 	return r;
     }
 
-    Function getFunction(String name) throws TemplateException {
-	Function function = functions.get(name);
-	if (function != null) return function;   
-
-	if (superParser != null) {
-	    if (name.startsWith(SUPER))
-		return superParser.getFunction(name.substring(SUPER.length()));
-	    else
-		return superParser.getFunction(name);
-	}
-
-	return null;
-    }
-
-    Object getValue(String name) throws TemplateException {
+    public Object getValue(String name) throws TemplateException {
 	Object value = variables.get(name);
 	if (value != null) return value;   
 
 	if (superParser != null) {
-	    if (name.startsWith(SUPER))
-		return superParser.getValue(name.substring(SUPER.length()));
+	    if (name.startsWith(SUPER_PREFIX))
+		return superParser.getValue
+                    (name.substring(SUPER_PREFIX.length()));
 	    else
 		return superParser.getValue(name);
 	}
@@ -262,21 +266,26 @@
 	return null;
     }
 
-    void setValue(String name, Object value) {
+    public void setValue(String name, Object value) {
 	variables.put(name, value);
     }
 
-    void clearValues() {
+    public void clearValues() {
 	variables.clear();
+        Functions.registerAllFunctions(this);
     }
 
     // TEST
-    public static void main(String[] args) 
+    public static void main(String[] args)
 	throws IOException, TemplateException {
 	
 	TemplateParser p = new TemplateParser();
 	
-	FileReader in = new FileReader("parser.in");
+	TemplateReader in = 
+            new TemplateReader
+            (new LineNumberReader
+             (new FileReader("parser.in")), "parser.in");
+
 	FileWriter out = new FileWriter("parser.out");
 
 	p.parse(in, out);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/TemplateReader.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,64 @@
+/*
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: TemplateReader.java,v 1.5 2006/12/14 14:39:22 mikhail Exp $
+ */
+
+package kryshen.tema;
+
+import java.io.Reader;
+import java.io.LineNumberReader;
+import java.io.FilterReader;
+import java.io.IOException;
+
+/**
+ * Reader for TEMA templates. Stores data source name (commonly
+ * filename) and tracks line numbers for error reporting.
+ *
+ * @author Mikhail A. Kryshen
+ */
+public class TemplateReader extends FilterReader {
+    private String source = null;
+
+    private LineNumberReader lnReader = null;
+    private TemplateReader parentReader = null;
+
+    public TemplateReader(LineNumberReader in, String source) {
+        super(in);
+        this.lnReader = in;
+        this.source = source;
+    }
+
+    public TemplateReader(Reader in, TemplateReader parent) {
+        super(in);
+        this.source = source;
+    }
+
+    public String getSource() {
+        if (source != null)
+            return source;
+        
+        return parentReader.getSource();
+    }
+    
+    public int getLineNumber() {
+        if (lnReader != null)
+            return lnReader.getLineNumber();
+        
+        return parentReader.getLineNumber();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/demo/DemoFrame.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,181 @@
+/*
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: DemoFrame.java,v 1.3 2006/12/14 15:59:48 mikhail Exp $
+ */
+
+package kryshen.tema.demo;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.URL;
+
+import kryshen.tema.*;
+
+/**
+ * TEMA demonstation console.
+ */
+public class DemoFrame extends Frame {
+    private TextArea input;
+    private TextArea output;
+    private TextArea error;
+    
+    public DemoFrame() {
+        super("TEMA demo console");
+
+        GridBagLayout gbl = new GridBagLayout();
+
+        GridBagConstraints c = new GridBagConstraints();
+
+        setLayout(gbl);
+
+        input = new TextArea(25, 40);
+        input.setEditable(true);
+
+        output = new TextArea(25, 40);
+        output.setEditable(false);
+
+        error = new TextArea(5, 80);
+        error.setEditable(false);
+
+        Label l;
+
+        c.insets = new Insets(3, 3, 3, 3);
+        c.fill = GridBagConstraints.BOTH;
+        c.gridwidth = GridBagConstraints.RELATIVE;
+
+        l = new Label("Enter your code and click \"Process\".");
+
+        gbl.setConstraints(l, c);
+        add(l);
+
+        Panel buttons = new Panel();
+        buttons.setLayout(new FlowLayout(FlowLayout.LEFT));
+        
+        Button process = new Button("Process");
+        Button clear = new Button("Clear");
+        Button close = new Button("Close");
+
+        buttons.add(process);
+        buttons.add(clear);
+        buttons.add(close);
+
+        c.gridwidth = GridBagConstraints.REMAINDER; 
+
+        gbl.setConstraints(buttons, c);
+        add(buttons);
+
+        c.fill = GridBagConstraints.BOTH;
+        c.anchor = GridBagConstraints.CENTER;
+        c.gridwidth = GridBagConstraints.RELATIVE;
+
+        l = new Label("Input:");
+
+        gbl.setConstraints(l, c);
+        add(l);
+
+        c.gridwidth = GridBagConstraints.REMAINDER; 
+
+        l = new Label("Output:");
+
+        gbl.setConstraints(l, c);
+        add(l);
+
+        c.gridwidth = GridBagConstraints.RELATIVE; 
+
+        gbl.setConstraints(input, c);
+        add(input);
+       
+        c.gridwidth = GridBagConstraints.REMAINDER; 
+
+        gbl.setConstraints(output, c);
+        add(output);
+
+        l = new Label("Errors:");
+
+        gbl.setConstraints(l, c);
+        add(l);
+
+        gbl.setConstraints(error, c);
+        add(error);      
+
+        process.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    process();
+                }
+            });
+
+        clear.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    error.setText("");
+                    output.setText("");
+                    input.setText("");
+                    
+                }
+            });
+
+        close.addActionListener(new ActionListener() {
+                public void actionPerformed(ActionEvent e) {
+                    dispose();
+                }
+            });
+
+        addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent e) {
+                    dispose();
+                }
+            });
+        
+        URL source = getClass().getResource("demo.template");
+        StringBuffer buffer = new StringBuffer();
+
+        try {
+            Reader in = new BufferedReader
+                (new InputStreamReader(source.openStream(), "UTF-8"));           
+            
+            for (int ch = in.read(); ch >= 0; ch = in.read()) {
+                buffer.append((char)ch);
+            }
+
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        
+        input.setText(buffer.toString());
+    }
+
+    private void process() {
+        String s = input.getText();
+        
+        TemplateReader tr = new TemplateReader
+            (new LineNumberReader(new StringReader(s)), "input");
+        TemplateParser tp = new TemplateParser();
+        StringWriter sw = new StringWriter();
+
+        error.setText("");
+
+        try {
+            tp.parse(tr, sw);
+        } catch (Exception e) {
+            error.setText(e.toString());
+        }
+
+        output.setText(sw.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/demo/Hello.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Hello.java,v 1.2 2006/12/14 14:39:24 mikhail Exp $
+ */
+
+package kryshen.tema.demo;
+
+import java.io.Writer;
+import java.io.IOException;
+import kryshen.tema.*;
+
+/**
+ * Example function implementation.
+ * 
+ * @author Mikhail A. Kryshen
+ */
+public class Hello extends Function {
+    public Hello() {}
+
+    public int invoke(FunctionDataParser fdp, Writer out)
+        throws IOException, TemplateException {
+        
+        out.write("Hello, ");
+        fdp.parseData(out);
+
+        return 1;
+    }
+}
--- a/src/kryshen/tema/functions/Define.java	Tue May 16 18:04:09 2006 +0400
+++ b/src/kryshen/tema/functions/Define.java	Thu Dec 14 23:22:05 2006 +0300
@@ -1,7 +1,21 @@
 /*
- * Copyright (C) 2006 Mikhail A. Kryshen
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
  *
- * $Id: Define.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Define.java,v 1.7 2006/12/14 14:35:00 mikhail Exp $
  */
 
 package kryshen.tema.functions;
@@ -11,9 +25,15 @@
 
 import kryshen.tema.*;
 
+/**
+ * Define function implementation.
+ *
+ * @author Mikhail A. Kryshen
+ */
 public class Define extends Function {
+    public static final Function DEFINE = new Define();
+
     public Define() {
-        super("define");
     }
 
     public int invoke(FunctionDataParser fdp, Writer out)
@@ -22,37 +42,42 @@
         final String arg0 = fdp.getNextArg();
         final String data = fdp.getData();
 
-        Function newFunction = new Function(arg0) {
+        Function newFunction = new Function() {
                 public int invoke(final FunctionDataParser fdp, final Writer out)
                     throws IOException, TemplateException {
-
+		    
                     TemplateParser functionParser = 
                         new TemplateParser(fdp.getTemplateParser());
                     
-                    functionParser.registerFunction(new Function("nextarg") {
-                            public int invoke(FunctionDataParser unusedFdp, 
-                                              final Writer out)
-                                throws IOException, TemplateException {
-
-                                return fdp.parseNextArg(out);
-                            }
-                        });
+                    functionParser.registerFunction
+			("nextarg", new Function() {
+				public int invoke(FunctionDataParser unusedFdp, 
+						  final Writer out)
+				    throws IOException, TemplateException {
+				    
+				    return fdp.parseNextArg(out);
+				}
+			    });
+		    
+                    functionParser.registerFunction
+			("data",new Function() {
+				public int invoke(FunctionDataParser unusedFdp, 
+						  final Writer out)
+				    throws IOException, TemplateException {
+				    
+				    return fdp.parseData(out);
+				}
+			    });
+		    
+                    TemplateReader dataReader = new TemplateReader
+                        (new StringReader(data), fdp.getTemplateReader());
 
-                    functionParser.registerFunction(new Function("data") {
-                            public int invoke(FunctionDataParser unusedFdp, 
-                                              final Writer out)
-                                throws IOException, TemplateException {
-
-                                return fdp.parseData(out);
-                            }
-                        });
-
-                    return functionParser.parse(new StringReader(data), out);                                       
+                    return functionParser.parse(dataReader, out);
                 }
             };
-
-        fdp.getTemplateParser().registerFunction(newFunction);
-
+	
+        fdp.getTemplateParser().registerFunction(arg0, newFunction);
+	
         out.write(arg0);
         return 1;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/functions/IO.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,163 @@
+/*
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: IO.java,v 1.4 2006/12/14 15:59:49 mikhail Exp $
+ */
+
+package kryshen.tema.functions;
+
+import java.io.*;
+import java.util.*;
+
+import kryshen.tema.*;
+
+/**
+ * I/O functions.
+ */
+public class IO {
+    public static final Function COPY =
+        new Function() {
+           public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+
+                String arg0 = fdp.getNextArg();
+                String arg1 = fdp.getNextArg();
+
+                File source = new File
+                    (Tema.getProperty("resource_base"), arg0);
+                File dest = new File(arg1);
+                
+                try {
+                    copyFile(source, dest);
+                } catch (IOException e) {
+                    System.err.println(e);
+                    return 0;
+                }
+                out.write(arg1);
+                return 1;
+            }
+        };
+
+    public static final Function WRITE =
+        new Function() {
+           public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+
+                String arg0 = fdp.getNextArg();
+
+		System.err.println("Writing " + arg0 + "...");
+
+                Writer fw;
+
+                try {
+		    fw = Tema.createFileWriter(arg0);
+                } catch (IOException e) {
+                    System.err.println(e);
+                    //throw new TemplateException(e.getMessage(), e, in);
+                    return 0;
+                }
+
+                try {
+		    fdp.parseData(fw);
+                } finally {
+                    fw.close();
+                }
+
+                out.write(arg0);
+
+		System.err.println("Saved " + arg0 + ".");
+                return 1;
+            }
+        };
+
+    public static final Function READ =
+        new Function() {
+           public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+
+	       String filename = fdp.getData();
+	       String file;
+	       
+                try {
+                    file = Tema.readFile(new File(filename));
+                } catch (IOException e) {
+                    System.err.println(e);
+                    //throw new TemplateException(e.getMessage(), e, in);
+                    return 0;
+                }
+		
+                out.write(file);
+                return 1;
+            }
+        };
+
+    public static final Function INCLUDE =
+        new Function() {
+           public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+                
+                String filename = fdp.getData();
+                
+                TemplateReader fin;
+
+                try {
+                    fin = Tema.createTemplateReader(new File(filename));
+                } catch (IOException e) {
+                    throw new TemplateException(e.getMessage(), e,
+                                                fdp.getTemplateReader());
+                }
+
+                int r = fdp.getTemplateParser().parse(fin, out);
+
+                fin.close();
+                return r;
+            }
+        };
+
+    /**
+     * Update file (copy if newer).
+     *
+     * @param src source file.
+     * @param dest destination file.
+     *
+     * @trows IOException on copying error.
+     */
+    private static void copyFile(File src, File dest) throws IOException {
+	System.err.print("Copying " + src + "... ");
+	
+	if (src.lastModified() < dest.lastModified()) {
+	    System.err.println(dest + " is up to date.");
+	    return;
+	}
+
+	File parent = dest.getParentFile();
+	if (parent != null) parent.mkdirs();
+
+        InputStream in = new FileInputStream(src);
+        OutputStream out = new FileOutputStream(dest);
+        
+        byte[] buffer = new byte[1024];
+        int len;
+        while ((len = in.read(buffer)) > 0) {
+            out.write(buffer, 0, len);
+        }
+        in.close();
+        out.close();
+
+	System.err.println("saved " + dest + ".");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/functions/ImageConverter.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,188 @@
+/*
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: ImageConverter.java,v 1.4 2006/12/14 19:44:32 mikhail Exp $
+ */
+
+package kryshen.tema.functions;
+
+import java.util.*;
+import java.io.*;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.geom.AffineTransform;
+import javax.imageio.*;
+import javax.imageio.stream.*;
+
+import kryshen.tema.*;
+
+/**
+ * Convert images to specified format.
+ *
+ * @author Mikhail A. Kryshen
+ */
+public class ImageConverter extends Function {    
+
+    public static final Function IMAGE = new ImageConverter();
+
+    public int invoke(FunctionDataParser fdp, Writer out)
+        throws IOException, TemplateException {
+        
+        String arg0 = fdp.getNextArg();
+        String arg1 = fdp.getNextArg();
+        String arg2 = fdp.getNextArg();
+        int arg3 = fdp.hasMoreData() ? 
+            Integer.parseInt(fdp.getNextArg()) : -1;
+        int arg4 = fdp.hasMoreData() ? 
+            Integer.parseInt(fdp.getNextArg()) : -1;
+        
+        File source = new File
+            (Tema.getProperty("resource_base"), arg0);
+        
+        try {
+            convert
+                (source,                  /* source file */
+                 new File(arg1),          /* dest file */
+                 arg2,                    /* format */
+                 arg3,                    /* max width */
+                 arg4);                   /* max height */
+        } catch (Exception e) {
+            System.err.println(e);
+            return 0;
+        }
+        
+        out.write(arg1);
+        return 1;
+    }    
+    
+    public static void convert(File source, File dest, String format,
+                               int maxWidth, int maxHeight) 
+	throws IOException, InterruptedException {
+	
+	System.err.print("Converting image " + source + "... ");
+        
+	if (source.lastModified() < dest.lastModified()) {
+	    System.err.println(dest + " is up to date.");
+	    return;
+	}
+
+	BufferedImage image = ImageIO.read(source);
+
+	//int type = image.getType();
+	//final int type = BufferedImage.TYPE_INT_RGB;
+	//ColorModel cm = image.getColorModel();
+
+        int w = image.getWidth(null);
+        int h = image.getHeight(null);
+
+	//boolean scale = false;
+
+	float scale = 1f;
+
+	if (maxWidth > 0 && w > maxWidth)
+	    scale = (float)maxWidth / w;
+	
+	if (maxHeight > 0 && h * scale > maxHeight)
+	    scale = (float)maxHeight / h;
+
+	if (scale != 1f) {
+	    w *= scale; h *= scale;
+
+// 	    ColorModel cm = image.getColorModel();	    
+// 	    boolean alphaPremultiplied = cm.isAlphaPremultiplied();
+// 	    WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
+// 	    BufferedImage scaled = new BufferedImage
+// 		(cm, raster, alphaPremultiplied, null);
+
+// 	    BufferedImage scaled = new BufferedImage(w, h, image.getType());
+	    
+
+ 	    Image scaled = image.getScaledInstance(w, h, Image.SCALE_SMOOTH);
+
+ 	    ColorModel cm = image.getColorModel();	    
+ 	    boolean alphaPremultiplied = image.isAlphaPremultiplied();
+ 	    WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
+ 	    image = new BufferedImage(cm, raster, alphaPremultiplied, null);
+
+	    Graphics g = image.getGraphics();
+	    g.drawImage(scaled, 0, 0, null);
+	    g.dispose();
+
+//	    image = scale(image, scaled, scale);
+//	    Graphics2D g = scaled.createGraphics();
+//	    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+// 			       RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+// 	    System.err.print(" " + g.drawImage(image, 0, 0, w, h, null) + " ");
+// 	    g.dispose();
+// 	    image = scaled;
+	}
+       
+	File parent = dest.getParentFile();
+	if (parent != null) parent.mkdirs();
+
+ 	ImageIO.write(image, format, dest);
+	System.err.println("saved " + dest + ".");	
+    }
+
+//     public static ColorModel getColorModel(Image image) 
+// 	throws InterruptedException {
+
+// 	PixelGrabber grabby = new PixelGrabber(image, 0, 0, 1, 1, false);
+// 	if (!grabby.grabPixels())
+// 	    throw new RuntimeException("pixel grab fails");
+// 	return grabby.getColorModel();
+//     }
+
+//     private static BufferedImage scale(BufferedImage image, 
+// 				       BufferedImage dest, 
+// 				       float scale) {
+
+// 	AffineTransform tx = new AffineTransform();
+// 	tx.scale(scale, scale);
+
+//  	AffineTransformOp op = new AffineTransformOp
+//  	    (tx, AffineTransformOp.TYPE_BILINEAR);
+
+// 	return op.filter(image, dest);
+//     }
+
+    // TEST    
+    public static void main(String[] args) 
+	throws IOException, InterruptedException {
+
+	convert(new File(args[0]), new File(args[1]), "png", 300, 300);
+    }
+
+
+//     public static BufferedImage toBufferedImage(Image image, ColorModel cm) {
+// 	if (image instanceof BufferedImage)
+// 	    return (BufferedImage)image;
+
+// 	int w = image.getWidth(null);
+// 	int h = image.getHeight(null);
+
+// 	boolean alphaPremultiplied = cm.isAlphaPremultiplied();
+// 	WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
+// 	BufferedImage result = new BufferedImage(cm, raster, alphaPremultiplied, null);
+// 	Graphics2D g = result.createGraphics();
+
+// 	g.drawImage(image, 0, 0, null);
+// 	g.dispose();
+
+// 	return result;
+//     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/functions/Logics.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,75 @@
+/*
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Logics.java,v 1.6 2006/12/14 14:39:26 mikhail Exp $
+ */
+
+package kryshen.tema.functions;
+
+import java.io.*;
+import java.util.*;
+
+import kryshen.tema.*;
+
+/**
+ * Logical and conditional functions.
+ *
+ * @author Mikhail A. Kryshen
+ */
+public class Logics {
+    public static final Function FALSE =
+        new Function() {
+            public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+		
+		fdp.parseData(out);
+                return 0;
+            }
+        };
+
+    public static final Function TRUE =
+        new Function() {
+            public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+		
+		fdp.parseData(out);
+                return 1;
+            }
+        };
+
+    /**
+     * Outputs it's data it has non-zero value.
+     */
+    public static final Function OPTIONAL =
+        new Function() {
+            public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+
+                StringWriter sw = new StringWriter();
+                int s = fdp.parseData(sw);
+                sw.close();
+                String data = sw.toString();
+
+                if (s != 0) {
+                    out.write(data);
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/functions/ReplaceWriter.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,154 @@
+/*
+ *  Copyright (C) 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: ReplaceWriter.java,v 1.2 2006/12/14 14:39:26 mikhail Exp $
+ */
+
+package kryshen.tema.functions;
+
+import java.io.Writer;
+import java.io.FilterWriter;
+import java.io.IOException;
+
+import java.util.LinkedList;
+import java.util.Iterator;
+
+/**
+ * FilterWriter which replaces characters with escape strings.
+ *
+ * @author Mikhail A. Kryshen
+ */
+class ReplaceWriter extends FilterWriter {
+    private String[] patterns;
+    private String[] replaces;
+
+    private String prefix;
+    private String postfix;
+
+    private int maxPatternLength = 0;
+
+    /** Have this Writer processed any data? */
+    private boolean processedData = false;
+
+    private StringBuffer buffer = new StringBuffer();
+
+    public ReplaceWriter(Writer w, String pattern, String replace) {
+        this(w, new String[]{pattern}, new String[]{replace});
+    }
+
+    public ReplaceWriter(Writer w, String pattern, String replace,
+                         String prefix, String postfix) {
+
+        this(w, new String[]{pattern}, new String[]{replace}, 
+             prefix, postfix);
+    }
+
+    public ReplaceWriter(Writer w, String[] patterns, String[] replaces) {
+        this(w, patterns, replaces, null, null);
+    }
+
+    public ReplaceWriter(Writer w, String[] patterns, String[] replaces, 
+                         String prefix, String postfix) {
+	super(w);
+        
+	this.patterns = patterns;
+	this.replaces = replaces;
+        
+        this.prefix = prefix;
+        this.postfix = postfix;
+        
+	for (int i = 0; i < patterns.length; i++) {
+	    int length = patterns[i].length();
+	    if (length > maxPatternLength)
+		maxPatternLength = length;
+	}
+    }
+
+    private boolean processBuffer(int minLength) throws IOException {
+        if (buffer.length() == 0) return false;
+
+        if (!processedData) {
+            if (prefix != null)
+                super.write(prefix, 0, prefix.length());
+            processedData = true;
+        }
+
+        int k;
+	for (k = 0; minLength + k < buffer.length(); k++) {
+	    for (int i = 0; i < patterns.length; i++) {
+		String pattern = patterns[i];
+		int length = pattern.length();
+
+                if (length + k > buffer.length())
+                    continue;
+
+		boolean match = true;
+
+		for (int j = 0; j < length; j++) {
+		    if (pattern.charAt(j) != buffer.charAt(j + k)) {
+			match = false;
+                        break;
+		    }
+		}
+
+		if (match) {
+                    super.write(buffer.substring(0, k), 0, k);
+                    buffer.delete(0, k + length);
+                    super.write(replaces[i], 0, replaces[i].length());
+		    return true;
+		}
+	    }
+	}
+
+        super.write(buffer.substring(0, k), 0, k);
+        buffer.delete(0, k);
+
+        return false;
+    }
+
+    public void write(int c) throws IOException {
+	buffer.append((char)c);
+	processBuffer(maxPatternLength);
+    }
+
+    public void write(char[] cbuf, int off, int len) throws IOException {
+	for (int i = off; i < off + len; i++) {
+	    buffer.append(cbuf[i]);
+	}
+	processBuffer(maxPatternLength);
+    }
+
+    public void write(String str, int off, int len) throws IOException {
+        buffer.append(str.substring(off, off + len));
+	processBuffer(maxPatternLength);
+    }
+
+    public void finish() throws IOException {
+        while (processBuffer(0));
+
+//         super.write(buffer.toString(), 0, buffer.length());
+//         buffer.delete(0, buffer.length());
+
+        if (processedData && postfix != null)
+            super.write(postfix, 0, postfix.length());
+    }
+
+    public void close() throws IOException {
+        finish();
+        super.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/kryshen/tema/functions/Standard.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,258 @@
+/*
+ *  Copyright (C) 2005, 2006 Mikhail A. Kryshen
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  $Id: Standard.java,v 1.5 2006/12/14 14:39:26 mikhail Exp $
+ */
+
+package kryshen.tema.functions;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+
+import kryshen.tema.*;
+
+/**
+ * Standard TEMA functions.
+ */
+public class Standard {
+    public static final Function SET =
+        new Function() {
+            public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+
+                String arg0 = fdp.getNextArg();
+                String arg1 = fdp.getData();
+                
+                fdp.getTemplateParser().setValue(arg0, arg1);
+                
+		out.write(arg0);
+                return 1;
+            }
+        };
+
+    /* prepare:qury_name sql_statement */
+    public static final Function PREPARE =
+        new Function() {
+            public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+
+                String arg0 = fdp.getNextArg();
+                String data = fdp.getData();
+
+		PreparedStatement statement;
+
+		try {
+		    statement = Tema.getDbConnection()
+                        .prepareStatement(data);
+		} catch (SQLException e) {
+		    throw new TemplateException
+                        (e.getMessage(), e, fdp.getTemplateReader());
+		}
+                
+                fdp.getTemplateParser().setValue(arg0, statement);   
+             
+		out.write(arg0);
+                return 1;
+            }
+        };
+
+    /* query:sql_query template arg1 arg2 ... argN */
+    public static final Function QUERY =
+        new Function() {
+           public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+                
+                String arg0 = fdp.getNextArg();
+                String arg1 = fdp.getNextArg();
+		List<String> args = fdp.getArgs();				
+
+		TemplateParser tp = fdp.getTemplateParser();
+
+                TemplateReader tr = 
+                    new TemplateReader(new StringReader(arg1),
+                                       fdp.getTemplateReader());
+
+		try {
+		    return Tema.query
+			(tr, (PreparedStatement)tp.getValue(arg0),
+			 args, tp, out);
+		} catch (SQLException e) {
+		    throw new TemplateException
+                        (e.getMessage(), e, fdp.getTemplateReader());
+		}
+            }
+        };
+
+    public static final Function REPLACE =
+        new Function() {
+	    public int invoke(FunctionDataParser fdp, Writer out)
+		throws IOException, TemplateException {		
+
+                String arg0 = fdp.getNextArg();
+                String arg1 = fdp.getNextArg();
+
+                ReplaceWriter rw = new ReplaceWriter(out, arg0, arg1);
+
+                int ret = fdp.parseData(rw);
+                rw.finish();
+                return ret;
+            }
+        };
+
+    public static final Function LOAD =
+
+        new Function() {
+            public int invoke(FunctionDataParser fdp, Writer out)
+                throws IOException, TemplateException {
+                
+                final String name = fdp.getNextArg();
+                final String className = fdp.getNextArg();
+
+                List<URL> urls = new ArrayList<URL>(1);
+
+                while (fdp.hasMoreData()) {
+                    urls.add(new URL(fdp.getNextArg()));                    
+                }
+                
+                ClassLoader loader = this.getClass().getClassLoader();
+
+                if (urls.size() > 0) {
+                    loader = new URLClassLoader
+                        (urls.toArray(new URL[0]), loader);
+                }                
+
+                Class<Function> functionClass;
+                Function function;
+
+                try {
+                    functionClass = loadFunctionClass(loader, className);
+                } catch (ClassNotFoundException e) {
+                    throw new TemplateException
+                        ("Class not found", e, fdp.getTemplateReader());
+                } catch (ClassCastException e) {
+                    throw new TemplateException
+                        ("Not a function class", e, fdp.getTemplateReader());
+                }
+                
+                try {
+                    function = functionClass.newInstance();
+                } catch (InstantiationException e) {
+                    throw new TemplateException
+                        ("Could not load class", e, fdp.getTemplateReader());
+                } catch (IllegalAccessException e) {
+                    throw new TemplateException
+                        ("Could not load class", e, fdp.getTemplateReader());
+                }
+
+                fdp.getTemplateParser().registerFunction(name, function);
+                                
+
+                out.write(name);
+                return 1;
+            }
+        };
+
+    public static final Function NULL_OUTPUT =
+        new Function() {
+	    public int invoke(FunctionDataParser fdp, Writer out)
+		throws IOException, TemplateException {		
+
+		/* Write nothing. */
+		return fdp.parseData(new Writer() {
+                    public void close() {}
+                    public void flush() {}
+                    public void write(char[] cbuf, int off, int len) {}
+                });
+            }
+        };
+
+    public static final Function XML_ESCAPE =
+        new Function() {
+	    public int invoke(FunctionDataParser fdp, Writer out)
+		throws IOException, TemplateException {		
+
+                final String[] chars = {"&", "<", ">", "`", "\""};
+                final String[] escape = {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"};
+
+                ReplaceWriter rw = new ReplaceWriter(out, chars, escape);
+
+                int ret = fdp.parseData(rw);
+                rw.finish();
+                return ret;
+            }
+        };
+
+    public static final Function XML_CDATA =
+        new Function() {
+	    public int invoke(FunctionDataParser fdp, Writer out)
+		throws IOException, TemplateException {		
+
+                ReplaceWriter rw = new ReplaceWriter
+                    (out, "]]>", "]]]><![CDATA[]>", "<![CDATA[", "]]>");
+
+                int ret = fdp.parseData(rw);
+                rw.finish();
+                return ret;
+            }
+        };
+
+
+    @SuppressWarnings("unchecked")
+    private static Class<Function> loadFunctionClass
+        (ClassLoader loader, String className)
+        throws ClassNotFoundException {
+        
+        return (Class<Function>)loader.loadClass(className);
+    }
+
+    /**
+     * Update file (copy if newer).
+     *
+     * @param src source file.
+     * @param dest destination file.
+     *
+     * @trows IOException on copying error.
+     */
+    private static void copyFile(File src, File dest) throws IOException {
+	System.err.print("Copying " + src + "... ");
+	
+	if (src.lastModified() < dest.lastModified()) {
+	    System.err.println(dest + " is up to date.");
+	    return;
+	}
+
+	File parent = dest.getParentFile();
+	if (parent != null) parent.mkdirs();
+
+        InputStream in = new FileInputStream(src);
+        OutputStream out = new FileOutputStream(dest);
+        
+        byte[] buffer = new byte[1024];
+        int len;
+        while ((len = in.read(buffer)) > 0) {
+            out.write(buffer, 0, len);
+        }
+        in.close();
+        out.close();
+
+	System.err.println("saved " + dest + ".");
+    }
+}
Binary file test/Hello.class has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/Hello.java	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,21 @@
+import java.io.Writer;
+import java.io.IOException;
+import kryshen.tema.*;
+
+/**
+ * Test function class.
+ * 
+ * @author Mikhail A. Kryshen
+ */
+public class Hello extends Function {
+    public Hello() {}
+
+    public int invoke(FunctionDataParser fdp, Writer out)
+        throws IOException, TemplateException {
+        
+        out.write("Hello, ");
+        fdp.parseData(out);
+
+        return 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/demo	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+#java -jar ../dist/tema.jar
+java -classpath .:../dist/tema.jar kryshen.tema.Tema
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/demo.bat	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,1 @@
+java -classpath .:..\dist\tema.jar kryshen.tema.Tema
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/include.template	Thu Dec 14 23:22:05 2006 +0300
@@ -0,0 +1,1 @@
+<%define\test test arg1:[%nextarg:%], test arg2:[%nextarg:%], test data:[%data:%].%>
\ No newline at end of file
--- a/test/inctest.template	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-<%test:1 2 3%>
--- a/test/macrotest	Tue May 16 18:04:09 2006 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-java -jar ../dist/tema.jar
--- a/test/main.template	Tue May 16 18:04:09 2006 +0400
+++ b/test/main.template	Thu Dec 14 23:22:05 2006 +0300
@@ -1,3 +1,28 @@
-<%define`test [%nextarg:%]+[%nextarg:%]=[%data:]%>
-<%include`inctest.template%>
-<%test:<%test:ab cd x%> [%\<%test\1 2 3%>%] y%>
+[%!\ UTF-8 text %]
+
+Вывод текста:
+test text
+
+Вывод специальных символов:
+[%\<%test%>%]
+
+Включение файла с объявлением функции:
+<%include:include.template%>
+
+Вызов новой функции:
+<%test:1 2 3%>
+
+Тестирование read:
+<%read\include.template%>
+
+Загрузка функции из класса:
+<%load\hello Hello%>
+
+Выполенение загруженной функции:
+<%hello\TEMA%>
+
+Условное выполнение:
+<%optional:<%true:%>True%> <%optional:<%false:%>False%>
+
+Тестирование xml_escape:
+<%xml_escape\x < a & b%>
--- a/test/tema.properties	Tue May 16 18:04:09 2006 +0400
+++ b/test/tema.properties	Thu Dec 14 23:22:05 2006 +0300
@@ -1,16 +1,16 @@
 # Data source configuration
-# resource          : jdbc:odbc:biotopes-data
+# resource          : jdbc:odbc:database
 # driver            : sun.jdbc.odbc.JdbcOdbcDriver
 
 # Base directory for images and files
-# resource_base     : C:\\biotopes\\db
+# resource_base     : .
 
 # Template to start processing with
 main_template     : main.template
 
 # File encodings
-# input_encoding    : ISO-8859-5
-# output_encoding   : ISO-8859-5
+input_encoding    : UTF-8
+output_encoding   : UTF-8
 
 # Cache templates
 # cache_read        : true