Annotation of 2001/DOM-Test-Suite/ecmascript/DOMTestCase.js, revision 1.37

1.1       dom-ts-4    1: /*
1.32      dom-ts-4    2: Copyright (c) 2001-2004 World Wide Web Consortium,
1.1       dom-ts-4    3: (Massachusetts Institute of Technology, Institut National de
                      4: Recherche en Informatique et en Automatique, Keio University). All
                      5: Rights Reserved. This program is distributed under the W3C's Software
                      6: Intellectual Property License. This program is distributed in the
                      7: hope that it will be useful, but WITHOUT ANY WARRANTY; without even
                      8: the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
                      9: PURPOSE.
                     10: See W3C License http://www.w3.org/Consortium/Legal/ for more details.
                     11: */
1.3       dom-ts-4   12:   function assertSize(descr, expected, actual) {
                     13:     var actualSize;
                     14:     actualSize = actual.length;
                     15:     assertEquals(descr, expected, actualSize);
                     16:   }
1.15      dom-ts-4   17: 
1.32      dom-ts-4   18:   function assertEqualsAutoCase(context, descr, expected, actual) {
                     19:        if (builder.contentType == "text/html") {
                     20:            if(context == "attribute") {
                     21:                assertEquals(descr, expected.toLowerCase(), actual.toLowerCase());
                     22:            } else {
                     23:                assertEquals(descr, expected.toUpperCase(), actual);
                     24:            }
                     25:        } else {
                     26:                assertEquals(descr, expected, actual); 
                     27:        }
                     28:   }
1.9       dom-ts-4   29:   
1.32      dom-ts-4   30: 
                     31:   function assertEqualsCollectionAutoCase(context, descr, expected, actual) {
                     32:     //
                     33:     //  if they aren't the same size, they aren't equal
                     34:     assertEquals(descr, expected.length, actual.length);
                     35:     
                     36:     //
                     37:     //  if there length is the same, then every entry in the expected list
                     38:     //     must appear once and only once in the actual list
                     39:     var expectedLen = expected.length;
                     40:     var expectedValue;
                     41:     var actualLen = actual.length;
                     42:     var i;
                     43:     var j;
                     44:     var matches;
                     45:     for(i = 0; i < expectedLen; i++) {
                     46:         matches = 0;
                     47:         expectedValue = expected[i];
                     48:         for(j = 0; j < actualLen; j++) {
                     49:                if (builder.contentType == "text/html") {
                     50:                        if (context == "attribute") {
                     51:                                if (expectedValue.toLowerCase() == actual[j].toLowerCase()) {
                     52:                                        matches++;
                     53:                                }
                     54:                        } else {
                     55:                                if (expectedValue.toUpperCase() == actual[j]) {
                     56:                                        matches++;
                     57:                                }
                     58:                        }
                     59:                } else {
                     60:                if(expectedValue == actual[j]) {
                     61:                        matches++;
                     62:                 }
                     63:             }
                     64:         }
                     65:         if(matches == 0) {
                     66:             assert(descr + ": No match found for " + expectedValue,false);
                     67:         }
                     68:         if(matches > 1) {
                     69:             assert(descr + ": Multiple matches found for " + expectedValue, false);
                     70:         }
                     71:     }
                     72:   }
                     73: 
1.13      dom-ts-4   74:   function assertEqualsCollection(descr, expected, actual) {
1.3       dom-ts-4   75:     //
                     76:     //  if they aren't the same size, they aren't equal
1.17      dom-ts-4   77:     assertEquals(descr, expected.length, actual.length);
1.3       dom-ts-4   78:     //
                     79:     //  if there length is the same, then every entry in the expected list
                     80:     //     must appear once and only once in the actual list
                     81:     var expectedLen = expected.length;
                     82:     var expectedValue;
                     83:     var actualLen = actual.length;
                     84:     var i;
                     85:     var j;
                     86:     var matches;
                     87:     for(i = 0; i < expectedLen; i++) {
                     88:         matches = 0;
                     89:         expectedValue = expected[i];
                     90:         for(j = 0; j < actualLen; j++) {
                     91:             if(expectedValue == actual[j]) {
                     92:                 matches++;
                     93:             }
                     94:         }
                     95:         if(matches == 0) {
1.17      dom-ts-4   96:             assert(descr + ": No match found for " + expectedValue,false);
1.3       dom-ts-4   97:         }
                     98:         if(matches > 1) {
1.17      dom-ts-4   99:             assert(descr + ": Multiple matches found for " + expectedValue, false);
1.3       dom-ts-4  100:         }
                    101:     }
                    102:   }
                    103: 
                    104: 
1.32      dom-ts-4  105:   function assertEqualsListAutoCase(context, descr, expected, actual) {
                    106:        var minLength = expected.length;
                    107:        if (actual.length < minLength) {
                    108:            minLength = actual.length;
                    109:        }
                    110:     //
                    111:     for(var i = 0; i < minLength; i++) {
                    112:                assertEqualsAutoCase(context, descr, expected[i], actual[i]);
                    113:     }
                    114:     //
                    115:     //  if they aren't the same size, they aren't equal
                    116:     assertEquals(descr, expected.length, actual.length);
                    117:   }
                    118: 
                    119: 
1.13      dom-ts-4  120:   function assertEqualsList(descr, expected, actual) {
1.27      dom-ts-4  121:        var minLength = expected.length;
                    122:        if (actual.length < minLength) {
                    123:            minLength = actual.length;
                    124:        }
1.3       dom-ts-4  125:     //
1.27      dom-ts-4  126:     for(var i = 0; i < minLength; i++) {
1.3       dom-ts-4  127:         if(expected[i] != actual[i]) {
1.17      dom-ts-4  128:                        assertEquals(descr, expected[i], actual[i]);
1.3       dom-ts-4  129:         }
                    130:     }
1.27      dom-ts-4  131:     //
                    132:     //  if they aren't the same size, they aren't equal
                    133:     assertEquals(descr, expected.length, actual.length);
1.3       dom-ts-4  134:   }
                    135: 
                    136:   function assertInstanceOf(descr, type, obj) {
                    137:     if(type == "Attr") {
1.17      dom-ts-4  138:         assertEquals(descr,2,obj.nodeType);
1.3       dom-ts-4  139:         var specd = obj.specified;
                    140:     }
                    141:   }
                    142: 
                    143:   function assertSame(descr, expected, actual) {
                    144:     if(expected != actual) {
1.17      dom-ts-4  145:         assertEquals(descr, expected.nodeType, actual.nodeType);
                    146:         assertEquals(descr, expected.nodeValue, actual.nodeValue);
1.3       dom-ts-4  147:     }
                    148:   }
                    149: 
