Index: src/webapp/artifactDemo/ArtifactDemo.json
===================================================================
--- src/webapp/artifactDemo/ArtifactDemo.json	(revision 8251)
+++ src/webapp/artifactDemo/ArtifactDemo.json	(working copy)
@@ -1,7 +0,0 @@
-{initFunction: "fluid.artifactDemo.initArtifactDemo",
-handlerFunction: "fluid.kettle.servlet.process",
-includes: "kettle/KettleIncludes.json",
-includesPrefix: "kettle/",
-loaderFunction: "fluid.artifactDemo.initArtifactDemo",
-debugMode: false
-}
\ No newline at end of file
Index: src/webapp/artifactDemo/js/artifactDemo.js
===================================================================
--- src/webapp/artifactDemo/js/artifactDemo.js	(revision 8251)
+++ src/webapp/artifactDemo/js/artifactDemo.js	(working copy)
@@ -19,66 +19,62 @@
 	
     fluid.artifactDemo = fluid.artifactDemo || {};
     
-    fluid.artifactDemo.couch = function(env) {
-    	
-    	var buildURL = function (parts) {
-    		var url = "";
-    		for (index in parts) {
-    			url += parts[index];
-    		}
-    		return url;
-    	};
-    	
-    	var buildDataURL = function (dbName, query) {
-    		return buildURL(["http://titan.atrc.utoronto.ca:5984/", dbName, 
-    				"/_fti/lucene/all?include_docs=true&q=", query]); 
-    	};
-    	
-    	var ampIndex = env.QUERY_STRING.indexOf("&");    	
-    	var databaseName = env.QUERY_STRING.substring(1, ampIndex);
-    	var artifactQuery = env.QUERY_STRING.substring(ampIndex + 1, env.QUERY_STRING.length);
+    fluid.artifactDemo.initArtifactDataFeed = function (config, app) {
+        var artifactDataHandler = function (context, env) {	
+            var buildURL = function (parts) {
+                var url = "";
+                for (index in parts) {
+                    url += parts[index];
+                }
+                return url;
+            };
+            
+            var buildDataURL = function (dbName, query) {
+                return buildURL(["http://titan.atrc.utoronto.ca:5984/", dbName, 
+                                 "/_fti/lucene/all?include_docs=true&q=", query]); 
+            };
 
-		var model = fluid.artifact.getData(buildDataURL(databaseName, artifactQuery));
-		
-		model = fluid.artifact.artifactCleanUp(fluid.engage.mapModel(model, databaseName));
-		
-		return [200, {"Content-Type":"text/plain"}, JSON.stringify({
-			model: model,
-            cutpoints: fluid.artifact.buildCutpoints(),
-    		tree: fluid.artifact.buildComponentTree(model)
-		})];
+            var ampIndex = env.QUERY_STRING.indexOf("&");    	
+            var databaseName = env.QUERY_STRING.substring(0, ampIndex);
+            var artifactQuery = env.QUERY_STRING.substring(ampIndex + 1, env.QUERY_STRING.length);
+            
+            var model = fluid.artifact.getData(buildDataURL(databaseName, artifactQuery));
+            
+            model = fluid.artifact.artifactCleanUp(fluid.engage.mapModel(model, databaseName));
+            
+            return [200, {"Content-Type":"text/plain"}, JSON.stringify({
+                model: model,
+                cutpoints: fluid.artifact.buildCutpoints(),
+                tree: fluid.artifact.buildComponentTree(model)
+            })];
+        };
+        
+        fluid.engage.mountHandler(app, "artifactData", artifactDataHandler);
     };
     
-    fluid.artifactDemo.initArtifactDemo = function(config) {
-        var app = fluid.kettle.makeKettleApp(config.get("appName"));
+    fluid.artifactDemo.initArtifactDemo = function(config, app) {
         var baseDir = config.get("baseDir");
         
-        var handler = fluid.kettle.renderHandler(
-        {baseDir: baseDir + "artifactDemo/",
-         renderOptions: [{source: "../../../../infusion/",
-                          target: "infusion"},
-                         {source: "../../../../engage/",
-                          target: "engage"}]});
+        var handler = fluid.kettle.renderHandler({
+            baseDir: baseDir + "artifactDemo/",
+            rebaseUrls: true,
+            renderOptions: {
+                rewriteUrlPrefixes: [{
+                    source: "../../../../infusion",
+                    target: "/infusion"
+                },
+                {
+                    source: "../../../../engage",
+                    target: "/engage"
+                }]
+            }
+        });
         
         handler.registerProducer("artifact", function(context, env) {
-        	return {"output": "THE CATT"};
+            return {};
         });
-        
-        var rootMount = fluid.kettle.mountDirectory(baseDir, "artifactDemo/");
-        
-        var infusionMount = fluid.kettle.mountDirectory(baseDir, "../../../infusion/");
-        
-        var engageClientMount = fluid.kettle.mountDirectory(baseDir, "../../../engage/");
-        
-        app.root["*"] = [handler, rootMount];
-        app.root["infusion"] = {
-        	"*": infusionMount
-        };
-        app.root["engage"] = {
-        	"*": engageClientMount
-        };
-        
-        return app.app;
+
+        fluid.engage.mountAcceptor(app, "artifactView", handler);
     };
     
-})(jQuery, fluid);
\ No newline at end of file
+})(jQuery, fluid);
Index: src/webapp/artifactDemo/CouchDemo.json
===================================================================
--- src/webapp/artifactDemo/CouchDemo.json	(revision 8251)
+++ src/webapp/artifactDemo/CouchDemo.json	(working copy)
@@ -1,6 +0,0 @@
-{handlerFunction: "fluid.kettle.servlet.process",
-includes: "kettle/KettleIncludes.json",
-includesPrefix: "kettle/",
-appFunction: "fluid.artifactDemo.couch",
-debugMode: false
-}
\ No newline at end of file
Index: src/webapp/browseDemo/BrowseCouchDemo.json
===================================================================
--- src/webapp/browseDemo/BrowseCouchDemo.json	(revision 8251)
+++ src/webapp/browseDemo/BrowseCouchDemo.json	(working copy)
@@ -1,6 +0,0 @@
-{handlerFunction: "fluid.kettle.servlet.process",
-includes: "kettle/KettleIncludes.json",
-includesPrefix: "kettle/",
-appFunction: "fluid.browseDemo.assembleData",
-debugMode: false
-}
\ No newline at end of file
Index: src/webapp/browseDemo/js/browseDemo.js
===================================================================
--- src/webapp/browseDemo/js/browseDemo.js	(revision 8251)
+++ src/webapp/browseDemo/js/browseDemo.js	(working copy)
@@ -12,140 +12,135 @@
 // Declare dependencies.
 /*global jQuery, fluid*/
 
