Throwable evaluate() {
        // Create a passthrough wrapper
        ServletRequestWrapper request = new HttpServletRequestWrapper((HttpServletRequest)pageContext.getRequest()) {
            // The default behavior of this method is to call getAttribute(String name) on the wrapped request object.
            @Override
            public java.lang.Object getAttribute(java.lang.String name) {
                if(attributes.containsKey(name)) {
                    return attributes.get(name);
                } else {
                    return super.getAttribute(name);
                }
            }
            // The default behavior of this method is to return getAttributeNames() on the wrapped request object.
            @Override
            public java.util.Enumeration getAttributeNames() {
                Set<String> names = new HashSet<String>();
                Enumeration<String> e = super.getAttributeNames();
                while(e.hasMoreElements()) {
                    names.add(e.nextElement());
                }
                names.addAll(attributes.keySet());
                return Collections.enumeration(names);
            }
            
            // The default behavior of this method is to return setAttribute(String name, Object o) on the wrapped request object.
            @Override public void setAttribute(java.lang.String name, java.lang.Object o) {
                if(attributes.containsKey(name)) {
                    attributes.remove(name);
                }
                super.setAttribute(name, o);
            }
            
        };
        ServletResponse response = pageContext.getResponse();
        JspWriter out = pageContext.getOut();

        List<String> queries = new ArrayList<String>();
        for(Map.Entry<String,String> entry : parameters.entrySet()) {
            String key = org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(entry.getKey(), request.getCharacterEncoding());
            String value = org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(entry.getValue(), request.getCharacterEncoding());
            queries.add(key + "=" + value);
        }

        try {
            org.apache.jasper.runtime.JspRuntimeLibrary.include(
                    request, response, 
                    page + (page.indexOf('?') > 0 ? '&' : '?') + StringUtils.join(queries, "&"),
                    out, false);
        } catch(Exception ex) {
            evaluated = true;
            Utilities.debug(pageContext, "found exception: " + ex.getMessage());
            return ex;
        }
        
        evaluated = true;
        return null;
    }