aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Fugate <dfugate@microsoft.com>2011-08-25 11:18:44 -0700
committerDavid Fugate <dfugate@microsoft.com>2011-08-25 11:18:44 -0700
commit28718864206f3254ed6fae9f1f630f2aa5005f79 (patch)
tree35ea93c8bbe32551cf799a0505953676c594cda7 /tools
parentc21525a32814e57a60dafb3d410847ba5a9cb09c (diff)
test\harness\*:
- a lot of JS harness code written in strings have been moved out to actual physical files such as ed.js (syntax error detection for globally scoped tests) and gs.js (global scope test case validator). This change makes it far easier to maintain the test harness code - reorganized helper.js providing a clear indication which methods are used by external objects, which are implementation details, and which are unequivocally test262-specific. I've also added, openErrorWindow, which will be used to open a descriptive error message window for each test case failure reported on the 'Run' tab - improved the error message for syntax errors occurring when a test case fails to load - sta.js no longer tries to pickle all helper functions it contains! Instead, we load the file directly from sth.js. The performance of fnGlobalObject has been improved. Finally, the ES5Harness object has been moved from sth.js (in a string) to here - sth.js now has a browser implementer hook, controller.implementerHook, which allows browser implementers to handle test case failures in their own way (e.g., log to the filesystem). The 'run' function was basically re-written Added 37 new test cases from the "IE Test Center" Build release. There were 14 modifications to existing test cases as well. Refactored SputnikGlobalScope.js such that test case paths are now used as indices into the GlobalScopeTests array. TestCasePackager.py had the concept of templated test harnesses introduced - see templates\runner.test262.html. Also added support for one HTML test harness per ES5 chapter. Last but not least, TestCasePackagerConfig.py now has a 'source control' abstraction class which abstracts away source control adds|edits when dynamically generating *.json and *.html test chapters.
Diffstat (limited to 'tools')
-rw-r--r--tools/TestCaseHTMLPackager/TestCasePackager.py69
-rw-r--r--tools/TestCaseHTMLPackager/TestCasePackagerConfig.py59
-rw-r--r--tools/TestCaseHTMLPackager/templates/runner.test262.html170
3 files changed, 277 insertions, 21 deletions
diff --git a/tools/TestCaseHTMLPackager/TestCasePackager.py b/tools/TestCaseHTMLPackager/TestCasePackager.py
index 6beb678c5..7c7a02d14 100644
--- a/tools/TestCaseHTMLPackager/TestCasePackager.py
+++ b/tools/TestCaseHTMLPackager/TestCasePackager.py
@@ -28,7 +28,14 @@ import datetime
import shutil
import re
import json
+import stat
+#--Stubs-----------------------------------------------------------------------
+def generateHarness(harnessType, jsonFile, description):
+ pass
+
+
+#------------------------------------------------------------------------------
from TestCasePackagerConfig import *
#--Globals---------------------------------------------------------------------
@@ -36,6 +43,8 @@ from TestCasePackagerConfig import *
__parser = argparse.ArgumentParser(description='Tool used to generate the test262 website')
__parser.add_argument('version', action='store',
help='Version of the test suite.')
+__parser.add_argument('--type', action='store', default='test262',
+ help='Type of test case runner to generate.')
ARGS = __parser.parse_args()
if not os.path.exists(EXCLUDED_FILENAME):
@@ -58,6 +67,9 @@ IS_MULTILINE_COMMENT = False
#List of all *.json files containing encoded test cases
SECTIONS_LIST = []
+ONE_JSON_PER_CHAPTER = False
+TESTCASELIST_PER_JSON = False
+
#--Sanity checks--------------------------------------------------------------#
if not os.path.exists(TEST262_CASES_DIR):
print "Cannot generate (JSON) test262 tests when the path containing said tests, %s, does not exist!" % TEST262_CASES_DIR
@@ -68,12 +80,10 @@ if not os.path.exists(TEST262_HARNESS_DIR):
sys.exit(1)
if not os.path.exists(TEST262_WEB_CASES_DIR):
- print "Cannot generate (JSON) test262 test cases to %s when it does not exist!" % TEST262_WEB_CASES_DIR
- sys.exit(1)
+ os.mkdir(TEST262_WEB_CASES_DIR)
if not os.path.exists(TEST262_WEB_HARNESS_DIR):
- print "Cannot copy test262 test harness to %s when it does not exist!" % TEST262_WEB_HARNESS_DIR
- sys.exit(1)
+ os.mkdir(TEST262_WEB_HARNESS_DIR)
if not hasattr(ARGS, "version"):
print "A test262 suite version must be specified from the command-line to run this script!"
@@ -143,7 +153,7 @@ def isTestStarted(line):
return False
elif IS_MULTILINE_COMMENT: #//we're already in a multi-line comment that hasn't ended
return False
- elif "//" in line: #//blah
+ elif re.match("^\s*//", line)!=None: #//blah
return False
elif re.match("^\s*$", line)!=None: #newlines
return False
@@ -164,7 +174,13 @@ for temp in TEST_CONTRIB_DIRS:
if not os.path.exists(temp):
print "The expected ES5 test directory,", temp, "did not exist!"
sys.exit(1)
- dirWalker(temp)
+
+ if not ONE_JSON_PER_CHAPTER:
+ dirWalker(temp)
+ else:
+ for tempSubdir in os.listdir(temp):
+ TEST_SUITE_SECTIONS.append(os.path.join(temp, tempSubdir))
+
for chapter in TEST_SUITE_SECTIONS:
chapterName = chapter.rsplit(os.path.sep, 1)[1]
@@ -182,12 +198,15 @@ for chapter in TEST_SUITE_SECTIONS:
excluded = 0
testCount = 0
for test in sourceFiles:
+ #TODO - use something other than the hard-coded 'TestCases' below
+ testPath = "TestCases" + test.split(TEST262_CASES_DIR, 1)[1].replace("\\", "/")
testName=test.rsplit(".", 1)[0]
testName=testName.rsplit(os.path.sep, 1)[1]
if EXCLUDE_LIST.count(testName)==0:
# dictionary for each test
testDict = {}
testDict["id"] = testName
+ testDict["path"] = testPath.replace("/ietestcenter", "").replace("/sputnik_converted", "")
tempFile = open(test, "r")
scriptCode = tempFile.readlines()
@@ -218,6 +237,7 @@ for chapter in TEST_SUITE_SECTIONS:
tests.append(testDict)
testCount += 1
else:
+ print "Excluded:", testName
excluded = excluded + 1
#we have completed our tests
@@ -230,6 +250,17 @@ for chapter in TEST_SUITE_SECTIONS:
with open(os.path.join(TEST262_WEB_CASES_DIR, chapterName + ".json"), "w") as f:
json.dump(testsList, f, separators=(',',':'), sort_keys=True)
+
+ if TESTCASELIST_PER_JSON:
+ CHAPTER_TEST_CASES_JSON = {}
+ CHAPTER_TEST_CASES_JSON["numTests"] = int(sect["numTests"])
+ CHAPTER_TEST_CASES_JSON["version"] = ARGS.version
+ CHAPTER_TEST_CASES_JSON["date"] = str(datetime.datetime.now().date())
+ CHAPTER_TEST_CASES_JSON["testSuite"] = [WEBSITE_CASES_PATH + chapterName + ".json"]
+ with open(os.path.join(TEST262_WEB_CASES_DIR, "testcases_%s.json" % chapterName), "w") as f:
+ json.dump(CHAPTER_TEST_CASES_JSON, f, separators=(',',':'), sort_keys=True)
+ generateHarness(ARGS.type, "testcases_%s.json" % chapterName, chapterName.replace("chapter", "Chapter "))
+
#add the name of the chapter test to our complete list
SECTIONS_LIST.append(WEBSITE_CASES_PATH + chapterName + ".json")
TOTAL_TEST_COUNT += int(sect["numTests"])
@@ -242,24 +273,36 @@ TEST_CASES_JSON["numTests"] = TOTAL_TEST_COUNT
TEST_CASES_JSON["version"] = ARGS.version
TEST_CASES_JSON["date"] = str(datetime.datetime.now().date())
TEST_CASES_JSON["testSuite"] = SECTIONS_LIST
-with open(os.path.join(TEST262_WEB_CASES_DIR, "testcaseslist.json"), "w") as f:
+with open(os.path.join(TEST262_WEB_CASES_DIR, "default.json"), "w") as f:
json.dump(TEST_CASES_JSON, f, separators=(',',':'), sort_keys=True)
-
+generateHarness(ARGS.type, "default.json", "Chapters 1-16")
#Deploy test harness to website as well
print ""
print "Deploying test harness files to 'TEST262_WEB_HARNESS_DIR'..."
-for filename in [x for x in os.listdir(TEST262_HARNESS_DIR) if x.endswith(".js")]:
- shutil.copy(os.path.join(TEST262_HARNESS_DIR, filename),
- os.path.join(TEST262_WEB_HARNESS_DIR, filename))
+if TEST262_HARNESS_DIR!=TEST262_WEB_HARNESS_DIR:
+ for filename in [x for x in os.listdir(TEST262_HARNESS_DIR) if x.endswith(".js")]:
+ toFilename = os.path.join(TEST262_WEB_HARNESS_DIR, filename)
+ fileExists = os.path.exists(toFilename)
+ if fileExists:
+ SC_HELPER.edit(toFilename)
+ shutil.copy(os.path.join(TEST262_HARNESS_DIR, filename),
+ toFilename)
+ if not fileExists:
+ SC_HELPER.add(toFilename)
#Copying the global scope files over as well
#TODO: really the HTML harness file should be generated as well...
print ""
print "Deploying global scope metadata files to 'TEST262_WEB_HARNESS_DIR'..."
for gsf in GLOBAL_SCOPE_FILES:
+ toFilename = os.path.join(TEST262_WEB_CASES_DIR, gsf)
+ fileExists = os.path.exists(toFilename)
+ if fileExists:
+ SC_HELPER.edit(toFilename)
shutil.copy(os.path.join(TEST262_CASES_DIR, gsf),
- os.path.join(TEST262_WEB_CASES_DIR, gsf))
-
+ toFilename)
+ if not fileExists:
+ SC_HELPER.add(toFilename)
print "Done."
diff --git a/tools/TestCaseHTMLPackager/TestCasePackagerConfig.py b/tools/TestCaseHTMLPackager/TestCasePackagerConfig.py
index e5019aa2f..9364556d7 100644
--- a/tools/TestCaseHTMLPackager/TestCasePackagerConfig.py
+++ b/tools/TestCaseHTMLPackager/TestCasePackagerConfig.py
@@ -20,6 +20,8 @@
#--Imports---------------------------------------------------------------------
import os
+import subprocess
+import stat
#--Globals---------------------------------------------------------------------
MAX_CASES_PER_JSON = 1000
@@ -29,7 +31,7 @@ MAX_CASES_PER_JSON = 1000
TEST_CONTRIB_DIRS = ["sputnik_converted", "ietestcenter"]
#Global scope source files found directly under "test\suite\".
-GLOBAL_SCOPE_FILES = ["SputnikGlobalScope.js"]
+GLOBAL_SCOPE_FILES = ["SputnikGlobalScope.js", "IETCGlobalScope.js"]
#Path to the root of the Hg repository (relative to this file's location)
TEST262_ROOT = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..")
@@ -55,13 +57,54 @@ WEBSITE_CASES_PATH = "resources/scripts/testcases/"
#These tests are either invalid as-per ES5 or have issues with the test262 web harness.
EXCLUDED_FILENAME = os.path.join(TEST262_ROOT, "test", "config", "excludelist.xml")
+#------------------------------------------------------------------------------
-
-#--Sanity checks--------------------------------------------------------------#
-
-
-#--Helpers--------------------------------------------------------------------#
-
+TEMPLATE_LINES = None
+__lastHarnessType = None
+
+def generateHarness(harnessType, jsonName, title):
+ global TEMPLATE_LINES
+ global __lastHarnessType
+ if TEMPLATE_LINES==None or harnessType!=__lastHarnessType:
+ __lastHarnessType = harnessType
+ TEMPLATE_LINES = []
+ with open(os.path.join(os.getcwd(), "templates","runner." + harnessType + ".html"), "r") as f:
+ TEMPLATE_LINES = f.readlines()
+ fileName = os.path.join(TEST262_ROOT, "website", jsonName.replace(".json", ".html"))
+ fileNameExists = False
+ if os.path.exists(fileName):
+ SC_HELPER.edit(fileName)
+ fileNameExists = True
+ with open(fileName, "w") as f:
+ for line in TEMPLATE_LINES:
+ if "var TEST_LIST_PATH =" in line:
+ f.write(" var TEST_LIST_PATH = \"resources/scripts/testcases/" + jsonName + "\";" + os.linesep)
+ #elif "ECMAScript 5" in line:
+ # f.write(line.replace("ECMAScript 5", "ECMAScript 5: %s" % title))
+ else:
+ f.write(line)
+ if not fileNameExists:
+ SC_HELPER.add(fileName)
#------------------------------------------------------------------------------
-
+class SCAbstraction(object):
+ '''
+ A class which abstracts working with source control systems in relation to
+ generated test262 files. Useful when test262 is also used internally by
+ browser implementors.
+ '''
+ def edit(self, filename):
+ '''
+ Source control edit of a file. For Mercurial, just make sure it's
+ writable.
+ '''
+ if not(os.stat(filename).st_mode & stat.S_IWRITE):
+ os.chmod(filename, stat.S_IWRITE)
+
+ def add(self, filename):
+ '''
+ Source control add of a file.
+ '''
+ subprocess.call(["hg", "add", filename])
+
+SC_HELPER = SCAbstraction() \ No newline at end of file
diff --git a/tools/TestCaseHTMLPackager/templates/runner.test262.html b/tools/TestCaseHTMLPackager/templates/runner.test262.html
new file mode 100644
index 000000000..3bfea29f2
--- /dev/null
+++ b/tools/TestCaseHTMLPackager/templates/runner.test262.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" />
+<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+<script type="text/javascript" src="resources/scripts/global/jquery-1.4.2.min.js"></script>
+<script type="text/javascript" src="resources/scripts/global/sections.js"></script>
+<script type="text/javascript">
+ //Globals
+ var TEST_LIST_PATH = "resources/scripts/testcases/testcaseslist.json";
+</script>
+<script type="text/javascript" src="resources/scripts/global/sth.js"></script>
+<script type="text/javascript" src="resources/scripts/global/sta.js"></script>
+<script type="text/javascript" src="resources/scripts/global/jqueryprogressbar.js"></script>
+<script type="text/javascript" src="resources/scripts/global/helper.js"></script>
+<script type="text/javascript" src="resources/scripts/global/jquery.base64.js"></script>
+<script type="text/javascript" src="resources/scripts/global/sputnikLib.js"></script>
+<script type="text/javascript" src="resources/scripts/testcases/SputnikGlobalScope.js"></script>
+<script type="text/javascript" src="resources/scripts/testcases/IETCGlobalScope.js"></script>
+<script language="javascript" type="text/javascript">
+ //To support all the browsers
+ $(window).resize(ResizeLoadIndicator);
+ $(window).load(ResizeLoadIndicator);
+ function ResizeLoadIndicator() {
+ $(".indicatorContainer .disabledBackground").css({ height: ($(window).height() - 20) + "px" });
+ }
+
+ $(".indicatorContainer").click(function(e) {
+ if (!e) { var e = window.event; }
+ e.cancelBubble = true;
+ if (e.stopPropagation) { e.stopPropagation(); }
+ });
+</script>
+
+<title>ECMAScript Test262</title>
+<link href="resources/styles/style.css" media="screen" rel="stylesheet" title="CSS" type="text/css" />
+</head>
+<body>
+ <div class="indicatorContainer" oncontextmenu="return false;">
+ <!--Blank div to disable back portion when indicator is shown-->
+ <div class="disabledBackground"></div>
+ <div id="loadingIndicator">
+ <div>
+ <img src="./resources/images/spinner.gif" alt="Loading..." />
+ <span>Loading...</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="wrapper">
+ <!-- This Container holds the Logo -->
+ <div class="logoHeader">
+ <div class="logoBg"><img src="resources/images/logo.png" /></div>
+ <div class="ecmascriptbacklink">
+ <p><a href='javascript:void(window.open("http://www.ecmascript.org/"));'>ECMAScript.org</a></p>
+ </div>
+ </div>
+ <!-- This Container holds the Navigation -->
+ <div class="navBar">
+ <ul>
+ <li><a href="#" class="selected nav-link" id="home">Home</a></li>
+ <li><a href="#" class="nav-link" id="run">Run</a></li>
+ <li><a href="#" class="nav-link test-report-link" id="results">Results</a></li>
+ <li><a href="#" class="nav-link" id="development">Development</a></li>
+ </ul>
+ </div>
+ <div class="content-container" id="contentContainer">
+ <!-- This is the Main Content Container -->
+ <div class="content-home">
+ <p class="headers">What is test262?</p>
+ <p class="content">test262 is a test suite intended to check agreement between JavaScript implementations and the ECMA-262 Specification (currently 5th Edition). The test suite contains thousands of individual tests, each of which tests some specific requirements of the ECMAScript specification.</p>
+ <p class="headers">What is ECMAScript?</p>
+ <p class="content">"ECMAScript" is the name under which the language more commonly known as "JavaScript" is standardized. Development of the ECMAScript standard is the responsibility of <a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'>Technical Committee 39 (TC39)</a> of <a href='javascript:void(window.open("http://www.ecma-international.org/"));'>Ecma International</a>. The ECMAScript standard is officially known as ECMA-262. ECMAScript 5 (or just ES5) is short hand for the "ECMA-262, 5th Edition ECMAScript Language Specification" the official name of the current edition of the standard. ECMAScript 5 was approved as an official Ecma standard by the Ecma General Assembly on December 3, 2009. <a href='javascript:void(window.open("http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf"));'>The ECMAScript 5 Specification (PDF)</a> is available from the Ecma International web site.</p>
+ <p class="headers">Who creates and maintains test262?</p>
+ <p class="content">Development of test262 is a project of Ecma TC39. The testing framework and individual tests are created by member organizations of TC39 and contributed to Ecma for use in test262. For more information about how test262 is developed and maintained click the “Development” tab at the top of this page.</p>
+ <p class="headers">What is the status of test262?</p>
+ <p class="content"><strong>test262 is not yet complete. It is still undergoing active development.</strong> Some portions of the ES5 specification have very complete test coverage while other portions of the specification have only partial test coverage. Some tests may be invalid or may yield false positive or false negative results. A perfect passing score on test262 does not guarantee that a JavaScript implementation perfectly supports ES5. Because tests are being actively added and modified, tests results from different days or times may not be directly comparable. Click the “Development” tab at the top of this page for instructions for reporting test262 bugs.</p>
+ <p class="headers">Where can I found out more?</p>
+ <p class="content">Please visit our <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id=test262:faq"));'>Frequently Asked Questions</a> section on the <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id="));'>ECMAScript Wiki</a>.</p>
+
+ <p class="headers">Running the Tests</p>
+ <p class="content">Click the “Run” tab at the top of this page for instructions and follow the instructions to run the tests.</p>
+
+ <a href='javascript:void(window.open("http://www.ecma-international.org/memento/TC39.htm"));'></a>
+
+ </div>
+
+ <div class="content-dev">
+ <p class="headers">Development</p>
+ <p class="content">Test262 is being developed by the members of Ecma TC39. Ecma's intellectual property policies, permit only Ecma
+ members to directly contribute code to the project. However, a <a href='javascript:void(window.open("http://mail.mozilla.org/pipermail/test262-discuss/"));'>public mailing list</a> is used to coordinate development of Test262. If you wish to participate in the discussion please <a href='javascript:void(window.open("http://mail.mozilla.org/listinfo/test262-discuss"));'>subscribe</a>. Bug reports and suggestions should be sent to the mailing list.
+ </p>
+ <p class="content">
+ Ecma members can find detailed instructions on Test262 development procedures at the <a href='javascript:void(window.open("http://wiki.ecmascript.org/doku.php?id=test262:test262"));'>Test262 Wiki</a>.
+ </p>
+ </div>
+
+ <div class="content-tests">
+ <!-- This is the Main Content Container -->
+ <p class="content">Please click on the Start button to start the test. Once you start the test you may pause the test anytime by clicking on the Pause button. You can click on the Results tab once the test is completed or after pausing the test. The Reset button is for restarting the test run.</p>
+<!--
+ <div class="progressBarHolder">
+ Chapter Index: <input type="text" size="2" maxlength="2" value="" id="chapterId" onkeypress="if(event.keyCode < 48 || event.keyCode > 57){return false;}"/>
+ </div>
+-->
+ <!-- This is the Progress Bar Holder -->
+ <div class="progressBarHolder">
+ <div id="progressbar"></div>
+ <div class="progressBarButtons">
+ <img src="resources/images/reset.png" class="button-reset"/>&nbsp;<img src="resources/images/start.png" class="button-start" id="btnStart"/>
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+ <p class="hide">>
+ Timer Value(ms) : <input id="txtTimerValue" value="50" /> <input id="btnSetTimerValue" value="Set Timer Value" type="button"/>
+ </p>
+ <!-- This is the Results Text Holder -->
+ <div class="resultsHeader">
+ <!--Total Loaded: <strong><span id="totalLoadedCounter"></span></strong><span class="Separator">|</span>-->
+ Tests To Run: <strong><span class="teststorun-counter" id="testsToRun"></span></strong>&nbsp;<span class="separator">|</span>
+ Total Tests Ran: <strong><span class="total-counter" id="totalCounter"></span></strong> <span class="separator">|</span> Pass: <span class="pass" id="Pass"></span> <span class="separator">|</span> Fail: <span class="fail" id="Fail"></span>
+ <span class="separator">|</span>&nbsp;Failed To Load: <span class="fail" id="failedToLoadCounter1"></span>
+ <p><span id="nextActivity"></span></p>
+ </div>
+ <!-- This is the Table -->
+ <div class="resultsTableHolder" id="tableLoggerParent">
+ <table width="100%" border="0" cellspacing="0" cellpadding="0" class="table-logger" id="tableLogger"></table>
+ </div>
+ <div>
+ Test Suite Ver.: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test Suite Date: <span class="targetTestSuiteDate"></span>
+ </div>
+ </div>
+
+ <div class="content-results">
+ <div class="crumbContainer">
+ <div class="crumbs"></div>
+ <div style="float:right;"><a class="setBlue hide" id="backlinkDiv" href="#"><< back</a></div>
+ <div style="clear : both;"></div>
+ </div>
+ <div class="resultsHeader"> <strong>Total Tests:<span class="totalCases"></span></strong><br />
+ Passed: <span class="passedCases"></span> <span class="separator">|</span> Failed: <span class="failedCases"></span> <span class="separator">|</span>
+ Failed To Load: <strong><span id="failedToLoadCounter"></span></strong>
+ </div>
+ <!-- This is the Table -->
+ <div class="resultsTableHolder">
+ <table width="100%" cellspacing="0" cellpadding="0" border="0" class="results-data-table"> </table>
+ <div id="resultMessage">Test results will be displayed after the tests are executed using the Run page.</div>
+ </div>
+ <div>
+ Test Suite Ver.: <span class="targetTestSuiteVersion"></span>&nbsp;<span class="separator">|</span>&nbsp;Test Suite Date: <span class="targetTestSuiteDate"></span>
+ </div>
+ <div class="downloadLinks">
+ <p><a class="anchor-download-xml" id="ancGenXMLReport"><strong>Download results as XML</strong></a></p> <!--| <strong><a href="resources/scripts/testcases.zip">Download Source</a></strong></p>-->
+ </div>
+ <div id="legend" class="hide">
+ <label class="reportGreen">Green:</label>&nbsp;100%&nbsp;
+ <label class="reportLightGreen">Green:</label>&nbsp;75% to 99.9%&nbsp;
+ <label class="reportYellow">Yellow:</label>&nbsp;50% to 75% &nbsp;
+ <label class="reportRed">Red:</label>&nbsp;less than 50%
+ </div>
+ </div>
+ </div>
+ </div>
+ <!-- This is the Footer -->
+ <div class="footer">
+ <!--<div class="Links"> <a href="">Privacy</a> | <a href="">Terms of Use</a> </div>-->
+ <div class="copyright"> &copy; <a href='javascript:void(window.open("http://www.ecma-international.org"));'>Ecma International</a> </div>
+ </div>
+ <iframe id="scriptLoader" class="hide"></iframe>
+</body>
+</html>