mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-26 05:48:57 +00:00

git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@301137 c90b9560-bf6c-de11-be94-00142212c4b1
656 lines
17 KiB
XML
656 lines
17 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
|
|
<chapter xml:id="mysqlnd-qc.usage" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
&reftitle.examples;
|
|
|
|
<section xml:id="mysqlnd-qc.basic_usage" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Basic usage</title>
|
|
<para>
|
|
The Query Cache plugin supports caching of queries issued by the following user API calls:
|
|
</para>
|
|
|
|
<para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ref.mysqli">mysqli</link>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<function>mysqli_query</function>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<function>mysqli_real_query</function> +
|
|
<function>mysqli_store_result</function>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ref.pdo-mysql">PDO_MYSQL</link>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<function>PDO::query</function> if
|
|
<literal>PDO::ATTR_EMULATE_PREPARES = 1</literal> (default setting)
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ref.mysql">mysql</link>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<function>mysql_query</function>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
|
|
<para>
|
|
A query which shall be cached must begin with the SQL hint
|
|
<literal>/*qc=on*/</literal>. It is recommended to use the PHP constant
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.constants">MYSQLND_QC_ENABLE_SWITCH</link>
|
|
</literal> instead of using the string value.
|
|
</para>
|
|
<para>
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
uncached:
|
|
<literal>SELECT id FROM test</literal>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
cached:
|
|
<literal>/*qc=on*/SELECT id FROM test</literal>
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
Example using the most advanced PHP MySQL API, which is
|
|
<literal>
|
|
<link linkend="ref.mysqli">mysqli</link>
|
|
</literal>:
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* Enable collection of query cache statistics */
|
|
ini_set("mysqlnd_qc.collect_statistics", 1);
|
|
|
|
/* Connect, create and populate test table */
|
|
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
|
|
$mysqli->query("DROP TABLE IF EXISTS test");
|
|
$mysqli->query("CREATE TABLE test(id INT)");
|
|
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
|
|
|
|
/* Will be cached because of the SQL hint: cache put and cache_miss */
|
|
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
/* Will NOT be cached and will NOT hit the cache: no SQL hint */
|
|
$res = $mysqli->query("SELECT id FROM test WHERE id = 2");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
/* Display cache statistics */
|
|
$stats = mysqlnd_qc_get_core_stats();
|
|
printf("Cache hit\t: %d\n", $stats['cache_hit']);
|
|
printf("Cache miss\t: %d\n", $stats['cache_miss']);
|
|
printf("Cache put\t: %d\n", $stats['cache_put']);
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&examples.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "2"
|
|
}
|
|
Cache hit : 0
|
|
Cache miss : 1
|
|
Cache put : 1
|
|
]]>
|
|
</screen>
|
|
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The default invalidation strategy of the cache is Time-to-Live (
|
|
<literal>TTL</literal>). Cache entries are valid for a certain duration.
|
|
The default duration is set by the PHP configuration directive
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.configuration">mysqlnd_qc.tll</link>
|
|
</literal>
|
|
</para>
|
|
</section>
|
|
|
|
<section xml:id="mysqlnd-qc.per_query_ttl" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Setting the TTL</title>
|
|
<para>
|
|
The default invalidation strategy of the query cache plugin is Time-to-Live (
|
|
<literal>TTL</literal>). The built-in storage handler will use the default
|
|
<literal>TTL</literal> defined by the PHP configuration value
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.configuration">mysqlnd_qc.ttl</link>
|
|
</literal> unless the query string contains
|
|
a hint for setting a different
|
|
<literal>TTL</literal>. The
|
|
<literal>TTL</literal> is specified in seconds.
|
|
</para>
|
|
<para>
|
|
Any
|
|
<literal>TTL</literal> based cache can serve stale data. Cache entries
|
|
are not automatically invalidated, if underlying data changes.
|
|
</para>
|
|
<para>
|
|
User-defined cache storage handler can implement any invalidation strategy
|
|
to work around this limitation.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* Connect, create and populate test table */
|
|
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
|
|
$mysqli->query("DROP TABLE IF EXISTS test");
|
|
$mysqli->query("CREATE TABLE test(id INT)");
|
|
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
|
|
|
|
printf("Default TTL\t: %d seconds\n", ini_get("mysqlnd_qc.ttl"));
|
|
|
|
/* Will be cached because of the SQL hint */
|
|
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
$mysqli->query("DELETE FROM test WHERE id = 1");
|
|
|
|
/* Cache hit - no automatic invalidation! */
|
|
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
sleep(ini_get("mysqlnd_qc.ttl"));
|
|
|
|
/* Cache miss - cache entry has expired */
|
|
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&examples.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Default TTL: : 30 seconds
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
NULL
|
|
]]>
|
|
</screen>
|
|
|
|
</example>
|
|
</para>
|
|
<para>
|
|
The default
|
|
<literal>TTL</literal> can be overruled using the SQL hint
|
|
<literal>/*qc_tt=seconds*/</literal>. The SQL hint must be appear immediately
|
|
after the SQL hint which enables caching. It is recommended to use
|
|
the PHP constant
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.constants">MYSQLND_QC_TTL_SWITCH</link>
|
|
</literal> instead of using the string value.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$start = microtime(true);
|
|
|
|
/* Connect, create and populate test table */
|
|
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
|
|
$mysqli->query("DROP TABLE IF EXISTS test");
|
|
$mysqli->query("CREATE TABLE test(id INT)");
|
|
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
|
|
|
|
printf("Default TTL\t: %d seconds\n", ini_get("mysqlnd_qc.ttl"));
|
|
|
|
/* Will be cached for 2 seconds */
|
|
$sql = sprintf("/*%s*//*%s%d*/SELECT id FROM test WHERE id = 1",
|
|
MYSQLND_QC_ENABLE_SWITCH,
|
|
MYSQLND_QC_TTL_SWITCH,
|
|
2);
|
|
$res = $mysqli->query($sql);
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
$mysqli->query("DELETE FROM test WHERE id = 1");
|
|
sleep(1);
|
|
|
|
/* Cache hit - no automatic invalidation and still valid! */
|
|
$res = $mysqli->query($sql);
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
sleep(2);
|
|
|
|
/* Cache miss - cache entry has expired */
|
|
$res = $mysqli->query($sql);
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
printf("Script runtime\t: %d seconds\n", microtime(true) - $start);
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&examples.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
Default TTL : 30 seconds
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
NULL
|
|
Script runtime : 3 seconds
|
|
|
|
]]>
|
|
</screen>
|
|
|
|
</example>
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section xml:id="mysqlnd-qc.cache_by_default" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Cache by default</title>
|
|
<para>
|
|
The query cache plugin will cache all queries regardless if
|
|
the query string begins with the SQL hint which enables caching or not,
|
|
if the PHP configuration directive
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.configuration">mysqlnd_qc.cache_by_default</link>
|
|
</literal> is set to
|
|
<literal>1</literal>.
|
|
The setting
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.configuration">mysqlnd_qc.cache_by_default</link>
|
|
</literal> is evaluated by the core of the query cache plugins.
|
|
Neither the built-in nor user-defined storage handler can overrule the setting.
|
|
</para>
|
|
<para>
|
|
The SQL hint
|
|
<literal>/*qc=off*/</literal> can be used to disable caching
|
|
of individual queries if
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.configuration">mysqlnd_qc.cache_by_default = 1</link>
|
|
</literal>
|
|
It is recommended to use the PHP constant
|
|
<literal>
|
|
<link linkend="mysqlnd-qc.constants">MYSQLND_QC_DISABLE_SWITCH</link>
|
|
</literal> instead of using the string value.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* Enable default caching of all statements */
|
|
ini_set("mysqlnd_qc.cache_by_default", 1);
|
|
|
|
/* Connect, create and populate test table */
|
|
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
|
|
$mysqli->query("DROP TABLE IF EXISTS test");
|
|
$mysqli->query("CREATE TABLE test(id INT)");
|
|
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
|
|
|
|
|
|
/* Will be cached although no SQL hint is present because of mysqlnd_qc.cache_by_default = 1*/
|
|
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
$mysqli->query("DELETE FROM test WHERE id = 1");
|
|
|
|
/* Cache hit - no automatic invalidation and still valid! */
|
|
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
/* Cache miss - query must not be cached or served from cache because of the SQL hint */
|
|
$res = $mysqli->query("/*" . MYSQLND_QC_DISABLE_SWITCH . "*/SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&examples.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
NULL
|
|
]]>
|
|
</screen>
|
|
|
|
</example>
|
|
</para>
|
|
</section>
|
|
|
|
|
|
<section xml:id="mysqlnd-qc.set_user_handlers" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>Procedural user-defined storage handler</title>
|
|
<para>
|
|
The query cache plugin supports the use of user-defined storage handler.
|
|
User-defined storage handler can use arbitrarily complex invalidation
|
|
algorithms and support arbitrary storage media.
|
|
</para>
|
|
<para>
|
|
All user-defined storage handlers have to provide a certain interface.
|
|
The functions of the user-defined storage handler will be called by the
|
|
core of the cache plugin. The necessary interface consists of seven
|
|
public functions. Both procedural and object oriented user-defined storage
|
|
handler must implement the same set of functions.
|
|
</para>
|
|
<para>
|
|
Please check the example for details.
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
/* Enable default caching of all statements */
|
|
ini_set("mysqlnd_qc.cache_by_default", 1);
|
|
|
|
/* Procedural user defined storage handler functions */
|
|
|
|
$__cache = array();
|
|
|
|
function get_hash($host_info, $port, $user, $db, $query) {
|
|
global $__cache;
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
|
|
return md5(sprintf("%s%s%s%s%s", $host_info, $port, $user, $db, $query));
|
|
}
|
|
|
|
function find_query_in_cache($key) {
|
|
global $__cache;
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
|
|
if (isset($__cache[$key])) {
|
|
$tmp = $__cache[$key];
|
|
if ($tmp["valid_until"] < time()) {
|
|
unset($__cache[$key]);
|
|
$ret = NULL;
|
|
} else {
|
|
$ret = $__cache[$key]["data"];
|
|
}
|
|
} else {
|
|
$ret = NULL;
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
function return_to_cache($key) {
|
|
/*
|
|
Called on cache hit after cached data has been processed,
|
|
may be used for reference counting
|
|
*/
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
}
|
|
|
|
function add_query_to_cache_if_not_exists($key, $data, $ttl, $run_time, $store_time, $row_count) {
|
|
global $__cache;
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
|
|
$__cache[$key] = array(
|
|
"data" => $data,
|
|
"row_count" => $row_count,
|
|
"valid_until" => time() + $ttl,
|
|
"hits" => 0,
|
|
"run_time" => $run_time,
|
|
"store_time" => $store_time,
|
|
"cached_run_times" => array(),
|
|
"cached_store_times" => array(),
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
function query_is_select($query) {
|
|
printf("\t%s('%s'): ", __FUNCTION__, $query);
|
|
|
|
$ret = FALSE;
|
|
if (stristr($query, "SELECT") !== FALSE) {
|
|
/* cache for 5 seconds */
|
|
$ret = 5;
|
|
}
|
|
|
|
printf("%s\n", (FALSE === $ret) ? "FALSE" : $ret);
|
|
return $ret;
|
|
}
|
|
|
|
function update_query_run_time_stats($key, $run_time, $store_time) {
|
|
global $__cache;
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
|
|
if (isset($__cache[$key])) {
|
|
$__cache[$key]['hits']++;
|
|
$__cache[$key]["cached_run_times"][] = $run_time;
|
|
$__cache[$key]["cached_store_times"][] = $store_time;
|
|
}
|
|
}
|
|
|
|
function get_stats($key = NULL) {
|
|
global $__cache;
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
|
|
if ($key && isset($__cache[$key])) {
|
|
$stats = $__cache[$key];
|
|
} else {
|
|
$stats = array();
|
|
foreach ($__cache as $key => $details) {
|
|
$stats[$key] = array(
|
|
'hits' => $details['hits'],
|
|
'bytes' => strlen($details['data']),
|
|
'uncached_run_time' => $details['run_time'],
|
|
'cached_run_time' => (count($details['cached_run_times']))
|
|
? array_sum($details['cached_run_times']) / count($details['cached_run_times'])
|
|
: 0,
|
|
);
|
|
}
|
|
}
|
|
|
|
return $stats;
|
|
}
|
|
|
|
function clear_cache() {
|
|
global $__cache;
|
|
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
|
|
|
|
$__cache = array();
|
|
return TRUE;
|
|
}
|
|
|
|
/* Install procedural user-defined storage handler */
|
|
if (!mysqlnd_qc_set_user_handlers("get_hash", "find_query_in_cache",
|
|
"return_to_cache", "add_query_to_cache_if_not_exists",
|
|
"query_is_select", "update_query_run_time_stats",
|
|
"get_stats", "clear_cache")) {
|
|
printf("Failed to install user-defined storage handler\n");
|
|
}
|
|
|
|
|
|
/* Connect, create and populate test table */
|
|
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
|
|
$mysqli->query("DROP TABLE IF EXISTS test");
|
|
$mysqli->query("CREATE TABLE test(id INT)");
|
|
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
|
|
|
|
printf("\nCache put/cache miss\n");
|
|
|
|
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
/* Delete record to verify we get our data from the cache */
|
|
$mysqli->query("DELETE FROM test WHERE id = 1");
|
|
|
|
printf("\nCache hit\n");
|
|
|
|
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
|
|
printf("\nDisplay cache statistics\n");
|
|
var_dump(mysqlnd_qc_get_cache_info());
|
|
|
|
printf("\nFlushing cache, cache put/cache miss");
|
|
var_dump(mysqlnd_qc_clear_cache());
|
|
|
|
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
|
|
var_dump($res->fetch_assoc());
|
|
$res->free();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&examples.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
query_is_select('DROP TABLE IF EXISTS test'): FALSE
|
|
query_is_select('CREATE TABLE test(id INT)'): FALSE
|
|
query_is_select('INSERT INTO test(id) VALUES (1), (2)'): FALSE
|
|
|
|
Cache put/cache miss
|
|
query_is_select('SELECT id FROM test WHERE id = 1'): 5
|
|
get_hash(5)
|
|
find_query_in_cache(1)
|
|
add_query_to_cache_if_not_exists(6)
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
query_is_select('DELETE FROM test WHERE id = 1'): FALSE
|
|
|
|
Cache hit
|
|
query_is_select('SELECT id FROM test WHERE id = 1'): 5
|
|
get_hash(5)
|
|
find_query_in_cache(1)
|
|
return_to_cache(1)
|
|
update_query_run_time_stats(3)
|
|
array(1) {
|
|
["id"]=>
|
|
string(1) "1"
|
|
}
|
|
|
|
Display cache statistics
|
|
get_stats(0)
|
|
array(4) {
|
|
["num_entries"]=>
|
|
int(1)
|
|
["handler"]=>
|
|
string(4) "user"
|
|
["handler_version"]=>
|
|
string(5) "1.0.0"
|
|
["data"]=>
|
|
array(1) {
|
|
["18683c177dc89bb352b29965d112fdaa"]=>
|
|
array(4) {
|
|
["hits"]=>
|
|
int(1)
|
|
["bytes"]=>
|
|
int(71)
|
|
["uncached_run_time"]=>
|
|
int(398)
|
|
["cached_run_time"]=>
|
|
int(4)
|
|
}
|
|
}
|
|
}
|
|
|
|
Flushing cache, cache put/cache miss clear_cache(0)
|
|
bool(true)
|
|
query_is_select('SELECT id FROM test WHERE id = 1'): 5
|
|
get_hash(5)
|
|
find_query_in_cache(1)
|
|
add_query_to_cache_if_not_exists(6)
|
|
NULL
|
|
|
|
]]>
|
|
</screen>
|
|
|
|
</example>
|
|
</para>
|
|
</section>
|
|
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|