camltemplate-1.0.2/0040755000076400010400000000000011030647136020114 5ustar gdsАдминистраторыcamltemplate-1.0.2/AUTHORS0100644000076400010400000000014010245311563021153 0ustar gdsАдминистраторыCamlTemplate is developed and maintained by Benjamin Geer (benjamin DOT geer AT gmail DOT com). camltemplate-1.0.2/camltemplate.godiva0100644000076400010400000000105511030375316023753 0ustar gdsАдминистраторы(* Godiva spec file *) Package: godi-camltemplate Version: 1.0.1 Revision: 0 Depends: godi-ocaml (>= 3.08) Build-Depends: godi-findlib (>= 1.0.4) Sources: http://saucecode.org/camltemplate/releases/camltemplate-1.0.1.tar.gz Homepage: http://saucecode.org/camltemplate/ Maintainer: Benjamin Geer Options: configure, opt, htdoc Docfiles: README, INSTALL, COPYING Description: A library for generating text from templates. CamlTemplate can be used to generate web pages, scripts, SQL queries, XML documents and other sorts of text. . camltemplate-1.0.2/ChangeLog0100644000076400010400000011032210263223055021657 0ustar gdsАдминистраторы2005-06-08 Benjamin Geer * doc/manual/manual.tex, examples/fastcgi/fcgihello.ml, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/ctBinop.ml, src/ctCache.ml, src/ctCache.mli, src/ctContext.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctScope.ml, src/ctSourcePos.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctTemplateModel.ml, src/ctTemplateTypes.ml, src/ctUnop.ml, src/ctUtil.ml, src/ctWeb.ml: Updated postal address of Free Software Foundation. 2005-05-29 Benjamin Geer * doc/manual/manual.tex, examples/fastcgi/fcgihello.ml, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/ctBinop.ml, src/ctCache.ml, src/ctCache.mli, src/ctContext.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctScope.ml, src/ctSourcePos.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctTemplateModel.ml, src/ctTemplateTypes.ml, src/ctUnop.ml, src/ctUtil.ml, src/ctWeb.ml: Amended copyright dates. * doc/manual/manual.tex: Small documentation correction. * examples/fastcgi/Makefile, examples/thread/Makefile: Fixed 'make clean' in example Makefiles. 2005-05-26 Benjamin Geer * INSTALL, doc/manual/manual.tex: Restored 'make opt' in installation instructions. * Makefile, camltemplate.godiva: Make native-code compilation optional again. * camltemplate.godiva, examples/filetest/Makefile, examples/hello/Makefile, examples/mod_caml/Makefile: Fixed compilation of examples when installed by GODI. * AUTHORS: Fixed email address. * NEWS, TODO: Added NEWS item, removed TODO items. * ChangeLog: Updated ChangeLog. * examples/fastcgi/Makefile: Cleaner 'make clean'. * Makefile: Makefile fix. * ChangeLog, NEWS, doc/manual/manual.tex, src/META: Getting ready for release. 2005-05-26 Benjamin Geer * examples/fastcgi/Makefile: Cleaner 'make clean'. * Makefile: Makefile fix. * ChangeLog, NEWS, doc/manual/manual.tex, src/META: Getting ready for release. 2005-05-25 Benjamin Geer * camltemplate.godiva, doc/manual/manual.tex, src/camlTemplate_mt.ml, src/ctUtil.ml: Updated docs, removed debugging output. * examples/thread/Makefile, src/camlTemplate_mt.ml, src/ctCache.ml, src/ctUtil.ml: I think this threading issue is fixed now... * src/camlTemplate_mt.ml: Added camlTemplate_mt.ml. * Makefile.rules, examples/fastcgi/Makefile, examples/fastcgi/fcgihello.tmpl, examples/mod_caml/cthello.tmpl, examples/thread/Makefile, src/META, src/Makefile, src/ctCache.ml, src/ctUtil.ml: Next attempt at fixing optional multithreading support. * examples/filetest/Makefile: Removed unused variable. * doc/manual/manual.tex: Dated manual. * camltemplate.godiva, doc/manual/manual.tex, examples/fastcgi/Makefile, examples/thread/Makefile, src/Makefile, src/ctUtil.ml: Apparently fixed the problem of threaded and non-threaded .cmi files being incompatible. 2005-05-24 Benjamin Geer * examples/Makefile, src/Makefile: Fixed uninstallation. * INSTALL, Makefile, doc/Makefile, doc/manual/manual.tex, examples/fastcgi/Makefile, examples/fastcgi/README, examples/fastcgi/fcgihello.ml, examples/fastcgi/fcgihello.tmpl, examples/mod_caml/Makefile, examples/mod_caml/cthello.ml.in, examples/thread/Makefile, src/Makefile: Fixed incompatibility between MT library and non-MT .cmi file. Added FastCGI example. 2005-05-23 Benjamin Geer * examples/thread/Makefile: Changed threads example to native code. * src/Makefile: Really clean in src. * src/Makefile: Another Makefile tweak. * src/Makefile: Small Makefile fix. * INSTALL, Makefile, Makefile.rules, camltemplate.godiva, configure, doc/manual/manual.tex, examples/Makefile, examples/examples.rules, examples/filetest/Makefile, examples/hello/Makefile, examples/mod_caml/Makefile, examples/mod_caml/cthello.ml.in, examples/thread/Makefile, examples/thread/README, src/META, src/Makefile, src/camlTemplateInit.ml: Applied Janne Hellsten's patch to build two versions of the library, one with thread support and one without. A few other Makefile fixes. 2004-10-20 Benjamin Geer * src/ctParser.mly: Fixed incorrect handling of a syntax error in macro call arguments. 2004-10-17 Benjamin Geer * src/ctUtil.ml: Changed open_in to open_in_bin to fix Cygwin file-reading problem. 2004-09-02 Benjamin Geer * doc/manual/manual.tex: Updated Apache 2.0 bug information in manual. * examples/filetest/coleridge.html.saved, src/ctLexer.mll: Bug fix for escapes wasn't quite right; it had changed the syntax slightly. Fixed that. * TODO: Added TODO. * examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/ctLexer.mll: Fixed incorrect handling of escapes, and added test cases. 2004-07-15 Benjamin Geer * camltemplate.godiva: Updated GODIVA spec file. * doc/manual/manual.tex: Fixed date in manual. * ChangeLog: Updated ChangeLog. * NEWS, doc/manual/manual.tex, examples/thread/thread_test.ml, src/META, src/ctUtil.ml: Fixed bug that caused compile error if thread support was enabled. 2004-06-11 Benjamin Geer * doc/manual/manual.tex: Another small correction. * doc/manual/manual.tex: Corrected exception name. * doc/manual/manual.tex: Clarified thread support. * doc/manual/manual.tex: Minor correction in manual. 2004-05-21 Benjamin Geer * src/camlTemplate.mli: Cleaned up the ocamldoc documentation a bit. 2004-05-14 Benjamin Geer * OCamlMakefile: Updated OCamlMakefile to version 6.11.0. 2004-05-11 Benjamin Geer * doc/manual/manual.tex: Fixed incorrect backslash. * ChangeLog, NEWS, camltemplate.godiva, doc/manual/manual.tex, src/META: Releasing version 0.9.1. 2004-05-03 Benjamin Geer * doc/manual/manual.tex, examples/filetest/macro.tmpl, src/ctLexer.mll: Change the line-continuation character from '#' to '\'. Using # was a silly idea; everything else uses '\'. * src/ctUtil.ml: Fixed comment. * src/camlTemplate.mli: Fixed incorrect comment. * INSTALL, camltemplate.godiva, doc/manual/manual.tex, examples/filetest/macro.tmpl, src/camlTemplate.mli, src/ctLexer.mll, src/ctStatement.ml: CamlTemplate now requires OCaml 3.07. Improved discussion of whitespace in manual. * examples/filetest/Makefile, examples/hello/Makefile, examples/thread/Makefile, src/Makefile, examples/mod_caml/Makefile: Makefile cleanup. * doc/manual/manual.tex: Fixed typeface. * configure: Removed unneeded variable. 2004-05-03 Benjamin Geer * doc/manual/manual.tex, examples/filetest/macro.tmpl, src/ctLexer.mll: Change the line-continuation character from '#' to '\'. Using # was a silly idea; everything else uses '\'. * src/ctUtil.ml: Fixed comment. * src/camlTemplate.mli: Fixed incorrect comment. * INSTALL, camltemplate.godiva, doc/manual/manual.tex, examples/filetest/macro.tmpl, src/camlTemplate.mli, src/ctLexer.mll, src/ctStatement.ml: CamlTemplate now requires OCaml 3.07. Improved discussion of whitespace in manual. * examples/filetest/Makefile, examples/hello/Makefile, examples/thread/Makefile, src/Makefile, examples/mod_caml/Makefile: Makefile cleanup. * doc/manual/manual.tex: Fixed typeface. * configure: Removed unneeded variable. 2004-05-02 Benjamin Geer * tools/collect_files: Added credit to tools/collect_files. * src/ctCache.ml, src/ctUtil.ml: Replaced file-reading function with a simpler one by Markus Mottl. * src/ctCache.ml, src/ctUtil.ml: Replaced pa_ifdef.cmo with pa_macro.cmo when calling camlp4. * src/ctCache.ml, src/ctUtil.ml: Improved some function names and comments. 2004-05-01 Benjamin Geer * camltemplate.godiva, examples/Makefile: More fixes for GODI. * NEWS, doc/manual/manual.tex: Minor documentation fixes. * NEWS, doc/manual/manual.tex, src/ctLexer.mll: Changed lexer so that if a newline is preceded by '#', both the '#' and the newline are ignored. * NEWS: Updated NEWS. * src/ctParser.mly: Fixed parser to handle empty templates. * NEWS: Updated NEWS. * doc/manual/manual.tex: Updated manual to reflect syntax change. * examples/filetest/coleridge.tmpl, src/ctLexer.mll: Changed lexer so that whitespace preceding a statement is eaten only when it starts at the beginning of a line. * src/ctCache.ml: Removed test code. 2004-04-30 Benjamin Geer * Makefile, configure, doc/Makefile, examples/Makefile: Fixed to use the PKGBASE variable now exported by GODIVA. * Makefile: Fixed Makefile so it won't work unless you run 'configure' first. * Makefile: Fixed small Makefile bug. * configure: Fixed so GODI can set the package name. * ChangeLog, INSTALL, NEWS, TODO, camltemplate.godiva, configure, doc/Makefile, doc/manual/manual.tex, examples/Makefile: Updated docs for release 0.9.0. More GODI/GODIVA packaging fixes. * camltemplate.godiva, doc/Makefile: Fixing build problems for GODI package. * INSTALL, README, doc/manual/manual.tex: Updated installation instructions. * Makefile, camltemplate.godiva, configure, doc/Makefile, src/META: Makefile fixes. Added Godiva spec file. * examples/mod_caml/Makefile, examples/thread/Makefile, src/Makefile, tools/collect_files, Makefile, Makefile.rules, OCamlMakefile, configure, doc/Makefile, doc/manual/manual.tex, examples/Makefile, examples/examples.rules, examples/filetest/Makefile, examples/hello/Makefile: Build changes in preparation for making a GODI package. 2004-04-30 Benjamin Geer * camltemplate.godiva, doc/Makefile: Fixing build problems for GODI package. * INSTALL, README, doc/manual/manual.tex: Updated installation instructions. * Makefile, camltemplate.godiva, configure, doc/Makefile, src/META: Makefile fixes. Added Godiva spec file. * examples/mod_caml/Makefile, examples/thread/Makefile, src/Makefile, tools/collect_files, Makefile, Makefile.rules, OCamlMakefile, configure, doc/Makefile, doc/manual/manual.tex, examples/Makefile, examples/examples.rules, examples/filetest/Makefile, examples/hello/Makefile: Build changes in preparation for making a GODI package. 2004-04-29 Benjamin Geer * src/Makefile: Removed extra commented line. * examples/filetest/Makefile, examples/hello/Makefile, examples/mod_caml/Makefile, examples/thread/Makefile, src/Makefile: Fixed LIBS in Makefiles so that the CamlTemplate library isn't linked to unix.cma or pcre.cma, because this causes problems for programs that use other libraries liked to those .cmas. Instead, programs using CamlTemplate have to link to unix and pcre. Thanks to Olivier Andrieu for pointing this out. 2004-04-17 Benjamin Geer * doc/manual/manual.tex, src/ctCache.ml: Documentation fixes. 2004-04-06 Benjamin Geer * src/Makefile, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctAst.ml, src/ctBinop.ml, src/ctCache.ml, src/ctCache.mli, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLiteral.ml, src/ctStatement.ml, src/ctUnop.ml: More code cleanup. Back to class types instead of pure virtual classes; extra methods can be accommodated by upcasting. 2004-04-04 Benjamin Geer * src/camlTemplate.mli, src/ctCache.ml, src/ctCache.mli: Went back to a virtual class for source_loader, so that people can have implementations containing methods that aren't in the type. * src/ctContext.ml, src/ctTemplateTypes.ml: Added some comments. * OCamlMakefile, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/ctCache.ml, src/ctCache.mli, src/ctContext.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctTemplateTypes.ml: Code cleanup. Replaced virtual classes with class types in the API. 2004-03-22 Benjamin Geer * src/camlTemplate.ml, src/camlTemplate.mli: Cleanup up code a bit and corrected a comment. 2004-03-13 Benjamin Geer * ChangeLog, NEWS, doc/manual/manual.tex, src/META: Releasing version 0.8.1. * examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/camlTemplate.ml, src/ctLexer.mll, src/ctParserAux.ml: Fixed bug that could have caused a template to be parsed incorrectly if a previous template had a syntax error. Fixed test data to reflect current template syntax. 2004-03-13 Benjamin Geer * examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/camlTemplate.ml, src/ctLexer.mll, src/ctParserAux.ml: Fixed bug that could have caused a template to be parsed incorrectly if a previous template had a syntax error. Fixed test data to reflect current template syntax. 2004-02-24 Benjamin Geer * doc/manual/manual.tex, examples/hello/hello.ml: Clarified the 'hello' example. * doc/manual/manual.tex, examples/hello/hello.ml: Fixed formatting in manual and example. * doc/manual/manual.tex: Fixed some errors in the manual. * Makefile: Fixed handling of Makefile.config in 'make dist'. * ChangeLog: Updated ChangeLog. * Makefile.config, NEWS, doc/manual/manual.tex, src/META, src/ctContext.ml: Updated NEWS and version numbers for release, and removed deleted files from CVS. * src/ctTemplate.ml: Fixed comment. * src/camlTemplate.ml, src/camlTemplate.mli, src/ctTemplate.ml: Code and comment cleanup. * Makefile.config, TODO, doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctUtil.ml: Got rid of the functorised API. A template cache is now a Cache.t that you have to create an instance of. Cleaned up the implementation of macro caching; macros are now cached in template objects. * src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctContext.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctWeb.ml, INSTALL, Makefile.config, TODO, configure, doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml: Switched to a functorised API, so that different template source loaders can use different template caches. Added a 'configure' script. Got rid of the circular dependency between the CamlTemplate and CtStatement modules, and the hack used to maintain it. Minor documentation corrections. 2004-02-24 Benjamin Geer * Makefile.config, NEWS, doc/manual/manual.tex, src/META, src/ctContext.ml: Updated NEWS and version numbers for release, and removed deleted files from CVS. * src/ctTemplate.ml: Fixed comment. * src/camlTemplate.ml, src/camlTemplate.mli, src/ctTemplate.ml: Code and comment cleanup. * Makefile.config, TODO, doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctUtil.ml: Got rid of the functorised API. A template cache is now a Cache.t that you have to create an instance of. Cleaned up the implementation of macro caching; macros are now cached in template objects. * src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctContext.ml, src/ctStatement.ml, src/ctTemplate.ml, src/ctWeb.ml, INSTALL, Makefile.config, TODO, configure, doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml: Switched to a functorised API, so that different template source loaders can use different template caches. Added a 'configure' script. Got rid of the circular dependency between the CamlTemplate and CtStatement modules, and the hack used to maintain it. Minor documentation corrections. 2004-02-04 Benjamin Geer * ChangeLog, NEWS: Fixed NEWS, updated ChangeLog. * NEWS, doc/manual/manual.tex, src/META: Updated files for release. 2004-02-03 Benjamin Geer * doc/Makefile, src/Makefile: Fixed src/Makefile to find pcre using ocamlfind. Fixed doc/Makefile to pass an -o option to dvips. 2004-01-14 Benjamin Geer * ChangeLog, doc/manual/manual.tex, src/ctLexer.mll, src/ctParser.mly: Added 'null' literal. Several documentation fixes. * src/Makefile: Applied patch from Kamil Shakirov to correct native code installation. 2004-01-05 Benjamin Geer * ChangeLog: Updated ChangeLog. * examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/META, NEWS, doc/manual/manual.tex: Updated test to check escapes in string literals, and updated version for release 0.7.1. * examples/filetest/Makefile: 'make clean' now removes test results. 2004-01-05 Benjamin Geer * examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/META, NEWS, doc/manual/manual.tex: Updated test to check escapes in string literals, and updated version for release 0.7.1. * examples/filetest/Makefile: 'make clean' now removes test results. 2004-01-04 Benjamin Geer * doc/manual/manual.tex, examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, examples/filetest/macro.tmpl, src/camlTemplate.mli, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctLexer.mll, src/ctMacro.ml, src/ctStatement.ml, src/ctUtil.ml, src/ctWeb.ml: Modified lexer to ignore spaces and tabs before statements. 2004-01-03 Benjamin Geer * doc/manual/manual.tex: Fixed some minor errors and omissions in the manual. * INSTALL, doc/manual/manual.tex: Updated INSTALL. * ChangeLog, ReleaseChecklist: Updated ChangeLog and ReleaseChecklist. * NEWS, doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctAst.ml, src/ctBinop.ml, src/ctContext.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctScope.ml, src/ctSourcePos.ml, src/ctStatement.ml, src/ctTemplateModel.ml, src/ctUnop.ml, src/ctUtil.ml, src/ctWeb.ml: Updated NEWS and copyright date. 2003-12-28 Benjamin Geer * NEWS, TODO, doc/manual/manual.tex, examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, examples/filetest/macro.tmpl, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctBinop.ml, src/ctContext.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctScope.ml, src/ctStatement.ml, src/ctTemplateModel.ml, src/ctUnop.ml, src/ctUtil.ml, src/ctWeb.ml: Implemented nested scopes and namespaces. 2003-12-14 Benjamin Geer * doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/ctBinop.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctStatement.ml, src/ctTemplateModel.ml, src/ctUnop.ml, src/ctWeb.ml: Shortened the names of the template_value types, and made the names of exception types follow Caml conventions. 2003-12-13 Benjamin Geer * examples/filetest/filetest.ml, src/ctLexer.mll, src/ctParser.mly, test/test.sh, Makefile, doc/manual/manual.tex: Extended literal syntax to be more like OCaml's. Updated manual to mention floats. * TODO, examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/ctBinop.ml, src/ctExpression.ml, src/ctLexer.mll, src/ctUnop.ml: Finished implementing TemplateFloat. 2003-12-12 Benjamin Geer * TODO: Reworked ideas about the module system. 2003-12-04 Benjamin Geer * TODO: Updated TODO. * TODO: Revised TODO. * TODO, src/camlTemplate.mli, src/ctExpression.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctParser.mly, src/ctTemplateModel.ml: Started adding TemplateFloat. 2003-12-02 Benjamin Geer * TODO, doc/manual/manual.tex, src/ctIdent.ml, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctStatement.ml: Allowed calling a macro with fewer arguments than it was defined with. Made error messages a bit more readable. 2003-12-01 Benjamin Geer * examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, src/ctLexer.mll: Changed lexer to allow #else# and #end#, to facilitate writing a template all on one line. * TODO: Added TODO items. 2003-11-30 Benjamin Geer * doc/manual/manual.tex, src/camlTemplate.mli, src/ctWeb.ml: Added asList web function. * doc/manual/manual.tex, src/Makefile: Doc and build fixes. * src/ctParser.mly, src/ctParserAux.ml, src/ctSourcePos.ml, src/ctStatement.ml, src/ctTemplateModel.ml, src/ctUnop.ml, src/ctUtil.ml, src/ctWeb.ml, doc/manual/manual.tex, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/Makefile, examples/mod_caml/cthello.ml, examples/mod_caml/cthello.ml.in, examples/thread/thread_test.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctAst.ml, src/ctBinop.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml: Added licence exception to allow linking with Apache. 2003-11-29 Benjamin Geer * src/camlTemplate.mli: Removed needless 'open' in camlTemplate.mli. * NEWS, TODO, doc/manual/manual.tex, examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, examples/mod_caml/Makefile, src/META, src/ctHashLookup.ml, src/ctLexer.mll, src/ctParser.mly, test/test.sh: Added a bracket operator for calculating a hash key at run time. 2003-11-01 Benjamin Geer * Makefile: Added 'webinstall' Makefile target to add distribution to SauceCode site. 2003-10-20 Benjamin Geer * doc/manual/manual.tex: Changed incorrect UTF-8 copyright character to Latin-1. 2003-10-09 Benjamin Geer * Makefile, ReleaseChecklist: Added release checklist and Makefile comments. * doc/manual/manual.tex: Fixed typo in manual. * ChangeLog, NEWS, doc/manual/manual.tex: Updated NEWS and manual for release. * src/Makefile, ChangeLog: Use +pcre in Makefile. * ChangeLog, doc/manual/manual.tex, src/META, src/Makefile: Not so spurious after all... 2003-10-08 Benjamin Geer * src/Makefile: Removed spurious LIBDIR in Makefile. * INSTALL, doc/manual/manual.tex, src/META, src/Makefile, src/ctWeb.ml: Switched from Str to Pcre because Str isn't thread-safe. * NEWS: Added missing item to NEWS. * ChangeLog: Updated ChangeLog. * NEWS, doc/manual/manual.tex, examples/filetest/coleridge.html.saved, examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, examples/filetest/footer.tmpl, src/META, src/camlTemplate.ml, src/ctHashLookup.ml, src/ctMacro.ml: Bug fix: when an error occurred in a macro template, the name of the macro template was not reported in the exception message. Added GPL notice to manual. Clarified hash-lookup exception mesages. Fixed META to include native-code version of the library. * INSTALL, Makefile, TODO, doc/manual/manual.tex, examples/Makefile, examples/filetest/filetest.ml, examples/hello/hello.ml, examples/mod_caml/cthello.ml, examples/thread/thread_test.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml, src/ctAst.ml, src/ctBinop.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctSourcePos.ml, src/ctStatement.ml, src/ctTemplateModel.ml, src/ctUnop.ml, src/ctUtil.ml, src/ctWeb.ml: Changed (C) to a real copyright symbol in the source code headers. Updated docs to reflect support in mod_caml 0.9.3. Added a TODO. * doc/manual/manual.tex: Added note about threads and Apache 2.0. * INSTALL, TODO: Added TODO for multithreading in Apache 2.0. 2003-10-07 Benjamin Geer * INSTALL, Makefile, TODO, doc/manual/manual.tex, examples/filetest/coleridge.html.saved, test/test.sh: Added 'make test'. * AUTHORS: Added AUTHORS. * TODO: Added a TODO. * NEWS: Added NEWS. * INSTALL, doc/manual/manual.tex, mod_caml.patch, src/META, src/camlTemplate.mli, src/ctExpression.ml: Deleted mod_caml.patch, since it has been incorprated into mod_caml, and and updated the documentation accordingly. Clarified type conversion in the manual. Fixed some code comments, and an exception string. * src/camlTemplate.ml, src/ctUtil.ml: Changed bash-ism to sh-ism. * examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, examples/filetest/footer.tmpl, examples/filetest/macro.tmpl: Fixed macro to use new escHtml function. * TODO, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/ctWeb.ml: Added functions for escaping URLs and HTML text. * INSTALL, doc/manual/manual.tex, mod_caml.patch, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateInit.ml: Updated mod_caml patch and instructions for mod_caml 0.9.2, using Richard Jones's suggestion of an initialisation module. 2003-10-06 Benjamin Geer * src/ctAst.ml: Comment fix. * src/camlTemplate.ml, src/ctStatement.ml: Fixed some comments. * src/camlTemplate.ml: Possibly better handling of I/O errors when reading template files. * src/camlTemplate.ml, src/ctExceptions.ml, src/ctLexer.mll: Renamed CtLexerError -> LexerError (which had got a Ct mistakenly tacked on to it). * doc/manual/manual.tex: Changed OCaml link to point to caml.inria.fr, since it seems to get updated more often. * doc/manual/manual.tex: Grammar correction. * TODO: Added TODO item. * doc/manual/manual.tex: Formatting fixes. * doc/manual/manual.tex: Corrected section about multithreading. * Makefile, doc/manual/manual.tex, src/META: Increased version number to 0.5.1. * ChangeLog: Updated ChangeLog. * doc/manual/manual.tex: Reordered material in the manual. * Makefile.config: Fixed instructions in Makefile.config so people don't unnecessarily have to rebuild the docs. * doc/manual/manual.tex: Mentioned PDF and PostScript versions of the manual in the manual itself. * ChangeLog: Updated ChangeLog. * doc/Makefile: Fixed bug in Makefile: missing documentation image in distribution archive. 2003-10-05 Benjamin Geer * doc/manual/manual.tex: Fixed date in manual. * ChangeLog: Updated ChangeLog. * ChangeLog, INSTALL, doc/manual/manual.tex: Minor documentation fixes. * ChangeLog, TODO, examples/thread/README: Updated TODO. * INSTALL, Makefile, Makefile.config, doc/manual/manual.tex, examples/Makefile, examples/mod_caml/Makefile, examples/mod_caml/README, examples/mod_caml/cthello.ml, mod_caml.patch, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/ctUtil.ml: Finally got it to work with mod_caml! * doc/manual/manual.tex: It's important to mention UTF-8, but we can take ISO-8859-n for granted. * doc/manual/manual.tex: Small correction in manual. * TODO, doc/manual/manual.tex, examples/mod_caml/README: Reorganised the introductory material in the manual. Added a TODO for mod_caml. 2003-10-05 Benjamin Geer * ChangeLog, INSTALL, doc/manual/manual.tex: Minor documentation fixes. * ChangeLog, TODO, examples/thread/README: Updated TODO. * INSTALL, Makefile, Makefile.config, doc/manual/manual.tex, examples/Makefile, examples/mod_caml/Makefile, examples/mod_caml/README, examples/mod_caml/cthello.ml, mod_caml.patch, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/ctUtil.ml: Finally got it to work with mod_caml! * doc/manual/manual.tex: It's important to mention UTF-8, but we can take ISO-8859-n for granted. * doc/manual/manual.tex: Small correction in manual. * TODO, doc/manual/manual.tex, examples/mod_caml/README: Reorganised the introductory material in the manual. Added a TODO for mod_caml. 2003-10-04 Benjamin Geer * ChangeLog: Added ChangeLog. * README, doc/Makefile, doc/manual/manual.tex, examples/thread/thread_test.ml, examples/thread/thread_test.tmpl: Small improvements to examples and manual. * doc/manual/manual.tex: Small additions to the documentation. * examples/Makefile, examples/thread/Makefile, examples/thread/thread_test.ml, examples/thread/thread_test.tmpl: Added multithreading example. * INSTALL, Makefile, README, TODO, doc/Makefile, doc/manual/manual.tex, src/META, src/camlTemplate.mli: Minor cleanups. * examples/Makefile: Fixed Makefile. * Makefile, doc/manual/manual.tex, examples/filetest/filetest.ml, src/Makefile, src/camlTemplate.mli, src/ctExpression.ml, src/ctFunctionCall.ml, src/ctMethodCall.ml, src/ctParser.mly, src/ctTemplateModel.ml: Improved documentation. Renamed TemplateMethod -> TemplateFunction. 2003-10-03 Benjamin Geer * examples/mod_caml/Makefile: Trying to get the mod_caml example to work... 2003-10-02 Benjamin Geer * src/expression.ml, src/hashLookup.ml, src/ident.ml, src/lexer.mll, src/literal.ml, src/macro.ml, src/methodCall.ml, src/parser.mly, src/parserAux.ml, src/sourcePos.ml, src/statement.ml, src/templateModel.ml, src/unop.ml, src/util.ml, Makefile, doc/manual/manual.tex, examples/mod_caml/Makefile, src/Makefile, src/ast.ml, src/binop.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/ctAst.ml, src/ctBinop.ml, src/ctExceptions.ml, src/ctExpression.ml, src/ctHashLookup.ml, src/ctIdent.ml, src/ctLexer.mll, src/ctLiteral.ml, src/ctMacro.ml, src/ctMethodCall.ml, src/ctParser.mly, src/ctParserAux.ml, src/ctSourcePos.ml, src/ctStatement.ml, src/ctTemplateModel.ml, src/ctUnop.ml, src/ctUtil.ml, src/exceptions.ml: Prefixed all internal modules with 'Ct'. * examples/mod_caml/Makefile, examples/mod_caml/README, examples/mod_caml/cthello.ml, examples/mod_caml/cthello.tmpl: Added a (currently non-working) mod_caml example. * INSTALL, Makefile, TODO, doc/manual/manual.tex, examples/filetest/Makefile, examples/hello/Makefile, src/META, src/Makefile: Build/install changes. 2003-09-30 Benjamin Geer * doc/manual/manual.tex: Fixed LaTeX syntax errors. * doc/manual/manual.tex, examples/hello/hello.ml, src/exceptions.ml, src/lexer.mll, src/parser.mly, src/statement.ml: Updated documentation. * doc/Makefile: Trivial change. * doc/Makefile, doc/manual/manual.tex, doc/manual/merge.dia, doc/manual/merge.eps, examples/hello/Makefile, examples/hello/hello.ml, examples/hello/hello.tmpl: New documentation and example. * Makefile, examples/Makefile, examples/filetest/Makefile, examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, src/Makefile, src/binop.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/expression.ml, src/hashLookup.ml, src/ident.ml, src/literal.ml, src/macro.ml, src/methodCall.ml, src/parser.mly, src/statement.ml, src/unop.ml: Lots of changes. 2003-09-26 Benjamin Geer * TODO, src/Makefile, src/macro.ml, src/parser.mly, src/statement.ml: Changed syntax to allow full expressions in #include directives. Moved macro code into a separate module. * TODO: Updated TODO. * src/camlTemplate.ml: Reformatted. * src/camlTemplate.ml: Fixed off-by-one error. * examples/filetest/.cvsignore: Added .cvsignore. * TODO, src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli, src/util.ml: Added a mutex to support multithreaded programs. * examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, examples/filetest/footer.tmpl, src/camlTemplate.ml, src/camlTemplate.mli, src/exceptions.ml, src/lexer.mll: Modified syntax so dollar signs can be used unescaped when not followed by an open brace. Added a safety net to catch unhandled Parse_error exceptions. * TODO: Updated TODO. * examples/filetest/footer.tmpl, examples/filetest/macro.tmpl, src/camlTemplateModel.ml, src/templateModel.ml: Aded missing files. * examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, src/ast.ml, src/binop.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/exceptions.ml, src/expression.ml, src/hashLookup.ml, src/ident.ml, src/lexer.mll, src/literal.ml, src/methodCall.ml, src/parser.mly, src/parserAux.ml, src/sourcePos.ml, src/statement.ml, src/unop.ml, src/util.ml: Added CVS Id keywords. 2003-09-25 Benjamin Geer * examples/filetest/Makefile, examples/filetest/filetest.ml, src/Makefile, src/binop.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/exceptions.ml, src/expression.ml, src/hashLookup.ml, src/ident.ml, src/lexer.mll, src/literal.ml, src/methodCall.ml, src/parser.mly, src/statement.ml, src/unop.ml: Reorganised the modules in the API, so they're nested now. * src/lexer.mll: Simplified comment implementation. * TODO, examples/filetest/coleridge.tmpl, src/camlTemplate.ml, src/lexer.mll: Added support for comments in templates. 2003-09-24 Benjamin Geer * TODO, examples/filetest/filetest.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/statement.ml: Reworked template cache. * src/camlTemplate.ml: Modifications to cache. 2003-09-23 Benjamin Geer * TODO: More notes. 2003-09-22 Benjamin Geer * TODO: Cache implementation notes. 2003-09-21 Benjamin Geer * TODO, examples/filetest/coleridge.tmpl, src/lexer.mll, src/parser.mly: Fixed bugs in macro implementation. * src/Makefile, src/camlTemplate.ml, src/exceptions.ml, src/parser.mly, src/parserAux.ml, src/statement.ml: Added support for macros (not tested yet). * TODO, examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, src/Makefile, src/binop.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateModel.ml, src/exceptions.ml, src/expression.ml, src/hashLookup.ml, src/ident.ml, src/lexer.mll, src/literal.ml, src/methodCall.ml, src/parser.mly, src/statement.ml, src/unop.ml: Added a directive for including templates in templates. Added a template cache. 2003-09-20 Benjamin Geer * TODO: Idea. * TODO: Added TODO items. * examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, src/lexer.mll: Fixed the eating of newlines after a directive. * examples/filetest/coleridge.tmpl: Added UTF-8 test text. * src/camlTemplate.ml: Doc fix. * src/Makefile, src/camlTemplate.ml, src/camlTemplate.mli: Cleaned up ocamldoc. * Makefile: Makefile fixes. * Makefile, README, src/Makefile: Small fixes. * COPYING, Makefile, OCamlMakefile, TODO, examples/Makefile, examples/filetest/Makefile, examples/filetest/coleridge.tmpl, examples/filetest/filetest.ml, src/Makefile, src/ast.ml, src/binop.ml, src/camlTemplate.ml, src/camlTemplate.mli, src/camlTemplateModel.ml, src/exceptions.ml, src/expression.ml, src/hashLookup.ml, src/ident.ml, src/lexer.mll, src/literal.ml, src/methodCall.ml, src/parser.mly, src/sourcePos.ml, src/statement.ml, src/unop.ml, src/util.ml: Imported sources camltemplate-1.0.2/configure0100755000076400010400000000110310244417461022015 0ustar gdsАдминистраторы#!/bin/sh show_help= prefix=/usr/local for option do optarg=`expr "x$option" : 'x[^=]*=\(.*\)'` case $option in -h | --help) show_help=true ;; --prefix=*) prefix=$optarg ;; esac done if test -n "$show_help"; then cat < Makefile.config < Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. camltemplate-1.0.2/doc/0040755000076400010400000000000011030647116020657 5ustar gdsАдминистраторыcamltemplate-1.0.2/doc/html/0040755000076400010400000000000011030647110021615 5ustar gdsАдминистраторыcamltemplate-1.0.2/doc/html/api/0040755000076400010400000000000011030647110022366 5ustar gdsАдминистраторыcamltemplate-1.0.2/doc/html/api/CamlTemplate.Cache.html0100644000076400010400000001537711030642050026636 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate.Cache

Module CamlTemplate.Cache


module Cache: sig .. end
Caches templates.


Customising How Source Code is Loaded



type source_check_result =
| TemplateUnchanged (*Indicates that the source code of the checked template has not changed since it was loaded.*)
| TemplateChanged (*Indicates that the source code of the checked template has changed since it was loaded.*)
| TemplateDeleted (*Indicates that the source code of the checked template was deleted since it was loaded.*)
The type returned by a template source loader when it checks whether a template's source code has changed.
class type source_loader = object .. end
An implementation of this class type can be used by a template cache to load template source code.
val as_source_loader : #source_loader -> source_loader
Upcasting function for CamlTemplate.Cache.source_loader.
val make_file_loader : template_dir:string -> source_loader
Returns a CamlTemplate.Cache.source_loader that loads template source code from files in a directory. The name of each template is used as the filename.

template_dir : the directory in which the template source files are located.

Using Template Caches


type t 
The type of template caches.
val create : ?loader:source_loader ->
?check_interval:float -> unit -> t
Creates a template cache.

loader : the source_loader that will be used to load template source code for the cache. If omitted, the cache uses a source_loader that loads template source code from the current working directory.
check_interval : the interval at which the template cache should be refreshed. The default is 5 minutes. If the interval is zero, the cache will be refreshed every time CamlTemplate.Cache.get_template is called. If the interval is negative, it will never be refreshed.
val get_template : cache:t -> template_name:string -> CamlTemplate.template
Given a cache and the name of a template, returns the template from the cache. If the template is not in the cache, it is loaded and cached.

If the cache is due to be refreshed, this method refreshes the cache (i.e. reloads any templates that have been modified since they were last loaded, and removes any deleted templates from the cache) before looking for the requested template.
Raises CamlTemplate.Syntax_error if a template cannot be parsed.

camltemplate-1.0.2/doc/html/api/CamlTemplate.Cache.source_loader.html0100644000076400010400000000366411030642050031457 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate.Cache.source_loader

Class type CamlTemplate.Cache.source_loader


class type source_loader = object .. end
An implementation of this class type can be used by a template cache to load template source code.

method check : template_name:string ->
load_time:float -> source_check_result
Checks whether a template's source has changed since it was last loaded. The load time is a time in seconds, as returned by Unix.time.
method load : template_name:string -> string
Loads the source code for a template.
camltemplate-1.0.2/doc/html/api/CamlTemplate.html0100644000076400010400000001432111030642050025620 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate

Module CamlTemplate


module CamlTemplate: sig .. end
A template processor.

Copyright © 2003, 2004, 2005 Benjamin Geer. Please see the file COPYING for licence information.

The latest version of this software can be found at http://saucecode.org/camltemplate.



Overview

To use templates, first write template source code (see the manual for instructions). Then create a template cache using the CamlTemplate.Cache module, and call CamlTemplate.Cache.get_template to create a CamlTemplate.template from your template source code.

To marge a template with data, put the data in a CamlTemplate.Model.thash. Then call CamlTemplate.merge.

Template Data Models


module Model: sig .. end
Provides the types used in the data models that are merged with templates.

Templates


type template 
Represents a parsed template.
val merge : tmpl:template ->
model:Model.thash -> buf:Buffer.t -> unit
Merges the data in a CamlTemplate.Model.thash with the template, and returns the resulting text in the buffer provided.
Raises Template_error if an error occurs in the template.
val get_name : template -> string
Returns the name of a template.
val dump : template -> string
Returns a simple string representation of the parse tree, for debugging purposes.

Exceptions


exception Syntax_error of string
Raised if an error is found when parsing template source code.
exception Template_error of string
Raised if an error occurs when merging data with a template.

Template Loading and Caching


module Cache: sig .. end
Caches templates.

Miscellaneous


val add_web_functions : Model.thash -> unit
Adds the following template functions to a template data model:

  • urlEncode URL-encodes a string.
  • escHtml Escapes special characters in text to be included in an HTML document.
  • escHtmlAttr Escapes special characters in text to be included in an HTML attribute.
  • escHtmlTextarea Escapes special characters in text to be included in an HTML textarea.
  • asList Converts any value to a list, if it isn't already a list. If the argument is a list, returns the argument. If the argument is null, returns an empty list. Otherwise, returns a single-element list containing the argument. This may be useful for dealing with form input fields that can have multiple values.
Each of these functions expects one argument.
camltemplate-1.0.2/doc/html/api/CamlTemplate.Model.html0100644000076400010400000001553611030642050026670 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate.Model

Module CamlTemplate.Model


module Model: sig .. end
Provides the types used in the data models that are merged with templates.


type tvalue =
| Tnull (*A null value.*)
| Tstr of string (*A string value.*)
| Tint of int (*An integer value.*)
| Tfloat of float (*A floating-point value.*)
| Tbool of bool (*A boolean value.*)
| Tlist of tlist (*A list.*)
| Thash of thash (*A set of key-value pairs.*)
| Tfun of tfun (*An Objective Caml function that can be called by a template.*)
A value in a template data model.
type tlist = tvalue list 
The type contained in a Tlist: a list of tvalues.
type thash = (string, tvalue) Hashtbl.t 
The type contained in a Thash: a collection of tvalues, each of which has a name.
type tfun = args:tvalue list -> tvalue 
The type contained in a Tfun: a function that takes tvalues as arguments, and returns a tvalue.
exception Tfun_error of string
An exception that tfun functions can raise when called by a template.
camltemplate-1.0.2/doc/html/api/index.html0100644000076400010400000000234311030642050024360 0ustar gdsАдминистраторы CamlTemplate API Documentation

CamlTemplate API Documentation

Index of types
Index of exceptions
Index of values
Index of class methods
Index of class types
Index of modules


CamlTemplate
A template processor.
camltemplate-1.0.2/doc/html/api/index_attributes.html0100644000076400010400000000142711030642050026630 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of class attributes

Index of class attributes


camltemplate-1.0.2/doc/html/api/index_classes.html0100644000076400010400000000140511030642050026073 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of classes

Index of classes


camltemplate-1.0.2/doc/html/api/index_class_types.html0100644000076400010400000000211411030642050026765 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of class types

Index of class types


S
source_loader [CamlTemplate.Cache]
An implementation of this class type can be used by a template cache to load template source code.

camltemplate-1.0.2/doc/html/api/index_exceptions.html0100644000076400010400000000307711030642050026626 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of exceptions

Index of exceptions


S
Syntax_error [CamlTemplate]
Raised if an error is found when parsing template source code.

T
Template_error [CamlTemplate]
Raised if an error occurs when merging data with a template.
Tfun_error [CamlTemplate.Model]
An exception that tfun functions can raise when called by a template.

camltemplate-1.0.2/doc/html/api/index_methods.html0100644000076400010400000000256411030642050026110 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of class methods

Index of class methods


C
check [CamlTemplate.Cache.source_loader]
Checks whether a template's source has changed since it was last loaded.

L
load [CamlTemplate.Cache.source_loader]
Loads the source code for a template.

camltemplate-1.0.2/doc/html/api/index_modules.html0100644000076400010400000000251211030642050026106 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of modules

Index of modules


C
Cache [CamlTemplate]
Caches templates.
CamlTemplate
A template processor.

M
Model [CamlTemplate]
Provides the types used in the data models that are merged with templates.

camltemplate-1.0.2/doc/html/api/index_module_types.html0100644000076400010400000000141711030642050027152 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of module types

Index of module types


camltemplate-1.0.2/doc/html/api/index_types.html0100644000076400010400000000515211030642050025605 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of types

Index of types


S
source_check_result [CamlTemplate.Cache]
The type returned by a template source loader when it checks whether a template's source code has changed.

T
t [CamlTemplate.Cache]
The type of template caches.
template [CamlTemplate]
Represents a parsed template.
tfun [CamlTemplate.Model]
The type contained in a Tfun: a function that takes tvalues as arguments, and returns a tvalue.
thash [CamlTemplate.Model]
The type contained in a Thash: a collection of tvalues, each of which has a name.
tlist [CamlTemplate.Model]
The type contained in a Tlist: a list of tvalues.
tvalue [CamlTemplate.Model]
A value in a template data model.

camltemplate-1.0.2/doc/html/api/index_values.html0100644000076400010400000000604211030642050025737 0ustar gdsАдминистраторы CamlTemplate API Documentation : Index of values

Index of values


A
add_web_functions [CamlTemplate]
Adds the following template functions to a template data model:
as_source_loader [CamlTemplate.Cache]
Upcasting function for CamlTemplate.Cache.source_loader.

C
create [CamlTemplate.Cache]
Creates a template cache.

D
dump [CamlTemplate]
Returns a simple string representation of the parse tree, for debugging purposes.

G
get_name [CamlTemplate]
Returns the name of a template.
get_template [CamlTemplate.Cache]
Given a cache and the name of a template, returns the template from the cache.

M
make_file_loader [CamlTemplate.Cache]
Returns a CamlTemplate.Cache.source_loader that loads template source code from files in a directory.
merge [CamlTemplate]
Merges the data in a CamlTemplate.Model.thash with the template, and returns the resulting text in the buffer provided.

camltemplate-1.0.2/doc/html/api/style.css0100644000076400010400000000417411030642050024241 0ustar gdsАдминистраторыa:visited {color : #416DFF; text-decoration : none; } a:link {color : #416DFF; text-decoration : none;} a:hover {color : Red; text-decoration : none; background-color: #5FFF88} a:active {color : Red; text-decoration : underline; } .keyword { font-weight : bold ; color : Red } .keywordsign { color : #C04600 } .superscript { font-size : 4 } .subscript { font-size : 4 } .comment { color : Green } .constructor { color : Blue } .type { color : #5C6585 } .string { color : Maroon } .warning { color : Red ; font-weight : bold } .info { margin-left : 3em; margin-right : 3em } .code { color : #465F91 ; } h1 { font-size : 20pt ; text-align: center; } h2 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90BDFF ;padding: 2px; } h3 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90DDFF ;padding: 2px; } h4 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90EDFF ;padding: 2px; } h5 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #90FDFF ;padding: 2px; } h6 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #C0FFFF ; padding: 2px; } div.h7 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #E0FFFF ; padding: 2px; } div.h8 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #F0FFFF ; padding: 2px; } div.h9 { font-size : 20pt ; border: 1px solid #000000; margin-top: 5px; margin-bottom: 2px;text-align: center; background-color: #FFFFFF ; padding: 2px; } .typetable { border-style : hidden } .indextable { border-style : hidden } .paramstable { border-style : hidden ; padding: 5pt 5pt} body { background-color : White } tr { background-color : White } td.typefieldcomment { background-color : #FFFFFF } pre { margin-bottom: 4px } div.sig_block {margin-left: 2em}camltemplate-1.0.2/doc/html/api/type_CamlTemplate.Cache.html0100644000076400010400000000711111030642050027662 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate.Cache sig
  type source_check_result =
      TemplateUnchanged
    | TemplateChanged
    | TemplateDeleted
  class type source_loader =
    object
      method check :
        template_name:string ->
        load_time:float -> CamlTemplate.Cache.source_check_result
      method load : template_name:string -> string
    end
  val as_source_loader :
    #CamlTemplate.Cache.source_loader -> CamlTemplate.Cache.source_loader
  val make_file_loader :
    template_dir:string -> CamlTemplate.Cache.source_loader
  type t
  val create :
    ?loader:CamlTemplate.Cache.source_loader ->
    ?check_interval:float -> unit -> CamlTemplate.Cache.t
  val get_template :
    cache:CamlTemplate.Cache.t ->
    template_name:string -> CamlTemplate.template
end
camltemplate-1.0.2/doc/html/api/type_CamlTemplate.Cache.source_loader.html0100644000076400010400000000246511030642050032516 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate.Cache.source_loader object
  method check :
    template_name:string ->
    load_time:float -> CamlTemplate.Cache.source_check_result
  method load : template_name:string -> string
end
camltemplate-1.0.2/doc/html/api/type_CamlTemplate.html0100644000076400010400000002112611030642050026662 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate sig
  module Model :
    sig
      type tvalue =
          Tnull
        | Tstr of string
        | Tint of int
        | Tfloat of float
        | Tbool of bool
        | Tlist of CamlTemplate.Model.tlist
        | Thash of CamlTemplate.Model.thash
        | Tfun of CamlTemplate.Model.tfun
      and tlist = CamlTemplate.Model.tvalue list
      and thash = (string, CamlTemplate.Model.tvalue) Hashtbl.t
      and tfun =
        args:CamlTemplate.Model.tvalue list -> CamlTemplate.Model.tvalue
      exception Tfun_error of string
    end
  type template
  val merge :
    tmpl:CamlTemplate.template ->
    model:CamlTemplate.Model.thash -> buf:Buffer.t -> unit
  val get_name : CamlTemplate.template -> string
  val dump : CamlTemplate.template -> string
  exception Syntax_error of string
  exception Template_error of string
  module Cache :
    sig
      type source_check_result =
          TemplateUnchanged
        | TemplateChanged
        | TemplateDeleted
      class type source_loader =
        object
          method check :
            template_name:string ->
            load_time:float -> CamlTemplate.Cache.source_check_result
          method load : template_name:string -> string
        end
      val as_source_loader :
        #CamlTemplate.Cache.source_loader -> CamlTemplate.Cache.source_loader
      val make_file_loader :
        template_dir:string -> CamlTemplate.Cache.source_loader
      type t
      val create :
        ?loader:CamlTemplate.Cache.source_loader ->
        ?check_interval:float -> unit -> CamlTemplate.Cache.t
      val get_template :
        cache:CamlTemplate.Cache.t ->
        template_name:string -> CamlTemplate.template
    end
  val add_web_functions : CamlTemplate.Model.thash -> unit
end
camltemplate-1.0.2/doc/html/api/type_CamlTemplate.Model.html0100644000076400010400000000613011030642050027717 0ustar gdsАдминистраторы CamlTemplate API Documentation : CamlTemplate.Model sig
  type tvalue =
      Tnull
    | Tstr of string
    | Tint of int
    | Tfloat of float
    | Tbool of bool
    | Tlist of CamlTemplate.Model.tlist
    | Thash of CamlTemplate.Model.thash
    | Tfun of CamlTemplate.Model.tfun
  and tlist = CamlTemplate.Model.tvalue list
  and thash = (string, CamlTemplate.Model.tvalue) Hashtbl.t
  and tfun = args:CamlTemplate.Model.tvalue list -> CamlTemplate.Model.tvalue
  exception Tfun_error of string
end
camltemplate-1.0.2/doc/html/manual/0040755000076400010400000000000011030647113023075 5ustar gdsАдминистраторыcamltemplate-1.0.2/doc/html/manual/contents_motif.gif0100644000076400010400000000047411030642140026614 0ustar gdsАдминистраторыGIF89aсpЂђяя!ю" Imported from XPM image: toc.xpm!щ,@зЬ6313Жc „BГ0 Г0‚ A0 Г0 Г0 ЂБ0 ѓБ`0Ђ@`0 ѓБ`  ѓБ`0Ђ@`0 ѓБ`0Ђ@`0000000000 0000000000 00000000 000000 0000 000000000 00000000000 00000000000000`АЂ ;camltemplate-1.0.2/doc/html/manual/index.html0100644000076400010400000000575411030642140025075 0ustar gdsАдминистраторы The CamlTemplate Manual Version 1.0.1

The CamlTemplate Manual
Version 1.0.1

Benjamin Geer

7 July 2005



This document was translated from LATEX by HEVEA.
camltemplate-1.0.2/doc/html/manual/manual.css0100644000076400010400000000071511030642140025057 0ustar gdsАдминистраторы .toc{list-style:none;} .title{margin:auto;text-align:center} .center{text-align:center;margin-left:auto;margin-right:auto;} .flushleft{text-align:left;margin-left:0ex;margin-right:auto;} .flushright{text-align:right;margin-left:auto;margin-right:0ex;} DIV TABLE{margin-left:inherit;margin-right:inherit;} PRE{text-align:left;margin-left:0ex;margin-right:auto;} BLOCKQUOTE{margin-left:4ex;margin-right:4ex;text-align:left;} .part{margin:auto;text-align:center} camltemplate-1.0.2/doc/html/manual/manual.html0100644000076400010400000013566311030642140025246 0ustar gdsАдминистраторы The CamlTemplate Manual Version 1.0.1

The CamlTemplate Manual
Version 1.0.1

Benjamin Geer

7 July 2005


1  Introduction

This manual describes how to use CamlTemplate, a template processor for Objective Caml programs. It can be used to generate web pages, scripts, SQL queries, XML documents and other sorts of text.

1.1  About This Manual

This manual is provided in HTML and PDF formats in the CamlTemplate distribution.

1.2  Licence

CamlTemplate is free software, released under the GNU General Public License. This manual is released under the same licence.

In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.

1.3  Features

  • A versatile, easy-to-learn template syntax that supports common scripting-language constructs, while encouraging a separation between presentation logic and application logic.
  • The supported Caml data structures accomodate lists, tables and trees of items in a straightforward manner.
  • Works well with mod_caml and mod_fastcgi.
  • Supports any ASCII-compatible encoding, including UTF-8.
  • Optional support for multithreading.
CamlTemplate works by merging data with handwritten templates. This process is illustrated in Figure 1.

The template contains only the handwritten material; some other program provides the data. The template's author doesn't need to be involved in writing that program; he or she only needs to know what data the program provides, and can therefore change the template without involving the program's developers. Likewise, the program can be modified so that it obtains data in a different way, without affecting the template. Different templates can be used to display the same data in different ways (e.g. to generate normal and `printer-friendly' versions of a web page).




Figure 1: Generating a document



1.4  Getting CamlTemplate

The CamlTemplate source code and documentation can be downloaded from the CamlTemplate web site.

1.5  Installing CamlTemplate

1.5.1  Installing with GODI

If you use GODI, you can install CamlTemplate from godi_console. Otherwise, you can install manually as described below.

1.5.2  Installing Manually

Requirements: Unpack the archive:
tar zxf camltemplate-x.y.z.tar.gz
cd camltemplate-x.y.z
To see the configuration options, type:
./configure --help
Type the following, adding any options you need:
./configure
Then type:
make
make opt
make test
If there are no errors, type make install as root. This installs bytecode and native-code versions of the library using ocamlfind. Documentation in HTML and PDF formats is installed in $PREFIX/doc/camltemplate. Several sample programs can be found in $PREFIX/share/camltemplate.

To uninstall the library, type make uninstall as root.

1.5.3  Integration with mod_caml

Mod_caml is an Apache module that dynamically loads OCaml bytecode to handle HTTP requests.

CamlTemplate has been tested with mod_caml 1.3.6 and Apache 1.3. (We haven't tested it with Apache 2.0, because a bug in Apache 2.0 has prevented mod_caml from working at all; this looks as if it will be fixed in Apache 2.2. If you need to use Apache 2.0, try the instructions on the mod_caml web site, and let us know if it works.)

1. Install mod_caml, and make sure it works on its own before proceeding (try the hello.ml example that comes with it).

2. In your httpd.conf, after the configuration you added for mod_caml, add the following line:
CamlLoad /path/to/camltemplate/camltemplate.cma
(If you don't know where it is, type ocamlfind query camltemplate at a shell prompt.)

3. Restart Apache.

4. Try compiling and installing the example in examples/mod_caml (see the README there).

1.5.4  Integration with mod_fastcgi

Mod_fastcgi is an Apache module that allows the web server to hand off HTTP requests to a pool of long-running programs; these can be OCaml programs compiled to bytecode or native code.

This has been tested using Christophe Troestler's OCaml-CGI package and mod_fastcgi 2.4.2, and works with Apache versions 1.3 and 2.0. For an example, see examples/fastcgi. You'll need to use CamlTemplate's optional thread support (see Section 4.4 for instructions).

1.6  Mailing List and Support

The camltemplate mailing list is used for questions, suggestions, bug reports and discussion about CamlTemplate.

There is also a Frequently Asked Questions page.

1.7  Author

CamlTemplate is developed and maintained by Benjamin Geer (benjamin DOT geer AT gmail DOT com).

1.8  History

In 1999, Benjamin Geer wrote a template processor in Java, called FreeMarker, based on the experience of using a similar tool with graphic designers in a web development shop. CamlTemplate borrows some aspects of FreeMarker (small library not tied to web development, JavaScript-like expressions, Perl-like data structures), as well as some ideas from the Apache Jakarta project's Velocity template processor (generated parser, more concise syntax), released in 2001. The first version of CamlTemplate was released in October 2003.

2  Writing Templates

2.1  Inserting Values

Here is a simple example of a template for generating an HTML page:
<html>
<head>
  <title>${title}</title>
</head>

<body>
<h1>${title}</h1>

Today's date: ${date}
</body>
</html>
This template expects two pieces of data: a title and a date. A dollar sign followed by an expression in braces is called an expansion; it means, `insert the value of this expression here'. If the value of title was Important Page, and the value of date was 29 September 2003, the resulting document would look like this:
<html>
<head>
  <title>Important Page</title>
</head>

<body>
<h1>Important Page</h1>

Today's date: 29 September 2003
</body>
</html>
A variable such as title or date is called a scalar variable, meaning that it contains only one value.

If an expansion contains a value that has not been set, it produces no output. This makes it convenient to write HTML form elements that display the value previously entered, if any:
<input type="text" name="address" value="${address}"/>

2.2  Hashes

It is often convenient to group several related values together, and give a name to the group. A hash is a collection of values, each of which has a name (called a `key'). Continuing with the example from the previous section, we might want to break down the date into day, month and year components:
Today's date: ${date.day}-${date.month}-${date.year}
Here, date is a hash, which contains three scalars: day, month and year. (An expression like date.day is called a hash lookup.) The result might be:
Today's date: 29-09-2003
Hashes can contain hashes, e.g.:
Date of birth:
  ${user.dob.day}-${user.dob.month}-${user.dob.year}
The string value of any variable (or other expression) can be used as a hash key by enclosing the expression in square brackets:
Error in field "${fieldName}": ${errors[fieldName]}
If the value of fieldName was always "title", the above would be the same as writing:
Error in field "title": ${errors.title}

2.3  Lists

Generated documents often contain lists of data. In a template, the #foreach statement processes all the elements in a list. Here's a simple example:
<p>Signatories:</p>

<ul>
  #foreach (signatory in signatories)
  <li>${signatory}</li>
  #end
</ul>
The output might look like this:
<p>Signatories:</p>

<ul>
  <li>Arthur Artichoke</li>
  <li>Bernard Banana</li>
  <li>Carol Carrot</li>
  <li>Dorothy Date</li>
</ul>
For each element in the list, the #foreach statement stores the element's value temporarily in the name given before the in, then processes the template text between the #foreach and the #end.

Here's an example that generates an HTML table:
<table>
<thead>
  <tr>
    <th>Name</th>
    <th>Date of Birth</th>
    <th>Favourite Colour</th>
  </tr>
</thead>
<tbody>
  #foreach (person in garden.people)
  <tr>
    <td>${person.name}</td>
    <td>${person.bdate}</td>
    <td>${person.colour}</td>
  </tr>
  #end
</tbody>
</table>
Here garden is a hash that contains a list called people. Each element of people is a hash containing three scalars (name, bdate and colour).

2.4  Conditionals

A template can contain optional text, which is used only if some condition is met. The #if statement tests a condition. For example:
#if (approved)
  This document has been approved for publication.
#else
  This document is awaiting approval.
#end
We have seen scalars that contain strings (i.e. text); true and false are also possible values of a scalar (e.g. approved above). Any scalar is equal to true if it has a value other than 0 or the empty string. A list is equal to true if it exists and isn't empty. A hash is equal to true if it exists. This makes it convenient to check, for example, whether a list contains any values before processing its contents:
#if (searchResults)
  #foreach (result in searchResults)
    ...
  #end
#end
If a scalar contains a string or a number, an expression can test the scalar's value, using comparison operators such as == (equals), != (is unequal to), < (is less than) and > (is greater than). You can also use #elseif blocks to test several conditions. For example:
#if (hour > 17)
  Good evening!
#elseif (hour > 12)
  Good afternoon!
#else
  Good morning!
#end

#if (status == "approved")
  This document has been approved for publication.
#else
  This document is awaiting approval.
#end
See Section 3.6 for the full details of expressions.

2.5  Setting values

The #set statement assigns a value to a name. The value is not set in the data model that the program has provided; a template cannot use #set to change its data model. The value remains internal to the template, and only while the template is being merged; it is then forgotten. Returning to the earlier example of an HTML table, suppose we wanted the background colour of the rows to alternate between yellow and white. We could write:
<tbody>
  #set (background = "white")

  #foreach (person in garden.people)
    <tr bgcolor="${background}">
      <td>${person.name}</td>
      <td>${person.bdate}</td>
      <td>${person.colour}</td>
    </tr>

    #if (background == "white")
      #set (background = "yellow")
    #else
      #set (background = "white")
    #end
  #end
</tbody>

2.6  Including Templates in Templates

Rather than copy and paste the same text into several templates, you can put the common text in a separate template, and include that template in other templates using the #include statement. For example, you might include a standard header and footer on each page:
#include ("header.tmpl")

...

#include ("footer.tmpl")
Included templates will not see any values that have been set in the including template, nor can the including template see any values that the included template sets. If you want to pass values into a reusable section of template code, use a macro, as described in the next section.

2.7  Macros

To create a reusable bit of template code that uses values you provide, you can write a macro. The #macro statement defines a macro, which can then be used as a statement in its own right. For example, here is a macro that formats a date in a particular way, given the year, month and day as numbers:
#macro formatDate(year, month, day)
  #var (monthPrefix)
  #var (dayPrefix)

  #if (month < 10)
    #set (monthPrefix = "0")
  #end

  #if (day < 10)
    #set (dayPrefix = "0")
  #end

  ${year}-${monthPrefix}${month}-${dayPrefix}${day}
#end
(The #var statement will be explained in a moment.)

Here is some template code that expects a hash called date like the one we saw in Section 2.2, and uses it to call the formatDate macro above:
Today's date:
  #formatDate(date.year, date.month, date.day)
A macro may be called with fewer arguments than it was defined with; the remaining arguments are set to null. It is an error to call a macro with too many arguments.

2.7.1  Defining Variables in Macros

The #var statement in the macro above initialises a variable for use within the macro, setting it to a null value. We could have written:
#set (monthPrefix = "")
But if there was already a variable called monthPrefix outside the macro, #set would change the value of the existing variable. (Sometimes this might be what you want.) By contrast, a variable initialised inside a macro with #var only exists within that macro, and doesn't affect any other variable that might have the same name outside the macro; its value is forgotten once the macro has completed. Once you have used #var to initialise a variable in a macro, you can use #set to change its value, as in the example above. To initialise a variable with a value other than null, you can write:
#var (colour = "blue")
When used outside of a macro, #var has the same effect as #set.

2.7.2  Storing Macros in Separate Templates

If there are some macros that you want to use in more than one template, you can define them in a separate template, which we'll call a macro template. In each template where you want to use those macros, you then need to tell CamlTemplate where to look for them, using the #open statement. For example, if you've written a macro template called macros.tmpl, and you want to use them in a template called test.tmpl, you would put the following line in test.tmpl, before using any of the macros:
#open ("macros.tmpl")
You can put several #open statements in a template. When you call a macro, CamlTemplate looks for it first in the template that's being merged, and then in any macro templates that have been opened in that template.

2.8  Functions

A function can be supplied to a template as part of its data. Since functions are written in Objective Caml, they can do things that would be cumbersome or impossible to do in macros. A function takes one or more expressions as arguments, and returns a value, which can be used in an expansion or in a statement.

For example, CamlTemplate provides a function called escHtml, for escaping special characters in HTML documents. It can be used like this:
Company name: ${escHtml(companyName)}
If the value of companyName was Artichoke & Banana, the output would be:
Company name: Artichoke &amp; Banana
In addition to escHtml, CamlTemplate provides the following functions, which application developers can choose to make available to templates:
urlEncode
URL-encodes a string.
escHtmlAttr
Escapes special characters in text to be included in an HTML attribute.
escHtmlTextarea
Escapes special characters in text to be included in an HTML textarea.
asList
Converts any value to a list, if it isn't already a list. If the argument is a list, returns the argument. If the argument is null, returns an empty list. Otherwise, returns a single-element list containing the argument. This is useful for dealing with form input fields that can have multiple values.
Each of these functions expects one argument.

2.9  Comments

You can write a comment in a template by surrounding it with #* and *#:
#* This is a comment. *#
Comments do not appear in the output when a template is merged. Comments can contain comments.

3  Template Syntax Reference

3.1  Whitespace

It often makes templates more readable to include extra whitespace around statements. In particular, the CamlTemplate syntax encourages a style in which each statement is on a line by itself, possibly indented. This means that there is extra whitespace around the statement: the indentation preceding it, and the newline after it. However, it is often not desirable to include that extra whitespace in the output. To support this, CamlTemplate ignores whitespace in certain contexts. The basic rules are as follows:
  • When a line begins with whitepace followed by #, that whitespace is ignored.

  • When a newline follows the closing parenthesis of a statement, or a keyword such as #else, the newline is ignored.
Thus a statement or keyword on a line by itself 'disappears' from the output (except for any output produced by the statement itself). Consider the following template:
#macro sayHello()
Hello.
#end
#if (true)
  #sayHello()
#end
This will print a single line of text, consisting of Hello. followed by a newline.

Another example:
#macro sayHello()
Hello.
#end
#if (true)
The greeting is: #sayHello()
#end
This will print:
The greeting is: Hello.
Note that since the call to #sayHello() does not fall at the beginning of a line, the space after the colon is preserved.

It is often convenient to put a comment at the end of a line, like this:
#if (showGreeting)
${greeting} #* Display the greeting *#
#end
The rule for comments is therefore slightly different in one respect: whitespace preceding a comment is always ignored (even if it doesn't start at the beginning of a line), and a newline following a comment is ignored. The above example will print the value of greeting, with no additional whitespace or newlines.

In other contexts where a newline makes the template more readable, but you don't want to include it in the output, you can precede it with a backslash; both the backslash and the newline will be ignored, e.g.:
#if (true)
yes\
#end
This will print yes with no newline.

3.2  Comments

#* comment *#
Comments can be nested.

3.3  Escaping Characters

When used literally (rather than to indicate an expansion or a statement), ${ and # must be escaped with a backslash:
\${
\#
Additional backslashes preceding an escape sequence are simply included in the output, as are backslashes not followed by ${ or #.

3.4  Expansions

${expression}
Adds the value of expression (which must evaluate to a scalar) to the output.

3.5  Statements

A statement begins with a # character followed by a keyword. When a statement has a body, it is terminated by #end. If you need #end to be followed by a letter, you can write #end#; similarly, you can write #else# instead of #else. This makes it possible to write a template without newlines, e.g.:
There #if (n == 1)is 1 file#else#are ${n} files#end#.

3.5.1  foreach

#foreach (name in expression)
template text
#end
Evaluates expression as a list; iterates over the list, assigning each element in turn to name. Any previous value of name is temporarily hidden.

3.5.2  if

#if (expression)
template text
#elseif (expression)
template text
#else
template text
#end
The #elseif and #else blocks are optional; any number of #elseif blocks may be used. You can write #else# instead of #else.

3.5.3  set

#set (name = expression)
Assigns the value of expression to the variable name in one of the following places, in order of preference:
  1. In macro scope, if invoked in macro scope and the variable already has a value there.
  2. In template scope.

3.5.4  var

#var (name)

#var (name = expression)
Assigns the value of expression (or a null value if expression is not supplied), to the variable name in one of the following places, in order of preference:
  1. In macro scope, if invoked in macro scope.
  2. In template scope.

3.5.5  include

#include (expression)
Interprets the string value of expression as the name of a template, and includes the contents of that template in the one currently being processed.

3.5.6  Macro Definition

#macro macroname (paramname1, paramname2, ... paramnamen)
template text
#end
Defines a macro called macroname that takes n parameters.

3.5.7  Macro Invocation

#macroname (param1, param2, ... paramn)
Invokes the macro called macroname. If a macro is called with fewer parameters than were defined in the macro, the remaining parameters are set to null.

3.5.8  open

#open (expression)
Interprets the string value of expression as the name of a template, and adds it to the list of templates in which macros will be searched for when invoked in the currently running template.

3.6  Expressions

3.6.1  Data Types

  • Scalar:
    String
    A string literal is enclosed in double quotes: "string"). A double quote in a string literal must be escaped by preceding it with a backslash. The escapes \t (tab), \r (carriage return) and \n (newline) can also be used; \\ produces a backslash.
    Integer
    An integer literal is a sequence of one or more digits, optionally preceded by a minus sign. For convenience and readability, underscore characters (_) are accepted (and ignored) within integer literals.
    Float
    A floating-point literal consists of an integer part, a decimal part and an exponent part. The integer part is a sequence of one or more digits, optionally preceded by a minus sign. The decimal part is a decimal point followed by zero, one or more digits. The exponent part is the character e or E followed by an optional + or - sign, followed by one or more digits. The decimal part or the exponent part can be omitted, but not both (to avoid ambiguity with integer literals). For convenience and readability, underscore characters (_) are accepted (and ignored) within floating-point literals.
    Boolean
    The boolean literals are true and false.
  • Hash. Keys are identifiers, values are any template data type.
  • List. Values are any template data type.
  • Null. A nonexistent value of any type is represented as null. The null literal is null.

3.6.2  Conversions

Scalar types are converted to other scalar types automatically. When an operator has one integer operand and one float operand, the integer is promoted to a float. Otherwise, the interpreter attempts to convert the right-hand side of an expression to the type of the left-hand side, and raises Template_error if this not possible.

Any value can be compared with a boolean or null value. All scalar values are equal to true except integer 0 and the empty string; a null value is equal to false. All list and hash values are equal to true except the empty list. The string and integer values of true are "true" and 1, respectively; the string and integer values of false are "" (the empty string) and 0.

3.6.3  Identifiers

The characters allowed in identifiers are upper-case and lower-case ASCII letters, digits, the underscore and the apostrophe. The first character of an identifier must be an ASCII letter.

3.6.4  Operators

Table 1 lists the operators supported in expressions. Standard operator precedence applies, and can be overridden using parentheses.

Operator Meaning Compatible Types
! unary not boolean values
- subtraction, unary negation integers, floats
+ addition, string concatenation integers, floats, strings
* multiplication integers, floats
/ division integers, floats
% modulo integers, floats
== equality scalars
!= inequality scalars
< less than integers, floats, strings
> greater than integers, floats, strings
<= less than or equal to integers, floats, strings
>= greater than or equal to integers, floats, strings
&& and boolean values
|| or boolean values
. hash lookup with identifier as key hash on left, identifier on right
[] hash lookup with string as key hash on left, string on right
() function call function on left, comma-separated expressions in parentheses
= assignment identifier on left, expression on right


Table 1: Operators



4  Programming with the CamlTemplate Library

When reading this section, you will probably find it helpful to refer to the CamlTemplate API documentation, which is generated by ocamldoc and provided in the doc/api directory of the CamlTemplate distribution.

4.1  The General Procedure

The general procedure is as follows:
  1. Create a template cache using Cache.create.
  2. Create a data model consisting of values of type Model.tvalue.
  3. Load a template using Cache.get_template.
  4. Pass the template to the merge function to generate output.
Here is `Hello, world!' with a template. The template is as follows:
Here is the message: ${message}
And here is a program that uses it:
open Printf ;;
open CamlTemplate.Model ;;

let _ =
  (* Make a template cache. *)
  let cache = CamlTemplate.Cache.create () in
    (* Create a model. *)
  let model = Hashtbl.create 4 in
    Hashtbl.add model "message"
      (Tstr "Hello, world!");    
    try
      (* Get the template. *)
      let tmpl =
        CamlTemplate.Cache.get_template
          cache "hello.tmpl"
          (* Make a buffer for the output. *)
      and buf = Buffer.create 256 in
        (* Generate output. *)
        CamlTemplate.merge tmpl model buf;
        print_string (Buffer.contents buf)
    with
        CamlTemplate.Syntax_error msg ->
          eprintf "\n%s\n" msg
      | CamlTemplate.Template_error msg ->
          eprintf "\n%s\n" msg ;;
There are other examples in the examples directory of the distribution.

4.2  Template Data Models

A template data model is a tree of values; these values can be scalars (strings, integers, floats or booleans), lists, hashtables or functions. The root of the tree must be a hashtable. In a template, an identifier by itself is the name of an entry in that root hashtable.

Tabular data can be represented as a list of hashes of scalars. Each element in the list represents a row in the table, and consists of a hash in which the names are column names and the values are cell values. Such a model can be handled as shown in Section 2.3.

4.3  Loading and Caching Templates

Once loaded and parsed, templates are cached; the Cache module provides functions for creating template caches, getting templates from them and configuring the behaviour of a cache (e.g. how often it is refreshed). By default, templates are loaded from files, but you can provide a class of type source_loader to load them from another source.

The #include and #open statements fetch the included or opened template from the cache when the enclosing template is merged. Therefore, if an #include or #open refers to a template that doesn't exist, this won't be detected until the outer template is merged.

Macros are stored in the templates in which they are defined. When a template containing a macro definition changes, the macro definition is updated as well.

4.4  Threads

CamlTemplate provides optional support for multithreaded programs. If you need thread support, in addition to linking your program with the camlTemplate library, you must also link in camlTemplate_mt.cmo (for bytecode programs) or camlTemplate_mt.cmx (for native-code programs). This ensures that the following are true:
  • Multiple threads can safely use the same template cache concurrently.

  • Multiple threads can safely pass the same template (or different templates) to the merge function.

  • Multiple templates running in different threads can safely use the same model, as long as no template function changes the model. (Note that none of the template statements, including #set and #var, can change the model.) Values set using #set and #var are visible only to the thread that set them.

4.5  Error Handling

The get_template function raises Syntax_error if it cannot parse a template. It may also raise other exceptions if it fails to read template source code because of an I/O error.

If a template cannot be merged because of a run-time error (e.g. a wrong data type), the merge function raises Template_error.

If a Caml function called from a template is unable to complete successfully, it can raise Tfun_error; this causes merge to raise Template_error.

5  Design

This section describes the implementation of CamlTemplate; you don't need to read it unless you are interested in developing CamlTemplate itself.

CamlTemplate is a fairly straightforward implementation of the Interpreter1 pattern. It uses ocamllex and ocamlyacc to parse template source code, generating an abstract syntax tree consisting of objects; these objects do the work of interpreting the template.

5.1  The Abstract Syntax Tree

There are two kinds of objects in the abstract syntax tree, represented by the class type statement and the virtual class expression. Statements produce output; expressions have values. A template consists essentially of a list of statements (each of which may contain one or more lists of statements, e.g. to represent the body of a loop, or the branches of a conditional); when merged, the template iterates over its statements, calling each statement's interpret method in turn.

5.2  The Parser and Lexer

The parser is very straightforward, and probably needs no explanation if you are familiar with ocamlyacc. The lexer, on the other hand, is rather complicated, mainly because of the absence of delimiters around literal text in a template language; this requires us to assume that we are reading literal text until we get to something that looks like template language syntax.

The CamlTemplate lexer therefore maintains some state to indicate which sort of environment is being tokenised. The variable cur_mode keeps track of whether the lexer is currently in literal text, an expansion or a statement. For the most part, instead of using specialised rules, the lexer uses a single rule containing all the patterns that are meaningful in tokens; once it has matched a pattern, it decides what to do depending on its current mode.

5.3  Scopes

Scopes in CamlTemplate are roughly patterned after those in JavaScript. There are two writable scopes, template scope and macro scope; the template model is an additional read-only scope. Assignment and lookup of values in scopes are encapsulated in the scope class in ctScope.ml.

5.4  Thread Support

Since parser and lexer both maintain some global state, and since template caches are modifiable, they are all protected by a global mutex (in ctCache.ml) when thread support is linked in.


1
Erich Gamma et al., Design Patterns: Elements of Resuable Object-Oriented Software, Addison Wesley Longman, 1997.

This document was translated from LATEX by HEVEA.
camltemplate-1.0.2/doc/html/manual/manual001.gif0100644000076400010400000000444111030642141025256 0ustar gdsАдминистраторыGIF89a>ЎUUUЄЄЄяяя!щ,>юњЏ©ЛнЈњґЪ‹іЮјC†вx扦кК¶( ЗҐKЧцЌз^ьБъ ‡_…DL*—Lr3jJ§Фк"jВZ·Ь®M{{ЗдІEдD›Чм¶Aќ№зфЄ8>«лSІѕя((7‡s·—€1ИШиИшdЁXy–gY8ѓ€‡™щЩЄIЩй)Љљ є*YЄµљ:‹ ›ЩєIИgK;Ы[‰[«fм+zњ(ЬJq(9 Џ^=сRt:У5@п`эvKзе.tЯѕд<тi\—ъ“ҐKў03Ј·щЭLx­·юЏю=аЯ:щЭ—ЮЂdм§ЦVэ§Уhяё†z] x &mqДџJnщ#!„‡5|eЎDO`”’`zЁџЃx%—бP\18гЉ,иўl0r…j`G•U=¶s#Ћ F3‚s»СcV|!1i_‘:N©]€›е(е!XтС?о}Ґg[‚Ч"ЮРaЌYDьёЈЬ—WЄ№Eљ—ђs'Vк`'ќ+фйћЖ(E~NБ ™‚ѕ FЎж±y(—‹>Є'љrт i¤°TљО ™©ЎљЪЎР5м(кsD8:к.ezуй¬>—j«5h­№къ&Ї¶N8л®ѕ¶мЇАЫюC±Н k¬tКоЪIіЕЉ)µПX+н/ПТ hўЩjЛ,·zы-ёRLк№е¦‚нkO¤«оємnЫf?тЉХnЃёЮ{Wѕ¤т‹ћїTР 0#nБМҐВГ|nВг(1Јwq _|lFs\зЖЕЂЊЇИИ‘МTЖLЊ2ВіЬІЖпsМѕ<іН+з<(П:'QіwAяьОDџ3ґ>>-\‹K3=зВOC]ЭФ”RнKТWc­­С\ПлхЧ :-v@VЯYцШЉќќц¦a·ЭНЫpЈ#хЬ–hЌ¶ЭХ°MЃКz‡,чЯsаќђа{Ю7в†·шв 7оёbђGююв±ыRсе;‚щА‚ Мyз џ::њў—О©М¤џ®єйћ»Оzли*±zм›П®п»¶g®;©ёп>SпОЖ ьaД-|сґїјЯКЛк|рЉ?O Я…MO=)ugъЪЇ~~швЏO~щжГ.жщкЇП~ыої/WИсsль–cЯ9уйGO§ЦУlїюХ И  Ехї?йпЂДвџЗ ИАe°~<`тђ¶Аз]ђ!ФA[–Ъђ3YАЗэ»¤…dЖyO ‚ВкMрv5“СTH(ўuё0;1‘H_з@ V0 8„  1’ЯThJL"LJR¶Ђp>?ЄOюµ‚ИБ R§9=ЩD»Ўщ'+$ +Јњcјв _4Д-6`AьyМs•ЗфE2 ўcЌК"±†Iђ%Tf.ФЉСР(Cq‘ѓOd mH+Ќ¤!йtЙ H)‘ЉюШ—ve‡v„ЏQRЙЙh)ЋѓФўTщ“УDR‘aјЈN>YGЌТ2ЎЏЉX@,)“ЏІ RJSЕ\О2‡©сЙ#sa“ИІBўvђВ(VЋЉIќД›gЦ’‰O¤%ЈИЋ0IїЙ¦0еКeмпЌТ€'q†чNcЩУ&@¤gMц№цX ьвжЇЄ0ѓF ЎSh+юуI2‡І€Ў6“hАґY6‹bЊўPУи?9К5Џ ўm)-Lє8”~BҐ‘cйб@ЪRJЌ¤§s©Уhj;›ћ0‚фgПpљ=ќТ0†vк@1КУ^щT©DЌ)R‘чФ¤&.ЄWўЄTэG1 ^5Y34кVЕХП¦ P¦”ТкW{є*ІћхZf…—XПкХМґu­Е°ЄRй:У`©Ї¦pзRщ*W,Ж°«ЊЮ` лЖп±ЖуЧbл.k=ІiҐДd)ЫьжWї­еo kз_P….АU0ЃЎз¦76u 0ѓм`ПBX†vќpћ*lб©b8Гox7Лб¤ЬЦј« ±€б ї«ША¬[±‹_<вVФГ2¶UЊіtc—)/ЗУ Ќ=згЩЖ?–Џe6dДE 8Й“}АK&™PJННЈCCЉЗm;f,[2Н­DЩњ ЪІV†uд‰Іi“PЌm\ЕЪ(“Љ:3ЉдL¦){З‡z, \КШъз,‹hmМs—wАзКЬђК,3…qIЈ/3оР!Ь (ЗLЈ1ЧYМф!hљ=d'63ъТ[Оґ™O=Iы–Тђ4 ­ЛЙЪ‡ѓжП/W]ј>Uy%Ћй$/AMd–±GІґPюМdзж:SмЃЌG¶У,mA•±a]E<JПuy)·'бmVЇ*ЬЛ^BІ%'nM}BлFЮ·эФоыД{ пЖd‘‡yo$§{ЎщVіђчЭ {=ЄЮ8[_uоЅR ‹ЕуЮОh\Чп©Е¦U8‚С; 3UгЃЭ0Х$^а«Ћ{ЯИь9ҐYњГ*61WГзтТц;жv+;camltemplate-1.0.2/doc/html/manual/manual001.html0100644000076400010400000002124411030642141025455 0ustar gdsАдминистраторы Introduction Up Next

1  Introduction

This manual describes how to use CamlTemplate, a template processor for Objective Caml programs. It can be used to generate web pages, scripts, SQL queries, XML documents and other sorts of text.

1.1  About This Manual

This manual is provided in HTML and PDF formats in the CamlTemplate distribution.

1.2  Licence

CamlTemplate is free software, released under the GNU General Public License. This manual is released under the same licence.

In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.

1.3  Features

  • A versatile, easy-to-learn template syntax that supports common scripting-language constructs, while encouraging a separation between presentation logic and application logic.
  • The supported Caml data structures accomodate lists, tables and trees of items in a straightforward manner.
  • Works well with mod_caml and mod_fastcgi.
  • Supports any ASCII-compatible encoding, including UTF-8.
  • Optional support for multithreading.
CamlTemplate works by merging data with handwritten templates. This process is illustrated in Figure 1.

The template contains only the handwritten material; some other program provides the data. The template's author doesn't need to be involved in writing that program; he or she only needs to know what data the program provides, and can therefore change the template without involving the program's developers. Likewise, the program can be modified so that it obtains data in a different way, without affecting the template. Different templates can be used to display the same data in different ways (e.g. to generate normal and `printer-friendly' versions of a web page).




Figure 1: Generating a document



1.4  Getting CamlTemplate

The CamlTemplate source code and documentation can be downloaded from the CamlTemplate web site.

1.5  Installing CamlTemplate

1.5.1  Installing with GODI

If you use GODI, you can install CamlTemplate from godi_console. Otherwise, you can install manually as described below.

1.5.2  Installing Manually

Requirements: Unpack the archive:
tar zxf camltemplate-x.y.z.tar.gz
cd camltemplate-x.y.z
To see the configuration options, type:
./configure --help
Type the following, adding any options you need:
./configure
Then type:
make
make opt
make test
If there are no errors, type make install as root. This installs bytecode and native-code versions of the library using ocamlfind. Documentation in HTML and PDF formats is installed in $PREFIX/doc/camltemplate. Several sample programs can be found in $PREFIX/share/camltemplate.

To uninstall the library, type make uninstall as root.

1.5.3  Integration with mod_caml

Mod_caml is an Apache module that dynamically loads OCaml bytecode to handle HTTP requests.

CamlTemplate has been tested with mod_caml 1.3.6 and Apache 1.3. (We haven't tested it with Apache 2.0, because a bug in Apache 2.0 has prevented mod_caml from working at all; this looks as if it will be fixed in Apache 2.2. If you need to use Apache 2.0, try the instructions on the mod_caml web site, and let us know if it works.)

1. Install mod_caml, and make sure it works on its own before proceeding (try the hello.ml example that comes with it).

2. In your httpd.conf, after the configuration you added for mod_caml, add the following line:
CamlLoad /path/to/camltemplate/camltemplate.cma
(If you don't know where it is, type ocamlfind query camltemplate at a shell prompt.)

3. Restart Apache.

4. Try compiling and installing the example in examples/mod_caml (see the README there).

1.5.4  Integration with mod_fastcgi

Mod_fastcgi is an Apache module that allows the web server to hand off HTTP requests to a pool of long-running programs; these can be OCaml programs compiled to bytecode or native code.

This has been tested using Christophe Troestler's OCaml-CGI package and mod_fastcgi 2.4.2, and works with Apache versions 1.3 and 2.0. For an example, see examples/fastcgi. You'll need to use CamlTemplate's optional thread support (see Section 4.4 for instructions).

1.6  Mailing List and Support

The camltemplate mailing list is used for questions, suggestions, bug reports and discussion about CamlTemplate.

There is also a Frequently Asked Questions page.

1.7  Author

CamlTemplate is developed and maintained by Benjamin Geer (benjamin DOT geer AT gmail DOT com).

1.8  History

In 1999, Benjamin Geer wrote a template processor in Java, called FreeMarker, based on the experience of using a similar tool with graphic designers in a web development shop. CamlTemplate borrows some aspects of FreeMarker (small library not tied to web development, JavaScript-like expressions, Perl-like data structures), as well as some ideas from the Apache Jakarta project's Velocity template processor (generated parser, more concise syntax), released in 2001. The first version of CamlTemplate was released in October 2003.


Up Next camltemplate-1.0.2/doc/html/manual/manual002.html0100644000076400010400000003331011030642141025453 0ustar gdsАдминистраторы Writing Templates Previous Up Next

2  Writing Templates

2.1  Inserting Values

Here is a simple example of a template for generating an HTML page:
<html>
<head>
  <title>${title}</title>
</head>

<body>
<h1>${title}</h1>

Today's date: ${date}
</body>
</html>
This template expects two pieces of data: a title and a date. A dollar sign followed by an expression in braces is called an expansion; it means, `insert the value of this expression here'. If the value of title was Important Page, and the value of date was 29 September 2003, the resulting document would look like this:
<html>
<head>
  <title>Important Page</title>
</head>

<body>
<h1>Important Page</h1>

Today's date: 29 September 2003
</body>
</html>
A variable such as title or date is called a scalar variable, meaning that it contains only one value.

If an expansion contains a value that has not been set, it produces no output. This makes it convenient to write HTML form elements that display the value previously entered, if any:
<input type="text" name="address" value="${address}"/>

2.2  Hashes

It is often convenient to group several related values together, and give a name to the group. A hash is a collection of values, each of which has a name (called a `key'). Continuing with the example from the previous section, we might want to break down the date into day, month and year components:
Today's date: ${date.day}-${date.month}-${date.year}
Here, date is a hash, which contains three scalars: day, month and year. (An expression like date.day is called a hash lookup.) The result might be:
Today's date: 29-09-2003
Hashes can contain hashes, e.g.:
Date of birth:
  ${user.dob.day}-${user.dob.month}-${user.dob.year}
The string value of any variable (or other expression) can be used as a hash key by enclosing the expression in square brackets:
Error in field "${fieldName}": ${errors[fieldName]}
If the value of fieldName was always "title", the above would be the same as writing:
Error in field "title": ${errors.title}

2.3  Lists

Generated documents often contain lists of data. In a template, the #foreach statement processes all the elements in a list. Here's a simple example:
<p>Signatories:</p>

<ul>
  #foreach (signatory in signatories)
  <li>${signatory}</li>
  #end
</ul>
The output might look like this:
<p>Signatories:</p>

<ul>
  <li>Arthur Artichoke</li>
  <li>Bernard Banana</li>
  <li>Carol Carrot</li>
  <li>Dorothy Date</li>
</ul>
For each element in the list, the #foreach statement stores the element's value temporarily in the name given before the in, then processes the template text between the #foreach and the #end.

Here's an example that generates an HTML table:
<table>
<thead>
  <tr>
    <th>Name</th>
    <th>Date of Birth</th>
    <th>Favourite Colour</th>
  </tr>
</thead>
<tbody>
  #foreach (person in garden.people)
  <tr>
    <td>${person.name}</td>
    <td>${person.bdate}</td>
    <td>${person.colour}</td>
  </tr>
  #end
</tbody>
</table>
Here garden is a hash that contains a list called people. Each element of people is a hash containing three scalars (name, bdate and colour).

2.4  Conditionals

A template can contain optional text, which is used only if some condition is met. The #if statement tests a condition. For example:
#if (approved)
  This document has been approved for publication.
#else
  This document is awaiting approval.
#end
We have seen scalars that contain strings (i.e. text); true and false are also possible values of a scalar (e.g. approved above). Any scalar is equal to true if it has a value other than 0 or the empty string. A list is equal to true if it exists and isn't empty. A hash is equal to true if it exists. This makes it convenient to check, for example, whether a list contains any values before processing its contents:
#if (searchResults)
  #foreach (result in searchResults)
    ...
  #end
#end
If a scalar contains a string or a number, an expression can test the scalar's value, using comparison operators such as == (equals), != (is unequal to), < (is less than) and > (is greater than). You can also use #elseif blocks to test several conditions. For example:
#if (hour > 17)
  Good evening!
#elseif (hour > 12)
  Good afternoon!
#else
  Good morning!
#end

#if (status == "approved")
  This document has been approved for publication.
#else
  This document is awaiting approval.
#end
See Section 3.6 for the full details of expressions.

2.5  Setting values

The #set statement assigns a value to a name. The value is not set in the data model that the program has provided; a template cannot use #set to change its data model. The value remains internal to the template, and only while the template is being merged; it is then forgotten. Returning to the earlier example of an HTML table, suppose we wanted the background colour of the rows to alternate between yellow and white. We could write:
<tbody>
  #set (background = "white")

  #foreach (person in garden.people)
    <tr bgcolor="${background}">
      <td>${person.name}</td>
      <td>${person.bdate}</td>
      <td>${person.colour}</td>
    </tr>

    #if (background == "white")
      #set (background = "yellow")
    #else
      #set (background = "white")
    #end
  #end
</tbody>

2.6  Including Templates in Templates

Rather than copy and paste the same text into several templates, you can put the common text in a separate template, and include that template in other templates using the #include statement. For example, you might include a standard header and footer on each page:
#include ("header.tmpl")

...

#include ("footer.tmpl")
Included templates will not see any values that have been set in the including template, nor can the including template see any values that the included template sets. If you want to pass values into a reusable section of template code, use a macro, as described in the next section.

2.7  Macros

To create a reusable bit of template code that uses values you provide, you can write a macro. The #macro statement defines a macro, which can then be used as a statement in its own right. For example, here is a macro that formats a date in a particular way, given the year, month and day as numbers:
#macro formatDate(year, month, day)
  #var (monthPrefix)
  #var (dayPrefix)

  #if (month < 10)
    #set (monthPrefix = "0")
  #end

  #if (day < 10)
    #set (dayPrefix = "0")
  #end

  ${year}-${monthPrefix}${month}-${dayPrefix}${day}
#end
(The #var statement will be explained in a moment.)

Here is some template code that expects a hash called date like the one we saw in Section 2.2, and uses it to call the formatDate macro above:
Today's date:
  #formatDate(date.year, date.month, date.day)
A macro may be called with fewer arguments than it was defined with; the remaining arguments are set to null. It is an error to call a macro with too many arguments.

2.7.1  Defining Variables in Macros

The #var statement in the macro above initialises a variable for use within the macro, setting it to a null value. We could have written:
#set (monthPrefix = "")
But if there was already a variable called monthPrefix outside the macro, #set would change the value of the existing variable. (Sometimes this might be what you want.) By contrast, a variable initialised inside a macro with #var only exists within that macro, and doesn't affect any other variable that might have the same name outside the macro; its value is forgotten once the macro has completed. Once you have used #var to initialise a variable in a macro, you can use #set to change its value, as in the example above. To initialise a variable with a value other than null, you can write:
#var (colour = "blue")
When used outside of a macro, #var has the same effect as #set.

2.7.2  Storing Macros in Separate Templates

If there are some macros that you want to use in more than one template, you can define them in a separate template, which we'll call a macro template. In each template where you want to use those macros, you then need to tell CamlTemplate where to look for them, using the #open statement. For example, if you've written a macro template called macros.tmpl, and you want to use them in a template called test.tmpl, you would put the following line in test.tmpl, before using any of the macros:
#open ("macros.tmpl")
You can put several #open statements in a template. When you call a macro, CamlTemplate looks for it first in the template that's being merged, and then in any macro templates that have been opened in that template.

2.8  Functions

A function can be supplied to a template as part of its data. Since functions are written in Objective Caml, they can do things that would be cumbersome or impossible to do in macros. A function takes one or more expressions as arguments, and returns a value, which can be used in an expansion or in a statement.

For example, CamlTemplate provides a function called escHtml, for escaping special characters in HTML documents. It can be used like this:
Company name: ${escHtml(companyName)}
If the value of companyName was Artichoke & Banana, the output would be:
Company name: Artichoke &amp; Banana
In addition to escHtml, CamlTemplate provides the following functions, which application developers can choose to make available to templates:
urlEncode
URL-encodes a string.
escHtmlAttr
Escapes special characters in text to be included in an HTML attribute.
escHtmlTextarea
Escapes special characters in text to be included in an HTML textarea.
asList
Converts any value to a list, if it isn't already a list. If the argument is a list, returns the argument. If the argument is null, returns an empty list. Otherwise, returns a single-element list containing the argument. This is useful for dealing with form input fields that can have multiple values.
Each of these functions expects one argument.

2.9  Comments

You can write a comment in a template by surrounding it with #* and *#:
#* This is a comment. *#
Comments do not appear in the output when a template is merged. Comments can contain comments.


Previous Up Next camltemplate-1.0.2/doc/html/manual/manual003.html0100644000076400010400000003544111030642141025463 0ustar gdsАдминистраторы Template Syntax Reference Previous Up Next

3  Template Syntax Reference

3.1  Whitespace

It often makes templates more readable to include extra whitespace around statements. In particular, the CamlTemplate syntax encourages a style in which each statement is on a line by itself, possibly indented. This means that there is extra whitespace around the statement: the indentation preceding it, and the newline after it. However, it is often not desirable to include that extra whitespace in the output. To support this, CamlTemplate ignores whitespace in certain contexts. The basic rules are as follows:
  • When a line begins with whitepace followed by #, that whitespace is ignored.

  • When a newline follows the closing parenthesis of a statement, or a keyword such as #else, the newline is ignored.
Thus a statement or keyword on a line by itself 'disappears' from the output (except for any output produced by the statement itself). Consider the following template:
#macro sayHello()
Hello.
#end
#if (true)
  #sayHello()
#end
This will print a single line of text, consisting of Hello. followed by a newline.

Another example:
#macro sayHello()
Hello.
#end
#if (true)
The greeting is: #sayHello()
#end
This will print:
The greeting is: Hello.
Note that since the call to #sayHello() does not fall at the beginning of a line, the space after the colon is preserved.

It is often convenient to put a comment at the end of a line, like this:
#if (showGreeting)
${greeting} #* Display the greeting *#
#end
The rule for comments is therefore slightly different in one respect: whitespace preceding a comment is always ignored (even if it doesn't start at the beginning of a line), and a newline following a comment is ignored. The above example will print the value of greeting, with no additional whitespace or newlines.

In other contexts where a newline makes the template more readable, but you don't want to include it in the output, you can precede it with a backslash; both the backslash and the newline will be ignored, e.g.:
#if (true)
yes\
#end
This will print yes with no newline.

3.2  Comments

#* comment *#
Comments can be nested.

3.3  Escaping Characters

When used literally (rather than to indicate an expansion or a statement), ${ and # must be escaped with a backslash:
\${
\#
Additional backslashes preceding an escape sequence are simply included in the output, as are backslashes not followed by ${ or #.

3.4  Expansions

${expression}
Adds the value of expression (which must evaluate to a scalar) to the output.

3.5  Statements

A statement begins with a # character followed by a keyword. When a statement has a body, it is terminated by #end. If you need #end to be followed by a letter, you can write #end#; similarly, you can write #else# instead of #else. This makes it possible to write a template without newlines, e.g.:
There #if (n == 1)is 1 file#else#are ${n} files#end#.

3.5.1  foreach

#foreach (name in expression)
template text
#end
Evaluates expression as a list; iterates over the list, assigning each element in turn to name. Any previous value of name is temporarily hidden.

3.5.2  if

#if (expression)
template text
#elseif (expression)
template text
#else
template text
#end
The #elseif and #else blocks are optional; any number of #elseif blocks may be used. You can write #else# instead of #else.

3.5.3  set

#set (name = expression)
Assigns the value of expression to the variable name in one of the following places, in order of preference:
  1. In macro scope, if invoked in macro scope and the variable already has a value there.
  2. In template scope.

3.5.4  var

#var (name)

#var (name = expression)
Assigns the value of expression (or a null value if expression is not supplied), to the variable name in one of the following places, in order of preference:
  1. In macro scope, if invoked in macro scope.
  2. In template scope.

3.5.5  include

#include (expression)
Interprets the string value of expression as the name of a template, and includes the contents of that template in the one currently being processed.

3.5.6  Macro Definition

#macro macroname (paramname1, paramname2, ... paramnamen)
template text
#end
Defines a macro called macroname that takes n parameters.

3.5.7  Macro Invocation

#macroname (param1, param2, ... paramn)
Invokes the macro called macroname. If a macro is called with fewer parameters than were defined in the macro, the remaining parameters are set to null.

3.5.8  open

#open (expression)
Interprets the string value of expression as the name of a template, and adds it to the list of templates in which macros will be searched for when invoked in the currently running template.

3.6  Expressions

3.6.1  Data Types

  • Scalar:
    String
    A string literal is enclosed in double quotes: "string"). A double quote in a string literal must be escaped by preceding it with a backslash. The escapes \t (tab), \r (carriage return) and \n (newline) can also be used; \\ produces a backslash.
    Integer
    An integer literal is a sequence of one or more digits, optionally preceded by a minus sign. For convenience and readability, underscore characters (_) are accepted (and ignored) within integer literals.
    Float
    A floating-point literal consists of an integer part, a decimal part and an exponent part. The integer part is a sequence of one or more digits, optionally preceded by a minus sign. The decimal part is a decimal point followed by zero, one or more digits. The exponent part is the character e or E followed by an optional + or - sign, followed by one or more digits. The decimal part or the exponent part can be omitted, but not both (to avoid ambiguity with integer literals). For convenience and readability, underscore characters (_) are accepted (and ignored) within floating-point literals.
    Boolean
    The boolean literals are true and false.
  • Hash. Keys are identifiers, values are any template data type.
  • List. Values are any template data type.
  • Null. A nonexistent value of any type is represented as null. The null literal is null.

3.6.2  Conversions

Scalar types are converted to other scalar types automatically. When an operator has one integer operand and one float operand, the integer is promoted to a float. Otherwise, the interpreter attempts to convert the right-hand side of an expression to the type of the left-hand side, and raises Template_error if this not possible.

Any value can be compared with a boolean or null value. All scalar values are equal to true except integer 0 and the empty string; a null value is equal to false. All list and hash values are equal to true except the empty list. The string and integer values of true are "true" and 1, respectively; the string and integer values of false are "" (the empty string) and 0.

3.6.3  Identifiers

The characters allowed in identifiers are upper-case and lower-case ASCII letters, digits, the underscore and the apostrophe. The first character of an identifier must be an ASCII letter.

3.6.4  Operators

Table 1 lists the operators supported in expressions. Standard operator precedence applies, and can be overridden using parentheses.

Operator Meaning Compatible Types
! unary not boolean values
- subtraction, unary negation integers, floats
+ addition, string concatenation integers, floats, strings
* multiplication integers, floats
/ division integers, floats
% modulo integers, floats
== equality scalars
!= inequality scalars
< less than integers, floats, strings
> greater than integers, floats, strings
<= less than or equal to integers, floats, strings
>= greater than or equal to integers, floats, strings
&& and boolean values
|| or boolean values
. hash lookup with identifier as key hash on left, identifier on right
[] hash lookup with string as key hash on left, string on right
() function call function on left, comma-separated expressions in parentheses
= assignment identifier on left, expression on right


Table 1: Operators




Previous Up Next camltemplate-1.0.2/doc/html/manual/manual004.html0100644000076400010400000001402111030642141025453 0ustar gdsАдминистраторы Programming with the CamlTemplate Library Previous Up Next

4  Programming with the CamlTemplate Library

When reading this section, you will probably find it helpful to refer to the CamlTemplate API documentation, which is generated by ocamldoc and provided in the doc/api directory of the CamlTemplate distribution.

4.1  The General Procedure

The general procedure is as follows:
  1. Create a template cache using Cache.create.
  2. Create a data model consisting of values of type Model.tvalue.
  3. Load a template using Cache.get_template.
  4. Pass the template to the merge function to generate output.
Here is `Hello, world!' with a template. The template is as follows:
Here is the message: ${message}
And here is a program that uses it:
open Printf ;;
open CamlTemplate.Model ;;

let _ =
  (* Make a template cache. *)
  let cache = CamlTemplate.Cache.create () in
    (* Create a model. *)
  let model = Hashtbl.create 4 in
    Hashtbl.add model "message"
      (Tstr "Hello, world!");    
    try
      (* Get the template. *)
      let tmpl =
        CamlTemplate.Cache.get_template
          cache "hello.tmpl"
          (* Make a buffer for the output. *)
      and buf = Buffer.create 256 in
        (* Generate output. *)
        CamlTemplate.merge tmpl model buf;
        print_string (Buffer.contents buf)
    with
        CamlTemplate.Syntax_error msg ->
          eprintf "\n%s\n" msg
      | CamlTemplate.Template_error msg ->
          eprintf "\n%s\n" msg ;;
There are other examples in the examples directory of the distribution.

4.2  Template Data Models

A template data model is a tree of values; these values can be scalars (strings, integers, floats or booleans), lists, hashtables or functions. The root of the tree must be a hashtable. In a template, an identifier by itself is the name of an entry in that root hashtable.

Tabular data can be represented as a list of hashes of scalars. Each element in the list represents a row in the table, and consists of a hash in which the names are column names and the values are cell values. Such a model can be handled as shown in Section 2.3.

4.3  Loading and Caching Templates

Once loaded and parsed, templates are cached; the Cache module provides functions for creating template caches, getting templates from them and configuring the behaviour of a cache (e.g. how often it is refreshed). By default, templates are loaded from files, but you can provide a class of type source_loader to load them from another source.

The #include and #open statements fetch the included or opened template from the cache when the enclosing template is merged. Therefore, if an #include or #open refers to a template that doesn't exist, this won't be detected until the outer template is merged.

Macros are stored in the templates in which they are defined. When a template containing a macro definition changes, the macro definition is updated as well.

4.4  Threads

CamlTemplate provides optional support for multithreaded programs. If you need thread support, in addition to linking your program with the camlTemplate library, you must also link in camlTemplate_mt.cmo (for bytecode programs) or camlTemplate_mt.cmx (for native-code programs). This ensures that the following are true:
  • Multiple threads can safely use the same template cache concurrently.

  • Multiple threads can safely pass the same template (or different templates) to the merge function.

  • Multiple templates running in different threads can safely use the same model, as long as no template function changes the model. (Note that none of the template statements, including #set and #var, can change the model.) Values set using #set and #var are visible only to the thread that set them.

4.5  Error Handling

The get_template function raises Syntax_error if it cannot parse a template. It may also raise other exceptions if it fails to read template source code because of an I/O error.

If a template cannot be merged because of a run-time error (e.g. a wrong data type), the merge function raises Template_error.

If a Caml function called from a template is unable to complete successfully, it can raise Tfun_error; this causes merge to raise Template_error.


Previous Up Next camltemplate-1.0.2/doc/html/manual/manual005.html0100644000076400010400000000670711030642141025470 0ustar gdsАдминистраторы Design Previous Up

5  Design

This section describes the implementation of CamlTemplate; you don't need to read it unless you are interested in developing CamlTemplate itself.

CamlTemplate is a fairly straightforward implementation of the Interpreter1 pattern. It uses ocamllex and ocamlyacc to parse template source code, generating an abstract syntax tree consisting of objects; these objects do the work of interpreting the template.

5.1  The Abstract Syntax Tree

There are two kinds of objects in the abstract syntax tree, represented by the class type statement and the virtual class expression. Statements produce output; expressions have values. A template consists essentially of a list of statements (each of which may contain one or more lists of statements, e.g. to represent the body of a loop, or the branches of a conditional); when merged, the template iterates over its statements, calling each statement's interpret method in turn.

5.2  The Parser and Lexer

The parser is very straightforward, and probably needs no explanation if you are familiar with ocamlyacc. The lexer, on the other hand, is rather complicated, mainly because of the absence of delimiters around literal text in a template language; this requires us to assume that we are reading literal text until we get to something that looks like template language syntax.

The CamlTemplate lexer therefore maintains some state to indicate which sort of environment is being tokenised. The variable cur_mode keeps track of whether the lexer is currently in literal text, an expansion or a statement. For the most part, instead of using specialised rules, the lexer uses a single rule containing all the patterns that are meaningful in tokens; once it has matched a pattern, it decides what to do depending on its current mode.

5.3  Scopes

Scopes in CamlTemplate are roughly patterned after those in JavaScript. There are two writable scopes, template scope and macro scope; the template model is an additional read-only scope. Assignment and lookup of values in scopes are encapsulated in the scope class in ctScope.ml.

5.4  Thread Support

Since parser and lexer both maintain some global state, and since template caches are modifiable, they are all protected by a global mutex (in ctCache.ml) when thread support is linked in.


Previous Up camltemplate-1.0.2/doc/html/manual/manual006.html0100644000076400010400000000120211030642141025452 0ustar gdsАдминистраторы Notes
1
Erich Gamma et al., Design Patterns: Elements of Resuable Object-Oriented Software, Addison Wesley Longman, 1997.
camltemplate-1.0.2/doc/html/manual/next_motif.gif0100644000076400010400000000047511030642141025737 0ustar gdsАдминистраторыGIF89aсpЂђяяpЂђ!ю# Imported from XPM image: next.xpm!щ,@зЬ63333ЖB! Г0 A0 Г0 Г0  0 ѓБ`0 ѓБ`0 ѓA Ѓ@ ѓБ`0 ѓБ`00000000000000000000000000000000000000000000  000000 0000000000000000000000000000`АЂ ;camltemplate-1.0.2/doc/html/manual/previous_motif.gif0100644000076400010400000000047511030642141026635 0ustar gdsАдминистраторыGIF89aсpЂђяяpЂђ!ю# Imported from XPM image: prev.xpm!щ,@зЬ63333Ж# „B Г0 AА0 Г0 Г0 А0 ѓБ`0 ѓБ`0 ѓA  ѓ ЂБ`0 ѓ`00000000000000000000000000000000000000000000  000 0000000000000000000000000000000`АЂ ;camltemplate-1.0.2/doc/Makefile0100644000076400010400000000244310264064613022322 0ustar gdsАдминистраторыTOP_DIR=.. -include $(TOP_DIR)/Makefile.config include $(TOP_DIR)/Makefile.rules DOC_MLI := ../src/camlTemplate.mli INSTALL_DIR := $(PREFIX)/doc/$(PKGBASE) .PHONY: htdoc htdoc: html/api/index.html html/manual/index.html html/api/index.html: $(TOP_DIR)/src/camlTemplate.mli mkdir -p html rm -rf html/api mkdir -p html/api ocamldoc -I ../src -html -d html/api -t "CamlTemplate API Documentation" $(DOC_MLI) html/manual/index.html: manual/manual.tex mkdir -p html rm -rf html/manual mkdir -p html/manual cd manual; \ hevea -fix -O -o manual.html manual.tex; \ hacha manual.html; \ cp *.html *.css *.gif ../html/manual .PHONY: pdfdoc pdfdoc: pdf/manual.pdf pdf/manual.pdf: manual/manual.tex set -e; rm -rf pdf; mkdir pdf; \ cd manual; \ latex manual.tex; \ latex manual.tex; \ dvips -o manual.ps manual.dvi; \ ps2pdf manual.ps ../pdf/manual.pdf .PHONY: install install: rm -rf $(INSTALL_DIR) mkdir -p $(INSTALL_DIR) mkdir -p html pdf cp -r html pdf $(INSTALL_DIR) .PHONY: uninstall uninstall: rm -rf $(INSTALL_DIR) .PHONY: clean clean: rm -rf html pdf *~ cd manual; rm -f *~ *.html *.css *.gif *.log *.out *.aux *.dvi *.ps \ *.htoc *.image.tex *.haux *.pdf .log .PHONY: distclean distclean: cd manual; rm -f *.html *.css *.gif *.htoc *.image.tex *.haux *.aux \ *.log *.dvi *.ps camltemplate-1.0.2/doc/manual/0040755000076400010400000000000011030647116022134 5ustar gdsАдминистраторыcamltemplate-1.0.2/doc/manual/manual.tex0100644000076400010400000011216611030375316024137 0ustar gdsАдминистраторы% CamlTemplate: A template processor for Objective Caml programs. % Copyright © 2003, 2004, 2005 Benjamin Geer % % 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 % USA % % In addition, as a special exception, Benjamin Geer gives permission % to link the code of this program with the Apache HTTP Server (or % with modified versions of Apache that use the same license as % Apache), and distribute linked combinations including the two. You % must obey the GNU General Public License in all respects for all of % the code used other than Apache. If you modify this file, you may % extend this exception to your version of the file, but you are not % obligated to do so. If you do not wish to do so, delete this % exception statement from your version. % $Id: manual.tex,v 1.86 2008-06-25 07:59:10 gds Exp $ \documentclass[12pt,a4paper]{article} \usepackage{times} \usepackage{t1enc} \usepackage[british]{babel} \usepackage[latin1]{inputenc} \usepackage{hevea} \usepackage{url} \usepackage{graphics} \usepackage{epsf} \title{The CamlTemplate Manual \\ Version 1.0.1} \author{Benjamin Geer} \date{7 July 2005} \urldef{\camltemplatepage}{\url}{http://saucecode.org/camltemplate} \urldef{\camltemplatelistpage}{\url}{http://lists.saucecode.org/wws/info/camltemplate} \urldef{\camltemplatefaqpage}{\url}{http://saucecode.org/camltemplate/faq.html} \urldef{\ocamlpage}{\url}{http://caml.inria.fr} \urldef{\modcamlpage}{\url}{http://merjis.com/developers/mod_caml/} \urldef{\fastcgipage}{\url}{http://www.fastcgi.com/} \urldef{\ocamlcgipage}{\url}{http://sourceforge.net/projects/ocaml-cgi/} \urldef{\freeswpage}{\url}{http://www.gnu.org/philosophy/free-sw.html} \urldef{\gplpage}{\url}{http://www.gnu.org/copyleft/gpl.html} \urldef{\freemarkerpage}{\url}{http://www.freemarker.org} \urldef{\velocitypage}{\url}{http://jakarta.apache.org/velocity/} \urldef{\findlibpage}{\url}{http://www.ocaml-programming.de/packages/} \urldef{\apachebugpage}{\url}{http://issues.apache.org/bugzilla/show_bug.cgi?id=27550} \urldef{\godipage}{\url}{http://www.ocaml-programming.de/godi/} \hyphenation{Caml-Template} \begin{document} \selectlanguage{british} \maketitle \section{Introduction} This manual describes how to use CamlTemplate, a template processor for \footahref{\ocamlpage}{Objective Caml} programs. It can be used to generate web pages, scripts, SQL queries, XML documents and other sorts of text. \subsection{About This Manual} This manual is provided in HTML and PDF formats in the CamlTemplate distribution. \subsection{Licence} CamlTemplate is \footahref{\freeswpage}{free software}, released under the \footahref{\gplpage}{GNU General Public License}. This manual is released under the same licence. In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. \subsection{Features} \begin{itemize} \item A versatile, easy-to-learn template syntax that supports common scripting-language constructs, while encouraging a separation between presentation logic and application logic. \item The supported Caml data structures accomodate lists, tables and trees of items in a straightforward manner. \item Works well with \footahref{\modcamlpage}{mod\_caml} and \footahref{\fastcgipage}{mod\_fastcgi}. \item Supports any ASCII-compatible encoding, including UTF-8. \item Optional support for multithreading. \end{itemize} CamlTemplate works by merging data with handwritten templates. This process is illustrated in Figure~\ref{fig-merge}. The template contains only the handwritten material; some other program provides the data. The template's author doesn't need to be involved in writing that program; he or she only needs to know what data the program provides, and can therefore change the template without involving the program's developers. Likewise, the program can be modified so that it obtains data in a different way, without affecting the template. Different templates can be used to display the same data in different ways (e.g. to generate normal and `printer-friendly' versions of a web page). \begin{figure} \centering \scalebox{.5}{\epsfbox{merge.eps}} \vspace{1em} \caption{Generating a document\label{fig-merge}} \end{figure} \subsection{Getting CamlTemplate} The CamlTemplate source code and documentation can be downloaded from the \footahref{\camltemplatepage}{CamlTemplate web site}. \subsection{Installing CamlTemplate} \subsubsection{Installing with GODI} If you use \footahref{\godipage}{GODI}, you can install CamlTemplate from {\tt godi\_console}. Otherwise, you can install manually as described below. \subsubsection{Installing Manually} \label{sec-manual-installation} Requirements: \begin{itemize} \item Objective Caml 3.08.3 or above. \item \footahref{\findlibpage}{findlib}. \item GNU make. \end{itemize} Unpack the archive: \begin{verbatim} tar zxf camltemplate-x.y.z.tar.gz cd camltemplate-x.y.z \end{verbatim} To see the configuration options, type: \begin{verbatim} ./configure --help \end{verbatim} Type the following, adding any options you need: \begin{verbatim} ./configure \end{verbatim} Then type: \begin{verbatim} make make opt make test \end{verbatim} If there are no errors, type {\tt make install} as root. This installs bytecode and native-code versions of the library using {\tt ocamlfind}. Documentation in HTML and PDF formats is installed in {\tt \$PREFIX/doc/camltemplate}. Several sample programs can be found in {\tt \$PREFIX/share/camltemplate}. To uninstall the library, type {\tt make uninstall} as root. \subsubsection{Integration with mod\_caml} Mod\_caml is an Apache module that dynamically loads OCaml bytecode to handle HTTP requests. CamlTemplate has been tested with mod\_caml 1.3.6 and Apache 1.3. (We haven't tested it with Apache 2.0, because a \footahref{\apachebugpage}{bug} in Apache 2.0 has prevented mod\_caml from working at all; this looks as if it will be fixed in Apache 2.2. If you need to use Apache 2.0, try the instructions on the mod\_caml web site, and let us know if it works.) 1. Install mod\_caml, and make sure it works on its own before proceeding (try the {\tt hello.ml} example that comes with it). 2. In your {\tt httpd.conf}, after the configuration you added for mod\_caml, add the following line: \begin{verbatim} CamlLoad /path/to/camltemplate/camltemplate.cma \end{verbatim} (If you don't know where it is, type {\tt ocamlfind query camltemplate} at a shell prompt.) 3. Restart Apache. 4. Try compiling and installing the example in {\tt examples/mod\_caml} (see the {\tt README} there). \subsubsection{Integration with mod\_fastcgi} Mod\_fastcgi is an Apache module that allows the web server to hand off HTTP requests to a pool of long-running programs; these can be OCaml programs compiled to bytecode or native code. This has been tested using Christophe Troestler's \footahref{\ocamlcgipage}{OCaml-CGI} package and mod\_fastcgi 2.4.2, and works with Apache versions 1.3 and 2.0. For an example, see {\tt examples/fastcgi}. You'll need to use CamlTemplate's optional thread support (see Section~\ref{sec-manual-threads} for instructions). \subsection{Mailing List and Support} The \footahref{\camltemplatelistpage}{camltemplate} mailing list is used for questions, suggestions, bug reports and discussion about CamlTemplate. There is also a \footahref{\camltemplatefaqpage}{Frequently Asked Questions} page. \subsection{Author} CamlTemplate is developed and maintained by Benjamin Geer ({\tt benjamin DOT geer AT gmail DOT com}). \subsection{History} In 1999, Benjamin Geer wrote a template processor in Java, called \footahref{\freemarkerpage}{FreeMarker}, based on the experience of using a similar tool with graphic designers in a web development shop. CamlTemplate borrows some aspects of FreeMarker (small library not tied to web development, JavaScript-like expressions, Perl-like data structures), as well as some ideas from the Apache Jakarta project's \footahref{\velocitypage}{Velocity} template processor (generated parser, more concise syntax), released in 2001. The first version of CamlTemplate was released in October 2003. \section{Writing Templates} \subsection{Inserting Values} Here is a simple example of a template for generating an HTML page: \begin{verbatim} ${title}

${title}

Today's date: ${date} \end{verbatim} This template expects two pieces of data: a title and a date. A dollar sign followed by an expression in braces is called an {\em expansion}; it means, `insert the value of this expression here'. If the value of {\tt title} was {\tt Important Page}, and the value of {\tt date} was {\tt 29 September 2003}, the resulting document would look like this: \begin{verbatim} Important Page

Important Page

Today's date: 29 September 2003 \end{verbatim} A variable such as {\tt title} or {\tt date} is called a {\em scalar variable}, meaning that it contains only one value. If an expansion contains a value that has not been set, it produces no output. This makes it convenient to write HTML form elements that display the value previously entered, if any: \begin{verbatim} \end{verbatim} \subsection{Hashes} \label{sec-hashes} It is often convenient to group several related values together, and give a name to the group. A {\em hash} is a collection of values, each of which has a name (called a `key'). Continuing with the example from the previous section, we might want to break down the date into day, month and year components: \begin{verbatim} Today's date: ${date.day}-${date.month}-${date.year} \end{verbatim} Here, {\tt date} is a hash, which contains three scalars: {\tt day}, {\tt month} and {\tt year}. (An expression like {\tt date.day} is called a {\em hash lookup}.) The result might be: \begin{verbatim} Today's date: 29-09-2003 \end{verbatim} Hashes can contain hashes, e.g.: \begin{verbatim} Date of birth: ${user.dob.day}-${user.dob.month}-${user.dob.year} \end{verbatim} The string value of any variable (or other expression) can be used as a hash key by enclosing the expression in square brackets: \begin{verbatim} Error in field "${fieldName}": ${errors[fieldName]} \end{verbatim} If the value of {\tt fieldName} was always {\tt "title"}, the above would be the same as writing: \begin{verbatim} Error in field "title": ${errors.title} \end{verbatim} \subsection{Lists} Generated documents often contain lists of data. In a template, the {\tt \#foreach} statement processes all the elements in a list. Here's a simple example: \begin{verbatim}

Signatories:

    #foreach (signatory in signatories)
  • ${signatory}
  • #end
\end{verbatim} The output might look like this: \begin{verbatim}

Signatories:

  • Arthur Artichoke
  • Bernard Banana
  • Carol Carrot
  • Dorothy Date
\end{verbatim} For each element in the list, the {\tt \#foreach} statement stores the element's value temporarily in the name given before the {\tt in}, then processes the template text between the {\tt \#foreach} and the {\tt \#end}. \label{example-table}Here's an example that generates an HTML table: \begin{verbatim} #foreach (person in garden.people) #end
Name Date of Birth Favourite Colour
${person.name} ${person.bdate} ${person.colour}
\end{verbatim} Here {\tt garden} is a hash that contains a list called {\tt people}. Each element of {\tt people} is a hash containing three scalars ({\tt name}, {\tt bdate} and {\tt colour}). \subsection{Conditionals} A template can contain optional text, which is used only if some condition is met. The {\tt \#if} statement tests a condition. For example: \begin{verbatim} #if (approved) This document has been approved for publication. #else This document is awaiting approval. #end \end{verbatim} We have seen scalars that contain strings (i.e. text); {\tt true} and {\tt false} are also possible values of a scalar (e.g. {\tt approved} above). Any scalar is equal to {\tt true} if it has a value other than 0 or the empty string. A list is equal to {\tt true} if it exists and isn't empty. A hash is equal to {\tt true} if it exists. This makes it convenient to check, for example, whether a list contains any values before processing its contents: \begin{verbatim} #if (searchResults) #foreach (result in searchResults) ... #end #end \end{verbatim} If a scalar contains a string or a number, an expression can test the scalar's value, using comparison operators such as {\tt ==} (equals), {\tt !=} (is unequal to), {\tt <} (is less than) and {\tt >} (is greater than). You can also use {\tt \#elseif} blocks to test several conditions. For example: \begin{verbatim} #if (hour > 17) Good evening! #elseif (hour > 12) Good afternoon! #else Good morning! #end #if (status == "approved") This document has been approved for publication. #else This document is awaiting approval. #end \end{verbatim} See Section~\ref{sec-expressions} for the full details of expressions. \subsection{Setting values} The {\tt \#set} statement assigns a value to a name. The value is not set in the data model that the program has provided; a template cannot use {\tt \#set} to change its data model. The value remains internal to the template, and only while the template is being merged; it is then forgotten. Returning to the earlier example of an HTML table, suppose we wanted the background colour of the rows to alternate between yellow and white. We could write: \begin{verbatim} #set (background = "white") #foreach (person in garden.people) ${person.name} ${person.bdate} ${person.colour} #if (background == "white") #set (background = "yellow") #else #set (background = "white") #end #end \end{verbatim} \subsection{Including Templates in Templates} Rather than copy and paste the same text into several templates, you can put the common text in a separate template, and include that template in other templates using the {\tt \#include} statement. For example, you might include a standard header and footer on each page: \begin{verbatim} #include ("header.tmpl") ... #include ("footer.tmpl") \end{verbatim} Included templates will not see any values that have been set in the including template, nor can the including template see any values that the included template sets. If you want to pass values into a reusable section of template code, use a macro, as described in the next section. \subsection{Macros} To create a reusable bit of template code that uses values you provide, you can write a {\em macro}. The {\tt \#macro} statement defines a macro, which can then be used as a statement in its own right. For example, here is a macro that formats a date in a particular way, given the year, month and day as numbers: \begin{verbatim} #macro formatDate(year, month, day) #var (monthPrefix) #var (dayPrefix) #if (month < 10) #set (monthPrefix = "0") #end #if (day < 10) #set (dayPrefix = "0") #end ${year}-${monthPrefix}${month}-${dayPrefix}${day} #end \end{verbatim} (The {\tt \#var} statement will be explained in a moment.) Here is some template code that expects a hash called {\tt date} like the one we saw in Section~\ref{sec-hashes}, and uses it to call the {\tt formatDate} macro above: \begin{verbatim} Today's date: #formatDate(date.year, date.month, date.day) \end{verbatim} A macro may be called with fewer arguments than it was defined with; the remaining arguments are set to null. It is an error to call a macro with too many arguments. \subsubsection{Defining Variables in Macros} The {\tt \#var} statement in the macro above initialises a variable for use within the macro, setting it to a null value. We could have written: \begin{verbatim} #set (monthPrefix = "") \end{verbatim} But if there was already a variable called {\tt monthPrefix} outside the macro, {\tt \#set} would change the value of the existing variable. (Sometimes this might be what you want.) By contrast, a variable initialised inside a macro with {\tt \#var} only exists within that macro, and doesn't affect any other variable that might have the same name outside the macro; its value is forgotten once the macro has completed. Once you have used {\tt \#var} to initialise a variable in a macro, you can use {\tt \#set} to change its value, as in the example above. To initialise a variable with a value other than null, you can write: \begin{verbatim} #var (colour = "blue") \end{verbatim} When used outside of a macro, {\tt \#var} has the same effect as {\tt \#set}. \subsubsection{Storing Macros in Separate Templates} If there are some macros that you want to use in more than one template, you can define them in a separate template, which we'll call a {\em macro template}. In each template where you want to use those macros, you then need to tell CamlTemplate where to look for them, using the {\tt \#open} statement. For example, if you've written a macro template called {\tt macros.tmpl}, and you want to use them in a template called {\tt test.tmpl}, you would put the following line in {\tt test.tmpl}, before using any of the macros: \begin{verbatim} #open ("macros.tmpl") \end{verbatim} You can put several {\tt \#open} statements in a template. When you call a macro, CamlTemplate looks for it first in the template that's being merged, and then in any macro templates that have been opened in that template. \subsection{Functions} A function can be supplied to a template as part of its data. Since functions are written in Objective Caml, they can do things that would be cumbersome or impossible to do in macros. A function takes one or more expressions as arguments, and returns a value, which can be used in an expansion or in a statement. For example, CamlTemplate provides a function called {\tt escHtml}, for escaping special characters in HTML documents. It can be used like this: \begin{verbatim} Company name: ${escHtml(companyName)} \end{verbatim} If the value of {\tt companyName} was {\tt Artichoke \& Banana}, the output would be: \begin{verbatim} Company name: Artichoke & Banana \end{verbatim} In addition to {\tt escHtml}, CamlTemplate provides the following functions, which application developers can choose to make available to templates: \begin{description} \item[urlEncode] URL-encodes a string. \item[escHtmlAttr] Escapes special characters in text to be included in an HTML attribute. \item[escHtmlTextarea] Escapes special characters in text to be included in an HTML {\tt textarea}. \item[asList] Converts any value to a list, if it isn't already a list. If the argument is a list, returns the argument. If the argument is null, returns an empty list. Otherwise, returns a single-element list containing the argument. This is useful for dealing with form input fields that can have multiple values. \end{description} Each of these functions expects one argument. \subsection{Comments} You can write a comment in a template by surrounding it with {\tt \#*} and {\tt *\#}: \begin{verbatim} #* This is a comment. *# \end{verbatim} Comments do not appear in the output when a template is merged. Comments can contain comments. \section{Template Syntax Reference} \subsection{Whitespace} It often makes templates more readable to include extra whitespace around statements. In particular, the CamlTemplate syntax encourages a style in which each statement is on a line by itself, possibly indented. This means that there is extra whitespace around the statement: the indentation preceding it, and the newline after it. However, it is often not desirable to include that extra whitespace in the output. To support this, CamlTemplate ignores whitespace in certain contexts. The basic rules are as follows: \begin{itemize} \item When a line begins with whitepace followed by {\tt \#}, that whitespace is ignored. \item When a newline follows the closing parenthesis of a statement, or a keyword such as {\tt \#else}, the newline is ignored. \end{itemize} Thus a statement or keyword on a line by itself 'disappears' from the output (except for any output produced by the statement itself). Consider the following template: \begin{verbatim} #macro sayHello() Hello. #end #if (true) #sayHello() #end \end{verbatim} This will print a single line of text, consisting of {\tt Hello.} followed by a newline. Another example: \begin{verbatim} #macro sayHello() Hello. #end #if (true) The greeting is: #sayHello() #end \end{verbatim} This will print: \begin{verbatim} The greeting is: Hello. \end{verbatim} Note that since the call to {\tt \#sayHello()} does not fall at the beginning of a line, the space after the colon is preserved. It is often convenient to put a comment at the end of a line, like this: \begin{verbatim} #if (showGreeting) ${greeting} #* Display the greeting *# #end \end{verbatim} The rule for comments is therefore slightly different in one respect: whitespace preceding a comment is always ignored (even if it doesn't start at the beginning of a line), and a newline following a comment is ignored. The above example will print the value of {\tt greeting}, with no additional whitespace or newlines. In other contexts where a newline makes the template more readable, but you don't want to include it in the output, you can precede it with a backslash; both the backslash and the newline will be ignored, e.g.: \begin{verbatim} #if (true) yes\ #end \end{verbatim} This will print {\tt yes} with no newline. \subsection{Comments} \begin{quote} {\tt \#*} {\em comment} {\tt *\#} \end{quote} Comments can be nested. \subsection{Escaping Characters} When used literally (rather than to indicate an expansion or a statement), {\tt \$\{} and {\tt \#} must be escaped with a backslash: \begin{verbatim} \${ \# \end{verbatim} Additional backslashes preceding an escape sequence are simply included in the output, as are backslashes not followed by {\tt \$\{} or {\tt \#}. \subsection{Expansions} \begin{quote} {\tt \$\{}{\em expression}{\tt \}} \end{quote} Adds the value of {\em expression} (which must evaluate to a scalar) to the output. \subsection{Statements} A statement begins with a {\tt \#} character followed by a keyword. When a statement has a body, it is terminated by {\tt \#end}. If you need {\tt \#end} to be followed by a letter, you can write {\tt \#end\#}; similarly, you can write {\tt \#else\#} instead of {\tt \#else}. This makes it possible to write a template without newlines, e.g.: \begin{verbatim} There #if (n == 1)is 1 file#else#are ${n} files#end#. \end{verbatim} \subsubsection{foreach} \begin{quote} {\tt \#foreach} ({\em name} in {\em expression}) \begin{quote}{\em template text}\end{quote} {\tt \#end} \end{quote} Evaluates {\em expression} as a list; iterates over the list, assigning each element in turn to {\em name}. Any previous value of {\em name} is temporarily hidden. \subsubsection{if} \begin{quote} {\tt \#if} ({\em expression}) \begin{quote}{\em template text}\end{quote} {\tt \#elseif} ({\em expression}) \begin{quote}{\em template text}\end{quote} {\tt \#else} \begin{quote}{\em template text}\end{quote} {\tt \#end} \end{quote} The {\tt \#elseif} and {\tt \#else} blocks are optional; any number of {\tt \#elseif} blocks may be used. You can write {\tt \#else\#} instead of {\tt \#else}. \subsubsection{set} \begin{quote} {\tt \#set} ({\em name} {\tt =} {\em expression}) \end{quote} Assigns the value of {\em expression} to the variable {\em name} in one of the following places, in order of preference: \begin{enumerate} \item In macro scope, if invoked in macro scope and the variable already has a value there. \item In template scope. \end{enumerate} \subsubsection{var} \begin{quotation} {\tt \#var} ({\em name}) {\tt \#var} ({\em name} {\tt =} {\em expression}) \end{quotation} Assigns the value of {\em expression} (or a null value if {\em expression} is not supplied), to the variable {\em name} in one of the following places, in order of preference: \begin{enumerate} \item In macro scope, if invoked in macro scope. \item In template scope. \end{enumerate} \subsubsection{include} \begin{quote} {\tt \#include} ({\em expression}) \end{quote} Interprets the string value of {\em expression} as the name of a template, and includes the contents of that template in the one currently being processed. \subsubsection{Macro Definition} \begin{quote} {\tt \#macro} {\em macroname} ({\em paramname1}, {\em paramname2}, ... {\em paramnamen}) \begin{quote}{\em template text}\end{quote} {\tt \#end} \end{quote} Defines a macro called {\em macroname} that takes {\em n} parameters. \subsubsection{Macro Invocation} \begin{quote} {\tt \#}{\em macroname} ({\em param1}, {\em param2}, ... {\em paramn}) \end{quote} Invokes the macro called {\em macroname}. If a macro is called with fewer parameters than were defined in the macro, the remaining parameters are set to null. \subsubsection{open} \begin{quote} {\tt \#open} ({\em expression}) \end{quote} Interprets the string value of {\em expression} as the name of a template, and adds it to the list of templates in which macros will be searched for when invoked in the currently running template. \subsection{Expressions} \label{sec-expressions} \subsubsection{Data Types} \begin{itemize} \item Scalar: \begin{description} \item[String] A string literal is enclosed in double quotes: {\tt "}{\em string}{\tt "}). A double quote in a string literal must be escaped by preceding it with a backslash. The escapes {\tt $\backslash$t} (tab), {\tt $\backslash$r} (carriage return) and {\tt $\backslash$n} (newline) can also be used; {\tt $\backslash\backslash$} produces a backslash. \item[Integer] An integer literal is a sequence of one or more digits, optionally preceded by a minus sign. For convenience and readability, underscore characters (\_) are accepted (and ignored) within integer literals. \item[Float] A floating-point literal consists of an integer part, a decimal part and an exponent part. The integer part is a sequence of one or more digits, optionally preceded by a minus sign. The decimal part is a decimal point followed by zero, one or more digits. The exponent part is the character e or E followed by an optional + or - sign, followed by one or more digits. The decimal part or the exponent part can be omitted, but not both (to avoid ambiguity with integer literals). For convenience and readability, underscore characters (\_) are accepted (and ignored) within floating-point literals. \item[Boolean] The boolean literals are {\tt true} and {\tt false}. \end{description} \item Hash. Keys are identifiers, values are any template data type. \item List. Values are any template data type. \item Null. A nonexistent value of any type is represented as null. The null literal is {\tt null}. \end{itemize} \subsubsection{Conversions} Scalar types are converted to other scalar types automatically. When an operator has one integer operand and one float operand, the integer is promoted to a float. Otherwise, the interpreter attempts to convert the right-hand side of an expression to the type of the left-hand side, and raises {\tt Template\_error} if this not possible. Any value can be compared with a boolean or null value. All scalar values are equal to {\tt true} except integer 0 and the empty string; a null value is equal to {\tt false}. All list and hash values are equal to {\tt true} except the empty list. The string and integer values of {\tt true} are {\tt "true"} and 1, respectively; the string and integer values of {\tt false} are {\tt ""} (the empty string) and 0. \subsubsection{Identifiers} \label{sec-identifiers} The characters allowed in identifiers are upper-case and lower-case ASCII letters, digits, the underscore and the apostrophe. The first character of an identifier must be an ASCII letter. \subsubsection{Operators} Table~\ref{table-operators} lists the operators supported in expressions. Standard operator precedence applies, and can be overridden using parentheses. \begin{table} \centering \begin{tabular}{|l|l|p{10em}|} \hline {\em Operator} & {\em Meaning} & {\em Compatible Types} \\ \hline ! & unary not & boolean values \\ - & subtraction, unary negation & integers, floats \\ + & addition, string concatenation & integers, floats, strings \\ $*$ & multiplication & integers, floats \\ / & division & integers, floats \\ \% & modulo & integers, floats \\ == & equality & scalars \\ != & inequality & scalars \\ < & less than & integers, floats, strings \\ > & greater than & integers, floats, strings \\ <= & less than or equal to & integers, floats, strings \\ >= & greater than or equal to & integers, floats, strings \\ \&\& & and & boolean values \\ || & or & boolean values \\ . & hash lookup with identifier as key & hash on left, identifier on right \\ $[]$ & hash lookup with string as key & hash on left, string on right \\ () & function call & function on left, comma-separated expressions in parentheses \\ = & assignment & identifier on left, expression on right \\ \hline \end{tabular} \caption{Operators\label{table-operators}} \end{table} \section{Programming with the CamlTemplate Library} \label{sec-library} When reading this section, you will probably find it helpful to refer to the CamlTemplate API documentation, which is generated by ocamldoc and provided in the {\tt doc/api} directory of the CamlTemplate distribution. \subsection{The General Procedure} The general procedure is as follows: \begin{enumerate} \item Create a template cache using {\tt Cache.create}. \item Create a data model consisting of values of type {\tt Model.tvalue}. \item Load a template using {\tt Cache.get\_template}. \item Pass the template to the {\tt merge} function to generate output. \end{enumerate} Here is `Hello, world!' with a template. The template is as follows: \begin{verbatim} Here is the message: ${message} \end{verbatim} And here is a program that uses it: \begin{verbatim} open Printf ;; open CamlTemplate.Model ;; let _ = (* Make a template cache. *) let cache = CamlTemplate.Cache.create () in (* Create a model. *) let model = Hashtbl.create 4 in Hashtbl.add model "message" (Tstr "Hello, world!"); try (* Get the template. *) let tmpl = CamlTemplate.Cache.get_template cache "hello.tmpl" (* Make a buffer for the output. *) and buf = Buffer.create 256 in (* Generate output. *) CamlTemplate.merge tmpl model buf; print_string (Buffer.contents buf) with CamlTemplate.Syntax_error msg -> eprintf "\n%s\n" msg | CamlTemplate.Template_error msg -> eprintf "\n%s\n" msg ;; \end{verbatim} There are other examples in the {\tt examples} directory of the distribution. \subsection{Template Data Models} A template data model is a tree of values; these values can be scalars (strings, integers, floats or booleans), lists, hashtables or functions. The root of the tree must be a hashtable. In a template, an identifier by itself is the name of an entry in that root hashtable. Tabular data can be represented as a list of hashes of scalars. Each element in the list represents a row in the table, and consists of a hash in which the names are column names and the values are cell values. Such a model can be handled as shown in Section~\ref{example-table}. \subsection{Loading and Caching Templates} Once loaded and parsed, templates are cached; the {\tt Cache} module provides functions for creating template caches, getting templates from them and configuring the behaviour of a cache (e.g. how often it is refreshed). By default, templates are loaded from files, but you can provide a class of type {\tt source\_loader} to load them from another source. The {\tt \#include} and {\tt \#open} statements fetch the included or opened template from the cache when the enclosing template is merged. Therefore, if an {\tt \#include} or {\tt \#open} refers to a template that doesn't exist, this won't be detected until the outer template is merged. Macros are stored in the templates in which they are defined. When a template containing a macro definition changes, the macro definition is updated as well. \subsection{Threads} \label{sec-manual-threads} CamlTemplate provides optional support for multithreaded programs. If you need thread support, in addition to linking your program with the {\tt camlTemplate} library, you must also link in {\tt camlTemplate\_mt.cmo} (for bytecode programs) or {\tt camlTemplate\_mt.cmx} (for native-code programs). This ensures that the following are true: \begin{itemize} \item Multiple threads can safely use the same template cache concurrently. \item Multiple threads can safely pass the same template (or different templates) to the {\tt merge} function. \item Multiple templates running in different threads can safely use the same model, as long as no template function changes the model. (Note that none of the template statements, including {\tt \#set} and {\tt \#var}, can change the model.) Values set using {\tt \#set} and {\tt \#var} are visible only to the thread that set them. \end{itemize} \subsection{Error Handling} The {\tt get\_template} function raises {\tt Syntax\_error} if it cannot parse a template. It may also raise other exceptions if it fails to read template source code because of an I/O error. If a template cannot be merged because of a run-time error (e.g. a wrong data type), the {\tt merge} function raises {\tt Template\_error}. If a Caml function called from a template is unable to complete successfully, it can raise {\tt Tfun\_error}; this causes {\tt merge} to raise {\tt Template\_error}. \section{Design} This section describes the implementation of CamlTemplate; you don't need to read it unless you are interested in developing CamlTemplate itself. CamlTemplate is a fairly straightforward implementation of the Interpreter\footnote{Erich Gamma et al., {\em Design Patterns: Elements of Resuable Object-Oriented Software}, Addison Wesley Longman, 1997.} pattern. It uses {\tt ocamllex} and {\tt ocamlyacc} to parse template source code, generating an abstract syntax tree consisting of objects; these objects do the work of interpreting the template. \subsection{The Abstract Syntax Tree} There are two kinds of objects in the abstract syntax tree, represented by the class type {\tt statement} and the virtual class {\tt expression}. Statements produce output; expressions have values. A template consists essentially of a list of statements (each of which may contain one or more lists of statements, e.g. to represent the body of a loop, or the branches of a conditional); when merged, the template iterates over its statements, calling each statement's {\tt interpret} method in turn. \subsection{The Parser and Lexer} The parser is very straightforward, and probably needs no explanation if you are familiar with ocamlyacc. The lexer, on the other hand, is rather complicated, mainly because of the absence of delimiters around literal text in a template language; this requires us to assume that we are reading literal text until we get to something that looks like template language syntax. The CamlTemplate lexer therefore maintains some state to indicate which sort of environment is being tokenised. The variable {\tt cur\_mode} keeps track of whether the lexer is currently in literal text, an expansion or a statement. For the most part, instead of using specialised rules, the lexer uses a single rule containing all the patterns that are meaningful in tokens; once it has matched a pattern, it decides what to do depending on its current mode. \subsection{Scopes} Scopes in CamlTemplate are roughly patterned after those in JavaScript. There are two writable scopes, template scope and macro scope; the template model is an additional read-only scope. Assignment and lookup of values in scopes are encapsulated in the {\tt scope} class in {\tt ctScope.ml}. \subsection{Thread Support} Since parser and lexer both maintain some global state, and since template caches are modifiable, they are all protected by a global mutex (in {\tt ctCache.ml}) when thread support is linked in. \end{document} camltemplate-1.0.2/doc/manual/merge.dia0100644000076400010400000003005507736350474023732 0ustar gdsАдминистраторы #A4# #CamlTemplate# #Data# #Template# #Output File# camltemplate-1.0.2/doc/manual/merge.eps0100644000076400010400000001326707736350474023772 0ustar gdsАдминистраторы%!PS-Adobe-2.0 EPSF-2.0 %%Title: merge.dia %%Creator: Dia v0.90 %%CreationDate: Mon Sep 29 15:43:45 2003 %%For: ben %%Magnification: 1.0000 %%Orientation: Portrait %%BoundingBox: 0 0 456 410 %%Pages: 1 %%EndComments %%BeginProlog /cp {closepath} bind def /c {curveto} bind def /f {fill} bind def /a {arc} bind def /ef {eofill} bind def /ex {exch} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth pop} bind def /tr {translate} bind def /ellipsedict 8 dict def ellipsedict /mtrx matrix put /ellipse { ellipsedict begin /endangle exch def /startangle exch def /yrad exch def /xrad exch def /y exch def /x exch def /savematrix mtrx currentmatrix def x y tr xrad yrad sc 0 0 1 startangle endangle arc savematrix setmatrix end } def /mergeprocs { dup length 3 -1 roll dup length dup 5 1 roll 3 -1 roll add array cvx dup 3 -1 roll 0 exch putinterval dup 4 2 roll putinterval } bind def %%EndProlog %%BeginSetup %%EndSetup 28.346000 -28.346000 scale -5.211647 -15.724975 translate 0.100000 slw [] 0 sd [] 0 sd 0 slc 0 slj 0 slc 0 slj [] 0 sd 1.000000 1.000000 1.000000 srgb n 6.503693 7.342893 m 19.100307 7.342893 l 12.802000 10.557107 l f 0.000000 0.000000 0.000000 srgb n 6.503693 7.342893 m 19.100307 7.342893 l 12.802000 10.557107 l cp s [ /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /C /a /m /l /T /e /p /t /xi /xi /D /O /u /space /F /i /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi /xi ] /e0 exch def /Helvetica_e0 undefinefont /Helvetica_e0 /Helvetica findfont dup length dict begin {1 index /FID ne {def} {pop pop} ifelse} forall /Encoding e0 def currentdict end definefont pop /Helvetica_e0 ff 0.800000 scf sf ( !"#$%"&#!'%) sw 2 div 12.802000 ex sub 8.386447 m ( !"#$%"&#!'%) gs 1 -1 sc sh gr 0.100000 slw [] 0 sd [] 0 sd 0 slc 0 slj 0 slc 0 slj [] 0 sd 1.000000 1.000000 1.000000 srgb n 5.261647 1.878595 m 5.766268 1.476819 6.018579 1.342893 6.523200 1.342893 c 7.027821 1.342893 7.280132 1.476819 7.784753 1.878595 c 7.784753 4.021405 l 7.280132 4.423181 7.027821 4.557107 6.523200 4.557107 c 6.018579 4.557107 5.766268 4.423181 5.261647 4.021405 c 5.261647 1.878595 l f 0.000000 0.000000 0.000000 srgb n 5.261647 1.878595 m 5.766268 1.476819 6.018579 1.342893 6.523200 1.342893 c 7.027821 1.342893 7.280132 1.476819 7.784753 1.878595 c 7.784753 4.021405 l 7.280132 4.423181 7.027821 4.557107 6.523200 4.557107 c 6.018579 4.557107 5.766268 4.423181 5.261647 4.021405 c 5.261647 1.878595 l s 0 slc 0 slj [] 0 sd n 5.261647 1.878595 m 5.766268 2.280372 6.018579 2.414298 6.523200 2.414298 c 7.027821 2.414298 7.280132 2.280372 7.784753 1.878595 c s /Helvetica_e0 ff 0.800000 scf sf (*!'!) sw 2 div 6.523200 ex sub 3.457851 m (*!'!) gs 1 -1 sc sh gr 0.100000 slw [] 0 sd [] 0 sd 0 slc 0 slj 0 slc 0 slj [] 0 sd 1.000000 1.000000 1.000000 srgb n 16.874047 1.825025 m 21.218753 1.825025 l 21.218753 3.753553 l 20.349812 3.432132 19.915341 3.432132 19.046400 3.753553 c 18.177459 4.074975 17.742988 4.074975 16.874047 3.753553 c 16.874047 1.825025 l f 0.000000 0.000000 0.000000 srgb n 16.874047 1.825025 m 21.218753 1.825025 l 21.218753 3.753553 l 20.349812 3.432132 19.915341 3.432132 19.046400 3.753553 c 18.177459 4.074975 17.742988 4.074975 16.874047 3.753553 c 16.874047 1.825025 l s /Helvetica_e0 ff 0.800000 scf sf ($%"&#!'%) sw 2 div 19.046400 ex sub 2.868579 m ($%"&#!'%) gs 1 -1 sc sh gr 0.100000 slw [] 0 sd [] 0 sd 0 slc n 6.523200 4.557107 m 6.503693 7.342893 l s 0 slj n 6.109305 6.540112 m 6.503693 7.342893 l 6.909285 6.545714 l f 0.100000 slw [] 0 sd [] 0 sd 0 slc n 19.046400 3.753553 m 19.100307 7.342893 l s 0 slj n 18.688339 6.548990 m 19.100307 7.342893 l 19.488248 6.536977 l f 0.100000 slw [] 0 sd [] 0 sd 0 slc 0 slj 0 slc 0 slj [] 0 sd 1.000000 1.000000 1.000000 srgb n 9.482047 13.475025 m 16.017953 13.475025 l 16.017953 15.403553 l 14.710772 15.082132 14.057181 15.082132 12.750000 15.403553 c 11.442819 15.724975 10.789228 15.724975 9.482047 15.403553 c 9.482047 13.475025 l f 0.000000 0.000000 0.000000 srgb n 9.482047 13.475025 m 16.017953 13.475025 l 16.017953 15.403553 l 14.710772 15.082132 14.057181 15.082132 12.750000 15.403553 c 11.442819 15.724975 10.789228 15.724975 9.482047 15.403553 c 9.482047 13.475025 l s /Helvetica_e0 ff 0.800000 scf sf (+,'&,'-./#%) sw 2 div 12.750000 ex sub 14.518579 m (+,'&,'-./#%) gs 1 -1 sc sh gr 0.100000 slw [] 0 sd [] 0 sd 0 slc n 12.802000 10.557107 m 12.750000 13.475025 l s 0 slj n 12.364318 12.668025 m 12.750000 13.475025 l 13.164191 12.682280 l f showpage camltemplate-1.0.2/doc/pdf/0040755000076400010400000000000011030647121021424 5ustar gdsАдминистраторыcamltemplate-1.0.2/doc/pdf/manual.pdf0100644000076400010400000022402511030642176023403 0ustar gdsАдминистраторы%PDF-1.2 %ЗмЏў 6 0 obj <> stream xњќXЫІЫ¶ндQ_БGgЖ‚pїф-NRыtмЦIФ6™Й EсHt%Q&)џїпЖeѓ¤¤:ћМ™±<мЛЪk/аcA +ЁяKїХqсq±ъY»~с±`a Єcсj “®а”hНu±~\ДПXБ¬ †Zq"ЉхqсbЅЇї]XCЦЦ¬·‹Я—ЗГЪ+E¬28\П‡rл lНXWћ.еБ/•Д)U,№$V†Щы Ж‰rчйъ¦=Ґэµђ:Ќ3ющбХПа “¦ё·~© Ў†™b)А їЄOКc·q°ФЙґНлєо‚1Т®ќ7Жї2БJЊ5ёьп—Гіе†HЕUе”Єd /!њ)LaО*‹Ґ`єsСррЅ"ЋJ—ѕ8 Б¦™©v{©†д;м, Ж|ё’“ЉpЈБZЌ>®чM6ДЩґЕ1rf Г·u_uН¦H0ѓбqjЯЇ1ВЎ%Oi€†бp™іwЅф!ЭМe4ї†‡аЮ95‡ЗЛ`D‡sLxй‡ ‚гГK°ЦЃ ;wmUч}ў'-‘,Гт12 °hб?7кjт-<њё+–ќ€ЅЎсљHc-zю) †X@FvґЏћГй}LY’…!ОPH"dЙgY¦њЂ3¦я:ќ†(M)+–У•аЬ®+Џ= 6pBi.®‡!AS Ќ­КЂж€VЧMLмj™іґ 8ЃвгКМуЙ‰Ф9џ»ъTwcЬ•xЦSЅIPЈLаaзrWч!ЎBA5иЎvТ `Нdу~щйm*­s‰}јФ]“6‚,Aщ–|–|Ё`юЧwoS­h.1OЫ¶єлУ­$С2Rћў»”pЕ0Ђн°ЏuП}иM6µнв`’иmыbг¤ОсJ0PЊeЁHJ®љ3А–B’‰јX* pЏщnУ^B^%"еh*ЦµЂH0‰^Ќ4zC ћV-PШ’C6ењ ЉwёЬpqeЁц\7Е0•0єы©Щ&$9 oЉГ‘e=‡ЏМрf“ж;‡Ґж&3РРЭч?ь-%@0Љй…b>–13ВгтЖчb—v–} ҐЁѓ™!›~и¤ Аљ4Sn"/й2О.ћ«пNАoр¶©кSUЯM*®фIUъk]‚©ІK)±+0ЩЏ]]§XeM.ѓЗ!p>tй2—Ъ6c9жЛ Zр(фёШдш='pБrєтeЊ¤ўЦ`oйкC]&–‚¬@·FЯ.§mЌќRжЄЕ„kи©№{ѕюЗїВB`j'qелАh‡*r9ЅїlM•‚iGyRТЯu°,№њy-ѕЪkЃe•OжШ‚&u ЭЕЭ«T.®+•7&t;иъ6v@$М]ЗО›жШхе±F•3†щбMgё?іL"&—bfЙr»m|YД68q№…•эќеA-‚; GР”s]5Йy`‘Э©#nвџџ«ъ<ћ¦AБdRљ @Pz”+ќ!‘»;ЃлwA 8ВЁНXё§Р 1v†sЭ›~"Z)“W]v¦љНйїБPґО\‘ШR@њҐ›ROХnklQь¶GY>ц(D$\rLc’©©sќ{иS3мoБ7DЊlъЭ№¬Т] ‘зЮэfЅ~џЉИдЪъҐо>%µіёEЊ:М№Гpюю"‹6c3¤'vЎ©ЗvЫ|“@”Кн—r.±whўTЦ%1da х0­В™wс?мЛ!9В(EЎк°ЊЄwЊљХ9j“І‚&8+«ёШ'G„§ Р2sJЈiї;B«їTР:iU?@\эm9LYЯвЖы@{Lґ Aі·€›<L§g€ aяq]ьдџ•©*ьѓ"`[0к9ьB@ ґвкёxх°X=ј+†оR/Vя)ШbхЖяукэчрурCс—ЕЏqЇ»O—#юґфмн’…‡1ж@ыШрx‰/¶NР {‚€‡я†‡—рТй]ШГщЇ«U—+Тњє¦$Џ]ъrvР2ьсџт?8AOxzz"»У…ґЭnuЮ7‡¶oПызХx!‹ІчPя2eІ”мџИ>v8ё}kѓ+уCФЬXоаMЌМ$ю¬ҐU{~>ФЏГjw>ащ3KЏчЯ$„пЌ@LK 2)љe”шїя.3ghendstream endobj 7 0 obj 2108 endobj 22 0 obj <> stream xњ•Y[oЫШ.ъи—юѕ%VGз~iџљdі5°Eцвb_ШТ-sC‘ IEхїпњЫђ’ДЃЫ ‡њЫ7ЯМ~,(aх?йпfусжcБВµьgі/^ЯЭ¬aЄ`’©yqчp` Д‰•…ЎЊ0YЬнo^2"^Ээy#8бћЎЕЭцже;ЙбgйRUЋЗ>I нтХБ_ZяВuБqJm+Ґ€ґМ+О‰”AтoQђ‰№ ьk¤ЛZяйEь]ЗtєфЙ_RДj§DVЩеX7Хwю–¤ДЁйV9<­ЖnХTeЯъЫZҐyѕ=VыCSЋUxPiDѕ3<µcщїаДМI“џx,G•3В9НF ЗГЎлЗаєаЃИт›nїп‚f©U6_6}}лv·тчV‚ ёлЉdИ$љІЭЛ]ґM«$Зw¶ГШ7г<†Рr©mєyz„H»)‚зgЄvУыrC8С†Кtіф—aЊcr‡кPцХh»вД•mїЇЖSUµЙYEQчЎЇ† в–[ J‰T6ё“Юt»zи]ўY]ЩnГEJёb9ебРФ›ЙMЁгЩжр"І€5Ъњ’Ђ5Рjџ‹µ»З6‰`Vњ'¶ Ц)F$ЈиoК}ѓq–щк¶C4A5g"Уuмcq(J,W;е0Тm 5TџІ9,M=¤$CёњQYЛXЮ7с]ЎJЌё##ЪaЗѕЉІ!д*ыЫ=ДIK¤}JQ Uе-±NfкђъёusаxVgмЛzч8>tэ)8 ·ЌFgы` іђJ|ЛѕlЫ*2 @™»,ь™мNDИgWизfч· RЕ°4»юГђ2®НWOUУ¤«ЉтlК©1­ п¶l @=°($‰2жХC’ Є#9Ґ±¤е’ќЉХ\l±ј®ђ1D­ђЏКaЬмк% {8±ZТ/Їф/Зќыд|cMэ:зEиЬ"崉ڙd™>ћ"љИяїѕ№Ѕ]A}Ђо#Ї9Пј›рЪH-rїѓSЃЂЭ4Зm"<@9ќкк?wпVц3nj 1 ^@PПtхэБуTЩ¤VbЕes№ѓЉв.s2”H”69ыc3ШъЄф¦ЃР8aNЂM&ЯіП]nѕЫфјџAl™ИP=ЕШ*Ж4їЖ?ЂЙ=dЃ)Џу®}¬NЁZ!ђs+Ѓ8i›­GъЂ]¤їYхЁ,щ(?хх8ЖFўЎQP¬ьЬ—‡аї‚Rњ(до±._vи»ФGµхЉgl¶©†(cЋC‹в+ ѓT`дл¦9zцКlМ°.±Я»z”ћf¦MЛYАЊjfKn1МіЯв T$pЃ>?–u«Ж&®уќ®mћR ПцЏснМшљвЛaVЖ уФцuЩь#Х'0v¬nm5ђ]•=л@Gџ.SkfбЯхе>y@al\М D6Я|Є·Un3FЈЉЙ y>ѓIІTbR¦x:qП©•›*1РўМSЗЗX†КЂ™мя¶«†цEв[-x–e }T8ДM[EАpJ­@Б.ЖNЂ№Џ®Iа fОЂј 'ЪK3®g—lOЧ|ВєґXнЫф>¤м%P EЅ©ZЃЃ(ХS°г4»љЌt3¬¦њFh@Џ’иЩcцBsФљ O5ЋёIРhйь№`ґћGpHі”ВўЖО<щРv Ђ{lО©–­Б-б”ЗtM¤г_f§EДќCЪк9¤S"мDҐЛЯ%ґЁ‰u§N®vтM™†cІ0БL1чХUAWИ3ї°Иz(дё _ЯёаLЖ[ЌЖ~­сLЬc/r°XщН0М@кqёх-љ‘bшѓ€!Й†Вt™ЬV™‘'T-нzMwЂ}Џ¤з$єцcэ!uS%qИ­эр ц—эњк!.ЊЬ`Z]8в{2c `ЂЕiCJ%4Ж©µ¤"‡ћ59 oх_cµB>ПН"KLpLР…ЉФ4ЫUЏ)?fўЭоЫѓР>мз06q1Аиищo Ыз‡л‡дХHМ6ље€У§ел±ў|JЈцМяё§ћ­бЧH\ Ш¬ ЄіJ(pDћ}Ё6ИbЮ]w™3h1s–kЂдБPвЉт6yЁ|&ш•‡PВ’ў‡8Љ¤ч€)ю)ыђ(v™}й№$ЛlЉгЅФ ¶хКћQГ{ЩП\КФЈ­џ>.I.ц\~v¦°4Е|%Я@ЙЪ~9ЯC2MO4яыЛЉДб€Ю1}Хgм*Шю¦€klОmЧпгDЋэbўU&ђSю{илvД=FчL-«‡ѕ®Ъmу™М—8-,'Б$џЛJT7жђ1lrifЉг€pЄо§шУ9Єе®ъэUЪ;ОЏгАbђщСЏтХ‹‹Г·Є1#Я#Y!Іp *’ЗҐhўяЛҐeЕВМЁГAњТџЈћµ`pЃ­nиЋэ&ГЉб<лYu=-6Жm·9оззGвC/ёЎмЄЪfЈИ¶K4g.0§¶йКm"`зC•±сРwылA!•ф A¤љ·иg„Е@N{WГщц1Фњі•єЋс#HXЙЅ ^J!"њsqgb‹€‚эГ€ЉU„ЦЦCK%ЛgШєm‡±lљ|.aSё<^ЬњГ ґщ–3ѓЁ%,U%T_TмПЦ$ц \Ѓ1%Од?ј{»Њi_“аСLйнCBS2гл©;&•dЃњУ”JЪ6Уt~¦НЦФ"§АЛљЇдh’ ]P›“ю’IyЄ љ©y‡hеь)qE_¤5И xИњќ[  ¦]rЛюњ№kiД‚ф4‘иtSґч=nЉюа2q,*лЃ;/Єщ,ж¦Yl Ћ• БQв«БЩ—нn„† KЊФ[ИpНе0Гoъъ>СlҐо{;“-b:+9ЕйЙНєaЕчwЕПю3ЊтGу…яО8°юS t[pкЩЖъЇ5ЇooЦ·я.ЖюXЭ¬+ШНъ_юЧлџЮАџЫ·Е_nѕїЌпZю¤Ј ^бь“р€u”крI'<ЪВOoРaCЛЃ)РлJђX3ЏгxшыzЅЇъ?лЃlєэz[}Jч:њuЖшЙ‰|Я¬УЛПlYqjь‡b\цўк+F>·вt:‘‡xєLYT‚OЈэ-ћеqSщEє~·ц'№гyль¬6yVъПRжкјЋUњЏ90ГЕКЮџшm«5T_”Ѓu [fЅ^*D2€уЌkФнb9bРяь€лЙЗendstream endobj 23 0 obj 2517 endobj 31 0 obj <> stream xњеWKsGNqЬKюВ& Ыљчѓ#„Д6•cj‘ЦРJ¶1жђЯћofwV’ЅаFҐ\ei{{єїоює{tЙ8 Жг_ч9nЉЛBhN±«B°уB„(HfҐхdk еј!©{Йґђ>H2ћ/q ЙYqT\2‘LзЏqГћЈCҐ™¤”Чмш¤hэ &Ќ$НіB·Ѓ7ЕC¶wчЮчп>ё··яЗг·ЕіcцњВKE>0З5Ђ>Т’70”@М б)8&9—іщy\Hо4I±С<ДПlA /Ho|аD'±NR&Юќ±Ц=Л&­µЉґмќжзq‘aeI†ЭИqeг[‘N‹“яuфGџ€ЮoБгЮK°ЋДЋоy|Ї‘i ЬЋэЁа`Э—ZxO2fa,H™эУЮюЮ‘•¶Ѓ\,њбd5‚СЭ•њ·’i/±О9R¬„?–’јe*pNОlћЈ¦нЊ eЌ&­cfETT лЭж№ѓ±uв°И»oмЧLБ­P‘њ¤У©`·¦ПMR7·dвhРљ8d ДVnPKrгk‚б™2ј›‹ЎY{™ґдM{P k!4СрІИ€ФH:&ґQЂЈУ4WЪ“тЅdє‘ш6J‚…'#њ€yVЬqТѕ–>ъэ tЌбВчЁ“–§ЂтcF±СїЃ+вэv°~ Ыа†\PМHCеЏlыщСюѓGы%ЌоmоЖnmЉ>‚-яТ+NЖ0c …¦Т’г,€Ё#И·-э1МBEМБ№ѓY8тLЗD&јїћџ®u„ЄР:ЦEЅгIсP<Ћ2,т 1Ё[ЩуzV/ЄХщм4ѕ3–xђщ]E–NЉ,љМЗл¦ћ­в›СЎtЫpJ‰RhґN ·сµN с&,Њ·І3t0[®Єй4ыс`vтўљ­соєuІsйЎќњЕaХлЛхщўЋ°–Џ;`v'OЋрҐ”..ћш~И2ѕ:ЌЕРbxщжm=^ќwА9™Ы'ј(f0ЄХmћ„‘9є§U3ЌBйЙБh'QРЙ$є_ЧЙз‹ѕ.6ЛЄ7у$tqц©Oш¦Ў€KP—в№RjRцsѓѕ3›LПЯtzљ9,_Ћћ…ћЉќ‚ќ k2©ъ!kmЩ+{µatє+€ю‚‚јzzш¬|9о{џ5dMВЧ"€'В0ДHћmµa€ПЬaъћяює+єG‡uВ¦z—„vЃ»ќЄ•VF$jvn^П.Єq:ЃMБҐО'VguЗ+Enиj1>KЕХЛ n>A“Ь~—&\“іv»7VХў b38>ј?ЙlY+±Є›‹iµЄЛчtMGйфCЉ,оPфz‰Я,m“Ћ'Й¦FъЗ, 6<†ЈСЫ):Ћj7Q»й ¶cДЯІn†щ%ъi7Ес|vCp>K¦-Yeу‘щE”/Ґ’,oћ›|u}с±ґ:KЖЄнґТnNъБ/ґІПoYћХУ‹БиqsРЮ‰я€H:’mM‹Б`OжУiКVњџ"3ж s8E(г…­OW5™t3—№Мй*е 0…Yv}»]кТyЊG!rеЇзлn°ШЉ­pVЧ“Зэ~Е4›#­8ф+МБїhЩогoв'Еиа[-Цu1ъ“‰bф[ьчдХS|ьВѕ+ћґ¶†·)®t! —¶нЧ8ёБU±ЫяyЦy† .sйВZZОгІЈ¶,g«ХЕгСиккЉж‘ЪeК®ҐєЯ‹щйўj$•&хќЮк`}«\ЉwХiЅмJб­ЛвQ‡a2Ж<+S^¶GЮз#­OЄsЄVЈљjсnЅќН›zФ„+ґ»ЩjЦї–yЏЫ,ћЇгъ6Ъ%ќ­љЫвй ЕУ T,aЩ¶УBх<€яыѓ©2endstream endobj 32 0 obj 1461 endobj 37 0 obj <> stream xњ•Ymo7>фЈ~…>Р€(ѕїфp84Ќ‹Hp№њЂцѓЃb-­,]$­І»Єлюъ.Й!Ч^;( DЕ—бМ3ПОЯ®fЛПЬО#N)>_mgaѓIњX97”&з«гмY®›УvwiлЧ«яБB&F Сrѕа†=_mfЇV»ъд'В€”ЖВ®~ґ8Ч?„хгѓRja^±Е±ъ2њЕ$с“>Д‘пgB«У–Н№ч“qpіеhщhv_wэ”э f збxi‡©ЧЫбpFЊ’"-ЯХбю0M;Євpa!™Ћѓ§fѓУ™cq¬nЫ¦нЮ fIШX«В1S~бpEMњ5yҐэ©л«ГaкVJg\2ІмДXќ6l›¦'Г},‘TК8јЪн‡ЙpєОЌѕ†mУьЫ‡ѕ^7›:BЙ`QЋDuЪ »1рK®Tэ3¤В‰б¶ф—"Ь•®шЯ:¦Ё,кч:IИА~·Х!zДЩtч®‚уєЊCДњЫж®­Ћѓ$DAЩвuuЉёQ ЧМ W/!Ђ“1ъ¬“АЪЗNкvА,Яv“5„q^є Шј®J:\щqMpNІp (;dPrЗеTР‰”ђCo)_Ђщ8cщµBcѕјIЩiН79Nй^жё‘YOТК@$0I"НqвдSљѓЈН€ц№aDH&°Ю0ў€Hpќьz}кk@DКL A5.ЩwїпwґQТ$›Нo>xУ‡sВ шTЎа},ж+ИPgД8™_Ѓ|~BNcЙЋПХ:„ YлТ’KD9p‡ДzФпЄSЛЩжбTчkpчX PўHђMµй°bЁ4ьпџўЭВ ,keaђљ0!У‚ѕ‰a’aї«N1y50°bFпж0ѕч«Х§бL+:]µ­ї^ Иw1јЋt4а-]ЕeВ°dj‘`’CќЩЄ.єHDГmе *"Д{s‰б+аЎх8”/ 4НfD]М59YEsА%2CПпOґПјyхKв)CfbХ¶а)ёHvщ®ЉЈс5UsOЯЗ=ќБH 2^  ЯЂ¤ТЪ}¬1Pw&ТiЪpSћЎ ±zэвЮф¶^W—.L‡г(OУ‡K9Пk<Би6\КH§°ЪЗRUЕАЅ(@.V2ЈЩRЋSЩ‚NR2ч"vQN јт‹fАЏо$ly§Ё'µEнquЗdћЫЅя’0:EЯCjqўi©О‘*в¶mЋдF`ѕUCЃјJV4н—ЁЋ@Хj!Q‚ф1ЙAГ¤И«ь#й.CУЌы¤8=ЉсЁCУ| Г KlЋaRІ’#Еп·(Uђ}ZМР EX—jдo¬Я6ЧппюИ …№І‰уЊДy1°ђ>|:°”#ШБ!-ёБ: HA6HЉ‚«љKД¶Т‹:aa"KђЃвВ ёк>e rIЂRЁ_ѕДцНxљњqСcя1оДcЬЃУ]ОЮй¬йИНлБN _й‘ќЊ$ш)›€Ќс '§єHЕCLхП А«v8Х?Q7Ѓ5¤у:ґl$‰ndy«ш–аЉ·„(Fm70ЧyH 7Uшђ§ ЛO#Cy‹ ¤Пrю4ЭLжюoq+ИОьl5IкЈюі‹»еKЌ;уMIQIє:6P­Ф№’|ѕъсЭЗ«©“ a¦є Ж¶ЋЬ~µљяЗ?и+Ёjю{к; лнбКvОБ<я№>ОЮ^П–Чз ЛкЩт—9›-ЯыЮ~ъ >®ЯНя6»є{Mю8А„(aХиЗЇјзњЉфЫц@vо€Уzq_€”ШnЭ,VЊ–Л}ЧAѓNЄЂє¦Ѕ[Ю^оюY^-$„.Cш7чїЭ>a«ЛYЯЕЖ  Їн7я|:МЌR“mЪ‚y Н<Ь)8;јыKt±яы?(Деendstream endobj 38 0 obj 2283 endobj 41 0 obj <> stream xњ•YЫЋЫ8]мc…ЯfДґx'gџ’М%= ™‰1ѓ,Фj¶­D–IN'їЕ[Ij;AЌ¤”H«Nќ:E}\„® я“~W‡«ЏWW4Ње_Хaх|{µщ‹йҐДJЙVЫ»«8ЃВKЊ±Т%T¬¶‡«)‘D<Щѕїв’¦ј¶ЅЅъсєЭ®/ЗєkэCU­­IплqпG™$Rh‘FЭняоКa¬vµёщ‹т№ kКЎ’ЇЦр[€0е•џ6‡!CuZiZ„ѓyLgЈкБЏБљЉуlKмЈ‚XCуШіcYнќа«……§&Њs –[љЖЗ}9†уАn¦ђyе¦йВЪљhQЁ|цhѓ"¶PУь°(5„1љпЭMX“Ey¶`pэ§рЄвЁлГ#VШ<6v8flЫ—нmXvWE>m<  O†4‘RCвРЛнцЌ]s vj»ZѓУ|hаYп>ћЬ0†Ј €о€V0†cҐтK0љ‡Ћ]ЧГбliМXеИ6]»[ч§¶­Ы]АЂЏб™Џ}; ясЏ$%‚j;№xNfАЈуU ї%JжUn\B€ЁЧ/КC°ђѓS’6 з6¤ђ&?©єГ:zKqAѓ·"hЏuг0 ђIЯpХН—СUЭm„ў"КЭrtN йvёЂИMeeҐ‹ ’14чЦ‘`/х6Џоvў# BiHЋc“юЖ№6еµ1<»bdДC6RҐі§!‘Б"‚еЧ_мыz»cМ )‰ж2ыhb” d>tЯБтЌлHiI­Й6Д– !зq\їшн:1 PY€х #-б, ЃвЦЪ0ЃТK\В.лщ‹@КќKИA€9·жљЂљЂp@цїћіWALЃю‚U {љfщѓхYAш”¬ч1В’R5!жГЂ„RдНђЉ!уа,g iб–ъ8>¬МСVeпSВ©F›3c™¤УБ ’ижgЬюc-ґEh$РsR(=т7S­9ЯyкзтplЬУ юcі@ ОЕ(чМЈlАН‹..1lѕQЈ( »¦$Ў`FзCэ7B’Пгr Р…™flЩРbзЦ!mP6eW¦ 3СЖ)R$§дё¤Gю6ХJ@JћпаPеи‚ К)›§Џg y¶хи zЩ$”+eтБЖ}пК[¬\С9ѓ §г±лCЌд,µyЏwЩчѕ¶Ј—Ює* яє щЃ€RО*ДФ]‚…/©XЦлvыSXfxч„¤`ЙШД…J‚‚ ўЎиѓЕ   ’‡@Ѕ*л&1•Ї)іда©\R”І Й ђҐЮN8Ч5PSl!‚®‘*1®K©ZP“У¤‚Ћ)\—иKyz¦и‹]„)„nЙ^‡йЊ y _sЖ7йЊ> р-…IтитБ™ђѓгҐ ѕД‚ЏLИGй%%єo8нvу§P>№-° ЖМЦВbM8нRф™EAЦ;пн!БQъJ>Kч‹$t[ХiмА&НсёеMwс S|_FеrЄ!‡Хlw€mп&vЧK—P®&mЪ ]J5плъйЧ АЪ±щЊ f0=ћ @MКkДP-YуП•KаuУ%Ђ‹SkuяJmdЎ6N/Ў0^NAШЛ Фзш, T т6ќЖ}DЦY:‰®йфн@%Р3ЌшДX€©O€" 6*ц —КaУ“Шѕ€%+Ў‰ѓ¬kGш'N…Е 7_R„ёFX?wнытP·InЪгщ›‹=(/%щД®—К‡ї&'ЬМЦф В±+щщх6)XEфn„wi7ЯтaЅ¶M5\ўЯyZIµВўKл2C”О{Ѓ\ѕМ°Z~з«4. вйЧѓ(ХЂА9Љ^zYЩ№љьж¬·јnП6 Ъў›8k‘ж<.@OS\оыnМА ыЌЖhОчEyЖґ•†­U~TgЛщФъэ^Ж‚&Ню4‘)ВфiB9CTРЗў|—(ЁЂrЬ«ІяђZЈ±Ц№њ— ±>FPе|‡}).EВkVOk|/i6#}6П4ЕM9 YSЭЏф bJY{Ю^ …кf¦уРзЈлkЧVс„Ж—ЌE/ ТyRћуюEOJ39ъ(–gхЎnК2єД©еKmЇзwlUg·#ШДA—yЬЧURдаЙьаЦ х®ћ``,JІЇ–—ЅчТёtПiоkґҐщ#(пЕ'Y Ю, ыоHR"Ћk|{@ Яt}Яevѓv?>$-И ‚uи.…„+фs9AQIOjЉT”Вк[} л9°НШаP9]іЂЂ=”Q­§‹‘™›ъ¦/#г@oД ‘gµЭ€Ї Ж: (ЃR<РчyЕ|5$Haси‘Сzљф¬1€Ґпе€·U_ЗuSH‰В§жХЕ%ДЊГ.fZп‚ЦJ xbJЧ7®oтвЬ·яШлё¬¦ЕoЛ±њБW/єЋРњ`«wOв>РЊQД[єБXяЮ5щ"К°Iяе7Щ”э—‘VЯєш2T73µЅw}¬oѕSђxБ5с’™®эwЏzє{ьЅьPцс¬ѕ_°x© …а= ы‡„2)'c=1Z Џэн‡–э'ўЄЗ\њНSя1q¶ј\=M4њDіуєЕ‰–_­[МbЭzВЁ¬L·E Б­Fѕ>–эђj©с,ђќKФ¬Й>t}ѕк›]=T][Х±1аa?|ц9AДw? i·wЌЛe8IЁ?№ВШTcYQP’Кє`B©™„ъјXФ°ч^CуъЌ¬нsgњ дќЗсЋt&RѕKнк‰^/Ь•ГщІ _0(*}±РЇ«±»‰сЗq‰]8‰gЗVАЮЊі„^@A•р7Џ`ЁКрrb}yбъzМ—ї^аЈЧ¶‘ммК:974KЩhAxG®!Z<ц аЪsЩxЭот–юЉPЎШш;zООъ’І9б~Ъьўр]ч$0_¦>p© /цЃзВ$Е1}ЉЄВvэЧ–ш&фp”ћ]ЇПbь(zсЮ%epv4пј8ыФ2k:_n_э‘Л ј•ф гO~ш—нкOя‰JBsдTxahьg(г‡б1гїd=їѕЪ\їZе»«Н?+zµyйя{южьєюyхЇ«_®гZ?wQµт·сѕП?wAЭR Хш±+Я› M1ђлї(@к’HДС~Џ?m6Cwк+n‚о·uг&1х°й‚ђcђzОЎY§КѓЕґЪ%’1x›\o’ {ЧLh7ї6№ЌfЏ1Ф_т d(OUшЪ@АвНээ°©Ы»sC»M•ї…xЋ’sњ¤‚hФtыЌwU ЦюT°Е\ЗЫ„пунВШщХШжЬд»т#ЩЏg&ЗS\ф%ќ№R<Ж®ыы{r т ТхЮё‹{аtЬE>f—чQ ђ2€…а‚Oі:ѕ<}FМѓљ]гыЇ©ѕ«‹‹KМ8яу{|<.endstream endobj 42 0 obj 2703 endobj 45 0 obj <> stream xњҐX]oЫ6}ПЇ0‚YЃїЙ® РZ ¶ОЏ{b+±VЩr-№mPфїптлRІ•tй †)Љд=чЬ{эqV:+Ь_ь\nО>ћ}њQ?–>–›Щ/‹і«чММ(%VJ6[Ьћ…(LbД€™.(Ўb¶ШњэфrЭoљлз‹ОЁ 0фО UекъщE™Г·И фuЯTЧПѕъПo/ЇВwчтзЉ0х*,Џ!–……oЪХ=.¶ўѓеа <МунЄјїи`Lj"¤…ЬЪ«ІЇ^ё•#VИ8ъм«яSDгу„ЅCњ2ћз*xQ>ВKЇ3Ix}±®;Њ њЫt’ѕЪмШХFЖ9ЏOьђ$T2ЖвР—]µмэ"њҐµH‹|ц§ўДh‡Z70›ўЫХХІ /CРЄА™·юeN ҐtЖ§фш0M"„б2,*)cйmјџI‰.,ОЬ®ь`Aё¦|ь:·щu8‰}гС’Є4іmљrпЏ_@vuљЪХw[ї@Y‚х¶mж>Џ\Гм‚ тШxh,Ў…± АПU8.#Мт4xsџ8m-Её"XЪPуXўцUЧХ­џ- Ў©WoSlВ¤±›}™RQhќV„ЎАDОУШІlљpZNIЃЬ »z/ЖE;uР‚3Жс е6ќуБ‚&qЯџГЛF[ЋЎфIjtbО¦‚/эс”cTBдпzЫUыйgУ ъµ?” 4Ню6УВJDѕ9T!Ј (TШAF#ѓЎ/1dpџЄ Zќ`OH•дЄuµЇ.H„љJ¬­··1-ЪЉУ0dAйiв(  љ’HµБIЛG”*н8OЬЕ>§Ґ}Щ}с·›]»пЛ­Oђrrћ‚шЅј›Ьљ¬6 ШЛ©СXнШђ# ,9‘f$ ЏѓҐх“АZЕ–z‚%J™я‡і±Я lАV;hд7Хю>Vь)рЙЗT=4}ЅЅ‹rЎi‘ыгт°©B%`n ыpнЎYE-*рMЫ~€НxЬ3л±Д¤1#Ѓ2Z1E5ѓЄ{1…аh`T!‡‚шѕaDSКња±MЗvђ“‰ry#xа­нг|F¶ В ®Іеpyшѕз@2Iы™=!УњZ0@‹!DЩџ<Е–$©ЌKTљЄД}]Ю„цГбInџЭa№цHВЊФЏ—‡Жэъ™%сiчЯ_йБbg¤`GZJБ~Lk©1ЁҐSR M–зЁбНhF8ЎЦ"rњ&ВІ…вГЉWЁAµwТ™K[Љцn]цhf8hw¦t’`=ђаe»нKђЫИ5mpУvЫЬЗІg…ББ* %З>э@3цb87‚вvHѕ(‰]‘ Ц¶QT{Ж±g "”c»™ М€RGNRK6бNФИ’Х#Ѓйъ·kHQкc©%"wЙmъЊ!аЎТМ›Є ~мMБУhWх—qp•И№>j±ЛоцнкЭћWдньlйzљуCї;фv.€ЧРша•BВѓДўтCL§°ВЮЕT°мссp–љв~PЃЮsБ(HzZo[G©ю ЃvІoЈ=‘EщЩЧЎ<ЎE‹7„7‹ЯЮщ@Aф¶Эoвu@кlЫљКI[В dт$› BЦВєѓKХ}\ЮpЃ·•(ЄР¬Е”KSGФ f®Ps°‹K«1ЖOu{иљґ!ҐXєpj0‘+П &2KyќL$§jlв©»YЈiїџЦS 9 ^ќ?ы§|;їєЋЅMО.T”wЁOФ’РЇU„E·ПMѕ)»uХMµЗyљ8‡\К°ДЫDQБ#мгTвE¤ЅнcQ‚єе†ъlvg8f3s]:mu·o»ЁPюijWЕ>\ё }x§}ЩДꄦ€¦Оэ°:ХЦzZ— Da¤}{W·ч‘ЂpO‹GќЃЛ®FrOЭНпкL4ЏЇлЯ#µя(аhе·°ОGЪњ bP’аrIеЄдщ иЃ—/ИџБ~=%О.Gщ§hжлIЛ †Х y¤3Џb(vрЕІ‹°мЈ>AeЖ2нb·У»кC9»Њњa;uUўuR"[уґЁК­ъуєSэХщ™EKЙ|ѓБР•ТЎr:юЪ@¦АЛh1Б”єrI3~\№с_і?ОЬЯїfУП$endstream endobj 46 0 obj 1706 endobj 51 0 obj <> stream xњ­X[OгV~ПЇ€Ш•‰ОэІBHЅ©]iU©Ыј•Ju‚!.‰ ¶і4ZсЯ;зкK j«Љ`|;Ф^МRИЛ6+J§љ3„©d 7uо}Wх4лl›ХУ ‚1”И!nЖ>Yp%АN†Љj%З°: ЋA 2„ЩQ1bкvG6i(оgдлP ДиХбНЩ7eЄUN±pLУqё ‚j•`№-\%Љ„Є®ќК>Р+с”а!“d М1AЖ¶№‹а‰§Lf^]KsKОeЃ$Џжn«кaя8™л–Iqј9w¶@Нvu№фl4Њ!„kїmЕq“Ьо3ЄЖ2е*џ¦ `ДgjШ,(ЖlІє5EJr2Ёn€OоФ3ђuљЦ™'b lБ‡•vЬј6NЙEРўxbоЭЈiO‰°AҐБLЬсп‰0GЛAGuГmў!«ўn7NпВV<ђђЕёХмrЯд5є­V‘%Уя;Я0РЌ‰™sЬ™.нh6uУЮь`µtG#`W†эчEбATУЦaъДcnўa_|±*ђДhdЫ}ћ:Qк„>l„-$Ш…њЪ!)еоз$#иwФE¶ s ђNї9«кРњOхZAЛ®CL8Vo `‰i|© hјЉ 1и0ҐЮЏ6№щЅM5.Rљ‰xg)Јмzє”1wtщ'#ЮаКѓo`F§­a>У]›ИЛх¶jBJ‡ЊъЏGЗ)K‘TшўNfу“"@і®u¶~Ј&T^љ^Y ЈПI?ФµOє+>1°к”§dЭщцциаЙыЇоБПЩ.9ща!Й‘T]сец†ж·tмчйbў^cѓbъx .gЈky дoТ8,Ђ+)®’Ў“н :Мќo УSHЭџ›zхРLZg`ТM‡NЪўЭж'S¶ [[ГY–ќЮм2»lUДцв/ЇT‹]:OшPн=H`Ў24Нм«ґдh2Z‡`ГљЂХ«+Х&ДЂ ¤QЂнђ)°Пu«Ээ4Ц№ќО№ш?Боcп®“Ьf…ЊPЋЬ‰p1џ—ЎK*jZ ‚џPбa¦њД;>MЫLw›pna›‹Чрc^ж5фYgЄЂеIt3|µЮпмов™bСA›—ЃРi.LFђnJ &Q;‘+2ЁҐ!Тa’ЙPњpЧX>–бhЇМ}“Ю®Рж°Oѓ;Ѓ‰¦ЈµсЁ6”гыпо*XNЧ“г94kЪ€йOM —Щ Eп‚сXWk h?M9ЉO›ЊЇ±%¤XLУю6OађtЄщqЂeШ,F»3]ЮПчХ¶ё~я5й}№єAИ%wVѕЛao;ќ-Ff^]Zл'PeО#юФBQнЫЗЅЯв,}‹-{vЈ КТЧЈЧWµБjЦnЉ&®¶ОР‰нe…?,зїМмПЯe4±+endstream endobj 52 0 obj 1697 endobj 55 0 obj <> stream xњЌWYoЫF~ЧЇђЋЃhµчвИCZ ©уBKk‹-E*$ќ4ъЯ;{’”i;` »іs|уНЎЇKЊИ»Oьї;.ѕ.ѕ.‰?KяvЗехv±юLх’d„ Лнн"< D‘жK… "|№=.^^ќ6•wuС7mi»ЧWлУжrыч‚jdае'ёЇ6— В_®ьЯнN«rу¦нч­“Vi‚ќwзеоРьcЇЦ еоWI`ЄаЪ¶uСоќ„–c•4\5|†зйЦ=wЕчo‹¶©ј}‚cй5·M?2o§ЖЯ5 tшсРш»ўyN0F«‰йµѓ.Чџ › ¬ђђЁBLzЙNJ"® Q{гe„KПl±;xР%"TТtZЩЈ­{wБ)ВЉ™xQЦ^C‚лtЦ¬?њ)I‘TeЧїтЉ)">‘}А‘ЙЫ·M›ь:ЏS$…L’]ЂeO 2Zй|J:wОАЄШSЮЖx/ј‚(# ЇaЕ4CРТшНќ ¤ё)¶ўєчЄ)s9ПЫг©i‹¶¬|ѕ…ABqq'С3pr™ЭЁ‹cРmђў4‰Ю•оМ ‚µIцўcZ‘B¶uМ»–$еэЖ:ђ=<1“a{l‚D&эu c)?uЈѓ°йдЃ«Е·жѕ-OC‹ПУЈ©аjP@аЎФУЩіЋћЇО#ZЗXCT<ЖУмLвЏzЖћЖхееЙ¶]гУ$ЮіЮs•ѕѓjktІ pгЛeф‹!ЖН/ЃЅЯьц3XC®ГэAм¤p$tі‡LD©‹q#™ќ1 ­«з† »ѓ2А6udvсьрuХ7G\_ЊЊNР›+qr№тJ_DpЛ KUW„&'Y–:]дВкј:б5З2ћољє/К:'sл›кU"лuѓЬЫWИљфоЉЄІы№AZ§6€1Ў›y”Њ»Ђ(µJЮ§ЕДQ0ч•сb{dЮ+B1>и –?ЄЖ\|В#ШДджrЋ9U”sР9¬¬фoYЯщb.ЂЎу·ЦЖѕlTЋ«@‹6¬+qќбятrdш¦Hzњ–ѓ'Е«9=nOґЇ®9EРс‡ќҐЁgу>pЎO|ЉоE±tл—1oђ еzЂ«–"—9Кsдo›z_цeSU7gl•Дab р&V“[fv рП–г€гК ћ№УлЅqE‘Gas ®¤µYкБАЬRвSBВ&іюыЎ ґЗ1¦мњЋjhч](@аћЖ™{MцL8Е9чеm|Ћ•МЊkвF Г™ 2ДНs[“'|8Ъ>, L*H?·ЩньЋг¦Т)°ен,sЎ\Хь’п8=l«¶л».TҐyјRs`Ю_бљ”LwЏяT‚_¬T>»ЅsЏєхvp1LнОЯo—.ЬзІ§Є,endstream endobj 56 0 obj 1349 endobj 59 0 obj <> stream xњНXЫnЫF}ЧW(сClАЮмэТ6R  фҐ‰ЂўЂ_hjm±‘D™¤rщыО^IJ”фҐ…aаewжМ9sfщ<З€М±ы‹їеfц<{ћ-э”›щП‹ЩлTП AF:_<ОВ ўHу№В>_lfЧWХгНвпХH*чФb9»ѕї.v»¦юl—ч7ожб€В]чЛэ‹UХє;L -u|mY—ыЌЭvо†дH0™\нС&ЦnЏ–Hы/сX7GKмцлЄ,єЄЮ"'U бгtyГ#WvЭZwП‡юЇS‚ёв)Ф/EХUЫ§г‡CЕ:Ж„1Тdёч•Эъ_ lT$…$EЧб&3йЂєa"ПБeЅЩMХ†d йPњ%\пlStuВ9Мыјt_&TdрЫ]ќчzу滴кgsп@кЫ©х8TCг„г‹пY/:“p–рШfkв07р|ѕЁOlлGtћzЛO“»є±Bмк[ е|(К5р'R‚х©ё1*JgъюvъМ ъ™чнT@®QЛЈ€ “вЕ'hE]Ф‡Г';^€&ыЈ>ВЌїўp'¤zџЦUyб(з ¬зf8ќ@#Ы“™љv2?8S°ј…?C·?МRё5…э°®ЛOmњ…аyМ¬Уp2ёmп\<+3DcьЊљџ2л&°к fЏЕ@•РЬ–•ы Ж Bд$-х«oыizРИF§Є“n=iKwJD 3ЮEѓZћъЁІЄчMlє8OLo3-ТцDEKQЂcCтѕЇлe¤KяХВ~†бeыфВї#0IЗf“‹¶Жs»„г’?M‡ШC7ќ §xNoлz{Р…O2“«mкжlrqС3ЈAWtыц‚РGОю2_Ж¤ ѓ¶> stream xњµXKoЫFѕыWvЂ$@ЅЩчЈu|(РўТCSЅдBKk‰-E*$UЗтЯ;ы¦(9сЎEvWуьfж~\`DШэ‹W»‹ЏДџҐ?«ЭвЗеЕ›чD,GЊKєXЮ_„xD‘ж … "|±Ь]јўHј^юuБ(ў~ѓЛхЕ«?м8ЦнЖ]p‰$g&^ьгЋВRqЏЄж`w :Щ‚d„р:ЇµЂяSЅё¦qо/·6<…гЙSx@ЌfQвХ`ЗsБFЃu|4ЊХhw¶х/№Ѓ•®ЄaЁ7­·‰iD'йВid Ґdкђ@ЉБ'№SК7,ќЋќ;# |ЧжiymµіИkжH+ўвqфыШПgл®Ѕ/ %r&ЪО{N@=У)o1p2De2©nэE†gЛЗ`ьўCгбєЅGЧLBШ¤\\‚\ибnЧ­mэ’МИ,§ЈcRb1“nГ$™±п»M_н|є\д¬l+пЕHIЛk/B ]я©Чvэѓ·$€l…·љ`„MOыХВRФWUcЗ$dҐ †уР<2лIhBѕ¤&ЗXбђ…сХ¶j76„WёВ4>јЎ,кq€Ю Гжй  §`Б'В#ЊCаљџ L©g"МЁ,µ·»Є%Г)Д1Г¬nGЫ·UJV ” Bњѓ•*‰O©шОЛР”\-U»ц¶ДIFwmуиOв№Ь¶uгe30ВdQб5S`H ц‘‚Ђ\N±$яОЖ~G в§мlџк„еЁn"}‘вTⵆAЉhҐЋ5a‡?]LnO}Ях1њRжаoєqґ-ЉX•2'ыЅ}-ўЌеqZ СР“ґ(ЎOЎіUЯФБ=‡^n’Ѓ6Ђ†JSAЄ –66TBHzЪЭЗиГ)8]]µЩ›ЬYюц.єBiv|¬ољ Ра$щ1цы.”$аNC]$$_$ґђУ‡Р€)•ZpЧQ,њОC!‘)Ѕ«VoъоР(zsІW]Уъ8"5SьИu€3ЊXх5бЎ‘.ЬРLцжrЧіјHQ™/Ќ/ѕ1bF±Ѓ!Wў|gЗРU«ґLсxґMУEђ)иБУ0Ѓ §YbDKB±ЌqЉ1DуПяЊ`f„©)V`X(JrЈлНъґ’zђщэ№{MЊoрЎЂ н_ЯЊwЭъс6¶Q>с9u`ЕЯіj‰0VЙо·Q 3ЙмKпбе‡Ч>°Д!RQРГ44Џ+ЁG[­¶о^BKayљ~xµ·эРщ  mЎtКФКrљ7Uї†ъЭЫЄ')ѓ°`9mю7cqЄLFдЖб®{щвsсмЛеmб\!У^w3®o_|†!GAѕЬјЃЈѕе»Щ›;.йСЛЩ]@|ѕјО HКЮЊэmґШ… d_ХчртИѓo¤днI°f9Ѓ;нrт'ЮWЖCЦЅSk±Mh:sЇяЬќСдёЄџё'#WКњфѓ©®њЮ9’/!?ЗяЧvХЦq†HкXNєZ¦ЄV2e'У!В^j<Ј—Ћєhх<'›СЬMхй¦рѕ‚nЪ'®'yџa¶xV”§ИЄЫЗ GXncЏЎсХsВ#іјЫWCh±`МХdPЗЩOJ7 ёО<µ§иУ “ ›к"KГBҐУ8?!дСўе fD2УцЃ†Ae”}#±њБЏPгHЙФЫ»CЄ2ћW„U °e’rі?¤]B=#сћZс8v"иVЭn: PkўrЪї.хq«„3Ўз»”d™Вv_х‰АБп©3§ЈT ъ„Q:Цћ\{Ё'юВ)l ®/.¤…B3G® s> stream xњ­XЫЋ·ьё_1ђ Xv(Ю/№<$p pG$/zйќйХv2©§G«…ЎO‘,»gzV¶иa!»XUзФ©"?,8 ябЯхожГН‡…HkеПz·шлкжхЎB°`Њ\¬оoт6IжхВqБ„^¬v7ЇЋнpdЯ®юs#і>hШ¶ЪЬјъс>®ЃпґВµ§Г)mіТ[\|ЊKћ!¬ДҐf?¤ЏaХ‹І8ТљbЉыЂkп›г1YФМ8оpхc\2Мй`Љ7НцФжќћiо<.wыlUJf”+V›ё2ІњЭ·§cs·mгZЃe[,ЫхРцсе VъбpЏоn‹cC»{їm†lЖ0оTЙМъ°io“'Ѓy%Лтйц X 5;qi©|B/–B3ќЦwНє?$#К0/)IM \H4yІiЏлѕ»k7ЙПњіЉr‚Ыe51'ґA:7©а‹а°vнXаєхТIТМЇдЊ Mьhу"°¬jб].R \®rf“б±pР®ji…—DTф–«+!{fнHQQ‚§ єб€NЈдё)Eч(2Т’кчЭ»‡ЃЎ2J­К9Яз‚Ц.ИR ‡}wµИЪ|ЉЂL‹џЁ»МdНБM*Ґ‡¶o1ЃАЫў ]цќзUfDњб‡8YОa‚5 "WkцюРпљњmFx™й‚фЁйЄBtҐј<РzЬР‚ RЮ7эР­OЫ¦'ґ€вsЅч г5UХosЅх®$ы]—5QрЪт?–mµц2%#т•~µ™Ni~jі‰Т„юmFYЊJwwШШ ґІЙ~ѓџK#jтћ.зЪбюґ»kыгжDa m€YЭД2рbЄ РЅ$Ґ.гъ ц6Еs›Љ#ђ{‹_ -«ЈoїMђJћ¦€¤/?жМЁ~р6[ъ№oп»Oш)nшв—pШмw И!kфЛоЪ:1=сВх?!А*”d Ћ†#;ХXы_В¬ш|(‰TРг№.зющВю юЖE‡Ь"r,?еXѕ9‰1сЈ:}€…Ф“щ@(і©гДищyХъ( ”13aјъъ—H¤ПЛЇ%й3ю/ЖЕЎzCЎvЬ·!ї UфП}Ѓ“њMvкЦв&|Я\м}ъЊ<‰н1LE?/n 0"иT1Vcn®µ\©ҐP{nO‰‘;ПtџЗn»ЕiДxљ-ЁB_y®1А8Цнq$ЕЄ­•FbҐэYђNЉ@ЕЅbҐ’Бя8ЯTT( Т"ЁbѓЃН‚єЫ,! ®‚3™uД}fbд|nbФ–›з"‡=ч#®”УУGsКCsL°iNЈфєЩnЫНјР9ќ\zЩєф¤„ѕню‹Й6ћъT{бHi">вTtИW’Шmйэc‹Ѕ2в?‘Ј#Ох0л№ «„=Gt§щзиЪзбF›aЧ-ъаaјz®;СиЌ,РА–ЇЃ9бI*рк;с жјШґк,-з0L/nµOНЎyІ‚tk<ШxMЛНЭ{ёЁ™ћляу-UБB…±@¬ ћЯ¤|ЂЁkFњI6– ’E}P$Зэ6оcµй‚bҐG6Xнј> 5ѓф#хЯ‹»¤ФРbш¤ыяҐЊ™‚PЇY‚б[Ћ’—зИh8џИЎЂЄХJуc)Зn jЎ¤д«о8$ЏmЏ•Ёsf)ќо{wЉuDq\Y"^)&ѕв]к)шI…њНЊeѕзrфВрjiљqi Ќ1эзyЎ‚ћКT±ы sЯо@–»э»Д ¦B}ЁщB„†§›~¤eы8ЬЦќ·вјЬ\Ѕ€нOЫ-C‰u5Кk‚ЁЯ’ «кUSжаС5¬ны|e‰&•’Пњ>*v§Х®‘ИCUyH<‚уй”fГoиуr­ ТSЖЕѓъё‰|>“}|л‘nRKeлЪ№Gµ)SH¤їо аpХЋ в_i°‚@Ѓ¬]|€)Ђ«p!ЫБР»DyFщ1–дхК3’*j'&ПHWЯ аІDпЧ†ьь@ћПЇР wцв®vZМЎmмoЧf„otW„:єfЫagїЊ й»%ЬОhяЬ;SЖ#№eaђ—ЈЫєe%Э¤л§5¤kNЊ#Тџ'5bLЕkOџPЮ LyO6YП(нsMvж:… ЊЋ”иКѓ[Q н) яFБhЬ€с(№>њ¶TIнyїPZё¤ЛщudЗгіЫРоЇЬpЎЬQGэшяtU{1ЯVЎчxБгУW–‘tаo«Е?nвїя#Цnendstream endobj 68 0 obj 2027 endobj 71 0 obj <> stream xњќZmo№оЈ…ђMШ{ЛwтЉ~H=\Ђ^ЇЅ( шЛZZЫ{‘ґЋv•\Pфїwёд №/RњА ¬Vдpж™gћкГЄ,ШЄфсяzwсбвГЉ ПрЯz·zs}сэoL¬+њR|u}wѕАVЊ—…ґ+SІ‚ЙХхове›cякъч x®JБбҐлНЕЛжО?cрLiџххЎ^5EйJ|ьЙ?І…bLг·«nш¶(Хџmuµщм?¶ђ† ьїП9‹Џ>ъGЄ0Т)‰oљкv;l/аОqЇuµЭЦяьыЯёНЏ,XaИш]»пюyЁпљ?В»cчX^”Таюн±пљMШМFI–\0њМV3ґ`W­не’WB©BѕєbІђГЛП»є_2ЊuҐ=нТцёЙe!8ѕ·~ЁцчhfЙ•™i$™№дФн1”Ц |ЪЮНЈ·ёbVd*EгЏ¦л›э} “.™шbH‹бeWhSєшЙНЛwн®о›]=IЮ-K0lєXaЙ»жюap,8І”Я6^ Ј k†0xw{?Tцє(­т№=ЖҐ ·ъ Ач}qуjxОЇ 8o|3]h-(HЂјCХхB¤(4зf }H»sA!џ%_7ы¦oЄmУшKG”’>$і‚[©З[ъер^д°Џт©й–0НEбЊГH=яXNАY’WЫэцsѓЦ…Y6њ@P‘о„™9Н~0SRZGhЁђѕ¬&NJ) .ђ8ЉЫ&ѕМAsУЦЭюEt•њЂ6`ЇаВQ,«»а>gУі»zќ,`ґСOІЊАѕkµSD4ћS#Ґ*mмSQ 4щл„(аqIйрPEіJО&›yіР#5Ѓ$Л:М$pїНcШU»:f’KGШгS игияњXбu¶@¬`ЛЈш¤|жР–¦ЗъўЌxЅсDoЃ= ґ(†нWФЌЅoыѕЮЗМh‚уєЋ©_J1qдѕ+З'А$еЦC,ђ¶‚8eЭо·u_oЉаи!М9eэЉыЪBK…Ц e1џъ›в¬я»еZ g•ҐBЮ:™хPE)лыбаЊзщ—(k`, „#)7ѓ1F=ќ ­МИ0оfJ{zЕЊґ'(7sўHјїI<ђЃвLџъ‡9Ђ…тT‘=а@ъШ,{ИKК’5ЈІО$… qnв\aЬ_Ж”Мк©2QR]'·eЫ/Љњ%¦®<`Ј Љ‘ЫoЫшэЊd—РW@01®е ќhб°x—;5/|EТNQ¤їў¤љ$<±иAн™VLїв‚ПYжуXг|VЫd,H^ГрнуVHⴈЮнЃЕ, ­В”uHф-ѓГ")F,—Мђ0ЄВCOОРё®ЌЎv¶jTј»Иo`oЄфQqqhKhaLPxЁїР:$HюґС‰*)ЫXi$\йI™Ѕёkй fЃ] ·±K»ЇcЎS†ё№ЏюѕЊБСI]ЖSЃм3ЊМY-‘wЛMэЭ››љ3€Е.Ц#НH5Ё‘ќ—lК0qr—#–е¤Зv„t"т‡fэђ Ў.ў~Ч«l·ЎВe Uа*<…Г№4©е(CGнЫSDeZ­Ќ((S CУ—‡д‚шјй-­БsїMZG#Тк*њwи±D™ ф|/и?Ќў<ы„9в)O.tБТ>К^¤ђP€Pfѕ¤L  —*#С¶CВФУ¬»ЊфГ),ZХЗІ5ґL(ЯЧ±®шж<)tґМdнc bЗ”иу«Эц:КvaЁКьJ „СHЅйЕю\‹ґн¶mЯGњрrЪ„шBд©s№ и4y4R4$=а[¦·«ИЁP=oѓУf…П7§xШ®‡Јок}?PЧ:ЫO“ЖQ)Џ¶ЏКХIНxs™•%.IGБtЦЪј Y®ѕЬЗрl,иeРULY87К‡}"ЃQnѓrs‰xтжН¦жm”NТ§*љqv©еh8С=,ігт‰Т%JН”юi€!‡/кГі9«gеgQМYW”yО‘;3%тСЧ“?YКµFДK|“…„ K—ж›Os((…ю¤;!ъЖ€‰;Ўвiбf>ПxnqыxДj.•ќЋF Ф]»Э¶Q!Hў”OЖ#‡n*УyЉмO(D©3>ыW Ќ·u ђЃ<¶Јj‡"ГПRHґж4d4OЌL;џ~Ѓ&КXђуЙuj2EйNф4ҐџЩe= ’Tє’Имжеі,лNµ,~ИgАҐюґ€a`°$•rЊ@:oВ,8#X„„rCХЖx-‘ЩЎЪ.ХҐе7rш btю’¤Р™¤Н›)d»Ў H@tвЗ¬Ґ“3<йSC•еCAзіЭж3бк„зьrU†’ўњИ‹lK'мЎ(DяTf›>–x„Пѕ;tЁуҐWTОжа»LЌл„KІЛ7TШuRR¦¤ЩГmЌ—)@цј$7…qВ0?ґёк}ЅБ№јљСX,\&шQ5яЄr< ‚д‡,e9;?-ќїP.‡У НEЮў`мR#хХ3кД^сT CЄП'JЁ!~Pт1›ъћ‘/]&dЌRтM­ьDкH@4Цл иўѓ»аш¤ Ґ?члѕiчЛ=-ѕ›хґЇ1=µ©wqЌHoЄФIyаЁ’Уђ+\}Ѓ©О’»гг㶉чEЉ‹ !ЌАНиАeљhj›ДO•жДжРёaqG@ҐыЕмН4Ъґi¤ї©ъЄHХ…M„CRpЖ§ЮA AoNЧ6‡tyЎЗ¤вu"Nщ рќMFіЃтЇ·їЧ°ЗрІ*К¤Тџ4[чьu‘!­ИZxt(yФw‡R!І c>Ћ¦~;D ђ—к‘ї'»пв>єd3p]лs·ч™РСD†„&ЁAиўхqw[pxкBxЖэЂЂЉљ‚ЊъПшсѓОх_ЫuMњИJ…ЫОp™Ґi<5Ш"ЬLѓfпЕ’+Ђcу:2Њ?хRnAР-еV_ЅџЗ'РYhБ§і•СевR_DЙ*@sў‹Zь;j}~lwђCBq‰+ш[э"E: зџюz3\bГяпЭјъЯўЦ±@љШ h ё;A( УЯ0ALќа№K~Пl“Я0НzeЁh‰-3[— µ JљГњь•ЫВ&±ЖлC¤ЧѕvЂІ§хЯЋбMчioЄ=ь-Щ"}»БGќ»сї3rж-ЙY*д}lD‡ґ°Јўќ/ьi*yО SPІЎ—Mа?`ГЭСЯ®WяєряУШҐќendstream endobj 72 0 obj 3038 endobj 75 0 obj <> stream xњЌYЫЋЫИт8/щ $›ЕЄ—}пvћv 6а €Ј И#GвМ0K‘2IeмїOх­є)r?ађЭu9uкTйл®"tW№сягщолЭЧхПТЗуо·ГЭ/_ЩQJ¬”lwxё Px‰#vєў„ЉЭб|чгыб|©ып9ьчNj"¤…ч§»ыъЬјsO#VИшфЧqnЏOГпЌы‹¦DsNгџюTџ/хpR©фБouяЬг_ѕP^љґ§V©ШnП$Вїэ©woRAЊR:ћPџNнЬ}<Ъ“Оћ‡pоЌ«‚0e’Нtь8џ»-dEё¶ЙьџЭ+ўbt:я}}оо1gр&MЏ›уҐ«з&ЖFiћоєЊЮ *‰ЎаWxшїцФLюђЉTF¦лж'µD љЮ}єОБxЯsЫ?ъ‡†(YҐ®эС…eт†п№Ё ±r·чC,џџ SСz&Oбј\єцX§€JI¬f"юсЊў¤bФ$ьkђ+УM7\љ1xҐ Пр8Ц}тЉ§3.ГдПеЉРЭђ= Ж1МЦ№юЭ{Za«Ђ&d†iFУ{u°©в эЉfjaeє№n»ъѕ W ў•Ї\=ЗґNп"Ёф¬М*Ђћх`•Кq»эq1[ЃЛkurб__>пя®љІаЌҐ3Kя¦y„¤“MK(„Q g 'Ж” яuћЗ-[Фd¦c} v|§ЙИйТЫє‹Y­ёЕ¬>Хc}њcЖ%„MbШЪђp™-B<’4—Б·yгЅaэмѕ‰%D+D`Ы»л©9y“!лЉЉWnЏ\њрср·ПС/mXхјЏµЈЇ„Ї1gЪШЮыcL¦@\зf;'`•®аµuN<Ё\­“СН·№цyb 3Г|“%©6Г•№тҐ›№“_М №Н#тM№[ѕ—JHЁЫЬ ўШvоЂљV№[њPчлRоny~ПЎ+Б К›}h· НMj•Шs;ЌF#бќ= зХУзvљ·NsA6qПы!Сћ И{[ј9О> Њ.8[:н:2:ны1…ЋЎ0“[Ч]}ИuVsq[VRa‚yЗtаЪП±Щ@IҐkЪ‡hЌ¤ШДЫ9љЈЎы¦gSяgяJJT*ЭнuЃ 7h$dддв–pљ;С¶M>5LЂи@Ё|z€PЎT¤ЇS5PyИmЎ®ЊcjћLzјћ›ЮЫ-’ lшнЉdЂ5є@Qґ‹RЖи*VѓvЌН|ы)VќҐ«l›Ж™…q$V‡ЎЪ.]†"—.їйФqҐ,[ёмEСТ_».ёЌЌЎкzС5,Qkђ} uО!Б:iХm6Ѓa)4Ќ2ИgЖзvjьЭR№в”w;y‘п^#f‚>Щ5ы¦k’ЛH\J]Шѓf8K–‡~®Ы> +)њ°ZGЩ0JЯ;еzb|~x qvІ–mЂMЛІУ\§жбЪ­uЪГ0Жd+јтФФ]4љѓVҐИПньлbcузФh$Л”|№ъ0(TЃmйMwљўО4V G=GMfTµz Щи©~›xЊB[Іњуµ›ЫK—µ¶ъжsЗy)uЋу¦€*ёЮАUЕсЎљ—9&Gk‡ДV А!НA•†(¤QV{cаOЄ2ҐбТЋќЪn t@ѕаЛЎobМ¤ьm‚#wЂ P#QrVАWZн5„Й  Rђ±a‚s‡L[}jџ^ЭЛGЭъџАСјирГ5u€¶ґьуШО)hљБЛ цЊZGЫ~ЎЅ7ѕџЛ)KФy гэчµ­Уu‡kЉµЎ*ўё@™3Ъђ@у·хr+*–хуГO/H2ћЕ{ЪfkJtБvn: рЎK \hЎА†ђўЫђ­°Ў¬Ф€ОВwjыШ?їѓЯbZЌa 4_љ‡·rЂзйю&б%ЏQ+ Щ ЄyEx  ШЦ<цп' —йR7к“ҐuQТҐRЄМхsМ№&*ьцfaЉJ№Кл&ЬxЃ­«|Ж06л“ќєMkАЋbbµб(&њ8ЕдB}гўjЈ»Мc‹XYЪу"L њНИц,EЇpЧ2НаQv!ЗЊ.†Э *шJgмJУµМmуR» аµ е s/ЇР2/е”›хZУ\­oШ«нq”ЁС­q¤РqГu¬C®яTњнCЌ›ЕRе{И€ѓ*П;‰cLоGекLзSЕДўnЛe›06<s2>PtC?HП†ґЈ™1Z¬3+ЃФk‰gйыЯвЫvћљоБЗЉLjм¶—aљЪыо{'S2сжFТ‹Ў,ТЅ(`!ЪHyuдPЛ™бQ.,tТҐUVae 6P/oPQVФb№Т,Ўдg· пV&,д<¦Л·] АL±ъ@gИ†hе­©жіXcsl’цpЫж%GБѓЉi”°БNґ¬6Їн7ц±П  8 (еШoЊ¬/ЁЙш С ЈРЊЏ©=sѓУдsK^)МСж"#‚UX|-V?/иё7 еЮ єT¬2gѓ,ИZ> stream xњҐXMЏгёЅч%Б@оЕ+~““S6 І  l` —ѕЁm№­Њ,y,y{‹эп)~%[v;рБ)•ИЄч^=тЛў tQё_ь_ппѕЬ}YP?–юЦыЕ«»пяНФ‚RbҐd‹Хц.ј@”„«….(Ўb±ЪЯ=ьйqх_xњтЙг”ha%јІЪЬ=ьgWµо)^ЛТ`йF4QљQ‡ЪКЌБ»Ј&ЋЅ6uf†ЛXЮvMУщaFM1_{@ЎЌcГ.DUД4 ®›®ЇЫї( "MКcХВ+}нCIE [¤Џv[‰.”ѕѕЌ~(‡ja>ъђ)­T qМ!ФEЬЮgя&1КJ‡Є0D%>фцкc " ЉKlКnґф\п№SJ!` 7ў¦сCц` VЅе 0:i4В#Kќф7ѕЮ/„:gж(ЩЫЁfRѓЎ \•”b‚їЅ‡еѓј¦Чэ+*A”-Кc|ЎЅ“е’њ§ ъЉ.PН® )0R)$S(ђЈ©ф,№a.MЈ]kї$85lRхї¶ =аџ‘ 9Ј•_KЂт<ђ—|Ј ьK± нbьaLїЛqfdµK$їтr¬ЄTWX.h;Jqя)>ќеy†  йЦљo"ђЋЪ Nё^1еД•$s"„ХдoЯеuґ.iZ&Нx?wЃFРl йзfSqЊ! ЃІл*RЫъј3й—И№2&ўpё»вt¤1цZ•О·Ў99›®JВDZ*`@Tz©СmC6\Sґ}a•РЉG‘o&?7»ЗзDМQ|©Ы6™ZKґQ‰сQБ8Ўfк[гЕсЋЬЈґZ…m3/BfЭК5Ъ6ЁJ Ѕ‚8« _ёеЧ]¬PqЛщЋU_ЌН¬ъ°д5uТ;&оOCЊC­’УШ icw°д6™'ЃрZG›¦€Ц4}оЧ'ШЦС(pГ•МЖCЊEїрЂПOzШ«‘х[w{tОСж#®щЬКm” “ёz<ГШі3МфлcЃ0hкПсu`НД›сЙdШEuёРоz«YШлн…ж<=ф»охџQy®ЉтџKвф»_Ђ‚МcЊыпў†ќXрчєлд›шUОн4wп”ЅпоГrњmъЏ©w2@Э”Гг©™НЦX n¦АзSЁЈF"Іahґ»cqЄhI­БsgЯФ/»Ўy‹‚Ў2ѓ7uRЊ"¤·Х1Ѓ°ЗРвФ-Є ‚јГcKazАЯCµНМЃ”ё’Ч]=Tэ2&а«bЬQe$L`п9ѓџЊUб>$¦xжЈУЮU6Н©AЩ\є»ЧЛЎт-јkI!q0ћOcNбiХ‘'Цд#С¬–D» КЋ)ЮF<ЛШ|-м°®!µb‰З»–!ё5.у—бxs"БcШ”„Рmq№ТЂb l“«1[Sgтz’e7ЄЙе…ЉҐ№xNЊћ?ў>cК6­GъиQхяЯќњИЮw$«ВОn¦_гМ‘нg`I27Зw@cСC$ЌpьA5(џ»XКovЈ°,w%ҐЗCБ~§-ы)2ўЖ.а†—ЊL”ьж-O\–»DV6§$qZу©7№}5Vг‹c8Ќ5s хZйЮkd–Ы.ІМЋо_6›zЁ»6Р$EhH‚B%%тЧ‚ммєhІд«€лѓWбђY°sЈ”я”d$7EБіА^Є±-’"к|‘т5ф(DБ0їЇNяЈ3aЧ\&9{?IT&Йѕьќ…°Ш4‚ћ¦!cC ф®йГГЄВyBо>ц)Ш®КЧqЗЄЬ”ПMр#Вр…з іґЌhЇЂЅ ЫС[w YЧо|8q›.&ФC‰зЉ@ЎB[$л\h“•Э‹Ўзії‡—жґ e0p щ&)Є бX‚9у(s7p>+ ЌAх€ЫuдU&©ш:\©y7Аzh(А]`q]`; ™H&iжfх№\о›ІЯэЕWХк№ 1 Cёыx9Вя|—IЎь-бљc§љs·Яzг<Т=‘п•bЇ;Ш’ѓvLf†cц+тB>E]%Р ќщіТи&©p3яX-~№sїя”endstream endobj 80 0 obj 2051 endobj 83 0 obj <> stream xњ­XKo7ѕлWpЃЪЃЕтэh‘CдP —¶zСe-QС6«•¬]Х1Љьч џ»ТТNQ>Ша’Г™oѕщfиЗ9FdЋЭOьЅЮПgЏsвЧТЇх~юуrцГпTП AF:_ngбЃMi>W ВзЛэмц¦ЮЮ-яљQЌ¤r»–›Щнк¶?ќнкО}XД/ Вч_џm·Z№O°в¬я Fl»№ыn%мвV…$џ/ЁBLъЈЛ]ЭщЫ8ўДxЭSЭ4~• ЎЌЋ«ЗSЭцnщ:*ђ`"оgВћЛ›бћГyЄыЭфЦцc0К¤ќ­хkaJ’OMЭZ/s8Аёф—,€dЂЌљ/€Ш0DЭNFе$щшю°ЯЫ¶пJБ,(2’p(Q$J7oВN®ЇАd†G“л`Іd‘Kр ЯЬ”аY(Ѓ°Дtњ›±—‚#)K—U­‡ЕАbrаБFфЁ$*ЈЧхvуTXшм*6…кC·®ЋuыС;aА5–Тр~WќЄuoOЕ|/ A :†сПќх~3‚”Lњ;»с\€@€qµ©БpХ4ПоЗ€cMs-њЄ~gOЮ †y"Pї ёP†ГЙTh^hќvЦн¦^WЅЌЦЌaйKD gВщmаћ 49сщXµ]}р›!їLeXЮ1В ќ2№P№%ЁZ–Пw=ЬоІ»є»/qFЁ‚lу»JябЩпM‘НLa¤©E‘$М$wчзО™CeЇМ:v„ьЊЉSюj…GЁ‚µdµZкљЄЫэXtџ@. —гІX­рЗНї‘ёw›MЭCЄЄ&’`F^ЯD n(NOvm7‰ы 5B;bЎш‘•LРagП¶]®ЃW,q :D5"$Џєz ¬+ D,3vЭњ7jёg_jп $Z#-CўѕВЂ%IQзюxо=йDњж’«єX'Ђ·єrС[x46ЂЦъvЄснЎi|‚ Тт џ"ҐX–±з &-rSx±9U81s\±ФЁКВI!`z1N^О$Яо2њ_„ЕЇCВЉJ„AHаџЏApА!Yжb§IЇЉ‹Мя/е^јР4ф"p&Q§P锈"Бю>*nroЄљіќ¦ъ°-Ж{‘Јярe4ђ=ькцiWЇw‘э L)]#Н#,ЯUёѕ^м%РЩ8N&sгa\їўЂ Mu іѓК–\_ T›Ч 5]¦+Н1J_РULйъGjHеnћ6Џиъ.NfZ в•Њx•ТИ`•byHѓб№Ї~¬CqЂMmи0|жЦБе¶k*k( JЙkХ mЌeЃ^§Ѓ%6mЈyКа·J›+ЃєњRcVЬщhўҐWdЏПOГґ‘Ц§0±AзГ™KЈСIrqy- 0ђiњИ=хэfФvQжa1y&Ќ†р0џ<6ПС Ктиu"ђT«”™ЪЯ-@h•§«p†Q<ПUыѕnБ9©`(}QсбpN®MгНХ«B#Ґќњ}d°€u Јµ¶8?БTJu~Ыјд†+{:©Z‚sХжЩiфЊ№в™ђЋ“)йF IЛ&ЫGzCс`“з®ыА БH3~8F(аyҐ3ГгB©<Оќк p|@‡L~!:|Љuиf™< ь󤆩¦ћD0ЋыоЬҐпошђХяЯн¦іEїA%H&*ЁUo+џ¦w™Gюm‘Б ОГ†»г›Рx ѓн…У }Б$HМ&ЈbЮWџ"•№БГ:ќгR• Јі"Р3љ0—[µћ4®QЯЙPtBeи э фзШ¤·G„°TyNЩЎUy вL§<ЅшКпо#ЪDдnkСGT~,PйZµёья† #,wІ\ЗЕ±ґ‘T<узнЫё$тFVw!М‰{r–Дт¤*!ѕ­x•fhм^±ГЫ~™Xqg:_CЁД”qI…GбВ„а€пг–уЯfоз+f"Vїendstream endobj 84 0 obj 1546 endobj 87 0 obj <> stream xњНWKoЫFѕлWрЕ¬-gЯ›ў‡ИЎЗєИ…–V1Љ”IЙIю}gџ$eJq§|ђ0п~уъжЫЗeA`Yёїш№Щ/ЏKр¶ф±Щ/я\/~ы‡Є%1BРеz·яиD‰жKUѕ\п·ЊoЦџLM%E·хvq»у&ў@ЃЊ¦¶s6<ґ  ЈН–›gЕыфшѕBµЂеЉRВ№чЅЩµЭаlм/ В„xк‡ЫаГ'g2ь¦@Dџ¦ЬЫ№“Ё&ZSЅЄfо$ „qќ|ь1‚ЊRM_!VAёђЙhыѕj›Щ; ~5)OЮМЭ№†uS 3В юд<ЏvЁЛЈА9`й®`У„Ич=ОfZЎWБЌ?—ЙђiЫlзp®р»ди©‚чO>NF ™і_Ц'ДФП–@FјZв^¬rвК>‚-UІ…‹kЇ~„я'.nn%sО«sYdЁ[чv>;€‚ улeGNOЩ‰юy\Џщ™ѓб†ыY6Сsэ`зҐHшL§‹ЇХ› ©Юeєхм0М=†6>lо(^শёЇЫНз>°ћwO¤5ѓ iPA‡#цFYыДІ‘ EЃ< ¤o‘zПkі9нпГ¶AyфЊр¦!©Jљ пJvVЊiуCРуИ°в"G¶/=.Мј„"п‰SGOБvкн–Dђ3цЇ3a]2Ыµ§јLb¬MМ€!"Уъ—®:О·Ѓ"B=фf¶tsћ9¶йЏ¶фќЂЪҐ„ѕћМЙцёШШF§XзЧCнY|єШу5РЫщQљоЃ(ыћбБ»rd?&ЋПr<Щ‹М.XT©&eиз&JaW+6ж†w^>хQ 1БR(IѓЎўўђлљ€`„›п‰жrяzAўЊCђA‘щVЛbиЕQtUy_Пт№kJ™UрEеcђпПћ?S(mc“z™(CћB^джь.lлєЌbЌз~ыuпЉI§VНЉgcы»<ъІСC¬н¶Ѓ±MAf…±MFзОv¶ЩШ·ю^eJЌ6@"©aµьХД M!&Ьt>¬Ў.ЉTљ~Ум]$N: _ ^М7Uщ}BqЉX›+*·эяU‹LђvЫ Љј1Є„tОМ5”ЮЊЏт,mгft/рaЕдГSжzєЗН WЦшxЯъµБ Єї<+сЩf€6™фКР В5”хГ‹Х?вн¬ЇбЉЈМs-=Тфru'mrYушФ…SђЙр•6xOhй~xї^юЅpя5Щendstream endobj 88 0 obj 1237 endobj 91 0 obj <> stream xњЕXKЏЫ6zфЇ0ђЛ€Y’ГgЃZґ‡zh±З\[›UcKЋ¤Н¦яѕ#ѕф0эhіA°‡5(j4ГщѕofшiM [Уб/ьЯVџVџЦМ­ЕЫГъЧыХЏqЅfЊX)щъюaе_`ё‰#Цљ2ВДъю°є"‰x}яч $1\qЬvї[Э}–pEY a©h‡5ґl¦–%‘FАzГ9Вн{х9оd0Э Њ(e‚±ww~‹ьҐ™ {квPж qфЛp-ЅО№µQЊHjШzГ–ѕЌcуЏr3uмзњ!F Х:м(э!Sа<т—Јs‘aR¤Љ‹eЧUMќ= ‹?­љЕ†IA”rў (чдґрЎо†З‚Ј!†Т?:'&Z°Eтµ°RДдпџЬFLі±W›‡lЊ@ЁR/$ ==yЧґБeК!v1,–sіфґЯ;—1ЅVЫя[•ЏЌJ~ЈШ*—!|L" л¦w‹ љи\чt<о«rчох—rА¬jЈ¦hпч' Њ=Й¶¤Њ]8‘¶*ЮпЛ,00Гщ5ЉўUbBUџєТФюМ)б’Б OёСЉ„џ¬ПН~Я„њ‰ДЛзЄюаС@гЮгѕШ–Э›¤qжД->®5н®t Д’к‚cЗ¶|(ЫІЮ–?№pЈ€2fJ;FЬkЭ11Ж·х©©C±m]80ИsтјЫ6ЗТ;„™¤QљEf}0(@КXy>іНЗЂ0#mьL№ ^2Бф…”]т’xе1–hґ±б"їсътЂ‰к]®єВNм/«ЪOљЭ „[ыЎћЙУzVХЫэУ.«ЪE¤PОkN¤Вё\±Ѕ1G·ў@Ешo©ЯJйй0№roлѕlљЅ{ѓRњО=RI;R©лЫH‹Фѕћ‰P2}­ ґzЙ"Ђц Е_t‰є'B1‹. Т™ЏҐ9Сyтє« (22‰[„¤c @rЏµҐЁ=g,‘Ал‚"c5bv¦ИIЙOnLXІЕї,†EdУ(*Їr'Gг¬ fеxыФўѕхыВ0‘шфѕњ‚†ЖеcЫ Цvе.ПW®Ў(Є ѕЄSѕюЃZгМЈ—*5LN},aФКёс·т‡єкhФЂ)F¤єц¬хФNB¶-ЖH“ ‡иъlфX·О”<@‰“<’вQ8ъv+!5dЕaшЛ}Ѕ"Юд>0рХи>АoьАЬ !д ЧҐJёЅрХ,із_Ќньь nбшЎІаЈЛЁчkC7И’W_ъ,@4оўВN+Ц«Т“{йз+бґ6x0`ПУм/J ЋжмJнЬы}№ЛBз._Љg4Јш 3Є@„ј&“Ю‰eshЬ¤ИF gX‡є32 VЌ… иЇђЃРR`l!nЛМ°Н¶8«Твф¦фl”Н‡Ж¶KgЌИк&X1ЄїZІЪђ1~«6(ЈДmёюЕРсp,[XЎ¦,ф©GЋ3з­ЌЇп"fгкXЌbь„ЅёЧЬЖ^­ю/{СGќЁO|["ёСQ"Я>„PpР_HЋ~Ез4b2™†з1Ћ™ЯПUяь–qфxТjН(ЩПabB›t&Я I”VФжЎтґrТа^Б^дDЁ\*9LЏЦ}k‚э@Њn7HЇw…шIГ3™йІ}—;ћ8jzys[ЉЄЏd8r¦4ЋZзћI:MЌE;йґвbWцЃ@У ‘†х‰ЫГэE^?A`Я‰‰^и§9ХOњњтb7џyјШЌ›ЂФ=‚в{N;T{yШQ§ГО,‘г°Yqг°sэЖ‹‡юўГЋЙ ;Щ[‘It“agrы’›#2К|ЪБ"G—У 2ѓ4»]ФБт¤Uп9o|ы2r>!\љ Ч&—ЏыЄлЈk®зAМҐ:xм“o е:№e@ЁфµзЗjыZ0P)5N|‡~H1Є_є>ФФFГпЛ±kЉk]YґЫGЇFШ€Ъ1sйЄ’‰tЎчьиi†g|qGvцю&]D]єїбЉ]:ЂpЬРЁt6љ^фЪ§:*џ@±ЏэEфўI1ч№vочыхџ«бп_jOЅґendstream endobj 92 0 obj 1598 endobj 95 0 obj <> stream xњЅZKo#№І7_тЊ9Н —пGж4›мbѓ Іk$‹¶Ф¶;‘Фvw+3ОЇO±IЩyl$жаA‹b«ѕък«ўћ.)a—Фя‹·‡‹§‹§K6>K¶‡Лп®/ѕэ‰©K&‰ђљ_^Я]„/0XД‰•—†2ВдехбвЅ ъГх?.'\Вwиеховэч_»с)%–9џЦ}ЯґЗЮрнOЬ\2FњRгю-ХЊ]n8'RЋЛagВЖ]±м»ьѕ*я”ўґ±сйµd5R¤…ПЏuz—ћјKqв¤г»”Чю:,dў\я5ТҐ3эј­цUчЫ5л)ЎЊJgaGAXШсзЎkЋчkЫ CЊСЙрO~ гD(–ьФгWБЋЈыfЁ»j?~А€V.ќґП ЇРB¤}лгvЯцхО"Q"Ї>Ћ«ЅГ­‹Пvнйv_Џ;ѓУ­3сщУ©к>ЪNЋб€q’Е…пВ9YbГќъВУЌё%Tў?Ю­№Мo¤q«›$:НP}ЮЌщLA)С`л -уБў‹©Ґ3ЯИ9ъfD›%Fqѕ KПH2tщбФ#f51‚‹шфv4LІљМ‘mхЈЖз\¦ЕПгbE¤rЙйЏ]Ѕ­wСGt,нЭЊпcђкО&Ч~n†‡С +ЭмxЦp<Яmµэз&:N бКЋлчUя@вЩҐ@/]?Њ§бpneЕд4«Yрђ­qбq Љ8лTЪkX†ѓяi—xу~Ёno>\­ЅP&©дЇ_·J Ђѓ8|ї­є®©олdђ8шнz8uЗ›‘ї„FзVЗЭЄ}*Ѓб{Б>5]ІжЃДњIЃъјoЋu4LБqх¶:†3M”rcМэ®Юж}ЯЋСе„Ґзшеї' њЏgьПґJИ=®ZмМиnw§m@ЏVЅYn8sd34е…)`+лq f„3эб8Фчхj”%pЈ0ЙЋOЃ,Q–eћмБ $/’PЬЋ9B&Ж”ЊYІ¶sИЪгЙб"sMэt.3ђёйѓц.ТёЈ:yї=¦$д ±ФvЛ…‡¶ +бT‹и®№o†ю*BC[љ°Ц>P№«э~$Ў ·А єd…АDXm$“’з’М[U(Цє€ЯЎ9ћъи#•чНэ‘Dжe?шGљHp¦љћ’{Й’–mЫ:`]ѓошЧH–¶њкх±I.@ф™–b®B@UОН®®vХmq}Ћј+5MG» »smMІмtЬХ]їЌзQkY¦ЧцЎкЄ-АdфЂтҐбsую—ђ¬p G3Pє„?E±вUЫmэ8Д(ИRzЭ¤ЈчSkУщА»`Ц.јPЇ(t_,B5(H‰цјЊ|HJ6G~їћ’@< ѕT™’?мЫj•жA] ѓ)с Хћьш"ФБНc цЌа0Дi±VGIК3Bъ¦ЗPЁсш•^^*"ћAN пeЂэсXuГU HЧI6Њl†'ЬХЫжм V•[,ЛlЊ-07аZё"/Сb&іДe*їпЛ#0GpЁ!°&шч…ьѓ/d“W‹эЧђAќ}щ‘бА3BњRэ„Aћ0>t sFњTWдЉb!2ўґc±,ґЦљВ»SZT¤хF„ЖДЙф&TrЂГ @eЌ™ Љ‘]!DGЂuМ, РРфg‰"Ёб~Ўф>ч±I‘ећЁpPіNl~ё ­”.Љ|·B!ХюFA.ы­bпИ ~ЋХр9Xп37eЪPчUаhЛ 3ЗкђfЩ@ш№рПЏх?`%Л9у+ьь'иp’€цMЦя-€БОЦЛГГххfуя}xfґЏИAцзУ~Oв‘ЂURrҐТЈ,>:&5 ѕеXЋѕЂуbU’d v:с@ ё°&Ґ®ДРy#№ж»Іљz_ >¦Шq®ґI] эFvbUP№¬В·хK ЋиА„ЕЬЛФ%rcаЧў~@P=хF@SЎJVnТФЧОbCіцMП#*ЭаФzќџ5$…®hг№c\зЇ‹xdСвєиwЎјrП№tјIyнЉЛ©©9`7)4+/ЊВmPЃ ЗPCєu‚3h‰‘Мd5оХ•ї‹as†z3К$о7Кk‹ўcХgk™oЂМЉµЉgkOC{Ђв№M­­™aЕ¤И<гъыC}ЊЫgщЏГН‹f@3$Н-ЃжY)"VЅLДж.O_™6И<ЃЯyLw*Ъ№Y]њnњЯ¦у х›8iJN7ѕЉЬf)=kvчЪЎ±х)‡4uЉЬдЋЎkmRNф—ІK$МnutСёы3ђаw тјdьЕГжsУЧWQшi§зGZзЊGйЂrbw UХЙМѓѓ'э8T“Р~вЌA4Txмё·gAZgнј7љЧ5чГж!FWЃЪЖMzђИЁhV¤hЯцМ)Zщ©яКд,yз‹зЭxW¦ь“)IРSJ|ќЬНЅP\Ажѓ‰ЂAю‡\ ягаЯШEЏ8щъѕѕЛn‰ 4П ?„юHSКЩј{ЦETЊU6ч¬ЏЭo¬уїФ]Чћ№;уе?Ў±№‹§ўЂZА=F9V‰66•†ЯЛ·mЯ7·ы ј4›Lў>%ъС‚ЄС?r§шj«…Т$тШ0ЏД0k•пp,ъw,Дpѓ«‹v“Н&lЕдЇмЂNсщЪ=–f/9pИrжHyn€SЈOблѕ©uHk“j№f–ЫІbЫ9E›ЙмЫ?–Ucэt љмаr– µа%KN‘s­‡јЕџ=дЕ№€o8—Ї|CЎ!FІђµ9SЉ*‘іNњVz*|ЋBЃ9мvГo>F]Йф ?7(‚LWѓ¬—ё™Ѕ:Љ¬Л0э•0@жYвurЋнљExA!2аЈ№?Џр^7ЬМ\<№МЃђRИhµ‚Мe7Ітr&!х*(нWA ОµЇҐжЇҐб|YdѕЧ(d2‚цШЦIЏ·Щ2}2Пњьl…зџ­d,гЂ7ЬkЅѕ‹Ґk%Н‹K¶ЧM4ООFЉхќЯjхчDPљM°v|v“Жж‰)TъЗz;4ЈµП€ю&reяь1n Ќ‡ћЕw#$†ДшnH?кЇ~‹ф{ГUЫя68зуЮwэк«С)†'пV#г§ѕxit“ь5Ґе|аюєsКЁс—-ћRхњI&¦A ыЎ‡О2Я†И[яьылЛї^шя&ІЛgendstream endobj 96 0 obj 3031 endobj 99 0 obj <> stream xњЅ›MoЫF†‹д¦_Ў$hEsї№ES IФ‡ mb ‡¦Zb,6’(KTТщсќэФК&е5л D0EЯ™}fvv№№ззкЗ~N—ЈлСхp„хпљc„8Лтb,A.ФM/ПGgзoЖнfWЌОюЈСЩЇкџ—її‚Џу_ЖЯЊ^џЏяKкпµ!DY†•)њqe хySH uУешеЕим-Uъ2Й_|/РaњБ‘ГG1ѕXЋћэ¶®6П/юaљQ*$Ьu1=+ЫF_}}С©V`~µўИEЎЬ7U№ЄWWэЪещ)ґ†aмeЁнUі\—m}№Ё”<Ъ e6 ъR&ДД^ъІ®¶э~P!иP?є1еІ чµФѓ)—02ЕC‘#тBdB‡цЙЭ0&Ч¤`”"µ[•›/JЃ2! ;¬«¦Ѕ›ОФbќ€Р@мeУ, w”4љCVa+ч““JF]т/v1dсЎЏ§‚РSр$HFt4&<ҐЦдxтў¶»ЛvSNЫєY}ЇGEBЪ"7P=ґйZжEоЪU©LD@ШC]"AХЮГzХЅ"+xОќЮjіХcађcзрг¦lc0аE†\ж§А¦©гс]†©5i e ЄњНjП hABё)kЫnмд Вмзf·iіљ–mµЉ/±O<шtрфuил'вАы$шЧ‡$ѓ_¤ЌБь’”fДt1Џ#|0QЗ E-w‹¶^/кi,a‰кщ‰Pb’Ъ6АЌ>ђhЋ’Ћ™ ЛLљЂњEЂ”Z”+n{UіZЙ’‚тећOх6ЋЄДr5U,T›Є^фA…ПhzЁsk¬o# J-КAµWµlf»EPbi XsТ’4АЌ>‚В§ ђзU@^ј€@(µ*ЌPКЄ®wеўnїD@”XњЃH†в¶УrQnbИ ­‡ &yq2X#nј|AFrUљ КЄWсl¤–gцдEі1D[&чЭqВ†P™ Ѕь1ЌФўмјЁZT[xњCГђ»ХX;/#љ™Фrm3Ёэ_‹0w{ф"l€}ёq!OЃ™0Ўъ)·Фўn{UW› VщъЕб’RЮЏёДЉ5qш@с‰‘а`rЊ°S GIFl…‹™эR«І}Q лx‰ѓ§2w4жќt ’rwMПќъVµYЌ=±ЭzjoН+$z{b^8ШЗ+‘jG09Їj±)‘1ј¦VеxЭЛєіF¦E6±ГY8|bd8Ш‡,¦ьИ"љQЄ§O#ђM­J!+ЉPV№љEђ•X—[uєю•е'ъиAщ)Ю1xJnВсхk=©U)zЉYЗЉxxЛТрpКJП'ј)\Иx8?<ґ`УСИєЬіљ,:Й5itd j^nзци‘ДМН~‹¦щё[ЫщжdЇ®[w7F~V­gХЄ­™ ’±ВэA№Ѕ=µ~4Ј_pЙЬ;MsXюыYЄsЈЕDЛќ:Z„Б5и,:Ј}°п4бP3 &ќг‹кCkж^”HфD*'>RЖИе"#pяD•`эЕ¦ѕљwћf1Бp™1$}™БщЫBщСФЕv‡ьЇї#’гбdх&GЉz€Ь8x[Џsя¶>mb$Ћ”о@qgЁ Ш›‰ЧDGbpиБyGњDЫї У‚Ўi1 Ю%кi>-€ђ'x{K±Ђ­ЈъюЩыз].Z]./RлТ , ы°[MЭ!Љб*wАNЛЕў_І4±dі Х/™ѕ^ІҐ”e№м «і7О№f№,х±µIЩЊ9Ц@Єg+„«u№Ѓu§nд©TіAя»ЮT[хЖ[Ч_’Ь Є-у(‡nМѓ}?жХ¶»U21цд€qП„@$=ЕF)ЁЫѓйЬW8њ’‹І{ЇЃЄFмjµ„1ё»§–з6Zy7» ~і»Ж йdњщV«!Є–z™1 Д=’оРШ(¤Я&с‘ЬюИ‚=$nЭg­ g"е`¦_іХсљЈsЁёџK{]З‡ёY эаgяВЕLэ'uд_§цЩ[,ВgNђ„>’@дUЋ›Р“ ҐgLиT-2vОЦРЎш‰»yўFќ›sсуКvЄ”ѕђПKuЦљЃNK/j|c·›хЫMџMе»њyOM-OХYџ›]°1 +C„ќЁpЦ2Ал.оЦо?HppД±ќLЛ­. $^ёЭIБP< rЌЮГGџЌMxЗЁГ&БЮжПп^ќџлPУ,gѕ‰[TmлцШ °Р†К¬ѕЄЭF›"%Ш8w>І№'пV305mЊя0!ђэО\§KќVКuќTіћWzµ©N/ двѕg&јkЏ6ЫЦЌѕИoЌѕ+%ъЋмГнОµtщњЂ>ІЦYоМ3'„CВЪzbgСЛКљВЭ2\ ‡‰CbчxҐрgґіО¬RoР (±П*z;«ndgDR­ЊмkЃє-2¬ ЬГхЦR‹GмWы‡0»{›P…ЇrяХт¦ЩмЋrџ‚&ў`ћQ]ЉБ Тщ‚ю®.ЛЌ±woЙiІн!ЃЇм7`oZУКЊ? ‘> stream xњҐWЯoЫ6циїВ ,)jVЗЯ\Р‡¶Ъ ђц “mЩЦf[®,7(†эп;R$%[¬УbИCкtјыо»пNџЖЃqfьпщvфiфi о,ьљoЗЇ§ЈЂЋA ‚Џ§ЛQы %љЏUрБvtНo¦ЌЁ &гM¦‹Сх}mПрm­ьYµЄун¶Ь­м#m(МЛfmO™$JkнO›uб<Ы”?{“o7S{*2B)ч§ЕvїЙg-)бB‡;Я—і:ЇїШ#µщLXf€д0ћPјU:у?ЦЕОЕDkб}ФEѕрQ3C2idЊЇ<ё3"2ў>у¦¬vПнЋAJмїTGg$УZЖФ7jё Nцu5Лg8D)ўщa·рж4у‡ecП ж¦UАt]lцЛЈуН!#¬•« %Bks\µ/ЈRВ\0хU±µ•Иђ®,{;3ўёБsѕ9ПYО•ѕФ}_цЙЦG1д& Vw6TТ|¶ЋїF.Ѓ;Ўe–Ђс}•/B{ЙкwQд»ё°*љЏ}Wз©5DpyК«oґџ OdrFЋЎ"¶ЦБk[OG“‚чхмв®ќH_=ЬЬF‡:гэoЏцCБэЯќ¦Ёь6j§tКњПRW0м} Rг¦џWЄd :4OЫ}–¬я • nЬ5ZТmyѕІШ>шќ ІHєW®Ц_b#jKгџ^†м»v\ъoс~/«ъ›пНю“Ъґ©ёТ^¬бS¶пѓњЅ„ъЪ…zТшБ—…Ёђ'Ў=њRБS‚щ¶·вњ*бSi‚]ь«њ€ыќWМ$ЗТZЃЭ&Gґ¶j`м†jpгmЃИ¬еЇУсп#ыу«¬кendstream endobj 107 0 obj 1597 endobj 110 0 obj <> stream xњҐYm‹дё†Н·щН!»0­іЮҐ,ІЙ}8Иr;ђ/‹§[=Э‰ЫћіЭ;;ђџ’,•d·g7GXё9Фv©TхФSOЙїn*B7•яяоО7їЮьєЎa-эЩќ7оn~ш…™ ҐДJЙ6w‡›йєЎЄ"њmtE ›»уНЫ§юФЋџ†ю<ѕ»ыЧЌе„UВ?·їy{яцГеpp=ЩuниЪqрЏPF‰С,>тp9ЬїуЛ[&8¬«Н– "ВoП§сиb†°мЅЃхїФзжОќџљztдгK;Ц_>№ѕпъ`Ю("*Нџ‡ЗhAйдХцOУ~UEґ-чsб4я«Ф„s_шоюѕээящОя¤А®и|ѓ-•‘RЦюј„[џќщќю'{оRЪюћSI*ҐЛђь®ПvxяЮ/эр еeю!V‚(±b`\…'пЋ®wюa^SйtЖzZ¤љИЉЄёШЌрpШ –•6q9<) •Њ%8|©!*.аD0ўЌвс‡S;a‡0fТбАкдн­љ(FУ‰\ary.зЏэ©w»±л_Во ®’[Э!оnТуЭз»нOѕb\„@_/г©kItBn<.јy\О! Гe„Ћ ,XЂУ љ |з— aZ+‘О6A(„‘Љоюµл`Ђ“К Ѓџ»ЅkVг°ҐL ±Ю2 Oя9ћШJLгXм'$б”§ммг† <§<№wц?©ёMfNCJ%њ<Б&ђ‘–±К±wa'p©ВЕDА6 сy‚‘V¦ќлжв†ч1†ЄТ<зlpф:с5 ЧOокv*Uўс$‘†¦з†]ЭФ}0Аd—eJњИrё ҐМ……8Т‚6 Њ®ЊЄRМ]?ЅT,—ЯuхDЄМ о§(х1JU†лCЧ5®n‡ыwБЋІ­X:B°ЌцБ[*“Ўc=Зъ!–Џ‡тЇмqёґ;Џу!]В‘*МъЭ1eSI“Њф]7†UhRЄe’«лjѓlT”- ІеєўdДуeгЃ4g|ћ+бkv†=°+1¬xlЏ]ќBхУDDњ€м\ґ 8ZHҐb*48Ќ4wᴇоxz3‘$PЏв&=юрС¤ћЦNгаљC„iУXXZVf)k0nm}v5L0;ыьd+О‚«Gn№в@l†ЮXЫ\4]Џ±hСr™zа‹©џGт ЇИІ< *ВҐ’игCOS. #YЕшЪ’U_џГ” Psj&RіА‚’TxЋжr›‚–0МІҐ!P‚#‡еX0I—ћМфМW;#pГОёо—kљґ°г7ЊNш…ЩBЄdагl$rЗJae­"-kЌ\ЫrЩЇCmМc»o¦є†’РH©хЂAЃ(‹ЉЋё¦ЌЊљз6‹_:ГL№~tЎO¦„ `~]$ [—"‘_‹Дїuх>ЋbР~ҐМй‰)‡n(dHvЗвi…јсєЦ|E?j dЈ‚~“{owIiUщЅя¦0«IЉ¬– ЃK€|NsыЫ(ўl…<5–ОC¤XЃ!ґРЊ‚ЭСнЯGzдВлПЭТGЙ­R—1 ј4.fT,Б§‰а Ѓ›,Р?CГO5Фћ–Ѕ~ЪЖО ,Бf#^VIZ$ђCbРPvэ]пк1fж(j±‰Н4<`Jў†AљD` |еСЌЙ–O]ПtПL‡ѕ;cЯa…9З([СEкЎЫ’Я<^Т­ЊHњРШ‘Д‚­ЉR{pЗ:i ѓEщщФ]ъ ЕЕ(Б|зYtlљҐа.%Я+мЬИоЯ:т*FKUЪ+’ґ’¬ЦћгУy >Њ®ЌЎј§qк0°’Ч&aбп*0ЅЅ;@‹HЯї›Є$UҐ“с/‘@ш¤7цоQXYdЎъТЊ·Qifщj^AЦжK‰X]А‡ ьL)ьЉВ–ѕCКk$‹HxУ87@·cю®ГeЊY№•ѕt—€V™k¦ЧXЮЇЦ^:4PБ<уІин»¦†kЯQP“§“—§U"Ѓ= mЎLоЬ§Є~ЌP,l$НcЏ. Эї ЉИ,$Z®9¬®"ю”іЬ рJf jжв$ѕ5tHЛКў»[§Л §QdjwНeїКЉcХўтЇМБC№ |Я=MҐІґ}Z М†{FС 5Ye†tг.Э# Љ„ќДълЎ&Я'! ъ4a з]™йВ»Aп­°вў$С8фE+Л4!ыdWЊ9[]х) ¤ ЉЙБзг§ {ЩR#П,88e7¤ОПз‰qЗЈ4цј¶бсЩхiаЂG·'1ЬМ Г}!4«I›C† Eўё?$Ц”*+‚5lуЂ,хр7аТЉО2xХлgЧ Їў lmp/wЂѓьЁ4«X#“мDймъn †Zћ%xњ”a_ЃгЪѕsCыL8zҐBscX»Q…щж66*™;РxњтйI”!Юћ fєм¦­ЃCaaW[‹ЕНЉЙЉКaп¶Ш.ЄЄгGА±r`BЗ#]ЪсФ¤®КххhR4ыо2®]*/ҐKГH1`_р–ВфеGьў|®w}7Dвд*Џ—Ё;Y^FА{:ҐОC_ Ђз®‡YMЁ KЁ¤V,ІДZі‘gМЩvЙґз.4эS]Y”џ«gШ»7mЊ‡џђsья™ш†zUUў4mСFЛ„l№сККП$юУP}jБњ*+^Z[Мy>юa[уІ‹чт”F*T! v0Ы=F№ЂЂ&ёмі‰ч·o°†«ЛУѕqћ4j>OО?$<ГђьК— ЕБg3џ€®•Ћ}Ф3@шЩЈЮЇЏj ЌжЄјкЯҐў]®СnYHpІю7GS!¦є'ґє‰ш±Ыpyzкъ1–’P81Ґ‰FAыН… Zх4a®‰ЭYAGгJpй±ЇПсвhR yьt€йQЙ*)HXМ Іu.i+йGзЩґб7ѕFE<Гm<ќЎz~•6ї­чы !КLFb’zЕAsjя]Ћ]ЄpѕЏ ЃЦуЫ ОуGXьЉкїНШЯфнlW|°\“±„2ЬЁ9%¶#T•¬щРЧУ•18!тmА$<ѓiy•“ЎRЬеУ|—_7C™к|Гa‹ЌMИE:®N; xyЪOз‘мОЭЪЎЎЂў“ч ®бv;_ЪCѓл&Q"ЁcБ@ЌЅ№76ыиэЉJ™ЌЧћ~yНУL¦ЩSЯтуUгxЉ$ЁідшњcezЭmУЃёрЯпнХЃ¦ЪSА*"SSTp:ј}n‡Ko%Ѕ*µY’ ъЎХR¦З‘У‘:tM“ђЩр9ЦLшо“/Цn'Зювю8хьD $>q"Јю‡п6яёсяю ИbУendstream endobj 111 0 obj 2806 endobj 114 0 obj <> stream xњҐZ[oЬЖоі^ъИCm@KНќ3х“ќЌЂ¦NcЎyP\®Д„KК$ЧІю}ПЬОђ\®нґ0`ЬЩб™п|з;—ЩЏ’С ±яВЯтpссвг†єgсOyШј»Ѕёъ…© Ґ™‘’mnчю tCЙёЪд„fTlnЇюъъцwXNщl9Нra$|еvwск§c3ЦOMeW ‘Q&Lшd|м«b7ШxћI*вWКўµ©Й$бЩPм«жЕ­Ґ™dqйqpSќ®nмВ¦„RЬааћ2xЄr—V‡§¦С:К9Qъm8 ftґЈмЪтШчU;zk¤ЙTћGs2ЏЗѕ-,‚m¶LXьмВ?њРgЂЛе pЪ¬—«ёф©ЬЊgZ’ь9­(;EN“sИ‰‘»{Ххa*x\ї«чо!П€RС)ыК"Њ#"П›wЇн‡[NLF№Щl©И,VvIз¶cЪМНи®3"ЄюЎZѓџk8uДglЛ±оЪuЏj–фясЁКЁK0ќK$Й4CњыcЫЦнѓыЛЁС-µчµИBѕ2Лr–@ћРBн„F -_Ў2/в„Бд'с›Љm9МsҐрйvUsй¶Ц™PjЕhґЉ67ќ‡‚©Њ!zk Ы.PђPCЧ( $КFo2k¦P‹цБыEАБЌС'‡T)TЬQІа«\гQо^э«уп xЌЏЕи!А~ў§фn»6Й‰/нцб¤TЁeМ‚&ґgG•™аxФa„З Да —ВШЁЫІ9оЭ–a$LЖs—~7Tгj1pz¦Э­ндEЈEЯ}*ъµќ¶†EОШ<LЈ‘¦.RМЬеAe2Ј„N€–ФM±$Оe^gЃp•*|тяJN)2»hЋћ у,  *гГо8њБ‘p6_Г‘±ѕ†#дгЇг8Я©џ`Oъ©к{ЇKњ‰¶]лCЮЄCвџЮ9І^_‚/ЊU¤™~т[йРDћ IµJU‡ ГTn` .”ЧaҐ@‹мѕ\Гю1МЌ»^чЖА€tё”¤рl?Р єmг6§™ђ,С·йЬ­ї]O8АoMuфЛC5ю6ЌЗеЖвJ Tл©ЃЋ')к‹zрм[ѕJTд/нX|ю­кыn• р6&рm!_ђL}µsФ\з&ЕZЫщQEY*#ъђ@є †NaйLqЖўхЂАЦsБ9m&vљ,шM деЌ'”›ЙєC))s¬[ЉfиB5C9Zб ЩІpЬЎ>хБf™­[ ‡“ЊЕpя\VOЦ^юAй©4sа(d‘pLФ-· j,€S§n†А|ЕРЄVpЌaг+$]Mc2#)Ќ Э±/+ф’DҐЌ ШKxз4щЮWe’8ЁџVиЩђjM†s*9h|vsхУЏЋА!ы TdК=ОЕ[E‘^$#n" Њs qГШкБЕ:Тф+GqЅЇN >xзѓБњObt\2Ф96№Аm“ТрЉЅPєmЗъ°boВКЙ#lwЇЄмБЃ№‹p$VШ›е‰љП}Ё„ “©LЫc< лй,КЖ—§коµ/ґ\АGBћ/›§yт es.–e3–@Я¦^ЊИщЫаду F 8Cк§•JћџrКи’SV–В“п‹CгрU”Ш`-4Љ­Dґ¦сT™uSыѕ;wB1ЁПѕо|УTh.ЏfЫ"fе™иbО JEЩБОUШrбRЏeY ГюШ„ЋZF%ўп/=[ґжЉ)[bИ©ЖЋa­1G‘=I‚Vaav ћw)¤V““Hµ7^‰Ќ1<uФL¦`ћлњ‚p“тПµ|+cIЃїсtя ia Ы@ђ1 ыё9ЃфЃj[P(ШмBДА$зХP?ґ«J\ёj*”8k,$7‡–>ЗЪpW e_Я‡n:ЈЛ–b=uТµҐњm%Љё_Y@›HмVHJ!6аnC¦©ЌШьЮ„њ¦R`јtGg?“йИЪ]Чю-ЊЮ@Ы\i™>;­±} w«лЎpч‘ў•‘Zљо)T°Аn© ы&дc’“rх8TН>Иk4ќ– Я°µт†›EySњ/дСL2жjµФ‡&h!QЉ†BубqЬwэіRo®а»@WЁГН—иЄШ’®аzµТ\і 7ЦsO=Ёm u±ЙќЂQ†`dDmЬГ®§j5Z№&±љ VЉPMЏ°§џ9qc»ЯиХ›XZ’”tОiђ—§Тё+БUMхyНjJ±Н:ЯdВБшt»—ў,Wч–NgQ$¦)MҐ~cИчY^яЇ–ґ #|VТ^†"кўTЗµ©Л0щґыЇzр{ и8Ће°ЄU)°Љ{K°r aсM\ ‚њ‰Lй«*HRвs ЅC=ДЧJj,—tЈijХЭяв<ј ЇUі™67™В†/-‡’µЬѓ/ББ†.И즻сбіЏB9™rtэ!НУ4Фуж:Н¤*џU 1в1!Ip!O^: Їwх№К8Фґ“®Кџ 6“®>4Яvcс·ЗIИ‚њGЗ}@ЗA‚q HШ&ђ"Л…µІЉUµZ?l)#1|1игЕx ыМ\ЈёЌПAuРys¬¤ЗGФ­УЪ‰Ш—;ґ) еҐЬЋeRЬ$ЧЂIlќщ@©Uж>cюeИљZаЂґЇЂИ­OpPvк”Єп_BМi№BПЙґѕlВE…«ЋLО—Н4Iqв№*YvюЙh;у$yЙ.“`ъTчг±h2y >1jЦTџ-:CHD_®‡3_Ч(ҐQ<>аЧakKdРSЯнЋeLВљ¦wЈ8И7Ює 54Уd)ё3«§Бґеg5ґmUЕЉМБttйkБЯЗЊ§рЉєгMі°SЦ°Д;†‰µњґ5ADѓ°Хкd/Ч4B«ЕРкU©¶=dєгДъжLЙ+Rю8Tгc· Б6йЅ0ыNJбс*элЫНїн/1$ИёэЩl!/n(±Ґ­¶ПmЫlј»№ёєщi3цЗквкЧ ЅёъСючозпбПН›ї\\ЯшЅVХ‚ii}жмW­к/8€r?кАvЦC@G…EbпУ@aЭ®ы CNq°ЩэGq882sИВ ҐҐВ&љб¬ЇhІЛш®|ъ.K7ѓ7Эiвaз– ГюgO/hNсюИ7PГЯсэXю]7IЂнШ']ъtqъL Кж/ХpДб›¶QЙъЮUXЫч}ЌҐ p@‘tУнЗgЗн-ЁVaоr6~ЩБ! <%8+z»ЫХ1mЛМ]hъ”1шЪЃBdLЩїЖjV щЄБџљЋѕшt&ЎоЏЏюЩµ‡ўЅ i”rTjLћ­± nЧж·”1¤ґэч_жМжendstream endobj 115 0 obj 3009 endobj 120 0 obj <> stream xњ•XЛЋг6fY_бe”9в›DV“`f1EfЪЛЃJf••ТГ-Й©®їџЛЧҐd»:Эh4єAKд}њsоЎ>п*Bw•я“юmъ‡Пџw4¬ељ~чуббпяЈrGбB±Эбщ!ѕ@б!FЊШйЉ*v‡юбIШЏ‡?8#LА;Хоp|шбpr~‘i"-ЈiсWїd€в”Ґ•zљЭЮ–„kЄутp o+ўМ‹яq_віЯQJ¬”!ґ=есaо#BlОg¤’†§Ое8xР0“ЦЫЩЇБЋЬтјц§_’Д(+улnzП"µ±iq^¦є}9-Пгф^1ђ€RЯс1ДA‰Tъ:ЅЉ(J1ёi|Єџєp„ђDk•k98w BљRж‡1uг6ШЕ ©d,WшЛ№«‡ziЗ!ьЖ‰Ў•Иy?‡- ЊrШыxIsfJaз=Чњ@{А…/=ьvЂMЎyшpЯvmЛ Н®LNы­]NaoIrхЖ¦о»чєi€яA1€Dу+qВJ ;1$)UвЅVЕЗґ°<џЎ‰…ЂrЁ±(`&±†K<–ZB вt„Х°%іЂrќ{p‚N†m9%LYµЕм#ћ¦:o°‡XhЖюЬµMЅёёУћк!@_геѕn‡ ® я9ќ'ЧФ—9Д*аtЖrWЗШUNxҐфURђ~IЄ~љЭР|гGЧµ}»ё)д&Ѓэ–Џ—iЎРKќѕоRЃЁ¶щ…е^—T4]!№Ъ!ТаZќ:+YЩ JXЗ=TMsDK=мcQ•%^-VИ}№Ф/о§4$#±T±}АN[$brџ/ндВ/‚NQ«.±Щ°/тjSэ*UВћзKBд–TљZ<®^бtUeЅеviЃJ$щ Й6№ъШ/i_U0ё­=аыjї ш2,m—иЄ +пEцв–Э$ГЛм ПуШ;(r ZBїсЧЕрµЇFгш[b€1€Т®}-и@вЗди‡иБ]Ў#Ђ ьўHEE~g~–ъKР¤=µ -phI “ўxр/ d‡DoГыъpHµЁСw M…ExЃђ87qWHЦајсZ±АЯLRБdо‡/{"|µє¤и@u¬FUJ j+2ѓNҐ\,НсјќЪж›-Ы[љНг”с-KKQa”B…qCљFЪPњВн4ЅД V‡¶вД'—№PVUЃс5НJF vfhgw$™‘ »P¬іШЮd`ћИњv=µ0Ї]t$ +GЉRD`s™~пЗЈ»з] ќ«ЬЌЧ;pз€}42Ѓ©n^“БтЄ¬ЃsФљdЯN.ЏђzГйWГчaр^°yПJAюґ0YEёБ]п ьV№э еzL­•zеЇzC$ЭµFх0'cдГТс8ЭА:›W|?pЗѓ“$k%$с_БПА,*ѓ7ѕ^•?+єжM?ОKв%дКБЖ„A”+Ў)–q^`„’iВґ2@А™‚©2°I‚—БржіkЪєу¤й@Ї%КДtйЬь^ТЊЄ+шЮ*Tюп…ЏP04н•­®Jїщ>…x @ДЎVq&т®|3QLV@Ыщz Ґr@+yЁ».ЃИЮXCёФ”lПхxЌЉ+@ј$їндЌНcыBэbХУѕpЃ}1щђ|'CAА[~ѕ’«ўЋ/Эш”м/L®BП`7ЈT”~ЯMbЖB9В{Ј ¬ ПЎ75Њщ$М°ёЈџЊhYЖcы7/ЌЏЙІP…)g=тEPЯcY­±·Vhµп=гuћЖЕ5‰LBЇецйэvь'kВ-cw‹j8µї,щ2o$bыKЬА¬БoHщKEэвлшMънЗ РbЅєJЗ[0 1а‹¶k^NSцшю| …"СCЎC€®< Е›MЧЇyдkќy 4Н\;†kжї p H|$ ћжџ‡ЭьџяЎІеendstream endobj 121 0 obj 2131 endobj 5 0 obj <> /Contents 6 0 R >> endobj 21 0 obj <> /Contents 22 0 R >> endobj 30 0 obj <> /Contents 31 0 R >> endobj 36 0 obj <> /Contents 37 0 R >> endobj 40 0 obj <> /Contents 41 0 R >> endobj 44 0 obj <> /Contents 45 0 R >> endobj 50 0 obj <> /Contents 51 0 R >> endobj 54 0 obj <> /Contents 55 0 R >> endobj 58 0 obj <> /Contents 59 0 R >> endobj 62 0 obj <> /Contents 63 0 R >> endobj 66 0 obj <> /Contents 67 0 R >> endobj 70 0 obj <> /Contents 71 0 R >> endobj 74 0 obj <> /Contents 75 0 R >> endobj 78 0 obj <> /Contents 79 0 R >> endobj 82 0 obj <> /Contents 83 0 R >> endobj 86 0 obj <> /Contents 87 0 R >> endobj 90 0 obj <> /Contents 91 0 R >> endobj 94 0 obj <> /Contents 95 0 R >> endobj 98 0 obj <> /Contents 99 0 R >> endobj 105 0 obj <> /Contents 106 0 R >> endobj 109 0 obj <> /Contents 110 0 R >> endobj 113 0 obj <> /Contents 114 0 R >> endobj 119 0 obj <> /Contents 120 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R 21 0 R 30 0 R 36 0 R 40 0 R 44 0 R 50 0 R 54 0 R 58 0 R 62 0 R 66 0 R 70 0 R 74 0 R 78 0 R 82 0 R 86 0 R 90 0 R 94 0 R 98 0 R 105 0 R 109 0 R 113 0 R 119 0 R ] /Count 23 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 19 0 obj <> endobj 20 0 obj <> endobj 29 0 obj <> endobj 35 0 obj <> endobj 39 0 obj <> endobj 43 0 obj <> endobj 49 0 obj <> endobj 53 0 obj <> endobj 57 0 obj <> endobj 61 0 obj <> endobj 65 0 obj <> endobj 69 0 obj <> endobj 73 0 obj <> endobj 77 0 obj <> endobj 81 0 obj <> endobj 85 0 obj <> endobj 89 0 obj <> endobj 93 0 obj <> endobj 97 0 obj <> endobj 104 0 obj <> endobj 108 0 obj <> endobj 112 0 obj <> endobj 118 0 obj <> endobj 122 0 obj <> endobj 25 0 obj <> endobj 24 0 obj <>stream xњcd`ab`ddд‹ ЋфqvЦvц Ћ44‰Ияђfь!ГфC–№ыwЯяџM¬K~ }ьоЙяЭVЂЃ…‘СН':Э9ї І(3=ЈDAГYSБРТТ\Б17µ(391OБ7±$#57±ИЙQОOОL-©ФSpМЙQй(VJ-N-*KMЃШкњџ[PZ’Z¤а›џ’Z”—X dgg И``h`жПcfZВШµ‰Ў„€l»@N`ROшЕчЈгр‚ппз3vяgюбяЅOф›с#ҐЯЊfFJ ЏMѕ|g|рд‹PСпѕї‚ЎЄTW€ц7ф7Ммж6eКґЮоѕ¶тї_ьrhџЦ>­¶[ІЎ©©Ўі»cBќ> endobj 101 0 obj <>stream xњcd`ab`ddдх€фрх‹Тvц 24 Ияђfь!ГфC–yБпѕп·~6±®ыЮ"фЭ\р»яw=fFF7п(зь‚КўМфЊ gMCKKsЗЬФўМдД<ЯД’ЊФЬД 'G!8?93µ¤ROБ1'G!¤ЈX!(µ8µЁ,5l§s~nAiIj‘‚o~JjQSt,ѓ ѓИ*vuчяЊnI|ящя$ьоЫрЛhcчжп}їыD7hэ2zіб·Фїvщ7@yэџMўїҐТЮь3ТJы.ЕЖW¶а§э‚ЯKg}ПџКц;qы ®3Ьr\,жуy8зOбб93›‡—Ѓ DeИ endstream endobj 124 0 obj 269 endobj 34 0 obj <> endobj 125 0 obj <> endobj 9 0 obj <> endobj 17 0 obj <> endobj 28 0 obj <> endobj 47 0 obj <> endobj 11 0 obj <> endobj 117 0 obj <> endobj 27 0 obj <> endobj 126 0 obj <> endobj 26 0 obj <> endobj 18 0 obj <> endobj 16 0 obj <> endobj 15 0 obj <> endobj 8 0 obj <> endobj 116 0 obj <> endobj 14 0 obj <> endobj 13 0 obj <> endobj 127 0 obj <> endobj 103 0 obj <> endobj 12 0 obj <> endobj 48 0 obj <> endobj 10 0 obj <> endobj 33 0 obj <> endobj 2 0 obj <>endobj xref 0 128 0000000000 65535 f 0000053800 00000 n 0000073106 00000 n 0000053582 00000 n 0000053848 00000 n 0000050185 00000 n 0000000015 00000 n 0000002193 00000 n 0000065960 00000 n 0000057286 00000 n 0000071913 00000 n 0000059664 00000 n 0000069645 00000 n 0000068289 00000 n 0000067156 00000 n 0000064823 00000 n 0000063690 00000 n 0000058417 00000 n 0000062564 00000 n 0000053903 00000 n 0000053933 00000 n 0000050353 00000 n 0000002213 00000 n 0000004802 00000 n 0000055912 00000 n 0000055690 00000 n 0000062068 00000 n 0000060859 00000 n 0000058475 00000 n 0000054040 00000 n 0000050505 00000 n 0000004823 00000 n 0000006356 00000 n 0000073046 00000 n 0000057108 00000 n 0000054149 00000 n 0000050657 00000 n 0000006377 00000 n 0000008732 00000 n 0000054258 00000 n 0000050809 00000 n 0000008753 00000 n 0000011528 00000 n 0000054345 00000 n 0000050961 00000 n 0000011549 00000 n 0000013327 00000 n 0000059601 00000 n 0000070781 00000 n 0000054454 00000 n 0000051105 00000 n 0000013348 00000 n 0000015117 00000 n 0000054519 00000 n 0000051249 00000 n 0000015138 00000 n 0000016559 00000 n 0000054584 00000 n 0000051393 00000 n 0000016580 00000 n 0000018385 00000 n 0000054638 00000 n 0000051537 00000 n 0000018406 00000 n 0000020313 00000 n 0000054681 00000 n 0000051681 00000 n 0000020334 00000 n 0000022433 00000 n 0000054735 00000 n 0000051825 00000 n 0000022454 00000 n 0000025564 00000 n 0000054811 00000 n 0000051969 00000 n 0000025585 00000 n 0000028125 00000 n 0000054887 00000 n 0000052113 00000 n 0000028146 00000 n 0000030269 00000 n 0000054974 00000 n 0000052257 00000 n 0000030290 00000 n 0000031908 00000 n 0000055028 00000 n 0000052401 00000 n 0000031929 00000 n 0000033238 00000 n 0000055093 00000 n 0000052545 00000 n 0000033259 00000 n 0000034929 00000 n 0000055158 00000 n 0000052689 00000 n 0000034950 00000 n 0000038053 00000 n 0000055223 00000 n 0000052833 00000 n 0000038074 00000 n 0000040236 00000 n 0000056730 00000 n 0000056493 00000 n 0000069497 00000 n 0000055310 00000 n 0000052986 00000 n 0000040258 00000 n 0000041929 00000 n 0000055389 00000 n 0000053133 00000 n 0000041951 00000 n 0000044831 00000 n 0000055455 00000 n 0000053280 00000 n 0000044853 00000 n 0000047936 00000 n 0000066021 00000 n 0000059725 00000 n 0000055510 00000 n 0000053435 00000 n 0000047958 00000 n 0000050163 00000 n 0000055635 00000 n 0000056472 00000 n 0000057087 00000 n 0000057198 00000 n 0000062013 00000 n 0000069439 00000 n trailer << /Size 128 /Root 1 0 R /Info 2 0 R >> startxref 73156 %%EOF camltemplate-1.0.2/examples/0040755000076400010400000000000011030647123021726 5ustar gdsАдминистраторыcamltemplate-1.0.2/examples/examples.rules0100644000076400010400000000013410244417461024621 0ustar gdsАдминистраторыifeq ($(CAMLTEMPLATE_DIR),) CAMLTEMPLATE_DIR := $(shell ocamlfind query camltemplate) endif camltemplate-1.0.2/examples/fastcgi/0040755000076400010400000000000011030647122023345 5ustar gdsАдминистраторыcamltemplate-1.0.2/examples/fastcgi/fcgihello.ml0100644000076400010400000000503610251606440025636 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: fcgihello.ml,v 1.3 2005-06-08 15:22:08 ben Exp $ *) (* "Hello, world" with FastCGI. *) open Printf ;; open CamlGI ;; open CamlGI.Cgi ;; open CamlTemplate.Model ;; let template_file = "templates/fcgihello.tmpl" ;; let run r = let q = new cgi r in (* Create a model. *) let model = Hashtbl.create 4 in Hashtbl.add model "message" (Tstr "Hello from CamlTemplate with FastCGI!"); (* Make a template cache. *) let cache = CamlTemplate.Cache.create () in try (* Get the template. *) let tmpl = CamlTemplate.Cache.get_template cache template_file (* Make a buffer for the output. *) and buf = Buffer.create 256 in (* Generate output. *) CamlTemplate.merge tmpl model buf; q#header (); Request.print_string r (Buffer.contents buf) with CamlTemplate.Syntax_error msg -> eprintf "\n%s\n" msg; raise (HttpError Cgi.cHTTP_SERVICE_UNAVAILABLE) | CamlTemplate.Template_error msg -> eprintf "\n%s\n" msg; raise (HttpError Cgi.cHTTP_SERVICE_UNAVAILABLE) ;; let () = register_script run ;; camltemplate-1.0.2/examples/fastcgi/fcgihello.tmpl0100644000076400010400000000013310245117640026175 0ustar gdsАдминистраторы Hello Here is the message: ${message} camltemplate-1.0.2/examples/fastcgi/Makefile0100644000076400010400000000177211030375316025014 0ustar gdsАдминистраторыTOP_DIR := ../.. -include $(TOP_DIR)/Makefile.rules include ../examples.rules # Change this to the directory where you've compiled Christophe # Troestler's CamlGI package. CAMLGI_DIR = ../../../CamlGI-0.5 # Change this to the directory where you install CGI programs to be run # by FastCGI. FCGI_BINDIR := /var/www/fcgi-bin TEMPLATEDIR := $(FCGI_BINDIR)/templates INCDIRS := -I $(CAMLGI_DIR) -I $(CAMLTEMPLATE_DIR) BYTE_LIBS := unix.cma threads.cma str.cma camlGI.cma camltemplate.cma BYTE_LIBS+=camlTemplate_mt.cmo NATIVE_LIBS := unix.cmxa threads.cmxa str.cmxa camlGI.cmxa camltemplate.cmxa NATIVE_LIBS+=camlTemplate_mt.cmx SOURCES := fcgihello.ml RESULT := fcgihello .PHONY: all opt clean install all: ocamlc -thread $(INCDIRS) -o $(RESULT) $(BYTE_LIBS) $(SOURCES) opt: ocamlopt -thread $(INCDIRS) -o $(RESULT) $(NATIVE_LIBS) $(SOURCES) clean: rm -rf $(RESULT) *.cm? *.o *~ ._d install: mkdir -p $(FCGI_BINDIR) cp fcgihello $(FCGI_BINDIR) mkdir -p $(TEMPLATEDIR) cp fcgihello.tmpl $(TEMPLATEDIR) camltemplate-1.0.2/examples/fastcgi/README0100644000076400010400000000122010244506171024221 0ustar gdsАдминистраторыThis example isn't built by default, because it requires Christophe Troestler's OCaml-CGI package. 1. Install mod_fastcgi, and put something like this in Apache's httpd.conf: LoadModule fastcgi_module /usr/lib/apache2/modules/mod_fastcgi.so Alias /fcgi-bin/ /var/www/fcgi-bin/ Options ExecCGI SetHandler fastcgi-script Allow from all 2. Download and compile OCaml-CGI (http://sourceforge.net/projects/ocaml-cgi/). 3. Change the paths in this example's Makefile, if necessary. 4. make; make install 5. Open http://localhost/fcgi-bin/fcgihello in a web browser. camltemplate-1.0.2/examples/filetest/0040755000076400010400000000000011030647123023545 5ustar gdsАдминистраторыcamltemplate-1.0.2/examples/filetest/.cvsignore0100644000076400010400000000001707735074762025564 0ustar gdsАдминистраторыcoleridge.html camltemplate-1.0.2/examples/filetest/coleridge.html.saved0100644000076400010400000001022010115710172027457 0ustar gdsАдминистраторы CamlTemplate Test Page

CamlTemplate Test Page

Here are some excerpts from poems by Samuel Taylor Coleridge, who was born on 1772-10-21.

Title Year Poet's age at time of writing Excerpt
Kubla Khan 1797 25 In Xanadu did Kubla Khan / A stately pleasure-dome decree.
Christabel 1800 28 'Tis the middle of the night by the castle clock, / And the owls have awakened the crowing cock;
Dejection: An Ode 1802 30 Well! If the Bard was weather-wise, who made / The grand old ballad of Sir Patrick Spence
The Rime of the Ancient Mariner 1817 45 It is an ancient Mariner / And he stoppeth one of three.

Some expressions:

Expression Value
48 * -3 + 12 - 1 / 6 -132
(48 * (-3 + (12 - 1))) / 6 64
(48 * (-3.45 + (12 - 1))) / 6.7 54.0895522388
"Poems by " + poet.name Poems by Samuel Taylor Coleridge
"Poems by \"" + poet.name + "\"" Poems by "Samuel Taylor Coleridge"
substring("Hello, world", 7, 5) world

Scalar values are true if they exist and are non-zero or non-empty; list and hash values are true if they exist:

This line will be included.

There are boolean true and false literals:

This line will be shown.

Scopes:

Expected Actual
"foo" "foo"
"bar" "bar"
"" ""
"foo" "foo"

An inline macro:

The poet's name is Samuel Taylor Coleridge.

The bracket operator:

Samuel Taylor Coleridge was born in 1772.

Some text to be HTML-escaped:

<Sam & Sara>

Dollar signs can be used unescaped, as long as they're not followed by '{':

The apples cost $3.00.

It's possible to escape print expressions:

${poet.name}

With two backslashes, you get:

\${poet.name}

A dollar sign followed by an expansion:

$Samuel Taylor Coleridge

A dollar sign followed by an escape:

$${poet.name}

You can also escape directives:

#if (poet)
Do something.
#end

Escapes in string literals:

	A quotation mark: "
	And a backslash: \

Nested comments:

A string containing comment characters:

#* This isn't a comment.

You can write #else# and #end# to avoid newlines:

The poet's name is Samuel Taylor Coleridge.

Some UTF-8 text:

En gГ©nГ©ral, les techniciens sont prГЄts Г  rГ©pondre uniquement aux questions concernant les logiciels qu'ils maintiennent.
A footer, included from another file:


This is the footer. camltemplate-1.0.2/examples/filetest/coleridge.tmpl0100644000076400010400000001101510115706452026377 0ustar gdsАдминистраторы#* A template for testing CamlTemplate. $Id: coleridge.tmpl,v 1.20 2004-09-02 21:14:18 ben Exp $ *# #open ("macro.tmpl") ${title}

${title}

#set (birthdate = poet.birthdate)

Here are some excerpts from poems by ${poet.name}, who was born on #formatDate (birthdate.year, birthdate.month, birthdate.day).

#set (bgcolor = "white") #foreach (poem in poems) #if (bgcolor == "white") #set (bgcolor = "yellow") #else #set (bgcolor = "white") #end #end
Title Year Poet's age at time of writing Excerpt
${poem.title} ${poem.year} ${poem.year - birthdate.year} ${poem.excerpt}

Some expressions:

Expression Value
48 * -3 + 12 - 1 / 6 ${48 * -3 + 12 - 1 / 6}
(48 * (-3 + (12 - 1))) / 6 ${(48 * (-3 + (12 - 1))) / 6}
(48 * (-3.45 + (12 - 1))) / 6.7 ${(48 * (-3.45 + (12 - 1))) / 6.7}
"Poems by " + poet.name ${"Poems by " + poet.name}
"Poems by \"" + poet.name + "\"" ${"Poems by \"" + poet.name + "\""}
substring("Hello, world", 7, 5) ${substring("Hello, world", 7, 5)}

Scalar values are true if they exist and are non-zero or non-empty; list and hash values are true if they exist:

#set (empty = "")
#if (foo) You won't see this line. #elseif (empty || 0) Or this one. #elseif (poems && title && poet) This line will be included. #else# And this one won't. #end#

There are boolean true and false literals:

#if (false) This line won't be shown. #elseif (false || (true && poet)) This line will be shown. #end

Scopes:

Expected Actual
"foo" #foo()
"bar" #bar()
"" #baz()
"foo" #quux()

An inline macro: #macro print_poet_name (poet_name) The poet's name is ${poet_name}. #end

#print_poet_name (poet.name)

The bracket operator:

${poet["name"]} was born in ${poet["birthdate"]["year"]}.

Some text to be HTML-escaped:

${escHtml(someText)}

Dollar signs can be used unescaped, as long as they're not followed by '{':

The apples cost $3.00.

It's possible to escape print expressions:

\${poet.name}

With two backslashes, you get:

\\${poet.name}

A dollar sign followed by an expansion:

$${poet.name}

A dollar sign followed by an escape:

$\${poet.name}

You can also escape directives:

\#if (poet)
Do something.
\#end

Escapes in string literals:

#set (b = "\\") #set (n = "\n") #set (t = "\t") #set (q = "\"")
${t}A quotation mark: ${q}${n}${t}And a backslash: ${b}

Nested comments:

#* Here's another comment. #* With a nested comment. Containing a string: "Hello, world!" And a string with comment characters: "*#" *# *#

A string containing comment characters:

${"#* This isn't a comment."}

You can write \#else\# and \#end\# to avoid newlines:

The poet's name is #if (poet)${poet.name}#else# This won't be shown#end#.

Some UTF-8 text:

En gГ©nГ©ral, les techniciens sont prГЄts Г  rГ©pondre uniquement aux questions concernant les logiciels qu'ils maintiennent.
A footer, included from another file: #include ("footer.tmpl") camltemplate-1.0.2/examples/filetest/filetest.ml0100644000076400010400000001105311030376601025713 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: filetest.ml,v 1.22 2008-06-25 08:10:41 gds Exp $ *) open Printf ;; open CamlTemplate.Model ;; (* The sort of data you might get from a database. *) let poem_row_names = [ "title"; "year"; "excerpt" ] ;; let poem_rows = [ [ Tstr "Kubla Khan"; Tint 1797; Tstr "In Xanadu did Kubla Khan / A stately pleasure-dome decree." ]; [ Tstr "Christabel"; Tint 1800; Tstr ("'Tis the middle of the night by the castle clock, / " ^ "And the owls have awakened the crowing cock;") ]; [ Tstr "Dejection: An Ode"; Tint 1802; Tstr ("Well! If the Bard was weather-wise, who made / " ^ "The grand old ballad of Sir Patrick Spence") ]; [ Tstr "The Rime of the Ancient Mariner"; Tint 1817; Tstr "It is an ancient Mariner / And he stoppeth one of three." ] ] ;; let add_to_hash hash name value = Hashtbl.add hash name value; hash ;; let make_hash_from_row poem_row = let row_hash = Hashtbl.create 3 in Thash (List.fold_left2 add_to_hash row_hash poem_row_names poem_row) ;; let make_poem_table () = Tlist (List.map make_hash_from_row poem_rows) ;; (* A hash containing he birthdate of Samuel Taylor Coleridge, in hash keys "day" "month" and "year". *) let birthdate = let hash = Hashtbl.create 3 in Hashtbl.add hash "day" (Tint 21); Hashtbl.add hash "month" (Tint 10); Hashtbl.add hash "year" (Tint 1772); Thash hash ;; (* A template function that returns a substring of a string. *) let substring ~args = match args with [ Tstr str; Tint start; Tint len ] -> Tstr (String.sub str start len) | _ -> raise (Tfun_error "Invalid argument") ;; (* Puts all of the above and some other bits into a template model. *) let make_model () = let root = Hashtbl.create 10 in Hashtbl.add root "title" (Tstr "CamlTemplate Test Page"); Hashtbl.add root "poet" (let hash = Hashtbl.create 2 in Hashtbl.add hash "name" (Tstr "Samuel Taylor Coleridge"); Hashtbl.add hash "birthdate" birthdate; Thash hash); Hashtbl.add root "substring" (Tfun substring); Hashtbl.add root "someText" (Tstr ""); Hashtbl.add root "poems" (make_poem_table ()); CamlTemplate.add_web_functions root; root ;; (* Runs coleridge.tmpl with the above model. *) let _ = (* Merge a template. *) let input_filename = "coleridge.tmpl" and output_filename = "coleridge.html" in eprintf "Reading %s\n" input_filename; let cache = CamlTemplate.Cache.create () in try let tmpl = CamlTemplate.Cache.get_template cache input_filename in (* eprintf "\nParse tree:\n%s\n" (CamlTemplate.dump tmpl); *) let buf = Buffer.create 256 in CamlTemplate.merge ~tmpl ~model:(make_model ()) ~buf; let out = open_out output_filename in set_binary_mode_out out true; output_string out (Buffer.contents buf); close_out out; eprintf "Wrote %s\n" output_filename with CamlTemplate.Syntax_error msg -> eprintf "\n%s\n" msg; exit 1 | CamlTemplate.Template_error msg -> eprintf "\n%s\n" msg; exit 1 ;; camltemplate-1.0.2/examples/filetest/footer.tmpl0100644000076400010400000000017407741024376025755 0ustar gdsАдминистраторы#* A footer used in coleridge.tmpl. $Id: footer.tmpl,v 1.4 2003-10-08 15:10:54 ben Exp $ *#


This is the footer. camltemplate-1.0.2/examples/filetest/macro.tmpl0100644000076400010400000000123010045517335025543 0ustar gdsАдминистраторы#* Macros used in coleridge.tmpl. $Id: macro.tmpl,v 1.6 2004-05-03 19:34:53 ben Exp $ *# #macro formatDate(year, month, day) #var (monthPrefix) #var (dayPrefix) #if (month < 10) #set (monthPrefix = "0") #end #if (day < 10) #set (dayPrefix = "0") #end ${year}-${monthPrefix}${month}-${dayPrefix}${day}\ #end #macro foo() #set (x = "foo") #* Sets x in template scope *# "${x}" #* Uses x from template scope *# #end #macro bar() #var (x = "bar") #* Sets local x *# "${x}" #* Uses local x *# #end #macro baz() #var (x) #* Sets local x to null *# "${x}" #* Uses local x *# #end #macro quux() "${x}" #* Uses x in template scope *# #end camltemplate-1.0.2/examples/filetest/Makefile0100644000076400010400000000057211030374372025211 0ustar gdsАдминистраторыTOP_DIR := ../.. -include $(TOP_DIR)/Makefile.config -include $(TOP_DIR)/Makefile.rules include ../examples.rules INCDIRS := $(shell ocamlfind query ) $(CAMLTEMPLATE_DIR) LIBS := unix str camltemplate SOURCES := filetest.ml RESULT := filetest TRASH := *~ coleridge.html OCAMLMAKEFILE := $(TOP_DIR)/OCamlMakefile .PHONY: all all: byte-code include $(TOP_DIR)/OCamlMakefile camltemplate-1.0.2/examples/hello/0040755000076400010400000000000011030647123023031 5ustar gdsАдминистраторыcamltemplate-1.0.2/examples/hello/hello.ml0100644000076400010400000000423210251606440024465 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: hello.ml,v 1.12 2005-06-08 15:22:08 ben Exp $ *) open Printf ;; open CamlTemplate.Model ;; let _ = (* Make a template cache. *) let cache = CamlTemplate.Cache.create () in (* Create a model. *) let model = Hashtbl.create 4 in Hashtbl.add model "message" (Tstr "Hello, world!"); try (* Get the template. *) let tmpl = CamlTemplate.Cache.get_template cache "hello.tmpl" (* Make a buffer for the output. *) and buf = Buffer.create 256 in (* Generate output. *) CamlTemplate.merge tmpl model buf; print_string (Buffer.contents buf) with CamlTemplate.Syntax_error msg -> eprintf "\n%s\n" msg | CamlTemplate.Template_error msg -> eprintf "\n%s\n" msg ;; camltemplate-1.0.2/examples/hello/hello.tmpl0100644000076400010400000000004007736350474025043 0ustar gdsАдминистраторыHere is the message: ${message} camltemplate-1.0.2/examples/hello/Makefile0100644000076400010400000000051311030375316024467 0ustar gdsАдминистраторыTOP_DIR := ../.. -include $(TOP_DIR)/Makefile.config -include $(TOP_DIR)/Makefile.rules include ../examples.rules INCDIRS := $(CAMLTEMPLATE_DIR) LIBS := unix str camltemplate SOURCES := hello.ml RESULT := hello TRASH := *~ OCAMLMAKEFILE := $(TOP_DIR)/OCamlMakefile .PHONY: all all: byte-code include $(TOP_DIR)/OCamlMakefile camltemplate-1.0.2/examples/Makefile0100644000076400010400000000144310244511400023357 0ustar gdsАдминистраторыTOP_DIR=.. -include $(TOP_DIR)/Makefile.config include $(TOP_DIR)/Makefile.rules BUILD_EXAMPLES := hello filetest thread ALL_EXAMPLES := $(BUILD_EXAMPLES) mod_caml fastcgi INSTALL_DIR := $(PREFIX)/share/$(PKGBASE) .PHONY: all all: set -e; for dir in $(BUILD_EXAMPLES); do cd $$dir; $(MAKE) all; cd ..; done .PHONY: clean clean: for dir in $(ALL_EXAMPLES); do cd $$dir; $(MAKE) clean; cd ..; done rm -f *~ .PHONY: install install: rm -rf $(INSTALL_DIR) mkdir -p $(INSTALL_DIR)/examples cp $(TOP_DIR)/OCamlMakefile $(INSTALL_DIR) cp -r examples.rules $(ALL_EXAMPLES) $(INSTALL_DIR)/examples find $(INSTALL_DIR)/examples -type d -name CVS -prune -exec rm -rf \{} \; find $(INSTALL_DIR)/examples -type d -name ._d -prune -exec rm -rf \{} \; .PHONY: uninstall uninstall: rm -rf $(INSTALL_DIR) camltemplate-1.0.2/examples/mod_caml/0040755000076400010400000000000011030647123023501 5ustar gdsАдминистраторыcamltemplate-1.0.2/examples/mod_caml/cthello.ml.in0100644000076400010400000000500010251606440026063 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: cthello.ml.in,v 1.9 2005-06-08 15:22:08 ben Exp $ *) (* A CamlTemplate version of mod_caml's 'hello' example. Make sure you can run that example first, before trying to run this one. *) open Apache ;; open Registry ;; open Cgi ;; open CamlTemplate.Model ;; open Printf ;; let template_file = "@TEMPLATEDIR@/cthello.tmpl" ;; let run r = let q = new cgi r in (* Create a model. *) let model = Hashtbl.create 4 in Hashtbl.add model "message" (Tstr "Hello, world!"); (* Make a template cache. *) let cache = CamlTemplate.Cache.create () in try (* Get the template. *) let tmpl = CamlTemplate.Cache.get_template cache template_file (* Make a buffer for the output. *) and buf = Buffer.create 256 in (* Generate output. *) CamlTemplate.merge tmpl model buf; q#header (); ignore (print_string r (Buffer.contents buf)) with CamlTemplate.Syntax_error msg -> eprintf "\n%s\n" msg | CamlTemplate.Template_error msg -> eprintf "\n%s\n" msg ;; let () = register_script run ;; camltemplate-1.0.2/examples/mod_caml/cthello.tmpl0100644000076400010400000000013210245117640026025 0ustar gdsАдминистраторы Hello Here is the message: ${message} camltemplate-1.0.2/examples/mod_caml/Makefile0100644000076400010400000000157511030375316025150 0ustar gdsАдминистраторыTOP_DIR := ../.. -include $(TOP_DIR)/Makefile.rules include ../examples.rules # Change this to the directory where you install .cmo files to be run # by mod_caml. MODCAML_BINDIR := /var/www/caml-bin # Change this to the directory where you want to install templates. TEMPLATEDIR := /var/www/caml-templates # Where to find the 'apache' package installed by mod_caml. OCAMLLIBDIR := $(shell ocamlc -where) INCDIRS := $(OCAMLLIBDIR)/apache $(CAMLTEMPLATE_DIR) LIBS := unix str cgi camltemplate SOURCES := cthello.ml TRASH := *~ cthello.ml OCAMLMAKEFILE := $(TOP_DIR)/OCamlMakefile .PHONY: all all: cthello.ml byte-code-nolink cthello.ml: cthello.ml.in sed -e 's,@TEMPLATEDIR@,$(TEMPLATEDIR),g' \ < $< > $@ .PHONY: install install: mkdir -p $(MODCAML_BINDIR) cp cthello.cmo $(MODCAML_BINDIR) mkdir -p $(TEMPLATEDIR) cp cthello.tmpl $(TEMPLATEDIR) include $(TOP_DIR)/OCamlMakefile camltemplate-1.0.2/examples/mod_caml/README0100644000076400010400000000046107740120664024370 0ustar gdsАдминистраторыThis example isn't built by default, because it requires mod_caml. 1. Follow the instructions on installing with mod_caml in the top-level INSTALL file. 2. Change the paths in this example's Makefile, if necessary. 3. make; make install 4. Open http://localhost/caml-bin/cthello.cmo in a web browser. camltemplate-1.0.2/examples/thread/0040755000076400010400000000000011030647123023175 5ustar gdsАдминистраторыcamltemplate-1.0.2/examples/thread/Makefile0100644000076400010400000000106311030374372024635 0ustar gdsАдминистраторыTOP_DIR := ../.. -include $(TOP_DIR)/Makefile.rules include ../examples.rules INCDIRS := -I $(shell ocamlfind query str) -I $(CAMLTEMPLATE_DIR) BYTE_LIBS := unix.cma str.cma threads.cma camltemplate.cma camlTemplate_mt.cmo NATIVE_LIBS := unix.cmxa str.cmxa threads.cmxa camltemplate.cmxa camlTemplate_mt.cmx SOURCES := thread_test.ml RESULT := thread_test .PHONY: all opt clean all: ocamlc -thread $(INCDIRS) -o $(RESULT) $(BYTE_LIBS) $(SOURCES) opt: ocamlopt -thread $(INCDIRS) -o $(RESULT) $(NATIVE_LIBS) $(SOURCES) clean: rm -f $(RESULT) *.cm? *.o *~ camltemplate-1.0.2/examples/thread/thread_test.ml0100644000076400010400000000510010251606440026027 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: thread_test.ml,v 1.11 2005-06-08 15:22:08 ben Exp $ *) open Printf ;; open CamlTemplate.Model ;; let thread_fun cache thread_num = (* Create a model. *) let model = Hashtbl.create 4 in Hashtbl.add model "threadNum" (Tint thread_num); for i = 1 to 5 do try (* Get the template. *) let tmpl = CamlTemplate.Cache.get_template cache "thread_test.tmpl" (* Make a buffer for the output. *) and buf = Buffer.create 256 in (* Generate output. *) CamlTemplate.merge tmpl model buf; printf "Thread %d: %s\n" thread_num (Buffer.contents buf); Thread.yield () with CamlTemplate.Syntax_error msg -> eprintf "\n%s\n" msg | CamlTemplate.Template_error msg -> eprintf "\n%s\n" msg done ;; let _ = (* Make a template cache. *) let cache = CamlTemplate.Cache.create () in let threads = Stack.create () in for thread_num = 1 to 5 do Stack.push (Thread.create (thread_fun cache) thread_num) threads done; try while true do Thread.join (Stack.pop threads) done with Stack.Empty -> () ;; camltemplate-1.0.2/examples/thread/thread_test.tmpl0100644000076400010400000000003007737640243026406 0ustar gdsАдминистраторыThread ${threadNum} herecamltemplate-1.0.2/INSTALL0100644000076400010400000000142511030375316021142 0ustar gdsАдминистраторыQuick Installation Instructions ------------------------------- If you use GODI (http://www.ocaml-programming.de/godi/), you can install CamlTemplate from godi_console. Otherwise, you can install manually as described below. Installing Manually ------------------- Requirements: * Objective Caml 3.08.3 or above. * GNU make. To see the configuration options, type: ./configure --help Type: ./configure make make opt make test Then as root, type: make install This installs the library using ocamlfind. Documentation is installed in $PREFIX/doc/camltemplate. Examples are installed in $PREFIX/share/camltemplate/examples. To unstall the library, type 'make uninstall' as root. The manual contains instructions on integrating CamlTemplate with mod_caml and mod_fastcgi. camltemplate-1.0.2/Makefile0100644000076400010400000000403410245323705021552 0ustar gdsАдминистраторыDIRS := src examples doc VERSION := $(shell grep version src/META | sed -e 's/version="//' -e 's/".*//') DIST_DIR := camltemplate-$(VERSION) # PKGBASE is provided by GODIVA. ifeq ($(PKGBASE),) PKGBASE := camltemplate endif export PKGBASE # Builds bytecode. .PHONY: all all: Makefile.config cd src; $(MAKE) all cd examples; $(MAKE) all # Builds native code. .PHONY: opt opt: Makefile.config cd src; $(MAKE) opt # Builds HTML documentation. .PHONY: htdoc htdoc: Makefile.config cd doc; make htdoc # Builds documentation in all formats. .PHONY: pdfdoc pdfdoc: Makefile.config cd doc; make pdfdoc # Runs a regression test. .PHONY: test test: test/test.sh # Installs the library. .PHONY: install install: Makefile.config cd src; $(MAKE) install cd doc; $(MAKE) install cd examples; $(MAKE) install # Uninstalls the library. .PHONY: uninstall uninstall: Makefile.config cd src; $(MAKE) uninstall cd doc; $(MAKE) uninstall cd examples; $(MAKE) uninstall # Creates a distribution tarball. .PHONY: dist dist: distclean all htdoc pdfdoc set -e; \ ./configure; \ rm -rf $(DIST_DIR)*; \ files=`ls`; \ mkdir $(DIST_DIR); \ cp -r $$files $(DIST_DIR); \ find $(DIST_DIR) -type d -name CVS -prune -exec rm -rf \{} \; cd $(DIST_DIR); \ for dir in $(DIRS); do \ if [ $$dir != "doc" ]; then \ cd $$dir; $(MAKE) clean; cd ..; \ fi; \ done; \ cd doc; $(MAKE) distclean; cd ../..; \ rm -f $(DIST_DIR)/Makefile.config; \ tar zcf $(DIST_DIR).tar.gz $(DIST_DIR); \ rm -rf $(DIST_DIR) # Copies the distribution and docs into the SauceCode web site. .PHONY: webinstall webinstall: $(DIST_DIR).tar.gz cp -r doc/html/api doc/html/manual ../../saucecode-site/saucecode.org/htdocs/camltemplate mkdir -p ../../saucecode-site/saucecode.org/htdocs/camltemplate/releases cp $(DIST_DIR).tar.gz ../../saucecode-site/saucecode.org/htdocs/camltemplate/releases # Deletes generated files. .PHONY: clean clean: for dir in $(DIRS); do cd $$dir; $(MAKE) clean; cd ..; done rm -rf *~ camltemplate-* .PHONY: distclean distclean: clean rm -f Makefile.config ./configure camltemplate-1.0.2/Makefile.rules0100644000076400010400000000026610245117640022705 0ustar gdsАдминистраторыTOOLS_DIR := $(TOP_DIR)/tools COLLECT_FILES := $(TOOLS_DIR)/collect_files OCAMLFIND := ocamlfind CAMLTEMPLATE_DIR := $(TOP_DIR)/src CAMLTEMPLATE_LIB := $(TOP_DIR)/src/camltemplate camltemplate-1.0.2/NEWS0100644000076400010400000001100411030644536020605 0ustar gdsАдминистраторы2008-06-26 Version 1.0.2 released: * Removed dependency from Pcre, standart library Str used instead (thanks to Eric Merritt). * Fixed handling of --prefix switch for configure script (thanks to Dave Peticolas). * Moved to OCaml forge, new project page: http://forge.ocamlcore.org/projects/camltemplate/ 2005-07-07 Version 1.0.1 released: * Minor cleanups. 2005-05-26 Version 1.0.0 released: * Fixed bug: META always depended on 'threads' even if threads weren't enabled. Thread support is now compiled into a separate file which can be linked in if needed, instead of being enabled when CamlTemplate is compiled (thanks to Janne Hellsten). * Fixed incorrect interpretation of backslashes. * Fixed reading of template files on Cygwin (thanks to Janne Hellsten). * Fixed incorrect handling of syntax errors in macro call arguments. * Added FastCGI example. 2004-07-15 Version 0.9.2 released: * Fixed bug that caused compile error if thread support was enabled. 2004-05-11 Version 0.9.1 released: * Changed the line-continuation character from '#' to the more standard '\'. * Now requires OCaml 3.07. * Use GODI's OCamlMakefile when available. * Some clarifications in the manual. 2004-05-01 Version 0.9.0 released: * API change: source_loader is now a class type rather than a virtual class. * Template syntax changes: whitespace preceding a statement is now ignored only if the whitespace starts at the beginning of a line. Preceding a newline with '#' now causes it to be ignored. * Packaged for GODI. * 'make' targets have changed: 'make' now just builds the bytecode version; use 'make opt' to build the native-code version. 'make install' now installs documentation and examples. * Fixed incorrect linking to Unix and Pcre libraries (thanks to Olivier Andrieu). * Fixed handling of empty templates. * Reorganised and cleaned up source code. 2004-03-13 Version 0.8.1 released: * Fixed a bug that could have caused a template to be parsed incorrectly if there was a syntax error in the most recently parsed template. 2004-02-24 Version 0.8.0 released: * Added support for multiple template caches. * Made some cosmetic changes in the API. * Added a 'configure' script. 2004-02-04 Version 0.7.2 released: * Added 'null' literal. * Fixed installation of native library (thanks to Kamil Shakirov). * Fixed Makefile to do a better job of finding Pcre, and to invoke dvips correctly on Mandrake Linux. * Documentation fixes. 2004-01-05 Version 0.7.1 released: * Whitespace immediately preceding a statement, on the same line, is now ignored. * Fixed a bug in the handling of escape characters in string literals. * A few documentation fixes. 2004-01-03 Version 0.7.0 released: * Added support for floating-point values. * Implemented nested scopes: macros have their own scope. Setting values in a template no longer changes the model. * Added a simple macro namespace system. Each template provides a namespace for its macros; to use macros defined in another template, you now have to use the new #open statement. * Added a bracket operator for calculating a hash key at run time. * Added a virtual class to replace the two separate functions for loading and checking template source code. * Shortened template model type names. * Added some design documentation. * Added licence exception allowing CamlTemplate to be linked with Apache. * Several bug fixes. 2003-10-09 Version 0.6.1 released: * Replaced Str with Pcre, because Str isn't thread-safe. 2003-10-08 Version 0.6.0 released: * No longer requires a patch for mod_caml, because the patch has been included in mod_caml. * Added functions for escaping URLs and HTML text. * Bug fix: when an error occurred in a macro template, the name of the macro template was not reported in the exception message, and in some cases the line number was incorrect. * Added 'make test'. 2003-10-06 Version 0.5.1 released (minor build and documentation fixes). Version 0.5.0 released. camltemplate-1.0.2/OCamlMakefile0100644000076400010400000006453710051231271022473 0ustar gdsАдминистраторы########################################################################### # OCamlMakefile # Copyright (C) 1999-2004 Markus Mottl # # For updates see: # http://www.oefai.at/~markus/ocaml_sources # # $Id: OCamlMakefile,v 1.4 2004-05-14 20:57:29 ben Exp $ # ########################################################################### # Modified by damien for .glade.ml compilation # Set these variables to the names of the sources to be processed and # the result variable. Order matters during linkage! ifndef SOURCES SOURCES := foo.ml endif export SOURCES ifndef RES_CLIB_SUF RES_CLIB_SUF := _stubs endif export RES_CLIB_SUF ifndef RESULT RESULT := foo endif export RESULT ifndef DOC_FILES DOC_FILES := $(filter %.mli, $(SOURCES)) endif export DOC_FILES export BCSUFFIX export NCSUFFIX ifndef TOPSUFFIX TOPSUFFIX := .top endif export TOPSUFFIX # Eventually set include- and library-paths, libraries to link, # additional compilation-, link- and ocamlyacc-flags # Path- and library information needs not be written with "-I" and such... # Define THREADS if you need it, otherwise leave it unset (same for # USE_CAMLP4)! export THREADS export VMTHREADS export ANNOTATE export USE_CAMLP4 export INCDIRS export LIBDIRS export EXTLIBDIRS export RESULTDEPS export OCAML_DEFAULT_DIRS export LIBS export CLIBS export OCAMLFLAGS export OCAMLNCFLAGS export OCAMLBCFLAGS export OCAMLLDFLAGS export OCAMLNLDFLAGS export OCAMLBLDFLAGS ifndef OCAMLCPFLAGS OCAMLCPFLAGS := a endif export OCAMLCPFLAGS export PPFLAGS export YFLAGS export IDLFLAGS export OCAMLDOCFLAGS export DVIPSFLAGS export STATIC # Add a list of optional trash files that should be deleted by "make clean" export TRASH #################### variables depending on your OCaml-installation ifdef MINGW export MINGW WIN32 := 1 endif ifdef MSVC export MSVC WIN32 := 1 EXT_OBJ := obj EXT_LIB := lib ifeq ($(CC),gcc) # work around GNU Make default value ifdef THREADS CC := cl -MT else CC := cl endif endif ifeq ($(CXX),g++) # work around GNU Make default value CXX := $(CC) endif CFLAG_O := -Fo endif ifdef WIN32 EXT_CXX := cpp EXE := .exe endif ifndef EXT_OBJ EXT_OBJ := o endif ifndef EXT_LIB EXT_LIB := a endif ifndef EXT_CXX EXT_CXX := cc endif ifndef EXE EXE := # empty endif ifndef CFLAG_O CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! endif export CC export CXX export CFLAGS export CXXFLAGS export LDFLAGS ifndef RPATH_FLAG RPATH_FLAG := -R endif export RPATH_FLAG ifndef PIC_FLAGS PIC_FLAGS := -fPIC -DPIC endif export PIC_FLAGS BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) ifndef OCAMLFIND OCAMLFIND := ocamlfind endif export OCAMLFIND ifndef OCAMLC OCAMLC := ocamlc endif export OCAMLC ifndef OCAMLOPT OCAMLOPT := ocamlopt endif export OCAMLOPT ifndef OCAMLMKTOP OCAMLMKTOP := ocamlmktop endif export OCAMLMKTOP ifndef OCAMLCP OCAMLCP := ocamlcp endif export OCAMLCP ifndef OCAMLDEP OCAMLDEP := ocamldep endif export OCAMLDEP ifndef OCAMLLEX OCAMLLEX := ocamllex endif export OCAMLLEX ifndef OCAMLYACC OCAMLYACC := ocamlyacc endif export OCAMLYACC ifndef OCAMLMKLIB OCAMLMKLIB := ocamlmklib endif export OCAMLMKLIB ifndef OCAML_GLADECC OCAML_GLADECC := lablgladecc2 endif export OCAML_GLADECC ifndef OCAML_GLADECC_FLAGS OCAML_GLADECC_FLAGS := endif export OCAML_GLADECC_FLAGS ifndef CAMELEON_REPORT CAMELEON_REPORT := report endif export CAMELEON_REPORT ifndef CAMELEON_REPORT_FLAGS CAMELEON_REPORT_FLAGS := endif export CAMELEON_REPORT_FLAGS ifndef CAMELEON_ZOGGY CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo endif export CAMELEON_ZOGGY ifndef CAMELEON_ZOGGY_FLAGS CAMELEON_ZOGGY_FLAGS := endif export CAMELEON_ZOGGY_FLAGS ifndef CAMLIDL CAMLIDL := camlidl endif export CAMLIDL ifndef CAMLIDLDLL CAMLIDLDLL := camlidldll endif export CAMLIDLDLL ifndef NOIDLHEADER MAYBE_IDL_HEADER := -header endif export NOIDLHEADER export NO_CUSTOM ifndef CAMLP4 CAMLP4 := camlp4 endif export CAMLP4 ifdef PACKS empty := space := $(empty) $(empty) comma := , ifdef PREDS PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) else OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) OCAML_DEP_PACKAGES := endif OCAML_FIND_LINKPKG := -linkpkg REAL_OCAMLFIND := $(OCAMLFIND) endif export OCAML_FIND_PACKAGES export OCAML_DEP_PACKAGES export OCAML_FIND_LINKPKG export REAL_OCAMLFIND ifndef OCAMLDOC OCAMLDOC := ocamldoc endif export OCAMLDOC ifndef LATEX LATEX := latex endif export LATEX ifndef DVIPS DVIPS := dvips endif export DVIPS ifndef PS2PDF PS2PDF := ps2pdf endif export PS2PDF ifndef OCAMLMAKEFILE OCAMLMAKEFILE := OCamlMakefile endif export OCAMLMAKEFILE ifndef OCAMLLIBPATH OCAMLLIBPATH := \ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml) endif export OCAMLLIBPATH ifndef OCAML_LIB_INSTALL OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib endif export OCAML_LIB_INSTALL ########################################################################### #################### change following sections only if #################### you know what you are doing! # delete target files when a build command fails .PHONY: .DELETE_ON_ERROR .DELETE_ON_ERROR: # for pedants using "--warn-undefined-variables" export MAYBE_IDL export REAL_RESULT export CAMLIDLFLAGS export THREAD_FLAG export RES_CLIB export MAKEDLL export ANNOT_FLAG INCFLAGS := SHELL := /bin/sh MLDEPDIR := ._d BCDIDIR := ._bcdi NCDIDIR := ._ncdi FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.c %.$(EXT_CXX) %.rep %.zog %.glade FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) FILTERED_REP := $(filter %.rep, $(FILTERED)) DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) AUTO_REP := $(FILTERED_REP:.rep=.ml) FILTERED_ZOG := $(filter %.zog, $(FILTERED)) DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) FILTERED_GLADE := $(filter %.glade, $(FILTERED)) DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) FILTERED_ML := $(filter %.ml, $(FILTERED)) DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) FILTERED_MLI := $(filter %.mli, $(FILTERED)) DEP_MLI := $(FILTERED_MLI:.mli=.di) FILTERED_MLL := $(filter %.mll, $(FILTERED)) DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) AUTO_MLL := $(FILTERED_MLL:.mll=.ml) FILTERED_MLY := $(filter %.mly, $(FILTERED)) DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) FILTERED_IDL := $(filter %.idl, $(FILTERED)) DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) ifndef NOIDLHEADER C_IDL += $(FILTERED_IDL:.idl=.h) endif OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) FILTERED_C_CXX := $(filter %.c %.$(EXT_CXX), $(FILTERED)) OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) MLDEPS := $(filter %.d, $(ALL_DEPS)) MLIDEPS := $(filter %.di, $(ALL_DEPS)) BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.rep %.zog %.glade, $(FILTERED)) IMPLO_INTF := $(ALLML:%.mli=%.mli.__) IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ $(basename $(file)).cmi $(basename $(file)).cmo) IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) INTF := $(filter %.cmi, $(IMPLO_INTF)) IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) IMPL_ASM := $(IMPL_CMO:.cmo=.asm) IMPL_S := $(IMPL_CMO:.cmo=.s) OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) EXECS := $(addsuffix $(EXE), \ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) ifdef WIN32 EXECS += $(BCRESULT).dll $(NCRESULT).dll endif CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) ifneq ($(strip $(OBJ_LINK)),) RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) endif ifndef MSVC DLLSONAME := dll$(CLIB_BASE).so endif NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \ $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \ $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) ifndef MSVC ifndef STATIC NONEXECS += $(DLLSONAME) endif endif ifndef LIBINSTALL_FILES LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) ifndef MSVC ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) LIBINSTALL_FILES += $(DLLSONAME) endif endif endif endif export LIBINSTALL_FILES ifdef WIN32 # some extra stuff is created while linking DLLs NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp endif TARGETS := $(EXECS) $(NONEXECS) # If there are IDL-files ifneq ($(strip $(FILTERED_IDL)),) MAYBE_IDL := -cclib -lcamlidl endif ifdef USE_CAMLP4 CAMLP4PATH := \ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4) INCFLAGS := -I $(CAMLP4PATH) CINCFLAGS := -I$(CAMLP4PATH) endif DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %) CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ $(EXTLIBDIRS:%=-L%) $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) \ $(OCAML_DEFAULT_DIRS:%=-L%) ifndef PROFILING INTF_OCAMLC := $(OCAMLC) else ifndef THREADS INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) else # OCaml does not support profiling byte code # with threads (yet), therefore we force an error. ifndef REAL_OCAMLC $(error Profiling of multithreaded byte code not yet supported by OCaml) endif INTF_OCAMLC := $(OCAMLC) endif endif COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) \ $(OCAML_DEFAULT_DIRS:%=-ccopt -L%) ifndef MSVC CLIBS_OPTS := $(CLIBS:%=-cclib -l%) else # MSVC libraries do not have 'lib' prefix CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) endif ifneq ($(strip $(OBJ_LINK)),) ifdef CREATE_LIB OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) else OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) endif else OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) endif # If we have to make byte-code ifndef REAL_OCAMLC # EXTRADEPS is added dependencies we have to insert for all # executable files we generate. Ideally it should be all of the # libraries we use, but it's hard to find the ones that get searched on # the path since I don't know the paths built into the compiler, so # just include the ones with slashes in their names. EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) REAL_OCAMLC := $(INTF_OCAMLC) REAL_IMPL := $(IMPL_CMO) REAL_IMPL_INTF := $(IMPLO_INTF) IMPL_SUF := .cmo DEPFLAGS := MAKE_DEPS := $(MLDEPS) $(BCDEPIS) ifdef CREATE_LIB CFLAGS := $(PIC_FLAGS) $(CFLAGS) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) MAKEDLL := $(DLLSONAME) ALL_LDFLAGS := -dllib $(DLLSONAME) endif endif endif ifndef NO_CUSTOM ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS))" "" ALL_LDFLAGS += -custom endif endif ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ $(COMMON_LDFLAGS) $(LIBS:%=%.cma) CAMLIDLDLLFLAGS := ifdef THREADS ifdef VMTHREADS THREAD_FLAG := -vmthread else THREAD_FLAG := -thread endif ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS) endif endif endif # we have to make native-code else EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef PROFILING SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) PLDFLAGS := else SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) PLDFLAGS := -p endif REAL_IMPL := $(IMPL_CMX) REAL_IMPL_INTF := $(IMPLX_INTF) IMPL_SUF := .cmx CFLAGS := -DNATIVE_CODE $(CFLAGS) DEPFLAGS := -native MAKE_DEPS := $(MLDEPS) $(NCDEPIS) ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) CAMLIDLDLLFLAGS := -opt ifndef CREATE_LIB ALL_LDFLAGS += $(LIBS:%=%.cmxa) else CFLAGS := $(PIC_FLAGS) $(CFLAGS) endif ifdef THREADS THREAD_FLAG := -thread ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS) endif endif endif endif export MAKE_DEPS ifdef ANNOTATE ANNOT_FLAG := -dtypes else endif ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) ifdef make_deps -include $(MAKE_DEPS) PRE_TARGETS := endif ########################################################################### # USER RULES # Call "OCamlMakefile QUIET=" to get rid of all of the @'s. QUIET=@ # generates byte-code (default) byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes bc: byte-code byte-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes bcnl: byte-code-nolink top: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes # generates native-code native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes nc: native-code native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncnl: native-code-nolink # generates byte-code libraries byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" \ CREATE_LIB=yes \ make_deps=yes bcl: byte-code-library # generates native-code libraries native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes ncl: native-code-library ifdef WIN32 # generates byte-code dll byte-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).dll \ REAL_RESULT="$(BCRESULT)" \ make_deps=yes bcd: byte-code-dll # generates native-code dll native-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).dll \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncd: native-code-dll endif # generates byte-code with debugging information debug-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dc: debug-code debug-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcnl: debug-code-nolink # generates byte-code libraries with debugging information debug-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcl: debug-code-library # generates byte-code for profiling profiling-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ make_deps=yes pbc: profiling-byte-code # generates native-code profiling-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PROFILING="y" \ make_deps=yes pnc: profiling-native-code # generates byte-code libraries profiling-byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ CREATE_LIB=yes \ make_deps=yes pbcl: profiling-byte-code-library # generates native-code libraries profiling-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" PROFILING="y" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes pncl: profiling-native-code-library # packs byte-code objects pack-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ REAL_RESULT="$(BCRESULT)" \ PACK_LIB=yes make_deps=yes pabc: pack-byte-code # packs native-code objects pack-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(NCRESULT).cmx $(NCRESULT).o \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PACK_LIB=yes make_deps=yes panc: pack-native-code # generates HTML-documentation htdoc: doc/$(RESULT)/html # generates Latex-documentation ladoc: doc/$(RESULT)/latex # generates PostScript-documentation psdoc: doc/$(RESULT)/latex/doc.ps # generates PDF-documentation pdfdoc: doc/$(RESULT)/latex/doc.pdf # generates all supported forms of documentation doc: htdoc ladoc psdoc pdfdoc ########################################################################### # LOW LEVEL RULES $(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \ $(REAL_IMPL) nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) ifdef WIN32 $(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ -o $@ $(REAL_IMPL) endif %$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \ $(REAL_IMPL) .SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ .mly .di .d .$(EXT_LIB) .idl .c .$(EXT_CXX) .h .so \ .rep .zog .glade ifndef MSVC $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \ $(OCAMLMKLIB_FLAGS) endif $(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \ $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(REAL_IMPL) $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \ $(OCAMLNLDFLAGS) -o $@ $(REAL_IMPL) $(RES_CLIB): $(OBJ_LINK) ifndef MSVC ifneq ($(strip $(OBJ_LINK)),) $(AR) rcs $@ $(OBJ_LINK) endif else ifneq ($(strip $(OBJ_LINK)),) lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) endif endif .mli.cmi: $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ else \ echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ fi .ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ else \ echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ fi ifdef PACK_LIB $(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \ $(OBJS_LIBS) -o $@ $(REAL_IMPL) endif .PRECIOUS: %.ml %.ml: %.mll $(OCAMLLEX) $< .PRECIOUS: %.ml %.mli %.ml %.mli: %.mly $(OCAMLYACC) $(YFLAGS) $< .PRECIOUS: %.ml %.ml : %.rep $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< .PRECIOUS: %.ml %.ml : %.zog $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ .PRECIOUS: %.ml %.ml : %.glade $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ .PRECIOUS: %.ml %.mli %_stubs.c %.h %.ml %.mli %_stubs.c %.h: %.idl $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ $(CAMLIDLFLAGS) $< $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi .c.$(EXT_OBJ): $(OCAMLC) -c -cc "$(CC) $(CFLAGS) $(CINCFLAGS)" \ $< $(CFLAG_O)$@ .$(EXT_CXX).$(EXT_OBJ): $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ $(MLDEPDIR)/%.d: %.ml $(QUIET)echo making $@ from $< $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(DINCFLAGS) $< > $@; \ else \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \ fi $(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli $(QUIET)echo making $@ from $< $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \ else \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \ fi doc/$(RESULT)/html: $(DOC_FILES) rm -rf $@ mkdir -p $@ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ echo $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \ $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \ else \ echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -html -d $@ $(OCAMLDOCFLAGS) \ $(INCFLAGS) $(DOC_FILES); \ $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -html -d $@ $(OCAMLDOCFLAGS) \ $(INCFLAGS) $(DOC_FILES); \ fi doc/$(RESULT)/latex: $(DOC_FILES) rm -rf $@ mkdir -p $@ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ echo $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \ $(DOC_FILES) -o $@/doc.tex; \ $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \ -o $@/doc.tex; \ else \ echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \ $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \ $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \ $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \ fi doc/$(RESULT)/latex/doc.ps: doc/$(RESULT)/latex cd doc/$(RESULT)/latex && \ $(LATEX) doc.tex && \ $(LATEX) doc.tex && \ $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F) doc/$(RESULT)/latex/doc.pdf: doc/$(RESULT)/latex/doc.ps cd doc/$(RESULT)/latex && $(PS2PDF) $( tvalue) (** The type contained in a [Tfun]: a function that takes [tvalue]s as arguments, and returns a [tvalue]. *) (** An exception that [tfun] functions can raise when called by a template. *) exception Tfun_error of string end ;; (** {1 Templates} *) (** Represents a parsed template. *) type template ;; (** Merges the data in a {!CamlTemplate.Model.thash} with the template, and returns the resulting text in the buffer provided. @raise Template_error if an error occurs in the template. *) val merge : tmpl:template -> model:Model.thash -> buf:Buffer.t -> unit ;; (** Returns the name of a template. *) val get_name : template -> string ;; (** Returns a simple string representation of the parse tree, for debugging purposes. *) val dump : template -> string ;; (** {1 Exceptions} *) (** Raised if an error is found when parsing template source code. *) exception Syntax_error of string ;; (** Raised if an error occurs when merging data with a template. *) exception Template_error of string ;; (** {1 Template Loading and Caching} *) (** Caches templates. *) module Cache : sig (** {1 Customising How Source Code is Loaded} *) (** The type returned by a template source loader when it checks whether a template's source code has changed. *) type source_check_result = TemplateUnchanged (** Indicates that the source code of the checked template has not changed since it was loaded. *) | TemplateChanged (** Indicates that the source code of the checked template has changed since it was loaded. *) | TemplateDeleted (** Indicates that the source code of the checked template was deleted since it was loaded. *) ;; (** An implementation of this class type can be used by a template cache to load template source code. *) class type source_loader = object (** Checks whether a template's source has changed since it was last loaded. The load time is a time in seconds, as returned by [Unix.time]. *) method check : template_name:string -> load_time:float -> source_check_result (** Loads the source code for a template. *) method load : template_name:string -> string end ;; (** Upcasting function for {!CamlTemplate.Cache.source_loader}. *) val as_source_loader : #source_loader -> source_loader ;; (** Returns a {!CamlTemplate.Cache.source_loader} that loads template source code from files in a directory. The name of each template is used as the filename. @param template_dir the directory in which the template source files are located. *) val make_file_loader : template_dir:string -> source_loader ;; (** {1 Using Template Caches} *) (** The type of template caches. *) type t (** Creates a template cache. @param loader the [source_loader] that will be used to load template source code for the cache. If omitted, the cache uses a [source_loader] that loads template source code from the current working directory. @param check_interval the interval at which the template cache should be refreshed. The default is 5 minutes. If the interval is zero, the cache will be refreshed every time {!CamlTemplate.Cache.get_template} is called. If the interval is negative, it will never be refreshed. *) val create : ?loader:source_loader -> ?check_interval:float -> unit -> t ;; (** Given a cache and the name of a template, returns the template from the cache. If the template is not in the cache, it is loaded and cached. If the cache is due to be refreshed, this method refreshes the cache (i.e. reloads any templates that have been modified since they were last loaded, and removes any deleted templates from the cache) before looking for the requested template. @raise CamlTemplate.Syntax_error if a template cannot be parsed. *) val get_template : cache:t -> template_name:string -> template ;; end ;; (** {1 Miscellaneous} *) (** Adds the following template functions to a template data model: - [urlEncode] URL-encodes a string. - [escHtml] Escapes special characters in text to be included in an HTML document. - [escHtmlAttr] Escapes special characters in text to be included in an HTML attribute. - [escHtmlTextarea] Escapes special characters in text to be included in an HTML [textarea]. - [asList] Converts any value to a list, if it isn't already a list. If the argument is a list, returns the argument. If the argument is null, returns an empty list. Otherwise, returns a single-element list containing the argument. This may be useful for dealing with form input fields that can have multiple values. Each of these functions expects one argument. *) val add_web_functions : Model.thash -> unit ;; camltemplate-1.0.2/src/camlTemplate_mt.ml0100644000076400010400000000106710245200423024335 0ustar gdsАдминистраторы open CtUtil ;; (* In multi-threading mode, the variable create_lock_unlock_pair is initialized right at startup with a reasonable mutex creator, and static_mutex is initialised with a real mutex. In non-mt mode, the default value of these variables contain a dummy creator that does not lock anything. *) let _ = CtUtil.create_lock_unlock := (fun () -> let mtx = Mutex.create () in { lock = (fun () -> Mutex.lock mtx); unlock = (fun () -> Mutex.unlock mtx) } ); CtUtil.static_mutex := !CtUtil.create_lock_unlock () ;; camltemplate-1.0.2/src/ctBinop.ml0100644000076400010400000002210110251606440022621 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctBinop.ml,v 1.10 2005-06-08 15:22:08 ben Exp $ *) open Printf ;; open CtSourcePos ;; open CtTemplateModel ;; open CtExpression ;; open CtExceptions ;; (* Most binary operators are defined in this module. *) (* A virtual base class for binary operators. *) class virtual binary_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit expression pos val left = left val right = right method calculate left_value right_value int_fun float_fun = (* Promote ints to floats if necessary. *) match (left_value, right_value) with (Tfloat left_float, _) -> Tfloat (float_fun left_float (right#value_to_float right_value)) | (_, Tfloat right_float) -> Tfloat (float_fun (left#value_to_float left_value) right_float) | (_, _) -> Tint (int_fun (left#value_to_int left_value) (right#value_to_int right_value)) end ;; (* Addition and string concatenation operator. *) class plus_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right method get_value cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in match left_value with (* Concatenate strings if the lhs is a string. *) Tstr s -> Tstr (s ^ (right#value_to_string right_value)) | _ -> self#calculate left_value right_value (+) (+.) method dump = sprintf "(%s + %s)" left#dump right#dump end ;; (* Subtraction operator. *) class minus_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right method get_value cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in self#calculate left_value right_value (-) (-.) method dump = sprintf "(%s - %s)" left#dump right#dump end ;; (* Multiplication operator. *) class times_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right method get_value cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in self#calculate left_value right_value ( * ) ( *. ) method dump = sprintf "(%s * %s)" left#dump right#dump end ;; (* Division operator. *) class div_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right method get_value cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in try self#calculate left_value right_value (/) (/.) with Division_by_zero -> raise (Template_error (template_error_message pos "Division by zero")) method dump = sprintf "(%s / %s)" left#dump right#dump end ;; (* Integer modulo operator. *) class mod_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right method get_value cur_scope = try Tint ((left#to_int cur_scope) mod (right#to_int cur_scope)) with Division_by_zero -> raise (Template_error (template_error_message pos "Division by zero")) method dump = sprintf "(%s %% %s)" left#dump right#dump end ;; (* Logical AND operator. *) class and_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right inherit boolean_op method to_bool cur_scope = (left#to_bool cur_scope) && (right#to_bool cur_scope) method dump = sprintf "(%s && %s)" left#dump right#dump end ;; (* Logical OR operator. *) class or_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right inherit boolean_op method to_bool cur_scope = (left#to_bool cur_scope) || (right#to_bool cur_scope) method dump = sprintf "(%s || %s)" left#dump right#dump end ;; (* Virtual base class for operators that compare two values. *) class virtual comparison_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit binary_op pos left right inherit boolean_op method do_compare left_value right_value = match (left_value, right_value) with (* Compare strings if the lhs is a string. Otherwise, promote ints to floats if necessary. *) (Tstr left_str, _) -> compare left_str (right#value_to_string right_value) | (Tfloat left_float, _) -> compare left_float (right#value_to_float right_value) | (_, Tfloat right_float) -> compare (left#value_to_float left_value) right_float | (Tint left_int, _) -> compare left_int (right#value_to_int right_value) | (Tbool left_bool, _) -> compare left_bool (right#value_to_bool right_value) | _ -> let detail = sprintf "Can't compare %s of type %s with %s of type %s" left#get_desc (get_type_name left_value) right#get_desc (get_type_name right_value) in raise (Template_error (template_error_message self#get_pos detail)) end (* Equality operator. *) class equals_equals_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit comparison_op pos left right method to_bool cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in match left_value with Tnull -> is_null right_value | _ -> ((self#do_compare left_value right_value) = 0) method dump = sprintf "(%s == %s)" left#dump right#dump end ;; (* Inequality operator. *) class not_equals_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit comparison_op pos left right method to_bool cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in match left_value with Tnull -> is_null right_value | _ -> ((self#do_compare left_value right_value) <> 0) method dump = sprintf "(%s <> %s)" left#dump right#dump end ;; (* Less-than operator. *) class less_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit comparison_op pos left right method to_bool cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in (self#do_compare left_value right_value) < 0 method dump = sprintf "(%s < %s)" left#dump right#dump end ;; (* Greater-than operator. *) class greater_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit comparison_op pos left right method to_bool cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in (self#do_compare left_value right_value) > 0 method dump = sprintf "(%s > %s)" left#dump right#dump end ;; (* Less-than-or-equal-to operator. *) class less_or_equal_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit comparison_op pos left right method to_bool cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in (self#do_compare left_value right_value) <= 0 method dump = sprintf "(%s < %s)" left#dump right#dump end ;; (* Greater-than-or-equal-to operator. *) class greater_or_equal_op ~(pos : source_pos) ~(left : expression) ~(right : expression) = object (self) inherit comparison_op pos left right method to_bool cur_scope = let left_value = (left#get_value cur_scope) in let right_value = (right#get_value cur_scope) in (self#do_compare left_value right_value) >= 0 method dump = sprintf "(%s >= %s)" left#dump right#dump end ;; camltemplate-1.0.2/src/ctCache.ml0100644000076400010400000001222610251606440022564 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctCache.ml,v 1.12 2005-06-08 15:22:08 ben Exp $ *) (******************************************************************************* Template loading and caching. *) open CtTemplateTypes ;; open CtTemplate ;; type source_check_result = TemplateUnchanged | TemplateChanged | TemplateDeleted ;; class type source_loader = object method check : template_name:string -> load_time:float -> source_check_result method load : template_name:string -> string end ;; let as_source_loader loader = (loader :> source_loader) ;; class file_loader ~(template_dir : string) = object val template_dir = template_dir method check ~template_name ~load_time = let filename = Filename.concat template_dir template_name in try let file_stats = Unix.stat filename in if file_stats.Unix.st_mtime > load_time then TemplateChanged else TemplateUnchanged with Unix.Unix_error (error_code, fun_name, arg) as e -> if error_code = Unix.ENOENT then TemplateDeleted else raise e method load ~template_name = let filename = Filename.concat template_dir template_name in CtUtil.read_file_as_string filename end ;; let make_file_loader ~(template_dir : string) = as_source_loader (new file_loader template_dir) ;; (* Represents an entry in the template cache. *) type entry = { (* The parsed template. *) mutable tmpl : template; (* The time when the template was loaded. *) mutable load_time : float; } ;; (* The type of template caches. *) type t = { (* Keys are template names. *) entries : (string, entry) Hashtbl.t; (* The template source loader. *) loader : source_loader; (* The interval at which the cache should be checked. *) check_interval : float; (* The last time the cache was checked. *) mutable last_check_time : float } ;; let create ?(loader = as_source_loader (new file_loader Filename.current_dir_name)) ?(check_interval = 300.0) () = { entries = Hashtbl.create 16; loader = loader; check_interval = check_interval; last_check_time = 0.0 } ;; (* Refreshes the cache if necessary. *) let rec check_cache cache = let current_time = Unix.time () in Hashtbl.iter (fun template_name entry -> match cache.loader#check template_name entry.load_time with TemplateUnchanged -> () | TemplateChanged -> entry.tmpl <- (make_template template_name (cache.loader#load template_name) (get_template ~cache)); entry.load_time <- current_time | TemplateDeleted -> Hashtbl.remove cache.entries template_name) cache.entries; cache.last_check_time <- current_time (* Loads a template from the cache.*) and get_template ~cache ~template_name = CtUtil.call_in_mutex ~f:(function () -> (* Is it time to check the cache? *) let current_time = Unix.time () in if cache.check_interval >= 0.0 && current_time -. cache.last_check_time >= cache.check_interval then check_cache cache; (* Do we have the template? *) try let entry = Hashtbl.find cache.entries template_name in entry.tmpl with Not_found -> (* No; load it. *) let new_tmpl = make_template template_name (cache.loader#load template_name) (get_template ~cache) in let new_entry = { tmpl = new_tmpl; load_time = current_time } in Hashtbl.add cache.entries template_name new_entry; new_tmpl) ~mutex:!CtUtil.static_mutex ;; camltemplate-1.0.2/src/ctCache.mli0100644000076400010400000000410210251606441022730 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctCache.mli,v 1.5 2005-06-08 15:22:09 ben Exp $ *) (* See CamlTemplate.mli for a description of this module. *) open CtTemplateTypes ;; type t ;; type source_check_result = TemplateUnchanged | TemplateChanged | TemplateDeleted ;; class type source_loader = object method check : template_name:string -> load_time:float -> source_check_result method load : template_name:string -> string end ;; val as_source_loader : #source_loader -> source_loader ;; val make_file_loader : template_dir:string -> source_loader ;; val create : ?loader:source_loader -> ?check_interval:float -> unit -> t ;; val get_template : cache:t -> template_name:string -> template ;; camltemplate-1.0.2/src/ctContext.ml0100644000076400010400000000442610251606441023211 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctContext.ml,v 1.8 2005-06-08 15:22:09 ben Exp $ *) open CtTemplateTypes ;; open CtScope ;; (* The implementation of the context type in CtTemplateTypes. *) class context_impl ~(template_name : string) ~(cur_scope : scope) ~(opened_modules : string list) ~(buf : Buffer.t) ~(get_template_fun : template_name:string -> template) = object val template_name = template_name val cur_scope = cur_scope val mutable opened_modules = opened_modules val buf = buf val get_template_fun = get_template_fun method get_template_name = template_name method get_cur_scope = cur_scope method get_opened_modules = opened_modules method add_opened_module module_name = opened_modules <- List.rev (module_name :: opened_modules) method get_buf = buf method get_template name = get_template_fun name method make_macro_context = {< cur_scope = cur_scope#make_macro_scope >} end ;; camltemplate-1.0.2/src/ctExceptions.ml0100644000076400010400000000536710251606441023713 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctExceptions.ml,v 1.8 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtSourcePos ;; (* Exceptions and related functions. *) type lexer_error = Illegal_character of char | Unterminated_string | Unterminated_comment | Unterminated_expansion | Mismatched_parens | Keyword_as_ident of string ;; exception Lexer_error of lexer_error * source_pos ;; let lexer_error_message error_type = match error_type with Illegal_character ch -> sprintf "Illegal character '%c'" ch | Unterminated_string -> "Unterminated string" | Unterminated_comment -> "Unterminated comment" | Unterminated_expansion -> "Unterminated expansion" | Mismatched_parens -> "Mismatched parentheses" | Keyword_as_ident keyword -> sprintf "Keyword \"%s\" used as identifier" keyword ;; exception Syntax_error of string ;; let syntax_error_message template_name pos detail = if detail = "" then sprintf "In template %s:\nSyntax error near line %d, character %d" template_name pos#get_line_no pos#get_char_no else sprintf "In template %s:\nSyntax error near line %d, character %d:\n%s" template_name pos#get_line_no pos#get_char_no detail exception Template_error of string ;; let template_error_message pos detail = sprintf "At line %d, character %d:\n%s" pos#get_line_no pos#get_char_no detail ;; camltemplate-1.0.2/src/ctExpression.ml0100644000076400010400000001252210251606441023720 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctExpression.ml,v 1.14 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtSourcePos ;; open CtTemplateModel ;; open CtScope ;; open CtExceptions ;; (* Provides base classes for expressions and type conversion functions for scalars. *) exception TypeError of (string option) ;; let get_type_name value = match value with Tnull -> "null" | Tstr _ -> "string" | Tint _ -> "integer" | Tfloat _ -> "float" | Tbool _ -> "boolean" | Tlist _ -> "list" | Thash _ -> "hash" | Tfun _ -> "function" ;; let is_null value = match value with Tnull -> true | Tstr s -> s = "" | Tint i -> i = 0 | Tfloat f -> f = 0.0 | Tbool b -> not b | _ -> false ;; let string_for_value value = match value with Tstr s -> s | Tint i -> string_of_int i | Tfloat f -> string_of_float f | Tbool b -> if b then "true" else "" | Tnull -> "" | _ -> raise (TypeError None) ;; let int_for_value value = match value with Tint i -> i | Tstr s -> ( try int_of_string s with Failure "int_of_string" -> raise (TypeError (Some s)) ) | Tbool b -> if b then 1 else 0 | Tfloat f -> int_of_float f | Tnull -> 0 | _ -> raise (TypeError None) ;; let float_for_value value = match value with Tint i -> float_of_int i | Tstr s -> ( try float_of_string s with Failure "float_of_string" -> raise (TypeError (Some s)) ) | Tbool b -> if b then 1.0 else 0.0 | Tfloat f -> f | Tnull -> 0.0 | _ -> raise (TypeError None) ;; let bool_for_value value = match value with Tbool b -> b | Tstr s -> s <> "" | Tint i -> i <> 0 | Tfloat f -> f <> 0.0 | Tnull -> false | Tlist l -> l <> [] | _ -> true ;; (* Virtual base class for AST nodes that have a value. *) class virtual expression ~(pos : source_pos) = object (self) val pos = pos method get_pos = pos method virtual get_value : scope -> tvalue method virtual dump : string method get_desc = "expression" method value_to_string value = try string_for_value value with TypeError repr -> raise (self#conversion_error value repr "string") method to_string (cur_scope : scope) = let value = self#get_value cur_scope in self#value_to_string value method value_to_int value = try int_for_value value with TypeError repr -> raise (self#conversion_error value repr "integer") method to_int (cur_scope : scope) = let value = self#get_value cur_scope in self#value_to_int value method value_to_float value = try float_for_value value with TypeError repr -> raise (self#conversion_error value repr "float") method to_float (cur_scope : scope) = let value = self#get_value cur_scope in self#value_to_float value method value_to_bool value = try bool_for_value value with TypeError repr -> raise (self#conversion_error value repr "boolean") method to_bool (cur_scope : scope) = let value = self#get_value cur_scope in self#value_to_bool value method private conversion_error value repr dest_type = let detail = match repr with None -> sprintf "Can't convert %s, of type %s, to type %s" self#get_desc (get_type_name value) dest_type | Some str -> sprintf "Can't convert %s, of type %s (value %S), to type %s" self#get_desc (get_type_name value) str dest_type in let msg = template_error_message self#get_pos detail in Template_error msg end ;; (* Upcasting function for expressions. *) let as_expression expr = (expr :> expression) ;; (* Mixin class for all operators that return a boolean value. Derived classes must override to_bool.*) class virtual boolean_op = object (self) method get_value (cur_scope : scope) = Tbool (self#to_bool cur_scope) end ;; camltemplate-1.0.2/src/ctFunctionCall.ml0100644000076400010400000000600710251606441024143 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctFunctionCall.ml,v 1.10 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtSourcePos ;; open CtTemplateModel ;; open CtExpression ;; open CtExceptions ;; (* Implements calls to functions in the template model. *) class function_call_op ~(pos : source_pos) ~(left : expression) ~(params : expression list) = object (self) inherit expression pos val left = left val params = params method get_value model = let left_value = (left#get_value model) in match left_value with Tfun f -> ( let get_param_value model expr = expr#get_value model in let param_values = List.map (get_param_value model) params in try f param_values with Tfun_error text -> let detail = sprintf "Error in function %s: %s" left#get_desc text in let msg = template_error_message pos detail in raise (Template_error msg) ) | Tnull -> let detail = sprintf "Function %s is null" left#get_desc in let msg = template_error_message self#get_pos detail in raise (Template_error msg) | _ -> let detail = sprintf "%s is of type %s (function expected)" left#get_desc (get_type_name left_value) in let msg = template_error_message self#get_pos detail in raise (Template_error msg) method dump = sprintf "(%s(...))" left#dump end ;; camltemplate-1.0.2/src/ctHashLookup.ml0100644000076400010400000000650710251606441023644 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctHashLookup.ml,v 1.11 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtSourcePos ;; open CtTemplateModel ;; open CtScope ;; open CtExpression ;; open CtIdent ;; open CtExceptions ;; (* Base class for hash lookup operators defined below. *) class virtual hash_lookup_op ~(pos : source_pos) ~(left : expression) = object (self) inherit expression pos val left = left method virtual do_lookup : cur_scope:scope -> left_hash:thash -> tvalue method get_value cur_scope = let left_value = (left#get_value cur_scope) in match left_value with Thash left_hash -> self#do_lookup ~cur_scope ~left_hash | Tnull -> raise (Template_error (template_error_message self#get_pos "Value on left side of hash lookup is null")) | _ -> let detail = sprintf "Value on left side of hash lookup is of type %s (hash expected)" (get_type_name left_value) in let msg = template_error_message self#get_pos detail in raise (Template_error msg) end ;; (* Represents the dot operator. *) class dot_op ~(pos : source_pos) ~(left : expression) ~(key : ident) = object (self) inherit hash_lookup_op pos left val key = key method do_lookup ~cur_scope ~left_hash = try Hashtbl.find left_hash key#get_name with Not_found -> Tnull method get_desc = key#get_desc method dump = sprintf "(%s.%s)" left#dump key#dump end ;; (* Represents the bracket operator. *) class bracket_op ~(pos : source_pos) ~(left : expression) ~(key : expression) = object (self) inherit hash_lookup_op pos left val key = key method do_lookup ~cur_scope ~left_hash = let key_value = key#to_string cur_scope in try Hashtbl.find left_hash key_value with Not_found -> Tnull method get_desc = key#get_desc method dump = sprintf "(%s[%s])" left#dump key#dump end ;; camltemplate-1.0.2/src/ctIdent.ml0100644000076400010400000000353610251606441022631 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctIdent.ml,v 1.10 2005-06-08 15:22:09 ben Exp $ *) open CtSourcePos ;; open CtTemplateModel ;; open CtScope ;; open Printf ;; open CtExpression ;; (* Represents identifiers. *) class ident ~(pos : source_pos) ~(name : string) = object (self) inherit expression pos val name = name method get_value cur_scope = cur_scope#lookup name method get_name = name method get_desc = sprintf "'%s'" name method dump = name end ;; camltemplate-1.0.2/src/ctLexer.mll0100644000076400010400000010453210246305765023030 0ustar gdsАдминистраторы{ (* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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 In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctLexer.mll,v 1.22 2005-05-29 09:31:33 ben Exp $ *) open CtParser ;; open CtSourcePos ;; open Printf ;; open CtExceptions ;; (* An ocamllex lexer for template source code. *) (* Our current position in the input. *) let cur_pos = new source_pos ;; (* Buffering for string literals. *) let string_buf = Buffer.create 256 (* Buffering for template text. *) let text_buf = Buffer.create 256 (* The position where the current string literal started. *) let string_start_pos = new source_pos ;; (* The current depth of nested comments. *) let comment_nesting_depth = ref 0 ;; (* The start position of the outermost comment. *) let comment_start_pos = new source_pos ;; (* The lexer works in different 'modes', depending on whether it's in template text, a statement, an expansion, etc. *) type lexer_mode = Text_mode | Expansion_mode | Dollar_mode | Statement_mode | Eof_mode ;; let cur_mode = ref Text_mode ;; (* The position where we entered the current mode. *) let mode_start_pos = new source_pos ;; (* We have to count parentheses to know when to leave statement mode. *) let paren_count = ref 0 ;; (* Functions for changing modes. *) let to_text_mode () = (* eprintf "to_text_mode "; *) cur_mode := Text_mode; mode_start_pos#set_from cur_pos; Buffer.reset text_buf ;; let to_dollar_mode () = (* eprintf "to_dollar_mode "; *) cur_mode := Dollar_mode; mode_start_pos#set_from cur_pos ;; let to_expansion_mode () = (* eprintf "to_expansion_mode "; *) cur_mode := Expansion_mode; mode_start_pos#set_from cur_pos; paren_count := 0 ;; let to_statement_mode () = (* eprintf "to_statement_mode "; *) cur_mode := Statement_mode; mode_start_pos#set_from cur_pos; paren_count := 0 ;; let to_eof_mode () = (* eprintf "to_eof_mode "; *) cur_mode := Eof_mode; mode_start_pos#set_from cur_pos ;; (* Called by the parser wrapper before parsing each template. *) let reset_lexer () = cur_pos#reset; comment_nesting_depth := 0; Buffer.reset string_buf; to_text_mode () ;; (* Called by the parser wrapper after parsing each template; may reduce memory usage. *) let clean_up_lexer () = Buffer.reset string_buf ;; (* Keywords. *) type keyword_types = TrueKwd | FalseKwd | NullKwd | IfKwd | ElseKwd | ElseIfKwd | ForEachKwd | InKwd | SetKwd | VarKwd | EndKwd | IncludeKwd | MacroKwd | OpenKwd ;; let token_for_keyword kwd pos = match kwd with TrueKwd -> TRUE pos | FalseKwd -> FALSE pos | NullKwd -> NULL pos | IfKwd -> IF pos | ElseKwd -> ELSE pos | ElseIfKwd -> ELSEIF pos | ForEachKwd -> FOREACH pos | InKwd -> IN pos | SetKwd -> SET pos | VarKwd -> VAR pos | EndKwd -> END pos | IncludeKwd -> INCLUDE pos | MacroKwd -> MACRO pos | OpenKwd -> OPEN pos ;; let keyword_table = Hashtbl.create 10 ;; let _ = List.iter (function (kwd_name, kwd) -> Hashtbl.add keyword_table kwd_name kwd) [ "true", TrueKwd; "false", FalseKwd; "null", NullKwd; "if", IfKwd; "else", ElseKwd; "else#", ElseKwd; "elseif", ElseIfKwd; "foreach", ForEachKwd; "in", InKwd; "set", SetKwd; "var", VarKwd; "end", EndKwd; "end#", EndKwd; "include", IncludeKwd; "macro", MacroKwd; "open", OpenKwd ] ;; } let blank = [ ' ' '\t' ] let ident_first_char = [ 'A'-'Z' 'a'-'z' ] let ident_char = [ 'A'-'Z' 'a'-'z' '_' '\'' '0'-'9' ] let int_literal = [ '0'-'9' ] [ '0'-'9' '_' ]* let float_literal = [ '0'-'9' ] [ '0'-'9' '_' ]* ('.' [ '0'-'9' '_' ]* )? ([ 'e' 'E' ] [ '+' '-' ]? [ '0'-'9' ]+)? rule main = parse | '\\' { (* eprintf "backslash[%d] " cur_pos#get_char_no; *) match !cur_mode with Text_mode -> cur_pos#incr_char_no; maybe_escape lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), cur_pos)) } | '$' ([^ '{' '$' ] | eof) { (* eprintf "dollar(non-expansion)[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in let str = Lexing.lexeme lexbuf in let len = String.length str in if len = 2 && str.[1] = '\n' then cur_pos#incr_line_no else cur_pos#advance_char_no len; match !cur_mode with Text_mode -> if str.[len - 1] = '\\' then ( Buffer.add_char text_buf '$'; maybe_escape lexbuf ) else ( Buffer.add_string text_buf str; main lexbuf ) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '$' + { (* eprintf "dollar_start[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in let str = Lexing.lexeme lexbuf in let len = String.length str in match !cur_mode with Text_mode -> let text_start_pos = mode_start_pos#clone in Buffer.add_string text_buf (String.sub str 0 (len - 1)); cur_pos#advance_char_no (len - 1); to_dollar_mode (); cur_pos#incr_char_no; let dollar_start_pos = mode_start_pos#clone in if (Buffer.length text_buf) > 0 then TEXT (text_start_pos, dollar_start_pos, Buffer.contents text_buf) else main lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), cur_pos)) } | '{' { (* eprintf "expansion_start[%d] " cur_pos#get_char_no; *) match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); cur_pos#incr_char_no; main lexbuf | Dollar_mode -> (* Use the dollar's position as the start position of the EXPANSION. *) let dollar_start_pos = mode_start_pos#clone in to_expansion_mode (); mode_start_pos#set_from dollar_start_pos; cur_pos#incr_char_no; EXPANSION (dollar_start_pos) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), cur_pos)) } | '}' { (* eprintf "expansion_end[%d] " cur_pos#get_char_no; *) match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); cur_pos#incr_char_no; main lexbuf | Expansion_mode -> cur_pos#incr_char_no; to_text_mode (); main lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), cur_pos)) } | blank* "#*" { (* eprintf "comment_in_text[%d] " cur_pos#get_char_no; *) let len = String.length (Lexing.lexeme lexbuf) in cur_pos#advance_char_no (len - 2); match !cur_mode with Text_mode -> comment_nesting_depth := 1; comment_start_pos#set_from cur_pos#clone; cur_pos#advance_char_no 2; comment lexbuf; main lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), cur_pos)) } | blank* '#' { (* eprintf "instr_start[%d] " cur_pos#get_char_no; *) let str = Lexing.lexeme lexbuf in let len = String.length str in let str_start_pos = cur_pos#clone in cur_pos#advance_char_no (len - 1); match !cur_mode with Text_mode -> (* Eat preceding spaces only if they start at the beginning of the line. *) let text_end_pos = if str_start_pos#get_char_no = 0 && len > 1 then ( str_start_pos ) else ( Buffer.add_string text_buf (String.sub str 0 (len - 1)); cur_pos#clone ) in let text_start_pos = mode_start_pos#clone in to_statement_mode (); cur_pos#incr_char_no; if (Buffer.length text_buf) > 0 then TEXT (text_start_pos, text_end_pos, Buffer.contents text_buf) else if str_start_pos#is_origin then (* Make sure the parser's input begins with a token, so we can always handle a syntax error when '#' is the first character in the file. *) START (str_start_pos) else main lexbuf | Expansion_mode -> raise (Lexer_error (Unterminated_expansion, mode_start_pos)) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), cur_pos)) } | '(' { (* eprintf "lparen[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> paren_count := !paren_count + 1; LPAREN pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | ')' '\n'? { (* eprintf "rparen[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in let str = Lexing.lexeme lexbuf in let len = String.length str in if str.[len - 1] = '\n' then ( (* eprintf "to_next_line "; *) cur_pos#incr_line_no ) else ( (* eprintf "to_next_char "; *) cur_pos#advance_char_no len ); match !cur_mode with Text_mode -> (* eprintf "already_in_text "; *) Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> paren_count := !paren_count - 1; (* eprintf "paren_count(%d) " !paren_count; *) if !paren_count < 0 then raise (Lexer_error (Mismatched_parens, pos)) else if !cur_mode = Statement_mode && !paren_count = 0 then to_text_mode (); RPAREN pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '\n' { (* eprintf "newline[line %d] " (cur_pos#get_line_no + 1); *) let pos = cur_pos#clone in cur_pos#incr_line_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf '\n'; main lexbuf | Expansion_mode | Statement_mode -> main lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | blank { (* eprintf "blank[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> main lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | "\"" { (* eprintf "string[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> Buffer.reset string_buf; string_start_pos#set_from pos; string_token lexbuf; STRING (string_start_pos#clone, (Buffer.contents string_buf)) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | int_literal { (* eprintf "int_digits[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> INT (pos, (int_of_string str)) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | float_literal { (* eprintf "float_digits[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> FLOAT (pos, (float_of_string str)) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | (ident_first_char ident_char* '#'? as word) '\n'? { (* eprintf "word[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in let str_len = String.length str in if str.[str_len - 1] = '\n' then cur_pos#incr_line_no else cur_pos#advance_char_no str_len; let word_len = String.length word in let word_ends_with_hash = word.[word_len - 1] = '#' in let reject_hash_at_end () = if word_ends_with_hash then let hash_pos = pos#clone in hash_pos#advance_char_no (word_len - 1); raise (Lexer_error (Illegal_character '#', hash_pos)) in match !cur_mode with Text_mode -> (* We might be here because we got something like foo#else, where 'foo#' matched as a word. If so, add 'foo', switch to statement mode, and return the text. *) if word_ends_with_hash then ( Buffer.add_string text_buf (String.sub word 0 (word_len - 1)); let text_start_pos = mode_start_pos#clone in to_statement_mode (); let statement_start_pos = mode_start_pos#clone in TEXT (text_start_pos, statement_start_pos, Buffer.contents text_buf) ) else (* Otherwise, add the whole string. *) ( Buffer.add_string text_buf str; main lexbuf ) | Expansion_mode -> reject_hash_at_end (); ( try let kwd = Hashtbl.find keyword_table word in let tok = token_for_keyword kwd pos in ( (* eprintf "keyword \"%s\" " word; *) match kwd with TrueKwd -> TRUE pos | FalseKwd -> FALSE pos | _ -> raise (Lexer_error (Keyword_as_ident word, pos)) ) with Not_found -> (* eprintf "ident \"%s\" " word; *) IDENT (pos, word) ) | Statement_mode -> ( try let kwd = Hashtbl.find keyword_table word in let tok = token_for_keyword kwd pos in (* eprintf "keyword \"%s\" " word; *) if kwd = ElseKwd || kwd = EndKwd then to_text_mode (); tok with Not_found -> (* eprintf "ident \"%s\" " word; *) reject_hash_at_end (); IDENT (pos, word) ) | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '[' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> LBRACKET pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | ']' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> RBRACKET pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '+' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> PLUS pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '-' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> MINUS pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '*' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> TIMES pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '/' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> DIV pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '%' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> MOD pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '=' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> EQUALS pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | "==" { (* eprintf "%s " (Lexing.lexeme lexbuf); *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> EQUALS_EQUALS pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | "!=" { (* eprintf "%s " (Lexing.lexeme lexbuf); *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> NOT_EQUALS pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '<' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> LESS pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '>' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> GREATER pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | "<=" { (* eprintf "%s " (Lexing.lexeme lexbuf); *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> LESS_OR_EQUAL pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | ">=" { (* eprintf "%s " (Lexing.lexeme lexbuf); *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> GREATER_OR_EQUAL pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | "&&" { (* eprintf "%s " (Lexing.lexeme lexbuf); *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> AND pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | "||" { (* eprintf "%s " (Lexing.lexeme lexbuf); *) let pos = cur_pos#clone and str = Lexing.lexeme lexbuf in cur_pos#advance_char_no (String.length str); match !cur_mode with Text_mode -> Buffer.add_string text_buf str; main lexbuf | Expansion_mode | Statement_mode -> OR pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '!' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> NOT pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | '.' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> DOT pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | ',' { (* eprintf "%c " (Lexing.lexeme_char lexbuf 0); *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | Expansion_mode | Statement_mode -> COMMA pos | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | _ { (* eprintf "other[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in cur_pos#incr_char_no; match !cur_mode with Text_mode -> Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); main lexbuf | _ -> raise (Lexer_error (Illegal_character (Lexing.lexeme_char lexbuf 0), pos)) } | eof { (* eprintf "eof "; *) match !cur_mode with Text_mode -> let text_start_pos = mode_start_pos#clone in to_eof_mode (); cur_pos#incr_char_no; let eof_start_pos = mode_start_pos#clone in if (Buffer.length text_buf) > 0 then TEXT (text_start_pos, eof_start_pos, Buffer.contents text_buf) else main lexbuf | Eof_mode | Statement_mode -> (* print_newline (); *) EOF | Dollar_mode -> raise (Lexer_error (Unterminated_expansion, mode_start_pos)) | Expansion_mode -> raise (Lexer_error (Unterminated_expansion, mode_start_pos)) } and string_token = parse '\"' { (* eprintf "string_end[%d] " cur_pos#get_char_no; *) cur_pos#incr_char_no; () } | '\\' ['\\' '\"' 'n' 't' 'r'] { cur_pos#advance_char_no 2; let char_to_add = match Lexing.lexeme_char lexbuf 1 with 'n' -> '\n' | 't' -> '\t' | 'r' -> '\r' | c -> c in Buffer.add_char string_buf char_to_add; string_token lexbuf } | eof { raise (Lexer_error (Unterminated_string, string_start_pos)) } | _ { Buffer.add_char string_buf (Lexing.lexeme_char lexbuf 0); cur_pos#incr_char_no; string_token lexbuf } and comment = parse '\"' { (* eprintf "string_in_comment[%d] " cur_pos#get_char_no; *) Buffer.reset string_buf; string_start_pos#set_from cur_pos; cur_pos#incr_char_no; string_token lexbuf; comment lexbuf } | "#*" { (* eprintf "nested_comment[%d] " cur_pos#get_char_no; *) comment_nesting_depth := !comment_nesting_depth + 1; cur_pos#advance_char_no 2; comment lexbuf } | "*#" '\n'? { (* eprintf "comment_end[%d] " cur_pos#get_char_no; *) let str = Lexing.lexeme lexbuf in let len = String.length str in if str.[len - 1] = '\n' then cur_pos#incr_line_no else cur_pos#advance_char_no len; comment_nesting_depth := !comment_nesting_depth - 1; if !comment_nesting_depth = 0 then () else comment lexbuf } | '\n' { cur_pos#incr_line_no; comment lexbuf } | _ { cur_pos#incr_char_no; comment lexbuf} | eof { raise (Lexer_error (Unterminated_comment, comment_start_pos)) } and maybe_escape = parse '\\' * ("${" | '#' | '\n') { (* eprintf "escape[%d] " cur_pos#get_char_no; *) let pos = cur_pos#clone in let str = Lexing.lexeme lexbuf in let len = String.length str in if str.[len - 1] = '\n' then cur_pos#incr_line_no else ( cur_pos#advance_char_no len; Buffer.add_string text_buf str ); main lexbuf } | _ { (* eprintf "non_escape[%d] " cur_pos#get_char_no; *) Buffer.add_char text_buf '\\'; Buffer.add_char text_buf (Lexing.lexeme_char lexbuf 0); cur_pos#incr_char_no; main lexbuf } camltemplate-1.0.2/src/ctLiteral.ml0100644000076400010400000000373510251606441023163 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctLiteral.ml,v 1.11 2005-06-08 15:22:09 ben Exp $ *) open CtSourcePos ;; open CtTemplateModel ;; open Printf ;; open CtExpression ;; (* Represents literals. *) class literal ~(pos : source_pos) ~(value : tvalue) = object (self) inherit expression pos val value = value method get_value cur_scope = value method dump = match value with Tstr s -> sprintf "%S" s | Tint i -> string_of_int i | Tbool b -> string_of_bool b | Tfloat f -> string_of_float f | _ -> assert false method get_desc = "literal" end ;; camltemplate-1.0.2/src/ctMacro.ml0100644000076400010400000000726010251606441022625 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctMacro.ml,v 1.13 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtSourcePos ;; open CtTemplateModel ;; open CtScope ;; open CtTemplateTypes ;; open CtExpression ;; open CtIdent ;; open CtStatement ;; open CtExceptions ;; (* Classes and functions relating to template macros. *) (* Helper functions for the macro_impl class. *) let add_arg_to_scope (cur_scope : scope) (arg_name : ident) (arg : tvalue) = cur_scope#add arg_name#get_name arg ;; let remove_arg_from_scope (cur_scope : scope) (arg_name : ident) = cur_scope#remove arg_name#get_name ;; (* Pads a list of macro arguments with nulls to make it the right length. *) let pad_args args len = let rec pad_args_aux padded = if List.length padded = len then padded else pad_args_aux (Tnull :: padded) in List.rev (pad_args_aux (List.rev args)) (* A macro definition. Macros are stored in templates, but they aren't statements. *) class macro_impl ~(template_name : string) ~(pos : source_pos) ~(macro_name : string) ~(arg_names : ident list) ~(statements : statement list) = object val template_name = template_name val pos = pos val macro_name = macro_name val arg_names = arg_names val statements = statements method call ~args ~ctx = let arg_count = List.length args in let arg_name_count = List.length arg_names in if arg_count > arg_name_count then let msg = sprintf "Too many arguments for macro %s, defined in template %s at line %d, character %d" macro_name template_name pos#get_line_no pos#get_char_no in raise (Template_error msg) else let padded_args = if arg_count < arg_name_count then pad_args args arg_name_count else args in List.iter2 (add_arg_to_scope ctx#get_cur_scope) arg_names padded_args; ( try interpret_statements ctx statements; with Template_error msg -> let msg_with_macro_desc = sprintf "In template %s:\nIn macro %s:\n%s" template_name macro_name msg in raise (Template_error msg_with_macro_desc) ); List.iter (remove_arg_from_scope ctx#get_cur_scope) arg_names method get_macro_name = macro_name method dump = dump_statements statements end ;; camltemplate-1.0.2/src/ctParser.mly0100644000076400010400000002506610251606441023215 0ustar gdsАдминистраторы%{ (* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctParser.mly,v 1.18 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtStatement ;; open CtExpression ;; open CtIdent ;; open CtLiteral ;; open CtUnop ;; open CtBinop ;; open CtFunctionCall ;; open CtHashLookup ;; open CtTemplateTypes ;; open CtMacro ;; open CtTemplateModel ;; open CtParserAux ;; (* An ocamlyacc parser for template source code. *) (* Convenience function that raises an exception for the position in a TEXT token. *) let parser_error_for_text (_, end_pos, _) = raise (ParserError end_pos) ;; (* Convenience function that gets the string from a TEXT token. *) let string_for_text (_, _, str) = str ;; %} %token START %token TEXT %token EXPANSION %token IF %token ELSE %token ELSEIF %token FOREACH %token IN %token SET %token VAR %token END %token INCLUDE %token MACRO %token OPEN %token EOF %token STRING %token INT %token FLOAT %token TRUE %token FALSE %token NULL %token IDENT %token LPAREN %token RPAREN %token LBRACKET %token RBRACKET %token PLUS %token MINUS %token TIMES %token DIV %token MOD %token EQUALS_EQUALS %token NOT_EQUALS %token LESS %token GREATER %token LESS_OR_EQUAL %token GREATER_OR_EQUAL %token AND %token OR %token NOT %token DOT %token COMMA %token EQUALS %left EQUALS %left COMMA %left OR %left AND %left EQUALS_EQUALS NOT_EQUALS %left LESS GREATER LESS_OR_EQUAL GREATER_OR_EQUAL %left PLUS MINUS %left TIMES DIV MOD %nonassoc NOT UMINUS %left DOT %start input %type input %% input: EOF { [] } | START stmts EOF { $2 } | START error { raise (ParserError $1) } | stmts EOF { $1 } ; stmts: stmt { [$1] } | stmt stmts { $1 :: $2 } ; stmt: EXPANSION expr { as_statement (new expansion_statement ~expr:$2) } | EXPANSION error { raise (ParserError $1) } | IF if_chain else_part END { as_statement (new if_statement ~cond_branches:$2 ~else_statements:$3) } | IF error { raise (ParserError $1) } | FOREACH LPAREN ident IN expr RPAREN stmts END { as_statement (new for_each_statement ~index:$3 ~list_expr:$5 ~statements:$7) } | FOREACH error { raise (ParserError $1) } | SET LPAREN ident EQUALS expr RPAREN { as_statement (new set_statement ~left:$3 ~right:$5) } | SET error { raise (ParserError $1) } | VAR LPAREN ident EQUALS expr RPAREN { as_statement (new var_statement ~left:$3 ~right:(Some $5)) } | VAR LPAREN ident RPAREN { as_statement (new var_statement ~left:$3 ~right:None) } | VAR error { raise (ParserError $1) } | TEXT { as_statement (new text_statement ~text:(string_for_text $1)) } | TEXT error { parser_error_for_text $1 } | INCLUDE LPAREN expr RPAREN { as_statement (new include_statement ~pos:$1 ~template_name:$3) } | INCLUDE error { raise (ParserError $1) } | MACRO ident macro_arg_names stmts END { add_macro_for_current_template (new macro_impl ~template_name:(!current_template_name) ~pos:$1 ~macro_name:$2#get_name ~arg_names:$3 ~statements:$4); as_statement (new null_statement) } | MACRO error { raise (ParserError $1) } | OPEN LPAREN expr RPAREN { as_statement (new open_statement ~pos:$1 ~template_name:$3) } | OPEN error { raise (ParserError $1) } | ident function_args { as_statement (new macro_call_statement ~pos:($1#get_pos) ~macro_name:$1#get_name ~args:$2) } | IDENT error { raise (ParserError (fst $1)) } ; if_chain: LPAREN expr RPAREN stmts { [($2, $4)] } | LPAREN expr RPAREN stmts ELSEIF if_chain { ($2, $4) :: $6 } | LPAREN expr RPAREN stmts ELSEIF error { raise (ParserError $5) } ; else_part: /* empty */ { [] } | ELSE stmts { $2 } | ELSE error { raise (ParserError $1) } ; macro_arg_names: LPAREN RPAREN { [] } | LPAREN ident_list RPAREN { $2 } ; ident_list: ident { [$1] } | ident COMMA ident_list { $1 :: $3 } ; | ident COMMA error { raise (ParserError $2) } ; ident: IDENT { new ident ~pos:(fst $1) ~name:(snd $1) } | IDENT error { raise (ParserError (fst $1)) } ; expr: ident { as_expression $1 } | INT { as_expression (new literal ~pos:(fst $1) ~value:(Tint (snd $1))) } | STRING { as_expression (new literal ~pos:(fst $1) ~value:(Tstr (snd $1))) } | FLOAT { as_expression (new literal ~pos:(fst $1) ~value:(Tfloat (snd $1))) } | TRUE { as_expression (new literal ~pos:$1 ~value:(Tbool true)) } | FALSE { as_expression (new literal ~pos:$1 ~value:(Tbool false)) } | NULL { as_expression (new literal ~pos:$1 ~value:(Tnull)) } | function_call { $1 } | dot_lookup { $1 } | bracket_lookup { $1 } | NOT expr { as_expression (new not_op ~pos:$1 ~arg:$2) } | MINUS expr %prec UMINUS { as_expression (new negative_op ~pos:$1 ~arg:$2) } | expr PLUS expr { as_expression (new plus_op ~pos:$2 ~left:$1 ~right:$3) } | expr MINUS expr { as_expression (new minus_op ~pos:$2 ~left:$1 ~right:$3) } | expr TIMES expr { as_expression (new times_op ~pos:$2 ~left:$1 ~right:$3) } | expr DIV expr { as_expression (new div_op ~pos:$2 ~left:$1 ~right:$3) } | expr MOD expr { as_expression (new mod_op ~pos:$2 ~left:$1 ~right:$3) } | expr EQUALS_EQUALS expr { as_expression (new equals_equals_op ~pos:$2 ~left:$1 ~right:$3) } | expr NOT_EQUALS expr { as_expression (new not_equals_op ~pos:$2 ~left:$1 ~right:$3) } | expr LESS expr { as_expression (new less_op ~pos:$2 ~left:$1 ~right:$3) } | expr GREATER expr { as_expression (new greater_op ~pos:$2 ~left:$1 ~right:$3) } | expr LESS_OR_EQUAL expr { as_expression (new less_or_equal_op ~pos:$2 ~left:$1 ~right:$3) } | expr GREATER_OR_EQUAL expr { as_expression (new greater_or_equal_op ~pos:$2 ~left:$1 ~right:$3) } | expr AND expr { as_expression (new and_op ~pos:$2 ~left:$1 ~right:$3) } | expr OR expr { as_expression (new or_op ~pos:$2 ~left:$1 ~right:$3) } | LPAREN expr RPAREN { $2 } | LPAREN error { raise (ParserError $1) } ; function_call: ident function_args { as_expression (new function_call_op ~pos:($1#get_pos) ~left:(as_expression $1) ~params:$2) } | dot_lookup function_args { as_expression (new function_call_op ~pos:($1#get_pos) ~left:$1 ~params:$2) } ; function_args: LPAREN RPAREN { [] } | LPAREN error { raise (ParserError $1) } | LPAREN expr_list RPAREN { $2 } ; expr_list: expr { [$1] } | expr COMMA expr_list { $1 :: $3 } ; | expr COMMA error { raise (ParserError $2) } ; dot_lookup: ident DOT ident { as_expression (new dot_op ~pos:($3#get_pos) ~left:(as_expression $1) ~key:$3) } | function_call DOT ident { as_expression (new dot_op ~pos:($3#get_pos) ~left:$1 ~key:$3) } ; bracket_lookup: ident LBRACKET expr RBRACKET { as_expression (new bracket_op ~pos:$2 ~left:(as_expression $1) ~key:$3) } | bracket_lookup LBRACKET expr RBRACKET { as_expression (new bracket_op ~pos:$2 ~left:$1 ~key:$3) } | function_call LBRACKET expr RBRACKET { as_expression (new bracket_op ~pos:$2 ~left:$1 ~key:$3) } ; camltemplate-1.0.2/src/ctParserAux.ml0100644000076400010400000000400410251606441023467 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctParserAux.ml,v 1.10 2005-06-08 15:22:09 ben Exp $ *) (* Parsing-related things that are used by other modules. Caml seems to need them to be in a separate module. *) open CtSourcePos ;; open CtTemplateTypes ;; let current_template_name = ref "" ;; let macros = ref ([] : macro list) ;; let add_macro_for_current_template mac = macros := mac :: !macros ;; let get_macros () = !macros ;; (* Must be called before parsing. *) let reset_parser () = macros := [] ;; (* Should be called after parsing, to minimise memory usage. *) let clean_up_parser () = Parsing.clear_parser (); exception ParserError of source_pos ;; camltemplate-1.0.2/src/ctScope.ml0100644000076400010400000000676010251606441022641 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctScope.ml,v 1.4 2005-06-08 15:22:09 ben Exp $ *) open CtTemplateModel ;; (* Constructor called by template when invoked *) class scope (model : thash) = object val model = model val template_scope : thash = Hashtbl.create 8 val macro_scope : thash option = None method get_model = model (* Returns the value of a variable in the innermost scope where it's set. *) method lookup key = try match macro_scope with Some hash -> Hashtbl.find hash key | None -> raise Not_found with Not_found -> try Hashtbl.find template_scope key with Not_found -> try Hashtbl.find model key with Not_found -> Tnull (* Sets the value of a variable in macro scope if it's already set there, otherwise in template scope. *) method set key value = try match macro_scope with Some hash -> ignore (Hashtbl.find hash key); Hashtbl.replace hash key value | None -> raise Not_found with Not_found -> Hashtbl.replace template_scope key value (* Adds a variable in the innermost available scope, shadowing any existing value. *) method add key value = try match macro_scope with Some hash -> Hashtbl.add hash key value | None -> raise Not_found with Not_found -> Hashtbl.add template_scope key value (* Removes a variable added with #add *) method remove key = try match macro_scope with Some hash -> ignore (Hashtbl.find hash key); Hashtbl.remove hash key | None -> raise Not_found with Not_found -> Hashtbl.remove template_scope key (* Defines a variable in the innermost available scope. *) method define key value = match macro_scope with Some hash -> Hashtbl.replace hash key value | None -> Hashtbl.replace template_scope key value (* Call this method on a template scope to make a macro scope. *) method make_macro_scope = {< macro_scope = Some (Hashtbl.create 8) >} end ;; camltemplate-1.0.2/src/ctSourcePos.ml0100644000076400010400000000454610251606441023512 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctSourcePos.ml,v 1.6 2005-06-08 15:22:09 ben Exp $ *) (* Represents a position (line number and character number) in template source code. Line numbers are 1-based; character numbers are 0-based. *) class source_pos = object (self) val mutable line_no = 1 val mutable char_no = 0 method get_line_no = line_no method set_line_no ln = line_no <- ln method get_char_no = char_no method set_char_no cn = char_no <- cn method set_from (pos : source_pos) = line_no <- pos#get_line_no; char_no <- pos#get_char_no; method advance_char_no offset = char_no <- char_no + offset method incr_line_no = line_no <- line_no + 1; self#reset_char_no; method incr_char_no = char_no <- char_no + 1 method reset_line_no = line_no <- 1 method reset_char_no = char_no <- 0 method reset = self#reset_line_no; self#reset_char_no; method is_origin = line_no = 1 && char_no = 0 method clone = {< >} end ;; camltemplate-1.0.2/src/ctStatement.ml0100644000076400010400000002255510251606441023534 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctStatement.ml,v 1.16 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtSourcePos ;; open CtScope ;; open CtTemplateModel ;; open CtExpression ;; open CtIdent ;; open CtExceptions ;; open CtTemplateTypes ;; (* This module includes all of the statement classes. *) (* Class type for AST nodes that produce output. *) class type statement = object method interpret : ctx:context -> unit method dump : string end ;; (* Upcasting function for statements. *) let as_statement stmt = (stmt :> statement) ;; (* Interprets a statement, using the specified context. *) let interpret_statement (ctx : context) (stmt : statement) = stmt#interpret ctx (* Interprets a list of statements, using the specified context. *) let interpret_statements (ctx : context) (statements : statement list) = List.iter (interpret_statement ctx) statements (* Dumps the parse tree of a list of statements. *) let dump_statements (statements : statement list) = List.fold_left (fun str stmt -> sprintf "%s%s" str stmt#dump) "" statements (* A statement that just outputs some text. *) class text_statement ~(text : string) = object val text = text method interpret ~(ctx : context) = Buffer.add_string ctx#get_buf text method dump = "[text]" end ;; (* A statement that prints the value of an expression. *) class expansion_statement ~(expr : expression) = object val expr = expr method interpret ~(ctx : context) = Buffer.add_string ctx#get_buf (expr#to_string ctx#get_cur_scope) method dump = sprintf "[print %s]" expr#dump end ;; (* A standard foreach statement. *) class for_each_statement ~(index : ident) ~(list_expr : expression) ~(statements : statement list) = object (self) val index = index val list_expr = list_expr val statements = statements (* Fishes out the list from a Tlist. *) method private get_value_list cur_scope = let list_expr_value = list_expr#get_value cur_scope in match list_expr_value with Tlist ls -> ls | Tnull -> raise (Template_error (template_error_message list_expr#get_pos "List is null")) | _ -> let detail = sprintf "Value after \"in\" is of type %s (list expected)" (get_type_name list_expr_value) in let msg = template_error_message list_expr#get_pos detail in raise (Template_error msg) method interpret ~(ctx : context) = let index_name = index#get_name and value_list = self#get_value_list ctx#get_cur_scope in let for_each_iter elem = (* Within the scope of the foreach, the value of the index variable hides the value of any variable with the same name. *) ctx#get_cur_scope#add index_name elem; interpret_statements ctx statements; ctx#get_cur_scope#remove index_name in List.iter for_each_iter value_list method dump = sprintf "[foreach %s in %s %s]" index#dump list_expr#dump (dump_statements statements) end ;; (* Represents an 'if' or 'elseif' branch. *) type cond_branch = expression * (statement list) ;; (* A standard if-elseif-else statement. *) class if_statement ~(cond_branches : cond_branch list) ~(else_statements : statement list) = object (self) val cond_branches = cond_branches val else_statements = else_statements method private interpret_branch ctx branch = let expr = fst branch in let branch_statements = snd branch in if expr#to_bool ctx#get_cur_scope then ( interpret_statements ctx branch_statements; true ) else false method interpret ~(ctx : context) = if not (self#interpret_branches ctx) then interpret_statements ctx else_statements method private interpret_branches ctx = let rec interpret_branches_aux branches = match branches with [] -> false | branch :: tail -> (self#interpret_branch ctx branch) || (interpret_branches_aux tail) in interpret_branches_aux cond_branches method dump = let else_dump = match else_statements with [] -> "" | _ -> sprintf "[else %s]" (dump_statements else_statements) in sprintf "[if %s%s]" self#dump_branches else_dump method private dump_branches = List.fold_left (fun str (expr, stmts) -> sprintf "%s[cond_branch %s: %s]" str expr#dump (dump_statements stmts)) "" cond_branches end ;; (* A statement that sets the value of a variable. *) class set_statement ~(left : ident) ~(right : expression) = object val left = left val right = right method interpret ~(ctx : context) = let ident_name = left#get_name in ctx#get_cur_scope#set ident_name (right#get_value ctx#get_cur_scope) method dump = sprintf "[set %s = %s]" left#dump right#dump end ;; (* A statement that defines a variable in the innermost scope. *) class var_statement ~(left : ident) ~(right : expression option) = object val left = left val right = right method interpret ~(ctx : context) = let ident_name = left#get_name in let right_value = match right with Some right_expr -> right_expr#get_value ctx#get_cur_scope | None -> Tnull in ctx#get_cur_scope#define ident_name right_value method dump = match right with Some right_expr -> sprintf "[var %s = %s]" left#dump right_expr#dump | None -> sprintf "[var %s]" left#dump end ;; (* A statement that interprets an included template. *) class include_statement ~(pos : source_pos) ~(template_name : expression) = object method interpret ~(ctx : context) = let included_tmpl = ctx#get_template (template_name#to_string ctx#get_cur_scope) in try included_tmpl#merge ctx#get_cur_scope#get_model ctx#get_buf with Template_error msg -> let msg_with_include_pos = template_error_message pos msg in raise (Template_error msg_with_include_pos) method dump = "[include]" end ;; (* A statement that opens a module. *) class open_statement ~(pos : source_pos) ~(template_name : expression) = object method interpret ~(ctx : context) = let template_name_str = template_name#to_string ctx#get_cur_scope in (* Make sure the template is loaded and up to date. *) ignore (ctx#get_template template_name_str); (* Add its name to the list of opened modules. *) if not (List.mem template_name_str ctx#get_opened_modules) then ctx#add_opened_module template_name_str method dump = "[open]" end ;; (* Macro-related statements. *) (* Searches for a macro in a list of templates. *) let rec find_macro get_template template_names macro_name = match template_names with [] -> raise Not_found | template_name :: tail -> try let tmpl = get_template template_name in tmpl#get_macro macro_name with Not_found -> find_macro get_template tail macro_name ;; (* A statement that calls a macro. *) class macro_call_statement ~(pos : source_pos) ~(macro_name : string) ~(args : expression list) = object val pos = pos val macro_name = macro_name val args = args method interpret ~(ctx : context) = let mac = try find_macro ctx#get_template ctx#get_opened_modules macro_name with Not_found -> let detail = sprintf "Macro %s not found" macro_name in let msg = template_error_message pos detail in raise (Template_error msg) in let arg_values = List.map (fun arg -> arg#get_value ctx#get_cur_scope) args in try mac#call arg_values ctx#make_macro_context with Template_error msg -> let msg_with_call_pos = template_error_message pos msg in raise (Template_error msg_with_call_pos) method dump = sprintf "[call %s]" macro_name end ;; (* A statement that does nothing. (Replaces a macro in the template where it was defined.) *) class null_statement = object method interpret ~(ctx : context) = () method dump = "[null]" end ;; camltemplate-1.0.2/src/ctTemplate.ml0100644000076400010400000001025710251606441023337 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctTemplate.ml,v 1.7 2005-06-08 15:22:09 ben Exp $ *) open Printf ;; open CtTemplateTypes ;; open CtContext ;; open CtScope ;; open CtStatement ;; open CtExceptions ;; (******************************************************************************* The template implementation class. *) class template_impl (template_name : string) (statements : statement list) (macros : macro list) (get_template_fun : template_name:string -> template) = object (self) val template_name = template_name val statements = statements val get_template_fun = get_template_fun val macro_cache = let hash = ((Hashtbl.create 16) : (string, macro) Hashtbl.t) in List.iter (function mac -> Hashtbl.replace hash mac#get_macro_name mac) macros; hash method merge ~model ~buf = let ctx = new context_impl ~template_name ~cur_scope:(new scope model) ~opened_modules:[ template_name ] ~buf ~get_template_fun in try interpret_statements ctx statements with Template_error msg -> let msg_with_name = sprintf "In template %s:\n%s" template_name msg in raise (Template_error msg_with_name) method get_name = template_name method get_macro macro_name = Hashtbl.find macro_cache macro_name method dump = sprintf "[template %s: %s]" template_name (dump_statements statements) end ;; (* Parses and constructs a template_impl from a string containing template source code. *) let make_template template_name template_text get_template_fun = let lexbuf = Lexing.from_string template_text in (* Tell the parser the name of the current template. *) CtParserAux.current_template_name := template_name; try (* Parse and return the template. *) CtParserAux.reset_parser (); CtLexer.reset_lexer (); let statements = CtParser.input CtLexer.main lexbuf in let macros = CtParserAux.get_macros () in let tmpl = new template_impl template_name statements macros get_template_fun in CtParserAux.clean_up_parser (); CtLexer.clean_up_lexer (); tmpl with Lexer_error (error_type, pos) -> let detail = lexer_error_message error_type in let msg = syntax_error_message template_name pos detail in raise (Syntax_error msg) | CtParserAux.ParserError (pos) -> let msg = syntax_error_message template_name pos "" in raise (Syntax_error msg) | Parsing.Parse_error -> let msg = syntax_error_message template_name CtLexer.cur_pos "Unhandled parse error: please report as a bug" in raise (Syntax_error msg) ;; camltemplate-1.0.2/src/ctTemplateModel.ml0100644000076400010400000000340410251606441024314 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctTemplateModel.ml,v 1.10 2005-06-08 15:22:09 ben Exp $ *) (* See CamlTemplate.Model. *) type tvalue = Tnull | Tstr of string | Tint of int | Tfloat of float | Tbool of bool | Tlist of tlist | Thash of thash | Tfun of tfun and tlist = tvalue list and thash = (string, tvalue) Hashtbl.t and tfun = (args:(tvalue list) -> tvalue) exception Tfun_error of string camltemplate-1.0.2/src/ctTemplateTypes.ml0100644000076400010400000000475410251606441024371 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctTemplateTypes.ml,v 1.4 2005-06-08 15:22:09 ben Exp $ *) open CtTemplateModel ;; open CtScope ;; (* The template, macro and context abstractions used internally by the interpreter. These are all in one place because they're interdependent. *) (* Instances of the template type are returned to the user (as an opaque type). *) class type template = object method merge : model:thash -> buf:Buffer.t -> unit method get_name : string method dump : string method get_macro : string -> macro end (* Represents a macro definition; macros are kept in the templates where they were defined. *) and macro = object method call : args:(tvalue list) -> ctx:context -> unit method get_macro_name : string method dump : string end (* Holds the interpreter's context while a template is being merged. *) and context = object method get_template_name : string method get_cur_scope : scope method get_opened_modules : string list method add_opened_module : string -> unit method get_buf : Buffer.t method get_template : string -> template method make_macro_context : context end ;; camltemplate-1.0.2/src/ctUnop.ml0100644000076400010400000000462210251606441022504 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctUnop.ml,v 1.10 2005-06-08 15:22:09 ben Exp $ *) open CtSourcePos ;; open CtTemplateModel ;; open CtScope ;; open Printf ;; open CtExpression ;; (* Unary operators are defined in this module. *) (* A virtual base class for unary operators. *) class virtual unary_op ~(pos : source_pos) ~(arg : expression) = object (self) inherit expression pos val arg = arg end ;; (* Unary boolean negation. *) class not_op ~(pos : source_pos) ~(arg : expression) = object (self) inherit unary_op pos arg as super inherit boolean_op method to_bool cur_scope = not (arg#to_bool cur_scope) method dump = sprintf "(!%s)" arg#dump end ;; (* Unary integer or float negation. *) class negative_op ~(pos : source_pos) ~(arg : expression) = object (self) inherit unary_op pos arg method get_value cur_scope = let value = arg#get_value cur_scope in match value with | Tfloat f -> Tfloat (-.f) | _ -> Tint (-(arg#value_to_int value)) method dump = sprintf "(-%s)" arg#dump end ;; camltemplate-1.0.2/src/ctUtil.ml0100644000076400010400000000612110251606441022474 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctUtil.ml,v 1.21 2005-06-08 15:22:09 ben Exp $ *) (* Miscellaneous utility functions. *) (* Returns the contents of a file as a string. (Thanks to Markus Mottl.) *) let read_file_as_string filename = let file = open_in_bin filename in let size = in_channel_length file in try let buf = String.create size in really_input file buf 0 size; close_in file; buf with e -> (try close_in file with _ -> ()); raise e (* Implements try-with-finally. *) let try_with_finally ~(f : unit -> 'a) ~(finally: unit -> unit) = let res = try f () with e -> finally (); raise e in finally (); res ;; type mutex_pair = { lock : unit -> unit; unlock : unit -> unit; } (* In multi-threading mode, the variable create_lock_unlock_pair is initialized right at startup with a reasonable mutex creator. In non-mt mode, the default value of this variable contains a dummy creator that does not lock anything. Don't use this function to create a static mutex; instead, use the static_mutex reference defined below. *) let create_lock_unlock = ref (fun () -> { lock = (fun () -> ()); unlock = (fun () -> ()) }) (* Locks a mutex, calls a function, then unlocks the mutex. The mutex is also unlocked if the function throws an exception. *) let call_in_mutex ~(f : unit -> 'a) ~mutex = mutex.lock (); try_with_finally ~f ~finally:(function () -> mutex.unlock ()) ;; (* A static real or dummy mutex that can be used by other modules. Don't store the value of this reference in a variable; instead, it must be dereferenced every time it is used. *) let static_mutex = ref (!create_lock_unlock ()) ;; camltemplate-1.0.2/src/ctWeb.ml0100644000076400010400000001335311030374372022302 0ustar gdsАдминистраторы(* CamlTemplate: A template processor for Objective Caml programs. Copyright © 2003, 2004, 2005 Benjamin Geer 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., 51 Franklin St., 5th Floor, Boston MA 02110-1301 USA In addition, as a special exception, Benjamin Geer gives permission to link the code of this program with the Apache HTTP Server (or with modified versions of Apache that use the same license as Apache), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Apache. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. *) (* $Id: ctWeb.ml,v 1.13 2008-06-25 07:51:22 gds Exp $ *) (* Provides template functions for escaping URLs and HTML text. *) open Str;; open CtTemplateModel ;; (* Code from wserver.ml, (C) 1997 Daniel de Rauglaudre, INRIA. *) let hexa_digit x = if x >= 10 then Char.chr (Char.code 'A' + x - 10) else Char.chr (Char.code '0' + x) ;; (* Characters to be escaped in URLs, according to RFC 1738. *) let special = function | '\000'..'\031' | '\127'..'\255' (* non US ASCII *) | '<' | '>' | '"' | '#' | '%' (* space should be here, but its encoding uses only one char *) | '{' | '}' | '|' | '\\' | '^' | '~' | '[' | ']' | '`' (* unsafe *) | ';' | '/' | '?' | ':' | '@' | '=' | '&' (* reserved *) -> true | '+' -> true | _ -> false ;; (* URL-encodes a string. *) let encode s = let rec need_code i = if i < String.length s then match s.[i] with | ' ' -> true | x -> if special x then true else need_code (succ i) else false in let rec compute_len i i1 = if i < String.length s then let i1 = if special s.[i] then i1 + 3 else succ i1 in compute_len (succ i) i1 else i1 in let rec copy_code_in s1 i i1 = if i < String.length s then let i1 = match s.[i] with | ' ' -> s1.[i1] <- '+'; succ i1 | c -> if special c then ( s1.[i1] <- '%'; s1.[i1 + 1] <- hexa_digit (Char.code c / 16); s1.[i1 + 2] <- hexa_digit (Char.code c mod 16); i1 + 3 ) else ( s1.[i1] <- c; succ i1 ) in copy_code_in s1 (succ i) i1 else s1 in if need_code 0 then let len = compute_len 0 0 in copy_code_in (String.create len) 0 0 else s ;; (* Characters that may need to be escaped in HTML. *) let amp_re = regexp "&" ;; let lt_re = regexp "<" ;; let gt_re = regexp ">" ;; let quot_re = regexp "\"" ;; let eol_re = regexp "\r?\n" ;; (* Escapes HTML text between tags. *) let esc_html str = let str = global_replace amp_re "&" str in let str = global_replace lt_re "<" str in let str = global_replace gt_re ">" str in let str = global_replace quot_re """ str in let str = global_replace eol_re "
" str in str ;; (* Escapes HTML text in attributes. *) let esc_html_attr str = let str = global_replace amp_re "&" str in let str = global_replace lt_re "<" str in let str = global_replace gt_re ">" str in let str = global_replace quot_re """ str in let str = global_replace eol_re " " str in str ;; (* Escapes HTML text in the value of a