From 0c4ff6f7fc3f9e1ccbe9de8ad42533e7ed1ecf15 Mon Sep 17 00:00:00 2001
From: Zac Spitzer <zac.spitzer@gmail.com>
Date: Thu, 1 Apr 2021 16:30:13 +0200
Subject: [PATCH] Cleanup admin applications list

- improve language
- log errors to application log / cftrace
- format code
---
 .../context/admin/ext.applications.detail.cfm |  13 +-
 .../context/admin/ext.applications.list.cfm   | 184 +++++++++---------
 .../main/cfml/context/admin/ext.functions.cfm |  10 +-
 .../context/admin/resources/language/en.xml   |  16 +-
 .../context/admin/resources/language/en.xml   |  16 +-
 test/components/Administrator/en.xml          |  14 +-
 6 files changed, 123 insertions(+), 130 deletions(-)

diff --git a/core/src/main/cfml/context/admin/ext.applications.detail.cfm b/core/src/main/cfml/context/admin/ext.applications.detail.cfm
index 51a92948cd..dae6c9bf75 100644
--- a/core/src/main/cfml/context/admin/ext.applications.detail.cfm
+++ b/core/src/main/cfml/context/admin/ext.applications.detail.cfm
@@ -1,7 +1,4 @@
 <cfscript>
