PWLib
1.10.10
|
00001 /* 00002 * httpform.h 00003 * 00004 * Forms management using HTTP User Interface. 00005 * 00006 * Portable Windows Library 00007 * 00008 * Copyright (c) 1993-2002 Equivalence Pty. Ltd. 00009 * 00010 * The contents of this file are subject to the Mozilla Public License 00011 * Version 1.0 (the "License"); you may not use this file except in 00012 * compliance with the License. You may obtain a copy of the License at 00013 * http://www.mozilla.org/MPL/ 00014 * 00015 * Software distributed under the License is distributed on an "AS IS" 00016 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 00017 * the License for the specific language governing rights and limitations 00018 * under the License. 00019 * 00020 * The Original Code is Portable Windows Library. 00021 * 00022 * The Initial Developer of the Original Code is Equivalence Pty. Ltd. 00023 * 00024 * Contributor(s): ______________________________________. 00025 * 00026 * $Log: httpform.h,v $ 00027 * Revision 1.18 2005/11/30 12:47:37 csoutheren 00028 * Removed tabs, reformatted some code, and changed tags for Doxygen 00029 * 00030 * Revision 1.17 2003/03/24 04:30:41 robertj 00031 * Added function to set and get strings from PConfig in correct format for 00032 * use with HTTP form array contsructs. 00033 * 00034 * Revision 1.16 2002/11/06 22:47:24 robertj 00035 * Fixed header comment (copyright etc) 00036 * 00037 * Revision 1.15 2002/09/16 01:08:59 robertj 00038 * Added #define so can select if #pragma interface/implementation is used on 00039 * platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan. 00040 * 00041 * Revision 1.14 2001/10/10 08:07:48 robertj 00042 * Fixed large memory leak of strings when doing POST to a form. 00043 * 00044 * Revision 1.13 2000/12/18 07:12:37 robertj 00045 * Added ability to have fixed length array fields. 00046 * 00047 * Revision 1.12 1999/03/09 08:01:46 robertj 00048 * Changed comments for doc++ support (more to come). 00049 * 00050 * Revision 1.11 1999/02/16 08:07:10 robertj 00051 * MSVC 6.0 compatibility changes. 00052 * 00053 * Revision 1.10 1998/11/30 02:50:48 robertj 00054 * New directory structure 00055 * 00056 * Revision 1.9 1998/09/23 06:19:31 robertj 00057 * Added open source copyright license. 00058 * 00059 * Revision 1.8 1998/08/20 05:45:33 robertj 00060 * Fixed bug where substitutions did not always occur if near end of macro block. 00061 * 00062 * Revision 1.7 1998/01/26 00:25:24 robertj 00063 * Major rewrite of HTTP forms management. 00064 * 00065 * Revision 1.6 1997/08/09 07:46:51 robertj 00066 * Fixed problems with value of SELECT fields in form 00067 * 00068 * Revision 1.5 1997/07/26 11:38:17 robertj 00069 * Support for overridable pages in HTTP service applications. 00070 * 00071 * Revision 1.4 1997/07/08 13:16:12 robertj 00072 * Major HTTP form enhancements for lists and arrays of fields. 00073 * 00074 * Revision 1.3 1997/06/08 04:49:40 robertj 00075 * Adding new llist based form field. 00076 * 00077 * Revision 1.2 1997/04/01 06:01:39 robertj 00078 * Allowed value list in drop down box to be modified once created. 00079 * 00080 * Revision 1.1 1996/06/28 12:55:56 robertj 00081 * Initial revision 00082 * 00083 */ 00084 00085 #ifndef _PHTTPFORM 00086 #define _PHTTPFORM 00087 00088 #ifdef P_USE_PRAGMA 00089 #pragma interface 00090 #endif 00091 00092 #include <ptclib/http.h> 00093 00094 00096 // PHTTPField 00097 00101 class PHTTPField : public PObject 00102 { 00103 PCLASSINFO(PHTTPField, PObject) 00104 public: 00105 PHTTPField( 00106 const char * bname, // base name (identifier) for the field. 00107 const char * title, // Title text for field (defaults to name). 00108 const char * help // Help text for the field. 00109 ); 00110 // Create a new field in a HTTP form. 00111 00117 virtual Comparison Compare( 00118 const PObject & obj 00119 ) const; 00120 00126 const PCaselessString & GetName() const { return fullName; } 00127 00133 const PCaselessString & GetBaseName() const { return baseName; } 00134 00137 virtual void SetName( 00138 const PString & newName // New name for field 00139 ); 00140 00146 virtual const PHTTPField * LocateName( 00147 const PString & name // Full field name to locate 00148 ) const; 00149 00155 const PString & GetTitle() const { return title; } 00156 00162 const PString & GetHelp() const { return help; } 00163 00164 void SetHelp( 00165 const PString & text // Help text. 00166 ) { help = text; } 00167 void SetHelp( 00168 const PString & hotLinkURL, // URL for link to help page. 00169 const PString & linkText // Help text in the link. 00170 ); 00171 void SetHelp( 00172 const PString & hotLinkURL, // URL for link to help page. 00173 const PString & imageURL, // URL for image to be displayed in link. 00174 const PString & imageText // Text in the link when image unavailable. 00175 ); 00176 // Set the help text for the field. 00177 00183 virtual PHTTPField * NewField() const = 0; 00184 00185 virtual void ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const; 00186 // Splice expanded macro substitutions into text string 00187 00190 virtual void GetHTMLTag( 00191 PHTML & html // HTML to receive the fields HTML tag. 00192 ) const = 0; 00193 00196 virtual PString GetHTMLInput( 00197 const PString & input // Source HTML text for input tag. 00198 ) const; 00199 00202 virtual PString GetHTMLSelect( 00203 const PString & selection // Source HTML text for input tag. 00204 ) const; 00205 00208 virtual void GetHTMLHeading( 00209 PHTML & html // HTML to receive the field info. 00210 ) const; 00211 00217 virtual PString GetValue(BOOL dflt = FALSE) const = 0; 00218 00221 virtual void SetValue( 00222 const PString & newValue // New value for the field. 00223 ) = 0; 00224 00228 virtual void LoadFromConfig( 00229 PConfig & cfg // Configuration for value transfer. 00230 ); 00231 00235 virtual void SaveToConfig( 00236 PConfig & cfg // Configuration for value transfer. 00237 ) const; 00238 00244 virtual BOOL Validated( 00245 const PString & newVal, // Proposed new value for the field. 00246 PStringStream & msg // Stream to take error HTML if value not valid. 00247 ) const; 00248 00249 00255 virtual void GetAllNames(PStringList & list) const; 00256 00259 virtual void SetAllValues( 00260 const PStringToString & data // New value for the field. 00261 ); 00262 00268 virtual BOOL ValidateAll( 00269 const PStringToString & data, // Proposed new value for the field. 00270 PStringStream & msg // Stream to take error HTML if value not valid. 00271 ) const; 00272 00273 00274 BOOL NotYetInHTML() const { return notInHTML; } 00275 void SetInHTML() { notInHTML = FALSE; } 00276 00277 protected: 00278 PCaselessString baseName; 00279 PCaselessString fullName; 00280 PString title; 00281 PString help; 00282 BOOL notInHTML; 00283 }; 00284 00285 00286 PLIST(PHTTPFieldList, PHTTPField); 00287 00288 class PHTTPCompositeField : public PHTTPField 00289 { 00290 PCLASSINFO(PHTTPCompositeField, PHTTPField) 00291 public: 00292 PHTTPCompositeField( 00293 const char * name, // Name (identifier) for the field. 00294 const char * title = NULL, // Title text for field (defaults to name). 00295 const char * help = NULL // Help text for the field. 00296 ); 00297 00298 virtual void SetName( 00299 const PString & name // New name for field 00300 ); 00301 00302 virtual const PHTTPField * LocateName( 00303 const PString & name // Full field name to locate 00304 ) const; 00305 00306 virtual PHTTPField * NewField() const; 00307 00308 virtual void ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const; 00309 00310 virtual void GetHTMLTag( 00311 PHTML & html // HTML to receive the field info. 00312 ) const; 00313 00314 virtual PString GetHTMLInput( 00315 const PString & input // Source HTML text for input tag. 00316 ) const; 00317 00318 virtual void GetHTMLHeading( 00319 PHTML & html // HTML to receive the field info. 00320 ) const; 00321 00322 virtual PString GetValue(BOOL dflt = FALSE) const; 00323 00324 virtual void SetValue( 00325 const PString & newValue // New value for the field. 00326 ); 00327 00328 virtual void LoadFromConfig( 00329 PConfig & cfg // Configuration for value transfer. 00330 ); 00331 virtual void SaveToConfig( 00332 PConfig & cfg // Configuration for value transfer. 00333 ) const; 00334 00335 virtual void GetAllNames(PStringList & list) const; 00336 virtual void SetAllValues( 00337 const PStringToString & data // New value for the field. 00338 ); 00339 00340 virtual BOOL ValidateAll( 00341 const PStringToString & data, // Proposed new value for the field. 00342 PStringStream & msg // Stream to take error HTML if value not valid. 00343 ) const; 00344 00345 00353 virtual PINDEX GetSize() const; 00354 00355 void Append(PHTTPField * fld); 00356 PHTTPField & operator[](PINDEX idx) const { return fields[idx]; } 00357 void RemoveAt(PINDEX idx) { fields.RemoveAt(idx); } 00358 void RemoveAll() { fields.RemoveAll(); } 00359 00360 protected: 00361 PHTTPFieldList fields; 00362 }; 00363 00364 00365 class PHTTPSubForm : public PHTTPCompositeField 00366 { 00367 PCLASSINFO(PHTTPSubForm, PHTTPCompositeField) 00368 public: 00369 PHTTPSubForm( 00370 const PString & subFormName, // URL for the sub-form 00371 const char * name, // Name (identifier) for the field. 00372 const char * title = NULL, // Title text for field (defaults to name). 00373 PINDEX primaryField = 0, // Pimary field whove value is in hot link 00374 PINDEX secondaryField = P_MAX_INDEX // Seconary field next to hotlink 00375 ); 00376 00377 PHTTPField * NewField() const; 00378 void GetHTMLTag(PHTML & html) const; 00379 void GetHTMLHeading(PHTML & html) const; 00380 00381 protected: 00382 PString subFormName; 00383 PINDEX primary; 00384 PINDEX secondary; 00385 }; 00386 00387 00388 class PHTTPFieldArray : public PHTTPCompositeField 00389 { 00390 PCLASSINFO(PHTTPFieldArray, PHTTPCompositeField) 00391 public: 00392 PHTTPFieldArray( 00393 PHTTPField * baseField, 00394 BOOL ordered, 00395 PINDEX fixedSize = 0 00396 ); 00397 00398 ~PHTTPFieldArray(); 00399 00400 00401 virtual PHTTPField * NewField() const; 00402 00403 virtual void ExpandFieldNames(PString & text, PINDEX start, PINDEX & finish) const; 00404 00405 virtual void GetHTMLTag( 00406 PHTML & html // HTML to receive the field info. 00407 ) const; 00408 00409 virtual void LoadFromConfig( 00410 PConfig & cfg // Configuration for value transfer. 00411 ); 00412 virtual void SaveToConfig( 00413 PConfig & cfg // Configuration for value transfer. 00414 ) const; 00415 00416 00417 virtual void SetAllValues( 00418 const PStringToString & data // New value for the field. 00419 ); 00420 00421 virtual PINDEX GetSize() const; 00422 void SetSize(PINDEX newSize); 00423 00424 PStringArray GetStrings( 00425 PConfig & cfg 00426 ); 00427 00428 void SetStrings( 00429 PConfig & cfg, 00430 const PStringArray & values 00431 ); 00432 00433 protected: 00434 void AddBlankField(); 00435 void AddArrayControlBox(PHTML & html, PINDEX fld) const; 00436 void SetArrayFieldName(PINDEX idx) const; 00437 00438 PHTTPField * baseField; 00439 BOOL orderedArray; 00440 BOOL canAddElements; 00441 }; 00442 00443 00444 class PHTTPStringField : public PHTTPField 00445 { 00446 PCLASSINFO(PHTTPStringField, PHTTPField) 00447 public: 00448 PHTTPStringField( 00449 const char * name, 00450 PINDEX size, 00451 const char * initVal = NULL, 00452 const char * help = NULL 00453 ); 00454 PHTTPStringField( 00455 const char * name, 00456 const char * title, 00457 PINDEX size, 00458 const char * initVal = NULL, 00459 const char * help = NULL 00460 ); 00461 00462 virtual PHTTPField * NewField() const; 00463 00464 virtual void GetHTMLTag( 00465 PHTML & html 00466 ) const; 00467 00468 virtual PString GetValue(BOOL dflt = FALSE) const; 00469 00470 virtual void SetValue( 00471 const PString & newVal 00472 ); 00473 00474 00475 protected: 00476 PString value; 00477 PString initialValue; 00478 PINDEX size; 00479 }; 00480 00481 00482 class PHTTPPasswordField : public PHTTPStringField 00483 { 00484 PCLASSINFO(PHTTPPasswordField, PHTTPStringField) 00485 public: 00486 PHTTPPasswordField( 00487 const char * name, 00488 PINDEX size, 00489 const char * initVal = NULL, 00490 const char * help = NULL 00491 ); 00492 PHTTPPasswordField( 00493 const char * name, 00494 const char * title, 00495 PINDEX size, 00496 const char * initVal = NULL, 00497 const char * help = NULL 00498 ); 00499 00500 virtual PHTTPField * NewField() const; 00501 00502 virtual void GetHTMLTag( 00503 PHTML & html 00504 ) const; 00505 00506 virtual PString GetValue(BOOL dflt = FALSE) const; 00507 00508 virtual void SetValue( 00509 const PString & newVal 00510 ); 00511 00512 static PString Decrypt(const PString & pword); 00513 }; 00514 00515 00516 class PHTTPIntegerField : public PHTTPField 00517 { 00518 PCLASSINFO(PHTTPIntegerField, PHTTPField) 00519 public: 00520 PHTTPIntegerField( 00521 const char * name, 00522 int low, int high, 00523 int initVal = 0, 00524 const char * units = NULL, 00525 const char * help = NULL 00526 ); 00527 PHTTPIntegerField( 00528 const char * name, 00529 const char * title, 00530 int low, int high, 00531 int initVal = 0, 00532 const char * units = NULL, 00533 const char * help = NULL 00534 ); 00535 00536 virtual PHTTPField * NewField() const; 00537 00538 virtual void GetHTMLTag( 00539 PHTML & html 00540 ) const; 00541 00542 virtual PString GetValue(BOOL dflt = FALSE) const; 00543 00544 virtual void SetValue( 00545 const PString & newVal 00546 ); 00547 00548 virtual void LoadFromConfig( 00549 PConfig & cfg 00550 ); 00551 virtual void SaveToConfig( 00552 PConfig & cfg 00553 ) const; 00554 00555 virtual BOOL Validated( 00556 const PString & newVal, 00557 PStringStream & msg 00558 ) const; 00559 00560 00561 protected: 00562 int low, high, value; 00563 int initialValue; 00564 PString units; 00565 }; 00566 00567 00568 class PHTTPBooleanField : public PHTTPField 00569 { 00570 PCLASSINFO(PHTTPBooleanField, PHTTPField) 00571 public: 00572 PHTTPBooleanField( 00573 const char * name, 00574 BOOL initVal = FALSE, 00575 const char * help = NULL 00576 ); 00577 PHTTPBooleanField( 00578 const char * name, 00579 const char * title, 00580 BOOL initVal = FALSE, 00581 const char * help = NULL 00582 ); 00583 00584 virtual PHTTPField * NewField() const; 00585 00586 virtual void GetHTMLTag( 00587 PHTML & html 00588 ) const; 00589 00590 virtual PString GetHTMLInput( 00591 const PString & input 00592 ) const; 00593 00594 virtual PString GetValue(BOOL dflt = FALSE) const; 00595 00596 virtual void SetValue( 00597 const PString & newVal 00598 ); 00599 00600 virtual void LoadFromConfig( 00601 PConfig & cfg 00602 ); 00603 virtual void SaveToConfig( 00604 PConfig & cfg 00605 ) const; 00606 00607 00608 protected: 00609 BOOL value, initialValue; 00610 }; 00611 00612 00613 class PHTTPRadioField : public PHTTPField 00614 { 00615 PCLASSINFO(PHTTPRadioField, PHTTPField) 00616 public: 00617 PHTTPRadioField( 00618 const char * name, 00619 const PStringArray & valueArray, 00620 PINDEX initVal = 0, 00621 const char * help = NULL 00622 ); 00623 PHTTPRadioField( 00624 const char * name, 00625 const PStringArray & valueArray, 00626 const PStringArray & titleArray, 00627 PINDEX initVal = 0, 00628 const char * help = NULL 00629 ); 00630 PHTTPRadioField( 00631 const char * name, 00632 PINDEX count, 00633 const char * const * valueStrings, 00634 PINDEX initVal = 0, 00635 const char * help = NULL 00636 ); 00637 PHTTPRadioField( 00638 const char * name, 00639 PINDEX count, 00640 const char * const * valueStrings, 00641 const char * const * titleStrings, 00642 PINDEX initVal = 0, 00643 const char * help = NULL 00644 ); 00645 PHTTPRadioField( 00646 const char * name, 00647 const char * groupTitle, 00648 const PStringArray & valueArray, 00649 PINDEX initVal = 0, 00650 const char * help = NULL 00651 ); 00652 PHTTPRadioField( 00653 const char * name, 00654 const char * groupTitle, 00655 const PStringArray & valueArray, 00656 const PStringArray & titleArray, 00657 PINDEX initVal = 0, 00658 const char * help = NULL 00659 ); 00660 PHTTPRadioField( 00661 const char * name, 00662 const char * groupTitle, 00663 PINDEX count, 00664 const char * const * valueStrings, 00665 PINDEX initVal = 0, 00666 const char * help = NULL 00667 ); 00668 PHTTPRadioField( 00669 const char * name, 00670 const char * groupTitle, 00671 PINDEX count, 00672 const char * const * valueStrings, 00673 const char * const * titleStrings, 00674 PINDEX initVal = 0, 00675 const char * help = NULL 00676 ); 00677 00678 virtual PHTTPField * NewField() const; 00679 00680 virtual void GetHTMLTag( 00681 PHTML & html 00682 ) const; 00683 00684 virtual PString GetHTMLInput( 00685 const PString & input 00686 ) const; 00687 00688 virtual PString GetValue(BOOL dflt = FALSE) const; 00689 00690 virtual void SetValue( 00691 const PString & newVal 00692 ); 00693 00694 00695 protected: 00696 PStringArray values; 00697 PStringArray titles; 00698 PString value; 00699 PString initialValue; 00700 }; 00701 00702 00703 class PHTTPSelectField : public PHTTPField 00704 { 00705 PCLASSINFO(PHTTPSelectField, PHTTPField) 00706 public: 00707 PHTTPSelectField( 00708 const char * name, 00709 const PStringArray & valueArray, 00710 PINDEX initVal = 0, 00711 const char * help = NULL 00712 ); 00713 PHTTPSelectField( 00714 const char * name, 00715 PINDEX count, 00716 const char * const * valueStrings, 00717 PINDEX initVal = 0, 00718 const char * help = NULL 00719 ); 00720 PHTTPSelectField( 00721 const char * name, 00722 const char * title, 00723 const PStringArray & valueArray, 00724 PINDEX initVal = 0, 00725 const char * help = NULL 00726 ); 00727 PHTTPSelectField( 00728 const char * name, 00729 const char * title, 00730 PINDEX count, 00731 const char * const * valueStrings, 00732 PINDEX initVal = 0, 00733 const char * help = NULL 00734 ); 00735 00736 virtual PHTTPField * NewField() const; 00737 00738 virtual void GetHTMLTag( 00739 PHTML & html 00740 ) const; 00741 00742 virtual PString GetValue(BOOL dflt = FALSE) const; 00743 00744 virtual void SetValue( 00745 const PString & newVal 00746 ); 00747 00748 00749 PStringArray values; 00750 00751 00752 protected: 00753 PString value; 00754 PINDEX initialValue; 00755 }; 00756 00757 00759 // PHTTPForm 00760 00761 class PHTTPForm : public PHTTPString 00762 { 00763 PCLASSINFO(PHTTPForm, PHTTPString) 00764 public: 00765 PHTTPForm( 00766 const PURL & url 00767 ); 00768 PHTTPForm( 00769 const PURL & url, 00770 const PHTTPAuthority & auth 00771 ); 00772 PHTTPForm( 00773 const PURL & url, 00774 const PString & html 00775 ); 00776 PHTTPForm( 00777 const PURL & url, 00778 const PString & html, 00779 const PHTTPAuthority & auth 00780 ); 00781 00782 00783 virtual void OnLoadedText( 00784 PHTTPRequest & request, 00785 PString & text 00786 ); 00787 virtual BOOL Post( 00788 PHTTPRequest & request, 00789 const PStringToString & data, 00790 PHTML & replyMessage 00791 ); 00792 00793 00794 PHTTPField * Add( 00795 PHTTPField * fld 00796 ); 00797 void RemoveAllFields() 00798 { fields.RemoveAll(); fieldNames.RemoveAll(); } 00799 00800 enum BuildOptions { 00801 CompleteHTML, 00802 InsertIntoForm, 00803 InsertIntoHTML 00804 }; 00805 00806 void BuildHTML( 00807 const char * heading 00808 ); 00809 void BuildHTML( 00810 const PString & heading 00811 ); 00812 void BuildHTML( 00813 PHTML & html, 00814 BuildOptions option = CompleteHTML 00815 ); 00816 00817 00818 protected: 00819 PHTTPCompositeField fields; 00820 PStringSet fieldNames; 00821 }; 00822 00823 00825 // PHTTPConfig 00826 00827 class PHTTPConfig : public PHTTPForm 00828 { 00829 PCLASSINFO(PHTTPConfig, PHTTPForm) 00830 public: 00831 PHTTPConfig( 00832 const PURL & url, 00833 const PString & section 00834 ); 00835 PHTTPConfig( 00836 const PURL & url, 00837 const PString & section, 00838 const PHTTPAuthority & auth 00839 ); 00840 PHTTPConfig( 00841 const PURL & url, 00842 const PString & section, 00843 const PString & html 00844 ); 00845 PHTTPConfig( 00846 const PURL & url, 00847 const PString & section, 00848 const PString & html, 00849 const PHTTPAuthority & auth 00850 ); 00851 00852 virtual void OnLoadedText( 00853 PHTTPRequest & request, 00854 PString & text 00855 ); 00856 virtual BOOL Post( 00857 PHTTPRequest & request, 00858 const PStringToString & data, 00859 PHTML & replyMessage 00860 ); 00861 00862 00865 void LoadFromConfig(); 00866 00872 const PString & GetConfigSection() const { return section; } 00873 00874 void SetConfigSection( 00875 const PString & sect 00876 ) { section = sect; } 00877 // Set the configuration file section. 00878 00883 PHTTPField * AddSectionField( 00884 PHTTPField * sectionFld, 00885 const char * prefix = NULL, 00886 const char * suffix = NULL 00887 ); 00888 00892 void AddNewKeyFields( 00893 PHTTPField * keyFld, 00894 PHTTPField * valFld 00895 ); 00896 00897 00898 protected: 00899 PString section; 00900 PString sectionPrefix; 00901 PString sectionSuffix; 00902 PHTTPField * sectionField; 00903 PHTTPField * keyField; 00904 PHTTPField * valField; 00905 00906 private: 00907 void Construct(); 00908 }; 00909 00910 00912 // PHTTPConfigSectionList 00913 00914 class PHTTPConfigSectionList : public PHTTPString 00915 { 00916 PCLASSINFO(PHTTPConfigSectionList, PHTTPString) 00917 public: 00918 PHTTPConfigSectionList( 00919 const PURL & url, 00920 const PHTTPAuthority & auth, 00921 const PString & sectionPrefix, 00922 const PString & additionalValueName, 00923 const PURL & editSection, 00924 const PURL & newSection, 00925 const PString & newSectionTitle, 00926 PHTML & heading 00927 ); 00928 00929 virtual void OnLoadedText( 00930 PHTTPRequest & request, 00931 PString & text 00932 ); 00933 virtual BOOL Post( 00934 PHTTPRequest & request, 00935 const PStringToString & data, 00936 PHTML & replyMessage 00937 ); 00938 00939 protected: 00940 PString sectionPrefix; 00941 PString additionalValueName; 00942 PString newSectionLink; 00943 PString newSectionTitle; 00944 PString editSectionLink; 00945 }; 00946 00947 00948 #endif 00949 00950 00951 // End Of File ///////////////////////////////////////////////////////////////