Sorcerer's IsleCode QueryParam Scanner / files

     1<!---
     2Copyright 2006-2007 TeraTech, Inc. http://teratech.com/
     3
     4Licensed under the Apache License, Version 2.0 (the "License");
     5you may not use this file except in compliance with the License.
     6You may obtain a copy of the License at
     7
     8http://www.apache.org/licenses/LICENSE-2.0
     9
    10Unless required by applicable law or agreed to in writing, software
    11distributed under the License is distributed on an "AS IS" BASIS,
    12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13See the License for the specific language governing permissions and
    14limitations under the License.
    15--->
    16<cfcomponent output="false" hint="I am the Fusebox application object, formerly the application.fusebox data structure.">
    17
    18	<cfscript>
    19	// initialize the fusebox (available to be read by developers but not to be written to)
    20	this.isFullyLoaded = false;
    21	this.circuits = structNew();
    22	this.classes = structNew();
    23	this.lexicons = structNew();
    24	this.plugins = structNew();
    25	this.pluginphases = structNew();
    26	this.nonFatalExceptionPrefix = "INFORMATION (can be ignored): ";
    27
    28	// this always has to be overridden:
    29	this.defaultFuseaction = "";
    30
    31	this.precedenceFormOrURL = "form";
    32	this.fuseactionVariable = "fuseaction";
    33
    34	// these are all ignored:
    35	this.parseWithComments = false;
    36	this.ignoreBadGrammar = true;
    37	this.allowLexicon = true;
    38	this.useAssertions = true;
    39	
    40	// FB55: this is implemented now:
    41	this.conditionalParse = false;
    42	
    43	this.password = "";
    44	this.mode = "production";
    45	this.scriptLanguage = "cfmx";
    46	this.scriptFileDelimiter = "cfm";
    47	this.maskedFileDelimiters = "htm,cfm,cfml,php,php4,asp,aspx";
    48	this.characterEncoding = "utf-8";
    49	// this is ignored:
    50	this.parseWithIndentation = this.parseWithComments;
    51	this.strictMode = false;
    52	this.allowImplicitFusebox = false;
    53	this.allowImplicitCircuits = false;
    54	this.debug = false;
    55	</cfscript>
    56	
    57	<cffunction name="init" returntype="fuseboxApplication" access="public" output="false" 
    58				hint="I am the constructor.">
    59		<cfargument name="appKey" type="string" required="true" 
    60					hint="I am FUSEBOX_APPLICATION_KEY." />
    61		<cfargument name="appPath" type="string" required="true" 
    62					hint="I am FUSEBOX_APPLICATION_PATH." />
    63		<cfargument name="myFusebox" type="myFusebox" required="true" 
    64					hint="I am the myFusebox data structure." />
    65		<cfargument name="callerPath" type="string" required="true" 
    66					hint="I am FUSEBOX_CALLER_PATH." />
    67		<cfargument name="appParameters" type="struct" required="true" 
    68					hint="I am FUSEBOX_PARAMETERS." />
    69		
    70		<cfset var myVersion = "5.5.1" />
    71		<!--- <cfset var myVersion = "5.5.0.#REReplace('$LastChangedRevision:683 $','[^0-9]','','all')#" /> --->
    72
    73		<cfset variables.factory = createObject("component","fuseboxFactory").init() />
    74		<cfset variables.fuseboxLexicon = variables.factory.getBuiltinLexicon() />
    75		<cfset variables.customAttributes = structNew() />
    76		
    77		<cfset variables.fuseboxFileExtension = "" />
    78
    79		<cfset variables.fuseboxVersion = myVersion />
    80		
    81		<cfset variables.appKey = arguments.appKey />
    82		<cfset this.webrootdirectory = replace(getDirectoryFromPath(getBaseTemplatePath()),"\","/","all") />
    83		<cfset variables.coreRoot = replace(getDirectoryFromPath(getCurrentTemplatePath()),"\","/","all") />
    84
    85		<cfset this.approotdirectory = getCanonicalPath(normalizePartialPath(arguments.callerPath) & normalizePartialPath(arguments.appPath)) />
    86
    87		<!--- this works on all platforms: --->
    88		<cfset this.osdelimiter = "/" />
    89
    90		<cfset this.coreToAppRootPath = relativePath(variables.coreRoot,this.approotdirectory) />
    91		<cfset this.appRootPathToCore = relativePath(this.approotdirectory,variables.coreRoot) />
    92		<cfset this.coreToWebRootPath = relativePath(variables.coreRoot,this.webrootdirectory) />
    93		<cfset this.WebRootPathToCore = relativePath(this.webrootdirectory,variables.coreRoot) />
    94		
    95		<cfset this.parsePath = "parsed/" />
    96		<cfset this.parseRootPath = "../" />
    97		<cfset this.pluginsPath = "plugins/" />
    98		<cfset this.lexiconPath = "lexicon/" />
    99		<cfset this.errortemplatesPath = "errortemplates/" />
   100		
   101		<!--- new in Fusebox 5.1: --->
   102		<cfset this.self = CGI.SCRIPT_NAME />
   103		<cfset this.queryStringStart = "?" />
   104		<cfset this.queryStringSeparator = "&" />
   105		<cfset this.queryStringEqual = "=" />
   106		
   107		<cfset this.circuits = structNew() />
   108		<cfset reload(arguments.appKey,arguments.appPath,arguments.myFusebox,arguments.appParameters) />
   109
   110		<cfif this.strictMode>
   111			<!--- rootdirectory was deprecated in Fusebox 5 so we no longer set it it strict mode: --->
   112			<cfset structDelete(this,"rootdirectory") />
   113		<cfelse>
   114			<!--- for FB4.0 compatibility: --->
   115			<cfset this.rootdirectory = this.approotdirectory />
   116		</cfif>
   117		
   118		<cfreturn this />
   119
   120	</cffunction>
   121
   122	<cffunction name="reload" returntype="void" access="public" output="false" 
   123				hint="I (re)load the fusebox.xml file into memory and (re)load all of the application components referenced by that.">
   124		<cfargument name="appKey" type="string" required="true" 
   125					hint="I am FUSEBOX_APPLICATION_KEY." />
   126		<cfargument name="appPath" type="string" required="true" 
   127					hint="I am FUSEBOX_APPLICATION_PATH." />
   128		<cfargument name="myFusebox" type="myFusebox" required="true" 
   129					hint="I am the myFusebox data structure." />
   130		<cfargument name="appParameters" type="struct" required="true" 
   131					hint="I am FUSEBOX_PARAMETERS." />
   132		
   133		<cfset var fbFile = "fusebox.xml.cfm" />
   134		<cfset var fbFileAlt = "fusebox.xml" />
   135		<cfset var fbFileExists = false />
   136		<cfset var fbXML = "" />
   137		<cfset var fbCode = "" />
   138		<cfset var encodings = 0 />
   139		<cfset var needToLoad = true />
   140		<cfset var fuseboxFiles = 0 />
   141		<cfset var p = "" />
   142			
   143		<!--- FB55: cache of parsed file signatures --->
   144		<cfset variables.parsedFileCache = structNew() />
   145		
   146		<!--- FB55: can override fusebox.xml parameters programmatically --->
   147		<!--- this sets up the defaults for the reload - prior to actually reading parameters --->
   148		<cfloop collection="#arguments.appParameters#" item="p">
   149			<cfset this[p] = arguments.appParameters[p] />
   150		</cfloop>
   151		<cfif structKeyExists(this,"allowImplicitFusebox") and this.allowImplicitFusebox>
   152			<cfset this.allowImplicitCircuits = true />
   153		</cfif>
   154
   155		<!---
   156			since we need to check the file, regardless of whether we load it,
   157			we might as well do the test up front and perform the strict check
   158			that just one version exists (ticket 135)
   159		--->
   160		<cfset fbFileExists = fileExists(this.approotdirectory & fbFile) />
   161		<cfif fbFileExists>
   162			<cfif this.strictMode and fileExists(this.approotdirectory & fbFileAlt)>
   163				<cfthrow type="fusebox.multipleFuseboxXML" 
   164						message="Both 'fusebox.xml' and 'fusebox.xml.cfm' exist" 
   165						detail="'fusebox.xml.cfm' will be used but 'fusebox.xml' also exists in '#this.approotdirectory#." />
   166			</cfif>
   167		<cfelse>
   168			<cfset fbFile = fbFileAlt />
   169			<cfset fbFileExists = fileExists(this.approotdirectory & fbFile) />
   170		</cfif>
   171
   172		<cfif structKeyExists(this,"timestamp")>
   173			<cfif fbFileExists>
   174				<!--- we only check the time stamp if the file exists --->
   175				<cfset needToLoad = fileModificationDate(this.approotdirectory & fbFile) gt parseDateTime(this.timestamp) />
   176			<cfelse>
   177				<!---
   178					if we loaded the application and there is no fusebox.xml file,
   179					then we must have loaded an implicit fusebox.xml file so there
   180					is no need to reload it again because an implicit file can't change!
   181				--->
   182				<cfset needToLoad = false />
   183			</cfif>
   184		</cfif>
   185
   186		<cfif needToLoad>
   187
   188			<cfif this.debug>
   189				<cfset arguments.myFusebox.trace("Compiler","Loading fusebox.xml file") />
   190			</cfif>
   191
   192			<!--- attempt to load fusebox.xml(.cfm): --->
   193			<cfif fbFileExists>
   194				<cftry>
   195					
   196					<cffile action="read" file="#this.approotdirectory##fbFile#"
   197							variable="fbXML"
   198							charset="#this.characterEncoding#" />
   199							
   200					<cfset variables.fuseboxFileExtension = listLast(fbFile,".") />
   201					
   202					<cfcatch type="security">
   203						<!--- cffile denied by sandbox security --->
   204						<cfthrow type="fusebox.security" 
   205								message="security error reading fusebox.xml" 
   206								detail="The file '#fbFile#' in the directory #this.approotdirectory# could not be read because sandbox security has disabled the cffile tag."
   207								extendedinfo="#cfcatch.detail#" />
   208					</cfcatch>
   209					
   210					<cfcatch type="any">
   211						<!--- the file exists but we cannot read it --->
   212						<cfthrow type="fusebox.missingFuseboxXML" 
   213								message="missing fusebox.xml" 
   214								detail="The file '#fbFile#' in the directory #this.approotdirectory# could not be read."
   215								extendedinfo="#cfcatch.detail#" />
   216					</cfcatch>
   217					
   218				</cftry>
   219
   220			<cfelse>
   221
   222				<cfif this.allowImplicitFusebox>
   223
   224					<cfif this.debug>
   225						<cfset arguments.myFusebox.trace("Compiler","Implicit fusebox.xml(.cfm) identified") />
   226					</cfif>
   227					<cfset fbXML = "<fusebox/>" />
   228					<!--- if the fusebox.xml file is missing there are no circuit declarations: --->
   229					<cfset this.allowImplicitCircuits = true />
   230
   231				<cfelse>
   232
   233					<cfthrow type="fusebox.missingFuseboxXML" 
   234							message="missing fusebox.xml" 
   235							detail="The file '#fbFile#' could not be found in the directory #this.approotdirectory#." />
   236
   237				</cfif>
   238
   239			</cfif>
   240			
   241			<cftry>
   242				
   243				<cfset fbCode = xmlParse(fbXML) />
   244				
   245				<!--- see if we need to re-read based on the encoding being different to our default --->
   246				<cfset encodings = xmlSearch(fbCode,"/fusebox/parameters/parameter[@name='characterEncoding']") />
   247				<cfif arrayLen(encodings) eq 1 and structKeyExists(encodings[1].xmlAttributes,"value")>
   248					<cfif encodings[1].xmlAttributes.value is not this.characterEncoding>
   249						<cfset this.characterEncoding = encodings[1].xmlAttributes.value />
   250						<!--- now re-read the file in case anything is changed in that new encoding --->
   251						<cffile action="read" file="#this.approotdirectory##fbFile#"
   252								variable="fbXML"
   253								charset="#this.characterEncoding#" />
   254						<cfset fbCode = xmlParse(fbXML) />
   255					</cfif>
   256				</cfif>
   257				
   258				<cfcatch type="any">
   259					<cfthrow type="fusebox.fuseboxXMLError" 
   260							message="Error reading fusebox.xml" 
   261							detail="A problem was encountered while reading the #fbFile# file. This is usually caused by unmatched XML tags (a &lt;tag&gt; without a &lt;/tag&gt; or without use of the &lt;tag/&gt; short-cut.)"
   262							extendedinfo="#cfcatch.detail#" />
   263				</cfcatch>
   264				
   265			</cftry>
   266			
   267			<cfif fbCode.xmlRoot.xmlName is not "fusebox">
   268				<cfthrow type="fusebox.badGrammar.badFuseboxFile"
   269						detail="Fusebox file does contain 'fusebox' XML" 
   270						message="Fusebox file #fbFile# does not contain 'fusebox' as the root XML node." />
   271			</cfif>
   272
   273			<cfset loadParameters(fbCode) />
   274
   275			<!--- FB55: can override fusebox.xml parameters programmatically --->
   276			<cfloop collection="#arguments.appParameters#" item="p">
   277				<cfset this[p] = arguments.appParameters[p] />
   278			</cfloop>
   279			<cfif structKeyExists(this,"allowImplicitFusebox") and this.allowImplicitFusebox>
   280				<cfset this.allowImplicitCircuits = true />
   281			</cfif>
   282
   283			<!---
   284				if the user overrides certain path variables, we need to normalize them:
   285				- this.parsePath (reset parseRootPath)
   286				- this.pluginsPath
   287				- this.lexiconPath
   288				- this.errortemplatesPath
   289				normalizing means changing all \ to / and appending / if not present
   290			--->
   291			<cfset this.parsePath = normalizePartialPath(this.parsePath) />
   292			<cfset this.parseRootPath = relativePath(expandFuseboxPath(this.parsePath),getApplicationRoot()) />
   293			<cfset this.pluginsPath = normalizePartialPath(this.pluginsPath) />
   294			<cfset this.lexiconPath = normalizePartialPath(this.lexiconPath) />
   295			<cfset this.errortemplatesPath = normalizePartialPath(this.errortemplatesPath) />
   296			
   297			<!--- Fusebox 5.1: default this.myself: --->
   298			<cfif not structKeyExists(this,"myself")>
   299				<cfset this.myself = getDefaultMyself(this.self) />
   300			</cfif>
   301			
   302			<cfset loadLexicons(fbCode) />
   303			<cfset loadClasses(fbCode) />
   304			<cfset loadPlugins(fbCode) />
   305			<cfset loadGlobalPreAndPostProcess(fbCode) />
   306			<!--- save fusebox.xml DOM internally for (re-)loading circuits --->
   307			<cfset variables.fbCode = fbCode />
   308			<cfset variables.fbFile = fbFile />
   309			<cfset this.timestamp = now() />
   310		</cfif>
   311		
   312		<!--- to track circuit loads on this request --->
   313		<cfparam name="request.__fusebox.CircuitsLoaded" default="#structNew()#" />		
   314		<cfset loadCircuits(variables.fbCode,arguments.myFusebox) />
   315		
   316		<!--- FB5: fusebox.loadclean will delete all the parsed files --->
   317		<cfif arguments.myFusebox.parameters.clean>
   318			<cfset deleteParsedFiles() />
   319		</cfif>
   320		
   321		<!--- application data available to developers via getApplicationData() method: --->
   322		<cfset variables.data = structNew() />
   323		
   324		<cfset this.isFullyLoaded = true />
   325		<cfset this.applicationStarted = false />
   326		<cfset this.dateLastLoaded = now() />
   327		
   328		<!---
   329			The following documented parts of application.fusebox are not supported in Fusebox 5:
   330			- application.fusebox.xml
   331			- application.fusebox.globalfuseactions.*
   332			- application.fusebox.circuits.*.xml
   333			- application.fusebox.circuits.preFuseaction.*
   334			- application.fusebox.circuits.postFuseaction.*
   335			- application.fusebox.circuits.*.fuseactions.*.xml
   336		--->
   337		
   338	</cffunction>
   339	
   340	<cffunction name="getPluginsPath" returntype="string" access="public" output="false" 
   341				hint="I am a convenience method to return the location of the plugins.">
   342	
   343		<cfreturn this.pluginsPath />
   344	
   345	</cffunction>
   346	
   347	<!--- FB55: exposes this directly in myFusebox for convenience --->
   348	<cffunction name="getApplicationData" returntype="struct" access="public" output="false" 
   349				hint="I return a reference to the application data cache. This is a new concept in Fusebox 5.">
   350	
   351		<cfreturn variables.data />
   352	
   353	</cffunction>
   354	
   355	<cffunction name="getApplicationRoot" returntype="any" access="public" output="false" 
   356				hint="I am a convenience method to return the full application root directory path.">
   357	
   358		<cfreturn this.approotdirectory />
   359	
   360	</cffunction>
   361	
   362	<cffunction name="expandFuseboxPath" returntype="any" access="public" output="false" 
   363				hint="I expand a path in the context of a Fusebox application.">
   364		<cfargument name="partialPath" type="any" required="true" 
   365					hint="I am the partial path to expand. If I do not begin with a /, prepend the Fusebox application root." />
   366
   367		<cfif left(arguments.partialPath,1) is "/">
   368			<!--- absolute path, i.e., root-relative or mapped --->
   369			<cfreturn replace(expandPath(arguments.partialPath),"\","/","all") />
   370		<cfelse>
   371			<!--- relative, i.e., relative to the Fusebox application root --->
   372			<cfreturn getApplicationRoot() & arguments.partialPath />
   373		</cfif>
   374		
   375	</cffunction>
   376	
   377	<cffunction name="getFuseboxXMLFilename" returntype="string" access="public" output="false" 
   378				hint="I return the actual name of the fusebox.xml(.cfm) file.">
   379	
   380		<cfreturn variables.fbFile />
   381	
   382	</cffunction>
   383	
   384	<cffunction name="getCoreToAppRootPath" returntype="any" access="public" output="false" 
   385				hint="I am a convenience method to return the relative path from the core files to the application root.">
   386	
   387		<cfreturn this.coreToAppRootPath />
   388	
   389	</cffunction>
   390	
   391	<cffunction name="compileAll" returntype="void" access="public" output="false" 
   392				hint="I compile all the public fuseactions in the application.">
   393		<cfargument name="myFusebox" type="myFusebox" required="true" 
   394					hint="I am the myFusebox data structure." />
   395
   396		<cfset var c = 0 />
   397		<cfset var a = 0 />
   398		<cfset var f = 0 />
   399	
   400		<cfloop collection="#this.circuits#" item="c">
   401			<cfset a = this.circuits[c].getFuseactions() />
   402			<cfloop collection="#a#" item="f">
   403				<cfif a[f].access is "public">
   404					<cfset compileRequest(c & "." & f,arguments.myFusebox) />
   405				</cfif>
   406			</cfloop>
   407		</cfloop>
   408
   409	</cffunction>
   410	
   411	<cffunction name="compileRequest" returntype="struct" access="public" output="false" 
   412				hint="I compile a specific (public) fuseaction as an external request.">
   413		<cfargument name="circuitFuseaction" type="string" required="true" 
   414					hint="I am the full name of the requested fuseaction (circuit.fuseaction)." />
   415		<cfargument name="myFusebox" type="myFusebox" required="true" 
   416					hint="I am the myFusebox data structure." />
   417
   418		<cfset var myVersion = getVersion() />
   419		<cfset var circuit = "" />
   420		<cfset var fuseaction = listLast(arguments.circuitFuseaction,".") />
   421		<cfset var i = 0 />
   422		<cfset var n = 0 />
   423		<cfset var needRethrow = true />
   424		<cfset var needTryOnFuseaction = false />
   425		<cfset var parsedName = "#lCase(arguments.circuitFuseaction)#.cfm" />
   426		<cfset var parsedFile = "#this.parsePath##parsedName#" />
   427		<cfset var fullParsedFile = "#this.expandFuseboxPath(this.parsePath)##parsedName#" />
   428		<cfset var result = structNew() />
   429		<cfset var writer = 0 />
   430		
   431		<!--- to track reloads on this request --->
   432		<cfparam name="request.__fusebox.CircuitsLoaded" default="#structNew()#" />
   433		<cfparam name="request.__fusebox.fuseactionsDone" default="#structNew()#" />
   434		
   435		<!--- note that in Fusebox 5, these are really all the same set of files --->
   436		<cfset arguments.myFusebox.version.loader = myVersion />
   437		<cfset arguments.myFusebox.version.parser = myVersion />
   438		<cfset arguments.myFusebox.version.transformer = myVersion />
   439		<!--- legacy test from FB41 although it's a bit pointless --->
   440		<cfif myFusebox.version.runtime neq myFusebox.version.loader>
   441			<cfthrow type="fusebox.versionMismatchException"
   442					message="The loader is not the same version as the runtime" />
   443		</cfif>
   444		
   445		<!--- validate format of the fuseaction: --->
   446		<cfif listLen(arguments.circuitFuseaction,".") lt 2>
   447			<cfthrow type="fusebox.malformedFuseaction" 
   448					message="malformed Fuseaction" 
   449					detail="You specified a malformed Fuseaction of #arguments.circuitFuseaction#. A fully qualified Fuseaction must be in the form [Circuit].[Fuseaction]." />	
   450		</cfif>
   451		
   452		<cfset circuit = left(arguments.circuitFuseaction,len(arguments.circuitFuseaction)-len(fuseaction)-1) />
   453
   454		<!--- set up myFusebox values for this request: --->
   455		<cfset arguments.myFusebox.originalCircuit = circuit />
   456		<cfset arguments.myFusebox.originalFuseaction = fuseaction />
   457		<cfloop collection="#this.plugins#" item="i">
   458			<cfset arguments.myFusebox.plugins[i] = structNew() />
   459		</cfloop>
   460
   461		<!--- ticket 293 - prevent dynamic do() from executing until prerequisites complete --->
   462		<cfset request.__fusebox.dynamicDoOK = true />
   463		
   464		<!--- check access on request - if the circuit/fuseaction doesn't exist we trap it later --->
   465		<cfif structKeyExists(this.circuits,circuit) and 
   466				structKeyExists(this.circuits[circuit].fuseactions,fuseaction) and
   467				this.circuits[circuit].fuseactions[fuseaction].getAccess() is not "public">
   468			<cfthrow type="fusebox.invalidAccessModifier" 
   469					message="Invalid Access Modifier" 
   470					detail="You tried to access #circuit#.#fuseaction# which does not have access modifier of public. A Fuseaction which is to be accessed from anywhere outside the application (such as called via an URL, or a FORM, or as a web service) must have an access modifier of public or if unspecified at least inherit such a modifier from its circuit.">
   471		</cfif>
   472
   473		<cfif not fileExists(fullParsedFile) or arguments.myFusebox.parameters.parse>
   474			<cflock name="#fullParsedFile#" type="exclusive" timeout="300">
   475				<cfif not fileExists(fullParsedFile) or arguments.myFusebox.parameters.parse>
   476					<cfset request.__fusebox.SuppressPlugins = false />
   477					<cfset writer = createObject("component","fuseboxWriter").init(this,arguments.myFusebox) />
   478					<cfset writer.open(parsedName) />
   479					<cfset writer.rawPrintln("<!--- circuit: #circuit# --->") />
   480					<cfset writer.rawPrintln("<!--- fuseaction: #fuseaction# --->") />
   481					<cfset writer.rawPrintln("<cftry>") />
   482					<cfset writer.setCircuit(circuit) />
   483					<cfset writer.setFuseaction(fuseaction) />
   484					<cfif variables.hasProcess["appinit"]>
   485						<cfset writer.setPhase("appinit") />
   486						<cfset writer.println("<cfif myFusebox.applicationStart or") />
   487						<cfset writer.println('		not myFusebox.getApplication().applicationStarted>') />
   488						<cfset writer.println('	<cflock name="##application.ApplicationName##_fusebox_##FUSEBOX_APPLICATION_KEY##_appinit" type="exclusive" timeout="30">') />
   489						<cfset writer.println('		<cfif not myFusebox.getApplication().applicationStarted>') />
   490						<cfset request.__fusebox.SuppressPlugins = true />
   491						<cfset variables.process["appinit"].compile(writer) />
   492						<cfset writer.println('			<cfset myFusebox.getApplication().applicationStarted = true />') />
   493						<cfset writer.println('		</cfif>') />
   494						<cfset writer.println('	</cflock>') />
   495						<cfset writer.println('</cfif>') />
   496					</cfif>
   497					<cfset request.__fusebox.SuppressPlugins = false />
   498					<cfif structKeyExists(this.pluginPhases,"preProcess")>
   499						<cfset n = arrayLen(this.pluginPhases["preProcess"]) />
   500						<cfloop from="1" to="#n#" index="i">
   501							<cfset this.pluginPhases["preProcess"][i].compile(writer) />
   502						</cfloop>
   503					</cfif>
   504					<cfset writer.setPhase("preprocessFuseactions") />
   505					<cfif variables.hasProcess["preprocess"]>
   506						<cfset variables.process["preprocess"].compile(writer) />
   507					</cfif>
   508					<cfif structKeyExists(this.pluginPhases,"fuseactionException") and
   509							arrayLen(this.pluginPhases["fuseactionException"]) gt 0 and
   510							not request.__fusebox.SuppressPlugins>
   511						<cfset needTryOnFuseaction = true />
   512						<cfset writer.rawPrintln("<cftry>") />
   513					</cfif>
   514					<cfif structKeyExists(this.pluginPhases,"preFuseaction")>
   515						<cfset n = arrayLen(this.pluginPhases["preFuseaction"]) />
   516						<cfloop from="1" to="#n#" index="i">
   517							<cfset this.pluginPhases["preFuseaction"][i].compile(writer) />
   518						</cfloop>
   519					</cfif>
   520					<cfset writer.setPhase("requestedFuseaction") />
   521					<cfset compile(writer,circuit,fuseaction,true) />
   522					<cfif structKeyExists(this.pluginPhases,"postFuseaction")>
   523						<cfset n = arrayLen(this.pluginPhases["postFuseaction"]) />
   524						<cfloop from="1" to="#n#" index="i">
   525							<cfset this.pluginPhases["postFuseaction"][i].compile(writer) />
   526						</cfloop>
   527					</cfif>
   528					<cfif needTryOnFuseaction>
   529						<cfset n = arrayLen(this.pluginPhases["fuseactionException"]) />
   530						<cfloop from="1" to="#n#" index="i">
   531							<cfset this.pluginPhases["fuseactionException"][i].compile(writer) />
   532						</cfloop>
   533						<cfset writer.rawPrintln("</cftry>") />
   534					</cfif>
   535					<cfset writer.setPhase("postprocessFuseactions") />
   536					<cfif variables.hasProcess["postprocess"]>
   537						<cfset variables.process["postprocess"].compile(writer) />
   538					</cfif>
   539					<cfif structKeyExists(this.pluginPhases,"postProcess")>
   540						<cfset n = arrayLen(this.pluginPhases["postProcess"]) />
   541						<cfloop from="1" to="#n#" index="i">
   542							<cfset this.pluginPhases["postProcess"][i].compile(writer) />
   543						</cfloop>
   544					</cfif>
   545					<cfif structKeyExists(this.pluginPhases,"processError") and
   546							not request.__fusebox.SuppressPlugins>
   547						<cfset n = arrayLen(this.pluginPhases["processError"]) />
   548						<cfloop from="1" to="#n#" index="i">
   549							<cfset needRethrow = false />
   550							<cfset this.pluginPhases["processError"][i].compile(writer) />
   551						</cfloop>
   552					</cfif>
   553					<cfif needRethrow>
   554						<cfset writer.rawPrintln('<' & 'cfcatch><' & 'cfrethrow><' & '/cfcatch>') />
   555					</cfif>
   556					<cfset writer.rawPrintln("</cftry>") />
   557					<cfset writer.close(variables.parsedFileCache) />
   558				</cfif>
   559			</cflock>
   560		</cfif>
   561		
   562		<cfset result.parsedName = parsedName />
   563		<cfif left(parsedFile,1) is "/">
   564			<cfset result.parsedFile = parsedFile />
   565		<cfelse>
   566			<cfset result.parsedFile = this.getCoreToAppRootPath() & parsedFile />
   567		</cfif>
   568		<cfset result.lockName = fullParsedFile />
   569		
   570		<cfreturn result />
   571		
   572	</cffunction>
   573	
   574	<cffunction name="do" returntype="string" access="public" output="true" 
   575				hint="I compile and execute a specific fuseaction.">
   576		<cfargument name="circuitFuseaction" type="string" required="true" 
   577					hint="I am the full name of the requested fuseaction (circuit.fuseaction)." />
   578		<cfargument name="myFusebox" type="myFusebox" required="true" 
   579					hint="I am the myFusebox data structure." />
   580		<cfargument name="returnOutput" type="boolean" required="true"
   581					hint="I indicate whether to display output (false) or return the output (true)." />
   582
   583		<cfset var parsedFileInfo = 0 />
   584		<cfset var output = "" />
   585		<cfset var circuit = "" />
   586		<cfset var fuseaction = "" />
   587
   588		<!--- ticket 293 - prevent dynamic do() from executing until prerequisites complete --->
   589		<cfif not structKeyExists(request,"__fusebox") or 
   590				not structKeyExists(request.__fusebox,"dynamicDoOK") or 
   591					not request.__fusebox.dynamicDoOK>
   592			<cfif structKeyExists(arguments.myFusebox,"originalCircuit") and 
   593					structKeyExists(arguments.myFusebox,"originalFuseaction")>
   594				<cfset output = output & " while executing " & arguments.myFusebox.originalCircuit & 
   595						"." & arguments.myFusebox.originalFuseaction />
   596			</cfif>
   597			<cfthrow type="fusebox.dynamicDoNotAllowed" message="dynamic 'do' not allowed" 
   598					detail="This request did not reach the state where dynamic 'do' is possible#output#." />
   599		</cfif>
   600		
   601		<!--- allow for abbreviated circuitFuseaction form: --->
   602		<cfif listLen(arguments.circuitFuseaction,".") lt 2>
   603			<cfset arguments.circuitFuseaction = arguments.myFusebox.thisCircuit & "." & arguments.circuitFuseaction />
   604		<cfelse>
   605			<cfset circuit = listFirst(arguments.circuitFuseaction,".") />
   606			<cfif circuit is not arguments.myFusebox.thisCircuit>
   607				<!--- different circuit, check access is not private (implicit fuseactions cannot be private) --->			
   608				<cfset fuseaction = listRest(arguments.circuitFuseaction,".") />
   609				<cfif structKeyExists(this.circuits,circuit) and 
   610						structKeyExists(this.circuits[circuit].fuseactions,fuseaction) and
   611						this.circuits[circuit].fuseactions[fuseaction].getAccess() is "private">
   612					<cfthrow type="fusebox.invalidAccessModifier" 
   613							message="invalid access modifier" 
   614							detail="The fuseaction '#circuit#.#fuseaction#' has an access modifier of private and can only be called from within its own circuit. Use an access modifier of internal or public to make it available outside its immediate circuit." />
   615				</cfif>
   616			</cfif>
   617		</cfif>
   618		
   619		<cfset parsedFileInfo = compileDynamicDo(arguments.circuitFuseaction,arguments.myFusebox) />
   620		
   621		<cfif this.debug>
   622			<cfset arguments.myFusebox.trace("Runtime","&lt;do action=""#arguments.circuitFuseaction#""/&gt; -- dynamic") />
   623		</cfif>
   624		<cfinvoke component="fuseboxExecutionContext" method="__executeDynamicDo" returnvariable="output"
   625					parsedFileInfo="#parsedFileInfo#" myFusebox="#arguments.myFusebox#" returnOutput="#arguments.returnOutput#" />
   626		
   627		<cfreturn output />
   628		
   629	</cffunction>
   630
   631	<cffunction name="compileDynamicDo" returntype="struct" access="private" output="false" 
   632				hint="I compile a specific fuseaction as a dynamic request.">
   633		<cfargument name="circuitFuseaction" type="string" required="true" 
   634					hint="I am the full name of the requested fuseaction (circuit.fuseaction)." />
   635		<cfargument name="myFusebox" type="myFusebox" required="true" 
   636					hint="I am the myFusebox data structure." />
   637
   638		<cfset var circuit = "" />
   639		<cfset var fuseaction = listLast(arguments.circuitFuseaction,".") />
   640		<cfset var i = 0 />
   641		<cfset var n = 0 />
   642		<cfset var needTryOnFuseaction = false />
   643		<cfset var parsedName = "do.#lCase(arguments.circuitFuseaction)#.cfm" />
   644		<cfset var parsedFile = "#this.parsePath##parsedName#" />
   645		<cfset var fullParsedFile = "#this.expandFuseboxPath(this.parsePath)##parsedName#" />
   646		<cfset var result = structNew() />
   647		<cfset var writer = 0 />
   648		
   649		<!--- validate format of the fuseaction: --->
   650		<cfif listLen(arguments.circuitFuseaction,".") lt 2>
   651			<cfthrow type="fusebox.malformedFuseaction" 
   652					message="malformed Fuseaction" 
   653					detail="You specified a malformed Fuseaction of #arguments.circuitFuseaction#. A fully qualified Fuseaction must be in the form [Circuit].[Fuseaction]." />	
   654		</cfif>
   655		
   656		<cfset circuit = left(arguments.circuitFuseaction,len(arguments.circuitFuseaction)-len(fuseaction)-1) />
   657
   658		<cfif not fileExists(fullParsedFile) or arguments.myFusebox.parameters.parse>
   659			<cflock name="#fullParsedFile#" type="exclusive" timeout="300">
   660				<cfif not fileExists(fullParsedFile) or arguments.myFusebox.parameters.parse>
   661					<cfset writer = createObject("component","fuseboxWriter").init(this,arguments.myFusebox) />
   662					<cfset writer.open(parsedName) />
   663					<cfset writer.rawPrintln("<!--- circuit: #circuit# --->") />
   664					<cfset writer.rawPrintln("<!--- fuseaction: #fuseaction# --->") />
   665					<cfset writer.setCircuit(circuit) />
   666					<cfset writer.setFuseaction(fuseaction) />
   667					<cfif structKeyExists(this.pluginPhases,"fuseactionException") and
   668							arrayLen(this.pluginPhases["fuseactionException"]) gt 0 and
   669							not request.__fusebox.SuppressPlugins>
   670						<cfset needTryOnFuseaction = true />
   671						<cfset writer.rawPrintln("<cftry>") />
   672					</cfif>
   673					<cfif structKeyExists(this.pluginPhases,"preFuseaction")>
   674						<cfset n = arrayLen(this.pluginPhases["preFuseaction"]) />
   675						<cfloop from="1" to="#n#" index="i">
   676							<cfset this.pluginPhases["preFuseaction"][i].compile(writer) />
   677						</cfloop>
   678					</cfif>
   679					<cfset writer.setPhase("requestedFuseaction") />
   680					<cfset compile(writer,circuit,fuseaction) />
   681					<cfif structKeyExists(this.pluginPhases,"postFuseaction")>
   682						<cfset n = arrayLen(this.pluginPhases["postFuseaction"]) />
   683						<cfloop from="1" to="#n#" index="i">
   684							<cfset this.pluginPhases["postFuseaction"][i].compile(writer) />
   685						</cfloop>
   686					</cfif>
   687					<cfif needTryOnFuseaction>
   688						<cfset n = arrayLen(this.pluginPhases["fuseactionException"]) />
   689						<cfloop from="1" to="#n#" index="i">
   690							<cfset this.pluginPhases["fuseactionException"][i].compile(writer) />
   691						</cfloop>
   692						<cfset writer.rawPrintln("</cftry>") />
   693					</cfif>
   694					<cfset writer.close(variables.parsedFileCache) />
   695				</cfif>
   696			</cflock>
   697		</cfif>
   698		
   699		<cfset result.parsedName = parsedName />
   700		<cfif left(parsedFile,1) is "/">
   701			<cfset result.parsedFile = parsedFile />
   702		<cfelse>
   703			<cfset result.parsedFile = this.getCoreToAppRootPath() & parsedFile />
   704		</cfif>
   705		<cfset result.lockName = fullParsedFile />
   706		
   707		<cfreturn result />
   708		
   709	</cffunction>
   710	
   711	<cffunction name="compile" returntype="void" access="public" output="false" 
   712				hint="I compile a specific fuseaction during a request (such as for a 'do' verb).">
   713		<cfargument name="writer" type="any" required="false" 
   714					hint="I am the parsed file writer object. I am required but it's faster to specify that I am not required." />
   715		<cfargument name="circuit" type="any" required="false" 
   716					hint="I am the circuit name. I am required but it's faster to specify that I am not required." />
   717		<cfargument name="fuseaction" type="any" required="false" 
   718					hint="I am the fuseaction name, within the specified circuit." />
   719		<cfargument name="topLevel" type="boolean" default="false" 
   720					hint="I specify whether or not this is a top-level (public) request." />
   721	
   722		<cfset var c = "" />
   723
   724		<cfif not structKeyExists(this.circuits,arguments.circuit)>
   725			<cfif this.allowImplicitCircuits>
   726				<!--- FB55: attempt to create an implicit circuit --->
   727				<cfset this.circuits[arguments.circuit] = 
   728						createObject("component","fuseboxImplicitCircuit")
   729							.init(this,arguments.circuit,arguments.writer.getMyFusebox()) />
   730				<!--- still need to check access here! --->
   731				<cfif arguments.writer.getMyFusebox().thisCircuit is not arguments.circuit and
   732						structKeyExists(this.circuits[circuit].fuseactions,arguments.fuseaction) and
   733						this.circuits[circuit].fuseactions[fuseaction].getAccess() is "private">
   734					<cfthrow type="fusebox.invalidAccessModifier" 
   735							message="invalid access modifier" 
   736							detail="The fuseaction '#arguments.circuit#.#arguments.fuseaction#' has an access modifier of private and can only be called from within its own circuit. Use an access modifier of internal or public to make it available outside its immediate circuit." />
   737				</cfif>
   738			<cfelse>
   739				<cfthrow type="fusebox.undefinedCircuit" 
   740						message="undefined Circuit" 
   741						detail="You specified a Circuit of #arguments.circuit# which is not defined." />
   742			</cfif>
   743		</cfif>
   744		<!--- FB5: development-circuit-load only reloads the requested circuit --->
   745		<cfif this.mode is "development-circuit-load">
   746			<!--- FB5: ensure we only reload each circuit once per request --->
   747			<cfif not structKeyExists(request.__fusebox.CircuitsLoaded,arguments.circuit)>
   748				<cfset request.__fusebox.CircuitsLoaded[arguments.circuit] = true />
   749				<cfset this.circuits[arguments.circuit].reload(arguments.writer.getMyFusebox()) />
   750			</cfif>
   751		</cfif>
   752	
   753		<cfset c = arguments.writer.setCircuit(arguments.circuit) />
   754		<cfset this.circuits[arguments.circuit]
   755				.compile(arguments.writer,arguments.fuseaction,arguments.topLevel) />
   756		<cfset arguments.writer.setCircuit(c) />
   757		
   758	</cffunction>
   759	
   760	<cffunction name="handleFuseboxException" returntype="boolean" access="public" output="true" 
   761				hint="I attempt to handle a Fusebox exception by looking for a handler file in the errortemplates/ directory. I return true if I handle the exception, else I return false.">
   762		<cfargument name="cfcatch" type="any" required="true" 
   763					hint="I am the original cfcatch structure from the exception that fusebox5.cfm caught." />
   764		<cfargument name="attributes" type="struct" required="true" 
   765					hint="I am the attributes 'scope'." />
   766		<cfargument name="myFusebox" type="any" required="true" 
   767					hint="I am the myFusebox object." />
   768		<cfargument name="appKey" type="string" required="true" 
   769					hint="I am the application key object." />
   770		
   771		<cfset var __handled = false />
   772		<cfset var __type = arguments.cfcatch.type />
   773		<cfset var __ext = "." & this.scriptFileDelimiter />
   774		<cfset var __errorFile = this.errortemplatesPath & __type & __ext />
   775		<cfset var __handlerExists = fileExists(expandFuseboxPath(__errorFile)) />
   776		<cfset var FUSEBOX_APPLICATION_KEY = arguments.appKey />
   777		
   778		<cfloop condition="not __handlerExists and len(__type) gt 0">
   779			<cfset __type = listDeleteAt(__type,listLen(__type,"."),".") />
   780			<cfset __errorFile = this.errortemplatesPath & __type & __ext />
   781			<cfset __handlerExists = fileExists(expandFuseboxPath(__errorFile)) />
   782		</cfloop>
   783		<cfif __handlerExists>
   784			<cfif left(__errorFile,1) is "/">
   785				<cfinclude template="#__errorFile#" />
   786			<cfelse>
   787				<cfinclude template="#getCoreToAppRootPath()##__errorFile#" />
   788			</cfif>
   789			<cfset __handled = true />
   790		</cfif>
   791		
   792		<cfreturn __handled />
   793		
   794	</cffunction>
   795	
   796	<cffunction name="getFuseactionFactory" returntype="any" access="public" output="false" 
   797				hint="I return the factory object that makes fuseaction objects for the framework.">
   798		
   799		<cfreturn variables.factory />
   800
   801	</cffunction>
   802	
   803	<cffunction name="getClassDefinition" returntype="struct" access="public" output="false" 
   804				hint="I return the class declaration for a given class. I throw an exception if the class has no declaration.">
   805		<cfargument name="className" type="string" required="true" 
   806					hint="I am the name of the class whose declaration should be returned." />
   807		
   808		<cfreturn this.classes[arguments.className] />
   809
   810	</cffunction>
   811	
   812	<cffunction name="getLexiconDefinition" returntype="any" access="public" output="false" 
   813				hint="I return the lexicon definition for a given namespace. I return either the internal Fusebox lexicon or a declared (Fusebox 4.1 style) lexicon.">
   814		<cfargument name="namespace" type="any" required="false" 
   815					hint="I am the namespace of the lexicon whose definition should be returned. I am required but it's faster to specify that I am not required." />
   816		
   817		<cfif arguments.namespace is variables.fuseboxLexicon.namespace>
   818			<cfreturn variables.fuseboxLexicon />
   819		<cfelse>
   820			<cfreturn variables.fb41Lexicons[arguments.namespace] />
   821		</cfif>
   822
   823	</cffunction>
   824	
   825	<cffunction name="getVersion" returntype="string" access="public" output="false" 
   826				hint="I return the version of this Fusebox 5 object. This is the preferred way to obtain the version in Fusebox 5.">
   827	
   828		<cfreturn variables.fuseboxVersion />
   829		
   830	</cffunction>
   831	
   832	<cffunction name="getAlias" returntype="any" access="public" output="false" 
   833				hint="I return the fake circuit alias for the application.">
   834	
   835		<cfreturn "$fusebox" />
   836	
   837	</cffunction>
   838	
   839	<cffunction name="getApplication" returntype="any" access="public" output="false" 
   840				hint="I return the fusebox application object.">
   841	
   842		<cfreturn this />
   843	
   844	</cffunction>
   845	
   846	<cffunction name="getCustomAttributes" returntype="struct" access="public" output="false" 
   847				hint="I return any custom attributes for the specified namespace prefix.">
   848		<cfargument name="ns" type="string" required="true" 
   849					hint="I am the namespace for which to return custom attributes." />
   850		
   851		<cfif structKeyExists(variables.customAttributes,arguments.ns)>
   852			<!--- we structCopy() this so folks can't poke values back into the metadata! --->
   853			<cfreturn structCopy(variables.customAttributes[arguments.ns]) />
   854		<cfelse>
   855			<cfreturn structNew() />
   856		</cfif>
   857		
   858	</cffunction>
   859	
   860	<cffunction name="getFuseboxFileExtension" returntype="string" access="public" output="false" 
   861				hint="I return the fusebox.xml file extension: either xml or cfm.">
   862					
   863		<cfreturn variables.fuseboxFileExtension />
   864		
   865	</cffunction>
   866	
   867	<cffunction name="deleteParsedFiles" returntype="void" access="private" output="false" 
   868				hint="I delete all the script files in the parsed/ directory.">
   869	
   870		<cfset var fileQuery = 0 />
   871		<cfset var parseDir = expandFuseboxPath(this.parsePath) />
   872		
   873		<cftry>
   874			<cfdirectory action="list" directory="#parseDir#" 
   875						filter="*.#this.scriptFileDelimiter#" name="fileQuery" />
   876			<cfloop query="fileQuery">
   877				<cffile action="delete" file="#parseDir##fileQuery.name#" />
   878			</cfloop>
   879		<cfcatch />
   880		</cftry>
   881	
   882	</cffunction>
   883	
   884	<cffunction name="loadCircuits" returntype="void" access="private" output="false" 
   885				hint="I (re)load all the circuits in an application.">
   886		<cfargument name="fbCode" type="any" required="true" 
   887					hint="I am the parsed XML representation of the fusebox.xml file." />
   888		<cfargument name="myFusebox" type="myFusebox" required="true" 
   889					hint="I am the myFusebox data structure." />
   890		
   891		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/circuits/circuit") />
   892		<cfset var i = 0 />
   893		<cfset var n = arrayLen(children) />
   894		<cfset var previousCircuits = this.circuits />
   895		<cfset var alias = "" />
   896		<cfset var parent = "" />
   897		<cfset var relative = true />
   898		<cfset var nAttrs = 0 />
   899		
   900		<cfset this.circuits = structNew() />
   901		
   902		<!--- pass 1: build the circuits --->
   903		<cfloop from="1" to="#n#" index="i">
   904			<cfif not structKeyExists(children[i].xmlAttributes,"alias")>
   905				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
   906						message="Required attribute is missing"
   907						detail="The attribute 'alias' is required, for a 'circuit' declaration in fusebox.xml." />
   908			</cfif>
   909			<cfif not structKeyExists(children[i].xmlAttributes,"path")>
   910				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
   911						message="Required attribute is missing"
   912						detail="The attribute 'path' is required, for the declaration of circuit '#children[i].xmlAttributes.alias#' in fusebox.xml." />
   913			</cfif>
   914			<cfif structKeyExists(children[i].xmlAttributes,"parent")>
   915				<cfset parent = children[i].xmlAttributes.parent />
   916				<cfset nAttrs = 3 />
   917			<cfelse>
   918				<cfset parent = "" />
   919				<cfset nAttrs = 2 />
   920			</cfif>
   921			<cfif structKeyExists(children[i].xmlAttributes,"relative")>
   922				<cfif listFind("true,false,yes,no",children[i].xmlAttributes.relative) eq 0>
   923					<cfthrow type="fusebox.badGrammar.invalidAttributeValue"
   924							message="Attribute has invalid value" 
   925							detail="The attribute 'relative' must either be ""true"" or ""false"", for the declaration of circuit '#children[i].xmlAttributes.alias#' in fusebox.xml." />
   926				</cfif>
   927				<cfset relative = children[i].xmlAttributes.relative />
   928				<cfset nAttrs = nAttrs + 1 />
   929			<cfelse>
   930				<cfset relative = true />
   931			</cfif>
   932			<cfif this.strictMode and nAttrs neq structCount(children[i].xmlAttributes)>
   933				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
   934						message="Unexpected attributes"
   935						detail="Attributes other than 'alias', 'path' and 'parent' were found for the declaration of circuit '#children[i].xmlAttributes.alias#' in fusebox.xml." />
   936			</cfif>
   937			<cfset alias = children[i].xmlAttributes.alias />
   938			<!--- record each circuit load per request - optimization for development-circuit-load mode --->
   939			<cfset request.__fusebox.CircuitsLoaded[alias] = true />
   940			<cfif structKeyExists(previousCircuits,alias) and
   941					children[i].xmlAttributes.path is previousCircuits[alias].getOriginalPath() and
   942					parent is previousCircuits[alias].parent and
   943					relative eq previousCircuits[alias].getOriginalPathIsRelative()>
   944				<!--- old circuit, we can just reload it --->
   945				<cfset this.circuits[alias] = previousCircuits[alias].reload(arguments.myFusebox) />
   946			<cfelse>
   947				<!--- new circuit, we must create it from scratch --->
   948				<cfset this.circuits[alias] =
   949						createObject("component","fuseboxCircuit")
   950							.init(this,alias,children[i].xmlAttributes.path,parent,arguments.myFusebox,relative) />
   951			</cfif>
   952		</cfloop>
   953		
   954		<!--- pass 2: build the circuit trace for each circuit --->
   955		<cfloop collection="#this.circuits#" item="i">
   956			<cfset this.circuits[i].buildCircuitTrace() />
   957		</cfloop>
   958		
   959	</cffunction>
   960	
   961	<cffunction name="loadLexicons" returntype="void" access="private" output="false" 
   962				hint="I load any lexicon declarations (both the Fusebox 4.1 style lexicon declarations and the Fusebox 5 style namespace declarations).">
   963		<cfargument name="fbCode" type="any" required="true" 
   964					hint="I am the parsed XML representation of the fusebox.xml file." />
   965		
   966		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/lexicons/lexicon") />
   967		<cfset var i = 0 />
   968		<cfset var n = arrayLen(children) />
   969		<cfset var aLex = "" />
   970		<cfset var attributes = arguments.fbCode.xmlRoot.xmlAttributes />
   971		<cfset var attr = "" />
   972		<cfset var ns = "" />
   973		
   974		<cfif n gt 0 and this.strictMode>
   975			<cfthrow type="fusebox.badGrammar.deprecated" 
   976					message="Deprecated feature"
   977					detail="Using the 'lexicon' declaration in fusebox.xml was deprecated in Fusebox 5." />
   978		</cfif>
   979
   980		<!--- load the legacy FB41 lexicons from the XML --->
   981		<cfset variables.fb41Lexicons = structNew() />
   982		
   983		<cfloop from="1" to="#n#" index="i">
   984			<cfset aLex = structNew() />
   985			<cfset aLex.namespace = children[i].xmlAttributes.namespace />
   986			<cfset aLex.path = normalizePartialPath(children[i].xmlAttributes.path) />
   987			<!--- FB41 lexicons are deprecated so we don't support absolute / mapped paths: --->
   988			<cfset aLex.path = getCoreToAppRootPath() & this.lexiconPath & aLex.path />
   989			<cfset variables.fb41Lexicons[children[i].xmlAttributes.namespace] = aLex />
   990		</cfloop>
   991		
   992		<!--- now load the new FB5 implicit lexicons from the <fusebox> tag --->
   993		<cfset variables.lexicons = structNew() />
   994		
   995		<!--- pass 1: pull out any namespace declarations --->
   996		<cfloop collection="#attributes#" item="attr">
   997			<cfif len(attr) gt 6 and left(attr,6) is "xmlns:">
   998				<!--- found a namespace declaration, pull it out: --->
   999				<cfset aLex = structNew() />
  1000				<cfset aLex.namespace = listLast(attr,":") />
  1001				<cfif aLex.namespace is variables.fuseboxLexicon.namespace>
  1002					<cfthrow type="fusebox.badGrammar.reservedName"
  1003							message="Attempt to use reserved namespace" 
  1004							detail="You have attempted to declare a namespace '#aLex.namespace#' (in fusebox.xml) which is reserved by the Fusebox framework." />
  1005				</cfif>
  1006				<cfset attributes[attr] = normalizePartialPath(attributes[attr]) />
  1007				<cfif left(attributes[attr],1) is "/">
  1008					<!--- assume mapped / root-relative path --->
  1009					<cfset aLex.path = attributes[attr] />
  1010				<cfelseif left(this.lexiconPath,1) is "/">
  1011					<!--- assume mapped / root-relative path --->
  1012					<cfset aLex.path = this.lexiconPath & attributes[attr] />
  1013				<cfelse>
  1014					<!--- relative paths --->
  1015					<cfset aLex.path = getCoreToAppRootPath() & 
  1016							this.lexiconPath & attributes[attr] />
  1017				</cfif>
  1018				<cfset variables.lexicons[aLex.namespace] = aLex />
  1019				<cfset variables.customAttributes[aLex.namespace] = structNew() />
  1020			</cfif>
  1021		</cfloop>
  1022		
  1023		<!--- pass 2: pull out any custom attributes --->
  1024		<cfloop collection="#attributes#" item="attr">
  1025			<cfif listLen(attr,":") eq 2>
  1026				<!--- looks like a custom attribute: --->
  1027				<cfset ns = listFirst(attr,":") />
  1028				<cfif ns is "xmlns">
  1029					<!--- special case - need to ignore xmlns:foo="bar" --->
  1030				<cfelseif structKeyExists(variables.customAttributes,ns)>
  1031					<cfset variables.customAttributes[ns][listLast(attr,":")] = attributes[attr] />
  1032				<cfelse>
  1033					<cfthrow type="fusebox.badGrammar.undeclaredNamespace" 
  1034							message="Undeclared lexicon namespace" 
  1035							detail="The lexicon prefix '#ns#' was found on a custom attribute in the <fusebox> tag but no such lexicon namespace has been declared." />
  1036				</cfif>
  1037			<cfelseif this.strictMode>
  1038				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
  1039						message="Unexpected attributes"
  1040						detail="Unexpected attributes were found in the 'fusebox' tag in fusebox.xml." />
  1041			</cfif>
  1042		</cfloop>
  1043		
  1044	</cffunction>
  1045	
  1046	<cffunction name="loadClasses" returntype="void" access="private" output="false" 
  1047				hint="I load any class declarations, including custom attributes (based on Fusebox 5 namespace declarations).">
  1048		<cfargument name="fbCode" type="any" required="true" 
  1049					hint="I am the parsed XML representation of the fusebox.xml file." />
  1050		
  1051		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/classes/class") />
  1052		<cfset var i = 0 />
  1053		<cfset var n = arrayLen(children) />
  1054		<cfset var attribs = 0 />
  1055		<cfset var attr = "" />
  1056		<cfset var ns = "" />
  1057		<cfset var customAttribs = 0 />
  1058		<cfset var constructor = "" />
  1059		<cfset var type = "" />
  1060		<cfset var nAttrs = 0 />
  1061		
  1062		<cfset this.classes = structNew() />
  1063		
  1064		<cfloop from="1" to="#n#" index="i">
  1065			<cfset attribs = children[i].xmlAttributes />
  1066
  1067			<cfif not structKeyExists(attribs,"alias")>
  1068				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
  1069						message="Required attribute is missing"
  1070						detail="The attribute 'alias' is required, for a 'class' declaration in fusebox.xml." />
  1071			</cfif>
  1072			<cfif not structKeyExists(attribs,"classpath")>
  1073				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
  1074						message="Required attribute is missing"
  1075						detail="The attribute 'classpath' is required, for a 'class' declaration in fusebox.xml." />
  1076			</cfif>
  1077			<cfif structKeyExists(attribs,"constructor")>
  1078				<cfset constructor = attribs.constructor />
  1079				<cfset nAttrs = 3 />
  1080			<cfelse>
  1081				<cfset constructor = "" />
  1082				<cfset nAttrs = 2 />
  1083			</cfif>
  1084			<!--- FB5: allow sensible default for type --->
  1085			<cfif structKeyExists(attribs,"type")>
  1086				<cfset type = attribs.type />
  1087				<cfset nAttrs = nAttrs + 1 />
  1088			<cfelse>
  1089				<cfset type = "component" />
  1090			</cfif>
  1091
  1092			<!--- scan for custom attributes --->
  1093			<cfset customAttribs = structNew() />
  1094			<cfloop collection="#attribs#" item="attr">
  1095				<cfif listLen(attr,":") eq 2>
  1096					<cfset nAttrs = nAttrs + 1 />
  1097					<!--- looks like a custom attribute: --->
  1098					<cfset ns = listFirst(attr,":") />
  1099					<cfif structKeyExists(variables.customAttributes,ns)>
  1100						<cfset customAttribs[ns][listLast(attr,":")] = attribs[attr] />
  1101					<cfelse>
  1102						<cfthrow type="fusebox.badGrammar.undeclaredNamespace" 
  1103								message="Undeclared lexicon namespace" 
  1104								detail="The lexicon prefix '#ns#' was found on a custom attribute in the <class> tag but no such lexicon namespace has been declared." />
  1105					</cfif>
  1106				</cfif>
  1107			</cfloop>
  1108			
  1109			<cfif this.strictMode and structCount(attribs) neq nAttrs>
  1110				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
  1111						message="Unexpected attributes"
  1112						detail="Unexpected attributes were found in the '#attribs.alias#' class declaration in fusebox.xml." />
  1113			</cfif>
  1114
  1115			<cfset this.classes[attribs.alias] = createObject("component","fuseboxClassDefinition")
  1116								.init(type,attribs.classpath,constructor,customAttribs) />
  1117			
  1118		</cfloop>
  1119		
  1120	</cffunction>
  1121	
  1122	<cffunction name="loadPlugins" returntype="void" access="private" output="false" 
  1123				hint="I load any plugin declarations.">
  1124		<cfargument name="fbCode" type="any" required="true" 
  1125					hint="I am the parsed XML representation of the fusebox.xml file." />
  1126		
  1127		<!--- TODO: this xpath means that we can't spot bad phase declarations: --->
  1128		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/plugins/phase") />
  1129		<cfset var i = 0 />
  1130		<cfset var n = arrayLen(children) />
  1131		<cfset var j = 0 />
  1132		<cfset var nn = 0 />
  1133		<cfset var phase = "" />
  1134		<cfset var plugin = 0 />
  1135		
  1136		<cfset this.plugins = structNew() />
  1137		<cfset this.pluginphases = structNew() />
  1138		
  1139		<cfloop from="1" to="#n#" index="i">
  1140			<cfif not structKeyExists(children[i].xmlAttributes,"name")>
  1141				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
  1142						message="Required attribute is missing"
  1143						detail="The attribute 'name' is required, for a 'plugin' declaration in fusebox.xml." />
  1144			</cfif>
  1145			<cfset phase = children[i].xmlAttributes.name />
  1146			<cfif this.strictMode and structCount(children[i].xmlAttributes) neq 1>
  1147				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
  1148						message="Unexpected attributes"
  1149						detail="Unexpected attributes were found in the '#phase#' phase declaration in fusebox.xml." />
  1150			</cfif>
  1151			<cfset nn = arrayLen(children[i].xmlChildren) />
  1152			<cfloop from="1" to="#nn#" index="j">
  1153				<cfset plugin = createObject("component","fuseboxPlugin").init(phase,children[i].xmlChildren[j],this,variables.lexicons) />
  1154				<cfset this.plugins[plugin.getName()][phase] = plugin />
  1155				<cfif not structKeyExists(this.pluginphases,phase)>
  1156					<cfset this.pluginphases[phase] = arrayNew(1) />
  1157				</cfif>
  1158				<cfset arrayAppend(this.pluginphases[phase],plugin) />
  1159			</cfloop>
  1160		</cfloop>
  1161		
  1162	</cffunction>
  1163	
  1164	<cffunction name="loadParameters" returntype="void" access="private" output="false" 
  1165				hint="I load any parameter declarations (and ensure none of them can overwrite public methods in this object!).">
  1166		<cfargument name="fbCode" type="any" required="true" 
  1167					hint="I am the parsed XML representation of the fusebox.xml file." />
  1168		
  1169		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/parameters/parameter") />
  1170		<cfset var i = 0 />
  1171		<cfset var n = arrayLen(children) />
  1172		<cfset var p = "" />
  1173		
  1174		<cfloop from="1" to="#n#" index="i">
  1175			<cfif not structKeyExists(children[i].xmlAttributes,"name")>
  1176				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
  1177						message="Required attribute is missing"
  1178						detail="The attribute 'name' is required, for a 'parameter' declaration in fusebox.xml." />
  1179			</cfif>
  1180			<cfset p = children[i].xmlAttributes.name />
  1181			<cfif not structKeyExists(children[i].xmlAttributes,"value")>
  1182				<cfthrow type="fusebox.badGrammar.requiredAttributeMissing"
  1183						message="Required attribute is missing"
  1184						detail="The attribute 'value' is required, for the '#p#' parameter declaration in fusebox.xml." />
  1185			</cfif>
  1186			<cfif this.strictMode and structCount(children[i].xmlAttributes) neq 2>
  1187				<cfthrow type="fusebox.badGrammar.unexpectedAttributes"
  1188						message="Unexpected attributes"
  1189						detail="Unexpected attributes were found in the '#p#' parameter declaration in fusebox.xml." />
  1190			</cfif>
  1191			<cfif structKeyExists(this,p) and isCustomFunction(this[p])>
  1192				<cfthrow type="fusebox.badGrammar.reservedName"
  1193						message="Attempt to use reserved parameter name"
  1194						detail="You have attempted to set a parameter called '#p#' which is reserved by the Fusebox framework." />
  1195			<cfelse>
  1196				<cfset this[p] = children[i].xmlAttributes.value />
  1197			</cfif>
  1198		</cfloop>
  1199		
  1200	</cffunction>
  1201	
  1202	<cffunction name="getDefaultMyself" returntype="string" access="public" output="false" 
  1203				hint="I return the default value of 'myself' for a given value of 'self'.">
  1204		<cfargument name="self" type="string" required="true" 
  1205					hint="I am the value of 'self' to use." />
  1206		
  1207		<cfreturn arguments.self & this.queryStringStart & this.fuseactionVariable & this.queryStringEqual />
  1208		
  1209	</cffunction>
  1210		
  1211	<cffunction name="loadGlobalProcess" returntype="void" access="private" output="false" 
  1212				hint="I load the globalfuseaction for the specified processing phase.">
  1213		<cfargument name="fbCode" type="any" required="true" 
  1214					hint="I am the parsed XML representation of the fusebox.xml file." />
  1215		<cfargument name="processPhase" type="string" required="true" 
  1216					hint="I am the name of the processing phase to load (appinit, preprocess or postprocess)." />
  1217		
  1218		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/globalfuseactions/#arguments.processPhase#") />
  1219		<cfset var n = arrayLen(children) />
  1220		
  1221		<cfif n eq 0>
  1222			<cfset variables.hasProcess[arguments.processPhase] = false />
  1223		<cfelseif n eq 1>
  1224			<cfset variables.hasProcess[arguments.processPhase] = true />
  1225			<cfset variables.process[arguments.processPhase] =
  1226					createObject("component","fuseboxAction")
  1227						.init(this,
  1228							"$globalfuseaction/#arguments.processPhase#",
  1229								"internal",
  1230									children[1].xmlChildren,true) />
  1231		<cfelse>
  1232			<cfthrow type="fusebox.badGrammar.nonUniqueDeclaration" 
  1233					message="Declaration was not unique" 
  1234					detail="More than one &lt;#arguments.process#&gt; declaration was found in the &lt;globalfuseactions&gt; section in fusebox.xml." />
  1235		</cfif>
  1236		
  1237	</cffunction>
  1238	
  1239	<cffunction name="loadGlobalPreAndPostProcess" returntype="void" access="private" output="false" 
  1240				hint="I load any globalfuseaction declarations.">
  1241		<cfargument name="fbCode" type="any" required="true" 
  1242					hint="I am the parsed XML representation of the fusebox.xml file." />
  1243		
  1244		<cfset var children = xmlSearch(arguments.fbCode,"/fusebox/globalfuseactions/*") />
  1245		<cfset var i = 0 />
  1246		<cfset var n = arrayLen(children) />
  1247		
  1248		<cfloop index="i" from="1" to="#n#">
  1249			<cfif listFind("appinit,preprocess,postprocess",children[i].xmlName) eq 0>
  1250				<cfthrow type="fusebox.badGrammar.illegalDeclaration"
  1251						message="Illegal declaration"
  1252						detail="The tag '#children[i].xmlName#' was found where 'appinit', 'preprocess' or 'postprocess' was expected in the &lt;globalfuseactions&gt; section in fusebox.xml." />
  1253			</cfif>
  1254		</cfloop>
  1255
  1256		<cfset variables.hasProcess = structNew() />
  1257		<cfset variables.process = structNew() />
  1258		<cfset loadGlobalProcess(arguments.fbCode,"appinit") />
  1259		<cfset loadGlobalProcess(arguments.fbCode,"preprocess") />
  1260		<cfset loadGlobalProcess(arguments.fbCode,"postprocess") />
  1261		
  1262	</cffunction>
  1263	
  1264	<cffunction name="relativePath" returntype="string" access="public" output="false" 
  1265				hint="I compute the relative path from one file system location to another.">
  1266		<cfargument name="from" type="string" required="true" 
  1267					hint="I am the full pathname from which the relative path should be computed." />
  1268		<cfargument name="to" type="string" required="true" 
  1269					hint="I am the full pathname to which the relative path should be computed." />
  1270		
  1271		<cfset var relative = "" />
  1272		<cfset var fromFirst = listFirst(arguments.from,"/") />
  1273		<cfset var fromRest = arguments.from />
  1274		<cfset var toFirst = listFirst(arguments.to,"/") />
  1275		<cfset var toRest = arguments.to />
  1276		<cfset var needSlash = false />
  1277		
  1278		<!--- trap special case first --->
  1279		<cfif arguments.from is arguments.to>
  1280			<cfreturn "" />
  1281		</cfif>
  1282	
  1283		<!--- walk down the common part of the paths --->
  1284		<cfloop condition="fromFirst is toFirst">
  1285			<cfset needSlash = true />
  1286			<cfset fromRest = listRest(fromRest,"/") />
  1287			<cfset toRest = listRest(toRest,"/") />
  1288			<cfset fromFirst = listFirst(fromRest,"/") />
  1289			<cfset toFirst = listFirst(toRest,"/") />
  1290		</cfloop>	
  1291		<!--- at this point the paths differ --->
  1292		<cfif not needSlash>
  1293			<!--- the paths differed from the top so we need to strip the leading / --->
  1294			<cfset toRest = right(toRest,len(toRest)-1) />
  1295		</cfif>
  1296		<cfset relative = repeatString("../",listLen(fromRest,"/")) & toRest />
  1297		<!---
  1298			ensure the trailing / is present - strictly speaking this is a bug fix for Railo
  1299			but it's probably a good practice anyway
  1300		--->
  1301		<cfif right(relative,1) is not "/">
  1302			<cfset relative = relative & "/" />
  1303		</cfif>
  1304
  1305		<cfreturn relative />
  1306		
  1307	</cffunction>
  1308	
  1309	<cffunction name="getCanonicalPath" returntype="string" access="public" output="false" 
  1310				hint="I return a canonical file path (with all /../ sections resolved).">
  1311		<cfargument name="path" type="string" required="true" 
  1312					hint="I am the path to resolve." />
  1313		
  1314		<cfset var resolvedPath = replace(arguments.path,"\","/","all") />
  1315		<cfset var leadingSlash = left(resolvedPath,1) is "/" />
  1316		<!--- UNC fix from Phil Muhm - ticket 239 --->
  1317		<cfset var leadingDoubleSlash = left(resolvedPath,2) is "//" />
  1318		<cfset var trailingSlash = right(resolvedPath,1) is "/" />
  1319		<cfset var segment = ""/>
  1320		<cfset var j = 1 />
  1321		<cfset var n = 0 />
  1322		<cfset var pathParts = arrayNew(1) />
  1323		<cfset var delimiter = "" />
  1324
  1325		<!--- remove pairs of directory/../ --->		
  1326		<cfloop list="#resolvedPath#" delimiters="/" index="segment">
  1327			<cfif segment is ".">
  1328				<!--- just ignore this --->
  1329			<cfelseif segment is "..">
  1330				<cfif j gt 1 and pathParts[j-1] is not "..">
  1331					<cfset j = j - 1 />
  1332				<cfelse>
  1333					<cfset pathParts[j] = segment />
  1334					<cfset j = j + 1 />
  1335				</cfif>
  1336			<cfelse>
  1337				<cfset pathParts[j] = segment />
  1338				<cfset j = j + 1 />
  1339			</cfif>
  1340		</cfloop>
  1341		
  1342		<!--- rebuild the path --->
  1343		<cfif leadingSlash>
  1344			<cfset delimiter = "/" />
  1345		</cfif>
  1346		<cfset resolvedPath = "" />
  1347		<cfset n = j - 1 />
  1348		<cfloop from="1" to="#n#" index="j">
  1349			<cfset resolvedPath = resolvedPath & delimiter & pathParts[j] />
  1350			<cfset delimiter = "/" />
  1351		</cfloop>
  1352		<cfif trailingSlash>
  1353			<cfset resolvedPath = resolvedPath & "/" />
  1354		</cfif>
  1355		<!--- UNC fix from Phil Muhm - ticket 239 --->
  1356		<cfif leadingDoubleSlash>
  1357			<cfset resolvedPath = "/" & resolvedPath />
  1358		</cfif>
  1359
  1360		<cfreturn resolvedPath />
  1361		
  1362	</cffunction>
  1363	
  1364	<cffunction name="normalizePartialPath" returntype="string" access="public" output="false" 
  1365				hint="I return a normalized file path (that has / instead of \ and ends with /).">
  1366		<cfargument name="partialPath" type="string" required="true" 
  1367					hint="I am the path to normalize." />
  1368		
  1369		<cfset var unixPath = replace(arguments.partialPath,"\","/","all") />
  1370		
  1371		<cfif right(unixPath,1) is not "/">
  1372			<cfset unixPath = unixPath & "/" />
  1373		</cfif>
  1374		
  1375		<cfreturn unixPath />
  1376		
  1377	</cffunction>
  1378	
  1379	<cffunction name="locateCfc" returntype="string" access="public" output="false"
  1380				hint="I deduce the dot-separated path to a CFC given its file system path (and a few heuristics).">
  1381		<cfargument name="filename" type="string" required="true" />
  1382	
  1383		<cfset var cfcPath = getCanonicalPath(filename) />
  1384		<cfset var webRoot = getCanonicalPath(expandPath("/")) />
  1385		<cfset var lenWebRoot = len(webRoot) />
  1386		<cfset var lenAppRoot = len(getApplicationRoot()) />
  1387		<cfset var lenCfcPath = len(cfcPath) />
  1388		<cfset var cfcDotPath = "" />
  1389		<cfset var firstSlash = 0 />
  1390		
  1391		<cfif lenCfcPath gt lenWebRoot and
  1392				left(cfcPath,lenWebRoot) is webRoot>
  1393			<!--- looks like it is under the webroot --->
  1394			<cfset cfcDotPath = replace(mid(cfcPath,lenWebRoot+1,lenCfcPath-lenWebRoot-4),"/",".","all") />
  1395		<cfelse>
  1396			<!--- must be mapped --->
  1397			<cfif lenCfcPath gt lenAppRoot and
  1398					left(cfcPath,lenAppRoot) is getApplicationRoot()>
  1399				<!--- looks like it is under the approot - assume approot is a mapping --->
  1400				<cfset cfcDotPath = listLast(getApplicationRoot(),"/") & "." &
  1401						replace(mid(cfcPath,lenAppRoot+1,lenCfcPath-lenAppRoot-4),"/",".","all") />
  1402			<cfelse>
  1403				<!--- dot-convert entire path and attempt to create it, dropping leading directories until we succeed --->
  1404				<!--- remove stuff up to leading / and also the .cfc at the end --->
  1405				<!--- note: this is *expensive* --->
  1406				<cfset firstSlash = find("/",cfcPath) />
  1407				<cfset cfcDotPath = replace(mid(cfcPath,firstSlash+1,lenCfcPath-firstSlash-4),"/",".","all") />
  1408				<cfloop condition="listLen(cfcDotPath) gt 0">
  1409					<cftry>
  1410						<cfset createObject("component",cfcDotPath) />
  1411						<!--- succeeded - return it --->
  1412						<cfbreak />
  1413						<cfcatch type="any">
  1414							<!--- failed - keep searching --->
  1415						</cfcatch>
  1416					</cftry>
  1417					<cfset cfcDotPath = listRest(cfcDotPath,".") />
  1418				</cfloop>
  1419			</cfif>
  1420		</cfif>
  1421		
  1422		<cfreturn cfcDotPath />
  1423	
  1424	</cffunction>
  1425	
  1426	<cffunction name="fileModificationDate" returntype="date" access="public" output="false" 
  1427				hint="I return the last modified date/time for a file.">
  1428		<cfargument name="filePath" type="string" required="false" 
  1429					hint="I am the full filesystem path to return the modification date." />
  1430
  1431		<!--- Java timestamp solution provided by Daniel Schmid --->
  1432		<cfset var jFile = 0 />
  1433		<cfset var dtLastModified = 0 />
  1434
  1435		<!--- watch out for hosts that have createObject("java") disabled - this is the buggy version from FB5 so it is not perfect --->
  1436		<cftry>
  1437			<cfset jFile = createObject("java","java.io.File").init(arguments.filePath) />
  1438			<cfset dtLastModified = parseDateTime(createObject("java","java.util.Date").init(jFile.lastModified())) />
  1439		<cfcatch type="any">
  1440			<cfdirectory action="list" directory="#getDirectoryFromPath(arguments.filePath)#" filter="#getFileFromPath(arguments.filePath)#" name="jFile" />
  1441			<cfif jFile.recordCount eq 1>
  1442				<cfset dtLastModified = parseDateTime(jFile.dateLastModified) />
  1443			<cfelse>
  1444				<!--- have to assume it was always modified --->
  1445				<cfset dtLastModified = now() />
  1446			</cfif>			
  1447		</cfcatch>
  1448		</cftry>
  1449		
  1450		<cfreturn dtLastModified />
  1451		
  1452	</cffunction>
  1453
  1454</cfcomponent>