1.16      dom-ts-4  150:   function assertURIEquals(assertID, scheme, path, host, file, name, query, fragment, isAbsolute, actual) {
1.7       dom-ts-4  151:     //
                    152:     //  URI must be non-null
1.17      dom-ts-4  153:     assertNotNull(assertID, actual);
1.7       dom-ts-4  154: 
                    155:     var uri = actual;
                    156: 
                    157:     var lastPound = actual.lastIndexOf("#");
                    158:     var actualFragment = "";
                    159:     if(lastPound != -1) {
                    160:         //
                    161:         //   substring before pound
                    162:         //
                    163:         uri = actual.substring(0,lastPound);
                    164:         actualFragment = actual.substring(lastPound+1);
                    165:     }
1.17      dom-ts-4  166:     if(fragment != null) assertEquals(assertID,fragment, actualFragment);
1.7       dom-ts-4  167: 
                    168:     var lastQuestion = uri.lastIndexOf("?");
                    169:     var actualQuery = "";
                    170:     if(lastQuestion != -1) {
                    171:         //
                    172:         //   substring before pound
                    173:         //
                    174:         uri = actual.substring(0,lastQuestion);
                    175:         actualQuery = actual.substring(lastQuestion+1);
                    176:     }
1.17      dom-ts-4  177:     if(query != null) assertEquals(assertID, query, actualQuery);
1.7       dom-ts-4  178: 
                    179:     var firstColon = uri.indexOf(":");
                    180:     var firstSlash = uri.indexOf("/");
                    181:     var actualPath = uri;
                    182:     var actualScheme = "";
                    183:     if(firstColon != -1 && firstColon < firstSlash) {
                    184:         actualScheme = uri.substring(0,firstColon);
                    185:         actualPath = uri.substring(firstColon + 1);
                    186:     }
                    187: 
                    188:     if(scheme != null) {
1.17      dom-ts-4  189:         assertEquals(assertID, scheme, actualScheme);
1.7       dom-ts-4  190:     }
                    191: 
                    192:     if(path != null) {
1.17      dom-ts-4  193:         assertEquals(assertID, path, actualPath);
1.7       dom-ts-4  194:     }
                    195: 
                    196:     if(host != null) {
                    197:         var actualHost = "";
1.16      dom-ts-4  198:         if(actualPath.substring(0,2) == "//") {
1.8       dom-ts-4  199:             var termSlash = actualPath.substring(2).indexOf("/") + 2;
1.7       dom-ts-4  200:             actualHost = actualPath.substring(0,termSlash);
                    201:         }
1.17      dom-ts-4  202:         assertEquals(assertID, host, actualHost);
1.7       dom-ts-4  203:     }
                    204: 
1.16      dom-ts-4  205:     if(file != null || name != null) {
1.7       dom-ts-4  206:         var actualFile = actualPath;
                    207:         var finalSlash = actualPath.lastIndexOf("/");
                    208:         if(finalSlash != -1) {
                    209:             actualFile = actualPath.substring(finalSlash+1);
                    210:         }
1.16      dom-ts-4  211:         if (file != null) {
1.17      dom-ts-4  212:             assertEquals(assertID, file, actualFile);
1.16      dom-ts-4  213:         }
                    214:         if (name != null) {
                    215:             var actualName = actualFile;
                    216:             var finalDot = actualFile.lastIndexOf(".");
                    217:             if (finalDot != -1) {
                    218:                 actualName = actualName.substring(0, finalDot);
                    219:             }
1.17      dom-ts-4  220:             assertEquals(assertID, name, actualName);
1.16      dom-ts-4  221:         }
1.7       dom-ts-4  222:     }
                    223: 
                    224:     if(isAbsolute != null) {
1.17      dom-ts-4  225:         assertEquals(assertID, isAbsolute, actualPath.substring(0,1) == "/");
1.13      dom-ts-4  226:     }
                    227:   }
                    228: 
1.29      dom-ts-4  229: 
                    230: // size() used by assertSize element
                    231: function size(collection)
                    232: {
                    233:   return collection.length;
                    234: }
                    235: 
1.30      dom-ts-4  236: function same(expected, actual)
                    237: {
                    238:   return expected === actual;
                    239: }
                    240: 
1.18      dom-ts-4  241: function getSuffix(contentType) {
                    242:     switch(contentType) {
                    243:         case "text/html":
                    244:         return ".html";
                    245: 
                    246:         case "text/xml":
                    247:         return ".xml";
                    248: 
                    249:         case "application/xhtml+xml":
                    250:         return ".xhtml";
                    251: 
                    252:         case "image/svg+xml":
                    253:         return ".svg";
                    254: 
                    255:         case "text/mathml":
                    256:         return ".mml";
                    257:     }
                    258:     return ".html";
                    259: }
                    260: 
1.34      dom-ts-4  261: function equalsAutoCase(context, expected, actual) {
                    262:        if (builder.contentType == "text/html") {
                    263:                if (content == "attribute") {
                    264:                        return expected.toLowerCase() == actual;
                    265:                }
                    266:                return expected.toUpperCase() == actual;
                    267:        }
                    268:        return expected == actual;
                    269: }
                    270: 
                    271: function catchInitializationError(blder, ex) {
                    272:        blder.initializationError = ex;
                    273:        blder.initializationFatalError = ex;
                    274: }
                    275: 
                    276: function checkInitialization(blder, testname) {
                    277:     if (blder.initializationError != null) {
                    278:         if (blder.skipIncompatibleTests) {
                    279:                info(testname + " not run:" + blder.initializationError);
                    280:                return blder.initializationError;
                    281:         } else {
                    282:                //
                    283:                //   if an exception was thrown
                    284:                //        rethrow it and do not run the test
                    285:             if (blder.initializationFatalError != null) {
                    286:                        throw blder.initializationFatalError;
                    287:                } else {
                    288:                        //
                    289:                        //   might be recoverable, warn but continue the test
                    290:                        warn(testname + ": " +  blder.initializationError);
                    291:                }
                    292:         }
                    293:     }
                    294:     return null;
                    295: }
                    296: 
                    297: 
