| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 """ | 2 """ |
| 3 Script used to parse the test results and generate an HTML report. | 3 Script used to parse the test results and generate an HTML report. |
| 4 | 4 |
| 5 @copyright: (c)2005-2007 Matt Kruse (javascripttoolbox.com) | 5 @copyright: (c)2005-2007 Matt Kruse (javascripttoolbox.com) |
| 6 @copyright: Red Hat 2008-2009 | 6 @copyright: Red Hat 2008-2009 |
| 7 @author: Dror Russo (drusso@redhat.com) | 7 @author: Dror Russo (drusso@redhat.com) |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 import os, sys, re, getopt, time, datetime, commands | 10 import os, sys, re, getopt, time, datetime, commands |
| 11 import common | 11 import common |
| 12 | 12 |
| 13 | 13 |
| 14 format_css=""" | 14 format_css = """ |
| 15 html,body { | 15 html,body { |
| 16 padding:0; | 16 padding:0; |
| 17 color:#222; | 17 color:#222; |
| 18 background:#FFFFFF; | 18 background:#FFFFFF; |
| 19 } | 19 } |
| 20 | 20 |
| 21 body { | 21 body { |
| 22 padding:0px; | 22 padding:0px; |
| 23 font:76%/150% "Lucida Grande", "Lucida Sans Unicode", Lucida, Verdana, Genev
a, Arial, Helvetica, sans-serif; | 23 font:76%/150% "Lucida Grande", "Lucida Sans Unicode", Lucida, Verdana, Genev
a, Arial, Helvetica, sans-serif; |
| 24 } | 24 } |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 | 173 |
| 174 /* Format menu items differently depending on what level of the tree the
y are in */ | 174 /* Format menu items differently depending on what level of the tree the
y are in */ |
| 175 /* Uncomment this if you want your fonts to decrease in size the deeper
they are in the tree */ | 175 /* Uncomment this if you want your fonts to decrease in size the deeper
they are in the tree */ |
| 176 /* | 176 /* |
| 177 ul.mktree li ul li { font-size: 90% } | 177 ul.mktree li ul li { font-size: 90% } |
| 178 */ | 178 */ |
| 179 } | 179 } |
| 180 """ | 180 """ |
| 181 | 181 |
| 182 | 182 |
| 183 table_js=""" | 183 table_js = """ |
| 184 /** | 184 /** |
| 185 * Copyright (c)2005-2007 Matt Kruse (javascripttoolbox.com) | 185 * Copyright (c)2005-2007 Matt Kruse (javascripttoolbox.com) |
| 186 * | 186 * |
| 187 * Dual licensed under the MIT and GPL licenses. | 187 * Dual licensed under the MIT and GPL licenses. |
| 188 * This basically means you can use this code however you want for | 188 * This basically means you can use this code however you want for |
| 189 * free, but don't claim to have written it yourself! | 189 * free, but don't claim to have written it yourself! |
| 190 * Donations always accepted: http://www.JavascriptToolbox.com/donate/ | 190 * Donations always accepted: http://www.JavascriptToolbox.com/donate/ |
| 191 * | 191 * |
| 192 * Please do not link to the .js files on javascripttoolbox.com from | 192 * Please do not link to the .js files on javascripttoolbox.com from |
| 193 * your site. Copy the files locally to your server instead. | 193 * your site. Copy the files locally to your server instead. |
| (...skipping 1179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 } | 1373 } |
| 1374 } | 1374 } |
| 1375 """ | 1375 """ |
| 1376 | 1376 |
| 1377 | 1377 |
| 1378 ################################################################# | 1378 ################################################################# |
| 1379 ## This script gets kvm autotest results directory path as an ## | 1379 ## This script gets kvm autotest results directory path as an ## |
| 1380 ## input and create a single html formatted result page. ## | 1380 ## input and create a single html formatted result page. ## |
| 1381 ################################################################# | 1381 ################################################################# |
| 1382 | 1382 |
| 1383 stimelist=[] | 1383 stimelist = [] |
| 1384 | 1384 |
| 1385 | 1385 |
| 1386 def make_html_file(metadata, results, tag, host, output_file_name, dirname): | 1386 def make_html_file(metadata, results, tag, host, output_file_name, dirname): |
| 1387 html_prefix=""" | 1387 html_prefix = """ |
| 1388 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/st
rict.dtd"> | 1388 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/st
rict.dtd"> |
| 1389 <html> | 1389 <html> |
| 1390 <head> | 1390 <head> |
| 1391 <title>KVM Autotest Results</title> | 1391 <title>KVM Autotest Results</title> |
| 1392 <style type="text/css"> | 1392 <style type="text/css"> |
| 1393 %s | 1393 %s |
| 1394 </style> | 1394 </style> |
| 1395 <script type="text/javascript"> | 1395 <script type="text/javascript"> |
| 1396 %s | 1396 %s |
| 1397 %s | 1397 %s |
| 1398 function popup(tag,text) { | 1398 function popup(tag,text) { |
| 1399 var w = window.open('', tag, 'toolbar=no,location=no,directories=no,status=no,me
nubar=no,scrollbars=yes,resizable=yes, copyhistory=no,width=600,height=300,top=2
0,left=100'); | 1399 var w = window.open('', tag, 'toolbar=no,location=no,directories=no,status=no,me
nubar=no,scrollbars=yes,resizable=yes, copyhistory=no,width=600,height=300,top=2
0,left=100'); |
| 1400 w.document.open("text/html", "replace"); | 1400 w.document.open("text/html", "replace"); |
| 1401 w.document.write(text); | 1401 w.document.write(text); |
| 1402 w.document.close(); | 1402 w.document.close(); |
| 1403 return true; | 1403 return true; |
| 1404 } | 1404 } |
| 1405 </script> | 1405 </script> |
| 1406 </head> | 1406 </head> |
| 1407 <body> | 1407 <body> |
| 1408 """%(format_css, table_js, maketree_js) | 1408 """ % (format_css, table_js, maketree_js) |
| 1409 | 1409 |
| 1410 | 1410 |
| 1411 if output_file_name: | 1411 if output_file_name: |
| 1412 output = open(output_file_name, "w") | 1412 output = open(output_file_name, "w") |
| 1413 else: #if no output file defined, print html file to console | 1413 else: #if no output file defined, print html file to console |
| 1414 output = sys.stdout | 1414 output = sys.stdout |
| 1415 # create html page | 1415 # create html page |
| 1416 print >> output, html_prefix | 1416 print >> output, html_prefix |
| 1417 print >> output, '<h2 id=\"page_title\">KVM Autotest Execution Report</h2>' | 1417 print >> output, '<h2 id=\"page_title\">KVM Autotest Execution Report</h2>' |
| 1418 | 1418 |
| 1419 # formating date and time to print | 1419 # formating date and time to print |
| 1420 t = datetime.datetime.now() | 1420 t = datetime.datetime.now() |
| 1421 | 1421 |
| 1422 epoch_sec = time.mktime(t.timetuple()) | 1422 epoch_sec = time.mktime(t.timetuple()) |
| 1423 now = datetime.datetime.fromtimestamp(epoch_sec) | 1423 now = datetime.datetime.fromtimestamp(epoch_sec) |
| 1424 | 1424 |
| 1425 # basic statistics | 1425 # basic statistics |
| 1426 total_executed = 0 | 1426 total_executed = 0 |
| 1427 total_failed = 0 | 1427 total_failed = 0 |
| 1428 total_passed = 0 | 1428 total_passed = 0 |
| 1429 for res in results: | 1429 for res in results: |
| 1430 total_executed+=1 | 1430 total_executed += 1 |
| 1431 if res['status'] == 'GOOD': | 1431 if res['status'] == 'GOOD': |
| 1432 total_passed+=1 | 1432 total_passed += 1 |
| 1433 else: | 1433 else: |
| 1434 total_failed+=1 | 1434 total_failed += 1 |
| 1435 stat_str = 'No test cases executed' | 1435 stat_str = 'No test cases executed' |
| 1436 if total_executed>0: | 1436 if total_executed > 0: |
| 1437 failed_perct = int(float(total_failed)/float(total_executed)*100) | 1437 failed_perct = int(float(total_failed)/float(total_executed)*100) |
| 1438 stat_str = ('From %d tests executed, %d have passed (%d%% failures)' % | 1438 stat_str = ('From %d tests executed, %d have passed (%d%% failures)' % |
| 1439 (total_executed, total_passed, failed_perct)) | 1439 (total_executed, total_passed, failed_perct)) |
| 1440 | 1440 |
| 1441 kvm_ver_str = metadata['kvmver'] | 1441 kvm_ver_str = metadata['kvmver'] |
| 1442 | 1442 |
| 1443 print >> output, '<table class="stats2">' | 1443 print >> output, '<table class="stats2">' |
| 1444 print >> output, '<tr><td>HOST</td><td>:</td><td>%s</td></tr>' % host | 1444 print >> output, '<tr><td>HOST</td><td>:</td><td>%s</td></tr>' % host |
| 1445 print >> output, '<tr><td>RESULTS DIR</td><td>:</td><td>%s</td></tr>' % tag | 1445 print >> output, '<tr><td>RESULTS DIR</td><td>:</td><td>%s</td></tr>' % tag |
| 1446 print >> output, '<tr><td>DATE</td><td>:</td><td>%s</td></tr>' % now.ctime() | 1446 print >> output, '<tr><td>DATE</td><td>:</td><td>%s</td></tr>' % now.ctime() |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1479 elif res['status'] == 'ERROR': | 1479 elif res['status'] == 'ERROR': |
| 1480 print >> output, '<td align=\"left\"><b><font color="red">ERROR!</fo
nt></b></td>' | 1480 print >> output, '<td align=\"left\"><b><font color="red">ERROR!</fo
nt></b></td>' |
| 1481 else: | 1481 else: |
| 1482 print >> output, '<td align=\"left\">%s</td>' % res['status'] | 1482 print >> output, '<td align=\"left\">%s</td>' % res['status'] |
| 1483 # print exec time (seconds) | 1483 # print exec time (seconds) |
| 1484 print >> output, '<td align="left">%s</td>' % res['exec_time_sec'] | 1484 print >> output, '<td align="left">%s</td>' % res['exec_time_sec'] |
| 1485 # print log only if test failed.. | 1485 # print log only if test failed.. |
| 1486 if res['log']: | 1486 if res['log']: |
| 1487 #chop all '\n' from log text (to prevent html errors) | 1487 #chop all '\n' from log text (to prevent html errors) |
| 1488 rx1 = re.compile('(\s+)') | 1488 rx1 = re.compile('(\s+)') |
| 1489 log_text = rx1.sub(' ',res['log']) | 1489 log_text = rx1.sub(' ', res['log']) |
| 1490 | 1490 |
| 1491 # allow only a-zA-Z0-9_ in html title name | 1491 # allow only a-zA-Z0-9_ in html title name |
| 1492 # (due to bug in MS-explorer) | 1492 # (due to bug in MS-explorer) |
| 1493 rx2 = re.compile('([^a-zA-Z_0-9])') | 1493 rx2 = re.compile('([^a-zA-Z_0-9])') |
| 1494 updated_tag = rx2.sub('_',res['title']) | 1494 updated_tag = rx2.sub('_', res['title']) |
| 1495 | 1495 |
| 1496 html_body_text = '<html><head><title>%s</title></head><body>%s</body
></html>'%(str(updated_tag),log_text) | 1496 html_body_text = '<html><head><title>%s</title></head><body>%s</body
></html>' % (str(updated_tag), log_text) |
| 1497 print >> output, '<td align=\"left\"><A HREF=\"#\" onClick=\"popup(\
'%s\',\'%s\')\">Info</A></td>'%(str(updated_tag),str(html_body_text)) | 1497 print >> output, '<td align=\"left\"><A HREF=\"#\" onClick=\"popup(\
'%s\',\'%s\')\">Info</A></td>' % (str(updated_tag), str(html_body_text)) |
| 1498 else: | 1498 else: |
| 1499 print >> output, '<td align=\"left\"></td>' | 1499 print >> output, '<td align=\"left\"></td>' |
| 1500 # print execution time | 1500 # print execution time |
| 1501 print >> output, '<td align="left"><A HREF=\"%s\">Debug</A></td>' % os.p
ath.join(dirname, res['title'], "debug") | 1501 print >> output, '<td align="left"><A HREF=\"%s\">Debug</A></td>' % os.p
ath.join(dirname, res['title'], "debug") |
| 1502 | 1502 |
| 1503 print >> output, '</tr>' | 1503 print >> output, '</tr>' |
| 1504 print >> output, "</tbody></table>" | 1504 print >> output, "</tbody></table>" |
| 1505 | 1505 |
| 1506 | 1506 |
| 1507 print >> output, '<h2 id=\"page_sub_title\">Host Info</h2>' | 1507 print >> output, '<h2 id=\"page_sub_title\">Host Info</h2>' |
| 1508 print >> output, '<h2 id=\"comment\">click on each item to expend/collapse</
h2>' | 1508 print >> output, '<h2 id=\"comment\">click on each item to expend/collapse</
h2>' |
| 1509 ## Meta list comes here.. | 1509 ## Meta list comes here.. |
| 1510 print >> output, '<p>' | 1510 print >> output, '<p>' |
| 1511 print >> output, '<A href="#" class="button" onClick="expandTree(\'meta_tree
\');return false;">Expand All</A>' | 1511 print >> output, '<A href="#" class="button" onClick="expandTree(\'meta_tree
\');return false;">Expand All</A>' |
| 1512 print >> output, '  ' | 1512 print >> output, '  ' |
| 1513 print >> output, '<A class="button" href="#" onClick="collapseTree(\'meta_tr
ee\'); return false;">Collapse All</A>' | 1513 print >> output, '<A class="button" href="#" onClick="collapseTree(\'meta_tr
ee\'); return false;">Collapse All</A>' |
| 1514 print >> output, '</p>' | 1514 print >> output, '</p>' |
| 1515 | 1515 |
| 1516 print >> output, '<ul class="mktree" id="meta_tree">' | 1516 print >> output, '<ul class="mktree" id="meta_tree">' |
| 1517 counter=0 | 1517 counter = 0 |
| 1518 keys = metadata.keys() | 1518 keys = metadata.keys() |
| 1519 keys.sort() | 1519 keys.sort() |
| 1520 for key in keys: | 1520 for key in keys: |
| 1521 val = metadata[key] | 1521 val = metadata[key] |
| 1522 print >> output, '<li id=\"meta_headline\">%s' % key | 1522 print >> output, '<li id=\"meta_headline\">%s' % key |
| 1523 print >> output, '<ul><table class="meta_table"><tr><td align="left">%s<
/td></tr></table></ul></li>' % val | 1523 print >> output, '<ul><table class="meta_table"><tr><td align="left">%s<
/td></tr></table></ul></li>' % val |
| 1524 print >> output, '</ul>' | 1524 print >> output, '</ul>' |
| 1525 | 1525 |
| 1526 print >> output, "</body></html>" | 1526 print >> output, "</body></html>" |
| 1527 if output_file_name: | 1527 if output_file_name: |
| 1528 output.close() | 1528 output.close() |
| 1529 | 1529 |
| 1530 | 1530 |
| 1531 def parse_result(dirname,line): | 1531 def parse_result(dirname, line): |
| 1532 parts = line.split() | 1532 parts = line.split() |
| 1533 if len(parts) < 4: | 1533 if len(parts) < 4: |
| 1534 return None | 1534 return None |
| 1535 global stimelist | 1535 global stimelist |
| 1536 if parts[0] == 'START': | 1536 if parts[0] == 'START': |
| 1537 pair = parts[3].split('=') | 1537 pair = parts[3].split('=') |
| 1538 stime = int(pair[1]) | 1538 stime = int(pair[1]) |
| 1539 stimelist.append(stime) | 1539 stimelist.append(stime) |
| 1540 | 1540 |
| 1541 elif (parts[0] == 'END'): | 1541 elif (parts[0] == 'END'): |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1553 result['exec_time_sec'] = 'na' | 1553 result['exec_time_sec'] = 'na' |
| 1554 tag = parts[3] | 1554 tag = parts[3] |
| 1555 | 1555 |
| 1556 # assign actual values | 1556 # assign actual values |
| 1557 rx = re.compile('^(\w+)\.(.*)$') | 1557 rx = re.compile('^(\w+)\.(.*)$') |
| 1558 m1 = rx.findall(parts[3]) | 1558 m1 = rx.findall(parts[3]) |
| 1559 result['testcase'] = m1[0][1] | 1559 result['testcase'] = m1[0][1] |
| 1560 result['title'] = str(tag) | 1560 result['title'] = str(tag) |
| 1561 result['status'] = parts[1] | 1561 result['status'] = parts[1] |
| 1562 if result['status'] != 'GOOD': | 1562 if result['status'] != 'GOOD': |
| 1563 result['log'] = get_exec_log(dirname,tag) | 1563 result['log'] = get_exec_log(dirname, tag) |
| 1564 if len(stimelist)>0: | 1564 if len(stimelist)>0: |
| 1565 pair = parts[4].split('=') | 1565 pair = parts[4].split('=') |
| 1566 etime = int(pair[1]) | 1566 etime = int(pair[1]) |
| 1567 stime = stimelist.pop() | 1567 stime = stimelist.pop() |
| 1568 total_exec_time_sec = etime - stime | 1568 total_exec_time_sec = etime - stime |
| 1569 result['exec_time_sec'] = total_exec_time_sec | 1569 result['exec_time_sec'] = total_exec_time_sec |
| 1570 return result | 1570 return result |
| 1571 return None | 1571 return None |
| 1572 | 1572 |
| 1573 | 1573 |
| 1574 def get_exec_log(resdir, tag): | 1574 def get_exec_log(resdir, tag): |
| 1575 stdout_file = os.path.join(resdir,tag) + '/debug/stdout' | 1575 stdout_file = os.path.join(resdir, tag) + '/debug/stdout' |
| 1576 stderr_file = os.path.join(resdir,tag) + '/debug/stderr' | 1576 stderr_file = os.path.join(resdir, tag) + '/debug/stderr' |
| 1577 status_file = os.path.join(resdir,tag) + '/status' | 1577 status_file = os.path.join(resdir, tag) + '/status' |
| 1578 dmesg_file = os.path.join(resdir,tag) + '/sysinfo/dmesg' | 1578 dmesg_file = os.path.join(resdir, tag) + '/sysinfo/dmesg' |
| 1579 log = '' | 1579 log = '' |
| 1580 log += '<br><b>STDERR:</b><br>' | 1580 log += '<br><b>STDERR:</b><br>' |
| 1581 log += get_info_file(stderr_file) | 1581 log += get_info_file(stderr_file) |
| 1582 log += '<br><b>STDOUT:</b><br>' | 1582 log += '<br><b>STDOUT:</b><br>' |
| 1583 log += get_info_file(stdout_file) | 1583 log += get_info_file(stdout_file) |
| 1584 log += '<br><b>STATUS:</b><br>' | 1584 log += '<br><b>STATUS:</b><br>' |
| 1585 log += get_info_file(status_file) | 1585 log += get_info_file(status_file) |
| 1586 log += '<br><b>DMESG:</b><br>' | 1586 log += '<br><b>DMESG:</b><br>' |
| 1587 log += get_info_file(dmesg_file) | 1587 log += get_info_file(dmesg_file) |
| 1588 return log | 1588 return log |
| 1589 | 1589 |
| 1590 | 1590 |
| 1591 def get_info_file(filename): | 1591 def get_info_file(filename): |
| 1592 data='' | 1592 data = '' |
| 1593 errors = re.compile(r"\b(error|fail|failed)\b", re.IGNORECASE) | 1593 errors = re.compile(r"\b(error|fail|failed)\b", re.IGNORECASE) |
| 1594 if os.path.isfile(filename): | 1594 if os.path.isfile(filename): |
| 1595 f = open('%s' % filename, "r") | 1595 f = open('%s' % filename, "r") |
| 1596 lines=f.readlines() | 1596 lines = f.readlines() |
| 1597 f.close() | 1597 f.close() |
| 1598 rx = re.compile('(\'|\")') | 1598 rx = re.compile('(\'|\")') |
| 1599 for line in lines: | 1599 for line in lines: |
| 1600 new_line = rx.sub('',line) | 1600 new_line = rx.sub('', line) |
| 1601 errors_found = errors.findall(new_line) | 1601 errors_found = errors.findall(new_line) |
| 1602 if len(errors_found)>0: | 1602 if len(errors_found) > 0: |
| 1603 data += '<font color=red>%s</font><br>'%str(new_line) | 1603 data += '<font color=red>%s</font><br>' % str(new_line) |
| 1604 else: | 1604 else: |
| 1605 data += '%s<br>'%str(new_line) | 1605 data += '%s<br>' % str(new_line) |
| 1606 if not data: | 1606 if not data: |
| 1607 data = 'No Information Found.<br>' | 1607 data = 'No Information Found.<br>' |
| 1608 else: | 1608 else: |
| 1609 data = 'File not found.<br>' | 1609 data = 'File not found.<br>' |
| 1610 return data | 1610 return data |
| 1611 | 1611 |
| 1612 | 1612 |
| 1613 | 1613 |
| 1614 def usage(): | 1614 def usage(): |
| 1615 print 'usage:', | 1615 print 'usage:', |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1680 html_path = '' | 1680 html_path = '' |
| 1681 | 1681 |
| 1682 if dirname: | 1682 if dirname: |
| 1683 if os.path.isdir(dirname): # TBD: replace it with a validation of | 1683 if os.path.isdir(dirname): # TBD: replace it with a validation of |
| 1684 # autotest result dir | 1684 # autotest result dir |
| 1685 res_dir = os.path.abspath(dirname) | 1685 res_dir = os.path.abspath(dirname) |
| 1686 tag = res_dir | 1686 tag = res_dir |
| 1687 status_file_name = dirname + '/status' | 1687 status_file_name = dirname + '/status' |
| 1688 sysinfo_dir = dirname + '/sysinfo' | 1688 sysinfo_dir = dirname + '/sysinfo' |
| 1689 host = get_info_file('%s/hostname' % sysinfo_dir) | 1689 host = get_info_file('%s/hostname' % sysinfo_dir) |
| 1690 rx=re.compile('^\s+[END|START].*$') | 1690 rx = re.compile('^\s+[END|START].*$') |
| 1691 # create the results set dict | 1691 # create the results set dict |
| 1692 results_data=[] | 1692 results_data = [] |
| 1693 if os.path.exists(status_file_name): | 1693 if os.path.exists(status_file_name): |
| 1694 f = open(status_file_name, "r") | 1694 f = open(status_file_name, "r") |
| 1695 lines=f.readlines() | 1695 lines = f.readlines() |
| 1696 f.close() | 1696 f.close() |
| 1697 for line in lines: | 1697 for line in lines: |
| 1698 if rx.match(line): | 1698 if rx.match(line): |
| 1699 result_dict = parse_result(dirname, line) | 1699 result_dict = parse_result(dirname, line) |
| 1700 if result_dict: | 1700 if result_dict: |
| 1701 results_data.append(result_dict) | 1701 results_data.append(result_dict) |
| 1702 # create the meta info dict | 1702 # create the meta info dict |
| 1703 metalist = { | 1703 metalist = { |
| 1704 'uname': get_info_file('%s/uname' % sysinfo_dir), | 1704 'uname': get_info_file('%s/uname' % sysinfo_dir), |
| 1705 'cpuinfo':get_info_file('%s/cpuinfo' % sysinfo_dir), | 1705 'cpuinfo':get_info_file('%s/cpuinfo' % sysinfo_dir), |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1718 else: | 1718 else: |
| 1719 print 'Invalid result directory <%s>' % dirname | 1719 print 'Invalid result directory <%s>' % dirname |
| 1720 sys.exit(1) | 1720 sys.exit(1) |
| 1721 else: | 1721 else: |
| 1722 usage() | 1722 usage() |
| 1723 sys.exit(1) | 1723 sys.exit(1) |
| 1724 | 1724 |
| 1725 | 1725 |
| 1726 if __name__ == "__main__": | 1726 if __name__ == "__main__": |
| 1727 main(sys.argv[1:]) | 1727 main(sys.argv[1:]) |
| OLD | NEW |