Annotation of Amaya/amaya/insertelem.c, revision 1.25

1.1       kia         1: /*
                      2:  *
1.21      vatton      3:  *  COPYRIGHT INRIA and W3C, 1996-2008
1.1       kia         4:  *  Please first read the full copyright statement in file COPYRIGHT.
                      5:  *
                      6:  */
                      7:  
                      8: /*
                      9:  * Authors: Emilien Kia
                     10:  *
                     11:  */
                     12: 
                     13: #define THOT_EXPORT extern
                     14: #include "amaya.h"
                     15: #include "document.h"
                     16: 
                     17: #include "containers.h"
                     18: #include "Elemlist.h"
                     19: 
                     20: #ifdef TEMPLATES
                     21: #include "Template.h"
                     22: #include "templates.h"
                     23: #include "templates_f.h"
                     24: #include "templateDeclarations.h"
                     25: 
                     26: #include "templateLoad_f.h"
                     27: #include "templateDeclarations_f.h"
                     28: #include "templateInstantiate_f.h"
1.19      kia        29: #include "templateUtils_f.h"
1.1       kia        30: #include "appdialogue_wx.h"
                     31: #include "init_f.h"
                     32: #include "wxdialogapi_f.h"
                     33: #include "AHTURLTools_f.h"
                     34: 
                     35: #endif /* TEMPLATES */
                     36: 
                     37: 
                     38: #include "fetchXMLname_f.h"
                     39: #include "MENUconf.h"
                     40: #include "parser.h"
                     41: #include "fetchXMLname_f.h"
                     42: 
1.2       cvs        43: typedef struct _sInsertableElementList *InsertableElementList;
                     44: typedef struct _sInsertableElementList
1.1       kia        45: {
                     46:   /** Current selected element.*/
                     47:   Element elem;
                     48:   /** Insertable element list.*/
                     49:   DLList list;
1.2       cvs        50: } sInsertableElementList;
1.1       kia        51: 
                     52: 
                     53: static HashMap InsertableElementMap = NULL;
                     54: 
                     55: 
1.6       vatton     56: /*----------------------------------------------------------------------
                     57:   ----------------------------------------------------------------------*/
1.1       kia        58: static InsertableElementList InsertableElementList_Create(Element elem, DLList list)
                     59: {
                     60:   InsertableElementList lst = (InsertableElementList)TtaGetMemory(sizeof(sInsertableElementList));
                     61:   lst->elem = elem;
                     62:   lst->list = list;
                     63:   return lst; 
                     64: }
                     65: 
                     66: static void InsertableElementList_Destroy(InsertableElementList list)
                     67: {
1.8       vatton     68:   if (list->list)
1.1       kia        69:     DLList_Destroy(list->list);
                     70:   TtaFreeMemory(list);
                     71: }
                     72: 
                     73: /*----------------------------------------------------------------------
                     74:   InsertableElement_Init
                     75:   Initialize the module.
                     76:   ----------------------------------------------------------------------*/
                     77: void InsertableElement_Init()
                     78: {
1.8       vatton     79:   if (!InsertableElementMap)
1.1       kia        80:     InsertableElementMap = PointerHashMap_Create((Container_DestroyElementFunction)InsertableElementList_Destroy, 32);
                     81: }
                     82: 
                     83: /*----------------------------------------------------------------------
                     84:   InsertableElement_Final
                     85:   Finalize the module.
                     86:   ----------------------------------------------------------------------*/
                     87: void InsertableElement_Final()
                     88: {
1.8       vatton     89:   if (InsertableElementMap)
1.1       kia        90:   {
                     91:     HashMap_Destroy(InsertableElementMap);
                     92:     InsertableElementMap = NULL;
                     93:   }
                     94: }
                     95: 
                     96: 
                     97: #ifdef TEMPLATES
                     98: /*----------------------------------------------------------------------
                     99:   FillUnionResolvedPossibleElement
                    100:   Fill an element list with all possible element, resolving them if union.
                    101:   @param name Element name
                    102:   @param elem Document element to attach
                    103:   @param resolvedPath Path of different succesive union name.
                    104:   @param list List to fill.
                    105:   ----------------------------------------------------------------------*/
1.25    ! kia       106: static void FillUnionResolvedPossibleElement(XTigerTemplate t, Declaration dec,
1.6       vatton    107:                                              Element elem, const char* resolvedPath,
                    108:                                              DLList list, int level)
