<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"../docbook/dtd/docbookx.dtd"
[
<!ENTITY % entities_version SYSTEM "version.xml">
%entities_version;
<!ENTITY license SYSTEM "license.xml">
<!ENTITY chardet "<application>Universal Encoding Detector</application>">
<!ENTITY chardet_version "1.0.1">
<!ENTITY chardet_modulename "<filename class='headerfile'>chardet</filename>">
<!ENTITY title "Documentation">
<!ENTITY url_book "http://chardet.feedparser.org/docs/">
<!ENTITY researchpaper "<ulink url='http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html'>A composite approach to language/encoding detection</ulink>">
<!ENTITY prompt "<prompt>>>> </prompt>">
<!ENTITY continuationprompt "<prompt>...     </prompt>">
<!ENTITY bom "<acronym condition='Byte Order Mark'>BOM</acronym>">
<!ENTITY be "<acronym condition='Big Endian'>BE</acronym>">
<!ENTITY le "<acronym condition='Little Endian'>LE</acronym>">
<!ENTITY detect "<function>detect</function>">
<!ENTITY zero "<constant>0</constant>">
<!ENTITY one "<constant>1</constant>">
<!ENTITY universaldetector_classname "<classname>UniversalDetector</classname>">
<!ENTITY esccharsetprober_classname "<classname>EscCharSetProber</classname>">
<!ENTITY mbcsgroupprober_classname "<classname>MBCSGroupProber</classname>">
<!ENTITY multibytecharsetprober_classname "<classname>MultiByteCharSetProber</classname>">
<!ENTITY sjisprober_classname "<classname>SJISProber</classname>">
<!ENTITY sjiscontextanalysis_classname "<classname>SJISContextAnalysis</classname>">
<!ENTITY eucjpcontextanalysis_classname "<classname>EUCJPContextAnalysis</classname>">
<!ENTITY japanesecontextanalysis_classname "<classname>JapaneseContextAnalysis</classname>">
<!ENTITY sbcsgroupprober_classname "<classname>SBCSGroupProber</classname>">
<!ENTITY singlebytecharsetprober_classname "<classname>SingleByteCharSetProber</classname>">
<!ENTITY hebrewprober_classname "<classname>HebrewProber</classname>">
<!ENTITY latin1prober_classname "<classname>Latin1Prober</classname>">
<!ENTITY big5freq_py "<filename>big5freq.py</filename>">
<!ENTITY langcyrillicmodel_py "<filename>langcyrillicmodel.py</filename>">
<!ENTITY universaldetector_py "<filename>universaldetector.py</filename>">
<!ENTITY escprober_py "<filename>escprober.py</filename>">
<!ENTITY escsm_py "<filename>escsm.py</filename>">
<!ENTITY mbcsgroupprober_py "<filename>mbcsgroupprober.py</filename>">
<!ENTITY mbcharsetprober_py "<filename>mbcharsetprober.py</filename>">
<!ENTITY chardistribution_py "<filename>chardistribution.py</filename>">
<!ENTITY sjisprober_py "<filename>sjisprober.py</filename>">
<!ENTITY jpcntx_py "<filename>jpcntx.py</filename>">
<!ENTITY sbcsgroupprober_py "<filename>sbcsgroupprober.py</filename>">
<!ENTITY sbcharsetprober_py "<filename>sbcharsetprober.py</filename>">
<!ENTITY hebrewprober_py "<filename>hebrewprober.py</filename>">
<!ENTITY latin1prober_py "<filename>latin1prober.py</filename>">
<!ENTITY ascii "<acronym>ASCII</acronym>">
]>

<article lang="en">
<?dbhtml filename="index.html"?>
<title>&title;</title>
<articleinfo>
<title>&title;</title>
<authorgroup>
<author>
<firstname>Mark</firstname>
<surname>Pilgrim</surname>
</author>
</authorgroup>
<copyright>
<year>2006</year>
<year>2007</year>
<year>2008</year>
<holder>Mark Pilgrim</holder>
</copyright>
<pubdate>&fileversion;</pubdate>
<abstract>
<title/>
<para>This documentation claims to describe the behavior of &chardet; &chardet_version;.  It does not claim to describe the behavior of any other version.</para>
<para>This documentation lives at <ulink url="&url_book;"/>.  If you're reading it somewhere else, you may not have the latest version.</para>
</abstract>
<keywordset>
<keyword>character</keyword>
<keyword>set</keyword>
<keyword>encoding</keyword>
<keyword>detection</keyword>
<keyword>Python</keyword>
<keyword>XML</keyword>
<keyword>feed</keyword>
</keywordset>
<legalnotice>
<para>This documentation is provided by the author <quote>as is</quote> without any express or implied warranties.  See <xref linkend="license"/> for more details.</para>
</legalnotice>
</articleinfo>