1.35      dom-ts-4  298: function EventMonitor() {
                    299:   this.atEvents = new Array();
                    300:   this.bubbledEvents = new Array();
                    301:   this.capturedEvents = new Array();
                    302:   this.allEvents = new Array();
                    303: }
                    304: 
                    305: EventMonitor.prototype.handleEvent = function(evt) {
                    306:     switch(evt.eventPhase) {
                    307:        case 1:
                    308:        monitor.capturedEvents[monitor.capturedEvents.length] = evt;
                    309:        break;
                    310:        
                    311:        case 2:
                    312:        monitor.atEvents[monitor.atEvents.length] = evt;
                    313:        break;
                    314: 
                    315:        case 3:
                    316:        monitor.bubbledEvents[monitor.bubbledEvents.length] = evt;
                    317:        break;
                    318:     }
                    319:     monitor.allEvents[monitor.allEvents.length] = evt;
                    320: }
                    321: 
1.36      dom-ts-4  322: function DOMErrorImpl(err) {
                    323:   this.severity = err.severity;
                    324:   this.message = err.message;
                    325:   this.type = err.type;
                    326:   this.relatedException = err.relatedException;
                    327:   this.relatedData = err.relatedData;
                    328:   this.location = err.location;
                    329: }
                    330: 
                    331: 
                    332: 
                    333: function DOMErrorMonitor() {
                    334:   this.allErrors = new Array();
                    335: }
                    336: 
                    337: DOMErrorMonitor.prototype.handleError = function(err) {
                    338:     this.allErrors[this.allErrors.length] = new DOMErrorImpl(err);
                    339: }
                    340: 
                    341: DOMErrorMonitor.prototype.assertLowerSeverity = function(id, severity) {
                    342:     var i;
                    343:     for (i = 0; i < this.allErrors.length; i++) {
                    344:         if (this.allErrors[i].severity >= severity) {
                    345:            assertEquals(id, severity - 1, this.allErrors[i].severity);
                    346:         }
                    347:     }
                    348: }
                    349: 
                    350: function UserDataNotification(operation, key, data, src, dst) {
                    351:     this.operation = operation;
                    352:     this.key = key;
                    353:     this.data = data;
                    354:     this.src = src;
                    355:     this.dst = dst;
                    356: }
                    357: 
                    358: function UserDataMonitor() {
                    359:        this.allNotifications = new Array();
                    360: }
                    361: 
                    362: UserDataMonitor.prototype.handle = function(operation, key, data, src, dst) {
                    363:     this.allNotifications[this.allNotifications.length] =
                    364:          new UserDataNotification(operation, key, data, src, dst);
                    365: }
                    366: 
1.35      dom-ts-4  367: 
                    368: 
1.17      dom-ts-4  369: function IFrameBuilder() {
1.18      dom-ts-4  370:     this.contentType = "text/html";
1.26      dom-ts-4  371:     this.supportedContentTypes = [ "text/html", 
                    372:         "text/xml", 
                    373:         "image/svg+xml", 
                    374:         "application/xhtml+xml",
                    375:         "text/mathml" ];    
1.18      dom-ts-4  376: 
                    377:     this.supportsAsyncChange = false;
1.26      dom-ts-4  378:     this.async = true;
1.18      dom-ts-4  379:     this.fixedAttributeNames = [
                    380:         "validating",  "expandEntityReferences", "coalescing", 
1.34      dom-ts-4  381:         "signed", "hasNullString", "ignoringElementContentWhitespace", "namespaceAware", "ignoringComments"];
1.18      dom-ts-4  382: 
1.31      dom-ts-4  383:     this.fixedAttributeValues = [false,  true, false, true, true , false, false, true ];
1.18      dom-ts-4  384:     this.configurableAttributeNames = [ ];
                    385:     this.configurableAttributeValues = [ ];
1.34      dom-ts-4  386:     this.initializationError = null;
                    387:     this.initializationFatalError = null;
                    388:     this.skipIncompatibleTests = false;
1.17      dom-ts-4  389: }
1.12      dom-ts-4  390: 
1.18      dom-ts-4  391: IFrameBuilder.prototype.hasFeature = function(feature, version) {
                    392:     return document.implementation.hasFeature(feature, version);
                    393: }
                    394: 
1.23      dom-ts-4  395: IFrameBuilder.prototype.getImplementation = function() {
                    396:     return document.implementation;
                    397: }
                    398: 
1.31      dom-ts-4  399: IFrameBuilder.prototype.setContentType = function(contentType) {
                    400:     this.contentType = contentType;
                    401:     if (contentType == "text/html") {
1.34      dom-ts-4  402:         this.fixedAttributeValues[6] = false;
1.31      dom-ts-4  403:     } else {
1.34      dom-ts-4  404:         this.fixedAttributeValues[6] = true;
1.31      dom-ts-4  405:     }
                    406: }
                    407: 
                    408: 
1.18      dom-ts-4  409: 
1.17      dom-ts-4  410: IFrameBuilder.prototype.preload = function(frame, varname, url) {
1.34      dom-ts-4  411:   if (this.contentType == "text/html" || this.contentType == "application/xhtml+xml") {
                    412:        if (url.substring(0,5) == "staff" || url == "nodtdstaff" || url == "datatype_normalization") {
1.26      dom-ts-4  413:        throw "Tests using staff or nodtdstaff are not supported by HTML processors";
                    414:        }  
1.18      dom-ts-4  415:   }
1.26      dom-ts-4  416:   var iframe = document.createElement("iframe");
                    417:   var srcname = url + getSuffix(this.contentType);
                    418:   iframe.setAttribute("name", srcname);
                    419:   iframe.setAttribute("src", fileBase + srcname);
                    420:   document.getElementsByTagName("body").item(0).appendChild(iframe);
                    421:   return 0; 
1.17      dom-ts-4  422: }
1.9       dom-ts-4  423: 
1.17      dom-ts-4  424: IFrameBuilder.prototype.load = function(frame, varname, url) {
1.26      dom-ts-4  425:        if (this.contentType == "text/html") {
                    426:        return frame.document;
                    427:     }
                    428:     var name = url + getSuffix(this.contentType);
                    429:     var iframes = document.getElementsByTagName("iframe");
                    430:     for(var i = 0; i < iframes.length; i++) {
                    431:        if (iframes.item(i).getAttribute("name") == name) {
1.33      dom-ts-4  432:            var item = iframes.item(i);
                    433:            if (typeof(item.contentDocument) != 'undefined') {
                    434:                return item.contentDocument;
                    435:            }
                    436:            if (typeof(item.document) != 'undefined') {
                    437:                   return item.document;
                    438:            }
                    439:            return null;
1.26      dom-ts-4  440:        }
                    441:     }
                    442:     return null;
1.17      dom-ts-4  443: }
1.9       dom-ts-4  444: 
1.17      dom-ts-4  445: IFrameBuilder.prototype.getImplementationAttribute = function(attr) {
1.18      dom-ts-4  446:     for (var i = 0; i < this.fixedAttributeNames.length; i++) {
                    447:         if (this.fixedAttributeNames[i] == attr) {
                    448:             return this.fixedAttributeValues[i];
1.15      dom-ts-4  449:         }
1.9       dom-ts-4  450:     }
1.18      dom-ts-4  451:     throw "Unrecognized implementation attribute: " + attr;
1.17      dom-ts-4  452: }
1.9       dom-ts-4  453: 
1.5       dom-ts-4  454: 
1.1       dom-ts-4  455: 
1.18      dom-ts-4  456: IFrameBuilder.prototype.setImplementationAttribute = function(attribute, value) {
                    457:     var supported = this.getImplementationAttribute(attribute);
                    458:     if (supported != value) {
1.34      dom-ts-4  459:         this.initializationError = "IFrame loader does not support " + attribute + "=" + value;
1.18      dom-ts-4  460:     }
                    461: }
                    462: 
                    463: 