1.1       kia       109: {
1.25    ! kia       110:   Document    doc;
        !           111:   if(t && dec && elem)
1.1       kia       112:     {
1.25    ! kia       113:       doc = TtaGetDocument(elem);
        !           114:       if (dec->nature==ComponentNat)
        !           115:         DLList_Append(list, ElemListElement_CreateComponent(level, dec->name, (void*)dec,
        !           116:                                                             resolvedPath, elem));
        !           117:       else if (dec->nature==UnionNat)
        !           118:         {
        !           119:           DLList          tempList = ElemList_Create();
        !           120:           ForwardIterator iter = SearchSet_GetForwardIterator(dec->unionType.include);
        !           121:           SearchSetNode   mapnode;
        !           122:           DLListNode      listnode;
        !           123:       
        !           124:           int len1 = 0 , len2 = strlen(dec->name);
        !           125:           if (resolvedPath!=NULL)
        !           126:             len1 = strlen(resolvedPath);
        !           127:           char* newPath = (char*)TtaGetMemory(len1+len2+2);
        !           128:           if (len1 > 0)
        !           129:             {
        !           130:               strcpy(newPath, resolvedPath);
        !           131:               newPath[len1] = '/';
        !           132:               strcpy(newPath+len1+1, dec->name);
        !           133:             }
        !           134:           else
        !           135:             strcpy(newPath, dec->name);
        !           136:           
        !           137:           ITERATOR_FOREACH(iter, SearchSetNode, mapnode)
        !           138:             {
        !           139:               FillUnionResolvedPossibleElement(t, (Declaration)mapnode->elem, elem, newPath, tempList, level);
        !           140:             }
        !           141:           TtaFreeMemory(iter);
        !           142:           
        !           143:           iter = DLList_GetForwardIterator(tempList);
        !           144:           
        !           145:           
        !           146:           listnode = (DLListNode) ForwardIterator_GetFirst(iter);
        !           147:           ITERATOR_FOREACH(iter, DLListNode, listnode)
        !           148:             DLList_Append(list, listnode->elem);
        !           149:           TtaFreeMemory(iter);
        !           150:       
        !           151:           tempList->destroyElement = NULL;
        !           152:           DLList_Destroy(tempList);
        !           153:           
        !           154:           TtaFreeMemory(newPath);
        !           155:           
        !           156:           /** todo Remove excluded elements.*/
        !           157:         }
        !           158:       else if (dec->nature==SimpleTypeNat)
        !           159:         DLList_Append(list, ElemListElement_CreateBaseType(level, dec->name, resolvedPath,
        !           160:                                                            elem));
        !           161:         /* Do nothing. */
        !           162:       else
        !           163:         {
        !           164:           /* Search in tgt std elements. */
        !           165:           int xmlType; /* See parser.h */
        !           166:           for(xmlType=XHTML_TYPE; xmlType<Template_TYPE; xmlType++)
        !           167:             {
        !           168:               ElementType elType = {0,0};
        !           169:               char*       mappedName;
        !           170:               char       content;
        !           171:               ThotBool    checkProfile;
        !           172:               MapXMLElementType(xmlType, dec->name, &elType, &mappedName, &content,
        !           173:                                 &checkProfile, doc);
        !           174:               if (elType.ElTypeNum!=0)
        !           175:                 {
        !           176:                   if(TemplateCanInsertFirstChild(elType, elem, doc))
        !           177:                     DLList_Append(list, ElemListElement_CreateLanguageElement(level, elType,
        !           178:                                                                             resolvedPath, elem));
        !           179:                   break;
        !           180:                 }
        !           181:             }
        !           182:         }
1.1       kia       183:     }
                    184: }
                    185: 
                    186: /*----------------------------------------------------------------------
                    187:   FillInsertableElementFromElemAttribute
                    188:   Fill an element list with all possible elements from an attribute list.
                    189:   ----------------------------------------------------------------------*/
1.16      vatton    190: static void FillInsertableElementFromElemAttribute (XTigerTemplate t,
                    191:                                                     Element elem, Element refelem,
                    192:                                                     int attrib, DLList list, int level)
