1 <!-- $Id: book.xml,v 1.10 2006-04-20 12:42:47 adam Exp $ -->
3 <title>Metaproxy - User's Guide and Reference</title>
5 <firstname>Mike</firstname><surname>Taylor</surname>
8 <firstname>Adam</firstname><surname>Dickmeiss</surname>
12 <holder>Index Data</holder>
16 Metaproxy is a universal router, proxy and encapsulated
17 metasearcher for information retrieval protocols. It accepts,
18 processes, interprets and redirects requests from IR clients using
19 standard protocols such as ANSI/NISO Z39.50 (and in the future SRU
20 and SRW), as well as functioning as a limited
21 HTTP server. Metaproxy is configured by an XML file which
22 specifies how the software should function in terms of routes that
23 the request packets can take through the proxy, each step on a
24 route being an instantiation of a filter. Filters come in many
25 types, one for each operation: accepting Z39.50 packets, logging,
26 query transformation, multiplexing, etc. Further filter-types can
27 be added as loadable modules to extend Metaproxy functionality,
31 The terms under which Metaproxy will be distributed have yet to be
32 established, but it will not necessarily be open source; so users
33 should not at this stage redistribute the code without explicit
34 written permission from the copyright holders, Index Data ApS.
39 <chapter id="introduction">
40 <title>Introduction</title>
44 <ulink url="http://www.indexdata.com/metaproxy/">Metaproxy</ulink>
45 is a standalone program that acts as a universal router, proxy and
46 encapsulated metasearcher for information retrieval protocols such
47 as Z39.50, and in the future SRU and SRW. To clients, it acts as a
49 protocols: it can be searched, records can be retrieved from it,
50 etc. To servers, it acts as a client: it searches in them,
51 retrieves records from them, etc. it satisfies its clients'
52 requests by transforming them, multiplexing them, forwarding them
53 on to zero or more servers, merging the results, transforming
54 them, and delivering them back to the client. In addition, it
55 acts as a simple HTTP server; support for further protocols can be
56 added in a modular fashion, through the creation of new filters.
61 Cold bananas, fish, pyjamas,
62 Mutton, beef and trout!
63 - attributed to Cole Porter.
66 Metaproxy is a more capable alternative to
67 <ulink url="http://www.indexdata.com/yazproxy/">YAZ Proxy</ulink>,
68 being more powerful, flexible, configurable and extensible. Among
69 its many advantages over the older, more pedestrian work are
70 support for multiplexing (encapsulated metasearching), routing by
71 database name, authentication and authorisation and serving local
72 files via HTTP. Equally significant, its modular architecture
73 facilitites the creation of pluggable modules implementing further
80 <chapter id="licence">
81 <title>The Metaproxy Licence</title>
83 <emphasis role="strong">
84 No decision has yet been made on the terms under which
85 Metaproxy will be distributed.
87 It is possible that, unlike
88 other Index Data products, metaproxy may not be released under a
89 free-software licence such as the GNU GPL. Until a decision is
90 made and a public statement made, then, and unless it has been
91 delivered to you other specific terms, please treat Metaproxy as
92 though it were proprietary software.
93 The code should not be redistributed without explicit
94 written permission from the copyright holders, Index Data ApS.
100 <chapter id="architecture">
101 <title>The Metaproxy Architecture</title>
103 The Metaproxy architecture is based on three concepts:
104 the <emphasis>package</emphasis>,
105 the <emphasis>route</emphasis>
106 and the <emphasis>filter</emphasis>.
110 <term>Packages</term>
113 A package is request or response, encoded in some protocol,
114 issued by a client, making its way through Metaproxy, send to or
115 received from a server, or sent back to the client.
118 The core of a package is the protocol unit - for example, a
119 Z39.50 Init Request or Search Response, or an SRU searchRetrieve
120 URL or Explain Response. In addition to this core, a package
121 also carries some extra information added and used by Metaproxy
125 In general, packages are doctored as they pass through
126 Metaproxy. For example, when the proxy performs authentication
127 and authorisation on a Z39.50 Init request, it removes the
128 authentication credentials from the package so that they are not
129 passed onto the back-end server; and when search-response
130 packages are obtained from multiple servers, they are merged
131 into a single unified package that makes its way back to the
140 Packages make their way through routes, which can be thought of
141 as programs that operate on the package data-type. Each
142 incoming package initially makes its way through a default
143 route, but may be switched to a different route based on various
144 considerations. Routes are made up of sequences of filters (see
153 Filters provide the individual instructions within a route, and
154 effect the necessary transformations on packages. A particular
155 configuration of Metaproxy is essentially a set of filters,
156 described by configuration details and arranged in order in one
157 or more routes. There are many kinds of filter - about a dozen
158 at the time of writing with more appearing all the time - each
159 performing a specific function and configured by different
163 The word ``filter'' is sometimes used rather loosely, in two
164 different ways: it may be used to mean a particular
165 <emphasis>type</emphasis> of filter, as when we speak of ``the
166 auth_simplefilter'' or ``the multi filter''; or it may be used
167 to be a specific <emphasis>instance</emphasis> of a filter
168 within a Metaproxy configuration. For example, a single
169 configuration will often contain multiple instances of the
170 <literal>z3950_client</literal> filter. In
171 operational terms, of these is a separate filter. In practice,
172 context always make it clear which sense of the word ``filter''
176 Extensibility of Metaproxy is primarily through the creation of
177 plugins that provide new filters. The filter API is small and
178 conceptually simple, but there are many details to master. See
180 <link linkend="extensions">extensions</link>.
186 Since packages are created and handled by the system itself, and
187 routes are conceptually simple, most of the remainder of this
188 document concentrates on filters. After a brief overview of the
189 filter types follows, along with some thoughts on possible future
196 <chapter id="filters">
197 <title>Filters</title>
201 <title>Introductory notes</title>
203 It's useful to think of Metaproxy as an interpreter providing a small
204 number of primitives and operations, but operating on a very
205 complex data type, namely the ``package''.
208 A package represents a Z39.50 or SRU/W request (whether for Init,
209 Search, Scan, etc.) together with information about where it came
210 from. Packages are created by front-end filters such as
211 <literal>frontend_net</literal> (see below), which reads them from
212 the network; other front-end filters are possible. They then pass
213 along a route consisting of a sequence of filters, each of which
214 transforms the package and may also have side-effects such as
215 generating logging. Eventually, the route will yield a response,
216 which is sent back to the origin.
219 There are many kinds of filter: some that are defined statically
220 as part of Metaproxy, and others may be provided by third parties
221 and dynamically loaded. They all conform to the same simple API
222 of essentially two methods: <function>configure()</function> is
223 called at startup time, and is passed a DOM tree representing that
224 part of the configuration file that pertains to this filter
225 instance: it is expected to walk that tree extracting relevant
226 information; and <function>process()</function> is called every
227 time the filter has to processes a package.
230 While all filters provide the same API, there are different modes
231 of functionality. Some filters are sources: they create
233 (<literal>frontend_net</literal>);
234 others are sinks: they consume packages and return a result
235 (<literal>z3950_client</literal>,
236 <literal>backend_test</literal>,
237 <literal>http_file</literal>);
238 the others are true filters, that read, process and pass on the
239 packages they are fed
240 (<literal>auth_simple</literal>,
241 <literal>log</literal>,
242 <literal>multi</literal>,
243 <literal>query_rewrite</literal>,
244 <literal>session_shared</literal>,
245 <literal>template</literal>,
246 <literal>virt_db</literal>).
251 <section id="overview.filter.types">
252 <title>Overview of filter types</title>
254 We now briefly consider each of the types of filter supported by
255 the core Metaproxy binary. This overview is intended to give a
256 flavour of the available functionality; more detailed information
257 about each type of filter is included below in
258 <link linkend="filterref"
259 >the reference guide to Metaproxy filters</link>.
262 The filters are here named by the string that is used as the
263 <literal>type</literal> attribute of a
264 <literal><filter></literal> element in the configuration
265 file to request them, with the name of the class that implements
266 them in parentheses. (The classname is not needed for normal
267 configuration and use of Metaproxy; it is useful only to
271 The filters are here listed in alphabetical order:
275 <title><literal>auth_simple</literal>
276 (mp::filter::AuthSimple)</title>
278 Simple authentication and authorisation. The configuration
279 specifies the name of a file that is the user register, which
280 lists <varname>username</varname>:<varname>password</varname>
281 pairs, one per line, colon separated. When a session begins, it
282 is rejected unless username and passsword are supplied, and match
283 a pair in the register. The configuration file may also specific
284 the name of another file that is the target register: this lists
285 lists <varname>username</varname>:<varname>dbname</varname>,<varname>dbname</varname>...
286 sets, one per line, with multiple database names separated by
287 commas. When a search is processed, it is rejected unless the
288 database to be searched is one of those listed as available to
294 <title><literal>backend_test</literal>
295 (mp::filter::Backend_test)</title>
297 A sink that provides dummy responses in the manner of the
298 <literal>yaz-ztest</literal> Z39.50 server. This is useful only
299 for testing. Seriously, you don't need this. Pretend you didn't
300 even read this section.
305 <title><literal>frontend_net</literal>
306 (mp::filter::FrontendNet)</title>
308 A source that accepts Z39.50 connections from a port
309 specified in the configuration, reads protocol units, and
310 feeds them into the next filter in the route. When the result is
311 revceived, it is returned to the original origin.
316 <title><literal>http_file</literal>
317 (mp::filter::HttpFile)</title>
319 A sink that returns the contents of files from the local
320 filesystem in response to HTTP requests. (Yes, Virginia, this
321 does mean that Metaproxy is also a Web-server in its spare time. So
322 far it does not contain either an email-reader or a Lisp
323 interpreter, but that day is surely coming.)
328 <title><literal>log</literal>
329 (mp::filter::Log)</title>
331 Writes logging information to standard output, and passes on
332 the package unchanged.
337 <title><literal>multi</literal>
338 (mp::filter::Multi)</title>
340 Performs multicast searching.
342 <link linkend="multidb">the extended discussion</link>
343 of virtual databases and multi-database searching below.
348 <title><literal>query_rewrite</literal>
349 (mp::filter::QueryRewrite)</title>
351 Rewrites Z39.50 Type-1 and Type-101 (``RPN'') queries by a
352 three-step process: the query is transliterated from Z39.50
353 packet structures into an XML representation; that XML
354 representation is transformed by an XSLT stylesheet; and the
355 resulting XML is transliterated back into the Z39.50 packet
361 <title><literal>session_shared</literal>
362 (mp::filter::SessionShared)</title>
364 When this is finished, it will implement global sharing of
365 result sets (i.e. between threads and therefore between
366 clients), yielding performance improvements especially when
367 incoming requests are from a stateless environment such as a
368 web-server, in which the client process representing a session
369 might be any one of many. However:
373 This filter is not yet completed.
379 <title><literal>template</literal>
380 (mp::filter::Template)</title>
382 Does nothing at all, merely passing the packet on. (Maybe it
383 should be called <literal>nop</literal> or
384 <literal>passthrough</literal>?) This exists not to be used, but
385 to be copied - to become the skeleton of new filters as they are
386 written. As with <literal>backend_test</literal>, this is not
387 intended for civilians.
392 <title><literal>virt_db</literal>
393 (mp::filter::Virt_db)</title>
395 Performs virtual database selection: based on the name of the
396 database in the search request, a server is selected, and its
397 address added to the request in a <literal>VAL_PROXY</literal>
398 otherInfo packet. It will subsequently be used by a
399 <literal>z3950_client</literal> filter.
401 <link linkend="multidb">the extended discussion</link>
402 of virtual databases and multi-database searching below.
407 <title><literal>z3950_client</literal>
408 (mp::filter::Z3950Client)</title>
410 Performs Z39.50 searching and retrieval by proxying the
411 packages that are passed to it. Init requests are sent to the
412 address specified in the <literal>VAL_PROXY</literal> otherInfo
413 attached to the request: this may have been specified by client,
414 or generated by a <literal>virt_db</literal> filter earlier in
415 the route. Subsequent requests are sent to the same address,
416 which is remembered at Init time in a Session object.
422 <section id="future.directions">
423 <title>Future directions</title>
425 Some other filters that do not yet exist, but which would be
426 useful, are briefly described. These may be added in future
427 releases (or may be created by third parties, as loadable
433 <term><literal>frontend_cli</literal> (source)</term>
436 Command-line interface for generating requests.
441 <term><literal>frontend_sru</literal> (source)</term>
444 Receive SRU (and perhaps SRW) requests.
449 <term><literal>sru2z3950</literal> (filter)</term>
452 Translate SRU requests into Z39.50 requests.
457 <term><literal>sru_client</literal> (sink)</term>
460 SRU searching and retrieval.
465 <term><literal>srw_client</literal> (sink)</term>
468 SRW searching and retrieval.
473 <term><literal>opensearch_client</literal> (sink)</term>
476 A9 OpenSearch searching and retrieval.
486 <chapter id="configuration">
487 <title>Configuration: the Metaproxy configuration file format</title>
491 <title>Introductory notes</title>
493 If Metaproxy is an interpreter providing operations on packages, then
494 its configuration file can be thought of as a program for that
495 interpreter. Configuration is by means of a single file, the name
496 of which is supplied as the sole command-line argument to the
497 <command>metaproxy</command> program. (See
498 <link linkend="progref">the reference guide</link>
499 below for more information on invoking Metaproxy.)
502 The configuration files are written in XML. (But that's just an
503 implementation detail - they could just as well have been written
504 in YAML or Lisp-like S-expressions, or in a custom syntax.)
507 Since XML has been chosen, an XML schema,
508 <filename>config.xsd</filename>, is provided for validating
509 configuration files. This file is supplied in the
510 <filename>etc</filename> directory of the Metaproxy distribution. It
511 can be used by (among other tools) the <command>xmllint</command>
512 program supplied as part of the <literal>libxml2</literal>
516 xmllint --noout --schema etc/config.xsd my-config-file.xml
519 (A recent version of <literal>libxml2</literal> is required, as
520 support for XML Schemas is a relatively recent addition.)
524 <section id="overview.xml.structure">
525 <title>Overview of XML structure</title>
527 All elements and attributes are in the namespace
528 <ulink url="http://indexdata.dk/yp2/config/1"/>.
529 This is most easily achieved by setting the default namespace on
530 the top-level element, as here:
533 <yp2 xmlns="http://indexdata.dk/yp2/config/1">
536 The top-level element is <yp2>. This contains a
537 <start> element, a <filters> element and a
538 <routes> element, in that order. <filters> is
539 optional; the other two are mandatory. All three are
543 The <start> element is empty, but carries a
544 <literal>route</literal> attribute, whose value is the name of
545 route at which to start running - analogous to the name of the
546 start production in a formal grammar.
549 If present, <filters> contains zero or more <filter>
550 elements. Each filter carries a <literal>type</literal> attribute
551 which specifies what kind of filter is being defined
552 (<literal>frontend_net</literal>, <literal>log</literal>, etc.)
553 and contain various elements that provide suitable configuration
554 for a filter of its type. The filter-specific elements are
556 <link linkend="filterref">the reference guide below</link>.
557 Filters defined in this part of the file must carry an
558 <literal>id</literal> attribute so that they can be referenced
562 <routes> contains one or more <route> elements, each
563 of which must carry an <literal>id</literal> element. One of the
564 routes must have the ID value that was specified as the start
565 route in the <start> element's <literal>route</literal>
566 attribute. Each route contains zero or more <filter>
567 elements. These are of two types. They may be empty, but carry a
568 <literal>refid</literal> attribute whose value is the same as the
569 <literal>id</literal> of a filter previously defined in the
570 <filters> section. Alternatively, a route within a filter
571 may omit the <literal>refid</literal> attribute, but contain
572 configuration elements similar to those used for filters defined
573 in the <filters> section. (In other words, each filter in a
574 route may be included either by reference or by physical
580 <section id="example.configuration">
581 <title>An example configuration</title>
583 The following is a small, but complete, Metaproxy configuration
584 file (included in the distribution as
585 <literal>metaproxy/etc/config0.xml</literal>).
586 This file defines a very simple configuration that simply proxies
587 to whatever backend server the client requests, but logs each
588 request and response. This can be useful for debugging complex
589 client-server dialogues.
592 <?xml version="1.0"?>
593 <yp2 xmlns="http://indexdata.dk/yp2/config/1">
594 <start route="start"/>
596 <filter id="frontend" type="frontend_net">
599 <filter id="backend" type="z3950_client">
604 <filter refid="frontend"/>
606 <filter refid="backend"/>
612 It works by defining a single route, called
613 <literal>start</literal>, which consists of a sequence of three
614 filters. The first and last of these are included by reference:
615 their <literal><filter></literal> elements have
616 <literal>refid</literal> attributes that refer to filters defined
617 within the prior <literal><filters></literal> section. The
618 middle filter is included inline in the route.
621 The three filters in the route are as follows: first, a
622 <literal>frontend_net</literal> filter accepts Z39.50 requests
623 from any host on port 9000; then these requests are passed through
624 a <literal>log</literal> filter that emits a message for each
625 request; they are then fed into a <literal>z3950_client</literal>
626 filter, which forwards the requests to the client-specified
627 backend Z39.509 server. When the response arrives, it is handed
628 back to the <literal>log</literal> filter, which emits another
629 message; and then to the front-end filter, which returns the
630 response to the client.
637 <chapter id="multidb">
638 <title>Virtual databases and multi-database searching</title>
642 <title>Introductory notes</title>
644 Two of Metaproxy's filters are concerned with multiple-database
645 operations. Of these, <literal>virt_db</literal> can work alone
646 to control the routing of searches to one of a number of servers,
647 while <literal>multi</literal> can work with the output of
648 <literal>virt_db</literal> to perform multicast searching, merging
649 the results into a unified result-set. The interaction between
650 these two filters is necessarily complex, reflecting the real
651 complexity of multicast searching in a protocol such as Z39.50
652 that separates initialisation from searching, with the database to
653 search known only during the latter operation.
656 ### Much, much more to say!
663 <chapter id="extensions">
664 <title>Writing extensions for Metaproxy</title>
665 <para>### To be written</para>
671 <chapter id="classes">
672 <title>Classes in the Metaproxy source code</title>
676 <title>Introductory notes</title>
678 <emphasis>Stop! Do not read this!</emphasis>
679 You won't enjoy it at all. You should just skip ahead to
680 <link linkend="refguide">the reference guide</link>,
682 <!-- The remainder of this paragraph is lifted verbatim from
683 Douglas Adams' _Hitch Hiker's Guide to the Galaxy_, chapter 8 -->
684 you things you really need to know, like the fact that the
685 fabulously beautiful planet Bethselamin is now so worried about
686 the cumulative erosion by ten billion visiting tourists a year
687 that any net imbalance between the amount you eat and the amount
688 you excrete whilst on the planet is surgically removed from your
689 bodyweight when you leave: so every time you go to the lavatory it
690 is vitally important to get a receipt.
693 This chapter contains documentation of the Metaproxy source code, and is
694 of interest only to maintainers and developers. If you need to
695 change Metaproxy's behaviour or write a new filter, then you will most
696 likely find this chapter helpful. Otherwise it's a waste of your
697 good time. Seriously: go and watch a film or something.
698 <citetitle>This is Spinal Tap</citetitle> is particularly good.
701 Still here? OK, let's continue.
704 In general, classes seem to be named big-endianly, so that
705 <literal>FactoryFilter</literal> is not a filter that filters
706 factories, but a factory that produces filters; and
707 <literal>FactoryStatic</literal> is a factory for the statically
708 registered filters (as opposed to those that are dynamically
713 <section id="individual.classes">
714 <title>Individual classes</title>
716 The classes making up the Metaproxy application are here listed by
717 class-name, with the names of the source files that define them in
722 <title><literal>mp::FactoryFilter</literal>
723 (<filename>factory_filter.cpp</filename>)</title>
725 A factory class that exists primarily to provide the
726 <literal>create()</literal> method, which takes the name of a
727 filter class as its argument and returns a new filter of that
728 type. To enable this, the factory must first be populated by
729 calling <literal>add_creator()</literal> for static filters (this
730 is done by the <literal>FactoryStatic</literal> class, see below)
731 and <literal>add_creator_dyn()</literal> for filters loaded
737 <title><literal>mp::FactoryStatic</literal>
738 (<filename>factory_static.cpp</filename>)</title>
740 A subclass of <literal>FactoryFilter</literal> which is
741 responsible for registering all the statically defined filter
742 types. It does this by knowing about all those filters'
743 structures, which are listed in its constructor. Merely
744 instantiating this class registers all the static classes. It is
745 for the benefit of this class that <literal>struct
746 metaproxy_1_filter_struct</literal> exists, and that all the filter
747 classes provide a static object of that type.
752 <title><literal>mp::filter::Base</literal>
753 (<filename>filter.cpp</filename>)</title>
755 The virtual base class of all filters. The filter API is, on the
756 surface at least, extremely simple: two methods.
757 <literal>configure()</literal> is passed a DOM tree representing
758 that part of the configuration file that pertains to this filter
759 instance, and is expected to walk that tree extracting relevant
760 information. And <literal>process()</literal> processes a
761 package (see below). That surface simplicitly is a bit
762 misleading, as <literal>process()</literal> needs to know a lot
763 about the <literal>Package</literal> class in order to do
769 <title><literal>mp::filter::AuthSimple</literal>,
770 <literal>Backend_test</literal>, etc.
771 (<filename>filter_auth_simple.cpp</filename>,
772 <filename>filter_backend_test.cpp</filename>, etc.)</title>
774 Individual filters. Each of these is implemented by a header and
775 a source file, named <filename>filter_*.hpp</filename> and
776 <filename>filter_*.cpp</filename> respectively. All the header
777 files should be pretty much identical, in that they declare the
778 class, including a private <literal>Rep</literal> class and a
779 member pointer to it, and the two public methods. The only extra
780 information in any filter header is additional private types and
781 members (which should really all be in the <literal>Rep</literal>
782 anyway) and private methods (which should also remain known only
783 to the source file, but C++'s brain-damaged design requires this
784 dirty laundry to be exhibited in public. Thanks, Bjarne!)
787 The source file for each filter needs to supply:
792 A definition of the private <literal>Rep</literal> class.
797 Some boilerplate constructors and destructors.
802 A <literal>configure()</literal> method that uses the
803 appropriate XML fragment.
808 Most important, the <literal>process()</literal> method that
809 does all the actual work.
816 <title><literal>mp::Package</literal>
817 (<filename>package.cpp</filename>)</title>
819 Represents a package on its way through the series of filters
820 that make up a route. This is essentially a Z39.50 or SRU APDU
821 together with information about where it came from, which is
822 modified as it passes through the various filters.
827 <title><literal>mp::Pipe</literal>
828 (<filename>pipe.cpp</filename>)</title>
830 This class provides a compatibility layer so that we have an IPC
831 mechanism that works the same under Unix and Windows. It's not
832 particularly exciting.
837 <title><literal>mp::RouterChain</literal>
838 (<filename>router_chain.cpp</filename>)</title>
845 <title><literal>mp::RouterFleXML</literal>
846 (<filename>router_flexml.cpp</filename>)</title>
853 <title><literal>mp::Session</literal>
854 (<filename>session.cpp</filename>)</title>
861 <title><literal>mp::ThreadPoolSocketObserver</literal>
862 (<filename>thread_pool_observer.cpp</filename>)</title>
869 <title><literal>mp::util</literal>
870 (<filename>util.cpp</filename>)</title>
872 A namespace of various small utility functions and classes,
873 collected together for convenience. Most importantly, includes
874 the <literal>mp::util::odr</literal> class, a wrapper for YAZ's
880 <title><literal>mp::xml</literal>
881 (<filename>xmlutil.cpp</filename>)</title>
883 A namespace of various XML utility functions and classes,
884 collected together for convenience.
890 <section id="other.source.files">
891 <title>Other Source Files</title>
893 In addition to the Metaproxy source files that define the classes
894 described above, there are a few additional files which are
895 briefly described here:
899 <term><literal>metaproxy_prog.cpp</literal></term>
902 The main function of the <command>metaproxy</command> program.
907 <term><literal>ex_router_flexml.cpp</literal></term>
910 Identical to <literal>metaproxy_prog.cpp</literal>: it's not clear why.
915 <term><literal>test_*.cpp</literal></term>
918 Unit-tests for various modules.
924 ### Still to be described:
925 <literal>ex_filter_frontend_net.cpp</literal>,
926 <literal>filter_dl.cpp</literal>,
927 <literal>plainfile.cpp</literal>,
928 <literal>tstdl.cpp</literal>.
935 <chapter id="refguide">
936 <title>Reference guide</title>
938 The material in this chapter is drawn directly from the individual
939 manual entries. In particular, the Metaproxy invocation section is
940 available using <command>man metaproxy</command>, and the section
941 on each individual filter is available using the name of the filter
942 as the argument to the <command>man</command> command.
946 <section id="progref">
947 <title>Metaproxy invocation</title>
952 <section id="filterref">
953 <title>Reference guide to Metaproxy filters</title>
960 <!-- Keep this comment at the end of the file
965 sgml-minimize-attributes:nil
966 sgml-always-quote-attributes:t
969 sgml-parent-document: "main.xml"
970 sgml-local-catalogs: nil
971 sgml-namecase-general:t