1.34      dom-ts-4  464: IFrameBuilder.prototype.canSetImplementationAttribute = function(attribute, value) {
                    465:     var supported = this.getImplementationAttribute(attribute);
                    466:     return (supported == value);
                    467: }
                    468: 
1.22      dom-ts-4  469: 
                    470: 
1.20      dom-ts-4  471: function SVGPluginBuilder() {
                    472:     this.contentType = "image/svg+xml";
                    473:     this.supportedContentTypes = [ "image/svg+xml" ];
                    474: 
                    475:     this.supportsAsyncChange = false;
                    476:     this.async = true;
                    477:     this.fixedAttributeNames = [
                    478:         "validating",  "expandEntityReferences", "coalescing", 
1.31      dom-ts-4  479:         "signed", "hasNullString", "ignoringElementContentWhitespace", "namespaceAware", "ignoringComments"];
1.20      dom-ts-4  480: 
1.34      dom-ts-4  481:     this.fixedAttributeValues = [false,  true, false, true, true , false, true, false ];
1.20      dom-ts-4  482:     this.configurableAttributeNames = [ ];
                    483:     this.configurableAttributeValues = [ ];
1.34      dom-ts-4  484:     this.initializationError = null;
                    485:     this.initializationFatalError = null;
                    486:     this.skipIncompatibleTests = false;
1.20      dom-ts-4  487: }
                    488: 
                    489: SVGPluginBuilder.prototype.hasFeature = function(feature, version) {
                    490:     if (feature == "XML") {
                    491:         if (version == null || version == "1.0" || version == "2.0") {
                    492:             return true;
                    493:         }
                    494:     }
1.33      dom-ts-4  495:     return false;
1.20      dom-ts-4  496: }
                    497: 
1.31      dom-ts-4  498: SVGPluginBuilder.prototype.setContentType = function(contentType) {
                    499:     this.contentType = contentType;
                    500: }
                    501: 
1.23      dom-ts-4  502: SVGPluginBuilder.prototype.getImplementation = function() {
                    503:   var embed = document.createElement("embed");
                    504:   embed.src = fileBase + url + getSuffix(this.contentType);
                    505:   embed.height = 100;
                    506:   embed.width = 100;
                    507:   embed.type = "image/svg+xml";
                    508:   embed.id = varname;
                    509:   var child = document.documentElement.firstChild;
                    510:   while(child != null) {
                    511:       if (child.nodeName != null && child.nodeName.toUpperCase() == "BODY") {
                    512:           child.appendChild(embed);
                    513:           return child.getSVGDocument.implementation;
                    514:       }
                    515:       child = child.nextSibling;
                    516:   }
                    517:   return null;
                    518: }
                    519: 
1.20      dom-ts-4  520: var svgloadcount = 0;
                    521: function SVGPluginBuilder_pollreadystate() {
                    522:   var newCount = 0;
                    523:   var child = document.documentElement.firstChild;
                    524:   while(child != null) {
                    525:       if (child.nodeName != null && child.nodeName.toUpperCase() == "BODY") {
                    526:           var grand = child.firstChild;
                    527:           while (grand != null) {
                    528:              if (grand.nodeName.toUpperCase() == 'EMBED' && grand.readystate == 4) {
                    529:                 newCount++;
                    530:              }
                    531:              grand = grand.nextSibling;
                    532:           }
                    533:           break;
                    534:       }
                    535:       child = child.nextSibling;
                    536:   }
                    537:   if (newCount > svgloadcount) {
                    538:     svgloadcount++;
                    539:     loadComplete();
                    540:     if (setUpPageStatus == 'complete') {
                    541:         return;
                    542:     }
                    543:   }
                    544:   setTimeout(SVGPluginBuilder_pollreadystate, 100);
                    545: }
                    546: 
                    547: SVGPluginBuilder.prototype.preload = function(frame, varname, url) {
                    548:   var embed = document.createElement("embed");
                    549:   embed.src = fileBase + url + getSuffix(this.contentType);
                    550:   embed.height = 100;
                    551:   embed.width = 100;
                    552:   embed.type = "image/svg+xml";
                    553:   embed.id = varname;
                    554:   var child = document.documentElement.firstChild;
                    555:   while(child != null) {
                    556:       if (child.nodeName != null && child.nodeName.toUpperCase() == "BODY") {
                    557:           child.appendChild(embed);
                    558:           break;
                    559:       }
                    560:       child = child.nextSibling;
                    561:   }
                    562:   //
                    563:   //   if unable to monitor ready state change then
                    564:   //     check if load is complete every in 0.1 second
                    565:   setTimeout(SVGPluginBuilder_pollreadystate , 100);
                    566:   return 0;
                    567: }
                    568: 
                    569: SVGPluginBuilder.prototype.load = function(frame, varname, url) {
                    570:   var child = document.documentElement.firstChild;
                    571:   while(child != null) {
                    572:       if (child.nodeName != null && child.nodeName.toUpperCase() == "BODY") {
                    573:                  var grand = child.firstChild;
                    574:                  while (grand != null) {
                    575:                        if (grand.id == varname) {
                    576:                                return grand.getSVGDocument();
                    577:                        }
                    578:                        grand = grand.nextSibling;
                    579:                  }
                    580:          }
                    581:       child = child.nextSibling;
                    582:    }
                    583:    return null;
                    584: }
                    585: 
                    586: SVGPluginBuilder.prototype.getImplementationAttribute = function(attr) {
                    587:     for (var i = 0; i < this.fixedAttributeNames.length; i++) {
                    588:         if (this.fixedAttributeNames[i] == attr) {
                    589:             return this.fixedAttributeValues[i];
                    590:         }
                    591:     }
                    592:     throw "Unrecognized implementation attribute: " + attr;
                    593: }
                    594: 
                    595: 
                    596: SVGPluginBuilder.prototype.setImplementationAttribute = function(attribute, value) {
                    597:     var supported = this.getImplementationAttribute(attribute);
                    598:     if (supported != value) {
1.34      dom-ts-4  599:         this.initializationError = "SVG Plugin loader does not support " + attribute + "=" + value;
1.20      dom-ts-4  600:     }
                    601: }
                    602: 