<section id="faq">
<title>Frequently asked questions</title>
<?dbhtml filename="faq.html"?>
<section id="faq.intro">
<title>What is character encoding?</title>
<para>When you think of <quote>text</quote>, you probably think of <quote>characters and symbols I see on my computer screen</quote>.  But computers don't deal in characters and symbols; they deal in bits and bytes.  Every piece of text you've ever seen on a computer screen is actually stored in a particular <emphasis>character encoding</emphasis>.  There are many different character encodings, some optimized for particular languages like Russian or Chinese or English, and others that can be used for multiple languages.  Very roughly speaking, the character encoding provides a mapping between the stuff you see on your screen and the stuff your computer actually stores in memory and on disk.</para>
<para>In reality, it's more complicated than that.  Many characters are common to multiple encodings, but each encoding may use a different sequence of bytes to actually store those characters in memory or on disk.  So you can think of the character encoding as a kind of decryption key for the text.  Whenever someone gives you a sequence of bytes and claims it's <quote>text</quote>, you need to know what character encoding they used so you can decode the bytes into characters and display them (or process them, or whatever).</para>
</section>
<section id="faq.what">
<title>What is character encoding auto-detection?</title>
<para>It means taking a sequence of bytes in an unknown character encoding, and attempting to determine the encoding so you can read the text.  It's like cracking a code when you don't have the decryption key.</para>
</section>
<section id="faq.impossible">
<title>Isn't that impossible?</title>
<para>In general, yes.  However, some encodings are optimized for specific languages, and languages are not random.  Some character sequences pop up all the time, while other sequences make no sense.  A person fluent in English who opens a newspaper and finds <quote>txzqJv 2!dasd0a QqdKjvz</quote> will instantly recognize that that isn't English (even though it is composed entirely of English letters).  By studying lots of <quote>typical</quote> text, a computer algorithm can simulate this kind of fluency and make an educated guess about a text's language.</para>
<para>In other words, encoding detection is really language detection, combined with knowledge of which languages tend to use which character encodings.</para>
</section>
<section id="faq.who">
<title>Who wrote this detection algorithm?</title>
<para>This library is a port of <ulink url="http://lxr.mozilla.org/seamonkey/source/extensions/universalchardet/src/base/">the auto-detection code in Mozilla</ulink>.  I have attempted to maintain as much of the original structure as possible (mostly for selfish reasons, to make it easier to maintain the port as the original code evolves).  I have also retained the original authors' comments, which are quite extensive and informative.</para>
<para>You may also be interested in the research paper which led to the Mozilla implementation, &researchpaper;.</para>
</section>
<section id="faq.yippie">
<title>Yippie!  Screw the standards, I'll just auto-detect everything!</title>
<para>Don't do that.  Virtually every format and protocol contains a method for specifying character encoding.</para>
<itemizedlist>
<listitem><para>HTTP can define a <literal>charset</literal> parameter in the <literal>Content-type</literal> header.</para></listitem>
<listitem><para>HTML documents can define a <literal>&lt;meta http-equiv="content-type"&gt;</literal> element in the <literal>&lt;head&gt;</literal> of a web page.</para></listitem>
<listitem><para>XML documents can define an <literal>encoding</literal> attribute in the XML prolog.</para></listitem>
</itemizedlist>
<para>If text comes with explicit character encoding information, you should use it.  If the text has no explicit information, but the relevant standard defines a default encoding, you should use that.  (This is harder than it sounds, because standards can overlap.  If you fetch an XML document over HTTP, you need to support both standards <emphasis>and</emphasis> figure out which one wins if they give you conflicting information.)</para>
<para>Despite the complexity, it's worthwhile to follow standards and <ulink url="http://www.w3.org/2001/tag/doc/mime-respect">respect explicit character encoding information</ulink>.  It will almost certainly be faster and more accurate than trying to auto-detect the encoding.  It will also make the world a better place, since your program will interoperate with other programs that follow the same standards.</para>
</section>
<section id="faq.why">
<title>Why bother with auto-detection if it's slow, inaccurate, and non-standard?</title>
<para>Sometimes you receive text with verifiably inaccurate encoding information.  Or text without any encoding information, and the specified default encoding doesn't work.  There are also some poorly designed standards that have no way to specify encoding at all.</para>
<para>If following the relevant standards gets you nowhere, <emphasis>and</emphasis> you decide that processing the text is more important than maintaining interoperability, then you can try to auto-detect the character encoding as a last resort.  An example is my <ulink url="http://feedparser.org/">Universal Feed Parser</ulink>, which calls this auto-detection library <ulink url="http://feedparser.org/docs/character-encoding.html">only after exhausting all other options</ulink>.</para>
</section>
</section>