1.1       kia       193: {
1.25    ! kia       194:   ElementType     elType        = TtaGetElementType(elem);
1.21      vatton    195:   AttributeType   attributeType = {elType.ElSSchema, attrib};
1.25    ! kia       196:   Attribute       att           = TtaGetAttribute (elem, attributeType);
        !           197:   int             size          = TtaGetTextAttributeLength (att);
        !           198:   char*           types         = (char *) TtaGetMemory (size+1); 
1.6       vatton    199: 
1.1       kia       200:   TtaGiveTextAttributeValue (att, types, &size);
1.25    ! kia       201:   SearchSet       set           = Template_GetDeclarationSetFromNames(t, types, true);
1.14      kia       202:   ForwardIterator iter;
1.25    ! kia       203:   SearchSetNode   node;
1.14      kia       204:    
1.25    ! kia       205:   iter = SearchSet_GetForwardIterator(set);
        !           206:   ITERATOR_FOREACH(iter, SearchSetNode, node)
1.14      kia       207:     {
1.25    ! kia       208:       FillUnionResolvedPossibleElement(t, (Declaration)node->elem, refelem, NULL, list, level);
1.14      kia       209:     }
1.25    ! kia       210:   SearchSet_Destroy (set);
1.6       vatton    211:   TtaFreeMemory (types);
1.1       kia       212: }
                    213: #endif/* TEMPLATES */
                    214: 
                    215: /*----------------------------------------------------------------------
1.19      kia       216:   SortInsertableElemList
                    217:   Sort a list of KeywordHashMap<Declaration> to be user friendly
                    218:   First components and then XmlElements and sorted alphabeticaly.
                    219:   ----------------------------------------------------------------------*/
                    220: static int SortInsertableElemList(ElemListElement elem1 ,ElemListElement elem2)
                    221: {
                    222: #ifdef TEMPLATES
                    223:   if(elem1->typeClass==elem2->typeClass)
                    224:       return strcmp(ElemListElement_GetName(elem1),ElemListElement_GetName(elem2));
                    225:   else
                    226:     return elem1->typeClass - elem2->typeClass;
                    227: #else  /* TEMPLATES */
                    228:   return 0;
                    229: #endif /* TEMPLATES */
                    230: }
                    231: 
                    232: 
                    233: /*----------------------------------------------------------------------
1.1       kia       234:   FillInsertableElemList
                    235:   Fill an element list with all insertable elements (base element or
                    236:   XTiger comonent).
                    237:   ----------------------------------------------------------------------*/
