Commits

Tatham Oddie committed d97676e

Implemented T4MVC.

Comments (0)

Files changed (9)

Web/AnalysisController.generated.cs

+// <auto-generated />
+// This file was generated by a T4 template.
+// Don't change it directly as your change would get overwritten.  Instead, make changes
+// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
+
+// Make sure the compiler doesn't complain about missing Xml comments
+#pragma warning disable 1591
+#region T4MVC
+
+using System;
+using System.Diagnostics;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Web;
+using System.Web.Hosting;
+using System.Web.Mvc;
+using System.Web.Mvc.Ajax;
+using System.Web.Mvc.Html;
+using System.Web.Routing;
+using T4MVC;
+namespace TathamOddie.RegexAnalyzer.Web.Controllers {
+    public partial class AnalysisController {
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public AnalysisController() { }
+
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        protected AnalysisController(Dummy d) { }
+
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        protected RedirectToRouteResult RedirectToAction(ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            return RedirectToRoute(callInfo.RouteValueDictionary);
+        }
+
+        [NonAction]
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public System.Web.Mvc.ActionResult Analyze() {
+            return new T4MVC_ActionResult(Area, Name, ActionNames.Analyze);
+        }
+
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public AnalysisController Actions { get { return MVC.Analysis; } }
+        [GeneratedCode("T4MVC", "2.0")]
+        public readonly string Area = "";
+        [GeneratedCode("T4MVC", "2.0")]
+        public readonly string Name = "Analysis";
+
+        static readonly ActionNamesClass s_actions = new ActionNamesClass();
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public ActionNamesClass ActionNames { get { return s_actions; } }
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public class ActionNamesClass {
+            public readonly string Analyze = "Analyze";
+        }
+
+
+        static readonly ViewNames s_views = new ViewNames();
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public ViewNames Views { get { return s_views; } }
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public class ViewNames {
+            public readonly string Basic = "~/Views/Analysis/Basic.cshtml";
+            public readonly string NoExpression = "~/Views/Analysis/NoExpression.cshtml";
+            public readonly string Verbose = "~/Views/Analysis/Verbose.cshtml";
+        }
+    }
+
+    [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+    public class T4MVC_AnalysisController: TathamOddie.RegexAnalyzer.Web.Controllers.AnalysisController {
+        public T4MVC_AnalysisController() : base(Dummy.Instance) { }
+
+        public override System.Web.Mvc.ActionResult Analyze(bool verbose, string q) {
+            var callInfo = new T4MVC_ActionResult(Area, Name, ActionNames.Analyze);
+            callInfo.RouteValueDictionary.Add("verbose", verbose);
+            callInfo.RouteValueDictionary.Add("q", q);
+            return callInfo;
+        }
+
+    }
+}
+
+#endregion T4MVC
+#pragma warning restore 1591

Web/Controllers/AnalysisController.cs

 
 namespace TathamOddie.RegexAnalyzer.Web.Controllers
 {
-    public class AnalysisController : Controller
+    public partial class AnalysisController : Controller
     {
         [ValidateInput(false)]
-        public ActionResult Analyze(
+        public virtual ActionResult Analyze(
             [DefaultValue(false)]bool verbose,
             string q)
         {
             if (string.IsNullOrEmpty(q))
-                return View("NoExpression");
+                return View(Views.NoExpression);
 
             ViewData["Expression"] = q;
 
             ViewData["ExpressionMarkup"] = RenderExpressionAsHtml(rootNode);
             ViewData["NodesMarkup"] = RenderNodesAsHtml(rootNode.Children);
 
-            return View("Basic");
+            return View(Views.Basic);
         }
 
         ActionResult AnalyzeVerbose(string expression)
             ViewData["AllNodes"] = FlattenNodes(rootNode.Children);
             ViewData["NodesMarkup"] = RenderNodesAsHtml(rootNode.Children);
 
-            return View("Verbose");
+            return View(Views.Verbose);
         }
 
         static IEnumerable<NodeViewModel> FlattenNodes(IEnumerable<Node> nodes)

Web/Controllers/HomeController.cs

 
 namespace TathamOddie.RegexAnalyzer.Web.Controllers
 {
-    public class HomeController : Controller
+    public partial class HomeController : Controller
     {
-        public ActionResult Index()
+        public virtual ActionResult Index()
         {
-            return View();
+            return View(Views.Index);
         }
     }
 }

Web/HomeController.generated.cs

+// <auto-generated />
+// This file was generated by a T4 template.
+// Don't change it directly as your change would get overwritten.  Instead, make changes
+// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
+
+// Make sure the compiler doesn't complain about missing Xml comments
+#pragma warning disable 1591
+#region T4MVC
+
+using System;
+using System.Diagnostics;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Web;
+using System.Web.Hosting;
+using System.Web.Mvc;
+using System.Web.Mvc.Ajax;
+using System.Web.Mvc.Html;
+using System.Web.Routing;
+using T4MVC;
+namespace TathamOddie.RegexAnalyzer.Web.Controllers {
+    public partial class HomeController {
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public HomeController() { }
+
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        protected HomeController(Dummy d) { }
+
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        protected RedirectToRouteResult RedirectToAction(ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            return RedirectToRoute(callInfo.RouteValueDictionary);
+        }
+
+
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public HomeController Actions { get { return MVC.Home; } }
+        [GeneratedCode("T4MVC", "2.0")]
+        public readonly string Area = "";
+        [GeneratedCode("T4MVC", "2.0")]
+        public readonly string Name = "Home";
+
+        static readonly ActionNamesClass s_actions = new ActionNamesClass();
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public ActionNamesClass ActionNames { get { return s_actions; } }
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public class ActionNamesClass {
+            public readonly string Index = "Index";
+        }
+
+
+        static readonly ViewNames s_views = new ViewNames();
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public ViewNames Views { get { return s_views; } }
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public class ViewNames {
+            public readonly string Index = "~/Views/Home/Index.cshtml";
+        }
+    }
+
+    [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+    public class T4MVC_HomeController: TathamOddie.RegexAnalyzer.Web.Controllers.HomeController {
+        public T4MVC_HomeController() : base(Dummy.Instance) { }
+
+        public override System.Web.Mvc.ActionResult Index() {
+            var callInfo = new T4MVC_ActionResult(Area, Name, ActionNames.Index);
+            return callInfo;
+        }
+
+    }
+}
+
+#endregion T4MVC
+#pragma warning restore 1591

Web/SharedController.generated.cs

+// <auto-generated />
+// This file was generated by a T4 template.
+// Don't change it directly as your change would get overwritten.  Instead, make changes
+// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
+
+// Make sure the compiler doesn't complain about missing Xml comments
+#pragma warning disable 1591
+#region T4MVC
+
+using System;
+using System.Diagnostics;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Web;
+using System.Web.Hosting;
+using System.Web.Mvc;
+using System.Web.Mvc.Ajax;
+using System.Web.Mvc.Html;
+using System.Web.Routing;
+using T4MVC;
+namespace T4MVC {
+    public class SharedController {
+
+        static readonly ViewNames s_views = new ViewNames();
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public ViewNames Views { get { return s_views; } }
+        [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+        public class ViewNames {
+            public readonly string _Layout = "~/Views/Shared/_Layout.cshtml";
+        }
+    }
+
+}
+
+#endregion T4MVC
+#pragma warning restore 1591
+// <auto-generated />
+// This file was generated by a T4 template.
+// Don't change it directly as your change would get overwritten.  Instead, make changes
+// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
+
+// Make sure the compiler doesn't complain about missing Xml comments
+#pragma warning disable 1591
+#region T4MVC
+
+using System;
+using System.Diagnostics;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Web;
+using System.Web.Hosting;
+using System.Web.Mvc;
+using System.Web.Mvc.Ajax;
+using System.Web.Mvc.Html;
+using System.Web.Routing;
+using T4MVC;
+
+[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+public static class MVC {
+    public static TathamOddie.RegexAnalyzer.Web.Controllers.AnalysisController Analysis = new TathamOddie.RegexAnalyzer.Web.Controllers.T4MVC_AnalysisController();
+    public static TathamOddie.RegexAnalyzer.Web.Controllers.HomeController Home = new TathamOddie.RegexAnalyzer.Web.Controllers.T4MVC_HomeController();
+    public static T4MVC.SharedController Shared = new T4MVC.SharedController();
+}
+
+namespace T4MVC {
+}
+
+namespace System.Web.Mvc {
+    [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+    public static class T4Extensions {
+        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result) {
+            return htmlHelper.RouteLink(linkText, result.GetRouteValueDictionary());
+        }
+
+        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, object htmlAttributes) {
+            return ActionLink(htmlHelper, linkText, result, new RouteValueDictionary(htmlAttributes));
+        }
+
+        public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, IDictionary<string, object> htmlAttributes) {
+            return htmlHelper.RouteLink(linkText, result.GetRouteValueDictionary(), htmlAttributes);
+        }
+
+        public static MvcForm BeginForm(this HtmlHelper htmlHelper, ActionResult result, FormMethod formMethod) {
+            return htmlHelper.BeginForm(result, formMethod, null);
+        }
+
+        public static MvcForm BeginForm(this HtmlHelper htmlHelper, ActionResult result, FormMethod formMethod, object htmlAttributes) {
+            return BeginForm(htmlHelper, result, formMethod, new RouteValueDictionary(htmlAttributes));
+        }
+
+        public static MvcForm BeginForm(this HtmlHelper htmlHelper, ActionResult result, FormMethod formMethod, IDictionary<string, object> htmlAttributes) {
+            var callInfo = result.GetT4MVCResult();
+            return htmlHelper.BeginForm(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary, formMethod, htmlAttributes);
+        }
+
+        public static void RenderAction(this HtmlHelper htmlHelper, ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            htmlHelper.RenderAction(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary);
+        }
+
+        public static MvcHtmlString Action(this HtmlHelper htmlHelper, ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            return htmlHelper.Action(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary);
+        }
+        public static string Action(this UrlHelper urlHelper, ActionResult result) {
+            return urlHelper.RouteUrl(result.GetRouteValueDictionary());
+        }
+
+        public static string ActionAbsolute(this UrlHelper urlHelper, ActionResult result) {
+            return string.Format("{0}{1}",urlHelper.RequestContext.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority),
+                urlHelper.RouteUrl(result.GetRouteValueDictionary()));
+        }
+
+        public static MvcHtmlString ActionLink(this AjaxHelper ajaxHelper, string linkText, ActionResult result, AjaxOptions ajaxOptions) {
+            return ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions);
+        }
+
+        public static MvcHtmlString ActionLink(this AjaxHelper ajaxHelper, string linkText, ActionResult result, AjaxOptions ajaxOptions, object htmlAttributes) {
+            return ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions, new RouteValueDictionary(htmlAttributes));
+        }
+
+        public static MvcHtmlString ActionLink(this AjaxHelper ajaxHelper, string linkText, ActionResult result, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes) {
+            return ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions, htmlAttributes);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result) {
+            return MapRoute(routes, name, url, result, null /*namespaces*/);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults) {
+            return MapRoute(routes, name, url, result, defaults, null /*constraints*/, null /*namespaces*/);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, string[] namespaces) {
+            return MapRoute(routes, name, url, result, null /*defaults*/, namespaces);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults, object constraints) {
+            return MapRoute(routes, name, url, result, defaults, constraints, null /*namespaces*/);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults, string[] namespaces) {
+            return MapRoute(routes, name, url, result, defaults, null /*constraints*/, namespaces);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults, object constraints, string[] namespaces) {
+            // Create and add the route
+            var route = CreateRoute(url, result, defaults, constraints, namespaces);
+            routes.Add(name, route);
+            return route;
+        }
+
+        // Note: can't name the AreaRegistrationContext methods 'MapRoute', as that conflicts with the existing methods
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result) {
+            return MapRouteArea(context, name, url, result, null /*namespaces*/);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults) {
+            return MapRouteArea(context, name, url, result, defaults, null /*constraints*/, null /*namespaces*/);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, string[] namespaces) {
+            return MapRouteArea(context, name, url, result, null /*defaults*/, namespaces);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults, object constraints) {
+            return MapRouteArea(context, name, url, result, defaults, constraints, null /*namespaces*/);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults, string[] namespaces) {
+            return MapRouteArea(context, name, url, result, defaults, null /*constraints*/, namespaces);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults, object constraints, string[] namespaces) {
+            // Create and add the route
+            var route = CreateRoute(url, result, defaults, constraints, namespaces);
+            context.Routes.Add(name, route);
+            route.DataTokens["area"] = context.AreaName;
+            return route;
+        }
+
+        private static Route CreateRoute(string url, ActionResult result, object defaults, object constraints, string[] namespaces) {
+            // Start by adding the default values from the anonymous object (if any)
+            var routeValues = new RouteValueDictionary(defaults);
+
+            // Then add the Controller/Action names and the parameters from the call
+            foreach (var pair in result.GetRouteValueDictionary()) {
+                routeValues.Add(pair.Key, pair.Value);
+            }
+
+            var routeConstraints = new RouteValueDictionary(constraints);
+
+            // Create and add the route
+            var route = new Route(url, routeValues, routeConstraints, new MvcRouteHandler());
+
+            route.DataTokens = new RouteValueDictionary();
+
+            if (namespaces != null && namespaces.Length > 0) {
+                route.DataTokens["Namespaces"] = namespaces;
+            }
+
+            return route;
+        }
+
+        public static IT4MVCActionResult GetT4MVCResult(this ActionResult result) {
+            var t4MVCResult = result as IT4MVCActionResult;
+            if (t4MVCResult == null) {
+                throw new InvalidOperationException("T4MVC methods can only be passed pseudo-action calls (e.g. MVC.Home.About()), and not real action calls.");
+            }
+            return t4MVCResult;
+        }
+
+        public static RouteValueDictionary GetRouteValueDictionary(this ActionResult result) {
+            return result.GetT4MVCResult().RouteValueDictionary;
+        }
+
+        public static ActionResult AddRouteValues(this ActionResult result, object routeValues) {
+            return result.AddRouteValues(new RouteValueDictionary(routeValues));
+        }
+
+        public static ActionResult AddRouteValues(this ActionResult result, RouteValueDictionary routeValues) {
+            RouteValueDictionary currentRouteValues = result.GetRouteValueDictionary();
+
+            // Add all the extra values
+            foreach (var pair in routeValues) {
+                currentRouteValues.Add(pair.Key, pair.Value);
+            }
+
+            return result;
+        }
+
+        public static ActionResult AddRouteValues(this ActionResult result, System.Collections.Specialized.NameValueCollection nameValueCollection) {
+            // Copy all the values from the NameValueCollection into the route dictionary
+            nameValueCollection.CopyTo(result.GetRouteValueDictionary());
+            return result;
+        }
+
+        public static ActionResult AddRouteValue(this ActionResult result, string name, object value) {
+            RouteValueDictionary routeValues = result.GetRouteValueDictionary();
+            routeValues.Add(name, value);
+            return result;
+        }
+        
+        public static void InitMVCT4Result(this IT4MVCActionResult result, string area, string controller, string action) {
+            result.Controller = controller;
+            result.Action = action;
+            result.RouteValueDictionary = new RouteValueDictionary();
+             
+            result.RouteValueDictionary.Add("Controller", controller);
+            result.RouteValueDictionary.Add("Action", action);
+        }
+
+        public static bool FileExists(string virtualPath) {
+            if (!HostingEnvironment.IsHosted) return false;
+            string filePath = HostingEnvironment.MapPath(virtualPath);
+            return System.IO.File.Exists(filePath);
+        }
+
+        static DateTime CenturyBegin=new DateTime(2001,1,1);
+        public static string TimestampString(string virtualPath) {
+            if (!HostingEnvironment.IsHosted) return string.Empty;
+            string filePath = HostingEnvironment.MapPath(virtualPath);
+            return Convert.ToString((System.IO.File.GetLastWriteTimeUtc(filePath).Ticks-CenturyBegin.Ticks)/1000000000,16);            
+        }
+    }
+}
+
+   
+[GeneratedCode("T4MVC", "2.0")]   
+public interface IT4MVCActionResult {   
+    string Action { get; set; }   
+    string Controller { get; set; }   
+    RouteValueDictionary RouteValueDictionary { get; set; }   
+}   
+  
+
+[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+public class T4MVC_ActionResult : System.Web.Mvc.ActionResult, IT4MVCActionResult {
+    public T4MVC_ActionResult(string area, string controller, string action): base()  {
+        this.InitMVCT4Result(area, controller, action);
+    }
+     
+    public override void ExecuteResult(System.Web.Mvc.ControllerContext context) { }
+    
+    public string Controller { get; set; }
+    public string Action { get; set; }
+    public RouteValueDictionary RouteValueDictionary { get; set; }
+}
+
+
+
+namespace Links {
+    [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+    public static class Scripts {
+        private const string URLPATH = "~/Scripts";
+        public static string Url() { return T4MVCHelpers.ProcessVirtualPath(URLPATH); }
+        public static string Url(string fileName) { return T4MVCHelpers.ProcessVirtualPath(URLPATH + "/" + fileName); }
+        public static readonly string jquery_1_4_1_vsdoc_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/jquery-1.4.1-vsdoc.min.js") ? Url("jquery-1.4.1-vsdoc.min.js") : Url("jquery-1.4.1-vsdoc.js");
+                      
+        public static readonly string jquery_1_4_1_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/jquery-1.4.1.min.js") ? Url("jquery-1.4.1.min.js") : Url("jquery-1.4.1.js");
+                      
+        public static readonly string jquery_1_4_1_min_js = Url("jquery-1.4.1.min.js");
+        public static readonly string jquery_validate_vsdoc_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/jquery.validate-vsdoc.min.js") ? Url("jquery.validate-vsdoc.min.js") : Url("jquery.validate-vsdoc.js");
+                      
+        public static readonly string jquery_validate_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/jquery.validate.min.js") ? Url("jquery.validate.min.js") : Url("jquery.validate.js");
+                      
+        public static readonly string jquery_validate_min_js = Url("jquery.validate.min.js");
+        public static readonly string MicrosoftAjax_debug_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/MicrosoftAjax.debug.min.js") ? Url("MicrosoftAjax.debug.min.js") : Url("MicrosoftAjax.debug.js");
+                      
+        public static readonly string MicrosoftAjax_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/MicrosoftAjax.min.js") ? Url("MicrosoftAjax.min.js") : Url("MicrosoftAjax.js");
+                      
+        public static readonly string MicrosoftMvcAjax_debug_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/MicrosoftMvcAjax.debug.min.js") ? Url("MicrosoftMvcAjax.debug.min.js") : Url("MicrosoftMvcAjax.debug.js");
+                      
+        public static readonly string MicrosoftMvcAjax_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/MicrosoftMvcAjax.min.js") ? Url("MicrosoftMvcAjax.min.js") : Url("MicrosoftMvcAjax.js");
+                      
+        public static readonly string MicrosoftMvcValidation_debug_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/MicrosoftMvcValidation.debug.min.js") ? Url("MicrosoftMvcValidation.debug.min.js") : Url("MicrosoftMvcValidation.debug.js");
+                      
+        public static readonly string MicrosoftMvcValidation_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/MicrosoftMvcValidation.min.js") ? Url("MicrosoftMvcValidation.min.js") : Url("MicrosoftMvcValidation.js");
+                      
+    }
+
+}
+
+static class T4MVCHelpers {
+    // You can change the ProcessVirtualPath method to modify the path that gets returned to the client.
+    // e.g. you can prepend a domain, or append a query string:
+    //      return "http://localhost" + path + "?foo=bar";
+    private static string ProcessVirtualPathDefault(string virtualPath) {
+        // The path that comes in starts with ~/ and must first be made absolute
+        string path = VirtualPathUtility.ToAbsolute(virtualPath);
+        
+        // Add your own modifications here before returning the path
+        return path;
+    }
+
+    // Calling ProcessVirtualPath through delegate to allow it to be replaced for unit testing
+    public static Func<string, string> ProcessVirtualPath = ProcessVirtualPathDefault;
+
+
+    // Logic to determine if the app is running in production or dev environment
+    public static bool IsProduction() { 
+        return (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled); 
+    }
+}
+
+
+
+
+namespace T4MVC {
+    [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
+    public class Dummy {
+        private Dummy() { }
+        public static Dummy Instance = new Dummy();
+    }
+}
+
+	
+
+#endregion T4MVC
+#pragma warning restore 1591
+
+

Web/T4MVC.settings.t4

+<#+
+/*
+
+This file contains settings used by T4MVC.tt. The main goal is to avoid the need for users
+to fork the 'official' template in order to achieve what they want.
+ 
+*/
+
+
+// The prefix used for things like MVC.Dinners.Name and MVC.Dinners.Delete(Model.DinnerID)
+const string HelpersPrefix = "MVC";
+
+// Namespaces to be referenced by the generated code
+readonly string[] ReferencedNamespaces = new string[] {
+};
+
+// The folder under the project that contains the areas
+const string AreasFolder = "Areas";
+
+// Choose whether you want to include an 'Areas' token when referring to areas.
+// e.g. Assume the Area is called Blog and the Controller is Post:
+// - When false use MVC.Blog.Post.etc...
+// - When true use MVC.Areas.Blog.Post.etc...
+static bool IncludeAreasToken = false;
+
+// The folder under the project that contains the controllers
+const string ControllersFolder = "Controllers";
+
+// The folder under the project that contains the views
+const string ViewsRootFolder = "Views";
+
+// Views in DisplayTemplates and EditorTemplates folders shouldn't be fully qualifed as it breaks
+// the templated helper code
+readonly string[]  NonQualifiedViewFolders = new string[] {
+  "DisplayTemplates",
+  "EditorTemplates"
+};
+
+// The name of the interface that all T4MVC action results will implement
+const string ActionResultInterfaceName = "IT4MVCActionResult";
+
+// If true, the T4MVC action result interface will be generated
+// If false, the namespace of the interface must be referenced in the 'ReferencedNamespaces' setting
+const bool GenerateActionResultInterface = true;
+
+// If true, use lower case tokens in routes for the area, controller and action names
+const bool UseLowercaseRoutes = false;
+
+// The namespace that the links are generated in (e.g. "Links", as in Links.Content.nerd_jpg)
+const string LinksNamespace = "Links";
+
+// If true, links to static files include a query string containing the file's last change time. This way,
+// when the static file changes, the link changes and guarantees that the client will re-request the resource.
+// e.g. when true, the link looks like: "/Content/nerd.jpg?2009-09-04T12:25:48"
+const bool AddTimestampToStaticLinks = false;
+
+// Folders containing static files for which links are generated (e.g. Links.Scripts.Map_js)
+readonly string[] StaticFilesFolders = new string[] {
+    "Scripts",
+    "Content",
+};
+
+// Static files to exclude from the generated links   
+readonly string[] ExcludedStaticFileExtensions = new string[] {   
+    ".cs"  
+};  
+
+//---------------------------------------------------------------------------
+//	Explicit HtmlHelpers
+//---------------------------------------------------------------------------
+//create explicit HtmlHelpers for rendering partials
+const bool ExplicitHtmlHelpersForPartials = false;
+const string ExplicitHtmlHelpersForPartialsFormat = "Render{0}";
+
+//---------------------------------------------------------------------------
+
+// If true, the template marks itself as unsaved as part of its execution.
+// This way it will be saved and update itself next time the project is built.
+// Basically, it keeps marking itself as unsaved to make the next build work.
+// Note: this is certainly hacky, but is the best I could come up with so far.
+static bool AlwaysKeepTemplateDirty = false;
+
+// If true,the template output will be split into multiple files.
+static bool SplitIntoMultipleFiles = true;
+
+void RenderAdditionalCode() {
+#>
+static class T4MVCHelpers {
+    // You can change the ProcessVirtualPath method to modify the path that gets returned to the client.
+    // e.g. you can prepend a domain, or append a query string:
+    //      return "http://localhost" + path + "?foo=bar";
+    private static string ProcessVirtualPathDefault(string virtualPath) {
+        // The path that comes in starts with ~/ and must first be made absolute
+        string path = VirtualPathUtility.ToAbsolute(virtualPath);
+        
+        // Add your own modifications here before returning the path
+        return path;
+    }
+
+    // Calling ProcessVirtualPath through delegate to allow it to be replaced for unit testing
+    public static Func<string, string> ProcessVirtualPath = ProcessVirtualPathDefault;
+
+
+    // Logic to determine if the app is running in production or dev environment
+    public static bool IsProduction() { 
+        return (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled); 
+    }
+}
+
+<#+
+}
+#>
+<#
+/*
+T4MVC Version 2.6.30
+Find latest version and documentation at http://mvccontrib.codeplex.com/wikipage?title=T4MVC
+Discuss on the T4MVC forum: http://forums.asp.net/1215.aspx
+
+T4MVC is part of the MvcContrib project (http://mvccontrib.codeplex.com)
+Maintained by David Ebbo, with much feedback from the MVC community (thanks all!)
+david.ebbo@microsoft.com
+http://twitter.com/davidebbo
+http://blogs.msdn.com/davidebb
+
+Related blog posts: http://blogs.msdn.com/davidebb/archive/tags/T4MVC/default.aspx
+
+Please use in accordance to the MvcContrib license (http://mvccontrib.codeplex.com/license)
+*/
+#>
+<#@ template language="C#v3.5" debug="true" hostspecific="true" #>
+<#@ assembly name="System.Core" #>
+<#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
+<#@ assembly name="EnvDTE" #>
+<#@ assembly name="EnvDTE80" #>
+<#@ assembly name="VSLangProj" #>
+<#@ import namespace="System.Collections.Generic" #>
+<#@ import namespace="System.IO" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Text.RegularExpressions" #>
+<#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
+<#@ import namespace="EnvDTE" #>
+<#@ import namespace="EnvDTE80" #>
+<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
+<#PrepareDataToRender(this); #>
+<#var manager = Manager.Create(Host, GenerationEnvironment); #>
+<#manager.StartHeader(); #>// <auto-generated />
+// This file was generated by a T4 template.
+// Don't change it directly as your change would get overwritten.  Instead, make changes
+// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
+
+// Make sure the compiler doesn't complain about missing Xml comments
+#pragma warning disable 1591
+#region T4MVC
+
+using System;
+using System.Diagnostics;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Web;
+using System.Web.Hosting;
+using System.Web.Mvc;
+using System.Web.Mvc.Ajax;
+using System.Web.Mvc.Html;
+using System.Web.Routing;
+using <#=T4MVCNamespace #>;
+<#foreach (var referencedNamespace in ReferencedNamespaces) { #>
+using <#=referencedNamespace #>;
+<#} #>
+<#manager.EndBlock(); #>
+
+[<#= GeneratedCode #>, DebuggerNonUserCode]
+public static class <#=HelpersPrefix #> {
+<#if (IncludeAreasToken) { #>
+public static class Areas {
+<#} #>
+<#foreach (var area in Areas.Where(a => !string.IsNullOrEmpty(a.Name))) { #>
+    static readonly <#=area.Name #>Class s_<#=area.Name #> = new <#=area.Name #>Class();
+    public static <#=area.Name #>Class <#=EscapeID(area.Namespace) #> { get { return s_<#=area.Name #>; } }
+<#} #>
+<#if (IncludeAreasToken) { #>
+}
+<#} #>
+<#foreach (var controller in DefaultArea.GetControllers()) { #>
+    public static <#=controller.FullClassName #> <#=controller.Name #> = new <#=controller.FullDerivedClassName #>();
+<#} #>
+}
+
+namespace <#=T4MVCNamespace #> {
+<#foreach (var area in Areas.Where(a => !string.IsNullOrEmpty(a.Name))) { #>
+    [<#= GeneratedCode #>, DebuggerNonUserCode]
+    public class <#=area.Name #>Class {
+        public readonly string Name = "<#=ProcessAreaOrControllerName(area.Name) #>";
+<#foreach (var controller in area.GetControllers()) { #>
+        public <#=controller.FullClassName #> <#=controller.Name #> = new <#=controller.FullDerivedClassName #>();
+<#} #>
+    }
+<#} #>
+}
+
+namespace System.Web.Mvc {
+    [<#= GeneratedCode #>, DebuggerNonUserCode]
+    public static class T4Extensions {
+        public static <#=HtmlStringType #> ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result) {
+            return htmlHelper.RouteLink(linkText, result.GetRouteValueDictionary());
+        }
+
+        public static <#=HtmlStringType #> ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, object htmlAttributes) {
+            return ActionLink(htmlHelper, linkText, result, new RouteValueDictionary(htmlAttributes));
+        }
+
+        public static <#=HtmlStringType #> ActionLink(this HtmlHelper htmlHelper, string linkText, ActionResult result, IDictionary<string, object> htmlAttributes) {
+            return htmlHelper.RouteLink(linkText, result.GetRouteValueDictionary(), htmlAttributes);
+        }
+
+        public static MvcForm BeginForm(this HtmlHelper htmlHelper, ActionResult result, FormMethod formMethod) {
+            return htmlHelper.BeginForm(result, formMethod, null);
+        }
+
+        public static MvcForm BeginForm(this HtmlHelper htmlHelper, ActionResult result, FormMethod formMethod, object htmlAttributes) {
+            return BeginForm(htmlHelper, result, formMethod, new RouteValueDictionary(htmlAttributes));
+        }
+
+        public static MvcForm BeginForm(this HtmlHelper htmlHelper, ActionResult result, FormMethod formMethod, IDictionary<string, object> htmlAttributes) {
+            var callInfo = result.GetT4MVCResult();
+            return htmlHelper.BeginForm(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary, formMethod, htmlAttributes);
+        }
+
+<#if (MvcVersion >= 2) {#>
+        public static void RenderAction(this HtmlHelper htmlHelper, ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            htmlHelper.RenderAction(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary);
+        }
+
+        public static MvcHtmlString Action(this HtmlHelper htmlHelper, ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            return htmlHelper.Action(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary);
+        }
+<#} #>
+        public static string Action(this UrlHelper urlHelper, ActionResult result) {
+            return urlHelper.RouteUrl(result.GetRouteValueDictionary());
+        }
+
+        public static string ActionAbsolute(this UrlHelper urlHelper, ActionResult result) {
+            return string.Format("{0}{1}",urlHelper.RequestContext.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority),
+                urlHelper.RouteUrl(result.GetRouteValueDictionary()));
+        }
+
+        public static <#=HtmlStringType #> ActionLink(this AjaxHelper ajaxHelper, string linkText, ActionResult result, AjaxOptions ajaxOptions) {
+            return ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions);
+        }
+
+        public static <#=HtmlStringType #> ActionLink(this AjaxHelper ajaxHelper, string linkText, ActionResult result, AjaxOptions ajaxOptions, object htmlAttributes) {
+            return ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions, new RouteValueDictionary(htmlAttributes));
+        }
+
+        public static <#=HtmlStringType #> ActionLink(this AjaxHelper ajaxHelper, string linkText, ActionResult result, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes) {
+            return ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions, htmlAttributes);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result) {
+            return MapRoute(routes, name, url, result, null /*namespaces*/);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults) {
+            return MapRoute(routes, name, url, result, defaults, null /*constraints*/, null /*namespaces*/);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, string[] namespaces) {
+            return MapRoute(routes, name, url, result, null /*defaults*/, namespaces);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults, object constraints) {
+            return MapRoute(routes, name, url, result, defaults, constraints, null /*namespaces*/);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults, string[] namespaces) {
+            return MapRoute(routes, name, url, result, defaults, null /*constraints*/, namespaces);
+        }
+
+        public static Route MapRoute(this RouteCollection routes, string name, string url, ActionResult result, object defaults, object constraints, string[] namespaces) {
+            // Create and add the route
+            var route = CreateRoute(url, result, defaults, constraints, namespaces);
+            routes.Add(name, route);
+            return route;
+        }
+
+<#if (MvcVersion >= 2) {#>
+        // Note: can't name the AreaRegistrationContext methods 'MapRoute', as that conflicts with the existing methods
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result) {
+            return MapRouteArea(context, name, url, result, null /*namespaces*/);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults) {
+            return MapRouteArea(context, name, url, result, defaults, null /*constraints*/, null /*namespaces*/);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, string[] namespaces) {
+            return MapRouteArea(context, name, url, result, null /*defaults*/, namespaces);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults, object constraints) {
+            return MapRouteArea(context, name, url, result, defaults, constraints, null /*namespaces*/);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults, string[] namespaces) {
+            return MapRouteArea(context, name, url, result, defaults, null /*constraints*/, namespaces);
+        }
+
+        public static Route MapRouteArea(this AreaRegistrationContext context, string name, string url, ActionResult result, object defaults, object constraints, string[] namespaces) {
+            // Create and add the route
+            var route = CreateRoute(url, result, defaults, constraints, namespaces);
+            context.Routes.Add(name, route);
+            route.DataTokens["area"] = context.AreaName;
+            return route;
+        }
+<#} #>
+
+        private static Route CreateRoute(string url, ActionResult result, object defaults, object constraints, string[] namespaces) {
+            // Start by adding the default values from the anonymous object (if any)
+            var routeValues = new RouteValueDictionary(defaults);
+
+            // Then add the Controller/Action names and the parameters from the call
+            foreach (var pair in result.GetRouteValueDictionary()) {
+                routeValues.Add(pair.Key, pair.Value);
+            }
+
+            var routeConstraints = new RouteValueDictionary(constraints);
+
+            // Create and add the route
+            var route = new Route(url, routeValues, routeConstraints, new MvcRouteHandler());
+
+            route.DataTokens = new RouteValueDictionary();
+
+            if (namespaces != null && namespaces.Length > 0) {
+                route.DataTokens["Namespaces"] = namespaces;
+            }
+
+            return route;
+        }
+
+        public static <#=ActionResultInterfaceName #> GetT4MVCResult(this ActionResult result) {
+            var t4MVCResult = result as <#=ActionResultInterfaceName #>;
+            if (t4MVCResult == null) {
+                throw new InvalidOperationException("T4MVC methods can only be passed pseudo-action calls (e.g. MVC.Home.About()), and not real action calls.");
+            }
+            return t4MVCResult;
+        }
+
+        public static RouteValueDictionary GetRouteValueDictionary(this ActionResult result) {
+            return result.GetT4MVCResult().RouteValueDictionary;
+        }
+
+        public static ActionResult AddRouteValues(this ActionResult result, object routeValues) {
+            return result.AddRouteValues(new RouteValueDictionary(routeValues));
+        }
+
+        public static ActionResult AddRouteValues(this ActionResult result, RouteValueDictionary routeValues) {
+            RouteValueDictionary currentRouteValues = result.GetRouteValueDictionary();
+
+            // Add all the extra values
+            foreach (var pair in routeValues) {
+                currentRouteValues.Add(pair.Key, pair.Value);
+            }
+
+            return result;
+        }
+
+        public static ActionResult AddRouteValues(this ActionResult result, System.Collections.Specialized.NameValueCollection nameValueCollection) {
+            // Copy all the values from the NameValueCollection into the route dictionary
+            nameValueCollection.CopyTo(result.GetRouteValueDictionary());
+            return result;
+        }
+
+        public static ActionResult AddRouteValue(this ActionResult result, string name, object value) {
+            RouteValueDictionary routeValues = result.GetRouteValueDictionary();
+            routeValues.Add(name, value);
+            return result;
+        }
+        
+        public static void InitMVCT4Result(this <#=ActionResultInterfaceName #> result, string area, string controller, string action) {
+            result.Controller = controller;
+            result.Action = action;
+            result.RouteValueDictionary = new RouteValueDictionary();
+            <# if (Areas.Count > 1) { #>result.RouteValueDictionary.Add("Area", area ?? "");<# } #> 
+            result.RouteValueDictionary.Add("Controller", controller);
+            result.RouteValueDictionary.Add("Action", action);
+        }
+
+        public static bool FileExists(string virtualPath) {
+            if (!HostingEnvironment.IsHosted) return false;
+            string filePath = HostingEnvironment.MapPath(virtualPath);
+            return System.IO.File.Exists(filePath);
+        }
+
+        static DateTime CenturyBegin=new DateTime(2001,1,1);
+        public static string TimestampString(string virtualPath) {
+            if (!HostingEnvironment.IsHosted) return string.Empty;
+            string filePath = HostingEnvironment.MapPath(virtualPath);
+            return Convert.ToString((System.IO.File.GetLastWriteTimeUtc(filePath).Ticks-CenturyBegin.Ticks)/1000000000,16);            
+        }
+    }
+}
+
+<#if (GenerateActionResultInterface) { #>   
+[<#= GeneratedCode #>]   
+public interface <#=ActionResultInterfaceName #> {   
+    string Action { get; set; }   
+    string Controller { get; set; }   
+    RouteValueDictionary RouteValueDictionary { get; set; }   
+}   
+<#} #>  
+
+<#foreach (var resultType in ResultTypes.Values) { #>
+[<#= GeneratedCode #>, DebuggerNonUserCode]
+public class T4MVC_<#=resultType.Name #> : <#=resultType.FullName #>, <#=ActionResultInterfaceName #> {
+    public T4MVC_<#=resultType.Name #>(string area, string controller, string action): base(<#resultType.Constructor.WriteNonEmptyParameterValues(true); #>)  {
+        this.InitMVCT4Result(area, controller, action);
+    }
+    <#foreach (var method in resultType.AbstractMethods) { #> 
+    <#=method.IsPublic ? "public" : "protected" #> override void <#=method.Name #>(<#method.WriteFormalParameters(true); #>) { }
+    <#} #>
+
+    public string Controller { get; set; }
+    public string Action { get; set; }
+    public RouteValueDictionary RouteValueDictionary { get; set; }
+}
+<#} #>
+
+
+
+namespace <#=LinksNamespace #> {
+<#
+foreach (string folder in StaticFilesFolders) {
+    ProcessStaticFiles(Project, folder);
+}
+#>
+}
+
+<#
+RenderAdditionalCode();
+#>
+<#foreach (var controller in GetAbstractControllers().Where(c => !c.HasDefaultConstructor)) { #>
+<#manager.StartNewFile(controller.GeneratedFileName); #>
+namespace <#=controller.Namespace #> {
+    public partial class <#=controller.ClassName #> {
+        protected <#=controller.ClassName #>() { }
+    }
+}
+<#manager.EndBlock(); #>
+<#} #>
+
+<#foreach (var controller in GetControllers()) { #>
+<#
+    // Don't generate the file at all if the existing one is up to date
+    if (controller.GeneratedCodeIsUpToDate) {
+        manager.KeepGeneratedFile(controller.GeneratedFileName);
+        continue;
+    }
+#>
+<#manager.StartNewFile(controller.GeneratedFileName); #>
+<#if (!String.IsNullOrEmpty(controller.Namespace)) { #>
+namespace <#=controller.Namespace #> {
+<#} #>
+    public <#if (!controller.NotRealController) { #>partial <#} #>class <#=controller.ClassName #> {
+<#if (!controller.NotRealController) { #>
+<#if (!controller.HasExplicitConstructor) { #>
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public <#=controller.ClassName #>() { }
+
+<#} #>
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        protected <#=controller.ClassName #>(Dummy d) { }
+
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        protected RedirectToRouteResult RedirectToAction(ActionResult result) {
+            var callInfo = result.GetT4MVCResult();
+            return RedirectToRoute(callInfo.RouteValueDictionary);
+        }
+
+<#foreach (var method in controller.ActionMethodsUniqueWithoutParameterlessOverload) { #>
+        [NonAction]
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public <#=method.ReturnTypeFullName #> <#=method.Name #>() {
+            return new T4MVC_<#=method.ReturnType #>(Area, Name, ActionNames.<#=method.ActionName #>);
+        }
+<#} #>
+
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public <#=controller.ClassName #> Actions { get { return <#=controller.T4MVCControllerFullName #>; } }
+        [<#= GeneratedCode #>]
+        public readonly string Area = "<#=ProcessAreaOrControllerName(controller.AreaName) #>";
+        [<#= GeneratedCode #>]
+        public readonly string Name = "<#=ProcessAreaOrControllerName(controller.Name) #>";
+
+        static readonly ActionNamesClass s_actions = new ActionNamesClass();
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public ActionNamesClass ActionNames { get { return s_actions; } }
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public class ActionNamesClass {
+<#foreach (var method in controller.ActionMethodsWithUniqueNames) { #>
+<#  if (UseLowercaseRoutes) { #>
+            public readonly string <#=method.ActionName #> = (<#=method.ActionNameValueExpression #>).ToLowerInvariant();
+<#  } else { #>
+            public readonly string <#=method.ActionName #> = <#=method.ActionNameValueExpression #>;
+<#  }
+} #>
+        }
+
+<#} #>
+
+        static readonly ViewNames s_views = new ViewNames();
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public ViewNames Views { get { return s_views; } }
+        [<#= GeneratedCode #>, DebuggerNonUserCode]
+        public class ViewNames {
+<#RenderControllerViews(controller);#>
+        }
+    }
+
+<#if (!controller.NotRealController) { #>
+    [<#= GeneratedCode #>, DebuggerNonUserCode]
+    public class <#=controller.DerivedClassName #>: <#=controller.FullClassName #> {
+        public <#=controller.DerivedClassName #>() : base(Dummy.Instance) { }
+
+<#foreach (var method in controller.ActionMethods) { #>
+        public override <#=method.ReturnTypeFullName #> <#=method.Name #>(<#method.WriteFormalParameters(true); #>) {
+            var callInfo = new T4MVC_<#=method.ReturnType #>(Area, Name, ActionNames.<#=method.ActionName #>);
+<#if (method.Parameters.Count > 0) { #>
+<#foreach (var p in method.Parameters) { #>
+            callInfo.RouteValueDictionary.Add(<#=p.RouteNameExpression #>, <#=p.Name #>);
+<#} #>
+<#}#>
+            return callInfo;
+        }
+
+<#} #>
+    }
+<#} #>
+<#if (!String.IsNullOrEmpty(controller.Namespace)) { #>
+}
+<#} #>
+
+<#manager.EndBlock(); #>
+<#} #>
+
+
+namespace <#=T4MVCNamespace #> {
+    [<#= GeneratedCode #>, DebuggerNonUserCode]
+    public class Dummy {
+        private Dummy() { }
+        public static Dummy Instance = new Dummy();
+    }
+}
+
+<# if (ExplicitHtmlHelpersForPartials) {	
+        manager.StartNewFile("T4MVC.ExplicitExtensions.cs"); #>	
+
+namespace System.Web.Mvc {
+    [<#= GeneratedCode #>]
+    public static class HtmlHelpersForExplicitPartials {
+    <#  
+        foreach(var partial in GetPartials()) {
+            string partialName = partial.Key;
+            string partialPath = partial.Value;
+            string partialRenderMethod = string.Format(ExplicitHtmlHelpersForPartialsFormat, partialName);
+    #>		 
+        ///<summary>
+        ///Render the <b><#= partialName #></b> partial.
+        ///</summary>
+        public static void <#= partialRenderMethod #>(this HtmlHelper html) {
+            html.RenderPartial("<#= partialPath #>");
+        }
+        
+        ///<summary>
+        ///Render the <b><#= partialName #></b> partial.
+        ///</summary>		
+        public static void <#= partialRenderMethod #>(this HtmlHelper html, object model) {
+            html.RenderPartial("<#= partialPath #>", model);
+        }
+    <# } #>	 
+    }
+}
+<#	manager.EndBlock(); #>	
+<#	}	#>	
+
+<#manager.StartFooter(); #>
+#endregion T4MVC
+#pragma warning restore 1591
+<#manager.EndBlock(); #>
+<#manager.Process(SplitIntoMultipleFiles); #>
+
+<#@ Include File="T4MVC.settings.t4" #>
+
+<#+ 
+const string T4MVCNamespace = "T4MVC";
+const string ControllerSuffix = "Controller";
+
+static DTE Dte;
+static Project Project;
+static string AppRoot;
+static HashSet<AreaInfo> Areas;
+static AreaInfo DefaultArea;
+static Dictionary<string, ResultTypeInfo> ResultTypes;
+static TextTransformation TT;
+static string T4FileName;
+static string T4Folder;
+static string GeneratedCode = @"GeneratedCode(""T4MVC"", ""2.0"")";
+static float MvcVersion;
+static string HtmlStringType;
+static Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
+
+IEnumerable<ControllerInfo> GetControllers() {
+    var controllers = new List<ControllerInfo>();
+
+    foreach (var area in Areas) {
+        controllers.AddRange(area.GetControllers());
+    }
+
+    return controllers;
+}
+
+IEnumerable<ControllerInfo> GetAbstractControllers() {
+    var controllers = new List<ControllerInfo>();
+
+    foreach (var area in Areas) {
+        controllers.AddRange(area.GetAbstractControllers());
+    }
+
+    return controllers;
+}
+
+IDictionary<string, string> GetPartials() {
+    var parts = GetControllers()
+        .Select(m => m.ViewsFolder)
+        .SelectMany(m => m.Views)
+        .Where(m => m.Value.EndsWith(".ascx"));
+
+    var partsDic = new Dictionary<string, KeyValuePair<string, string>>();
+
+    foreach(var part in parts) {
+        // Check if we already have a partial view by that name (e.g. if two Views folders have the same ascx)
+        int keyCollisionCount = partsDic.Where(m => m.Key == part.Key || m.Value.Key == part.Key).Count();
+
+        if (keyCollisionCount > 0) {
+            // Append a numbered suffix to avoid the conflict
+            partsDic.Add(part.Key + keyCollisionCount.ToString(), part);
+        }
+        else {
+            partsDic.Add(part.Key, part);
+        }
+    }
+
+    return partsDic.ToDictionary(k => k.Key, v => v.Value.Value);
+}
+
+void PrepareDataToRender(TextTransformation tt) {
+    TT = tt;
+    T4FileName = Path.GetFileName(Host.TemplateFile);
+    T4Folder = Path.GetDirectoryName(Host.TemplateFile);
+    Areas = new HashSet<AreaInfo>();
+    ResultTypes = new Dictionary<string, ResultTypeInfo>();
+
+    // Get the DTE service from the host
+    var serviceProvider = Host as IServiceProvider;
+    if (serviceProvider != null) {
+        Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
+    }
+
+    // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
+    if (Dte == null) {
+        throw new Exception("T4MVC can only execute through the Visual Studio host");
+    }
+
+    Project = GetProjectContainingT4File(Dte);
+
+    if (Project == null) {
+        Error("Could not find the VS Project containing the T4 file.");
+        return;
+    }
+
+    // Get the path of the root folder of the app
+    AppRoot = Path.GetDirectoryName(Project.FullName) + '\\';
+
+    MvcVersion = GetMvcVersion();
+
+    // Use the proper return type of render helpers
+    HtmlStringType = MvcVersion < 2 ? "string" : "MvcHtmlString";
+
+    ProcessAreas(Project);
+}
+
+float GetMvcVersion() {
+    var vsProject = (VSLangProj.VSProject)Project.Object;
+
+    foreach (VSLangProj.Reference r in vsProject.References) {
+        if (r.Name.Equals("System.Web.Mvc", StringComparison.OrdinalIgnoreCase)) {
+            return r.MajorVersion + (r.MinorVersion / 10);
+        }
+    }
+
+    // We should never get here, but default to v1 just in case
+    return 1;
+}
+
+Project GetProjectContainingT4File(DTE dte) {
+
+    // Find the .tt file's ProjectItem
+    ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
+
+    // If the .tt file is not opened, open it
+    if (projectItem.Document == null)
+        projectItem.Open(Constants.vsViewKindCode);
+
+    if (AlwaysKeepTemplateDirty) {
+        // Mark the .tt file as unsaved. This way it will be saved and update itself next time the
+        // project is built. Basically, it keeps marking itself as unsaved to make the next build work.
+        // Note: this is certainly hacky, but is the best I could come up with so far.
+        projectItem.Document.Saved = false;
+    }
+
+    return projectItem.ContainingProject;
+}
+
+void ProcessAreas(Project project) {
+    // Process the default area
+    ProcessArea(project.ProjectItems, null);
+
+    // Get the Areas folder
+    ProjectItem areaProjectItem = GetProjectItem(project, AreasFolder);
+    if (areaProjectItem == null)
+        return;
+
+    foreach (ProjectItem item in areaProjectItem.ProjectItems) {
+        if (IsFolder(item)) {
+            ProcessArea(item.ProjectItems, item.Name);
+        }
+    }
+}
+
+void ProcessArea(ProjectItems areaFolderItems, string name) {
+    var area = new AreaInfo() { Name = name };
+    ProcessAreaControllers(areaFolderItems, area);
+    ProcessAreaViews(areaFolderItems, area);
+    Areas.Add(area);
+
+    if (String.IsNullOrEmpty(name))
+        DefaultArea = area;
+}
+
+void ProcessAreaControllers(ProjectItems areaFolderItems, AreaInfo area) {
+    // Get area Controllers folder
+    ProjectItem controllerProjectItem = GetProjectItem(areaFolderItems, ControllersFolder);
+    if (controllerProjectItem == null)
+        return;
+
+    ProcessControllersRecursive(controllerProjectItem, area);
+}
+
+void ProcessAreaViews(ProjectItems areaFolderItems, AreaInfo area) {
+    // Get area Views folder
+    ProjectItem viewsProjectItem = GetProjectItem(areaFolderItems, ViewsRootFolder);
+    if (viewsProjectItem == null)
+        return;
+
+    ProcessAllViews(viewsProjectItem, area);
+}
+
+void ProcessControllersRecursive(ProjectItem projectItem, AreaInfo area) {
+
+    // Recurse into all the sub-items (both files and folder can have some - e.g. .tt files)
+    foreach (ProjectItem item in projectItem.ProjectItems) {
+        ProcessControllersRecursive(item, area);
+    }
+
+    if (projectItem.FileCodeModel != null) {
+        DateTime controllerLastWriteTime = File.GetLastWriteTime(projectItem.get_FileNames(0));
+        foreach (var type in projectItem.FileCodeModel.CodeElements.OfType<CodeClass2>()) {
+            ProcessControllerType(type, area, controllerLastWriteTime);
+        }
+        // Process all the elements that are namespaces
+        foreach (var ns in projectItem.FileCodeModel.CodeElements.OfType<CodeNamespace>()) {
+            foreach (var type in ns.Members.OfType<CodeClass2>()) {
+                ProcessControllerType(type, area, controllerLastWriteTime);
+            }
+        }
+    }
+}
+
+void ProcessControllerType(CodeClass2 type, AreaInfo area, DateTime controllerLastWriteTime) {
+    // Only process types that end with Controller
+    // REVIEW: this check is not super reliable. Should look at base class.
+    if (!type.Name.EndsWith(ControllerSuffix, StringComparison.OrdinalIgnoreCase))
+        return;
+
+    // Don't process generic classes (their concrete derived classes will be processed)
+    if (type.IsGeneric)
+        return;
+
+    // Make sure the class is partial
+    if (type.ClassKind != vsCMClassKind.vsCMClassKindPartialClass) {
+        try {
+            type.ClassKind = vsCMClassKind.vsCMClassKindPartialClass;
+        }
+        catch {
+            // If we couldn't make it partial, give a warning and skip it
+            Warning(String.Format("{0} was not able to make the class {1} partial. Please change it manually if possible", T4FileName, type.Name));
+            return;
+        }
+        Warning(String.Format("{0} changed the class {1} to be partial", T4FileName, type.Name));
+    }
+
+    // Collect misc info about the controller class and add it to the collection
+    var controllerInfo = new ControllerInfo {
+        Area = area,
+        Namespace = type.Namespace != null ? type.Namespace.Name : String.Empty,
+        ClassName = type.Name
+    };
+
+    // Check if the controller has changed since the generated file was last created
+    DateTime lastGenerationTime = File.GetLastWriteTime(controllerInfo.GeneratedFileFullPath);
+    if (lastGenerationTime > controllerLastWriteTime) {
+        controllerInfo.GeneratedCodeIsUpToDate = true;
+    }
+
+    // Either process new ControllerInfo or integrate results into existing object for partially defined controllers
+    var target = area.Controllers.Add(controllerInfo) ? controllerInfo : area.Controllers.First(c => c.Equals(controllerInfo));
+    target.HasExplicitConstructor |= HasExplicitConstructor(type);
+    target.HasExplicitDefaultConstructor |= HasExplicitDefaultConstructor(type);
+
+    if (type.IsAbstract) {
+        // If it's abstract, set a flag and don't process action methods (derived classes will)
+        target.IsAbstract = true;
+    }
+    else {
+        // Process all the action methods in the controller
+        ProcessControllerActionMethods(target, type);
+    }
+}
+
+void ProcessControllerActionMethods(ControllerInfo controllerInfo, CodeClass2 current) {
+
+    // We want to process not just the controller class itself, but also its parents, as they
+    // may themselves define actions
+    for (CodeClass2 type = current; type != null && type.FullName != "System.Web.Mvc.Controller"; type = (CodeClass2)type.Bases.Item(1)) {
+
+        // If the type doesn't come from this project, some actions on it will fail. Try to get a real project type if possible.
+        if (type.InfoLocation != vsCMInfoLocation.vsCMInfoLocationProject) {
+            // Go through all the projects in the solution
+            //foreach (Project prj in Dte.Solution.Projects) {
+            for (int i = 1; i <= Dte.Solution.Projects.Count; i++) {
+                Project prj = null;
+                try {
+                    prj = Dte.Solution.Projects.Item(i);
+                }
+                catch (System.Runtime.Serialization.SerializationException) {
+                    // Some project types (that we don't care about) cause a strange exception, so ingore it
+                    continue;
+                }
+
+                // Skip it if it's the current project or doesn't have a code model
+                try {
+                   if (prj == Project || prj.CodeModel == null)
+                      continue;
+                }
+                catch (System.NotImplementedException) {
+                   // Installer project does not implement CodeModel property
+                   continue;
+                }
+
+                // If we can get a local project type, use it instead of the original
+                var codeType = prj.CodeModel.CodeTypeFromFullName(type.FullName);
+                if (codeType != null && codeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationProject) {
+                    type = (CodeClass2)codeType;
+                    break;
+                }
+            }
+        }
+
+        foreach (CodeFunction2 method in GetMethods(type)) {
+            // Ignore non-public methods
+            if (method.Access != vsCMAccess.vsCMAccessPublic)
+                continue;
+
+            // Ignore methods that are marked as not being actions
+            if (GetAttribute(method.Attributes, "System.Web.Mvc.NonActionAttribute") != null)
+                continue;
+
+            // This takes care of avoiding generic types which cause method.Type.CodeType to blow up
+            if (method.Type.TypeKind != vsCMTypeRef.vsCMTypeRefCodeType)
+                continue;
+
+            // We only support action methods that return an ActionResult derived type
+            if (!method.Type.CodeType.get_IsDerivedFrom("System.Web.Mvc.ActionResult")) {
+                Warning(String.Format("{0} doesn't support {1}.{2} because it doesn't return a supported ActionResult type", T4FileName, type.Name, method.Name));
+                continue;
+            }
+
+            // If we haven't yet seen this return type, keep track of it
+            if (!ResultTypes.ContainsKey(method.Type.CodeType.Name)) {
+                var resTypeInfo = new ResultTypeInfo(method.Type.CodeType);
+
+                ResultTypes[method.Type.CodeType.Name] = resTypeInfo;
+            }
+
+            // Make sure the method is virtual
+            if (!method.CanOverride && method.OverrideKind != vsCMOverrideKind.vsCMOverrideKindOverride) {
+                try {
+                    method.CanOverride = true;
+                }
+                catch {
+                    // If we couldn't make it virtual, give a warning and skip it
+                    Warning(String.Format("{0} was not able to make the action method {1}.{2} virtual. Please change it manually if possible", T4FileName, type.Name, method.Name));
+                    continue;
+                }
+                Warning(String.Format("{0} changed the action method {1}.{2} to be virtual", T4FileName, type.Name, method.Name));
+            }
+
+            // Collect misc info about the action method and add it to the collection
+            controllerInfo.ActionMethods.Add(new ActionMethodInfo(method));
+        }
+    }
+}
+
+void ProcessAllViews(ProjectItem viewsProjectItem, AreaInfo area) {
+    // Go through all the sub-folders in the Views folder
+    foreach (ProjectItem item in viewsProjectItem.ProjectItems) {
+
+        // We only care about sub-folders, not files
+        if (!IsFolder(item))
+            continue;
+
+        // Find the controller for this view folder
+        ControllerInfo controller = area.Controllers.SingleOrDefault(c => c.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase));
+
+        if (controller == null) {
+            // If it doesn't match a controller, treat as a pseudo-controller for consistency
+            controller = new ControllerInfo {
+                Area = area,
+                NotRealController = true,
+                Namespace = MakeClassName(T4MVCNamespace, area.Name),
+                ClassName = item.Name + ControllerSuffix
+            };
+            area.Controllers.Add(controller);
+        }
+
+        AddViewsRecursive(item.ProjectItems, controller.ViewsFolder);
+    }
+}
+
+void AddViewsRecursive(ProjectItems items, ViewsFolderInfo viewsFolder) {
+  AddViewsRecursive(items, viewsFolder, false);
+}
+void AddViewsRecursive(ProjectItems items, ViewsFolderInfo viewsFolder, bool useNonQualifiedViewNames) {
+    // Go through all the files in the subfolder to get the view names
+    foreach (ProjectItem item in items) {
+        if (item.Kind == Constants.vsProjectItemKindPhysicalFile) {
+            if (Path.GetExtension(item.Name).Equals(".master", StringComparison.OrdinalIgnoreCase))
+                continue;   // ignore master files
+            viewsFolder.AddView(item, useNonQualifiedViewNames);
+        }
+        else if (item.Kind == Constants.vsProjectItemKindPhysicalFolder) {
+            string folderName = Path.GetFileName(item.Name);
+            if (folderName.Equals("App_LocalResources", StringComparison.OrdinalIgnoreCase))
+                continue;
+            // Use simple view names if we're already in that mode, or if the folder name is in the collection
+            bool folderShouldUseNonQualifiedViewNames = useNonQualifiedViewNames || NonQualifiedViewFolders.Contains(folderName, StringComparer.OrdinalIgnoreCase);
+            var subViewFolder = new ViewsFolderInfo() { Name = folderName };
+            viewsFolder.SubFolders.Add(subViewFolder);
+            AddViewsRecursive(item.ProjectItems, subViewFolder, folderShouldUseNonQualifiedViewNames);
+        }
+    }
+}
+
+void RenderControllerViews(ControllerInfo controller) {
+    PushIndent("            ");
+    RenderViewsRecursive(controller.ViewsFolder, controller);
+    PopIndent();
+}
+
+void RenderViewsRecursive(ViewsFolderInfo viewsFolder, ControllerInfo controller) {
+
+    // For each view, generate a readonly string
+    foreach (var viewPair in viewsFolder.Views) {
+        WriteLine("public readonly string " + EscapeID(Sanitize(viewPair.Key)) + " = \"" + viewPair.Value + "\";");
+    }
+
+    // For each sub folder, generate a class and recurse
+    foreach (var subFolder in viewsFolder.SubFolders) {
+        string newClassName = Sanitize(subFolder.Name);#>
+static readonly _<#=newClassName#> s_<#=newClassName#> = new _<#=newClassName#>();
+public _<#=newClassName#> <#=EscapeID(newClassName)#> { get { return s_<#=newClassName#>; } }
+public partial class _<#=newClassName#>{
+<#+
+PushIndent("    ");
+RenderViewsRecursive(subFolder, controller);
+PopIndent();
+
+WriteLine("}");
+    }
+}
+
+void ProcessStaticFiles(Project project, string folder) {
+
+    ProjectItem folderProjectItem = GetProjectItem(project, folder);
+    if (folderProjectItem != null) {
+        ProcessStaticFilesRecursive(folderProjectItem, "~");
+    }
+}
+
+void ProcessStaticFilesRecursive(ProjectItem projectItem, string path) {
+
+    if (IsFolder(projectItem)) { #>
+    [<#= GeneratedCode #>, DebuggerNonUserCode]
+    public static class <#=EscapeID(Sanitize(projectItem.Name)) #> {
+        private const string URLPATH = "<#=path#>/<#=projectItem.Name#>";
+        public static string Url() { return T4MVCHelpers.ProcessVirtualPath(URLPATH); }
+        public static string Url(string fileName) { return T4MVCHelpers.ProcessVirtualPath(URLPATH + "/" + fileName); }
+<#+
+PushIndent("    ");
+
+// Recurse into all the items in the folder
+foreach (ProjectItem item in projectItem.ProjectItems) {
+    ProcessStaticFilesRecursive(item, path + "/" + projectItem.Name);
+}
+
+PopIndent();
+#>
+    }
+
+<#+
+}
+    else { #>
+<#+
+if (!ExcludedStaticFileExtensions.Any(extension => projectItem.Name.EndsWith(extension, StringComparison.OrdinalIgnoreCase))) {
+    // if it's a non-minified javascript file
+    if (projectItem.Name.EndsWith(".js") && !projectItem.Name.EndsWith(".min.js")) { 
+        if (AddTimestampToStaticLinks) { #>
+    public static readonly string <#=Sanitize(projectItem.Name)#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=projectItem.Name.Replace(".js", ".min.js")#>") ? Url("<#=projectItem.Name.Replace(".js", ".min.js")#>")+"?"+T4Extensions.TimestampString(URLPATH + "/<#=projectItem.Name#>") : Url("<#=projectItem.Name#>")+"?"+T4Extensions.TimestampString(URLPATH + "/<#=projectItem.Name#>");
+        <#+} else {#>
+    public static readonly string <#=Sanitize(projectItem.Name)#> = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/<#=projectItem.Name.Replace(".js", ".min.js")#>") ? Url("<#=projectItem.Name.Replace(".js", ".min.js")#>") : Url("<#=projectItem.Name#>");
+        <#+}  #>          
+<#+}
+    else if (AddTimestampToStaticLinks) { #>
+    public static readonly string <#=Sanitize(projectItem.Name)#> = Url("<#=projectItem.Name#>")+"?"+T4Extensions.TimestampString(URLPATH + "/<#=projectItem.Name#>");
+<#+}
+    else { #>
+    public static readonly string <#=Sanitize(projectItem.Name)#> = Url("<#=projectItem.Name#>");
+<#+}
+} #>
+<#+
+// Non folder items may also have children (virtual folders, Class.cs -> Class.Designer.cs, template output)
+// Just register them on the same path as their parent item
+foreach (ProjectItem item in projectItem.ProjectItems) {
+    ProcessStaticFilesRecursive(item, path);
+}
+    }
+}
+ProjectItem GetProjectItem(Project project, string name) {
+    return GetProjectItem(project.ProjectItems, name);
+}
+
+ProjectItem GetProjectItem(ProjectItems items, string subPath) {
+
+    ProjectItem current = null;
+    foreach (string name in subPath.Split('\\')) {
+        try {
+            // ProjectItems.Item() throws when it doesn't exist, so catch the exception
+            // to return null instead.
+            current = items.Item(name);
+        }
+        catch {
+            // If any chunk couldn't be found, fail
+            return null;
+        }
+        items = current.ProjectItems;
+    }
+
+    return current;
+}
+
+static string GetVirtualPath(ProjectItem item) {
+    string fileFullPath = item.get_FileNames(0);
+    if (!fileFullPath.StartsWith(AppRoot, StringComparison.OrdinalIgnoreCase))
+        throw new Exception(string.Format("File {0} is not under app root {1}. Please report issue.", fileFullPath, AppRoot));
+
+    // Make a virtual path from the physical path
+    return "~/" + fileFullPath.Substring(AppRoot.Length).Replace('\\', '/');
+}
+
+static string ProcessAreaOrControllerName(string name) {
+    return UseLowercaseRoutes ? name.ToLowerInvariant() : name;
+}
+
+// Return all the CodeFunction2 in the CodeElements collection
+static IEnumerable<CodeFunction2> GetMethods(CodeClass2 codeClass) {
+    // Only look at regular method (e.g. ignore things like contructors)
+    return codeClass.Members.OfType<CodeFunction2>()
+        .Where(f => f.FunctionKind == vsCMFunction.vsCMFunctionFunction);
+}
+
+// Check if the class has any explicit constructor
+static bool HasExplicitConstructor(CodeClass2 codeClass) {
+    return codeClass.Members.OfType<CodeFunction2>().Any(
+        f => f.FunctionKind == vsCMFunction.vsCMFunctionConstructor);
+}
+
+// Check if the class has a default (i.e. no params) constructor
+static bool HasExplicitDefaultConstructor(CodeClass2 codeClass) {
+    return codeClass.Members.OfType<CodeFunction2>().Any(
+        f => f.FunctionKind == vsCMFunction.vsCMFunctionConstructor && f.Parameters.Count == 0);
+}
+
+// Find a method with a given name
+static CodeFunction2 GetMethod(CodeClass2 codeClass, string name) {
+    return GetMethods(codeClass).FirstOrDefault(f => f.Name == name);
+}
+
+// Find an attribute of a given type on an attribute collection
+static CodeAttribute2 GetAttribute(CodeElements attributes, string attributeType) {
+    for (int i = 1; i <= attributes.Count; i++) {
+        var attrib = (CodeAttribute2)attributes.Item(i);
+        if (attrib.FullName == attributeType) {
+            return attrib;
+        }
+    }
+    return null;
+}
+
+// Return whether a ProjectItem is a folder and not a file
+static bool IsFolder(ProjectItem item) {
+    return (item.Kind == Constants.vsProjectItemKindPhysicalFolder);
+}
+
+static string MakeClassName(string ns, string classname) {
+    return String.IsNullOrEmpty(ns) ? classname :
+        String.IsNullOrEmpty(classname) ? ns : ns + "." + codeProvider.CreateEscapedIdentifier(classname);
+}
+
+static string Sanitize(string token) {
+    // Replace all invalid chars by underscores
+    token = Regex.Replace(token, @"[\W\b]", "_", RegexOptions.IgnoreCase);
+
+    // If it starts with a digit, prefix it with an underscore
+    token = Regex.Replace(token, @"^\d", @"_$0");
+
+    // Check for reserved words
+    // TODO: Clean this up and add other reserved words (keywords, etc)
+    if (token == "Url") token = "_Url";
+
+    return token;
+}
+
+static string EscapeID(string id) {
+    return codeProvider.CreateEscapedIdentifier(id);
+}
+
+// Data structure to collect data about an area
+class AreaInfo {
+    public AreaInfo() {
+        Controllers = new HashSet<ControllerInfo>();
+    }
+
+    public string Name { get; set; }
+    public HashSet<ControllerInfo> Controllers { get; set; }
+
+    public string Namespace {
+        get {
+            // When *not* using an 'Areas' token, we need to disambiguate conflicts
+            // between Area names and controller names (from the default Area)
+            if (!IncludeAreasToken && DefaultArea.Controllers.Any(c => c.Name == Name))
+                return Name + "Area";
+
+            return Name;
+        }
+    }
+
+    public IEnumerable<ControllerInfo> GetControllers() {
+        return Controllers.Where(c => !c.IsAbstract);
+    }
+
+    public IEnumerable<ControllerInfo> GetAbstractControllers() {
+        return Controllers.Where(c => c.IsAbstract);
+    }
+}
+
+// Data structure to collect data about a controller class
+class ControllerInfo {
+    public ControllerInfo() {
+        ActionMethods = new HashSet<ActionMethodInfo>();
+        ViewsFolder = new ViewsFolderInfo();
+    }
+
+    public AreaInfo Area { get; set; }
+
+    public string AreaName {
+        get { return Area.Name ?? ""; }
+    }
+
+    public string T4MVCControllerFullName {
+        get {
+            string name = HelpersPrefix;
+            if (!String.IsNullOrEmpty(AreaName))
+                name += "." + EscapeID(Area.Namespace);
+            return name + "." + Name; ;
+        }
+    }
+
+    public string ViewPath {
+        get {
+            if (string.IsNullOrEmpty(Area.Name))
+                return String.Format("~/{0}/{1}/", ViewsRootFolder, Name);
+            else
+                return String.Format("~/{0}/{1}/{2}/", AreasFolder, ViewsRootFolder, Name);
+        }
+    }
+
+    // True when this is not a real controller, but a placeholder for views folders that don't match a controller
+    public bool NotRealController { get; set; }
+
+    public bool HasExplicitConstructor { get; set; }
+    public bool HasExplicitDefaultConstructor { get; set; }
+    public bool HasDefaultConstructor { get { return !HasExplicitConstructor || HasExplicitDefaultConstructor; } }
+    public bool IsAbstract { get; set; }
+
+    public bool GeneratedCodeIsUpToDate { get; set; }
+
+    public string ClassName { get; set; }
+    public string Name {
+        get {
+            // Trim the Controller suffix
+            return ClassName.Substring(0, ClassName.Length - ControllerSuffix.Length);
+        }
+    }
+
+    public string Namespace { get; set; }
+
+    public string FullClassName {
+        get {
+            return MakeClassName(Namespace, ClassName);
+        }
+    }
+
+    public string DerivedClassName {
+        get {
+            return "T4MVC_" + ClassName;
+        }
+    }
+
+    public string FullDerivedClassName {
+        get {
+            if (NotRealController)
+                return FullClassName;
+            return MakeClassName(Namespace, DerivedClassName);
+        }
+    }
+
+    public string GeneratedFileName {
+        get {
+            return MakeClassName(AreaName, ClassName + ".generated.cs");
+        }
+    }
+
+    public string GeneratedFileFullPath {
+        get {
+            return Path.Combine(T4Folder, GeneratedFileName);
+        }
+    }
+
+    public HashSet<ActionMethodInfo> ActionMethods { get; set; }
+
+    IEnumerable<ActionMethodInfo> ActionMethodsWithNoParameters {
+        get {
+            return ActionMethods.Where(m => m.CanBeCalledWithoutParameters);
+        }
+    }
+
+    public IEnumerable<ActionMethodInfo> ActionMethodsUniqueWithoutParameterlessOverload {
+        get {
+            return ActionMethodsWithUniqueNames.Except(ActionMethodsWithNoParameters, new ActionComparer());
+        }
+    }
+
+    // Return a list of actions without duplicate names (even with multiple overloads)
+    public IEnumerable<ActionMethodInfo> ActionMethodsWithUniqueNames {
+        get {
+            return ActionMethods.Distinct(new ActionComparer());
+        }
+    }
+
+    class ActionComparer : IEqualityComparer<ActionMethodInfo> {
+        public bool Equals(ActionMethodInfo x, ActionMethodInfo y) {
+            return x.ActionName == y.ActionName;
+        }
+
+        public int GetHashCode(ActionMethodInfo obj) {
+            return obj.ActionName.GetHashCode();
+        }
+    }
+
+    public ViewsFolderInfo ViewsFolder { get; private set; }
+
+    public override string ToString() {
+        return Name;
+    }
+
+    public override bool Equals(object obj) {
+        return obj != null && FullClassName == ((ControllerInfo)obj).FullClassName;
+    }
+
+    public override int GetHashCode() {
+        return FullClassName.GetHashCode();
+    }
+}
+
+// Info about a view folder, its views and its sub view folders
+class ViewsFolderInfo {
+    public ViewsFolderInfo() {
+        Views = new Dictionary<string, string>();
+        SubFolders = new List<ViewsFolderInfo>();
+    }
+
+    public void AddView(ProjectItem item, bool useNonQualifiedViewName) {
+        string viewName = Path.GetFileName(item.Name);
+        string viewFieldName = Path.GetFileNameWithoutExtension(viewName);
+ 
+        // If the simple view name is already in use, include the extension (e.g. foo_ascx instead of just foo)
+        if (Views.ContainsKey(viewFieldName))
+            viewFieldName = Sanitize(viewName);
+ 
+        Views[viewFieldName] = useNonQualifiedViewName ? Path.GetFileNameWithoutExtension(viewName) : GetVirtualPath(item);
+    }
+
+    public string Name { get; set; }
+    public Dictionary<string, string> Views { get; private set; }
+    public List<ViewsFolderInfo> SubFolders { get; set; }
+}
+
+// Data structure to collect data about a method
+class FunctionInfo {
+    protected CodeFunction2 _method;
+    private string _signature;
+
+    public FunctionInfo(CodeFunction2 method) {
+        Parameters = new List<MethodParamInfo>();
+
+        // Can be null when an custom ActionResult has no ctor
+        if (method == null)
+            return;
+
+        _method = method;
+
+        // Build a unique signature for the method, used to avoid duplication
+        _signature = method.Name;
+
+        CanBeCalledWithoutParameters = true;
+
+        // Process all the parameters
+        foreach (var p in method.Parameters.OfType<CodeParameter2>()) {
+            // If any param is not optional, then the method can't be called without parameters
+            if (p.ParameterKind != vsCMParameterKind.vsCMParameterKindOptional) {
+                CanBeCalledWithoutParameters = false;
+            }
+
+            string routeNameExpression = "\"" + p.Name + "\"";
+
+            // If there is a [Bind(Prefix = "someName")] attribute, use it
+            if (p.InfoLocation != vsCMInfoLocation.vsCMInfoLocationExternal) {
+                var attrib = GetAttribute(p.Attributes, "System.Web.Mvc.BindAttribute");
+                if (attrib != null) {
+                    var arg = attrib.Arguments.OfType<CodeAttributeArgument>().FirstOrDefault(a => a.Name == "Prefix");
+                    if (arg != null)
+                        routeNameExpression = arg.Value;
+                }
+            }
+            
+            Parameters.Add(
+                new MethodParamInfo() {
+                    Name = p.Name,
+                    RouteNameExpression = routeNameExpression,
+                    Type = p.Type.AsString
+                });
+            _signature += "," + p.Type.AsString;
+        }
+    }
+
+    public string Name { get { return _method.Name; } }
+    public string ReturnType { get { return _method.Type.CodeType.Name; } }
+    public string ReturnTypeFullName { get { return _method.Type.CodeType.FullName; } }
+    public bool IsPublic { get { return _method.Access == vsCMAccess.vsCMAccessPublic; } }
+    public List<MethodParamInfo> Parameters { get; private set; }
+    public bool CanBeCalledWithoutParameters { get; private set; }
+
+    // Write out all the parameters as part of a method declaration
+    public void WriteFormalParameters(bool first) {
+        foreach (var p in Parameters) {
+            if (first)
+                first = false;
+            else
+                TT.Write(", ");
+
+            TT.Write(p.Type + " " + p.Name);
+        }
+    }
+
+    // Pass non-empty param values to make sure the ActionResult ctors don't complain
+    // REVIEW: this is a bit dirty
+    public void WriteNonEmptyParameterValues(bool first) {
+        foreach (var p in Parameters) {
+            if (first)
+                first = false;
+            else
+                TT.Write(", ");
+
+            switch (p.Type) {
+                case "string":
+                    TT.Write("\" \"");
+                    break;
+                case "byte[]":
+                    TT.Write("new byte[0]");
+                    break;
+                default:
+                    TT.Write("default(" + p.Type + ")");
+                    break;
+            }
+        }
+    }
+
+    public override bool Equals(object obj) {
+        return obj != null && _signature == ((FunctionInfo)obj)._signature;
+    }
+
+    public override int GetHashCode() {
+        return _signature.GetHashCode();
+    }
+}
+
+// Data structure to collect data about an action method
+class ActionMethodInfo : FunctionInfo {
+    public ActionMethodInfo(CodeFunction2 method)
+        : base(method) {
+        // Normally, the action name is the method name. But if there is an [ActionName] on
+        // the method, get the expression from that instead
+        ActionNameValueExpression = '"' + Name + '"';
+        var attrib = GetAttribute(method.Attributes, "System.Web.Mvc.ActionNameAttribute");
+        if (attrib != null) {
+            var arg = (CodeAttributeArgument)attrib.Arguments.Item(1);
+            ActionNameValueExpression = arg.Value;
+        }
+    }
+
+    public string ActionName { get { return Name; } }
+    public string ActionNameValueExpression { get; set; }
+}
+
+// Data about an ActionResult derived type
+class ResultTypeInfo {
+    CodeType _codeType;
+    public ResultTypeInfo(CodeType codeType) {
+        _codeType = codeType;
+
+        var ctor = _codeType.Members.OfType<CodeFunction2>().FirstOrDefault(
+            f => f.FunctionKind == vsCMFunction.vsCMFunctionConstructor);
+        Constructor = new FunctionInfo(ctor);
+    }
+
+    public string Name { get { return _codeType.Name; } }
+    public string FullName { get { return _codeType.FullName; } }
+    public FunctionInfo Constructor { get; set; }
+    public IEnumerable<FunctionInfo> AbstractMethods {
+        get {
+            return _codeType.Members.OfType<CodeFunction2>().Where(
+                f => f.MustImplement).Select(f => new FunctionInfo(f));
+        }
+    }
+}
+
+class MethodParamInfo {
+    public string Name { get; set; }
+    public string RouteNameExpression { get; set; }
+    public string Type { get; set; }
+}
+
+
+/*
+    Manager.tt from Damien Guard: http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited
+*/
+
+
+// Manager class records the various blocks so it can split them up
+class Manager {
+    private class Block {
+        public String Name;
+        public int Start, Length;
+    }
+
+    private Block currentBlock;
+    private List<Block> files = new List<Block>();
+    private Block footer = new Block();
+    private Block header = new Block();
+    private ITextTemplatingEngineHost host;
+    private StringBuilder template;
+    protected List<String> generatedFileNames = new List<String>();
+
+    public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
+        return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
+    }
+
+    public void KeepGeneratedFile(String name) {
+        name = Path.Combine(Path.GetDirectoryName(host.TemplateFile), name);
+        generatedFileNames.Add(name);
+    }
+    
+    public void StartNewFile(String name) {
+        if (name == null)
+            throw new ArgumentNullException("name");
+        CurrentBlock = new Block { Name = name };
+    }
+
+    public void StartFooter() {
+        CurrentBlock = footer;
+    }
+
+    public void StartHeader() {
+        CurrentBlock = header;
+    }
+
+    public void EndBlock() {
+        if (CurrentBlock == null)
+            return;
+        CurrentBlock.Length = template.Length - CurrentBlock.Start;
+        if (CurrentBlock != header && CurrentBlock != footer)
+            files.Add(CurrentBlock);
+        currentBlock = null;
+    }
+
+    public virtual void Process(bool split) {
+        if (split) {
+            EndBlock();
+            String headerText = template.ToString(header.Start, header.Length);
+            String footerText = template.ToString(footer.Start, footer.Length);
+            String outputPath = Path.GetDirectoryName(host.TemplateFile);
+            files.Reverse();
+            foreach (Block block in files) {
+                String fileName = Path.Combine(outputPath, block.Name);
+                String content = headerText + template.ToString(block.Start, block.Length) + footerText;
+                generatedFileNames.Add(fileName);
+                CreateFile(fileName, content);
+                template.Remove(block.Start, block.Length);
+            }
+        }
+    }
+
+    protected virtual void CreateFile(String fileName, String content) {
+        if (IsFileContentDifferent(fileName, content))
+            File.WriteAllText(fileName, content);
+    }
+
+    public virtual String GetCustomToolNamespace(String fileName) {
+        return null;
+    }
+
+    public virtual String DefaultProjectNamespace {
+        get { return null; }
+    }
+
+    protected bool IsFileContentDifferent(String fileName, String newContent) {
+        return !(File.Exists(f