1.34      dom-ts-4  603: SVGPluginBuilder.prototype.canSetImplementationAttribute = function(attribute, value) {
                    604:     var supported = this.getImplementationAttribute(attribute);
                    605:     return (supported == value);
                    606: }
1.20      dom-ts-4  607: 
                    608: 
1.22      dom-ts-4  609: 
                    610: 
1.18      dom-ts-4  611: function MSXMLBuilder(progID) {
                    612:     this.progID = progID;
                    613:     this.configurableAttributeNames = [
                    614:         "validating", "ignoringElementContentWhitespace"];
                    615:     this.configurableAttributeValues = [ false, false ];
                    616:     this.fixedAttributeNames = [ "signed", "hasNullString", 
1.31      dom-ts-4  617:         "expandEntityReferences", "coalescing", "namespaceAware", "ignoringComments" ];
                    618:     this.fixedAttributeValues = [ true, true, false, false, false, false ];
1.18      dom-ts-4  619: 
                    620:     this.contentType = "text/xml";
                    621:     this.supportedContentTypes = [ 
                    622:         "text/xml", 
                    623:         "image/svg+xml", 
                    624:         "application/xhtml+xml",
                    625:         "text/mathml" ];
                    626: 
                    627:     this.async = false;
                    628:     this.supportsAsyncChange = true;
                    629:     this.parser = null;
1.34      dom-ts-4  630:     this.initializationError = null;
                    631:     this.initializationFatalError = null;
                    632:     this.skipIncompatibleTests = false;
1.18      dom-ts-4  633: }
                    634: 
                    635: MSXMLBuilder.prototype.createMSXML = function() {
1.19      dom-ts-4  636:     var parser = new ActiveXObject(this.progID);
1.18      dom-ts-4  637:     parser.async = this.async;
                    638:     parser.preserveWhiteSpace = !this.configurableAttributeValues[1];
                    639:     parser.validateOnParse = this.configurableAttributeValues[0];
                    640:     return parser;
                    641:   }
1.31      dom-ts-4  642:   
                    643: MSXMLBuilder.prototype.setContentType = function(contentType) {
                    644:     this.contentType = contentType;
                    645: }
                    646:   
1.18      dom-ts-4  647: 
                    648: MSXMLBuilder.prototype.preload = function(frame, varname, url) {
                    649:   if (this.async) {
                    650:      this.parser = this.createMSXML();
                    651:      parser.async = true;
                    652:      parser.onreadystatechange = MSXMLBuilder_onreadystatechange;
                    653:      parser.load(fileBase + url + getSuffix(this.contentType));
                    654:      if (parser.readystate != 4) {
                    655:         return 0;
                    656:      }
                    657:   }
                    658:   return 1;
                    659: }
                    660: 
                    661: MSXMLBuilder.prototype.load = function(frame, varname, url) {
1.19      dom-ts-4  662:     var parser = this.createMSXML();
1.18      dom-ts-4  663:        if(!parser.load(fileBase + url + getSuffix(this.contentType))) {
                    664:                throw parser.parseError.reason;
                    665:        }
                    666:     //
                    667:     //   if the first child of the document is a PI representing
                    668:     //      the XML Declaration, remove it from the tree.
                    669:     //
                    670:     //   According to the DOM FAQ, this behavior is not wrong,
                    671:     //      but the tests are written assuming that it is not there.
                    672:     //
                    673:     var xmlDecl = parser.firstChild;
                    674:     if(xmlDecl != null && xmlDecl.nodeType == 7 && xmlDecl.target.toLowerCase() == "xml") {
                    675:         parser.removeChild(xmlDecl);
                    676:     }
                    677:        return parser;
                    678: }
                    679: 
                    680: MSXMLBuilder.prototype.getImplementationAttribute = function(attr) {
                    681:     var i;
                    682:     for (i = 0; i < this.fixedAttributeNames.length; i++) {
                    683:         if (this.fixedAttributeNames[i] == attr) {
                    684:             return this.fixedAttributeValues[i];
                    685:         }
                    686:     }
                    687: 
                    688:     for (i = 0; i < this.configurableAttributeNames.length; i++) {
                    689:         if (this.configurableAttributeNames[i] == attr) {
                    690:             return this.configurableAttributeValues[i];
                    691:         }
                    692:     }
                    693: 
                    694:     throw "Unrecognized implementation attribute: " + attr;
                    695: }
                    696: 
                    697: 
                    698: MSXMLBuilder.prototype.setImplementationAttribute = function(attribute, value) {
                    699:     var i;
                    700:     for (i = 0; i < this.fixedAttributeNames.length; i++) {
1.19      dom-ts-4  701:         if (this.fixedAttributeNames[i] == attribute) {
1.18      dom-ts-4  702:             if (this.fixedAttributeValues[i] != value) {
1.34      dom-ts-4  703:                 this.initializationError = "MSXML does not support " + attribute + "=" + value;
1.18      dom-ts-4  704:             }
                    705:             return;
                    706:         }
                    707:     }
                    708:     for (i = 0; i < this.configurableAttributeNames.length; i++) {
                    709:         if (this.configurableAttributeNames[i] == attribute) {
                    710:             this.configurableAttributeValues[i] = value;
                    711:             return;
                    712:         }
                    713:     }
1.34      dom-ts-4  714:     this.initializationError = "Unrecognized implementation attribute: " + attr;
1.18      dom-ts-4  715: }
                    716:             
                    717: 