1.21      vatton    238: void FillInsertableElemList (Document doc, Element el, DLList list)
1.1       kia       239: {
1.4       cvs       240: #ifdef TEMPLATES
1.21      vatton    241:   Element          child, elem;
                    242:   ElementType      elType, childType;
1.6       vatton    243:   XTigerTemplate   t;
1.4       cvs       244: #endif/* TEMPLATES */
1.2       cvs       245:   int level;
1.17      cvs       246:   ThotBool cont = TRUE;
1.2       cvs       247: 
1.22      vatton    248:   if (el)
1.21      vatton    249:     {
                    250:     if (doc == 0)
1.22      vatton    251:       doc = TtaGetDocument(el);
1.1       kia       252: 
                    253: #ifdef TEMPLATES
1.24      kia       254:     t = GetXTigerDocTemplate(doc);
1.2       cvs       255:     level = 0;
                    256:     cont = TRUE;
1.21      vatton    257:     elem = el;
1.15      kia       258:     // Process for each ancestor.
1.21      vatton    259:     while (elem && cont)
1.1       kia       260:     {
1.21      vatton    261:       elType = TtaGetElementType (elem);
                    262:       switch (elType.ElTypeNum)
1.15      kia       263:         {
1.1       kia       264:         case Template_EL_repeat:
                    265:           child = TtaGetFirstChild(elem);
                    266:           childType = TtaGetElementType(child);
1.21      vatton    267:           switch (childType.ElTypeNum)
1.1       kia       268:           {
                    269:             case Template_EL_useEl:
                    270:             case Template_EL_useSimple:
                    271:             case Template_EL_bag:
1.21      vatton    272:               FillInsertableElementFromElemAttribute(t, el, elem,
1.6       vatton    273:                                                      Template_ATTR_types, list, level);
1.1       kia       274:               break;
                    275:             default:
                    276:               break;
                    277:           }
1.21      vatton    278:           cont = FALSE;
1.1       kia       279:           break;
                    280:         case Template_EL_useEl:
                    281:           // Fill for xt:use only if have no child.
1.8       vatton    282:           if (TtaGetFirstChild(elem)==NULL){
1.21      vatton    283:             FillInsertableElementFromElemAttribute(t, el, elem,
1.6       vatton    284:                                                    Template_ATTR_types, list, level);
1.21      vatton    285:             cont = FALSE;
1.1       kia       286:           }
                    287:           break;
                    288:         case Template_EL_bag:
1.6       vatton    289:           FillInsertableElementFromElemAttribute(t, elem, elem,
                    290:                                                  Template_ATTR_types, list, level);
1.15      kia       291:           cont = FALSE;
1.1       kia       292:           break;
1.15      kia       293:         }
1.21      vatton    294:       elem = GetFirstTemplateParentElement (elem);
1.1       kia       295:       level ++;
1.15      kia       296:     }
                    297: #endif/* TEMPLATES */
1.21      vatton    298:     }
1.19      kia       299:   DLList_Sort(list, (Container_CompareFunction)SortInsertableElemList);
1.1       kia       300: }
                    301: 
                    302: /*----------------------------------------------------------------------
                    303:   InsertableElement_GetList
                    304:   Get the insertable element list for a document.
                    305:   @param doc Document
                    306:   @return The insertable element list or NULL.
                    307:   ----------------------------------------------------------------------*/
                    308: DLList InsertableElement_GetList(Document doc)
                    309: {
1.16      vatton    310:   InsertableElementList list;
                    311: 
                    312:   list = (InsertableElementList) HashMap_Get(InsertableElementMap, (void*)doc);
1.6       vatton    313:   if (list)
1.1       kia       314:     return list->list;
                    315:   else
                    316:     return NULL;
                    317: }
                    318: 
                    319: /*----------------------------------------------------------------------
                    320:   InsertableElement_Update
                    321:   Update the insertable element list for a document.
                    322:   @param el Selected element, cant be NULL.
                    323:   @param document Document, can be NULL.
                    324:   @return List of insertable elements.
                    325:   ----------------------------------------------------------------------*/
1.7       kia       326: DLList InsertableElement_Update(Document doc, Element el)
1.1       kia       327: {
1.2       cvs       328:   InsertableElementList list;
1.16      vatton    329: 
                    330:   if (doc == 0)
                    331:     doc= TtaGetDocument (el);
                    332:   list = (InsertableElementList) HashMap_Get (InsertableElementMap, (void*)doc);
                    333:   if (list == NULL)
1.1       kia       334:   {
1.16      vatton    335:     list = InsertableElementList_Create (0, DLList_Create());
                    336:     HashMap_Set (InsertableElementMap, (void*)doc, list);
1.1       kia       337:   }
1.7       kia       338:   
1.16      vatton    339:   DLList_Empty (list->list);
                    340:   FillInsertableElemList (doc, el, list->list);
1.7       kia       341:   list->elem = el;
1.19      kia       342:   return list->list;
                    343: }
1.7       kia       344: 
1.19      kia       345: /*----------------------------------------------------------------------
                    346:   InsertableElement_ComputeList
                    347:   Update a insertable element list for a document.
                    348:   @param el Selected element, cant be NULL.
                    349:   @param document Document, can be NULL.
                    350:   @return List of insertable elements.
                    351:   ----------------------------------------------------------------------*/
                    352: DLList InsertableElement_ComputeList(Document doc, Element el)
                    353: {
                    354:   DLList list = DLList_Create();
                    355:   FillInsertableElemList (doc, el, list);
                    356:   return list;
1.1       kia       357: }
                    358: 
1.19      kia       359: 
1.3       kia       360: /*----------------------------------------------------------------------
                    361:   InsertableElement_DoInsertElement
                    362:   Insert the specified element.
                    363:   @param el Element to insert (ElemListElement)
                    364:   ----------------------------------------------------------------------*/
