1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-25 02:32:18 -05:00

0.0.4 from Peter Waher

This commit is contained in:
Peter Saint-Andre 2013-12-20 13:49:53 -07:00
parent 8e76770666
commit 6a0001367d

View File

@ -14,15 +14,7 @@
controls with undefined values or error messages, while still being backwards compatible with the existing data form model with available controls with undefined values or error messages, while still being backwards compatible with the existing data form model with available
extensions. extensions.
</abstract> </abstract>
<legal> &LEGALNOTICE;
<copyright>This XMPP Extension Protocol is copyright (c) 1999 - 2013 by the XMPP Standards Foundation (XSF).</copyright>
<permissions>Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the &quot;Specification&quot;), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.</permissions>
<warranty>## NOTE WELL: This Specification is provided on an &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. In no event shall the XMPP Standards Foundation or the authors of this Specification be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification. ##</warranty>
<liability>In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising out of the use or inability to use the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.</liability>
<conformance>
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which may be found at &lt;<link url='http://www.xmpp.org/extensions/ipr-policy.shtml'>http://www.xmpp.org/extensions/ipr-policy.shtml</link>&gt; or obtained by writing to XSF, P.O. Box 1641, Denver, CO 80201 USA).
</conformance>
</legal>
<number>xxxx</number> <number>xxxx</number>
<status>ProtoXEP</status> <status>ProtoXEP</status>
<type>Standards Track</type> <type>Standards Track</type>
@ -34,7 +26,7 @@
</dependencies> </dependencies>
<supersedes/> <supersedes/>
<supersededby/> <supersededby/>
<shortname>NOT_YET_ASSIGNED</shortname> <shortname>dynamic-forms</shortname>
<author> <author>
<firstname>Peter</firstname> <firstname>Peter</firstname>
<surname>Waher</surname> <surname>Waher</surname>
@ -42,6 +34,24 @@
<jid>peter.waher@jabber.org</jid> <jid>peter.waher@jabber.org</jid>
<uri>http://www.linkedin.com/in/peterwaher</uri> <uri>http://www.linkedin.com/in/peterwaher</uri>
</author> </author>
<revision>
<version>0.0.4</version>
<date>2013-12-18</date>
<initials>pw</initials>
<remark>
<p>The element formPostBack has been renamed to <strong>submit</strong>.</p>
<p>The element formUpdated has been renamed to <strong>updated</strong>.</p>
<p>The elements formPostBackResponse and cancelResponse have been removed. Error handling has been updated to conform to use IQ error stanzas and error codes.</p>
</remark>
</revision>
<revision>
<version>0.0.3</version>
<date>2013-12-04</date>
<initials>pw</initials>
<remark>
<p>Namespace changed to urn:xmpp:xdata:dynamic.</p>
</remark>
</revision>
<revision> <revision>
<version>0.0.2</version> <version>0.0.2</version>
<date>2013-10-29</date> <date>2013-10-29</date>
@ -284,7 +294,7 @@
<section1 topic='Use Cases' anchor='usecases'> <section1 topic='Use Cases' anchor='usecases'>
<p> <p>
The following subsections list use cases for the different enhancements defined by this extension. Elements are defined using the namespace The following subsections list use cases for the different enhancements defined by this extension. Elements are defined using the namespace
<strong>http://jabber.org/protocol/xdata-dynamic</strong> and namespace prefix <strong>xdd</strong>. <strong>urn:xmpp:xdata:dynamic</strong> and namespace prefix <strong>xdd</strong>.
</p> </p>
<section2 topic='Publishing post-back fields'> <section2 topic='Publishing post-back fields'>
<p> <p>
@ -298,7 +308,7 @@
<example caption='Publishing post-back fields'> <example caption='Publishing post-back fields'>
<![CDATA[ <![CDATA[
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Current location</title> <title>Current location</title>
<instructions>Select your current location to continue.</instructions> <instructions>Select your current location to continue.</instructions>
@ -333,7 +343,7 @@
</section2> </section2>
<section2 topic='Performing a server post-back'> <section2 topic='Performing a server post-back'>
<p> <p>
A server post-back is performed by sending an IQ set stanza with a <strong>formPostBack</strong> child element containing the A server post-back is performed by sending an IQ set stanza with a <strong>submit</strong> child element containing the
current state of the form. The type of the form must be <strong>submit</strong>. The client should also provide the current current state of the form. The type of the form must be <strong>submit</strong>. The client should also provide the current
user language in a <strong>xml:lang</strong> attribute, if available. user language in a <strong>xml:lang</strong> attribute, if available.
</p> </p>
@ -343,7 +353,7 @@
from='formclient@clayster.com/client' from='formclient@clayster.com/client'
to='formserver@clayster.com' to='formserver@clayster.com'
id='1'> id='1'>
<formPostBack xmlns='http://jabber.org/protocol/xdata-dynamic' xml:lang='en'> <submit xmlns='urn:xmpp:xdata:dynamic' xml:lang='en'>
<x xmlns="jabber:x:data" type="submit"> <x xmlns="jabber:x:data" type="submit">
<field var='xdd session'> <field var='xdd session'>
<value>009c7956-001c-43fb-8edb-76bcf74272c9</value> <value>009c7956-001c-43fb-8edb-76bcf74272c9</value>
@ -352,7 +362,7 @@
<value>CL</value> <value>CL</value>
</field> </field>
</x> </x>
</formPostBack> </submit>
</iq>]]> </iq>]]>
</example> </example>
<p> <p>
@ -360,8 +370,7 @@
submission of the data form. submission of the data form.
</p> </p>
<p> <p>
As a response to a successful form post-back, the server returns a <strong>formPostBackResponse</strong> element with a result code of <strong>OK</strong> As a response to a successful form post-back, the server returns the new data form, as is shown in the following example:
containing a new data form, as is shown in the following example:
</p> </p>
<example caption='Post-back response'> <example caption='Post-back response'>
<![CDATA[ <![CDATA[
@ -369,9 +378,8 @@
from='formserver@clayster.com' from='formserver@clayster.com'
to='formclient@clayster.com/client' to='formclient@clayster.com/client'
id='1'> id='1'>
<formPostBackResponse xmlns='http://jabber.org/protocol/xdata-dynamic' result='OK'>
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Current location</title> <title>Current location</title>
<instructions>Select your current location to continue.</instructions> <instructions>Select your current location to continue.</instructions>
@ -415,7 +423,6 @@
... ...
</field> </field>
</x> </x>
</formPostBackResponse>
</iq>]]> </iq>]]>
</example> </example>
<p> <p>
@ -439,7 +446,7 @@
<example caption='Publishing read-only fields'> <example caption='Publishing read-only fields'>
<![CDATA[ <![CDATA[
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Object properties</title> <title>Object properties</title>
<field var='xdd session' type='hidden'> <field var='xdd session' type='hidden'>
@ -497,7 +504,7 @@
<example caption='Publishing fields with undefined values'> <example caption='Publishing fields with undefined values'>
<![CDATA[ <![CDATA[
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Communication properties</title> <title>Communication properties</title>
<field var='xdd session' type='hidden'> <field var='xdd session' type='hidden'>
@ -546,7 +553,7 @@
<example caption='Publishing fields with undefined values'> <example caption='Publishing fields with undefined values'>
<![CDATA[ <![CDATA[
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Expression</title> <title>Expression</title>
<field var='xdd session' type='hidden'> <field var='xdd session' type='hidden'>
@ -591,7 +598,7 @@
from='formclient@clayster.com/client' from='formclient@clayster.com/client'
to='formserver@clayster.com' to='formserver@clayster.com'
id='4'> id='4'>
<cancel xmlns='http://jabber.org/protocol/xdata-dynamic'> <cancel xmlns='urn:xmpp:xdata:dynamic'>
<x xmlns="jabber:x:data" type="submit"> <x xmlns="jabber:x:data" type="submit">
<field var='xdd session'> <field var='xdd session'>
<value>009c7956-001c-43fb-8edb-76bcf74272c9</value> <value>009c7956-001c-43fb-8edb-76bcf74272c9</value>
@ -602,38 +609,44 @@
</iq>]]> </iq>]]>
</example> </example>
<p> <p>
After receiving the cancel request the form server returns a cancel response having a result code of <strong>OK</strong> if the form After receiving the cancel request the form server returns an empty response if the form was found (and therefore cancelled), or an
was found (and therefore cancelled), or <strong>NotFound</strong> if the form was not found. The following example shows an OK response: IQ error stanza with an <strong>item-not-found</strong> error if the form was not found. The following example shows a response where
the form was found and cancelled:
</p> </p>
<example caption='Dynamic form cancelled'> <example caption='Dynamic form cancelled'>
<![CDATA[ <![CDATA[
<iq type='result' <iq type='result'
from='formserver@clayster.com' from='formserver@clayster.com'
to='formclient@clayster.com/client' to='formclient@clayster.com/client'
id='4'> id='4'/>]]>
<cancelResponse xmlns='http://jabber.org/protocol/xdata-dynamic' result='OK'/>
</iq>]]>
</example> </example>
<p> <p>
<strong>Note:</strong> If cancelling a dynamic form using the approach described in this document, there's no need to also submit <strong>Note:</strong> If cancelling a dynamic form using the approach described in this document, there's no need to also submit
a cancel form as defined in the <link url='http://xmpp.org/extensions/xep-0004.html'>Data Forms</link> XEP. The form server automatically a cancel form as defined in the <link url='http://xmpp.org/extensions/xep-0004.html'>Data Forms</link> XEP. The form server automatically
makes sure the form is cancelled in all instances on the form server. makes sure the form is cancelled in all instances on the form server.
</p> </p>
<p>
<strong>Note 2:</strong> If the dynamic form is invoked from a specific operation that includes its own cancel procedure, like
Ad-hoc command sessions, the dynamic form is automatically and implicitly cancelled if the corresponding operation is cancelled.
There is no need to explicitly cancel the dynamic form as explained in this section in such cases.
</p>
</section2> </section2>
<section2 topic='Dynamic form not found during post-back'> <section2 topic='Dynamic form not found during post-back'>
<p> <p>
It might happen that the form server does not find the dynamic form posted by the form client during a post back. Reasons for this can be It might happen that the form server does not find the dynamic form posted by the form client during a post back. Reasons for this can be
that the form does not include a post-back field, or that a form session timeout has occurred and the form server has discarded the dynamic that the form does not include a post-back field, or that a form session timeout has occurred and the form server has discarded the dynamic
form to avoid memory leaks. Regardless of the reason, the form server responds using a <strong>NotFound</strong> result in the response, when form to avoid memory leaks. Regardless of the reason, the form server responds using an IQ error stanza with the <strong>item-not-found</strong>
the client posts a form that is not found back. error, when the client posts a form that is not found back.
</p> </p>
<example caption='Dynamic form not found during post-back'> <example caption='Dynamic form not found during post-back'>
<![CDATA[ <![CDATA[
<iq type='result' <iq type='error'
from='formserver@clayster.com' from='formserver@clayster.com'
to='formclient@clayster.com/client' to='formclient@clayster.com/client'
id='2'> id='2'>
<formPostBackResponse xmlns='http://jabber.org/protocol/xdata-dynamic' result='NotFound'/> <error type='cancel'>
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>]]> </iq>]]>
</example> </example>
<p> <p>
@ -643,25 +656,26 @@
</section2> </section2>
<section2 topic='Other error during post-back'> <section2 topic='Other error during post-back'>
<p> <p>
If another error occurs during post-back, the form server can inform the client about this, using the <strong>OtherError</strong> If another error occurs during post-back, the form server can inform the client about this by using the relevant error element and
result code, and include an <strong>error</strong> element to describe the error, as is shown in the following example: provide further information in a <strong>text</strong> element to describe the error, as is shown in the following example:
</p> </p>
<example caption='Other error during post-back'> <example caption='Other error during post-back'>
<![CDATA[ <![CDATA[
<iq type='result' <iq type='error'
from='formserver@clayster.com' from='formserver@clayster.com'
to='formclient@clayster.com/client' to='formclient@clayster.com/client'
id='3'> id='3'>
<formPostBackResponse xmlns='http://jabber.org/protocol/xdata-dynamic' result='OtherError'> <error type='cancel'>
<error>An internal error occurred: Stack limit has been reached.</error> <internal-server-error xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
</formPostBackResponse> <text>An internal error occurred: Stack limit has been reached.</text>
</error>
</iq>]]> </iq>]]>
</example> </example>
</section2> </section2>
<section2 topic='Asynchronous updates of forms (server push)'> <section2 topic='Asynchronous updates of forms (server push)'>
<p> <p>
The server may send asynchronous updates to open forms on the client. This can be done if the server detects changes that it wants to inform The server may send asynchronous updates to open forms on the client. This can be done if the server detects changes that it wants to inform
the client about. Changes are made by sending a <strong>message</strong> stanza including a <strong>formUpdated</strong> element which in turn the client about. Changes are made by sending a <strong>message</strong> stanza including a <strong>updated</strong> element which in turn
contains the new updated form. contains the new updated form.
</p> </p>
<p> <p>
@ -675,7 +689,7 @@
</p> </p>
<p> <p>
The client may have more than one form open at any given time. It might also be so that the form has been closed prior to receiving or handling the update message, The client may have more than one form open at any given time. It might also be so that the form has been closed prior to receiving or handling the update message,
and is therefore no longer visible. To be able to identify to which form the update corresponds, the <strong>formUpdated</strong> and is therefore no longer visible. To be able to identify to which form the update corresponds, the <strong>updated</strong>
element is required to include a <strong>sessionVariable</strong> attribute in which it identifies a <strong>unique</strong> identifying element is required to include a <strong>sessionVariable</strong> attribute in which it identifies a <strong>unique</strong> identifying
field in the form. When the client receives the update, it goes through all forms it has open. If a form has a field variable with a corresponding field in the form. When the client receives the update, it goes through all forms it has open. If a form has a field variable with a corresponding
name, and the field variable has a value equal to the value in the updated form, the form should be updated by the contents of the message. If no form is found, name, and the field variable has a value equal to the value in the updated form, the form should be updated by the contents of the message. If no form is found,
@ -684,7 +698,7 @@
<example caption='Asynchronous update of form (server push)'> <example caption='Asynchronous update of form (server push)'>
<![CDATA[ <![CDATA[
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Control parameters</title> <title>Control parameters</title>
<field var='xdd session' type='hidden'> <field var='xdd session' type='hidden'>
@ -703,9 +717,9 @@
... ...
<message from='server@clayster.com' <message from='server@clayster.com'
to='client@clayster.com/client'> to='client@clayster.com/client'>
<formUpdated xmlns='http://jabber.org/protocol/xdata-dynamic' sessionVariable='xdd session'> <updated xmlns='urn:xmpp:xdata:dynamic' sessionVariable='xdd session' xml:lang='en'>
<x xmlns="jabber:x:data" type="form" <x xmlns="jabber:x:data" type="form"
xmlns:xdd="http://jabber.org/protocol/xdata-dynamic" xmlns:xdd="urn:xmpp:xdata:dynamic"
xmlns:xdv="http://jabber.org/protocol/xdata-validate"> xmlns:xdv="http://jabber.org/protocol/xdata-validate">
<title>Control parameters</title> <title>Control parameters</title>
<field var='xdd session' type='hidden'> <field var='xdd session' type='hidden'>
@ -719,18 +733,22 @@
<value>49152</value> <value>49152</value>
</field> </field>
</x> </x>
</formUpdated> </updated>
</message>]]> </message>]]>
</example> </example>
<p> <p>
<strong>Note:</strong> Make sure to check the implementation note <link url='#clientsidevalues'>Merging Client-Side Values</link> for information <strong>Note:</strong> Make sure to check the implementation note <link url='#clientsidevalues'>Merging Client-Side Values</link> for information
on how to merge updates received from the server with current input made by the client. on how to merge updates received from the server with current input made by the client.
</p> </p>
<p>
<strong>Note 2:</strong> The client should also provide the current user language in a <strong>xml:lang</strong> attribute in the <strong>updated</strong>
element, if available, as is shown in the example above.
</p>
</section2> </section2>
</section1> </section1>
<section1 topic='Determining Support' anchor='support'> <section1 topic='Determining Support' anchor='support'>
<p>If an entity supports the protocol specified herein, regardless if the entity represents a form server or a form client; it MUST advertise <p>If an entity supports the protocol specified herein, regardless if the entity represents a form server or a form client; it MUST advertise
that fact by returning a feature of "http://jabber.org/protocol/xdata-dynamic" in response to &xep0030; information requests.</p> that fact by returning a feature of "urn:xmpp:xdata:dynamic" in response to &xep0030; information requests.</p>
<example caption="Service discovery information request"> <example caption="Service discovery information request">
<![CDATA[ <![CDATA[
<iq type='get' <iq type='get'
@ -748,7 +766,7 @@
id='disco1'> id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'> <query xmlns='http://jabber.org/protocol/disco#info'>
... ...
<feature var='http://jabber.org/protocol/xdata-dynamic'/> <feature var='urn:xmpp:xdata:dynamic'/>
... ...
</query> </query>
</iq>]]> </iq>]]>
@ -780,7 +798,7 @@
The form server must be aware that some form clients do not support dynamic forms. This in turn implies that form clients The form server must be aware that some form clients do not support dynamic forms. This in turn implies that form clients
may not call the correct cancel method to cancel a dynamic form. To protect the form server from memory leaks, it must may not call the correct cancel method to cancel a dynamic form. To protect the form server from memory leaks, it must
include a session timeout, and release any dynamic form session resources if no activity has been made during the include a session timeout, and release any dynamic form session resources if no activity has been made during the
corresponding time period. If the client would perform a post-back after the timeout period, a <strong>NotFound</strong> corresponding time period. If the client would perform a post-back after the timeout period, an <strong>item-not-found</strong>
error message must be returned, to show the corresponding dynamic form session no longer exists, and therefore could error message must be returned, to show the corresponding dynamic form session no longer exists, and therefore could
not be found. not be found.
</p> </p>
@ -877,8 +895,8 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<xs:schema <xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://jabber.org/protocol/xdata-dynamic' targetNamespace='urn:xmpp:xdata:dynamic'
xmlns='http://jabber.org/protocol/xdata-dynamic' xmlns='urn:xmpp:xdata:dynamic'
xmlns:xd="jabber:x:data" xmlns:xd="jabber:x:data"
elementFormDefault='qualified'> elementFormDefault='qualified'>
@ -914,7 +932,7 @@
</xs:simpleType> </xs:simpleType>
</xs:element> </xs:element>
<xs:element name='formPostBack'> <xs:element name='submit'>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element ref='xd:x' minOccurs='1' maxOccurs='1'/> <xs:element ref='xd:x' minOccurs='1' maxOccurs='1'/>
@ -922,17 +940,7 @@
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name='formPostBackResponse'> <xs:element name='updated'>
<xs:complexType>
<xs:choice>
<xs:element ref='xd:x' minOccurs='0' maxOccurs='1'/>
<xs:element name='error' type='xs:string' minOccurs='0' maxOccurs='1'/>
</xs:choice>
<xs:attribute name='result' type='PostBackResultCode' use='required'/>
</xs:complexType>
</xs:element>
<xs:element name='formUpdated'>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element ref='xd:x' minOccurs='1' maxOccurs='1'/> <xs:element ref='xd:x' minOccurs='1' maxOccurs='1'/>
@ -941,14 +949,6 @@
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:simpleType name='PostBackResultCode'>
<xs:restriction base='xs:string'>
<xs:enumeration value='OK'/>
<xs:enumeration value='NotFound'/>
<xs:enumeration value='OtherError'/>
</xs:restriction>
</xs:simpleType>
<xs:element name='cancel'> <xs:element name='cancel'>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
@ -957,16 +957,10 @@
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name='cancelResponse'>
<xs:complexType>
<xs:attribute name='result' type='PostBackResultCode' use='required'/>
</xs:complexType>
</xs:element>
</xs:schema>]]> </xs:schema>]]>
</code> </code>
</section1> </section1>
<section1 topic='Acknowledgements' anchor='ack'> <section1 topic='Acknowledgements' anchor='ack'>
<p>Thanks to Karin Forsell for all valuable feedback.</p> <p>Thanks to Karin Forsell and Lance Stout for all valuable feedback.</p>
</section1> </section1>
</xep> </xep>