1.34      dom-ts-4  718: MSXMLBuilder.prototype.canSetImplementationAttribute = function(attribute, value) {
                    719:     var i;
                    720:     for (i = 0; i < this.fixedAttributeNames.length; i++) {
                    721:         if (this.fixedAttributeNames[i] == attribute) {
                    722:             return (this.fixedAttributeValues[i] == value);
                    723:         }
                    724:     }
                    725:     for (i = 0; i < this.configurableAttributeNames.length; i++) {
                    726:         if (this.configurableAttributeNames[i] == attribute) {
                    727:                return true;
                    728:         }
                    729:     }
                    730:     return false;
                    731: }
                    732: 
                    733: 
1.23      dom-ts-4  734: MSXMLBuilder.prototype.getImplementation = function() {
                    735:     var doc = this.CreateMSXML();
                    736:     return doc.implementation;
                    737: }
1.18      dom-ts-4  738: 
                    739: //
                    740: //   Only used to select tests compatible with implementation
                    741: //      not used on tests that actually test hasFeature()
                    742: //
                    743: MSXMLBuilder.prototype.hasFeature = function(feature, version) {
                    744:     //
                    745:     //   MSXML will take null, unfortunately 
                    746:     //      there is no way to get it to there from script
                    747:     //      without a type mismatch error
                    748:     if(version == null) {
                    749:                switch(feature.toUpperCase()) {
                    750:                   case "XML":
                    751:                   case "CORE":
                    752:                   return true;
                    753:                   
                    754:                   case "HTML":
                    755:                   case "ORG.W3C.DOM":
                    756:                   return false;
                    757:                }
                    758:                if(this.getDOMImplementation().hasFeature(feature,"1.0")) {
                    759:                   return true;
                    760:                }
                    761:                if(this.getDOMImplementation().hasFeature(feature,"2.0")) {
                    762:                   return true;
                    763:                }
                    764:                if(this.getDOMImplementation().hasFeature(feature,"3.0")) {
                    765:                   return true;
                    766:                }
                    767:     }
                    768:        return this.getDOMImplementation().hasFeature(feature,version);
                    769:   }
                    770: 
                    771: 
1.9       dom-ts-4  772: 
1.17      dom-ts-4  773: function MozillaXMLBuilder() {
1.18      dom-ts-4  774:     this.contentType = "text/xml";
                    775: 
                    776:     this.configurableAttributeNames = [ ];
                    777:     this.configurableAttributeValues = [ ];
                    778:     this.fixedAttributeNames = [ "validating", "ignoringElementContentWhitespace", "signed", 
1.31      dom-ts-4  779:         "hasNullString", "expandEntityReferences", "coalescing", "namespaceAware", "ignoringComments" ];
                    780:     this.fixedAttributeValues = [ false, false, true, true, false, false, false, false ];
1.18      dom-ts-4  781: 
                    782:     this.contentType = "text/xml";
                    783:     this.supportedContentTypes = [ 
                    784:         "text/xml", 
                    785:         "image/svg+xml", 
                    786:         "application/xhtml+xml",
                    787:         "text/mathml" ];
                    788: 
                    789:     this.async = true;
                    790:     this.supportsAsyncChange = false;
                    791: 
1.17      dom-ts-4  792:     this.docs = new Array();
                    793:     this.docnames = new Array();
1.34      dom-ts-4  794:     this.initializationError = null;
                    795:     this.initializationFatalError = null;
                    796:     this.skipIncompatibleTests = false;
1.17      dom-ts-4  797: }
1.1       dom-ts-4  798: 
1.23      dom-ts-4  799: MozillaXMLBuilder.prototype.getImplementation = function() {
                    800:     return document.implementation;
                    801: }
                    802: 
1.31      dom-ts-4  803: MozillaXMLBuilder.prototype.setContentType = function(contentType) {
                    804:     this.contentType = contentType;
                    805: }
                    806: 
                    807: 
1.23      dom-ts-4  808: 
1.17      dom-ts-4  809: MozillaXMLBuilder.prototype.preload = function(frame, varname, url) {
                    810:   var domimpl = document.implementation;
                    811:   var doc = domimpl.createDocument("", "temp", null);
                    812:   doc.addEventListener("load", loadComplete, false);
1.18      dom-ts-4  813:   doc.load(fileBase + url + getSuffix(this.contentType));
1.17      dom-ts-4  814:   this.docs[this.docs.length] = doc;
                    815:   this.docnames[this.docnames.length] = varname;
                    816:   return 0;
                    817: }
1.1       dom-ts-4  818: 
1.17      dom-ts-4  819: MozillaXMLBuilder.prototype.load = function(frame, varname, url) {
                    820:     for(i = 0; i < this.docnames.length; i++) {
                    821:         if (this.docnames[i] == varname) {
                    822:             return this.docs[i];
1.9       dom-ts-4  823:         }
                    824:     }
1.17      dom-ts-4  825:     return null;
                    826: }
1.1       dom-ts-4  827: 
1.9       dom-ts-4  828: 
1.17      dom-ts-4  829: MozillaXMLBuilder.prototype.getImplementationAttribute = function(attr) {
1.22      dom-ts-4  830:     for (var i = 0; i < this.fixedAttributeNames.length; i++) {
                    831:         if (this.fixedAttributeNames[i] == attr) {
                    832:             return this.fixedAttributeValues[i];
                    833:         }
                    834:     }
1.17      dom-ts-4  835:     return false;
                    836: }
1.1       dom-ts-4  837: 
                    838: 
1.33      dom-ts-4  839: MozillaXMLBuilder.prototype.hasFeature = function(feature, version)
                    840: {
                    841:   return this.getImplementation().hasFeature(feature, version);
                    842: }
                    843: 
                    844: MozillaXMLBuilder.prototype.setImplementationAttribute = function(attribute, value) {
                    845:     var supported = this.getImplementationAttribute(attribute);
                    846:     if (supported != value) {
1.34      dom-ts-4  847:         this.initializationError = "Mozilla XML loader does not support " + attribute + "=" + value;
1.33      dom-ts-4  848:     }
                    849: }
