User Tools

Site Tools


Zip Compress Each

Summary

Below are examples demonstrating how you can collect individual files into a zlib compressed (*.zip) file.

The first example ("Build Data") demonstrates how to use the file system to build a dynamic list of files, relative to a base directory, to include in the *.zip. It also demonstrates how to then pass the data to the second utility script, which actually builds the zip.

The second example ("Utility") demonstrates how a utility type script that can be executed by an external script1) or plugin that passes in arguments could be used to produce zlib compressed archives.

API Areas of Interest

Example (Build Data)

File_Zip_Compress_Each.dsa
// Define an anonymous function;
// serves as our main loop,
// limits the scope of variables
(function(){
 
	// Define 'static' objects
	var s_oFileInfo = new DzFileInfo( getScriptFileName() );
 
	/*********************************************************************/
	// String : A function for retrieving a translation if one exists
	function text( sText )
	{
		// If the version of the application supports qsTr()
		if( typeof( qsTr ) != "undefined" ){
			// Return the translated (if any) text
			return qsTr( sText );
		}
 
		// Return the original text
		return sText;
	};
 
	/***********************************************************************
	***** DsFileSystem Prototype *****
	***********************************************************************/
 
	/*********************************************************************/
	function DsFileSystem()
	{
	};
 
	/***********************************************************************/
	DsFileSystem.superclass = Object;
 
	/*********************************************************************/
	// Array<String|DzDir> : Method for collecting an array of directory objects
	DsFileSystem.prototype.getDirectories = function( oDir, regxFilter, nFilter, nSort, sType, bRecurse )
	{
		// Declare working variable
		var sAbsPath;
 
		// Get the directory names
		var aDirs = oDir.entryList( regxFilter, nFilter, nSort );
		// Iterate over the directory names
		for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){
			// Get the absolute path of the 'current' dir
			sAbsPath = String( "%1/%2" ).arg( oDir.absPath() ).arg( aDirs[ i ] );
			// Based on the type requested
			switch( sType ){
				default:
				case "String":
					// Update the name with the absolute path of the directory
					aDirs[ i ] = sAbsPath;
					// If we are recursing
					if( bRecurse ){
						// Recursively collect the directory paths
						aDirs = aDirs.concat( this.getSubDirectories( new DzDir( sAbsPath ),
							regxFilter, nFilter, nSort, sType ) );
					}
					break;
				case "DzDir":					
					// Update the name with a directory object
					aDirs[ i ] = new DzDir( sAbsPath );
					// If we are recursing
					if( bRecurse ){
						// Recursively collect the directories
						aDirs = aDirs.concat( this.getSubDirectories( aDirs[ i ],
							regxFilter, nFilter, nSort, sType ) );
					}
					break;
			}
		}
 
		// Return the result
		return aDirs;
	};
 
	/*********************************************************************/
	// Array<String|DzDir> : Method for recursively collecting an array of directory objects
	DsFileSystem.prototype.getSubDirectories = function( oDir, regxFilter, nFilter, nSort, sType )
	{
		// Get the immediate child directories
		var aDirs = this.getDirectories( oDir, regxFilter, nFilter, nSort, sType, true );
		// Iterate over the directories
		for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){
			// Based on the type requested
			switch( sType ){
				default:
				case "String":
					// Recursively collect the directory paths
					aDirs = aDirs.concat( this.getSubDirectories( new DzDir( aDirs[ i ] ),
						regxFilter, nFilter, nSort, sType ) );
					break;
				case "DzDir":	
					// Recursively collect the directories
					aDirs = aDirs.concat( this.getSubDirectories( aDirs[ i ],
						regxFilter, nFilter, nSort, sType, true ) );
					break;
			}
		}
 
		// Return the result
		return aDirs;
	};
 
	/*********************************************************************/
	// Array<String|DzFileInfo|DzFile> : Method for collecting an array of files
	DsFileSystem.prototype.getFiles = function( oDir, regxFilter, nFilter, nSort, sType )
	{
		// Declare working variable
		var sAbsFilePath;
 
		// Get the file names
		var aFiles = oDir.entryList( regxFilter, nFilter, nSort );
		// Iterate over the file names
		for( var i = 0, nFiles = aFiles.length; i < nFiles; i += 1 ){
			// Get the absolute path of the 'current' file
			sAbsFilePath = oDir.absFilePath( aFiles[ i ] );
			// Based on the type requested
			switch( sType ){
				default:
				case "String":
					// Update the name with the absolute path of a file
					aFiles[ i ] = sAbsFilePath;
					break;
				case "DzFileInfo":
					// Update the name with a file info object
					aFiles[ i ] = new DzFileInfo( sAbsFilePath );
					break;
				case "DzFile":
					// Update the name with a file object
					aFiles[ i ] = new DzFile( sAbsFilePath );
					break;
			}
		}
 
		// Return the result
		return aFiles;
	};
 
	/*********************************************************************/
	// Array<String|DzDir> : Method for retrieving a list of directories
	DsFileSystem.prototype.getDirectoryList = function( sPath, sFilter, sType, bRecurse, bRelative )
	{
		// Declare the output
		var aDirs = [];
 
		// Create a directory object
		var oBaseDir = new DzDir( sPath );
		// If the directory doesn't exist
		if( !oBaseDir.exists() ){
			// We are done...
			return aDirs;
		}
 
		// Get the directories
		var aDirs = this.getDirectories( oBaseDir, sFilter,
			DzDir.Dirs | DzDir.NoDotAndDotDot, DzDir.Name, sType, bRecurse );
 
		// If we do not want relative
		if( !bRelative ){
			// Return the result
			return aDirs;
		}
 
		// Declare working variable
		var sAbsPath, sRelPath;
		var oDir;
 
		// Iterate over the directories
		for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){
			// Based on the type requested
			switch( sType ){
				default:
				case "String":
					// Get the 'current' path
					sAbsPath = aDirs[ i ];
					// Get the relative portion of the path
					sRelPath = sAbsPath.substring( sPath.length );
					// Update the path
					aDirs[ i ] = sRelPath;
					break;
				case "DzDir":
					// Get the 'current' directory
					oDir = aDirs[ i ];
					// Get the path
					sAbsPath = oDir.path();
					// Get the relative portion of the path
					sRelPath = sAbsPath.substring( sPath.length );
					// Update the path
					oDir.setPath( sRelPath );
					// Update the directory
					aDirs[ i ] = oDir;
					break;
			}
		}
 
		// Return the result
		return aDirs;
	};
 
	/*********************************************************************/
	// Array<String|DzFileInfo|DzFile> : Method for retrieving a list of files
	DsFileSystem.prototype.getFileList = function( sPath, sFilter, sType, bRecurse )
	{
		// Declare the output
		var aFiles = [];
 
		// Get the directories
		var aDirs = this.getDirectoryList( sPath, "*", "DzDir", bRecurse );
		// Iterate over the directories
		for( var i = 0, nDirs = aDirs.length; i < nDirs; i += 1 ){
			// Append the files from the 'current' directory to the output
			aFiles = aFiles.concat(
				this.getFiles( aDirs[ i ], sFilter, DzDir.Files, DzDir.Name, sType ) );
		}
 
		// Return the result
		return aFiles;
	};
 
	/*********************************************************************/
	// Declare working variables
	var sTitle;
	var sMessage;
 
	// Define common strings
	var sButton = text( "&OK" );
 
	// If the application version is less than 4.9.3.149
	if( App.version64 < 0x0004000900030095 ){
		//
		sTitle = "Version Error";
		sMessage = String( "This script requires %1 4.9.3.149 or newer to continue." )
						.arg( App.appName )
 
		// If the application is showing prompts
		if( App.showPrompts() ){
			// Inform the user
			MessageBox.information( text( sMessage ), text( sTitle ), sButton );
		}
 
		// Provide feecback
		print( sTitle, ":", sMessage );
 
		// We are done..
		return;
	}
 
	//
	var oScript = new DzScript();
 
	// Construct the path of the utility script that performs compression
	var sCompressScript = String( "%1/%2_Remote" )
							.arg( s_oFileInfo.absolutePath() )
							.arg( s_oFileInfo.completeBaseName() );
 
	// Attempt to find our script; doing it this way, we can debug with an
	// ascii file and distribute a binary [encrypted] file with the same name...
	// without having to update the contents of the script or manually handle
	// the file extensions; requires 3.0.1.5 or newer
	var sScriptPath = oScript.getScriptFile( sCompressScript );
 
	// Declare working variables
	var sAppData;
	var sBuild;
	var sSrcBasePath;
	var sAbsPath;
	var sRelPath;
	var sLayoutsPath;
	var sSrcPath;
	var sTgtPath;
	var aRelPaths;
	var aFiles;
	var nFiles;
	var oDir;
	var oFileSystem;
	var oData;
 
	// If a script is found
	if( !sScriptPath.isEmpty() ){
		// Get the "AppData" path
		sAppData = System.getenv( "AppData" );
		// If this is on Windows
		if( App.platform() == DzApp.Windows ){
			// Replace backslashes with forward slashes
			sAppData = sAppData.replace( new RegExp( "\\\\", "g" ), "/" );
		}
 
		// Initialize the build
		sBuild = "Studio4";
		// Depending on the release cycle, update
		switch( App.releaseCycle() ){
			default:
			case DzApp.GeneralRelease:
				break;
			case DzApp.PublicBuild:
			case DzApp.PublishingBuild:
			case DzApp.PrivateBuild:
			case DzApp.DevBuild:
				sBuild += " " + App.releaseCycleString();
				break;
		}
 
		// Define the source directory path
		sSrcBasePath = String("%1/%2/%3")
			.arg( sAppData )
			.arg( App.orgName )
			.arg( sBuild );
 
		// Create a directory object
		oDir = new DzDir( sSrcBasePath );
		// If the directory does not exist
		if( !oDir.exists() ){
			// Provide feedback
			print( sSrcBasePath, "does not exist!" );
			// We are done...
			return;
		}
 
		// Let the user know we are busy
		setBusyCursor();
 
		// Define the target filename
		sTgtPath = "c:/temp/DS_Layouts_Backup.zip";
 
		// Define the list of relative paths to zip
		aRelPaths = [
			"actions.dsx",
			"customactions.dsx",
			"layout.dse",
			"layout.dsx",
			"menus.dsx",
			"toolbars.dsx"
		];
 
		// Construct the user layouts path
		sLayoutsPath = String( "%1/user layouts" ).arg( sSrcBasePath );
		// Create a file system object
		oFileSystem = new DsFileSystem();
		// Get all of the files in the directory
		aFiles = oFileSystem.getFileList( sLayoutsPath, "*", "String", true );
		// Iterate over the files
		for( var i = 0, nFiles = aFiles.length; i < nFiles; i += 1 ){
			// Get the 'current' file
			sAbsPath = aFiles[ i ];
			// Get the relative portion of the path
			sRelPath = sAbsPath.substring( sSrcBasePath.length + 1 );
			// Update with the relative path
			aFiles[ i ] = sRelPath;
		}
		// Append any user layouts found
		aRelPaths = aRelPaths.concat( aFiles );
 
		/// Get the number of files
		nFiles = aRelPaths.length;
 
		// Initialize our data object
		oData = {
			"target_path": sTgtPath,
			"source_paths": new Array( nFiles ),
			"relative_paths": new Array( nFiles )
			//, "run_silent": true
		};
 
		// Iterate over the relative paths
		for( var i = 0; i < nFiles; i += 1 ){
			// Get the 'current' relative path
			sRelPath = aRelPaths[ i ];
			// Capture the value
			oData[ "relative_paths" ][i] = sRelPath;
 
			// Construct the 'current' source file path
			sSrcPath = String( "%1/%2" ).arg( sSrcBasePath ).arg( sRelPath );
			// Capture the value
			oData[ "source_paths" ][i] = sSrcPath;
		}
 
		// Let the user know we are done
		clearBusyCursor();
 
		//print( JSON.stringify( oData, null, "\t" ) );
 
		// If the script loads
		if( oScript.loadFromFile( sScriptPath ) ){
			// Execute the script; pass in an array of arguments
			oScript.execute( [ oData ] );
		// If the script doesn't load
		} else {
			// Define text variables for the message
			sTitle = "Read Error";
			sMessage = String( "The '%1' file could not be loaded." ).arg( sScriptPath );
			// If the application is showing prompts
			if( App.showPrompts() ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sButton );
			}
 
			// Provide feecback
			print( sTitle, ":", sMessage );
		}
	// If a script is not found
	} else {
		// Define text variables for the message
		sTitle = text( "File Not Found" );
		sMessage = text( "A '%1.ds(a|b|e)' file could not be found." ).arg( sBasePath );
		// If the application is showing prompts
		if( App.showPrompts() ){
			// Inform the user
			MessageBox.information( text( sMessage ), text( sTitle ), sButton );
		}
 
		// Provide feecback
		print( sTitle, ":", sMessage );
	}
 