<section id="encodings">
<?dbhtml filename="supported-encodings.html"?>
<sectioninfo>
<abstract>
<title/>
<para>&chardet; currently supports over two dozen character encodings.</para>
</abstract>
</sectioninfo>
<title>Supported encodings</title>
<itemizedlist>
<listitem><para><literal>Big5</literal>, <literal>GB2312</literal>/<literal>GB18030</literal>, <literal>EUC-TW</literal>, <literal>HZ-GB-2312</literal>, and <literal>ISO-2022-CN</literal> (Traditional and Simplified Chinese)</para></listitem>
<listitem><para><literal>EUC-JP</literal>, <literal>SHIFT_JIS</literal>, and <literal>ISO-2022-JP</literal> (Japanese)</para></listitem>
<listitem><para><literal>EUC-KR</literal> and <literal>ISO-2022-KR</literal> (Korean)</para></listitem>
<listitem><para><literal>KOI8-R</literal>, <literal>MacCyrillic</literal>, <literal>IBM855</literal>, <literal>IBM866</literal>, <literal>ISO-8859-5</literal>, and <literal>windows-1251</literal> (Russian)</para></listitem>
<listitem><para><literal>ISO-8859-2</literal> and <literal>windows-1250</literal> (Hungarian)</para></listitem>
<listitem><para><literal>ISO-8859-5</literal> and <literal>windows-1251</literal> (Bulgarian)</para></listitem>
<listitem><para><literal>windows-1252</literal></para></listitem>
<listitem><para><literal>ISO-8859-7</literal> and <literal>windows-1253</literal> (Greek)</para></listitem>
<listitem><para><literal>ISO-8859-8</literal> and <literal>windows-1255</literal> (Visual and Logical Hebrew)</para></listitem>
<listitem><para><literal>TIS-620</literal> (Thai)</para></listitem>
<listitem><para><literal>UTF-32</literal> &be;, &le;, 3412-ordered, or 2143-ordered (with a &bom;)</para></listitem>
<listitem><para><literal>UTF-16</literal> &be; or &le; (with a &bom;)</para></listitem>
<listitem><para><literal>UTF-8</literal> (with or without a &bom;)</para></listitem>
<listitem><para>&ascii;</para></listitem>
</itemizedlist>
<caution>
<title/>
<para>Due to inherent similarities between certain encodings, some encodings may be detected incorrectly.  In my tests, the most problematic case was Hungarian text encoded as <literal>ISO-8859-2</literal> or <literal>windows-1250</literal> (encoded as one but reported as the other).  Also, Greek text encoded as <literal>ISO-8859-7</literal> was often mis-reported as <literal>ISO-8859-2</literal>.  Your mileage may vary.</para>
</caution>
</section>