1.16      vatton    365: void InsertableElement_DoInsertElement (void* el)
1.3       kia       366: {
1.16      vatton    367:   ElemListElement elem = (ElemListElement) el;
                    368:   Element         ref = elem->refElem;
                    369:   ElementType     refType = TtaGetElementType (ref);
                    370:   Document        doc = TtaGetDocument (ref);
                    371:   Element         newEl = NULL;
                    372:   SSchema         templateSSchema;
1.10      kia       373: 
1.6       vatton    374: #ifdef AMAYA_DEBUG
1.12      vatton    375:   printf("insert %s into %s\n", ElemListElement_GetName(elem),
1.16      vatton    376:          TtaGetElementTypeName (refType));
1.6       vatton    377: #endif /* AMAYA_DEBUG */
1.11      kia       378: 
                    379: #ifdef TEMPLATES
1.16      vatton    380:   templateSSchema = TtaGetSSchema ("Template", doc);
                    381:   if (templateSSchema && refType.ElSSchema == templateSSchema)
1.3       kia       382:   {
1.11      kia       383:     switch(refType.ElTypeNum)
                    384:     {
                    385:       case Template_EL_repeat:
                    386:         if (elem->typeClass==DefinedComponent)
1.16      vatton    387:           newEl = Template_InsertRepeatChild (doc, ref,
                    388:                                               (Declaration)elem->elem.component.declaration,
                    389:                                               -1);
1.11      kia       390:         break;
                    391:       case Template_EL_bag:
1.16      vatton    392:         newEl = Template_InsertBagChild (doc, ref,
1.18      kia       393:                                          (Declaration)elem->elem.component.declaration,
                    394:                                          FALSE);
1.11      kia       395:         break;
                    396:       default:
                    397:         break;
                    398:     }
                    399:   }
1.3       kia       400: #endif /* TEMPLATES */
1.11      kia       401: 
1.12      vatton    402:   if (newEl)
1.16      vatton    403:     TtaSelectElement (doc, newEl);
1.3       kia       404: }
1.18      kia       405: 
                    406: /*----------------------------------------------------------------------
                    407:   GetFirstChildElementTo
                    408:   Find and retrieve the first child of root element which is an ascendent
                    409:   of the leaf element.
                    410:   If leaf is a child of root, return leaf itself.
                    411:   ----------------------------------------------------------------------*/
                    412: static Element GetFirstChildElementTo(Element root, Element leaf)
                    413: {
                    414:   Element parent = TtaGetParent(leaf);
                    415:   if(root==0 || leaf==0 || parent==0)
                    416:     return 0;
                    417:   
                    418:   while(parent)
                    419:     {
                    420:       if(parent==root)
                    421:         return leaf;
                    422:       leaf = parent;
                    423:       parent = TtaGetParent(parent);
                    424:     }
                    425:   return 0;
                    426: }
                    427: 
                    428: /*----------------------------------------------------------------------
                    429:   InsertableElement_InsertElement
                    430:   Insert the specified element in the given document before or after the selection.
                    431:   \param el Element to insert (ElemListElement)
                    432:   \param before True if inserting before given element, false after.
                    433:   ----------------------------------------------------------------------*/
