Symbian3/PDK/Source/GUID-A8130D83-E684-5B6C-BDFE-EB6EE3CD49E8.dita
changeset 5 f345bda72bc4
parent 3 46218c8b8afa
child 14 578be2adaf3e
equal deleted inserted replaced
4:4816d766a08a 5:f345bda72bc4
     1 <?xml version="1.0" encoding="utf-8"?>
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!--Arbortext, Inc., 1988-2004, v.4002-->
       
     3 <!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN"
       
     4  "concept.dtd">
       
     5 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
     6 <!-- This component and the accompanying materials are made available under the terms of the License 
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
     7 "Eclipse Public License v1.0" which accompanies this distribution, 
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
     8 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
     9 <!-- Initial Contributors:
     6 <!-- Initial Contributors:
    10     Nokia Corporation - initial contribution.
     7     Nokia Corporation - initial contribution.
    11 Contributors: 
     8 Contributors: 
    12 -->
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
    13 <concept id="GUID-A8130D83-E684-5B6C-BDFE-EB6EE3CD49E8" xml:lang="en"><title>Writing
    12 <concept id="GUID-A8130D83-E684-5B6C-BDFE-EB6EE3CD49E8" xml:lang="en"><title>Writing
    14 a UPS Dialog Creator</title>
    13 a UPS Dialog Creator</title><prolog><metadata><keywords/></metadata></prolog><conbody>
    15 <prolog>
    14 <section id="GUID-9383005F-53E7-465E-A10E-8A781EDB52E2"><title>Introduction</title> <p>Dialog
    16 <metadata>
    15 creators are ECom plug-ins that device creators can write to generate the
    17 <keywords></keywords>
    16 dialogs containing prompts for phone users. </p> <p>The plug-in has an API
    18 </metadata>
    17 that consists of two asynchronous functions: </p> <ul>
    19 </prolog>
       
    20 <conbody>
       
    21 <section><title>Introduction</title> <p>Dialog creators are EComplug-ins that
       
    22 device creators can write to generate the dialogs containing prompts for phone
       
    23 users. </p> <p>The plug-in has an API that consists of two asynchronous functions: </p> <ul>
       
    24 <li id="GUID-96CBCE79-4F5D-5F87-AC6B-C366346447AB"><p>The <codeph>PrepareDialog()</codeph> function.
    18 <li id="GUID-96CBCE79-4F5D-5F87-AC6B-C366346447AB"><p>The <codeph>PrepareDialog()</codeph> function.
    25 This function is called first by the UPS server. It enables the dialog creator
    19 This function is called first by the UPS server. It enables the dialog creator
    26 to query other system servers such as AppArc or the SIS registry to retrieve
    20 to query other system servers such as AppArc or the SIS registry to retrieve
    27 additional information to display in the dialog. For example it might query
    21 additional information to display in the dialog. For example it might query
    28 the SIS registry using the client application’s secure id. </p> </li>
    22 the SIS registry using the client application’s secure id. </p> </li>
    32 the option selected by the user and, if applicable, the fingerprint for a
    26 the option selected by the user and, if applicable, the fingerprint for a
    33 new decision record. </p> </li>
    27 new decision record. </p> </li>
    34 </ul> <p>The UPS displays only one prompt at a time so it is possible for
    28 </ul> <p>The UPS displays only one prompt at a time so it is possible for
    35 there to be a delay between calling the function to prepare the dialog and
    29 there to be a delay between calling the function to prepare the dialog and
    36 the function to display the dialog. It is also possible for other dialogs
    30 the function to display the dialog. It is also possible for other dialogs
    37 to be displayed between the dialog being prepared and its being displayed. </p> <p>Both <codeph>PrepareDialog()</codeph> and <codeph>DisplayDialog()</codeph
    31 to be displayed between the dialog being prepared and its being displayed. </p> <p>Both <codeph>PrepareDialog()</codeph> and <codeph>DisplayDialog()</codeph> are asynchronous and must support cancellation through <codeph>CActive::Cancel</codeph>.
    38 > are asynchronous and must support cancellation through <codeph>CActive::Cancel</codeph>.
       
    39 If either function is cancelled, the dialog creator instance is destroyed
    32 If either function is cancelled, the dialog creator instance is destroyed
    40 without calling further methods. </p> <p>The work split between <codeph>PrepareDialog()</codeph> and <codeph>DisplayDialog()</codeph> described
    33 without calling further methods. </p> <p>The work split between <codeph>PrepareDialog()</codeph> and <codeph>DisplayDialog()</codeph> described
    41 above is a recommendation, and some of the functionality could be implemented
    34 above is a recommendation, and some of the functionality could be implemented
    42 directly in the notifier implementation. </p> <p>In the example given in this
    35 directly in the notifier implementation. </p> <p>In the example given in this
    43 document, the functionality for dialogs is implemented separately from the
    36 document, the functionality for dialogs is implemented separately from the
    44 functionality for policy evaluators. This allows multiple policy evaluators
    37 functionality for policy evaluators. This allows multiple policy evaluators
    45 to share common UI code. However, it is possible to deliver policy evaluator
    38 to share common UI code. However, it is possible to deliver policy evaluator
    46 and dialog creator plug-ins in the same DLL. </p> </section>
    39 and dialog creator plug-ins in the same DLL. </p> </section>
    47 <section><title>Procedure</title> <p>Dialog creators implement the <codeph>CDialogCreator</codeph> interface.
    40 <section id="GUID-38974132-906B-45C9-8C38-0C9D0F396D15"><title>Procedure</title> <p>Dialog
    48 This section shows how to implement the functions that prepare and display
    41 creators implement the <codeph>CDialogCreator</codeph> interface. This section
    49 the user prompt. </p> <ol id="GUID-0F29F8B7-F303-5D42-BB95-A32B1FE13A9A">
    42 shows how to implement the functions that prepare and display the user prompt. </p> <ol id="GUID-0F29F8B7-F303-5D42-BB95-A32B1FE13A9A">
    50 <li id="GUID-9FDDAD1F-4B9A-516A-8A00-0C331F38C4CA"><p>Prepare a dialog using
    43 <li id="GUID-9FDDAD1F-4B9A-516A-8A00-0C331F38C4CA"><p>Prepare a dialog using
    51 the <xref href="GUID-2308E2F4-A878-3B0A-951B-EFC4908AD9BB.dita"><apiname>PrepareDialog()</apiname></xref> function. </p> </li>
    44 the <xref href="GUID-2308E2F4-A878-3B0A-951B-EFC4908AD9BB.dita"><apiname>PrepareDialog()</apiname></xref> function. </p> </li>
    52 <li id="GUID-45C16A52-A05E-545A-AB3A-967CCA35BB15"><p>Display the dialog using
    45 <li id="GUID-45C16A52-A05E-545A-AB3A-967CCA35BB15"><p>Display the dialog using
    53 the <xref href="GUID-E6C3B0F0-43A7-3656-946B-5CFE97DCFC80.dita"><apiname>DisplayDialog()</apiname></xref> function. </p> </li>
    46 the <xref href="GUID-E6C3B0F0-43A7-3656-946B-5CFE97DCFC80.dita"><apiname>DisplayDialog()</apiname></xref> function. </p> </li>
    54 </ol> <p>The Dialog Creator plug-in creates a dialog prompt in cases where
    47 </ol> <p>The Dialog Creator plug-in creates a dialog prompt in cases where
    55 no previous decision is found in the decision database. </p> <p><b> Preparing
    48 no previous decision is found in the decision database. </p> <p><b> Preparing
    56 the dialog</b> </p> <p>The parameters to <codeph>PrepareDialog()</codeph> are
    49 the dialog</b> </p> <p>The parameters to <codeph>PrepareDialog()</codeph> are
    57 mostly <codeph>const</codeph> pointers and references to the data that has
    50 mostly <codeph>const</codeph> pointers and references to the data that has
    58 already been generated by the UPS or policy evaluator. </p> <p>The following
    51 already been generated by the UPS or policy evaluator. </p> <p>The following
    59 table describes the parameters for the <codeph>PrepareDialog()</codeph> function: </p> <table
    52 table describes the parameters for the <codeph>PrepareDialog()</codeph> function: </p> <table id="GUID-6D139216-B6A8-55A1-8D9B-C15134198198">
    60 id="GUID-6D139216-B6A8-55A1-8D9B-C15134198198">
       
    61 <tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
    53 <tgroup cols="2"><colspec colname="col0"/><colspec colname="col1"/>
    62 <thead>
    54 <thead>
    63 <row>
    55 <row>
    64 <entry>Parameter</entry>
    56 <entry>Parameter</entry>
    65 <entry>Description</entry>
    57 <entry>Description</entry>
    96 <entry><p>The request status used to contain completion information for the
    88 <entry><p>The request status used to contain completion information for the
    97 function. </p> </entry>
    89 function. </p> </entry>
    98 </row>
    90 </row>
    99 </tbody>
    91 </tbody>
   100 </tgroup>
    92 </tgroup>
   101 </table> <p><note></note> The UPS does not allow any responses to be returned
    93 </table> <p><note/> The UPS does not allow any responses to be returned
   102 to the system server except those defined in the UPS policy file. If the dialog
    94 to the system server except those defined in the UPS policy file. If the dialog
   103 creator returns an option that was not specified in the policy, the request
    95 creator returns an option that was not specified in the policy, the request
   104 is rejected and <codeph>EUpsDecNo</codeph> is returned. </p><p>Your implementation
    96 is rejected and <codeph>EUpsDecNo</codeph> is returned. </p><p>Your implementation
   105 can assume that the pointers remain valid until after <codeph>DisplayDialog()</codeph> has
    97 can assume that the pointers remain valid until after <codeph>DisplayDialog()</codeph> has
   106 been called. </p><p>The <codeph>PrepareDialog()</codeph> function sets values. </p><p>The<codeph> DoPrepareDialogL()</codeph> function
    98 been called. </p><p>The <codeph>PrepareDialog()</codeph> function sets values. </p><p>The<codeph> DoPrepareDialogL()</codeph> function
   124 </ul> <p>In the example at the end of this section, the <codeph>DisplayDialog()</codeph> function
   116 </ul> <p>In the example at the end of this section, the <codeph>DisplayDialog()</codeph> function
   125 sets values. The <codeph>DoDisplayDialogL()</codeph> function calls the notifier
   117 sets values. The <codeph>DoDisplayDialogL()</codeph> function calls the notifier
   126 framework to display the dialogs. The <codeph>DoDisplayDialogL()</codeph> function
   118 framework to display the dialogs. The <codeph>DoDisplayDialogL()</codeph> function
   127 is called through a <codeph>switch</codeph> statement, which can be seen in
   119 is called through a <codeph>switch</codeph> statement, which can be seen in
   128 the full code sample at the end of this section: </p> </section>
   120 the full code sample at the end of this section: </p> </section>
   129 <section><title>Example</title> <p>The following code shows an example of
   121 <section id="GUID-9C1BBD11-028A-4853-98FC-BF4B881BE2AF"><title>Example</title> <p>The
   130 a full implementation of the dialog creator file: </p> <codeblock id="GUID-314673F2-BBA0-56C0-A76D-07862BB4592F"
   122 following code shows an example of a full implementation of the dialog creator
   131 xml:space="preserve">#<?Pub Caret1?>include "refdialogcreator.h"
   123 file: </p> <codeblock id="GUID-314673F2-BBA0-56C0-A76D-07862BB4592F" xml:space="preserve">#include "refdialogcreator.h"
   132 #include &lt;ecom/implementationproxy.h>
   124 #include &lt;ecom/implementationproxy.h&gt;
   133 #include &lt;apaid.h>
   125 #include &lt;apaid.h&gt;
   134 #include &lt;apgcli.h>
   126 #include &lt;apgcli.h&gt;
   135 #include &lt;ups/promptrequest.h>
   127 #include &lt;ups/promptrequest.h&gt;
   136 #include &lt;swi/sisregistrypackage.h>
   128 #include &lt;swi/sisregistrypackage.h&gt;
   137 #include &lt;swi/sisregistrysession.h>
   129 #include &lt;swi/sisregistrysession.h&gt;
   138 #include &lt;scs/nullstream.h>
   130 #include &lt;scs/nullstream.h&gt;
   139 #include &lt;s32mem.h>
   131 #include &lt;s32mem.h&gt;
   140 
   132 
   141 static const TUint KRefDialogCreatorImplementationId = 0x10283694;
   133 static const TUint KRefDialogCreatorImplementationId = 0x10283694;
   142 
   134 
   143 static const TUint KRefNotifierImplementationId = 0x1028369B;
   135 static const TUint KRefNotifierImplementationId = 0x1028369B;
   144 
   136 
   149 @return A pointer to the new reference dialog creator object.
   141 @return A pointer to the new reference dialog creator object.
   150 */
   142 */
   151     {
   143     {
   152     CRefDialogCreator* self = new (ELeave)CRefDialogCreator();
   144     CRefDialogCreator* self = new (ELeave)CRefDialogCreator();
   153     CleanupStack::PushL(self);
   145     CleanupStack::PushL(self);
   154     self->ConstructL();
   146     self-&gt;ConstructL();
   155     CleanupStack::Pop(self);
   147     CleanupStack::Pop(self);
   156     return self;
   148     return self;
   157     }
   149     }
   158 
   150 
   159 static const TImplementationProxy ImplementationTable[] = 
   151 static const TImplementationProxy ImplementationTable[] = 
   244     iPromptData = CPromptData::NewL();
   236     iPromptData = CPromptData::NewL();
   245     
   237     
   246     // Only one state at the moment but more should be
   238     // Only one state at the moment but more should be
   247     // added for long running operators e.g. querying the SIS registry
   239     // added for long running operators e.g. querying the SIS registry
   248     // or resolving the client entity.
   240     // or resolving the client entity.
   249     ResolveClientNameL(iRequest->ClientSid());
   241     ResolveClientNameL(iRequest-&gt;ClientSid());
   250     
   242     
   251     // Get the vendor name for the client process
   243     // Get the vendor name for the client process
   252     ResolveVendorNameL(iRequest->ClientVid());
   244     ResolveVendorNameL(iRequest-&gt;ClientVid());
   253     
   245     
   254     // Server / Service localized names generated in notifier plug-in. 
   246     // Server / Service localized names generated in notifier plug-in. 
   255     iPromptData->iServerSid = iRequest->ServerSid();
   247     iPromptData-&gt;iServerSid = iRequest-&gt;ServerSid();
   256     iPromptData->iServiceId = iRequest->ServiceId();
   248     iPromptData-&gt;iServiceId = iRequest-&gt;ServiceId();
   257     
   249     
   258     // Different dialog text is displayed depending on whether the client application
   250     // Different dialog text is displayed depending on whether the client application
   259     // is signed.
   251     // is signed.
   260     // N.B. Protected SID is assumed to be signed or included at ROM build.
   252     // N.B. Protected SID is assumed to be signed or included at ROM build.
   261     if (iRequest->IsClientSidProtected()) iPromptData->iFlags |= ETrustedClient;
   253     if (iRequest-&gt;IsClientSidProtected()) iPromptData-&gt;iFlags |= ETrustedClient;
   262     
   254     
   263     // Use the options specified by the policy
   255     // Use the options specified by the policy
   264     iPromptData->iOptions = iPolicy->Options();
   256     iPromptData-&gt;iOptions = iPolicy-&gt;Options();
   265     
   257     
   266     // Add the descriptions of the fingerprints. This could be used
   258     // Add the descriptions of the fingerprints. This could be used
   267     // to allow the user to grant access to all destinations 
   259     // to allow the user to grant access to all destinations 
   268     // or a single destination.
   260     // or a single destination.
   269     TInt count = iFingerprints->Count();
   261     TInt count = iFingerprints-&gt;Count();
   270     for (TInt i = 0; i &lt; count; ++i)
   262     for (TInt i = 0; i &lt; count; ++i)
   271         {
   263         {
   272         HBufC* description = (*iFingerprints)[i]->Description().AllocLC();
   264         HBufC* description = (*iFingerprints)[i]-&gt;Description().AllocLC();
   273         iPromptData->iDescriptions.AppendL(description);
   265         iPromptData-&gt;iDescriptions.AppendL(description);
   274         CleanupStack::Pop(description);
   266         CleanupStack::Pop(description);
   275         }
   267         }
   276     
   268     
   277     User::RequestComplete(iClientStatus, KErrNone);
   269     User::RequestComplete(iClientStatus, KErrNone);
   278     // DisplayDialog is invoked by the UPS, this just verifies 
   270     // DisplayDialog is invoked by the UPS, this just verifies 
   311         // The Always or Never option was selected so return the fingerprint 
   303         // The Always or Never option was selected so return the fingerprint 
   312         // for the new decision record.
   304         // for the new decision record.
   313         // 
   305         // 
   314         // In this implementation a copy of the original fingerprint is returned. However,
   306         // In this implementation a copy of the original fingerprint is returned. However,
   315         // it is permitted to return a different fingerprint e.g. a modifier description.        
   307         // it is permitted to return a different fingerprint e.g. a modifier description.        
   316         if (iPromptResult.iDestination >= 0 &amp;&amp; iPromptResult.iDestination &lt; iFingerprints->Count())        
   308         if (iPromptResult.iDestination &gt;= 0 &amp;&amp; iPromptResult.iDestination &lt; iFingerprints-&gt;Count())        
   317             {
   309             {
   318             *iFingerprint = (*iFingerprints)[iPromptResult.iDestination];
   310             *iFingerprint = (*iFingerprints)[iPromptResult.iDestination];
   319             }
   311             }
   320         else
   312         else
   321             {
   313             {
   328     }
   320     }
   329 
   321 
   330 void CRefDialogCreator::ResolveVendorNameL(const TVendorId&amp; aVid)
   322 void CRefDialogCreator::ResolveVendorNameL(const TVendorId&amp; aVid)
   331 /**
   323 /**
   332 Looks up the localized vendor name for the client process and writes
   324 Looks up the localized vendor name for the client process and writes
   333 this to iPromptData->iVendorName.
   325 this to iPromptData-&gt;iVendorName.
   334 
   326 
   335 Typically, this would be resolved from the SIS registry or a lookup table.
   327 Typically, this would be resolved from the SIS registry or a lookup table.
   336 
   328 
   337 @param aVid    The vendor id of the client process.
   329 @param aVid    The vendor id of the client process.
   338 */
   330 */
   339     {
   331     {
   340     if (iPromptData->iVendorName.Length() != 0)
   332     if (iPromptData-&gt;iVendorName.Length() != 0)
   341         {
   333         {
   342         // already obtained vendor name from SIS registry
   334         // already obtained vendor name from SIS registry
   343         return;
   335         return;
   344         }
   336         }
   345         
   337         
   346     if (aVid.iId == 0x70000001)
   338     if (aVid.iId == 0x70000001)
   347         {
   339         {
   348         _LIT(KSymbian, "Symbian Foundation");
   340         _LIT(KSymbian, "XYZ Vendor");
   349         iPromptData->iVendorName.Create(KSymbian);
   341         iPromptData-&gt;iVendorName.Create(KSymbian);
   350         }
   342         }
   351     else 
   343     else 
   352         {
   344         {
   353         _LIT(KUnknown, "Unknown vendor");
   345         _LIT(KUnknown, "Unknown vendor");
   354         iPromptData->iVendorName.Create(KUnknown);
   346         iPromptData-&gt;iVendorName.Create(KUnknown);
   355         }
   347         }
   356     }
   348     }
   357     
   349     
   358 void CRefDialogCreator::ResolveClientNameL(const TSecureId&amp; aSid)
   350 void CRefDialogCreator::ResolveClientNameL(const TSecureId&amp; aSid)
   359 /**
   351 /**
   384 
   376 
   385     // If the process has exited then it's o.k. to leave.
   377     // If the process has exited then it's o.k. to leave.
   386     if (! found)
   378     if (! found)
   387         {            
   379         {            
   388         RProcess clientProcess;
   380         RProcess clientProcess;
   389         User::LeaveIfError(clientProcess.Open(iRequest->ClientProcessId()));
   381         User::LeaveIfError(clientProcess.Open(iRequest-&gt;ClientProcessId()));
   390         CleanupClosePushL(clientProcess);
   382         CleanupClosePushL(clientProcess);
   391         iPromptData->iClientName.Create(clientProcess.FileName());        
   383         iPromptData-&gt;iClientName.Create(clientProcess.FileName());        
   392         CleanupStack::PopAndDestroy(&amp;clientProcess); 
   384         CleanupStack::PopAndDestroy(&amp;clientProcess); 
   393         }
   385         }
   394     }
   386     }
   395 
   387 
   396 TBool CRefDialogCreator::ResolveClientNameFromAppArcL(const TSecureId&amp; aSid)
   388 TBool CRefDialogCreator::ResolveClientNameFromAppArcL(const TSecureId&amp; aSid)
   412         CleanupStack::PushL(info);
   404         CleanupStack::PushL(info);
   413         
   405         
   414         err = apa.GetAppInfo(*info, TUid::Uid(aSid));
   406         err = apa.GetAppInfo(*info, TUid::Uid(aSid));
   415         if (err == KErrNone)
   407         if (err == KErrNone)
   416             {
   408             {
   417             iPromptData->iClientName.Close();
   409             iPromptData-&gt;iClientName.Close();
   418             iPromptData->iClientName.Create(info->iCaption);
   410             iPromptData-&gt;iClientName.Create(info-&gt;iCaption);
   419             found = ETrue;
   411             found = ETrue;
   420             }
   412             }
   421         else if (err != KErrNotFound)
   413         else if (err != KErrNotFound)
   422             {
   414             {
   423             User::Leave(err);
   415             User::Leave(err);
   449     
   441     
   450     Swi::CSisRegistryPackage* p(0);
   442     Swi::CSisRegistryPackage* p(0);
   451     TRAPD(err, p = r.SidToPackageL(TUid::Uid(aSid.iId)));
   443     TRAPD(err, p = r.SidToPackageL(TUid::Uid(aSid.iId)));
   452     if (err == KErrNone)
   444     if (err == KErrNone)
   453         {
   445         {
   454         iPromptData->iClientName.Create(p->Name());
   446         iPromptData-&gt;iClientName.Create(p-&gt;Name());
   455         iPromptData->iVendorName.Create(p->Vendor());
   447         iPromptData-&gt;iVendorName.Create(p-&gt;Vendor());
   456         found = ETrue;
   448         found = ETrue;
   457         delete p;
   449         delete p;
   458         }
   450         }
   459     CleanupStack::PopAndDestroy(&amp;r);
   451     CleanupStack::PopAndDestroy(&amp;r);
   460     return found;
   452     return found;
   461     }
   453     }
   462 
   454 
   463 // From CDialogCreator
   455 // From CDialogCreator
   464 void CRefDialogCreator::PrepareDialog(
   456 void CRefDialogCreator::PrepareDialog(
   465     const UserPromptService::CPromptRequest&amp; aRequest, const CPolicy&amp; aPolicy,            
   457     const UserPromptService::CPromptRequest&amp; aRequest, const CPolicy&amp; aPolicy,            
   466     const RPointerArray&lt;CFingerprint>&amp; aFingerprints, const CClientEntity* aClientEntity,
   458     const RPointerArray&lt;CFingerprint&gt;&amp; aFingerprints, const CClientEntity* aClientEntity,
   467     const TAny* aEvalPrivateData, TRequestStatus&amp; aStatus)
   459     const TAny* aEvalPrivateData, TRequestStatus&amp; aStatus)
   468     {
   460     {
   469     aStatus = KRequestPending;
   461     aStatus = KRequestPending;
   470     iClientStatus = &amp;aStatus;
   462     iClientStatus = &amp;aStatus;
   471     
   463     
   501     TRequestStatus* status = &amp;iStatus;
   493     TRequestStatus* status = &amp;iStatus;
   502     SetActive();
   494     SetActive();
   503     User::RequestComplete(status, KErrNone);
   495     User::RequestComplete(status, KErrNone);
   504     }
   496     }
   505 </codeblock> </section>
   497 </codeblock> </section>
   506 </conbody>
   498 </conbody></concept>
   507 </concept>
       
   508 <?Pub *0000019622?>