Changeset 1888

Show
Ignore:
Timestamp:
Tue Jan 24 15:31:10 2006
Author:
fgerlits
Message:

added Servers tab;
refactored a bit to reduce the amount of copy-paste code;
improved the spacings

Files:

Legend:

Unmodified
Added
Removed
Modified
  • trunk/livesupport/src/products/gLiveSupport/src/OptionsWindow.cxx

    r1884 r1888  
    89 89     // build up the notepad for the various sections  
    90 90     mainNotebook = Gtk::manage(new ScrolledNotebook);  
    91       Gtk::Box *      soundSectionBox = constructSoundSection();  
    92       Gtk::Box *      aboutSectionBox = constructAboutSection();  
      91     Gtk::Box *      soundSectionBox     = constructSoundSection();  
      92     Gtk::Box *      serversSectionBox   = constructServersSection();  
      93     Gtk::Box *      aboutSectionBox     = constructAboutSection();  
    93 94  
    94 95     try {  
    95 96         mainNotebook->appendPage(*soundSectionBox,  
    96 97                                  *getResourceUstring("soundSectionLabel"));  
      98         mainNotebook->appendPage(*serversSectionBox,  
      99                                  *getResourceUstring("serversSectionLabel"));  
    97 100         mainNotebook->appendPage(*aboutSectionBox,  
    98 101                                  *getResourceUstring("aboutSectionLabel"));  
     
    143 146     // show everything  
    144 147     set_name(windowName);  
    145       set_default_size(350, 300);  
      148     set_default_size(500, 400);  
    145 148     set_modal(false);  
    146 149     property_window_position().set_value(Gtk::WIN_POS_NONE);  
     
    170 173             optionsContainer  = gLiveSupport->getOptionsContainer();  
    171 174  
    172       // check for changes in the Sound tab  
    173       Ptr<const Glib::ustring>::Ref  
    174               oldCueDevice      = optionsContainer->getOptionItem(  
    175                                       OptionsContainer::cuePlayerDeviceName );  
    176       Ptr<const Glib::ustring>::Ref  
    177               newCueDevice(new Glib::ustring(cuePlayerEntry->get_text()));  
    178        
    179       if (*oldCueDevice != *newCueDevice) {  
    180           optionsContainer->setOptionItem(  
    181                                       OptionsContainer::cuePlayerDeviceName,  
    182                                       newCueDevice );  
    183       }  
    184        
    185       Ptr<const Glib::ustring>::Ref  
    186               oldOutputDevice   = optionsContainer->getOptionItem(  
    187                                       OptionsContainer::outputPlayerDeviceName );  
    188       Ptr<const Glib::ustring>::Ref  
    189               newOutputDevice(new Glib::ustring(outputPlayerEntry->get_text()));  
    190        
    191       if (*oldOutputDevice != *newOutputDevice) {  
    192           optionsContainer->setOptionItem(  
    193                                       OptionsContainer::outputPlayerDeviceName,  
    194                                       newOutputDevice );  
      175     StringEntryListType::const_iterator it;  
      176     for (it = stringEntryList.begin(); it != stringEntryList.end(); ++it) {  
      177      
      178         OptionsContainer::OptionItemString  optionItem = it->first;  
      179         EntryBin *                          entry      = it->second;  
      180          
      181         Ptr<const Glib::ustring>::Ref  
      182             oldValue = optionsContainer->getOptionItem(optionItem);  
      183         Ptr<const Glib::ustring>::Ref  
      184             newValue(new Glib::ustring(entry->get_text()));  
      185  
      186         if (*oldValue != *newValue) {  
      187             try {  
      188                 optionsContainer->setOptionItem(optionItem, newValue);  
      189             } catch (std::invalid_argument &e) {  
      190                 // TODO: signal error  
      191             }  
      192         }  
    195 193     }  
    196 194 }  
     
    223 221  
    224 222 /*------------------------------------------------------------------------------  
    225    *  Construct the "About" section.  
      223  *  Create a new user entry field item.  
    225 223  *----------------------------------------------------------------------------*/  
    226   Gtk::VBox*  
    227   OptionsWindow :: constructAboutSection(void)                        throw ()  
      224 EntryBin *  
      225 OptionsWindow :: createEntry(OptionsContainer::OptionItemString  optionItem)  
      226                                                                     throw ()  
    228 227 {  
    229       Glib::ustring   aboutLabelContents;  
    230       aboutLabelContents.append(PACKAGE_NAME);  
    231       aboutLabelContents.append(" ");  
    232       aboutLabelContents.append(PACKAGE_VERSION);  
    233       aboutLabelContents.append("\n\n");  
      228     Ptr<OptionsContainer>::Ref  optionsContainer  
      229                                    = gLiveSupport->getOptionsContainer();  
      230     Ptr<WidgetFactory>::Ref     wf = WidgetFactory::getInstance();  
      231  
      232     EntryBin *  entry = Gtk::manage(wf->createEntryBin());  
      233  
    234 234     try {  
    235           aboutLabelContents.append(*formatMessage("reportBugsToText",  
    236                                                    PACKAGE_BUGREPORT ));  
      235         entry->set_text(*optionsContainer->getOptionItem(optionItem));  
      236  
    237 237     } catch (std::invalid_argument &e) {  
    238           // TODO: signal error  
    239           std::cerr << e.what() << std::endl;  
    240           std::exit(1);  
      238         // TODO: signal error?  
      239         entry->set_text("");  
    241 240     }  
    242       Gtk::Label *    aboutLabel = Gtk::manage(  
    243                                       new Gtk::Label(aboutLabelContents) );  
    244    
    245       // make a new box and pack the components into it  
    246       Gtk::VBox *     section = Gtk::manage(new Gtk::VBox);  
    247       section->pack_start(*aboutLabel, Gtk::PACK_SHRINK, 5);  
    248 241      
    249       return section;  
      242     stringEntryList.push_back(std::make_pair(optionItem, entry));  
      243  
      244     return entry;  
    250 245 }  
    251 246  
     
    278 273     Gtk::Label *    cuePlayerLabel = Gtk::manage(  
    279 274                                     new Gtk::Label(cuePlayerLabelContents) );  
    280       audioDeviceTable->attach(*cuePlayerLabel, 0, 1, 0, 1);  
      275     audioDeviceTable->attach(*cuePlayerLabel,  
      276                                     0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 5, 0);  
    281 277      
    282       cuePlayerEntry = Gtk::manage(wf->createEntryBin());  
    283       cuePlayerEntry->set_text(*optionsContainer->getOptionItem(  
    284                                       OptionsContainer::cuePlayerDeviceName ));  
      278     EntryBin *      cuePlayerEntry = createEntry(  
      279                                     OptionsContainer::cuePlayerDeviceName);  
    285 280     audioDeviceTable->attach(*cuePlayerEntry, 1, 2, 0, 1);  
    286 281      
     
    297 292     Gtk::Label *    outputPlayerLabel = Gtk::manage(  
    298 293                                     new Gtk::Label(outputPlayerLabelContents) );  
    299       audioDeviceTable->attach(*outputPlayerLabel, 0, 1, 1, 2);  
      294     audioDeviceTable->attach(*outputPlayerLabel,  
      295                                     0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 5, 0);  
    300 296      
    301       outputPlayerEntry = Gtk::manage(wf->createEntryBin());  
    302       outputPlayerEntry->set_text(*optionsContainer->getOptionItem(  
    303                                       OptionsContainer::outputPlayerDeviceName ));  
      297     EntryBin *      outputPlayerEntry = createEntry(  
      298                                     OptionsContainer::outputPlayerDeviceName);  
    304 299     audioDeviceTable->attach(*outputPlayerEntry, 1, 2, 1, 2);  
    305 300  
    311 306 }  
    312 307  
      308  
      309 /*------------------------------------------------------------------------------  
      310  *  Construct the "Servers" section.  
      311  *----------------------------------------------------------------------------*/  
      312 Gtk::VBox*  
      313 OptionsWindow :: constructServersSection(void)                      throw ()  
      314 {  
      315     Ptr<OptionsContainer>::Ref  optionsContainer  
      316                                    = gLiveSupport->getOptionsContainer();  
      317     Ptr<WidgetFactory>::Ref     wf = WidgetFactory::getInstance();  
      318      
      319     // the settings for the authentication server  
      320     Gtk::Table *    authenticationTable = Gtk::manage(new Gtk::Table);  
      321     authenticationTable->set_row_spacings(5);  
      322     authenticationTable->set_col_spacings(5);  
      323      
      324     Gtk::Label *    authenticationLabel;  
      325     Gtk::Label *    authenticationServerLabel;  
      326     Gtk::Label *    authenticationPortLabel;  
      327     Gtk::Label *    authenticationPathLabel;  
      328     try {  
      329         authenticationLabel = Gtk::manage(new Gtk::Label(  
      330                             *getResourceUstring("authenticationLabel") ));  
      331         authenticationServerLabel = Gtk::manage(new Gtk::Label(  
      332                             *getResourceUstring("serverLabel") ));  
      333         authenticationPortLabel = Gtk::manage(new Gtk::Label(  
      334                             *getResourceUstring("portLabel") ));  
      335         authenticationPathLabel = Gtk::manage(new Gtk::Label(  
      336                             *getResourceUstring("pathLabel") ));  
      337          
      338     } catch (std::invalid_argument &e) {  
      339         // TODO: signal error  
      340         std::cerr << e.what() << std::endl;  
      341         std::exit(1);  
      342     }  
      343  
      344     authenticationTable->attach(*authenticationLabel,  
      345                                     0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 5, 0);  
      346     authenticationTable->attach(*authenticationServerLabel,  
      347                                     1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK);  
      348     authenticationTable->attach(*authenticationPortLabel,  
      349                                     1, 2, 1, 2, Gtk::SHRINK, Gtk::SHRINK);  
      350     authenticationTable->attach(*authenticationPathLabel,  
      351                                     1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);  
      352      
      353     EntryBin *  authenticationServerEntry = createEntry(  
      354                                     OptionsContainer::authenticationServer);  
      355     EntryBin *  authenticationPortEntry   = createEntry(  
      356                                     OptionsContainer::authenticationPort);  
      357     EntryBin *  authenticationPathEntry   = createEntry(  
      358                                     OptionsContainer::authenticationPath);  
      359      
      360     authenticationTable->attach(*authenticationServerEntry, 2, 3, 0, 1);  
      361     authenticationTable->attach(*authenticationPortEntry,   2, 3, 1, 2);  
      362     authenticationTable->attach(*authenticationPathEntry,   2, 3, 2, 3);  
      363      
      364     // the settings for the storage server  
      365     Gtk::Table *    storageTable = Gtk::manage(new Gtk::Table);  
      366     storageTable->set_row_spacings(5);  
      367     storageTable->set_col_spacings(5);  
      368      
      369     Gtk::Label *    storageLabel;  
      370     Gtk::Label *    storageServerLabel;  
      371     Gtk::Label *    storagePortLabel;  
      372     Gtk::Label *    storagePathLabel;  
      373     try {  
      374         storageLabel = Gtk::manage(new Gtk::Label(  
      375                             *getResourceUstring("storageLabel") ));  
      376         storageServerLabel = Gtk::manage(new Gtk::Label(  
      377                             *getResourceUstring("serverLabel") ));  
      378         storagePortLabel = Gtk::manage(new Gtk::Label(  
      379                             *getResourceUstring("portLabel") ));  
      380         storagePathLabel = Gtk::manage(new Gtk::Label(  
      381                             *getResourceUstring("pathLabel") ));  
      382          
      383     } catch (std::invalid_argument &e) {  
      384         // TODO: signal error  
      385         std::cerr << e.what() << std::endl;  
      386         std::exit(1);  
      387     }  
      388  
      389     storageTable->attach(*storageLabel,  
      390                                     0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 5, 0);  
      391     storageTable->attach(*storageServerLabel,  
      392                                     1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK);  
      393     storageTable->attach(*storagePortLabel,  
      394                                     1, 2, 1, 2, Gtk::SHRINK, Gtk::SHRINK);  
      395     storageTable->attach(*storagePathLabel,  
      396                                     1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);  
      397      
      398     EntryBin *  storageServerEntry = createEntry(  
      399                                             OptionsContainer::storageServer);  
      400     EntryBin *  storagePortEntry   = createEntry(  
      401                                             OptionsContainer::storagePort);  
      402     EntryBin *  storagePathEntry   = createEntry(  
      403                                             OptionsContainer::storagePath);  
      404      
      405     storageTable->attach(*storageServerEntry, 2, 3, 0, 1);  
      406     storageTable->attach(*storagePortEntry,   2, 3, 1, 2);  
      407     storageTable->attach(*storagePathEntry,   2, 3, 2, 3);  
      408      
      409     // make a new box and pack the components into it  
      410     Gtk::VBox *     section = Gtk::manage(new Gtk::VBox);  
      411     section->pack_start(*authenticationTable,   Gtk::PACK_SHRINK, 10);  
      412     section->pack_start(*storageTable,          Gtk::PACK_SHRINK, 10);  
      413      
      414     return section;  
      415 }  
      416  
      417  
      418 /*------------------------------------------------------------------------------  
      419  *  Construct the "About" section.  
      420  *----------------------------------------------------------------------------*/  
      421 Gtk::VBox*  
      422 OptionsWindow :: constructAboutSection(void)                        throw ()  
      423 {  
      424     Glib::ustring   aboutLabelContents;  
      425     aboutLabelContents.append("\n\n");  
      426     aboutLabelContents.append(PACKAGE_NAME);  
      427     aboutLabelContents.append(" ");  
      428     aboutLabelContents.append(PACKAGE_VERSION);  
      429     aboutLabelContents.append("\n\n");  
      430     try {  
      431         aboutLabelContents.append(*formatMessage("reportBugsToText",  
      432                                                  PACKAGE_BUGREPORT ));  
      433     } catch (std::invalid_argument &e) {  
      434         // TODO: signal error  
      435         std::cerr << e.what() << std::endl;  
      436         std::exit(1);  
      437     }  
      438     Gtk::Label *    aboutLabel = Gtk::manage(  
      439                                     new Gtk::Label(aboutLabelContents) );  
      440  
      441     // make a new box and pack the components into it  
      442     Gtk::VBox *     section = Gtk::manage(new Gtk::VBox);  
      443     section->pack_start(*aboutLabel, Gtk::PACK_SHRINK, 5);  
      444      
      445     return section;  
      446 }  
      447  
  • trunk/livesupport/src/products/gLiveSupport/src/OptionsContainer.cxx

    r1885 r1888  
    77 77                                                 throw (std::invalid_argument)  
    78 78 {  
    79       xmlpp::Node *           targetNode   = 0;  
    80       bool                    isAttribute  = false; // text node or attr node  
    81        
    82       switch (optionItem) {  
    83           case outputPlayerDeviceName :  
    84               targetNode  = getNode("outputPlayer/audioPlayer/gstreamerPlayer/"  
    85                                     "@audioDevice");  
    86               isAttribute = true;  
    87               break;  
    88            
    89           case cuePlayerDeviceName :  
    90               targetNode  = getNode("cuePlayer/audioPlayer/gstreamerPlayer/"  
    91                                     "@audioDevice");  
    92               isAttribute = true;  
    93               break;  
    94       }  
      79     bool              isAttribute  = false; // text node or attr node  
      80     xmlpp::Node *     targetNode = selectNode(optionItem, isAttribute);  
    95 81  
    96 82     if (isAttribute) {  
     
    121 107                                                 throw (std::invalid_argument)  
    122 108 {  
    123       const xmlpp::Node *     targetNode = 0;  
    124       bool                    isAttribute = false; // child text node or attr  
      109     bool                    isAttribute = false; // text node or attr node  
      110     const xmlpp::Node *     targetNode = selectNode(optionItem, isAttribute);  
    125 111      
    126       switch (optionItem) {  
    127           case outputPlayerDeviceName :  
    128               targetNode  = getNode("outputPlayer/audioPlayer/gstreamerPlayer/"  
    129                                     "@audioDevice");  
    130               isAttribute = true;  
    131               break;  
    132            
    133           case cuePlayerDeviceName :  
    134               targetNode  = getNode("cuePlayer/audioPlayer/gstreamerPlayer/"  
    135                                     "@audioDevice");  
    136               isAttribute = true;  
    137               break;  
    138       }  
    139    
    140 112     if (isAttribute) {  
    141 113         const xmlpp::Attribute *  
    161 133  
    162 134 /*------------------------------------------------------------------------------  
      135  *  Find the node corresponding to an OptionItemString value.  
      136  *----------------------------------------------------------------------------*/  
      137 xmlpp::Node *  
      138 OptionsContainer :: selectNode(OptionItemString     optionItem,  
      139                                bool &               isAttribute)  
      140                                                 throw (std::invalid_argument)  
      141 {  
      142     xmlpp::Node *   targetNode = 0;  
      143  
      144     switch (optionItem) {  
      145         case outputPlayerDeviceName :  
      146             targetNode  = getNode("outputPlayer/audioPlayer/gstreamerPlayer/"  
      147                                   "@audioDevice");  
      148             isAttribute = true;  
      149             break;  
      150          
      151         case cuePlayerDeviceName :  
      152             targetNode  = getNode("cuePlayer/audioPlayer/gstreamerPlayer/"  
      153                                   "@audioDevice");  
      154             isAttribute = true;  
      155             break;  
      156          
      157         case authenticationServer :  
      158             targetNode  = getNode("authenticationClientFactory/"  
      159                                   "webAuthentication/location/@server");  
      160             isAttribute = true;  
      161             break;  
      162          
      163         case authenticationPort :  
      164             targetNode  = getNode("authenticationClientFactory/"  
      165                                   "webAuthentication/location/@port");  
      166             isAttribute = true;  
      167             break;  
      168          
      169         case authenticationPath :  
      170             targetNode  = getNode("authenticationClientFactory/"  
      171                                   "webAuthentication/location/@path");  
      172             isAttribute = true;  
      173             break;  
      174          
      175         case storageServer :  
      176             targetNode  = getNode("storageClientFactory/"  
      177                                   "webStorage/location/@server");  
      178             isAttribute = true;  
      179             break;  
      180          
      181         case storagePort :  
      182             targetNode  = getNode("storageClientFactory/"  
      183                                   "webStorage/location/@port");  
      184             isAttribute = true;  
      185             break;  
      186          
      187         case storagePath :  
      188             targetNode  = getNode("storageClientFactory/"  
      189                                   "webStorage/location/@path");  
      190             isAttribute = true;  
      191             break;  
      192     }  
      193      
      194     return targetNode;  
      195 }  
      196  
      197  
      198 /*------------------------------------------------------------------------------  
    163 199  *  Return the first node matching an XPath string.  
    164 200  *----------------------------------------------------------------------------*/  
  • trunk/livesupport/src/products/gLiveSupport/src/OptionsWindow.h

    r1884 r1888  
    121 121  
    122 122         /**  
    123            *  The entry field for the cue player device's name.  
      123          *  The type for the list of user entry fields of string type.  
    123 123          */  
    124           EntryBin                  * cuePlayerEntry;  
      124         typedef std::vector<std::pair<OptionsContainer::OptionItemString,  
      125                                       EntryBin*> >      StringEntryListType;  
    125 126  
    126 127         /**  
    127            *  The entry field for the output player device's name.  
      128          *  The list of user entry fields of string type.  
    127 128          */  
    128           EntryBin                  * outputPlayerEntry;  
      129         StringEntryListType         stringEntryList;  
    128 129  
    129 130         /**  
     
    141 142  
    142 143         /**  
    143            *  Construct the "About" section.  
      144          *  Create a new user entry field item.  
    143 144          *  
    144            *  @return a pointer to the new box (already Gtk::manage()'ed)  
      145          *  This constructs [and Gtk::manage()s] the EntryBin, and  
      146          *  sets its text to the current value of the option.  
      147          *  The EntryBin is then added to the list of user entry fields.  
      148          *  
      149          *  @param  optionItem  the name of the option item for this entry  
      150          *  @return the newly created EntryBin  
    145 151          */  
    146           Gtk::VBox*  
    147           constructAboutSection(void)                         throw ();  
      152         EntryBin *  
      153         createEntry(OptionsContainer::OptionItemString  optionItem)  
      154                                                             throw ();  
    148 155  
    149 156         /**  
    156 163         constructSoundSection(void)                         throw ();  
    157 164  
      165         /**  
      166          *  Construct the "Servers" section.  
      167          *  
      168          *  @return a pointer to the new box (already Gtk::manage()'ed)  
      169          */  
      170         Gtk::VBox*  
      171         constructServersSection(void)                       throw ();  
      172  
      173         /**  
      174          *  Construct the "About" section.  
      175          *  
      176          *  @return a pointer to the new box (already Gtk::manage()'ed)  
      177          */  
      178         Gtk::VBox*  
      179         constructAboutSection(void)                         throw ();  
      180  
    158 181  
    159 182     protected:  
  • trunk/livesupport/src/products/gLiveSupport/src/OptionsContainer.h

    r1886 r1888  
    69 69 class OptionsContainer  
    70 70 {  
      71     public:  
      72         /**  
      73          *  The list of string options one can set.  
      74          *   
      75          *  These are options of type Glib::ustring; any string is accepted  
      76          *  as value, no range checking is done.  
      77          *   
      78          *  For the moment, this is the only kind of option supported.  
      79          */  
      80         typedef enum { outputPlayerDeviceName,  
      81                        cuePlayerDeviceName,  
      82                        authenticationServer,  
      83                        authenticationPort,  
      84                        authenticationPath,  
      85                        storageServer,  
      86                        storagePort,  
      87                        storagePath }    OptionItemString;  
      88          
      89  
    71 90     private:  
    72 91         /**  
     
    93 112  
    94 113         /**  
      114          *  Find the node corresponding to an OptionItemString value.  
      115          *  
      116          *  If there is no matching node, it returns a 0 pointer.  
      117          *  
      118          *  @param  optionItem      the name of the item to find the node for  
      119          *  @param  isAttribute     return parameter; is set to true if the  
      120          *                              node is an attribute, false if it's  
      121          *                              a CDATA text  
      122          *  @return a pointer to the node found, or 0  
      123          *  @exception  std::invalid_argument   thrown by getNode() [should  
      124          *                                      never happen]  
      125          */  
      126         xmlpp::Node *  
      127         selectNode(OptionItemString     optionItem,  
      128                    bool &               isAttribute)  
      129                                                 throw (std::invalid_argument);  
      130          
      131         /**  
    95 132          *  Return the first node matching an XPath string.  
    96 133          *  
     
    99 136          *  @param  xPath   the XPath of the node (from the root node)  
    100 137          *  @return a pointer to the node found, or 0  
      138          *  @exception  std::invalid_argument   if the XPath is not well formed  
    101 139          */  
    102 140         xmlpp::Node *  
    133 171  
    134 172         /**  
    135            *  The list of string options one can set.  
    136            *   
    137            *  These are options of type Glib::ustring; any string is accepted  
    138            *  as value, no range checking is done.  
    139            *   
    140            *  For the moment, this is the only kind of option supported.  
    141            */  
    142           typedef enum { outputPlayerDeviceName,  
    143                          cuePlayerDeviceName }    OptionItemString;  
    144            
    145           /**  
    146 173          *  Set a string type option.  
    147 174          *  
  • trunk/livesupport/src/products/gLiveSupport/var/root.txt

    r1881 r1888  
    222 222         windowTitle:string          { "LiveSupport Options Window" }  
    223 223          
    224           aboutSectionLabel:string    { "About" }  
    225 224         soundSectionLabel:string    { "Sound" }  
      225         serversSectionLabel:string  { "Servers" }  
      226         aboutSectionLabel:string    { "About" }  
    226 227  
    227 228         cancelButtonLabel:string    { "Cancel" }  
    229 230         okButtonLabel:string        { "OK" }  
    230 231          
    231           reportBugsToText:string     { "Report bugs to: {0}" }  
    232            
    233 232         cueDeviceLabel:string       { "Cue audio device:" }  
    234 233         outputDeviceLabel:string    { "Live Mode audio device:" }  
      234          
      235         authenticationLabel:string  { "Authentication server" }  
      236         storageLabel:string         { "Storage server" }  
      237         serverLabel:string          { "address:" }  
      238         portLabel:string            { "port:" }  
      239         pathLabel:string            { "path:" }  
      240          
      241         reportBugsToText:string     { "Report bugs to: {0}" }  
    235 242     }  
    236 243