1.22      dom-ts-4  850: 
1.34      dom-ts-4  851: 
                    852: MozillaXMLBuilder.prototype.canSetImplementationAttribute = function(attribute, value) {
                    853:     var supported = this.getImplementationAttribute(attribute);
                    854:     return (supported == value);
                    855: }
                    856: 
1.22      dom-ts-4  857: function DOM3LSBuilder() {
                    858:     this.contentType = "text/xml";
                    859: 
1.34      dom-ts-4  860:     this.fixedAttributeNames = [ signed, "hasNullString" ];
                    861:     this.fixedAttributeValues = [ true, true ];
                    862:     this.configurableAttributeNames = [ "validating", "ignoringElementContentWhitespace", 
                    863:         "expandEntityReferences", "coalescing", "namespaceAware", "ignoringComments" ];
                    864:     this.configurableAttributeValues = [ false, false, true, true, false, false, true, false ];
                    865:     this.domConfigNames = [ "validate", "element-content-whitespace", 
                    866:         "entities", "cdata-sections", "namespaces", "comments" ];
                    867:     this.domConfigSense = [ true, false, false, false, true, false ];
1.22      dom-ts-4  868: 
                    869:     this.contentType = "text/xml";
                    870:     this.supportedContentTypes = [ 
                    871:         "text/xml", 
                    872:         "image/svg+xml", 
                    873:         "application/xhtml+xml",
                    874:         "text/mathml" ];
                    875: 
1.34      dom-ts-4  876:     this.async = false;
1.22      dom-ts-4  877:     this.supportsAsyncChange = true;
                    878: 
                    879:     this.docs = new Array();
                    880:     this.docnames = new Array();
1.34      dom-ts-4  881:     this.lsparser = null;
                    882:     this.initializationError = null;
                    883:     this.initializationFatalError = null;
                    884:     this.skipIncompatibleTests = false;    
1.22      dom-ts-4  885: }
                    886: 
1.23      dom-ts-4  887: DOM3LSBuilder.prototype.getImplementation = function() {
                    888:     return document.implementation;
                    889: }
                    890: 
                    891: 
1.31      dom-ts-4  892: DOM3LSBuilder.prototype.setContentType = function(contentType) {
                    893:     this.contentType = contentType;
                    894: }
                    895: 
1.22      dom-ts-4  896: DOM3LSBuilder.prototype.preload = function(frame, varname, url) {
1.34      dom-ts-4  897:   if (!this.async) {
                    898:         return 1;
                    899:   }
                    900:   var domimpl = document.implementation;
                    901:   this.lsparser = domimpl.createLSParser(2, null);
                    902:   this.lsparser.addEventListener("load", loadComplete, false);
                    903:   var uri = fileBase + url + getSuffix(this.contentType);
                    904:   var doc = this.lsparser.parseURI(uri);
                    905:   this.docs[this.docs.length] = doc;
                    906:   this.docnames[this.docnames.length] = varname;
                    907:   return 0;
1.22      dom-ts-4  908: }
                    909: 
                    910: DOM3LSBuilder.prototype.load = function(frame, varname, url) {
                    911:     if (this.async) {
                    912:         for(i = 0; i < this.docnames.length; i++) {
                    913:             if (this.docnames[i] == varname) {
                    914:                 return this.docs[i];
                    915:             }
                    916:         }
                    917:         return null;
                    918:     }
1.34      dom-ts-4  919:     this.lsparser = document.implementation.createLSParser(1, null);
1.22      dom-ts-4  920:     var uri = fileBase + url + getSuffix(this.contentType);
1.34      dom-ts-4  921:     return this.lsparser.parseURI(uri);
1.22      dom-ts-4  922: }
                    923: 
                    924: 
                    925: DOM3LSBuilder.prototype.getImplementationAttribute = function(attr) {
1.34      dom-ts-4  926:     var i;
                    927:     for (i = 0; i < this.fixedAttributeNames.length; i++) {
                    928:        if (this.fixedAttributeNames[i] == attr) {
                    929:            return this.fixedAttributeValues[i];
                    930:         }
                    931:     }
                    932:     for (i = 0; i < this.configurableAttributeNames.length; i++) {
                    933:         if (this.configurableAttributeNames[i] == attr) {
                    934:                if(this.lsparser.domConfig.getParameter(this.domConfigNames[i])) {
                    935:                        return this.domConfigSense[i];
                    936:                } else {
                    937:                        return !this.domConfigSense[i];
                    938:                }
1.22      dom-ts-4  939:         }
                    940:     }
1.34      dom-ts-4  941:     throw "unrecognized implementation attribute " + att;
1.22      dom-ts-4  942: }
                    943: 
1.28      dom-ts-4  944: DOM3LSBuilder.prototype.hasFeature = function(feature, version) {
                    945:     return document.implementation.hasFeature(feature, version);
                    946: }
                    947: 
                    948: 
1.34      dom-ts-4  949: 
1.18      dom-ts-4  950: function createBuilder(implementation) {
1.34      dom-ts-4  951:   if (implementation == null) {
                    952:        return new IFrameBuilder();
                    953:   }
1.18      dom-ts-4  954:   switch(implementation) {
                    955:     case "msxml3":
1.27      dom-ts-4  956:     return new MSXMLBuilder("Msxml2.DOMDocument.3.0");
1.18      dom-ts-4  957:     
                    958:     case "msxml4":
                    959:     return new MSXMLBuilder("Msxml2.DOMDocument.4.0");
                    960: 
1.33      dom-ts-4  961:     case "mozillaXML":
1.18      dom-ts-4  962:     return new MozillaXMLBuilder();
                    963: 
1.20      dom-ts-4  964:     case "svgplugin":
                    965:     return new SVGPluginBuilder();
1.18      dom-ts-4  966: 
                    967:     case "dom3ls":
1.22      dom-ts-4  968:     return new DOM3LSBuilder();
1.33      dom-ts-4  969:     
                    970:     case "iframe":
                    971:     return new IFrameBuilder();
1.34      dom-ts-4  972:     
                    973:     default:
                    974:     alert ("unrecognized implementation " + implementation);
1.18      dom-ts-4  975:   }
1.34      dom-ts-4  976:   return new IFrameBuilder();
1.18      dom-ts-4  977: }
                    978: 