-var fluid = fluid || {};
+fluid.browseDemo = fluid.browseDemo || {};
 
-(function ($, fluid) {
+(function ($) {
 
-fluid.browseDemo = fluid.browseDemo || {};
+var baseDataURL = "http://titan.atrc.utoronto.ca:5984/";
+var baseQuery = "/_fti/lucene/by_collection_category?include_docs=true&q=";
+var baseArtifactURL = "../artifact?";
+var queryDelim = "&";
 
-fluid.browseDemo.assembleData = function (env) {
-    var baseDataURL = "http://titan.atrc.utoronto.ca:5984/";
-    var baseQuery = "/_fti/lucene/by_collection_category?include_docs=true&q=";
-    var baseArtifactURL = "../artifact?";
-    var queryDelim = "&";
+var parseEnv = function (envString, delimiter) {
+    var obj = {};
+    var ampIndex = envString.QUERY_STRING.indexOf(delimiter);
     
-    var parseEnv = function (envString, delimiter) {
-        var obj = {};
-        var ampIndex = envString.QUERY_STRING.indexOf(delimiter);    	
-        
-        obj.database = envString.QUERY_STRING.substring(1, ampIndex);
-        obj.query = envString.QUERY_STRING.substring(ampIndex + 1, envString.QUERY_STRING.length);
-        
-        return obj;
+    obj.database = envString.QUERY_STRING.substring(0, ampIndex);
+    obj.query = envString.QUERY_STRING.substring(ampIndex + 1, envString.QUERY_STRING.length);
+    
+    return obj;
+};
+
+var compileDatabaseURL = function (URLBase, queryBase, options) {
+    return URLBase + (options.database || "") + queryBase + (options.query || "");
+};
+
+var compileTargetURL = function (URLBase, queryDelimiter, query, options) {
+    return URLBase + (options.database || "") + queryDelimiter + query; 
+};
+
+var compileData = function (data) {
+    var categoryText = data[0].category;
+    var model = {
+        strings: {
+            title: categoryText
+        },
+        useCabinet: false,
+        lists: [{
+            category: categoryText,
+            listOptions: {}
+        }]
     };
     
-    var parsedENV = parseEnv(env, queryDelim);
+    model.lists[0].listOptions.links = fluid.transform(data, function (artifact) {
+        return {
+            target: artifact.target,
+            image: artifact.linkImage,
+            title: artifact.linkTitle,
+            description: artifact.linkDescription
+        };
+    });
     
-    var compileDatabaseURL = function (URLBase, queryBase, options) {
-        return URLBase + (options.database || "") + queryBase + (options.query || "");
-    };
+    return JSON.stringify(model);
+};
+
+var errorCallback = function (XMLHttpRequest, textStatus, errorThrown) {
+    fluid.log("XMLHttpRequest: " + XMLHttpRequest);
+    fluid.log("Status: " + textStatus);
+    fluid.log("Error: " + errorThrown);
+    returnValue = [500, {"Content-Type":"text/plain"}, errorThrown];
+};
     
-    var compileTargetURL = function (URLBase, queryDelimiter, query, options) {
-        return URLBase + (options.database || "") + queryDelimiter + query; 
+var ajaxCall = function (url, success, error) {
+    $.ajax({
+       url: url,
+       dataType: "json",
+       asyn: false,
+       success: success,
+       error: error
+    });
+};
+
+var getAjax = function (url, error) {
+    var data;
+    var success = function (returnedData) {
+        data = returnedData;
     };
     
-    var compileData = function (data) {
-        var categoryText = data[0].category;
-        var model = {
-            strings: {
-                title: categoryText
-            },
-            useCabinet: false,
-            lists: [{
-                category: categoryText,
-                listOptions: {}
-            }]
-        };
-        
-        model.lists[0].listOptions.links = fluid.transform(data, function (artifact) {
-            return {
-                target: artifact.target,
-                image: artifact.linkImage,
-                title: artifact.linkTitle,
-                description: artifact.linkDescription
-            };
-        });
-        
-        return JSON.stringify(model);
-    };
+    ajaxCall(url, success,error);
     
-    var errorCallback = function (XMLHttpRequest, textStatus, errorThrown) {
-        fluid.log("XMLHttpRequest: " + XMLHttpRequest);
-        fluid.log("Status: " + textStatus);
-        fluid.log("Error: " + errorThrown);
-        returnValue = [500, {"Content-Type":"text/plain"}, errorThrown];
-    };
-        
-    var ajaxCall = function (url, success, error) {
-        $.ajax({
-           url: url,
-           dataType: "json",
-           asyn: false,
-           success: success,
-           error: error
-        });
-    };
+    return JSON.parse(data);
+};
+
+var getArtifactData = function (rawData, database) {
+    var dataRows = rawData.rows || [];
+    return fluid.transform(dataRows, function (row) {
+        var artifact = row.doc;
+        return fluid.engage.mapModel(artifact, database);
+    });
+};
+
+var getData = function (baseURL, baseQuery, error, options) {
+    var url = compileDatabaseURL(baseURL, baseQuery, options);
+    var rawData = getAjax(url, error);
     
-    var getAjax = function (url, error) {
-        var data;
-        var success = function (returnedData) {
-            data = returnedData;
-        };
-        
-        ajaxCall(url, success,error);
-        
-        return JSON.parse(data);
-    };
+    var dataSet = getArtifactData(rawData, options.database);
     
-    var getArtifactData = function (rawData, database) {
-        var dataRows = rawData.rows || [];
-        return fluid.transform(dataRows, function (row) {
-            var artifact = row.doc;
-            return fluid.engage.mapModel(artifact, database);
-        });
+    return compileData(dataset);
+};
+
+fluid.browseDemo.initBrowseDataFeed = function (config, app) {
+    var browseDataHandler = function (env) {
+        var parsedENV = parseEnv(env.env, queryDelim);
+        return [200, {"Content-Type":"text/plain"}, getData(baseDataURL, baseQuery, errorCallback,parsedENV)];
     };
-  
-    var getData = function (baseURL, baseQuery, error, options) {
-        var url = compileDatabaseURL(baseURL, baseQuery, options);
-        var rawData = getAjax(url, error);
-        
-        var dataSet = getArtifactData(rawData, options.database);
-        
-        return compileData(dataset);
-    };
-    
-    return [200, {"Content-Type":"text/plain"}, getData(baseDataURL, baseQuery, errorCallback,parsedENV)];
+
+    fluid.engage.mountHandler(app, "artifactBrowseData", browseDataHandler);
 };
 
-fluid.browseDemo.initBrowseDemo = function(config) {
-        var app = fluid.kettle.makeKettleApp(config.get("appName"));
+
+fluid.browseDemo.initBrowseDemo = function(config, app) {
         var baseDir = config.get("baseDir");
         
-        var handler = fluid.kettle.renderHandler(
-        {baseDir: baseDir + "browseDemo/",
-         renderOptions: [{source: "../../../../infusion/",
-                          target: "infusion"},
-                         {source: "../../../../engage/",
-                          target: "engage"}]});
+        var handler = fluid.kettle.renderHandler({
+        	baseDir: baseDir + "browseDemo/",
+        	renderOptions: {
+                rebaseURLs: false,
+                rewriteUrlPrefixes: [{
+                    source: "../../../../infusion",
+                    target: "/infusion"
+                },
+                {
+                    source: "../../../../engage",
+                    target: "/engage"
+                }]
+        	}
+        });
         
         handler.registerProducer("browse", function(context, env) {
         	return {};
         });
         
-        var rootMount = fluid.kettle.mountDirectory(baseDir, "browseDemo/");
-        
-        var infusionMount = fluid.kettle.mountDirectory(baseDir, "../../../infusion/");
-        
-        var engageClientMount = fluid.kettle.mountDirectory(baseDir, "../../../engage/");
-        
-        app.root["*"] = [handler, rootMount];
-        app.root["infusion"] = {
-        	"*": infusionMount
-        };
-        app.root["engage"] = {
-        	"*": engageClientMount
-        };
-        
-        return app.app;
+        fluid.engage.mountAcceptor(app, "artifactBrowse", handler);
     };
-})(jQuery, fluid);
\ No newline at end of file
+})(jQuery);
Index: src/webapp/browseDemo/BrowseDemo.json
===================================================================
--- src/webapp/browseDemo/BrowseDemo.json	(revision 8251)
+++ src/webapp/browseDemo/BrowseDemo.json	(working copy)
@@ -1,7 +0,0 @@
-{initFunction: "fluid.browseDemo.initBrowseDemo",
-handlerFunction: "fluid.kettle.servlet.process",
-includes: "kettle/KettleIncludes.json",
-includesPrefix: "kettle/",
-loaderFunction: "fluid.browseDemo.initBrowseDemo",
-debugMode: true
-}
\ No newline at end of file
Index: src/webapp/engage/engageConfig.json
===================================================================
--- src/webapp/engage/engageConfig.json	(revision 0)
+++ src/webapp/engage/engageConfig.json	(revision 0)
@@ -0,0 +1,13 @@
+{initFunction: "fluid.engage.initEngageApp",
+handlerFunction: "fluid.kettle.servlet.process",
+includes: "kettle/KettleIncludes.json",
+includesPrefix: "kettle/",
+loaderFunction: "fluid.engage.initEngageApp",
+initServices: [
+    "fluid.artifactDemo.initArtifactDemo", 
+    "fluid.artifactDemo.initArtifactDataFeed", 
+    "fluid.browseDemo.initBrowseDemo",
+    "fluid.browseDemo.initBrowseDataFeed"
+],
+debugMode: true
+}
\ No newline at end of file
Index: src/webapp/engage/js/EngageApp.js
===================================================================
--- src/webapp/engage/js/EngageApp.js	(revision 0)
+++ src/webapp/engage/js/EngageApp.js	(revision 0)
@@ -0,0 +1,51 @@
+fluid = fluid || {};
+fluid.engage = fluid.engage || {};
+
+(function () {
+	
+	fluid.engage.mountHandler = function (onApp, atSegment, handler) {
+		fluid.engage.mountAcceptor(onApp, atSegment, {
+			accept: function (segment, relPath, pathInfo) {
+				return {
+					handle: handler
+				}
+			}
+		});
+	};
+	
+	fluid.engage.mountAcceptor = function (onApp, atSegment, acceptor) {
+		var acceptorMap = atSegment;
+		if (typeof atSegment === "string") {
+			acceptorMap = {};
+			acceptorMap[atSegment] = acceptor;
+		}
+
+		for (var segment in acceptorMap) {
+			onApp.root[segment] = {
+				"*": acceptorMap[segment]
+			};
+		}
+	};
+	
+	fluid.engage.initEngageApp = function (config) {
+		var app = fluid.kettle.makeKettleApp(config.get("appName")),
+		    serviceInits = config.get("initServices"),
+		    baseDir = config.get("baseDir");
+		
+		// Initialize each of the Engage app services registered in the config file.
+		fluid.setLogging(true);
+		for (var i = 0; i < serviceInits.length; i++) {
+			var initFn = serviceInits[i];
+			fluid.log("Initializing service " + initFn);
+			fluid.invokeGlobalFunction(initFn, [config, app]);
+		}
+		
+		// Mount shared directory points.
+		fluid.engage.mountAcceptor(app, {
+	    	"infusion": fluid.kettle.mountDirectory(baseDir, "../../../infusion/"),
+	    	"engage": fluid.kettle.mountDirectory(baseDir, "../../../engage/")
+		});
+		
+		return app.app;
+	};
+})();
Index: src/webapp/WEB-INF/web.xml
===================================================================
--- src/webapp/WEB-INF/web.xml	(revision 8251)
+++ src/webapp/WEB-INF/web.xml	(working copy)
@@ -5,70 +5,17 @@
 
 <web-app>
 	<servlet>
-		  <servlet-name>KettleDemo</servlet-name>
+		  <servlet-name>KettleServlet</servlet-name>
 		  <servlet-class>org.fluidproject.kettle.KettleServlet</servlet-class>
       <init-param>
           <param-name>kettleConfigLocation</param-name>
-          <param-value>/kettleDemo/kettleCherryDemo.json</param-value>
+          <param-value>/engage/engageConfig.json</param-value>
       </init-param>
 		<load-on-startup>1</load-on-startup>
 	</servlet>
-	<servlet>
-		  <servlet-name>ArtifactServlet</servlet-name>
-		  <servlet-class>org.fluidproject.kettle.KettleServlet</servlet-class>
-      <init-param>
-          <param-name>kettleConfigLocation</param-name>
-          <param-value>/artifactDemo/ArtifactDemo.json</param-value>
-      </init-param>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-	<servlet>
-		  <servlet-name>CouchServlet</servlet-name>
-		  <servlet-class>org.fluidproject.kettle.KettleServlet</servlet-class>
-      <init-param>
-          <param-name>kettleConfigLocation</param-name>
-          <param-value>/artifactDemo/CouchDemo.json</param-value>
-      </init-param>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-	<servlet>
-		  <servlet-name>BrowseServlet</servlet-name>
-		  <servlet-class>org.fluidproject.kettle.KettleServlet</servlet-class>
-      <init-param>
-          <param-name>kettleConfigLocation</param-name>
-          <param-value>/browseDemo/BrowseDemo.json</param-value>
-      </init-param>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
-    	<servlet>
-		  <servlet-name>BrowseCouchServlet</servlet-name>
-		  <servlet-class>org.fluidproject.kettle.KettleServlet</servlet-class>
-      <init-param>
-          <param-name>kettleConfigLocation</param-name>
-          <param-value>/browseDemo/BrowseCouchDemo.json</param-value>
-      </init-param>
-		<load-on-startup>1</load-on-startup>
-	</servlet>
 
 	<servlet-mapping>
-	    <servlet-name>KettleDemo</servlet-name>
-	    <url-pattern>/kettleDemo</url-pattern>
-	</servlet-mapping>
-	<servlet-mapping>
-	    <servlet-name>ArtifactServlet</servlet-name>
+	    <servlet-name>KettleServlet</servlet-name>
 	    <url-pattern>/</url-pattern>
 	</servlet-mapping>
-	<servlet-mapping>
-	    <servlet-name>BrowseServlet</servlet-name>
-	    <url-pattern>/browse</url-pattern>
-	</servlet-mapping>
-	<servlet-mapping>
-	    <servlet-name>CouchServlet</servlet-name>
-	    <url-pattern>/couch</url-pattern>
-	</servlet-mapping>
-    	<servlet-mapping>
-	    <servlet-name>BrowseCouchServlet</servlet-name>
-	    <url-pattern>/browsecouch</url-pattern>
-	</servlet-mapping>
-
 </web-app>
Index: src/webapp/kettle/KettleIncludes.json
===================================================================
--- src/webapp/kettle/KettleIncludes.json	(revision 8251)
+++ src/webapp/kettle/KettleIncludes.json	(working copy)
@@ -12,8 +12,9 @@
    "js/contentTypes.js",
    "js/kettle.js",
    "js/servletJSGI.js",
-   "../kettleDemo/js/kettleJSGIDemo.js",
-   "../kettleDemo/js/kettleCherryDemo.js", 
+   "../engage/js/EngageApp.js",
    "../artifactDemo/js/artifactDemo.js",
-   "../browseDemo/js/browseDemo.js"
+   "../browseDemo/js/browseDemo.js",
+   "../../../../engage/framework/js/Engage.js",
+   "../../../../engage/components/artifact/js/artifact.js"
   ]
