17d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#!/usr/bin/env python 27d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)# Copyright (c) 2013 The Chromium Authors. All rights reserved. 37d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 47d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)# found in the LICENSE file. 57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 67d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)"""Creates simple HTML for running a NaCl module. 77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)This script is designed to make the process of creating running 97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)Native Client executables in the browers simple by creating 107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)boilderplate a .html (and optionally a .nmf) file for a given 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)Native Client executable (.nexe). 127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)If the script if given a .nexe file it will produce both html 147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)the nmf files. If it is given an nmf it will only create 157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)the html file. 167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)""" 177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)import optparse 197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)import os 207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)import sys 217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)import subprocess 227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)HTML_TEMPLATE = '''\ 257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)<!DOCTYPE html> 267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)<!-- 277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)Sample html container for embedded NaCl module. This file was auto-generated 287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)by the create_html tool which is part of the NaCl SDK. 297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)The embed tag is setup with PS_STDOUT, PS_STDERR and PS_TTY_PREFIX attributes 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)which, for applications linked with ppapi_simple, will cause stdout and stderr 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)to be sent to javascript via postMessage. Also, the postMessage listener 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)assumes that all messages sent via postMessage are strings to be displayed in 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)the output textarea. 357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)--> 367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)<html> 377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)<head> 387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <meta http-equiv="Pragma" content="no-cache"> 397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <meta http-equiv="Expires" content="-1"> 407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <title>%(title)s</title> 417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)</head> 437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)<body> 447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <h2>Native Client Module: %(module_name)s</h2> 457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <p>Status: <code id="status">Loading</code></p> 467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <div id="listener"> 487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <embed id="nacl_module" name="%(module_name)s" src="%(nmf)s" 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) type="application/x-nacl" width=640 height=480 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PS_TTY_PREFIX="tty:" 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PS_STDOUT="/dev/tty" 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) PS_STDERR="/dev/tty" >/ 537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) </div> 547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <p>Standard output/error:</p> 567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <textarea id="stdout" rows="25" cols="80"> 577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)</textarea> 587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) <script> 607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)listenerDiv = document.getElementById("listener") 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)stdout = document.getElementById("stdout") 627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)nacl_module = document.getElementById("nacl_module") 637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)function updateStatus(message) { 657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) document.getElementById("status").innerHTML = message 667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)function addToStdout(message) { 697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) stdout.value += message; 707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) stdout.scrollTop = stdout.scrollHeight; 717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)function handleMessage(message) { 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var payload = message.data; 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var prefix = "tty:"; 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (typeof(payload) == 'string' && payload.indexOf(prefix) == 0) { 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) addToStdout(payload.slice(prefix.length)); 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)function handleCrash(event) { 827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) updateStatus("Crashed/exited with status: " + nacl_module.exitStatus) 837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)function handleLoad(event) { 867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) updateStatus("Loaded") 877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)listenerDiv.addEventListener("load", handleLoad, true); 907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)listenerDiv.addEventListener("message", handleMessage, true); 917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)listenerDiv.addEventListener("crash", handleCrash, true); 927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) </script> 937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)</body> 947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)</html> 957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)''' 967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)class Error(Exception): 997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) pass 1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)def Log(msg): 1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if Log.enabled: 1047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sys.stderr.write(str(msg) + '\n') 1057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)Log.enabled = False 1067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)def CreateHTML(filenames, options): 1097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) nmf = None 1107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for filename in filenames: 1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if not os.path.exists(filename): 1137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) raise Error('file not found: %s' % filename) 1147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if not os.path.isfile(filename): 1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) raise Error('specified input is not a file: %s' % filename) 1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) basename, ext = os.path.splitext(filename) 1197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if ext not in ('.nexe', '.pexe', '.nmf'): 1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) raise Error('input file must be .nexe, .pexe or .nmf: %s' % filename) 1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if ext == '.nmf': 1237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if len(filenames) > 1: 1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) raise Error('Only one .nmf argument can be specified') 1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) nmf = filename 1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) elif len(filenames) > 1 and not options.output: 1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) raise Error('When specifying muliple input files -o must' 1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ' also be specified.') 1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) htmlfile = options.output 1317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if not htmlfile: 1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) htmlfile = basename + '.html' 1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) basename = os.path.splitext(os.path.basename(htmlfile))[0] 1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if not nmf: 1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) nmf = os.path.splitext(htmlfile)[0] + '.nmf' 1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Log('creating nmf: %s' % nmf) 1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) create_nmf = os.path.join(SCRIPT_DIR, 'create_nmf.py') 1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) staging = os.path.dirname(nmf) 1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if not staging: 1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) staging = '.' 1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cmd = [create_nmf, '-s', staging, '-o', nmf] + filenames 1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if options.verbose: 1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cmd.append('-v') 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if options.debug_libs: 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cmd.append('--debug-libs') 1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Log(cmd) 1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) try: 1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) subprocess.check_call(cmd) 1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) except subprocess.CalledProcessError: 1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) raise Error('create_nmf failed') 1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Log('creating html: %s' % htmlfile) 1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) with open(htmlfile, 'w') as outfile: 1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) args = {} 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) args['title'] = basename 1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) args['module_name'] = basename 1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) args['nmf'] = os.path.basename(nmf) 1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) outfile.write(HTML_TEMPLATE % args) 1607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)def main(argv): 1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) usage = 'Usage: %prog [options] <.nexe/.pexe or .nmf>' 1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) epilog = 'Example: create_html.py -o index.html my_nexe.nexe' 1650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) parser = optparse.OptionParser(usage, description=__doc__, epilog=epilog) 1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) parser.add_option('-v', '--verbose', action='store_true', 1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) help='Verbose output') 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch parser.add_option('-d', '--debug-libs', action='store_true', 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch help='When calling create_nmf request debug libaries') 1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) parser.add_option('-o', '--output', dest='output', 1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) help='Name of html file to write (default is ' 1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 'input name with .html extension)', 1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) metavar='FILE') 1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # To enable bash completion for this command first install optcomplete 1760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # and then add this line to your .bashrc: 1770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) # complete -F _optcomplete create_html.py 1780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) try: 1790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) import optcomplete 1800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) optcomplete.autocomplete(parser) 1810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) except ImportError: 1820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) pass 1830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) options, args = parser.parse_args(argv) 1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if not args: 1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) parser.error('no input file specified') 1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if options.verbose: 1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Log.enabled = True 1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) CreateHTML(args, options) 1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return 0 1947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)if __name__ == '__main__': 1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) try: 1987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) rtn = main(sys.argv[1:]) 1997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) except Error, e: 2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sys.stderr.write('%s: %s\n' % (os.path.basename(__file__), e)) 2017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) rtn = 1 2027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) except KeyboardInterrupt: 2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sys.stderr.write('%s: interrupted\n' % os.path.basename(__file__)) 2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) rtn = 1 2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) sys.exit(rtn) 206