<section id="usage">
<?dbhtml filename="usage.html"?>
<title>Usage</title>
<section id="usage.basic">
<title>Basic usage</title>
<para>The easiest way to use the &chardet; library is with the &detect; function.</para>
<example id="example.basic.detect">
<title>Using the &detect; function</title>
<para>The &detect; function takes one argument, a non-Unicode string.  It returns a dictionary containing the auto-detected character encoding and a confidence level from &zero; to &one;.</para>
<screen>&prompt;<userinput>import urllib</userinput>
&prompt;<userinput>rawdata = urllib.urlopen('http://yahoo.co.jp/').read()</userinput>
&prompt;<userinput>import chardet</userinput>
&prompt;<userinput>chardet.detect(rawdata)</userinput>
<computeroutput>{'encoding': 'EUC-JP', 'confidence': 0.99}</computeroutput></screen>
</example>
</section>
<section id="usage.advanced">
<title>Advanced usage</title>
<para>If you're dealing with a large amount of text, you can call the &chardet; library incrementally, and it will stop as soon as it is confident enough to report its results.</para>
<para>Create a &universaldetector_classname; object, then call its <methodname>feed</methodname> method repeatedly with each block of text.  If the detector reaches a minimum threshold of confidence, it will set <varname>detector.done</varname> to <constant>True</constant>.</para>
<para>Once you've exhausted the source text, call <methodname>detector.close()</methodname>, which will do some final calculations in case the detector didn't hit its minimum confidence threshold earlier.  Then <varname>detector.result</varname> will be a dictionary containing the auto-detected character encoding and confidence level (the same as <link linkend="example.basic.detect">the <function>chardet.detect</function> function returns</link>).</para>
<example id="example.multiline">
<title>Detecting encoding incrementally</title>
<programlisting language="python"><![CDATA[import urllib
from chardet.universaldetector import UniversalDetector

usock = urllib.urlopen('http://yahoo.co.jp/')
detector = UniversalDetector()
for line in usock.readlines():
    detector.feed(line)
    if detector.done: break
detector.close()
usock.close()
print detector.result]]></programlisting>
<screen><computeroutput>{'encoding': 'EUC-JP', 'confidence': 0.99}</computeroutput></screen>
</example>
<para>If you want to detect the encoding of multiple texts (such as separate files), you can re-use a single &universaldetector_classname; object.  Just call <methodname>detector.reset()</methodname> at the start of each file, call <methodname>detector.feed</methodname> as many times as you like, and then call <methodname>detector.close()</methodname> and check the <varname>detector.result</varname> dictionary for the file's results.</para>
<example id="advanced.multifile.multiline">
<title>Detecting encodings of multiple files</title>
<programlisting language="python"><![CDATA[import glob
from charset.universaldetector import UniversalDetector

detector = UniversalDetector()
for filename in glob.glob('*.xml'):
    print filename.ljust(60),
    detector.reset()
    for line in file(filename, 'rb'):
        detector.feed(line)
        if detector.done: break
    detector.close()
    print detector.result
]]></programlisting>
</example>
</section>
</section>

