	public Function compileTemplate(final Scriptable scope, CharSequence source, final String sourceName) {
		final Context cx=runtime.enter();
		try {
			final Scriptable fragments=cx.newArray(scope, 0);
			EjsParser.Events events=new EjsParser.Events() {
				int fragmentIndex=0;
				public void handleLiteral(CharSequence text, LocationInfo location) {
					int index=fragmentIndex++;
					ScriptableObject.putProperty(fragments, index, text.toString());
				}
				public void handleInterpolation(CharSequence script, LocationInfo location) {
					StringBuilder interpDefn=new StringBuilder(script.length()+50);
					interpDefn.append("function(){return String(")
						.append(script).append(");}");
					Function interpFunction=cx.compileFunction(scope, interpDefn.toString(), 
							sourceName, location.getLineStart(), null);
					int index=fragmentIndex++;
					ScriptableObject.putProperty(fragments, index, interpFunction);
				}
				public void handleBlock(CharSequence script, LocationInfo location) {
					StringBuilder blockDefn=new StringBuilder(script.length()+50);
					blockDefn.append("function(){").append(script)
						.append("; return '';}");
					Function blockFunction=cx.compileFunction(scope, blockDefn.toString(), 
							sourceName, location.getLineStart(), null);
					int index=fragmentIndex++;
					ScriptableObject.putProperty(fragments, index, blockFunction);
				}
			};
			EjsParser parser=new EjsParser(events);
			parser.parse(source);
			return (Function) evaluatorFunction.call(cx, scope, null, new Object[] { fragments });
		} finally {
			runtime.exit();
		}
	}

	public Function compileTemplate(final Scriptable scope, CharSequence source, final String sourceName) {
		final Context cx=runtime.enter();
		try {
			final Scriptable fragments=cx.newArray(scope, 0);
			EjsParser.Events events=new EjsParser.Events() {
				int fragmentIndex=0;
				public void handleLiteral(CharSequence text, LocationInfo location) {
					int index=fragmentIndex++;
					ScriptableObject.putProperty(fragments, index, text.toString());
				}
				public void handleInterpolation(CharSequence script, LocationInfo location) {
					StringBuilder interpDefn=new StringBuilder(script.length()+50);
					interpDefn.append("function(){var expr=")
						.append(script).append(";return (expr===null||expr===undefined) ? null : String(expr);}");
					Function interpFunction=cx.compileFunction(scope, interpDefn.toString(), 
							sourceName, location.getLineStart(), null);
					int index=fragmentIndex++;
					ScriptableObject.putProperty(fragments, index, interpFunction);
				}
				public void handleBlock(CharSequence script, LocationInfo location) {
					StringBuilder blockDefn=new StringBuilder(script.length()+50);
					blockDefn.append("function(){").append(script)
						.append("; return '';}");
					Function blockFunction=cx.compileFunction(scope, blockDefn.toString(), 
							sourceName, location.getLineStart(), null);
					int index=fragmentIndex++;
					ScriptableObject.putProperty(fragments, index, blockFunction);
				}
			};
			EjsParser parser=new EjsParser(events);
			parser.parse(source);
			return (Function) evaluatorFunction.call(cx, scope, null, new Object[] { fragments });
		} finally {
			runtime.exit();
		}
	}
