 				if (StructKeyExists(loc.returnValue, "#loc.key#($second)"))
 					StructDelete(loc.returnValue, "#loc.key#($second)");
 			}
-
 			// add form variables to the params struct
-			for (loc.key in loc.returnValue)
-			{
-				if (Find("[", loc.key) && Right(loc.key, 1) == "]")
-				{
-					// object form field
-					loc.name = SpanExcluding(loc.key, "[");
-					// we split the key into an array so the developer can have multiple levels of params passed in
-					loc.nested = ListToArray(ReplaceList(loc.key, loc.name & "[,]", ""), "["); 
-					if (!StructKeyExists(loc.returnValue, loc.name))
-						loc.returnValue[loc.name] = {};
-					loc.struct = loc.returnValue[loc.name]; // we need a reference to the struct so we can nest other structs if needed
-					loc.iEnd = ArrayLen(loc.nested);
-					for (loc.i = 1; loc.i lte loc.iEnd; loc.i++) // looping over the array allows for infinite nesting
-					{
-						loc.item = loc.nested[loc.i];
-						if (!StructKeyExists(loc.struct, loc.item))
-							loc.struct[loc.item] = {};
-						if (loc.i != loc.iEnd)
-							loc.struct = loc.struct[loc.item]; // pass the new reference (structs pass a reference instead of a copy) to the next iteration
-						else
-							loc.struct[loc.item] = loc.returnValue[loc.key];
-					}
-					// delete the original key so it doesn't show up in the params
-					StructDelete(loc.returnValue, loc.key, false);
+			$createNestedParamStruct(params=loc.returnValue);
+			// find any new structs and convert them
+			$createNewArrayStruct(params=loc.returnValue);
+		}
+		
+		/************************************
+		*	We now do the routing and controller
+		*	params after we have built all other params
+		*	so that we don't have more logic around
+		*	params in arrays
+		************************************/
+
+		// go through the matching route pattern and add URL variables from the route to the struct
+		loc.iEnd = ListLen(arguments.foundRoute.pattern, "/");
+		for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
+		{
+			loc.item = ListGetAt(arguments.foundRoute.pattern, loc.i, "/");
+			if (Left(loc.item, 1) == "[")
+				loc.returnValue[ReplaceList(loc.item, "[,]", ",")] = ListGetAt(arguments.route, loc.i, "/");
+		}
+
+		// add controller and action unless they already exist
+		if (!StructKeyExists(loc.returnValue, "controller"))
+			loc.returnValue.controller = arguments.foundRoute.controller;
+		if (!StructKeyExists(loc.returnValue, "action"))
+			loc.returnValue.action = arguments.foundRoute.action;
+
+		// convert controller to upperCamelCase and action to normal camelCase
+		loc.returnValue.controller = REReplace(loc.returnValue.controller, "-([a-z])", "\u\1", "all");
+		loc.returnValue.action = REReplace(loc.returnValue.action, "-([a-z])", "\u\1", "all");
+
+		// add name of route to params if a named route is running
+		if (StructKeyExists(arguments.foundRoute, "name") && Len(arguments.foundRoute.name) && !StructKeyExists(loc.returnValue, "route"))
+			loc.returnValue.route = arguments.foundRoute.name;
+	</cfscript>
+	<cfreturn loc.returnValue>
+</cffunction>
+
+<cffunction name="$getParameterMap" returntype="struct" access="public" output="false">
+	<cfargument name="formScope" type="struct" required="true">
+	<cfargument name="urlScope" type="struct" required="true">
+	<cfargument name="parameters" type="struct" required="false" default="#Duplicate(GetPageContext().getRequest().getParameterMap())#">
+	<cfargument name="multipart" type="any" required="false" default="#form.getPartsArray()#">
+	<cfscript>
+		var loc = {};
+		loc.original = {};
+		loc.multipart = {};
+		loc.parameters = {};
+		// merge our coldfusion scopes together
+		loc.original = Duplicate(arguments.formScope);
+		StructDelete(loc.original, "fieldnames", false);
+		StructAppend(loc.original, arguments.urlScope, true);
+		// if the form our url scopes were set after the request started, we need to make sure that they are in arrays
+		for (loc.item in loc.original)
+		{
+			loc.parameters[loc.item] = [];
+			ArrayAppend(loc.parameters[loc.item], loc.original[loc.item]);
+		}
+		// get our values from the parameter map, this will always contain url variables and will contain form parameters when not a multipart form
+		for (loc.item in arguments.parameters)
+		{
+			loc.parameters[loc.item] = [];
+			loc.iEnd = ArrayLen(arguments.parameters[loc.item]);
+			for (loc.i = 1; loc.i lte loc.iEnd; loc.i++)
+				loc.parameters[loc.item][loc.i] = arguments.parameters[loc.item][loc.i];
+		}
+		// if this is defined, then we have a multipart for and will be getting our form values from here
+		if (StructKeyExists(arguments, "multipart"))
+		{
+			// build our multipart struct
+			loc.iEnd = ArrayLen(arguments.multipart);
+			for (loc.i = 1; loc.i lte loc.iEnd; loc.i++)
+			{
+				loc.param = arguments.multipart[loc.i];
+				if (loc.param.isParam())
+				{
+					if (!StructKeyExists(loc.multipart, loc.param.getName()))
+						loc.multipart[loc.param.getName()] = [];
+					ArrayAppend(loc.multipart[loc.param.getName()], loc.param.getStringValue());
+				}
+			}
+			
+			// now overwrite our parameters with the multipart values
+			for (loc.item in loc.multipart)
+				loc.parameters[loc.item] = loc.multipart[loc.item];
+		}
+		// overwrite any parameters in our map with the right values from the url
+		for (loc.item in arguments.urlScope)
+		{
+			loc.parameters[loc.item] = [];
+			ArrayAppend(loc.parameters[loc.item], arguments.urlScope[loc.item]);
+		}
+	</cfscript>
+	<cfreturn loc.parameters />
+</cffunction>
+
+<cffunction name="$createNestedParamStruct" returntype="struct" access="public" output="false">
+	<cfargument name="params" type="struct" required="true" />
+	<cfscript>
+		var loc = {};
+		for (loc.key in arguments.params)
+		{
+			if (Find("[", loc.key) && Right(loc.key, 1) == "]")
+			{
+				// object form field
+				loc.name = SpanExcluding(loc.key, "[");
+				// we split the key into an array so the developer can have multiple levels of params passed in
+				loc.nested = ListToArray(ReplaceList(loc.key, loc.name & "[,]", ""), "[", true); 
+				if (!StructKeyExists(arguments.params, loc.name))
+					arguments.params[loc.name] = {};
+				loc.struct = arguments.params[loc.name]; // we need a reference to the struct so we can nest other structs if needed
+				loc.iEnd = ArrayLen(loc.nested);
+				for (loc.i = 1; loc.i lte loc.iEnd; loc.i++) // looping over the array allows for infinite nesting
+				{
+					loc.item = loc.nested[loc.i];
+					if (!Len(loc.item)) // if we have an empty struct item it means that the developer is passing in new items
+						loc.item = "new";
+					if (!StructKeyExists(loc.struct, loc.item))
+						loc.struct[loc.item] = {};
+					if (loc.i != loc.iEnd)
+						loc.struct = loc.struct[loc.item]; // pass the new reference (structs pass a reference instead of a copy) to the next iteration
+					else if (IsArray(arguments.params[loc.key]) && ArrayLen(arguments.params[loc.key]) == 1)
+						loc.struct[loc.item] = arguments.params[loc.key][1];
+					else if (IsArray(arguments.params[loc.key]))
+						loc.struct[loc.item] = $arrayToStruct(arguments.params[loc.key]);
+					else
+						loc.struct[loc.item] = arguments.params[loc.key];
+				}
+				// delete the original key so it doesn't show up in the params
+				StructDelete(arguments.params, loc.key, false);
+			}
+			else if (IsArray(arguments.params[loc.key]) && ArrayLen(arguments.params[loc.key]) == 1)
+				arguments.params[loc.key] = arguments.params[loc.key][1];
+		}	
+	</cfscript>
+	<cfreturn arguments.params />
+</cffunction>
+
+<cffunction name="$createNewArrayStruct" returntype="void" access="public" output="false">
+	<cfargument name="params" type="struct" required="true" />
+	<cfscript>
+		var loc = {};
+		
+		loc.newStructArray = StructFindKey(arguments.params, "new", "all");
+		loc.iEnd = ArrayLen(loc.newStructArray);
+		
+		for (loc.i = 1; loc.i lte loc.iEnd; loc.i++)
+		{
+			loc.owner = loc.newStructArray[loc.i].owner.new;
+			loc.value = loc.newStructArray[loc.i].value;
+			loc.map = {};
+			$mapStruct(map=loc.map, struct=loc.value);
+			
+			StructClear(loc.value); // clear the struct now that we have our paths and values
+			
+			for (loc.item in loc.map) // remap our new struct
+			{
+				// move the last element to the first
+				loc.newPos = loc.item;
+				loc.last = Replace(ListLast(loc.newPos, "["), "]", "");
+				if (IsNumeric(loc.last))
+				{
+					loc.newPos = ListDeleteAt(loc.newPos, ListLen(loc.newPos, "["), "[");
+					loc.newPos = ListPrepend(loc.newPos, "[" & loc.last, "]");
 				}
 				else
 				{
-					loc.returnValue[loc.key] = loc.returnValue[loc.key];
-				}
-			}
-		}
-	</cfscript>
-	<cfreturn loc.returnValue>
+					loc.newPos = ListPrepend(loc.newPos, "[1", "]");
+				}
+				loc.map[loc.item].newPos = ListToArray(Replace(loc.newPos, "]", "", "all"), "[", false);
+				
+				// loop through the position array and build our new struct
+				loc.struct = loc.value;
+				loc.jEnd = ArrayLen(loc.map[loc.item].newPos);
+				for (loc.j = 1; loc.j lte loc.jEnd; loc.j++)
+				{
+					if (!StructKeyExists(loc.struct, loc.map[loc.item].newPos[loc.j]))
+						loc.struct[loc.map[loc.item].newPos[loc.j]] = {};
+					if (loc.j != loc.jEnd)
+						loc.struct = loc.struct[loc.map[loc.item].newPos[loc.j]];
+					else
+						loc.struct[loc.map[loc.item].newPos[loc.j]] = loc.map[loc.item].value;
+				}
+			}
+		}
+	</cfscript>
 </cffunction>
 
 <cffunction name="$findMatchingRoute" returntype="struct" access="public" output="false">

			{
				if (loc.key != "controller" && loc.key != "action")
				{
					try
					{
						loc.returnValue[loc.key] = deobfuscateParam(loc.returnValue[loc.key]);
					}
					catch(Any e) {}
				}
			}
		}

		if (StructCount(loc.returnValue))
		{
			// loop through form variables, merge any date variables into one, fix checkbox submissions

		// run verifications and before filters if they exist on the controller
		$runVerifications(controller=loc.controller, actionName=loc.params.action, params=loc.params);
		$runFilters(controller=loc.controller, type="before", actionName=loc.params.action);
		
		// check to see if the controller params has changed and if so, instantiate the new controller and re-run filters and verifications
		if (loc.params.controller != loc.controller.controllerName()) {
			loc.controller = $controller(loc.params.controller).$createControllerObject(loc.params);
			$runVerifications(controller=loc.controller, actionName=loc.params.action, params=loc.params);
			$runFilters(controller=loc.controller, type="before", actionName=loc.params.action);
		}
		
		if (application.wheels.showDebugInformation)
			$debugPoint("beforeFilters,action");