<section id="howitworks">
<?dbhtml filename="how-it-works.html"?>
<sectioninfo>
<abstract>
<title/>
<para>This is a brief guide to navigating the code itself.</para>
</abstract>
</sectioninfo>
<title>How it works</title>
<para>First, you should read &researchpaper;, which explains the detection algorithm and how it was derived.  This will help you later when you stumble across the huge character frequency distribution tables like &big5freq_py; and language models like &langcyrillicmodel_py;.</para>
<para>The main entry point for the detection algorithm is &universaldetector_py;, which has one class, &universaldetector_classname;.  (You might think the main entry point is the &detect; function in <filename>chardet/__init__.py</filename>, but that's really just a convenience function that creates a &universaldetector_classname; object, calls it, and returns its result.)</para>
<para>There are 5 categories of encodings that &universaldetector_classname; handles:</para>
<orderedlist>
<listitem><para><literal>UTF-n</literal> with a &bom;.  This includes <literal>UTF-8</literal>, both &be; and &le; variants of <literal>UTF-16</literal>, and all 4 byte-order variants of <literal>UTF-32</literal>.</para></listitem>
<listitem><para>Escaped encodings, which are entirely 7-bit &ascii; compatible, where non-&ascii; characters start with an escape sequence.  Examples: <literal>ISO-2022-JP</literal> (Japanese) and <literal>HZ-GB-2312</literal> (Chinese).</para></listitem>
<listitem><para>Multi-byte encodings, where each character is represented by a variable number of bytes.  Examples: <literal>Big5</literal> (Chinese), <literal>SHIFT_JIS</literal> (Japanese), <literal>EUC-KR</literal> (Korean), and <literal>UTF-8</literal> without a &bom;.</para></listitem>
<listitem><para>Single-byte encodings, where each character is represented by one byte.  Examples: <literal>KOI8-R</literal> (Russian), <literal>windows-1255</literal> (Hebrew), and <literal>TIS-620</literal> (Thai).</para></listitem>
<listitem><para><literal>windows-1252</literal>, which is used primarily on Microsoft Windows by middle managers who don't know a character encoding from a hole in the ground.</para></listitem>
</orderedlist>
<section id="how.bom">
<title><literal>UTF-n</literal> with a &bom;</title>
<para>If the text starts with a &bom;, we can reasonably assume that the text is encoded in <literal>UTF-8</literal>, <literal>UTF-16</literal>, or <literal>UTF-32</literal>.  (The &bom; will tell us exactly which one; that's what it's for.)  This is handled inline in &universaldetector_classname;, which returns the result immediately without any further processing.</para>
</section>
<section id="how.esc">
<title>Escaped encodings</title>
<para>If the text contains a recognizable escape sequence that might indicate an escaped encoding, &universaldetector_classname; creates an &esccharsetprober_classname; (defined in &escprober_py;) and feeds it the text.</para>
<para>&esccharsetprober_classname; creates a series of state machines, based on models of <literal>HZ-GB-2312</literal>, <literal>ISO-2022-CN</literal>, <literal>ISO-2022-JP</literal>, and <literal>ISO-2022-KR</literal> (defined in &escsm_py;).  &esccharsetprober_classname; feeds the text to each of these state machines, one byte at a time.  If any state machine ends up uniquely identifying the encoding, &esccharsetprober_classname; immediately returns the positive result to &universaldetector_classname;, which returns it to the caller.  If any state machine hits an illegal sequence, it is dropped and processing continues with the other state machines.</para>
</section>
<section id="how.mb">
<title>Multi-byte encodings</title>
<para>Assuming no &bom;, &universaldetector_classname; checks whether the text contains any high-bit characters.  If so, it creates a series of <quote>probers</quote> for detecting multi-byte encodings, single-byte encodings, and as a last resort, <literal>windows-1252</literal>.</para>
<para>The multi-byte encoding prober, &mbcsgroupprober_classname; (defined in &mbcsgroupprober_py;), is really just a shell that manages a group of other probers, one for each multi-byte encoding: <literal>Big5</literal>, <literal>GB2312</literal>, <literal>EUC-TW</literal>, <literal>EUC-KR</literal>, <literal>EUC-JP</literal>, <literal>SHIFT_JIS</literal>, and <literal>UTF-8</literal>.  &mbcsgroupprober_classname; feeds the text to each of these encoding-specific probers and checks the results.  If a prober reports that it has found an illegal byte sequence, it is dropped from further processing (so that, for instance, any subsequent calls to &universaldetector_classname;.<methodname>feed</methodname> will skip that prober).  If a prober reports that it is reasonably confident that it has detected the encoding, &mbcsgroupprober_classname; reports this positive result to &universaldetector_classname;, which reports the result to the caller.</para>
<para>Most of the multi-byte encoding probers are inherited from &multibytecharsetprober_classname; (defined in &mbcharsetprober_py;), and simply hook up the appropriate state machine and distribution analyzer and let &multibytecharsetprober_classname; do the rest of the work.  &multibytecharsetprober_classname; runs the text through the encoding-specific state machine, one byte at a time, to look for byte sequences that would indicate a conclusive positive or negative result.  At the same time, &multibytecharsetprober_classname; feeds the text to an encoding-specific distribution analyzer.</para>
<para>The distribution analyzers (each defined in &chardistribution_py;) use language-specific models of which characters are used most frequently.  Once &multibytecharsetprober_classname; has fed enough text to the distribution analyzer, it calculates a confidence rating based on the number of frequently-used characters, the total number of characters, and a language-specific distribution ratio.  If the confidence is high enough, &multibytecharsetprober_classname; returns the result to &mbcsgroupprober_classname;, which returns it to &universaldetector_classname;, which returns it to the caller.</para>
<para>The case of Japanese is more difficult.  Single-character distribution analysis is not always sufficient to distinguish between <literal>EUC-JP</literal> and <literal>SHIFT_JIS</literal>, so the &sjisprober_classname; (defined in &sjisprober_py;) also uses 2-character distribution analysis.  &sjiscontextanalysis_classname; and &eucjpcontextanalysis_classname; (both defined in &jpcntx_py; and both inheriting from a common &japanesecontextanalysis_classname; class) check the frequency of Hiragana syllabary characters within the text.  Once enough text has been processed, they return a confidence level to &sjisprober_classname;, which checks both analyzers and returns the higher confidence level to &mbcsgroupprober_classname;.</para>
</section>
<section id="how.sb">
<title>Single-byte encodings</title>
<para>The single-byte encoding prober, &sbcsgroupprober_classname; (defined in &sbcsgroupprober_py;), is also just a shell that manages a group of other probers, one for each combination of single-byte encoding and language: <literal>windows-1251</literal>, <literal>KOI8-R</literal>, <literal>ISO-8859-5</literal>, <literal>MacCyrillic</literal>, <literal>IBM855</literal>, and <literal>IBM866</literal> (Russian); <literal>ISO-8859-7</literal> and <literal>windows-1253</literal> (Greek); <literal>ISO-8859-5</literal> and <literal>windows-1251</literal> (Bulgarian); <literal>ISO-8859-2</literal> and <literal>windows-1250</literal> (Hungarian); <literal>TIS-620</literal> (Thai); <literal>windows-1255</literal> and <literal>ISO-8859-8</literal> (Hebrew).</para>
<para>&sbcsgroupprober_classname; feeds the text to each of these encoding+language-specific probers and checks the results.  These probers are all implemented as a single class, &singlebytecharsetprober_classname; (defined in &sbcharsetprober_py;), which takes a language model as an argument.  The language model defines how frequently different 2-character sequences appear in typical text.  &singlebytecharsetprober_classname; processes the text and tallies the most frequently used 2-character sequences.  Once enough text has been processed, it calculates a confidence level based on the number of frequently-used sequences, the total number of characters, and a language-specific distribution ratio.</para>
<para>Hebrew is handled as a special case.  If the text appears to be Hebrew based on 2-character distribution analysis, &hebrewprober_classname; (defined in &hebrewprober_py;) tries to distinguish between Visual Hebrew (where the source text actually stored <quote>backwards</quote> line-by-line, and then displayed verbatim so it can be read from right to left) and Logical Hebrew (where the source text is stored in reading order and then rendered right-to-left by the client).  Because certain characters are encoded differently based on whether they appear in the middle of or at the end of a word, we can make a reasonable guess about direction of the source text, and return the appropriate encoding (<literal>windows-1255</literal> for Logical Hebrew, or <literal>ISO-8859-8</literal> for Visual Hebrew).</para>
</section>
<section id="how.windows1252">
<title>windows-1252</title>
<para>If &universaldetector_classname; detects a high-bit character in the text, but none of the other multi-byte or single-byte encoding probers return a confident result, it creates a &latin1prober_classname; (defined in &latin1prober_py;) to try to detect English text in a <literal>windows-1252</literal> encoding.  This detection is inherently unreliable, because English letters are encoded in the same way in many different encodings.  The only way to distinguish <literal>windows-1252</literal> is through commonly used symbols like smart quotes, curly apostrophes, copyright symbols, and the like.  &latin1prober_classname; automatically reduces its confidence rating to allow more accurate probers to win if at all possible.</para>
</section>
</section>

<section id="history">
<?dbhtml filename="history.html"?>
<sectioninfo>
<abstract>
<title/>
<para>&chardet; is currently at version &chardet_version;.</para>
</abstract>
</sectioninfo>
<title>Revision history</title>
<variablelist>
<varlistentry>
<term><constant>1.0.1</constant> (2008-03-05)</term>
<listitem>
<itemizedlist>
<listitem><para>fixed typo in detecting little endian UTF-16; closes <ulink url="http://code.google.com/p/feedparser/issues/detail?id=81">issue 81</ulink></para></listitem>
<listitem><para>fixed length of <constant>ISO2022JPCharLenTable</constant>; closes <ulink url="http://code.google.com/p/feedparser/issues/detail?id=98">issue 98</ulink></para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>1.0</constant> (2006-01-10)</term>
<listitem>
<itemizedlist>
<listitem><para>Initial release</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
</section>

&license;

</article>