1.19      kia       434: Element InsertableElement_InsertElement (ElemListElement elem, ThotBool before)
1.18      kia       435: {
                    436: #ifdef TEMPLATES
                    437:   Element         ref = elem->refElem;
                    438:   ElementType     refType = TtaGetElementType (ref);
                    439:   Document        doc = TtaGetDocument (ref);
                    440:   Element         newEl = NULL, sibling = NULL;
                    441:   SSchema         templateSSchema;
1.19      kia       442:   Element         sel;
                    443:   int             car1, car2;
                    444:   XTigerTemplate  t = NULL;
                    445:   Declaration     dec = NULL;
1.18      kia       446: 
                    447:   templateSSchema = TtaGetSSchema ("Template", doc);
                    448: 
                    449:   if (templateSSchema && refType.ElSSchema == templateSSchema)
                    450:   {
                    451:     switch(refType.ElTypeNum)
                    452:     {
                    453:       case Template_EL_repeat:
1.19      kia       454:         if(elem->typeClass==DefinedComponent)
                    455:           dec = (Declaration)elem->elem.component.declaration;
                    456:         else if (elem->typeClass==LanguageElement)
                    457:           {
                    458:             t = GetXTigerDocTemplate(TtaGetDocument(elem->refElem));
                    459:             if (t)
                    460:                 dec = Template_GetElementDeclaration(t, ElemListElement_GetName(elem));
                    461:           }
                    462:         if (dec)
1.18      kia       463:           {
1.19      kia       464:             
1.18      kia       465:             TtaGiveFirstSelectedElement(doc, &sel, &car1, &car2);
                    466:             sibling = GetFirstChildElementTo(ref, sel);
                    467:             if(sibling)
                    468:               {
                    469:                 if(before)
                    470:                   TtaPreviousSibling(&sibling);
1.19      kia       471:                 newEl = Template_InsertRepeatChildAfter (doc, ref, dec, sibling);
1.18      kia       472:               }
                    473:           }
                    474:         break;
                    475:       case Template_EL_bag:
1.19      kia       476:         if(elem->typeClass==DefinedComponent)
                    477:           dec = (Declaration)elem->elem.component.declaration;
                    478:         else if (elem->typeClass==LanguageElement)
                    479:           {
                    480:             t = GetXTigerDocTemplate(TtaGetDocument(elem->refElem));
                    481:             if (t)
                    482:                 dec = Template_GetElementDeclaration(t, ElemListElement_GetName(elem));
                    483:           }
                    484:         if (dec)
                    485:             newEl = Template_InsertBagChild (doc, ref, dec, before);           
1.18      kia       486:         break;
                    487:       default:
                    488:         break;
                    489:     }
                    490:   }
1.19      kia       491:   return newEl;
                    492: #else /* TEMPLATES */
                    493:   return NULL;
1.18      kia       494: #endif /* TEMPLATES */
                    495: }
                    496: 
                    497: 
                    498: /*----------------------------------------------------------------------
                    499:   InsertableElement_QueryInsertElement(void* el, ThotBool bAfter)
                    500:   Do a InsertableElement_InsertElement with undo/redo management.
                    501:   ----------------------------------------------------------------------*/
1.19      kia       502: void InsertableElement_QueryInsertElement(ElemListElement elem, ThotBool before)
1.18      kia       503: {
                    504: #ifdef TEMPLATES
1.19      kia       505:   Element     elSel, newEl, firstEl;
                    506:   int         firstSel, lastSel;
                    507:   Document    doc = TtaGetDocument(elem->refElem);
                    508:   
                    509:   ThotBool    oldStructureChecking;
                    510:   DisplayMode dispMode;
                    511:   
                    512:   // If document is readonly, dont do anything
                    513:   if (!TtaGetDocumentAccessMode(doc))
                    514:     return;
                    515: 
                    516:   TtaGiveFirstSelectedElement(doc, &elSel, &firstSel, &lastSel);
                    517: 
                    518:   
                    519:   dispMode = TtaGetDisplayMode (doc);
                    520:   if (dispMode == DisplayImmediately)
                    521:     /* don't set NoComputedDisplay
                    522:        -> it breaks down views formatting when Enter generates new elements  */
                    523:     TtaSetDisplayMode (doc, DeferredDisplay);
                    524: 
                    525:   /* Prepare insertion.*/          
                    526:   oldStructureChecking = TtaGetStructureChecking (doc);
                    527:   TtaSetStructureChecking (FALSE, doc);
1.20      vatton    528:   TtaOpenUndoSequence (doc, NULL, NULL, 0, 0);
1.19      kia       529:   
                    530:   /* Do the insertion */
                    531:   newEl = InsertableElement_InsertElement (elem, before);
                    532:   
                    533:   /* Finish insertion.*/
                    534:   TtaCloseUndoSequence (doc);
                    535:   TtaSetDocumentModified (doc);
                    536:   TtaSetStructureChecking (oldStructureChecking, doc);
                    537:   // restore the display
                    538:   TtaSetDisplayMode (doc, dispMode);
                    539: 
1.20      vatton    540:   if (newEl)
1.19      kia       541:     {
1.20      vatton    542:       firstEl = GetFirstEditableElement (newEl);
                    543:       if (firstEl)
                    544:         {
                    545:           TtaSelectElement (doc, firstEl);
                    546:           TtaSetStatusSelectedElement (doc, 1, firstEl);
                    547:         }
                    548:       else
                    549:         {
                    550:           TtaSelectElement (doc, newEl);
                    551:           TtaSetStatusSelectedElement (doc, 1, newEl);
                    552:         }
1.19      kia       553:     }
1.18      kia       554: #endif /* TEMPLATES */
                    555: }

Webmaster