// Finalize the function and invoke
})();

Example (Utility)

File_Zip_Compress_Each_Remote.dsa
// Define an anonymous function;
// serves as our main loop,
// limits the scope of variables
(function( aArgs ){
 
	/*********************************************************************/
	// String : A function for retrieving a translation if one exists
	function text( sText )
	{
		// If the version of the application supports qsTr()
		if( typeof( qsTr ) != "undefined" ){
			// Return the translated (if any) text
			return qsTr( sText );
		}
 
		// Return the original text
		return sText;
	};
 
	/*********************************************************************/
	// String : A function for opening the application log
	function openApplicationLog()
	{
		// Cause any data in the log buffer to be written to file
		App.flushLogBuffer();
		// Cause the log file to be shown
		App.showURL( App.getLogFilename() );
	};
 
	/*********************************************************************/
	// Construct the message
	var sMessage = text( "This script accepts exactly 1 argument - an ECMA Object.  " +
		"This Object must define three (3) members, named 'target_path', 'source_paths' " +
		"and 'relative_paths'.  The values of the 'target_path' member must be of " +
		"the String type and should provide the absolute path of the zlib compressed " +
		"file (*.zip) to create.  The values of the 'source_paths' and 'relative_paths' " +
		"members must be of the Array type.  The 'source_paths' Array should consist " +
		"of String elements that define the absolute paths of the individual files to " +
		"include in the file specified by the 'target_path' member.  The 'relative_paths' " +
		"Array should consist of String elements that define the corresponding relative " +
		"paths of the individual files specified in the 'source_paths' Array, as they " +
		"should be named/placed within the file specified by the 'target_path' member.  " +
		"An optional fourth member named 'run_silent' of the Boolean type may be " +
		"defined to control whether or not modal messages to the user are supressed.\n\n" +
		"Example:\n" +
		"{\n" +
		"\t\"target_path\": \"C:/Temp/MyArchive.zip\",\n" +
		"\t\"source_paths\": [ \"D:/Absolute/Path/To/A/File.ext\" ],\n" +
		"\t\"relative_paths\": [ \"Path/To/A/File.ext\" ],\n" +
		"\t\"run_silent\": false\n" +
		"}" );
 
	var sTitle = text( "Usage" );
	var sOk = text( "&OK" );	
 
	// Initialize
	var sTgtPath = "";
	var aSrcPaths = [];
	var aRelPaths = [];
	var bSilent = false;
 
	// Declare working variables
	var vArg0;
	var vTarget;
	var vSrcPaths;
	var vRelPaths;
	var vSilent;
 
	// If this script was executed remotely with an argument
	if( aArgs.length > 0 ){
		// Get the first argument
		vArg0 = aArgs[0];
		// If it is not an ECMA Object
		if( typeof( vArg0 ) != "object" ){
			// Inform the user
			MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
			// We are done...
			return;
		}
 
		// If it has a member named "target_path"
		if( vArg0.hasOwnProperty( "target_path" ) ){
			// Get the "target_path" value
			vTarget = vArg0[ "target_path" ];
			// If "target_path" is not a string
			if( typeof( vTarget ) != "string" ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
 
			// Capture the value
			sTgtPath = vTarget;
 
			// If the value does not end with ".zip"
			if( !sTgtPath.endsWith( ".zip" ) ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
		}
 
		// If it has a member named "source_paths"
		if( vArg0.hasOwnProperty( "source_paths" ) ){
			// Get the "source_paths" value
			vSrcPaths = vArg0[ "source_paths" ];
			// If "source_paths" is not an Array
			if( !Array.isArray( vSrcPaths ) ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
 
			// Capture the value
			aSrcPaths = vSrcPaths;
 
			// If the value does not contain entries
			if( aSrcPaths.length < 1 ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
		}
 
		// If it has a member named "relative_paths"
		if( vArg0.hasOwnProperty( "relative_paths" ) ){
			// Get the "relative_paths" value
			vRelPaths = vArg0[ "relative_paths" ];
			// If "relative_paths" is not an Array
			if( !Array.isArray( vRelPaths ) ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
 
			// Capture the value
			aRelPaths = vRelPaths;
 
			// If the value does not contain entries
			if( aRelPaths.length < 1 ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
		}
 
		// If it has a member named "run_silent"
		if( vArg0.hasOwnProperty( "run_silent" ) ){
			// Get the "run_silent" value
			vSilent = vArg0[ "run_silent" ];
			// If "run_silent" is not a Boolean
			if( typeof( vSilent ) != "boolean" ){
				// Inform the user
				MessageBox.information( text( sMessage ), text( sTitle ), sOk );
 
				// We are done...
				return;
			}
 
			// Capture the value
			bSilent = vSilent;
		}
	}
 
	// If the application version is less than 4.9.3.149
	if( App.version64 < 0x0004000900030095 ){
		// Define our message strings
		sTitle = "Version Error";
		sMessage = String( "This script requires %1 4.9.3.149 or newer to continue." )
						.arg( App.appName )
 
		// If prompts are not being supressed
		if( !bSilent && App.showPrompts() ){
			// Inform the user
			MessageBox.information( text( sMessage ), text( sTitle ), sOk );
		}
 
		// Provide feecback
		print( sTitle, ":", sMessage );
 
		// We are done..
		return;
	}
 
	// If the length of the source and relative path arrays do not match
	if( sTgtPath.isEmpty()
	|| aSrcPaths.length < 1
	|| aSrcPaths.length != aRelPaths.length ){
		// If prompts are not being supressed
		if( !bSilent && App.showPrompts() ){
			// Inform the user
			MessageBox.information( text( sMessage ), text( sTitle ), sOk );
		}
 
		// Provide feedback
		print( sTitle, ":", sMessage );
 
		// We are done...
		return;
	}
 
	// Create a file info object
	var oFileInfo = new DzFileInfo( sTgtPath );
	// Get the absolute path for the target file
	var sFilePath = oFileInfo.absolutePath();
 
	// Create a directory object
	var oDir = new DzDir( sFilePath );
	// If the directory does not exist
	if( !oDir.exists() ){
		// If we cannot create all the missing directories in the path
		if( !oDir.mkpath( sFilePath ) ){
			// Define the message
			sTitle = "Resource Error";
			sMessage = String( "'%1' could not be created." ).arg( sFilePath );
 
			// If prompts are not being supressed
			if( !bSilent && App.showPrompts() ){
				// Inform the user
				MessageBox.warning( text( sMessage ), text( sTitle ), sOk );
			}
 
			// Provide feedback
			print( sTitle, ":", sMessage );
 
			// We are done...
			return;
		}
	}
 
	// Create a zip file object
	var oZipFile = new DzZipFile( sTgtPath );
	// If we cannot open the zip file for writing
	if( !oZipFile.open( DzZipFile.WriteOnly ) ){
		// Define the message
		sTitle = "Resource Error";
		sMessage = String( "'%1' could not be opened for writing." ).arg( sTgtPath );
 
		// If prompts are not being supressed
		if( !bSilent && App.showPrompts() ){
			// Inform the user
			MessageBox.warning( text( sMessage ), text( sTitle ), sOk );
		}
 
		// Provide feedback
		print( sTitle, ":", sMessage );
 
		// We are done...
		return;
	}
 
	// Declare working variables
	var sSrcPath;
	var sRelPath;
	var aRelFilePath;
	var sSrcFilePath;
	var sRelFilePath;
 
	// Initialize
	var bHasFeedback = false;
 
	var oFolderMap = {};
 
	// Let the user know we are busy
	setBusyCursor();
 
	// Create a file info object
	var oFileInfo = new DzFileInfo( "" );
	// Iterate over the paths
	for( var i = 0, n = aSrcPaths.length; i < n; i += 1 ){
		// Get the 'current' source path
		sSrcFilePath = aSrcPaths[i];
		// Get the 'current' relative path
		sRelFilePath = aRelPaths[i];
 
		// If the relative path starts with a slash
		if( sRelFilePath[0] == '/' ){
			// Provide feedback
			print( String( "'%1' contains a leading slash." ).arg( sRelFilePath ) );
			// Update the feedback flag
			bHasFeedback = true;
 
			// Remove the leading slash
			sRelFilePath = sRelFilePath.substring( 1 );
		}
 
		// If the tail of the pair do not match
		if( sSrcFilePath.toLowerCase().lastIndexOf( sRelFilePath.toLowerCase() ) < 0 ){
			// Provide feedback
			print( String( "'%1' is not relative to '%2'." ).arg( sRelFilePath ).arg( sSrcFilePath ) );
			// Update the feedback flag
			bHasFeedback = true;
		}
 
		// Update the file we are interested in
		oFileInfo.setFile( sSrcFilePath );
		// If the file does not exist
		if( !oFileInfo.exists() ){
			// Provide feedback
			print( String( "'%1' does not exist." ).arg( sSrcFilePath ) );
			// Update the feedback flag
			bHasFeedback = true;
 
			// Next!!
			continue;
		}
 
		// If the file is not readable
		if( !oFileInfo.isReadable() ){
			// Provide feedback
			print( String( "'%1' is not readable." ).arg( sSrcFilePath ) );
			// Update the feedback flag
			bHasFeedback = true;
 
			// Next!!
			continue;
		}
 
		// If the file is zero bytes
		if( oFileInfo.size() < 1 ){
			// Provide feedback
			print( String( "'%1' is zero byte." ).arg( sSrcFilePath ) );
			// Update the feedback flag
			bHasFeedback = true;
 
			// Next!!
			continue;
		}
 
		// Split the relative file path into parts
		aRelFilePath = sRelFilePath.split( "/" );
		// We do not want the filename
		aRelFilePath.pop();
 
		// Iterate over the path parts
		for( var j = 0, m = aRelFilePath.length; j < m; j += 1 ){
			// Build the relative in-zip path for the 'current' directory
			sRelPath = aRelFilePath.slice( 0, j + 1 ).join( "/" ) + "/";
 
			// If we have not processed this path yet
			if( !oFolderMap.hasOwnProperty( sRelPath ) ){
				// Get the absolute path for the source directory
				sSrcPath = oFileInfo.absolutePath() + "/";
 
				// Update our folder map
				oFolderMap[ sRelPath ] = sSrcPath;
 
				// If we cannot add the directory to the zip
				if( !oZipFile.addDirToZip( sSrcPath, sRelPath ) ){
					// Provide feedback
					print( String( "'%1' could not be added to '%2'." ).arg( sRelPath ).arg( sTgtPath ) );
					// Update the feedback flag
					bHasFeedback = true;
				}
			}
		}
 
		// If we cannot add the file to the zip
		if( !oZipFile.addFileToZip( sSrcFilePath, sRelFilePath ) ){
			// Provide feedback
			print( String( "'%1' could not be added to '%2'." ).arg( sSrcFilePath ).arg( sTgtPath ) );
			// Update the feedback flag
			bHasFeedback = true;
		}
	}
 
	// Close the zip file
	oZipFile.close();
 
	// Let the user know we are done
	clearBusyCursor();
 
	// If there is feedback to be conveyed to the user,
	// and we are showing prompts
	if( !bSilent && App.showPrompts() ){
		// Define the message
		sTitle = text( "Execution Compete" );
		sMessage = text( "'%1' has been created." ).arg( sTgtPath );
		// If there is feedback to provide
		if( bHasFeedback ){
			// Ammend the message
			sMessage += "\n\n" + text( "Events encountered during the process were written to the application log." );
		}
 
		// Inform the user
		switch( MessageBox.information( sMessage, sTitle, sOk,
					text( "Show..." ), bHasFeedback ? text( "See Log..." ) : "" ) ){
			case 1:
				// Cause the OS file browser to be opened
				App.showInNativeBrowser( sTgtPath );
				break;
			case 2:
				// Cause the file to be opened
				openApplicationLog();
				break;
			default:
				break
		}
	}
 
// Finalize the function and invoke
})( getArguments() );