1.30      dom-ts-4  979: function checkFeature(feature, version)
                    980: {
                    981:   if (!builder.hasFeature(feature, version))
                    982:   {
1.34      dom-ts-4  983:     //
                    984:     //   don't throw exception so that users can select to ignore the precondition
                    985:     //
                    986:     builder.initializationError = "builder does not support feature " + feature + " version " + version;
1.30      dom-ts-4  987:   }
                    988: }
                    989: 
1.34      dom-ts-4  990: function createConfiguredBuilder() {
                    991:        var builder = null;
                    992:        var contentType = null;
                    993:        var i;
                    994:        var contentTypeSet = false;
                    995:        var parm = null;
                    996:        if (top && typeof(top.jsUnitParmHash) != 'undefined') {
                    997:        builder = createBuilder(top.jsUnitGetParm('implementation'));
                    998:        
                    999:        parm = top.jsUnitGetParm("skipincompatibletests");
                   1000:        if (parm) {
                   1001:                if (parm == 'true') {
                   1002:                    builder.skipIncompatibleTests = true;
                   1003:                } else {
                   1004:                    builder.skipIncompatibleTests = false;
                   1005:                }
                   1006:        }
                   1007:        
                   1008:        if (top.jsUnitGetParm('asynchronous') == 'true' && builder.supportAsync) {
                   1009:                builder.async = true;
                   1010:        }
                   1011:        if (top.jsUnitGetParm('expandentityreferences')) {
                   1012:                if (top.jsUnitGetParm('expandEntityReferences') == 'true') {
                   1013:                builder.setImplementationAttribute('expandEntityReferences', true);
                   1014:                } else {
                   1015:                builder.setImplementationAttribute('expandEntityReferences', false);
                   1016:                }
                   1017:        }
                   1018:        if (top.jsUnitGetParm('ignoringelementcontentwhitespace')) {
                   1019:                if (top.jsUnitGetParm('ignoringElementContentWhitespace') == 'true') {
                   1020:                builder.setImplementationAttribute('ignoringElementContentWhitespace', true);
                   1021:                } else {
                   1022:                builder.setImplementationAttribute('ignoringElementContentWhitespace', false);
1.19      dom-ts-4 1023:             }
                   1024:         }
1.34      dom-ts-4 1025:        if (top.jsUnitGetParm('validating')) {
                   1026:                if (top.jsUnitGetParm('validating') == 'true') {
                   1027:                builder.setImplementationAttribute('validating', true);
                   1028:                } else {
                   1029:                builder.setImplementationAttribute('validating', false);
                   1030:                }
                   1031:        }
                   1032:        if (top.jsUnitGetParm('coalescing')) {
                   1033:                if (top.jsUnitGetParm('coalescing') == 'true') {
                   1034:                builder.setImplementationAttribute('coalescing', true);
                   1035:                } else {
                   1036:                builder.setImplementationAttribute('coalescing', false);
                   1037:                }
                   1038:        }
                   1039:        if (top.jsUnitGetParm('namespaceaware')) {
                   1040:                if (top.jsUnitGetParm('namespaceaware') == 'true') {
                   1041:                builder.setImplementationAttribute('namespaceAware', true);
                   1042:                } else {
                   1043:                builder.setImplementationAttribute('namespaceAware', false);
                   1044:                }
                   1045:        }
                   1046:        contentType = top.jsUnitGetParm('contenttype');
                   1047:        if (contentType != null) {
                   1048:                contentTypeSet = false;
                   1049:                for (i = 0; i < builder.supportedContentTypes.length; i++) {
                   1050:                if (builder.supportedContentTypes[i] == contentType) {
                   1051:                        builder.setContentType(contentType);
                   1052:                        contentTypeSet = true;
                   1053:                        break;
                   1054:                }
                   1055:                }
                   1056:                if (!contentTypeSet) {
                   1057:                this.exception = "Builder does not support content type " + contentType;
                   1058:                }
                   1059:        }
                   1060:        if (top.jsUnitGetParm('ignoringcomments')) {
                   1061:                if (top.jsUnitGetParm('ignoringcomments') == 'true') {
                   1062:                builder.setImplementationAttribute('ignoringComments', true);
                   1063:                } else {
                   1064:                builder.setImplementationAttribute('ignoringComments', false);
                   1065:                }
                   1066:        }
                   1067:        } else {
                   1068:        builder = new IFrameBuilder();
                   1069:        }
                   1070:        return builder;
1.18      dom-ts-4 1071: }
1.16      dom-ts-4 1072: 
                   1073: 
1.17      dom-ts-4 1074: function preload(frame, varname, url) {
                   1075:   return builder.preload(frame, varname, url);
1.15      dom-ts-4 1076: }
                   1077: 
1.17      dom-ts-4 1078: function load(frame, varname, url) {
                   1079:     return builder.load(frame, varname, url);
1.16      dom-ts-4 1080: }
1.15      dom-ts-4 1081: 
1.17      dom-ts-4 1082: function getImplementationAttribute(attr) {
                   1083:     return builder.getImplementationAttribute(attr);
1.15      dom-ts-4 1084: }
1.16      dom-ts-4 1085: 
1.9       dom-ts-4 1086: 
1.18      dom-ts-4 1087: function setImplementationAttribute(attribute, value) {
                   1088:     builder.setImplementationAttribute(attribute, value);
                   1089: }
                   1090: 
1.21      dom-ts-4 1091: function createXPathEvaluator(doc) {
                   1092:     try {
                   1093:         return doc.getFeature("XPath", null);
                   1094:     }
                   1095:     catch(ex) {
                   1096:     }
                   1097:     return doc;
                   1098: }
                   1099: 
1.10      dom-ts-4 1100: 
1.18      dom-ts-4 1101: function MSXMLBuilder_onreadystatechange() {
                   1102:     if (builder.parser.readyState == 4) {
                   1103:         loadComplete();
                   1104:     }
1.19      dom-ts-4 1105: }
                   1106: 
                   1107: 
                   1108: var fileBase = location.href;
                   1109: if (fileBase.indexOf('?') != -1) {
                   1110:    fileBase = fileBase.substring(0, fileBase.indexOf('?'));
                   1111: }
1.20      dom-ts-4 1112: fileBase = fileBase.substring(0, fileBase.lastIndexOf('/') + 1) + "files/";
                   1113: 
1.23      dom-ts-4 1114: function getImplementation() {
                   1115:     return builder.getImplementation();
                   1116: }
1.19      dom-ts-4 1117: 

Webmaster