_ExecutorIframe.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <html><head>
  2. <script type="text/javascript">
  3. Array.prototype._toString = Array.prototype.toString;
  4. Array.prototype.toString = function(){ return "[" + this._toString() + "]"; };
  5. Number.prototype._toString = Number.prototype.toString;
  6. Number.prototype.toString = function(radix){ if(!radix || radix==10){ return ""+this._toString() } if(radix==2){ return "0b"+this._toString(radix); } if(radix==8){ return "0o"+this._toString(radix); } if(radix==16){ return "0x"+this._toString(radix); } return this._toString(radix) + "#" + radix._toString(); };
  7. (function(){ // env is private
  8. parseFloat = function(str){
  9. var obj = null;
  10. function getRadixObject(whole, numberStr, base){
  11. obj = {number:numberStr, radix:base};
  12. return "";
  13. }
  14. function getBaseString(whole, base, numberStr){
  15. var baseNum = (base == '0b') ? 2 : (base == '0o') ? 8 : 16;
  16. return numberStr+"#"+baseNum;
  17. }
  18. var str = str.replace(/(0b|0o|0x)(([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+))/, getBaseString);
  19. var radix;
  20. var poundRegExp = /([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+)\#([0-9a-zA-Z]+)/g;
  21. if(poundRegExp.test(str)){
  22. // define obj in getRadixObject
  23. str.replace(poundRegExp, getRadixObject);
  24. radix = obj.radix;
  25. str = obj.number;
  26. }
  27. if(!radix){
  28. radix = 10;
  29. }
  30. var decimal = str.indexOf('.');
  31. if(decimal>=0){
  32. var left = str.substring(0,decimal);
  33. if(left == ""){
  34. left = "0";
  35. }
  36. var right = str.substring(decimal+1, str.length);
  37. if(right == ""){
  38. right = "0";
  39. }
  40. var num = parseInt(left, radix);
  41. var dec = parseInt(right, radix);
  42. var length = dec._toString().length;
  43. dec /= Math.pow(radix, right.length);
  44. return num+dec;
  45. }
  46. return parseInt(str, radix);
  47. };
  48. var env = {
  49. window: undefined, "delete": undefined, "new": undefined, // invalidate access to the globals for security so that window.blah is invalid as is delete window
  50. prompt: function(label, defaultValue){
  51. // summary
  52. // prompt the user for input without making IE8 mad.
  53. // params
  54. // label: the String name of the variable you are asking the user to input
  55. // defaultValue: primitive, the prompt will show this value initially
  56. label = label || '';
  57. defaultValue = defaultValue || '';
  58. try{
  59. return this.outerPrompt(label, defaultValue);
  60. }catch(e){
  61. return window.prompt(label, defaultValue);
  62. }
  63. },
  64. val: function(local, name, obj){
  65. // summary
  66. // allow the user to use locals, globals, or give input for undefined values
  67. // params:
  68. // local, a primitive object, is what value might've been passed to val as a local parameter.
  69. // name is the String name of the object. It is passed to see if there is an available global or to set the global.
  70. var objValue = obj[name];
  71. local = (objValue == undefined) ? (local == undefined ? window[name] : local) : objValue ;
  72. if(typeof local == 'undefined'){
  73. if(obj.graphing){
  74. return undefined;
  75. }
  76. local=this.prompt('Enter the value for ' + name, undefined, name);
  77. return local == null ? undefined : (isNaN(Number(local)) ? local : Number(local));
  78. }
  79. return local;
  80. },
  81. _makeKeywordsLiteral: function (text){
  82. // summary
  83. // surround reserved words with hex characters
  84. // ==, then >=. the <=, then !=, then = and surround them with \x0n first
  85. text = text.replace(/(!=(?!=)|==|>=|<=|=)/g, "\x02$1\x02");
  86. return text.replace(/\b(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|do|double|else|enum|export|extends|false|final|finally|float|for|function|goto|if|implements|import|in| instanceof|int|interface|long|native|null|package|private|protected|public|return|short|static|super| switch|synchronized|this|throw|throws|transient|true|try|typeof|var|void|volatile|while|with)\b/g, "\x02$1\x02");
  87. },
  88. switchToGermanNumbers: function(text){
  89. // summary
  90. // change the format of some javascript allowed numbers to an alternate form 3.5 goes to 3,5
  91. var num = 0;
  92. var numbers = [];
  93. function substituteCommas(whole, junk, text){
  94. numbers['_'+num+'_'] = text.replace(/\,/g, ';');
  95. return junk+'_'+(num++)+'_';
  96. }
  97. function substituteNumbers(wholematch, stuff, junk, text, stuff2){
  98. return stuff+numbers[text]+stuff2;
  99. }
  100. if(typeof text != "string"){
  101. text = text.toString();
  102. }
  103. if(text.indexOf('\x02')<0){
  104. text = this._makeKeywordsLiteral(text);
  105. //text = text.replace(/(!=(?!=)|==|>=|<=|=)/g, "\x02$1\x02");
  106. }
  107. // same as semiColonRegExp
  108. var commaRegExp = /([^\x02\s]*)(\([^\(\)]+\)|\[[^\[\]]+\])/;
  109. while(commaRegExp.test(text)){
  110. text = text.replace(commaRegExp , substituteCommas);
  111. }
  112. while(/((\W)*)(\_[0-9]+\_)((\W)*)/.test(text)){
  113. text = text.replace(/((\W)*)(\_[0-9]+\_)((\W)*)/g, substituteNumbers);
  114. }
  115. text = text.replace(/([0-9]*)\.([0-9]+)/g, "$1"+','+"$2");
  116. // get rid of keyword characters (duplicate code from parse())
  117. return text.replace(/\x02((.|\s)*?)\x02/g, "$1");
  118. },
  119. normalizeTextLanguage: function(text){
  120. // summary
  121. // change text to use javascript list separators and decimal points instead of commas
  122. // params
  123. // text is a string like "pow(3,1; 4);"
  124. // for that input, this method should return "pow(3.1, 4);"
  125. var num = 0;
  126. var numbers = [];
  127. function substituteSemicolons(whole, junk, text){
  128. numbers['_'+num+'_'] = text.replace(/\;/g, ',');
  129. return junk+'_'+(num++)+'_';
  130. }
  131. function substituteNumbers(wholematch, stuff, junk, text, stuff2){
  132. return stuff+numbers[text]+stuff2;
  133. }
  134. if(text.indexOf('\x02')<0){
  135. text = this._makeKeywordsLiteral(text);
  136. }
  137. // change all comma-type decimals into periods
  138. text = text.replace(/([0-9]*)\,([0-9]+)/g, "$1"+'.'+"$2");
  139. //alert(text);
  140. var semiColonRegExp = /([^\x02\s]*)(\([^\(\)]+\)|\[[^\[\]]+\])/; // /([^\x02\s]+)(\([^\(\)]+\)|\[[^\[\]]+\])/; // /[^\x02\s]+\([^\(\)]+\)|[^\x02\s]+\[[^\[\]]+\]/; // /[^\x02]\s*\([^\(]+\)/;
  141. while(semiColonRegExp.test(text)){
  142. text = text.replace(semiColonRegExp, substituteSemicolons);
  143. }
  144. while(/((\W)*)(\_[0-9]+\_)((\W)*)/.test(text)){
  145. text = text.replace(/((\W)*)(\_[0-9]+\_)((\W)*)/g, substituteNumbers);
  146. }
  147. // get rid of keyword characters (duplicate code from parse())
  148. return text.replace(/\x02((.|\s)*?)\x02/g, "$1");
  149. },
  150. preparse: function(text){
  151. // summary
  152. // change the numbers to javascript allowed numbers if it is from a different locale
  153. if(!this.isJavaScriptLanguage){
  154. text = this.normalizeTextLanguage(text);
  155. }
  156. return text;
  157. },
  158. // parseFloat(Number(4.5).toString(3)) should return 4.5
  159. postparse: function(text){
  160. // summary
  161. // make the javascript numbers match the locale
  162. if(!this.isJavaScriptLanguage){
  163. text = this.switchToGermanNumbers(text);
  164. }
  165. return text;
  166. },
  167. toDecimalRegExp: function(whole, base, number){
  168. // summary
  169. // get the decimal number from a float
  170. function getBase(base){
  171. switch(base){
  172. case '0b':
  173. return 2;
  174. case '0o':
  175. return 8;
  176. case '0x':
  177. return 16;
  178. default:
  179. return 10;
  180. }
  181. }
  182. //return parseInt(base, getBase(base));
  183. return parseFloat(base+number);
  184. },
  185. parse: function(text){
  186. // summary
  187. // This parses augmented mathematical syntax and converts it to executable JavaScript.
  188. // params:
  189. // text should be a String which represents an expression, a function, a number, etc
  190. //
  191. // this array holds the substitutions that represent an expression's parentheses and functions in a simplified way.
  192. var numbers = [],
  193. // characters
  194. functionContentsChar = '\x03',
  195. // these are the regular expression needed to find and replace operators
  196. factorialRE = /((\w|\.)+)\s*\!/,
  197. unaryRightsideRE = /(^|[\+\-\/\*\!\^\u221A]+\s*)([\+\-]+)\s*((\w|\.)+)(?!.*[\+\-])/,
  198. unaryRE = /(^|[^a-zA-Z0-9_\.\s]+\s*)([\+\-]+|\u221A)\s*((\w|\.)+)/, // /(^|[^a-zA-Z0-9_\.]\s*)([\+\-]+|\u221A)\s*((\w|\.)+)/,
  199. caretRE = /((\w|\.)+)\s*([\^])\s*((\w|\.)+)/, // /((\w|\.)+)\s*([\^])\s*(-?\s*(\w|\.)+)/,
  200. radicalRE = /((\w|\.)+)\s*(\u221A)\s*([+-]?\s*(\w|\.)+)/, // /((\w|\.)+)\s*(\u221A)\s*([+-]?\s*(\w|\.)+)(?!.*\u221A)/,
  201. binaryHighRE = /((\w|\.)+)\s*([*/])\s*((\w|\.)+)/,
  202. binaryLowRE = /((\w|\.)+)\s*([\+\-])+\s*((\w|\.)+)/;
  203. // get rid of all new and delete statements
  204. text = exterminateNewAndDelete(text);
  205. // make all keywords and operators literal (like '!=' or 'return') by surrounding them with unprintable characters
  206. text = this._makeKeywordsLiteral(text);
  207. function getBaseTen(whole, numberStr, base){
  208. return ""+parseFloat(numberStr+"#"+parseInt(base));
  209. }
  210. text = text.replace(/(0b)([0-1]+\.[0-1]*|\.[0-1]+|[0-1]+)/g, this.toDecimalRegExp);
  211. text = text.replace(/(0o)([0-7]+\.[0-7]*|\.[0-7]+|[0-7]+)/g, this.toDecimalRegExp);
  212. text = text.replace(/(0x)([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+)/g, this.toDecimalRegExp);
  213. text = text.replace(/([0-9a-zA-Z]+\.[0-9a-zA-Z]*|\.[0-9a-zA-Z]+|[0-9a-zA-Z]+)\#([0-9a-zA-Z]+)/g, getBaseTen);
  214. // parse the input to form JavaScript
  215. return MathParser(text);
  216. function MathParser(text){
  217. // Pi is better represented by \u03C0, but isn't computable
  218. text = text.replace(/\u03C0/g,"Math.PI");
  219. text = text.replace(/\u03F5/g,"Math.E");
  220. // Microsoft word will give you these '\u2013' for a subtraction sign sometimes, so I'll fix that here
  221. text = text.replace(/\u2013/g, "-");
  222. // add unreadable characters in front of functions so it is easier to manipulate
  223. text = text.replace(/(((\w|\.)+\s*)\()/g,putFuncChar);
  224. // change 10e-10 or 10e10 or 10e+10 to an constant right away
  225. text = scientificNotationSimplifier(text);
  226. // recursively track down and replace all simplified parts of the expression until everything is simple; then move the simple text into the correct JavaScript format
  227. text = parseRecursive(text);
  228. // now resubstitute the real text back into the string now that it is arranged correctly
  229. while (hasArrayIndexBasedOnUnderscore(text)){
  230. text = text.replace(/\_(\d+)\_/g, function(whole, one){return numbers[parseInt(one)]});
  231. }
  232. // get rid of the function character from the functions now
  233. text = text.replace(/\x01/g,"");
  234. // get rid of keyword characters too
  235. text = text.replace(/\x02((.|\s)*?)\x02/g, "$1");
  236. return text;
  237. }
  238. function exterminateNewAndDelete(text){
  239. return text.replace(/\b(delete|new|this\.*)\b/, "");
  240. }
  241. // A simple grouping has no parentheses inside the initial pair.
  242. function isSimpleGrouping(text){
  243. return (/^\([^()]*\)|\W\([^()]*\)/).test(text);
  244. }
  245. function ReplaceSimpleGrouping(text){
  246. return text.replace((/(^|\W)(\([^()]*\))/), replaceWithNum);
  247. }
  248. function replaceWithNum(wholeMatch, partMatch1, partMatch2){
  249. numbers.push(partMatch2);
  250. return partMatch1+"_"+(numbers.length-1)+"_";
  251. }
  252. function replaceFuncWithNum(wholeMatch){
  253. numbers.push(wholeMatch);
  254. return "_"+(numbers.length-1)+"_";
  255. }
  256. // A simple function has no parentheses within its parentheses, and has the special character \x01 leading up to the name and (...)
  257. function isSimpleFunction(text){
  258. return (/\x01((\w|\.)+\s*)\([^()]*\)/).test(text);
  259. }
  260. function ReplaceSimpleFunction(text){
  261. return text.replace(/\x01((\w|\.)+\s*)\([^()]*\)/, replaceFuncWithNum);
  262. }
  263. function FactorialParser(text){
  264. // loop this untill all ! are gone (in main)
  265. return text.replace(factorialRE, "\x01"+"factorial($1)");
  266. }
  267. function putFuncChar(wholematch){
  268. return '\x01'+wholematch;
  269. }
  270. function putInPiece(wholematch){
  271. return numbers[currentNum];
  272. }
  273. function caretParser(text){
  274. return text.replace(caretRE, replaceBinaryOp);
  275. }
  276. // the unary radical is inside the unaryOperatorParse(text) function
  277. function radicalOperatorParse(text){
  278. return text.replace(radicalRE, replaceBinaryOp);
  279. }
  280. function replaceBinaryOp(wholeMatch, operand1, nothing1, operator, operand2){
  281. switch(operator.charAt(0)){
  282. case '^':
  283. return "\x01"+"pow("+operand1+","+operand2+")";
  284. case '\u221A':
  285. return "\x01"+"pow("+operand2+", 1/"+operand1+")";
  286. case '*':
  287. case '/':
  288. return replaceFuncWithNum(wholeMatch);
  289. case '+':
  290. case '-':
  291. case 'e':
  292. return replaceFuncWithNum(simplifyPlusAnsMinus(wholeMatch));
  293. }
  294. }
  295. // e is treated as a binary operator
  296. function scientificNotationSimplifier(text){
  297. //return text.replace(/((\w|\.)+)\s*([\e])\s*([+-]*\s*(\w|\.)+)/g, replaceBinaryOp);
  298. return text.replace(/(([0-9]+\.?[0-9]*))(e)([+-]*([0-9]+))/g, replaceBinaryOp);
  299. }
  300. // this handles * and /
  301. function binaryHighPriorityOperatorParse(text){
  302. return text.replace(binaryHighRE, replaceBinaryOp);
  303. }
  304. // this handles + and - with two operands
  305. function binaryLowPriorityOperatorParse(text){
  306. return text.replace(binaryLowRE, replaceBinaryOp);
  307. }
  308. // this replaces the one operand +'s, -'s, and radicals
  309. function replaceUnaryOp(wholeMatch, garbage, operator0, operand0){
  310. // see what operator it is
  311. switch(operator0.charAt(0)){
  312. case '\u221A':
  313. return garbage+"\x01"+"sqrt("+operand0+")";
  314. case '+':
  315. case '-':
  316. return garbage+replaceFuncWithNum(simplifyPlusAnsMinus(wholeMatch.substr(garbage.length)));
  317. }
  318. }
  319. // this handles one operand operators -, +, radical
  320. function unaryOperatorParse(text){
  321. return text.replace(unaryRE, replaceUnaryOp);
  322. }
  323. // this handles one operand operators on the right side of everything
  324. function unaryOperatorRightsideParse(text){
  325. return text.replace(unaryRightsideRE, replaceUnaryOp);
  326. }
  327. function parseRecursive(text){
  328. // keep going until there is nothing left that can be simplified
  329. while (isSimpleGrouping(text)||isSimpleFunction(text)||factorialRE.test(text)||caretRE.test(text)||radicalRE.test(text)||unaryRE.test(text)||binaryHighRE.test(text)||binaryLowRE.test(text)){
  330. var sTextOrginal = text;
  331. if(isSimpleFunction(text)){
  332. var debugText = text;
  333. text = ReplaceSimpleFunction(text);
  334. var s = numbers[numbers.length-1],
  335. pL = s.indexOf("("),
  336. funcName = s.substring(s.indexOf("\x01")+1, pL),//take out the function character
  337. content = s.substring(pL+1, s.length-1);
  338. numbers[numbers.length-1] = funcName+"("+parseRecursive(functionContentsChar+content)+")";
  339. continue;
  340. }
  341. if(isSimpleGrouping(text)){
  342. text = ReplaceSimpleGrouping(text);
  343. var s = numbers[numbers.length-1],
  344. content = s.substring(1, s.length-1);
  345. numbers[numbers.length-1] = "("+parseRecursive(content)+")";
  346. continue;
  347. }
  348. // factorials must come first for 5^2! cases, it equals 25
  349. text = FactorialParser(text);
  350. if(text!=sTextOrginal){
  351. continue;
  352. }
  353. text = caretParser(text);
  354. if(text!=sTextOrginal){
  355. continue;
  356. }
  357. text = radicalOperatorParse(text);
  358. if(text!=sTextOrginal){
  359. continue;
  360. }
  361. text = unaryOperatorRightsideParse(text);
  362. if(text!=sTextOrginal){
  363. // put parentheses around the unary operators so 0--2 will pass
  364. numbers[numbers.length-1] = "("+numbers[numbers.length-1]+")";
  365. continue;
  366. }
  367. text = unaryOperatorParse(text);
  368. if(text!=sTextOrginal){
  369. // put parentheses around the unary operators so 0--2 will pass
  370. numbers[numbers.length-1] = "("+numbers[numbers.length-1]+")";
  371. continue;
  372. }
  373. text = binaryHighPriorityOperatorParse(text);
  374. if(text!=sTextOrginal){
  375. continue;
  376. }
  377. text = binaryLowPriorityOperatorParse(text);
  378. if(text!=sTextOrginal){
  379. continue;
  380. }
  381. // it should never ever make it to this point. If it does, I'll want to know about it.
  382. throw("Parse Error");
  383. }
  384. // make assignments within function calls be arranged to be (x=y, undefined)
  385. if(text.charAt(0) == functionContentsChar){
  386. text = text.substring(1, text.length);
  387. if(text.indexOf('=') >= 0){
  388. text = ReplaceFunctionContentAssignments(text);
  389. }
  390. }
  391. return text;
  392. }
  393. function ReplaceFunctionContentAssignments(text){
  394. return text.replace(/((\w|\.)+)\x02=\x02((\w|\.)+)/g, "("+"$1"+'\x02=\x02'+"$3"+", {_name:'"+"$1"+"', _value:"+"$3"+"})");
  395. }
  396. function hasArrayIndexBasedOnUnderscore(text){
  397. return /\_\d+\_/.test(text);
  398. }
  399. function simplifyPlusAnsMinus(text){
  400. function hasUnsimplifiedPlusMinus(text){
  401. return /\-\s*\-/.test(text)||/\+\s*\+/.test(text)||/\+\s*\-/.test(text)||/\-\s*\+/.test(text);
  402. }
  403. while(hasUnsimplifiedPlusMinus(text)){
  404. text = text.replace(/((\-\s*\-)|(\+\s*\+))/g, "+");
  405. text = text.replace(/((\+\s*\-)|(\-\s*\+))/g, "-");
  406. }
  407. return text;
  408. }
  409. },
  410. eval: function(text){
  411. // summary
  412. // create an anonymous function to run the code the parser generates from the user input.
  413. // params
  414. // text, type String, is the user input that needs to be parsed
  415. // this try catch is necessary to ensure that any incorrect input will receive NaN (it won't cause a self destruct from a user typo)
  416. try{
  417. var value = this.Function(undefined, '', 'return ' + text).call(this); // make sure it is called within the correct scope.
  418. //value = ((value instanceof Array || typeof value == "array") ? ("["+value+"]") : value.toString())
  419. return this.postparse(value);
  420. }catch(e){
  421. return NaN;
  422. }
  423. },
  424. normalizedFunction: function(name, args, body){
  425. // summary
  426. // create an anonymous function to run the code the parser generates from the user input.
  427. // params
  428. // name: this argument is simply a String that represents the name of the function being evaluated. It can be undefined, but in that case the function is a one time use.
  429. // args: the function arguments (a String)
  430. // body: the function body, also a String
  431. var argMultiVals = '',
  432. // make an array of parameters with what's given (if nothing is given, make an empty array)
  433. params = args ? (args||'').split(/\W+/) : [];
  434. argMultiVals += 'var _localObjectContainer = {};\n'+
  435. 'for(var _objCnt = 0; _objCnt < arguments.length; _objCnt++){\n'+
  436. 'if(typeof arguments[_objCnt] == "object" && "_name" in arguments[_objCnt] && "_value" in arguments[_objCnt]){\n'+
  437. '_localObjectContainer.graphing = arguments[_objCnt]._graphing;\n'+
  438. '_localObjectContainer[arguments[_objCnt]._name]=arguments[_objCnt]._value;\n'+
  439. 'arguments[_objCnt]=undefined;\n}\n}\n';
  440. // make the parameters fit into the val function so it can use either globals, locals, or if all are null, prompt the user for input
  441. for(var i=0; i < params.length; i++){
  442. var param = params[i];
  443. argMultiVals += param + '=val(' + param + ',"' + param + '", _localObjectContainer);\n';
  444. argMultiVals += 'if(typeof '+param+' == "undefined"){\n'+
  445. 'return null;}\n';
  446. }
  447. var _f_ = window.Function.apply(this,
  448. [
  449. args,
  450. 'with(Math){with(this.dojox.math){with(this){\n' +
  451. argMultiVals +
  452. this.parse(body) +
  453. '\n}}}'
  454. ]
  455. );
  456. if(name){
  457. return this[name] = _f_;
  458. }
  459. return _f_;
  460. },
  461. Function: function(name, args, body){
  462. // summary
  463. // create an anonymous function to run the code the parser generates from the user input. It also normalizes the language format.
  464. // params
  465. // name: this argument is simply a String that represents the name of the function being evaluated. It can be undefined, but in that case the function is a one time use.
  466. // args: the function arguments (a String)
  467. // body: the function body, also a String
  468. body = this.preparse(body);
  469. return this.normalizedFunction(name, args, body);
  470. }
  471. };
  472. for(var i in window){
  473. if(!(i in env) && i != "alert" && i != "confirm"){ env[i] = undefined; } // invalidate access to the window object's attributes for security so that document.blah is invalid
  474. }
  475. frameElement.onload(env);
  476. })();
  477. </script>
  478. </head><body>
  479. <script type="text/javascript">
  480. document.documentElement.removeChild(document.documentElement.firstChild); // remove HEAD to remove debugger access for extra security
  481. </script>
  482. </body></html>