-
-
-
 	function toOrderedArray(array arr, boolean desc=false) {
 		arraySort(arr,function(l,r) {
 			if(desc) {
@@ -23,10 +20,9 @@
 		}
 	}
 
-
-available=getDataByid(url.id,getExternalData(providerURLs));
-installed=getDataByid(url.id,extensions);
-isInstalled=installed.count() GT 0;
+	available=getDataByid(url.id,getExternalData(providerURLs));
+	installed=getDataByid(url.id,extensions);
+	isInstalled=installed.count() GT 0;
 
 
 // all version that can be installed
@@ -34,8 +30,7 @@ isInstalled=installed.count() GT 0;
 	// other Versions
 	if(!isNull(available.otherVersions) && !isSimpleValue(available.otherVersions)) {
 		all=duplicate(available.otherVersions);
-	}
-	else {
+	} else {
 		all=[];
 	}
 		
diff --git a/core/src/main/cfml/context/admin/ext.applications.list.cfm b/core/src/main/cfml/context/admin/ext.applications.list.cfm
index 07f1d18beb..2fab321ee8 100644
--- a/core/src/main/cfml/context/admin/ext.applications.list.cfm
+++ b/core/src/main/cfml/context/admin/ext.applications.list.cfm
@@ -1,7 +1,9 @@
 <cfscript>
 	hasAccess=true;
-	external=getExternalData(providerURLs,true);
-	existing={};
+	timer label="getExternalData"{
+		external = getExternalData(providerURLs,true);
+	}
+	existing = {};
 
 	function getLatestVersion(id) {
 		loop query=external {
@@ -141,101 +143,96 @@ Latest version: #latest.v#</cfif>"><cfif hasUpdates>
 	<h2>#stText.ext.notInstalled#</h2>
 	<div class="itemintro">#stText.ext.notInstalleddesc#</div>
 <cfif external.recordcount eq extensions.recordcount>
-	<cfset app_error.message = #stText.services.update.installExtns#>
+	<cfset app_error.message = stText.services.update.installExtns>
 	<cfset printerror(app_error)>
 <cfelseif external.recordcount lt extensions.recordcount>
-	<cfset app_error.message = #stText.services.update.chkInternet#>
+	<Cfdump var=#external#><cfdump var=#extensions#><cfabort>
+	<cfset app_error.message = stText.services.update.chkInternet>
 	<cfset printerror(app_error)>
 <cfelse>
 
-<cfscript>
-	existingIds = structKeyArray(existing);
-	unInstalledExt=external;
-
-	for(row=unInstalledExt.recordcount;row>=1;row--) {
-
-		rt = unInstalledExt.releaseType[row];
-		id = unInstalledExt.id[row];
-		// not for this admin type
-		if(!isnull(rt) and !isEmpty(rt) and rt != "all" and rt != request.adminType) {
-			queryDeleteRow(unINstalledExt,row);
-		}
-		// remove if already installed
-		if(arrayFindNoCase(existingIds,id)) {
-			queryDeleteRow(unINstalledExt,row);
+	<cfscript>
+		existingIds = StructKeyArray(existing);
+		availableExt = duplicate(external);
+		for(row = availableExt.recordcount ; row >= 1; row-- ) {
+			rt = availableExt.releaseType[row];
+			id = availableExt.id[row];
+			// not for this admin type
+			if( !isnull(rt) and !isEmpty(rt) and rt != "all" and rt != request.adminType) {
+				QueryDeleteRow( availableExt , row );
+			}
+			// remove if already installed
+			if(ArrayFindNoCase( existingIds, id )) {
+				QueryDeleteRow( availableExt, row );
+			}
 		}
-	}
-
-</cfscript>
-
-
-<!--- FILTER --->
-	<cfif unInstalledExt.recordcount GT 30>
-
-	<div class="filterform">
-		<cfformClassic onerror="customError" action="#request.self#?action=#url.action#" method="post">
-			<ul>
-				<li>
-					<label for="filter2">#stText.search.searchterm#:</label>
-					<input type="text" name="filter2" id="filter2" class="txt" value="#session.extFilter.filter2#" />
-				</li>
-				<li>
-					<input type="submit" class="button submit" name="mainAction" value="#stText.buttons.filter#" />
-				</li>
-			</ul>
-			<div class="clear"></div>
-		</cfformClassic>
-	</div><br>
-</cfif>
-
-<cfscript>
-	VersionStr = {
-		'pre_release':queryNew(unInstalledExt.columnlist),
-		'snapshot':queryNew(unInstalledExt.columnlist),
-		'release':queryNew(unInstalledExt.columnlist)
-	};
+	</cfscript>
 
-	loop query=unInstalledExt {
-		if(findNoCase("-ALPHA",unInstalledExt.version) || findNoCase("-BETA",unInstalledExt.version) || findNoCase("-RC",unInstalledExt.version)) 
-			addRow(unInstalledExt,VersionStr.pre_release,unInstalledExt.currentrow);
-		else if(findNoCase("-SNAPSHOT",unInstalledExt.version)) 
-			addRow(unInstalledExt,VersionStr.snapshot,unInstalledExt.currentrow);
-		else
-			addRow(unInstalledExt,VersionStr.release,unInstalledExt.currentrow);
-	}
+	<!--- FILTER --->
+	<cfif availableExt.recordcount GT 30>
+		<div class="filterform">
+			<cfformClassic onerror="customError" action="#request.self#?action=#url.action#" method="post">
+				<ul>
+					<li>
+						<label for="filter2">#stText.search.searchterm#:</label>
+						<input type="text" name="filter2" id="filter2" class="txt" value="#session.extFilter.filter2#" />
+					</li>
+					<li>
+						<input type="submit" class="button submit" name="mainAction" value="#stText.buttons.filter#" />
+					</li>
+				</ul>
+				<div class="clear"></div>
+			</cfformClassic>
+		</div><br>
+	</cfif>
 
-	function addRow(src,trg,srcRow) {
-		var trgRow=queryAddRow(arguments.trg);
-		loop array=queryColumnArray(arguments.src) item="local.col" {
-			querySetCell(arguments.trg,col,queryGetCell(arguments.src,col,arguments.srcRow),trgRow);
+	<cfscript>
+		VersionStr = {
+			'pre_release': QueryNew( availableExt.columnlist ),
+			'snapshot': QueryNew( availableExt.columnlist ),
+			'release': QueryNew( availableExt.columnlist )
+		};
+
+		loop query=availableExt {
+			if(findNoCase("-ALPHA",availableExt.version) || findNoCase("-BETA",availableExt.version) || findNoCase("-RC",availableExt.version)) 
+				addRow(availableExt,VersionStr.pre_release,availableExt.currentrow);
+			else if(findNoCase("-SNAPSHOT",availableExt.version)) 
+				addRow(availableExt,VersionStr.snapshot,availableExt.currentrow);
+			else
+				addRow(availableExt,VersionStr.release,availableExt.currentrow);
 		}
-	}
 
-		private function toVersionSortable(required string version) localMode=true {
-		version=unwrap(version.trim());
-		arr=listToArray(arguments.version,'.');
-		
-		// OSGi compatible version
-		if(arr.len()==4 && isNumeric(arr[1]) && isNumeric(arr[2]) && isNumeric(arr[3])) {
-			try{ return toOSGiVersion(version).sortable; }catch(local.e){};
+		function addRow( src, trg, srcRow ) {
+			var trgRow = queryAddRow( arguments.trg );
+			loop array=queryColumnArray(arguments.src) item="local.col" {
+				querySetCell(arguments.trg, col, QueryGetCell( arguments.src, col, arguments.srcRow ), trgRow );
+			}
 		}
 
-		rtn="";
-		loop array=arr index="i" item="v" {
-			if(len(v)<5)
-			 rtn&="."&repeatString("0",5-len(v))&v;
-			else
-				rtn&="."&v;
-		} 
-		return 	rtn;
-	}
-
-
-</cfscript>
+		private function toVersionSortable(required string version) localMode=true {
+			version = unwrap(version.trim());
+			arr = listToArray(arguments.version,'.');
+			
+			// OSGi compatible version
+			if(arr.len()==4 && isNumeric(arr[1]) && isNumeric(arr[2]) && isNumeric(arr[3])) {
+				try{ 
+					return toOSGiVersion(version).sortable; }
+				catch(local.e){};
+			}
 
+			rtn="";
+			loop array=arr index="i" item="v" {
+				if(len(v)<5)
+				rtn&="."&repeatString("0",5-len(v))&v;
+				else
+					rtn&="."&v;
+			} 
+			return rtn;	
+		}
 
-<cfset noneLasCounter=0>
- <cfif isQuery(external)>
+		noneLasCounter = 0;
+	</cfscript>
+<cfif isQuery(external)>
 	<cfset hiddenFormContents = "" >
 	<cfset count = 1>
 
@@ -291,15 +288,14 @@ Latest version: #latest.v#</cfif>"><cfif hasUpdates>
 	</div>
 	
 </cfif>
-	<cfif listnotinstalled eq 0 and unInstalledExt.recordcount gt 30>
+	<cfif listnotinstalled eq 0 and availableExt.recordcount gt 30>
 		<b>#stText.ext.searchbox# [#session.extFilter.filter2#]</b>
 	</cfif>
-
-<cfif noneLasCounter>
-	<div class="message" style="border-color: ##FC6;color:##C93;">
-		Extensions with a yellow border are not provided by the Lucee Association Switzerland and do not neccessarily follow our guidelines. These extensions are not reviewed by the Lucee Association Switzerland.
-	</div>
-</cfif>
+	<cfif noneLasCounter>
+		<div class="message" style="border-color: ##FC6;color:##C93;">
+			Extensions with a yellow border are not provided by the Lucee Association Switzerland and do not neccessarily follow our guidelines. These extensions are not reviewed by the Lucee Association Switzerland.
+		</div>
+	</cfif>
 </cfif>
 
 <!--- upload own extension --->
@@ -334,12 +330,10 @@ Latest version: #latest.v#</cfif>"><cfif hasUpdates>
 				</tr>
 			</tfoot>
 		</table>
-	</cfformClassic>
-
-	
+	</cfformClassic>	
 
 <cfhtmlbody>
-<script type="text/javascript">
+	<script type="text/javascript">
 	$(document).ready(function(){
 		if('#server.lucee.state#' == 'SNAPSHOT')
 			var version = 'Snapshot';
@@ -387,7 +381,7 @@ Latest version: #latest.v#</cfif>"><cfif hasUpdates>
 		});
 	}
 	</script>
-	</cfhtmlbody>
+</cfhtmlbody>
 </cfoutput>
 <cfif structKeyExists(request, "refresh") && request.refresh EQ true>
 	<script type="text/javascript">
diff --git a/core/src/main/cfml/context/admin/ext.functions.cfm b/core/src/main/cfml/context/admin/ext.functions.cfm
index 79952921d0..cdc3736a2d 100644
--- a/core/src/main/cfml/context/admin/ext.functions.cfm
+++ b/core/src/main/cfml/context/admin/ext.functions.cfm
@@ -274,8 +274,7 @@
 	* get information from specific ExtensionProvider, if an extension is provided by multiple providers only the for the newest (version) is returned
 	*/
 	function getExternalData(required string[] providers, boolean forceReload=false, numeric timeSpan=60, boolean useLocalProvider=true) {
-		var datas={};
-
+		var datas={};		
 		providers.each(parallel:true,closure:function(value){
 				var data=getProviderInfo(arguments.value,forceReload,timespan);
 				datas[arguments.value]=data;
@@ -341,7 +340,12 @@
 	    dump(q);*/
 
 		loop struct="#datas#" index="local.provider" item="local.data" {
-			if(structKeyExists(data,"error")) continue;
+			if (structKeyExists(data,"error")){
+				var err = "getExternalData() #local.provider# #data.error#";
+				trace text="#err#";
+				WriteLog(type="ERROR", text=err);
+				continue;
+			}
 
 			// rename older to otherVersions
 
diff --git a/core/src/main/cfml/context/admin/resources/language/en.xml b/core/src/main/cfml/context/admin/resources/language/en.xml
index be75c84a54..b691db8f2d 100755
--- a/core/src/main/cfml/context/admin/resources/language/en.xml
+++ b/core/src/main/cfml/context/admin/resources/language/en.xml
@@ -67,8 +67,8 @@
 	<data key="services.update.titleDesc">Upgrade or Downgrade the version by selecting from the drop-down box below.</data>
 	<data key="services.update.titleDesc2"> You cannot downgrade below {min-version} because your lucee.jar has bundled this version. To go below this version you need to replace your lucee.jar {server.lucee.loaderPath} OR .ico file {context} with an older version</data>
 	<data key="services.update.downgradeVersion">To downgrade your version below {minVersion} you need to replace your lucee.jar with an older version one you can download {url}. This is because the lucee.jars always bundles a version itself and it will always use at least that version.</data>
-	<data key="services.update.installExtns">All of the extensions are installed / Couldn't able to reach the server for list the Uninstalled Extensions. Please check your Internet Connection.</data>
-	<data key="services.update.chkInternet">Couldn't able to reach the server for list the "Uninstalled Extensions". Please check your Internet Connection</data>
+	<data key="services.update.installExtns">All of the extensions are installed / Unable to reach the Server for list the Uninstalled Extensions. Please check your Internet Connection.</data>
+	<data key="services.update.chkInternet">Unable to reach the server for list the "Uninstalled Extensions". Please check your Internet Connection</data>
 
 	<data key="services.certificate.desc">List SSL Certificates for a specific Host or install them.</data>
 	<data key="services.certificate.host">Host</data>
@@ -311,10 +311,10 @@
 	<data key="ext.version">Version</data>
 	<data key="ext.appupdate">Update</data>
 	<data key="ext.created">Release Date</data>
-	<data key="ext.notinstalled">Not installed</data>
+	<data key="ext.notinstalled">Available to Install</data>
 	<data key="ext.codename">Code Name</data>
 	<data key="ext.stepof">Step {current} of {total}</data>
-	<data key="ext.notinstalleddesc">These applications are not yet installed on the system.</data>
+	<data key="ext.notinstalleddesc">Applications available to be installed on this Server.</data>
 	<data key="ext.uninstallmissingcfc">Can&apos;t uninstall. Install.cfc is missing. Please uninstall the application manually.</data>
 	<data key="ext.application">Application</data>
 	<data key="ext.applabel">Application</data>
@@ -332,19 +332,19 @@
 	<data key="ext.projectUrl">Homepage</data>
 	<data key="ext.sourceUrl">Source Code</data>
 	<data key="ext.documentationUrl">Documentation</data>	
-	<data key="ext.installeddesc">These applications are already installed on the system.</data>
+	<data key="ext.installeddesc">Applications installed on this Server.</data>
 	<data key="ext.installedServer">Installed in Server Administrator</data>
 	<data key="ext.installedServerDesc">This Extension is already installed in the Server Administrator, you have 2 options, you can overwrite it for the current web context by installing it here as well or you can change it in the Server Administrator what will affect all Web Contexts.</data>
 	<data key="ext.free">Free</data>
 	<data key="ext.price">Price</data>
 	<data key="ext.licenseagreement">License agreement</data>
-	<data key="ext.uploadextension">Upload new extension (experimental)</data>
-	<data key="ext.uploadextensiondesc">If you downloaded an extension, you can add the extension here.</data>
+	<data key="ext.uploadextension">Upload new Extension</data>
+	<data key="ext.uploadextensiondesc">If you manually downloaded an extension, or built your own, you can install the extension here. You can also just drop the .lex file in the Server's /deploy directory.</data>
 	<data key="ext.upload">upload</data>
 	<data key="ext.nofileuploaded">You have not uploaded a file!&lt;br&gt;Please first choose a file.</data>
 	<data key="ext.extThumbnail">Extension thumbnail</data>
 	<data key="ext.msgAfterNotAgreed">Because you did not agree with the license, the extension was not installed.&lt;br&gt;In case you installed the extension before, you will need to uninstall it, if you do not wish to agree with it's license anymore.</data>
-	<data key="ext.extzipfile">Extension zip file</data>
+	<data key="ext.extzipfile">Extension zip (*.lex) file</data>
 	<data key="ext.viewdetails">View details</data>
 	<data key="ext.theError">The error</data>
 	<data key="ext.errorFileUpload">The file could not be uploaded.</data>
diff --git a/core/src/main/java/resource/context/admin/resources/language/en.xml b/core/src/main/java/resource/context/admin/resources/language/en.xml
index be75c84a54..b691db8f2d 100644
--- a/core/src/main/java/resource/context/admin/resources/language/en.xml
+++ b/core/src/main/java/resource/context/admin/resources/language/en.xml
@@ -67,8 +67,8 @@
 	<data key="services.update.titleDesc">Upgrade or Downgrade the version by selecting from the drop-down box below.</data>
 	<data key="services.update.titleDesc2"> You cannot downgrade below {min-version} because your lucee.jar has bundled this version. To go below this version you need to replace your lucee.jar {server.lucee.loaderPath} OR .ico file {context} with an older version</data>
 	<data key="services.update.downgradeVersion">To downgrade your version below {minVersion} you need to replace your lucee.jar with an older version one you can download {url}. This is because the lucee.jars always bundles a version itself and it will always use at least that version.</data>
-	<data key="services.update.installExtns">All of the extensions are installed / Couldn't able to reach the server for list the Uninstalled Extensions. Please check your Internet Connection.</data>
-	<data key="services.update.chkInternet">Couldn't able to reach the server for list the "Uninstalled Extensions". Please check your Internet Connection</data>
+	<data key="services.update.installExtns">All of the extensions are installed / Unable to reach the Server for list the Uninstalled Extensions. Please check your Internet Connection.</data>
+	<data key="services.update.chkInternet">Unable to reach the server for list the "Uninstalled Extensions". Please check your Internet Connection</data>
 
 	<data key="services.certificate.desc">List SSL Certificates for a specific Host or install them.</data>
 	<data key="services.certificate.host">Host</data>
@@ -311,10 +311,10 @@
 	<data key="ext.version">Version</data>
 	<data key="ext.appupdate">Update</data>
 	<data key="ext.created">Release Date</data>
-	<data key="ext.notinstalled">Not installed</data>
+	<data key="ext.notinstalled">Available to Install</data>
 	<data key="ext.codename">Code Name</data>
 	<data key="ext.stepof">Step {current} of {total}</data>
-	<data key="ext.notinstalleddesc">These applications are not yet installed on the system.</data>
+	<data key="ext.notinstalleddesc">Applications available to be installed on this Server.</data>
 	<data key="ext.uninstallmissingcfc">Can&apos;t uninstall. Install.cfc is missing. Please uninstall the application manually.</data>
 	<data key="ext.application">Application</data>
 	<data key="ext.applabel">Application</data>
@@ -332,19 +332,19 @@
 	<data key="ext.projectUrl">Homepage</data>
 	<data key="ext.sourceUrl">Source Code</data>
 	<data key="ext.documentationUrl">Documentation</data>	
-	<data key="ext.installeddesc">These applications are already installed on the system.</data>
+	<data key="ext.installeddesc">Applications installed on this Server.</data>
 	<data key="ext.installedServer">Installed in Server Administrator</data>
 	<data key="ext.installedServerDesc">This Extension is already installed in the Server Administrator, you have 2 options, you can overwrite it for the current web context by installing it here as well or you can change it in the Server Administrator what will affect all Web Contexts.</data>
 	<data key="ext.free">Free</data>
 	<data key="ext.price">Price</data>
 	<data key="ext.licenseagreement">License agreement</data>
-	<data key="ext.uploadextension">Upload new extension (experimental)</data>
-	<data key="ext.uploadextensiondesc">If you downloaded an extension, you can add the extension here.</data>
+	<data key="ext.uploadextension">Upload new Extension</data>
+	<data key="ext.uploadextensiondesc">If you manually downloaded an extension, or built your own, you can install the extension here. You can also just drop the .lex file in the Server's /deploy directory.</data>
 	<data key="ext.upload">upload</data>
 	<data key="ext.nofileuploaded">You have not uploaded a file!&lt;br&gt;Please first choose a file.</data>
 	<data key="ext.extThumbnail">Extension thumbnail</data>
 	<data key="ext.msgAfterNotAgreed">Because you did not agree with the license, the extension was not installed.&lt;br&gt;In case you installed the extension before, you will need to uninstall it, if you do not wish to agree with it's license anymore.</data>
-	<data key="ext.extzipfile">Extension zip file</data>
+	<data key="ext.extzipfile">Extension zip (*.lex) file</data>
 	<data key="ext.viewdetails">View details</data>
 	<data key="ext.theError">The error</data>
 	<data key="ext.errorFileUpload">The file could not be uploaded.</data>
diff --git a/test/components/Administrator/en.xml b/test/components/Administrator/en.xml
index 4092576395..6997eaebc3 100644
--- a/test/components/Administrator/en.xml
+++ b/test/components/Administrator/en.xml
@@ -259,10 +259,10 @@
 	<data key="ext.version">Version</data>
 	<data key="ext.appupdate">Update</data>
 	<data key="ext.created">Release Date</data>
-	<data key="ext.notinstalled">Not installed</data>
+	<data key="ext.notinstalled">Available to Install</data>
 	<data key="ext.codename">Code Name</data>
 	<data key="ext.stepof">Step {current} of {total}</data>
-	<data key="ext.notinstalleddesc">These applications are not yet installed on the system.</data>
+	<data key="ext.notinstalleddesc">Applications available to be installed on this Server.</data>
 	<data key="ext.uninstallmissingcfc">Can&apos;t uninstall. Install.cfc is missing. Please uninstall the application manually.</data>
 	<data key="ext.application">Application</data>
 	<data key="ext.applabel">Application</data>
@@ -274,22 +274,22 @@
 	<data key="ext.uninstallmethodexception">Can&apos;t uninstall. The uninstall method throws the following exception [{message}]. Please uninstall the application manually.</data>
 	<data key="ext.category">Category</data>
 	<data key="ext.availableversion">Available version</data>
-	<data key="ext.uninstalldone">uninstallation completed</data>
+	<data key="ext.uninstalldone">Uninstallation completed</data>
 	<data key="ext.provider">Provider</data>
 	<data key="ext.documentation">Documentation</data>
-	<data key="ext.installeddesc">These applications are already installed on the system.</data>
+	<data key="ext.installeddesc">Applications installed on this Server.</data>
 	<data key="ext.installedServer">Installed in Server Administrator</data>
 	<data key="ext.installedServerDesc">This Extension is already installed in the Server Administrator, you have 2 options, you can overwrite it for the current web context by installing it here as well or you can change it in the Server Administrator what will affect all Web Contexts.</data>
 	<data key="ext.free">Free</data>
 	<data key="ext.price">Price</data>
 	<data key="ext.licenseagreement">License agreement</data>
-	<data key="ext.uploadextension">Upload new extension (experimental)</data>
-	<data key="ext.uploadextensiondesc">If you downloaded an extension, you can add the extension here.</data>
+	<data key="ext.uploadextension">Upload new Extension</data>
+	<data key="ext.uploadextensiondesc">If you manually downloaded an extension, or built your own, you can install the extension here. You can also just drop the .lex file in the Server's /deploy directory.</data>
 	<data key="ext.upload">upload</data>
 	<data key="ext.nofileuploaded">You have not uploaded a file!&lt;br&gt;Please first choose a file.</data>
 	<data key="ext.extThumbnail">Extension thumbnail</data>
 	<data key="ext.msgAfterNotAgreed">Because you did not agree with the license, the extension was not installed.&lt;br&gt;In case you installed the extension before, you will need to uninstall it, if you do not wish to agree with it's license anymore.</data>
-	<data key="ext.extzipfile">Extension zip file</data>
+	<data key="ext.extzipfile">Extension zip (*.lex) file</data>
 	<data key="ext.viewdetails">View details</data>
 	<data key="ext.theError">The error</data>
 	<data key="ext.errorFileUpload">The file could not be uploaded.</data>