﻿#target photoshop-120
// (c) Copyright 2016.  Adobe Systems, Incorporated.  All rights reserved.
/*
@@@BUILDINFO@@@ photoshop_v2018.jsx 1.0.1  05-Sep-2017
*/


/*
@@@START_XML@@@
<?xml version="1.0" encoding="UTF-8"?>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en_US">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>This script enables other applications to communicate with Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="fr_FR">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Ce script permet à d'autres applications de communiquer avec Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="ja_JP">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>このスクリプトは、他のアプリケーションと Adobe Photoshop CC 2018 との通信を有効にします。</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="de_DE">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Mithilfe dieses Skripts können andere Anwendungen mit Adobe Photoshop CC 2018 kommunizieren.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="it_IT">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Questo script consente ad altre applicazioni di comunicare con Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="es_ES">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Este script posibilita que otras aplicaciones se comuniquen con Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="nl_NL">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Dit script laat andere toepassingen toe te communiceren met Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="pt_BR">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Este script permite que outros aplicativos se comuniquem com o Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="nb_NO">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Skriptet gjør at andre programmer kan kommunisere med Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="da_DK">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Dette script betyder, at andre programmer kan kommunikere med Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="fi_FI">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Tämän komentosarjan avulla muut sovellukset ja Adobe Photoshop CC 2018 voivat kommunikoida keskenään.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="sv_SE">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Det här skriptet gör det möjligt för andra program att kommunicera med Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="zh_TW">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>此指令碼能讓其他應用程式與 Adobe Photoshop CC 2018 進行通訊。</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="zh_CN">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>此脚本使其它应用程序能够与 Adobe Photoshop CC 2018 进行通信。</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="ko_KR">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>이 스크립트를 사용하면 다른 응용 프로그램에서 Adobe Photoshop CC 2018과(와) 통신할 수 있습니다.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="ar_AE">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>يتيح هذا النص التنفيذي للتطبيقات الأخرى أن تتصل بـ Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="cs_CZ">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Tento skript umožňuje dalším aplikacím komunikovat s aplikací Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="el_GR">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Αυτή η δέσμη ενεργειών δίνει τη δυνατότητα σε άλλες εφαρμογές να επικοινωνούν με το Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="es_MX">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Este script posibilita que otras aplicaciones se comuniquen con Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="fr_CA">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Ce script permet à d'autres applications de communiquer avec Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="fr_XM">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Ce script permet à d'autres applications de communiquer avec Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="he_IL">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>סקריפט זה מאפשר ליישומים אחרים לתקשר עם Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="hu_HU">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Ez a parancsfájl gondoskodik arról, hogy más alkalmazások kommunikálhassanak az Adobe Photoshop CC 2018 programmal.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="pl_PL">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Ten skrypt umożliwia innym aplikacjom komunikowanie się z programem Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="ro_RO">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Acest script permite altor aplicaţii să comunice cu Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="ru_RU">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Этот сценарий позволяет другим приложениям обмениваться данными с Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="tr_TR">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Bu komut dosyası, diğer uygulamaların Adobe Photoshop CC 2018 ile iletişim kurmasını sağlar.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="uk_UA">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Цей сценарій забезпечує обмін даними між Adobe Photoshop CC 2018 та іншими програмами.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en_AE">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>This script enables other applications to communicate with Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en_IL">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>This script enables other applications to communicate with Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
<ScriptInfo xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="fr_MA">
     <dc:title>Adobe Photoshop CC 2018</dc:title>
     <dc:description>Ce script permet à d'autres applications de communiquer avec Adobe Photoshop CC 2018.</dc:description>
</ScriptInfo>
@@@END_XML@@@
*/





// This JavaScript is to be read by Bridge, Photoshop, and other Adobe apps at
// launch. It enables some Photoshop-Bridge integration, such as installing
// the Photoshop automate commands in the Bridge menus, and generally exposes
// a larger Photoshop dom to the other apps.

// debug level: 0-2 (0:disable, 1:break on error, 2:break at beginning)
$.level = 0;
// debugger; // launch debugger on next line

// on localized builds we pull the $$$/Strings from a .dat file
$.localize = true;


//=================================================================
// Setup/Support
// This first portion of the script sets up an object to provide
// scope for all Photoshop BridgeTalk related routines to prevent
// name collision with other groups' scripts, defines some common
// utility functions, and adds some Photoshop related commands
// to the Bridge menus.
//=================================================================


try
{ // Overall try catch


//-----------------------------------------------------------------
// A Note About Exception Handling
//-----------------------------------------------------------------
// If execution of the body of a BridgeTalk message throws an
// exception, it will be silently swept under the carpet and not
// reported to the user. Therefore, many of the functions in here
// which are run as the body of a BridgeTalk message due to a user
// request have an overall try-catch to report such errors.
//
// Exceptions thrown out of Bridge MenuElement onSelect methods are
// also not reported, so they are wrapped in try-catch statements
// here.
//
// The X-DOM functions are not wrapped in try-catch statements so
// it is up to the caller to handle any exceptions if calling X-DOM
// functions via BridgeTalk.
//-----------------------------------------------------------------




// ================================================================
// ================================================================
// ================================================================
// Setup/Initialization
// The code below does basic initialization and setup tasks and
// must appear at the beggining of this script.
// ================================================================
// ================================================================
// ================================================================



try
{ // Inner try-catch to handle version info object disposal

var tempPSVersionInfo = new Object;
tempPSVersionInfo.scriptRevision = 11;
tempPSVersionInfo.btTargetName = 'photoshop'; // no version so BT can resolve to .032 or .064 as needed
tempPSVersionInfo.rootVersion = '120.0'; // no minor version so we can match against .032 or .064 as needed
tempPSVersionInfo.displayVersion = 'CC'; // does not get localized
tempPSVersionInfo.bridgeTargetVersion = '8';
tempPSVersionInfo.bridgeTarget = 'bridge';
tempPSVersionInfo.bridgeDisplayVersion = 'CC'; // does not get localized
tempPSVersionInfo.extensionManagerTargetVersion = '7';
tempPSVersionInfo.extensionManagerTarget = 'exman';


//-----------------------------------------------------------------
// Guard against loading in non-matching version of PS.
// This prevents the CC 2018 (and any future version) startup script
// from clobbering the CC startup script definitions on load (the
// original CC startup script did not have this check).
//-----------------------------------------------------------------

if ((BridgeTalk.appName == "photoshop") && (BridgeTalk.appVersion.indexOf (tempPSVersionInfo.rootVersion) != 0))
	throw localize ("$$$/private/PSBI/Error/NotMatchingPSVersion=This script is not intended for this version of Photoshop. Skipping load.");

//-----------------------------------------------------------------
// Guard against loading script if matching version of PS is not
// installed.
//-----------------------------------------------------------------

// getTargets (0) returns all versions of all apps - see if this version is among them
// Include the root version to make sure we don't match other versions if run in an app that is not
// part of the group
if (BridgeTalk.getTargets (0).join ().indexOf (tempPSVersionInfo.btTargetName + '-' + tempPSVersionInfo.rootVersion) == -1)
	{
	if ((BridgeTalk.appName == "photoshop") && (BridgeTalk.appVersion.indexOf (tempPSVersionInfo.rootVersion) == 0))
		{
		// Something is wrong! BridgeTalk thinks this version of Photoshop is not installed, but it is running this script...
		// Allow the script to load so that the user does not get bizarre JavaScript errors about photoshop not being defined,
		// and can still Browse to Bridge from Photoshop if the Bridge installation is not damaged.
		}
	else
		throw localize ("$$$/PSBI/Error/MatchingPSVersionNotInstalled=The version of Photoshop matching this script (%1) is not installed or its installation is damaged. Please reinstall.", tempPSVersionInfo.rootVersion);
	}

//-----------------------------------------------------------------
// Guard against loading multiple revisions of the same startup
// script. The latest revision will take precedence.
//-----------------------------------------------------------------

if (typeof photoshop != "undefined")
	{
	if ((photoshop.versionInfo.scriptRevision == undefined) ||
		(photoshop.versionInfo.scriptRevision < tempPSVersionInfo.scriptRevision))
		{
		// Delete the 'photoshop' object defined by the CC startup script; we will redefine it.
		delete photoshop;
		
		if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (tempPSVersionInfo.bridgeTargetVersion) == 0))
			{
			// Remove all the menu items installed by the CC startup script; we will create new ones
			// for CC 2018.
			MenuElement.remove ("PlaceInPhotoshop");
			MenuElement.remove ("Photomerge");
			MenuElement.remove ("ContactSheet");
			MenuElement.remove ("PicturePackage");
			MenuElement.remove ("Batch");
			MenuElement.remove ("LoadFilesIntoLayers");
			MenuElement.remove ("LensCorrect");
			MenuElement.remove ("MergeToHDR");
			MenuElement.remove ("ImageProcessor");
			}
		}
	else
		// Bail out right here.
		throw localize ("$$$/PSBI/Error/PSObjectDefined=Object 'photoshop' has already been defined. Older revision ignored.");
	}

}
catch (e)
{
	delete tempPSVersionInfo;
	throw e;
}


//-----------------------------------------------------------------
// Define photoshop object.
//-----------------------------------------------------------------

var photoshop = new Object;
photoshop.versionInfo = tempPSVersionInfo;
delete tempPSVersionInfo;


// Set the photoshop110 object equal to the generic photoshop object
// so photoshop110.foo() can be used.
photoshop110 = photoshop;
	
//-----------------------------------------------------------------
// Throughout this script commands are set up to be added to the
// Tools > Photoshop menu in Bridge. Since Bridge's menu API does
// not support automatic alphabetizing of menu items, we create
// an array with all the necessary menu item info in it, then sort
// it at the end of this script and create all the menu items.
//-----------------------------------------------------------------
photoshop.menuItemInfoArray = new Array ();



//-----------------------------------------------------------------
// An object used to control how UI is used and what behavior is
// chosen when checking to see if the correct version of PS is
// available to run a command.
//-----------------------------------------------------------------
AvailabilityCheckOptions.kBusyAsk = 0;
AvailabilityCheckOptions.kBusyWarn = 1;
AvailabilityCheckOptions.kBusyAutoQueue = 2;
AvailabilityCheckOptions.kBusyAutoCancel = 3;

function AvailabilityCheckOptions (inBusyAction, inWarnIfUnavailable)
	{
	// control how a busy PS is handled	
	this.busyAction = (inBusyAction == null) ? AvailabilityCheckOptions.kBusyAsk : inBusyAction;
	this.warnBusyText = localize ("$$$/PSBI/Error/PSBusyWarn=Photoshop %1 is currently busy with another task. Please finish that task in Photoshop and try again.", photoshop.versionInfo.displayVersion);
	this.askBusyText = localize ("$$$/PSBI/Error/PSBusyAsk=Photoshop %1 is currently busy with another task. Would you like to queue this command?", photoshop.versionInfo.displayVersion);
	
	// control how an uninstalled version of PS is controlled
	this.warnIfUnavailable = (inWarnIfUnavailable == null) ? true : inWarnIfUnavailable;
	this.warnInsidePSText = localize ("$$$/PSBI/Error/OtherVersionRunningInPS=Photoshop %1 is required for this command. Please quit this version and try again.", photoshop.versionInfo.displayVersion);

	// used to prevent UI from being shown twice in same call stack;
	// this gets set and the return value is remembered
	this.alreadyUsed = false;
	this.alreadyUsedReturnValue = false;
	}
	
// ================================================================
// ================================================================
// ================================================================
// CrossDOM/X-DOM
// Implements Photoshop's cross DOM API - the a small set of
// operations that are common to all Adobe apps.
// ================================================================
// ================================================================
// ================================================================

//-----------------------------------------------------------------
// executeScript (script) - Performs an "eval" on the given script.
//
// return value		Object		The value of evaling the last line
//								of the script
// script			String		The script to be evaled
//-----------------------------------------------------------------

photoshop.executeScript = function (script, availabilityCheckOptions)
	{
	// Make sure this can be run.
	if (availabilityCheckOptions == null)
		availabilityCheckOptions = new AvailabilityCheckOptions ();
		
	if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
		return;
		
	if (BridgeTalk.appName != "photoshop")
		{
		// Bring Photoshop to the foreground.
		BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
		
		// Create a new BridgeTalk message for Photoshop to invoke
		// executeScript.
		var btMessage = new BridgeTalk;
		btMessage.target = photoshop.versionInfo.btTargetName;
		btMessage.body = "photoshop.executeScript (" + script.toSource () + ");";
		btMessage.send();
		}
	else
		{
		app.bringToFront();
			
		// This is Photoshop, so just call our DOM routine
		eval (script.toString());
		}
	}

//-----------------------------------------------------------------
// open (files) - Performs the equivalent of File->Open on the
// requested paths. Accepts either an Array object or a single
// path.
//
// return value 	Array of File			an array of all the
//											successfully opened
//											files
// files			File or Array of File	files to open
//-----------------------------------------------------------------

photoshop.open = function (files, availabilityCheckOptions)
	{
	// Make sure this can be run.
	if (availabilityCheckOptions == null)
		availabilityCheckOptions = new AvailabilityCheckOptions ();
		
	if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
		return;
		
	if (BridgeTalk.appName != "photoshop")
		{
		// Bring Photoshop to the foreground.
		BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
		
		// Create a new BridgeTalk message for Photoshop to invoke
		// open.
		var btMessage = new BridgeTalk;
		btMessage.target = photoshop.versionInfo.btTargetName;
		btMessage.body = "photoshop.open (" + files.toSource () + ");";
		btMessage.send();
		}
	else
		{
		app.bringToFront();
			
		// This is Photoshop, so just call our DOM routine with the files		
		var fileArray = photoshop.ExtractFileArray (files); 
		
		for (index = 0; index < fileArray.length; ++index)
			{
			var file = fileArray[index];
			
			app.open (file);
			}
		}
	}

//-----------------------------------------------------------------
// openAsNew ([creation-options]*) - Performs the equivalent of
// File->New. The creation-options are app-specific and should
// ideally map on to the app's new() function. PS has no creation
// options.
//
// return value		Boolean		true if successful
//-----------------------------------------------------------------

photoshop.openAsNew = function (availabilityCheckOptions)
	{
	// Make sure this can be run.
	if (availabilityCheckOptions == null)
		availabilityCheckOptions = new AvailabilityCheckOptions ();
		
	if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
		return;
		
	if (BridgeTalk.appName != "photoshop")
		{
		// Bring Photoshop to the foreground.
		BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
		
		// Create a new BridgeTalk message for Photoshop to invoke
		// open.
		var btMessage = new BridgeTalk;
		btMessage.target = photoshop.versionInfo.btTargetName;
		btMessage.body = "photoshop.openAsNew ();";
		btMessage.send();
		}
	else
		{
		app.bringToFront();
		
		// This is Photoshop, so just call our DOM routine
		app.documents.add ();
		}
	}

//-----------------------------------------------------------------
// print (files) - Performs the equivalent of File->Print on the
// requested files.
//
// return value			Array of File			the array of files
//												successfully
//												printed
// files				File or Array of File	files to be printed
//-----------------------------------------------------------------

photoshop.print = function (files, availabilityCheckOptions)
	{
	// Make sure this can be run.
	if (availabilityCheckOptions == null)
		availabilityCheckOptions = new AvailabilityCheckOptions ();
		
	if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
		return;
		
	if (BridgeTalk.appName != "photoshop")
		{
		// Bring Photoshop to the foreground.
		BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
		
		// Create a new BridgeTalk message for Photoshop to invoke
		// open.
		var btMessage = new BridgeTalk;
		btMessage.target = photoshop.versionInfo.btTargetName;
		btMessage.body = "photoshop.print (" + files.toSource () + ");";
		btMessage.send();
		}
	else
		{
		app.bringToFront();
		
		// This is Photoshop, so just call our DOM routine with the files		
		var fileArray = photoshop.ExtractFileArray (files); 
		
		for (index = 0; index < fileArray.length; ++index)
			{
			var file = fileArray[index];
			
			var document = app.open (file);
			
			if (document != undefined)
				{
				var rememberDialogModes = displayDialogs;
				displayDialogs = DialogModes.ALL;
				document.print ();
				displayDialogs = rememberDialogModes;
				}
			}
		}
	}

//-----------------------------------------------------------------
// quit () - Performs the equivalent of File->Exit or File->Close.
//
//	return value	undefined
//-----------------------------------------------------------------

photoshop.quit = function (availabilityCheckOptions)
	{
	// Make sure this can be run.
	if (availabilityCheckOptions == null)
		availabilityCheckOptions = new AvailabilityCheckOptions (AvailabilityCheckOptions.kBusyWarn, false); // warn if busy, don't warn if wrong version is running
		
	if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
		return;
		
	if (BridgeTalk.appName != "photoshop")
		{
		// Bring Photoshop to the foreground.
		BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
		
		// Create a new BridgeTalk message for Photoshop to invoke
		// open.
		var btMessage = new BridgeTalk;
		btMessage.target = photoshop.versionInfo.btTargetName;
		btMessage.body = "photoshop.quit ();";
		btMessage.send();
		}
	else
		{
		app.bringToFront();
		
		// This is Photoshop, so just call our DOM		
		var quitID = stringIDToTypeID ('quit');
		executeAction (quitID, undefined, DialogModes.NO);
		}
	}

//-----------------------------------------------------------------
// reveal (file) - Gives the target app focus and brings the
// specified document to the foreground if it is already open.
//
// return value		Boolean		true if the file was open and was
//								successfully brought to the
//								foreground
// file				File		file to be revealed
//-----------------------------------------------------------------

photoshop.reveal = function (file, availabilityCheckOptions)
	{
	// Make sure this can be run.
	if (availabilityCheckOptions == null)
		availabilityCheckOptions = new AvailabilityCheckOptions ();
		
	if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
		return;
		
	if (BridgeTalk.appName != "photoshop")
		{
		// Bring Photoshop to the foreground.
		BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
		
		// Create a new BridgeTalk message for Photoshop to invoke
		// open.
		var btMessage = new BridgeTalk;
		btMessage.target = photoshop.versionInfo.btTargetName;
		btMessage.body = "photoshop.reveal (" + file.toSource () + ");";
		btMessage.send();
		}
	else
		{
		app.bringToFront();
		
		// This is Photoshop, so just call our DOM routine with the files		
		// Loop through the open documents looking for the one
		// we want to reveal. If it is found, make it the active
		// document.
		var docNum = app.documents.length - 1;
		
		while (docNum >= 0)
			{
			var document = app.documents[docNum];
			
			// If document is a new unsaved document, accessing
			// document.fullName results in an error. Comparing
			// it to undefined also results in an error, so it
			// is in a try-catch instead.
			try
				{
				if (document.fullName.fsName == file.fsName)
					{
					app.activeDocument = document;
					break;
					}
				}
			catch (e)
				{
				// ignore.
				}
				
			--docNum;
			}
		}
	}
	
	

// ================================================================
// ================================================================
// ================================================================
// Photoshop Commands
// The code below is for functionality which is present in
// Photoshop, such as Browse...
// ================================================================
// ================================================================
// ================================================================


//=================================================================
// Invoking Bridge
// Is called by Photoshop to invoke Bridge.
// Keep deprecated arguments for backwards compatibility with any
// scripts out in the wild.
//=================================================================

photoshop.invokeBridge = function (newWindow_deprecated, maximize_deprecated, path)
	{
	// Make sure this can be run, otherwise alert the user (true for UI).
	if (!photoshop.correctBridgeIsAvailable (false))
		return 0;
	
	// We pass this down to ensure the message we create is based
	// off of whether Bridge was running before we attempted to
	// launch it, not after we attempted to launch it.
	var wasRunning = false;
		
	if (BridgeTalk.isRunning (photoshop.versionInfo.bridgeTarget))
		{
  		wasRunning = true;
		}
  	else
  		{
  		// Make sure we attempt to launch it explicitly. send() will
		// typically do it, but can get confused and not do it under some
		// circumstances, for example if BridgeTalk previously attempted
		// to launch the target but the target never finished launching
		// for whatever reason (maybe another copy is running on Windows).
  		BridgeTalk.launch (photoshop.versionInfo.bridgeTarget);
  		}
	
	// Send an appropriate message to Bridge to tell it what to do.
	var bt = photoshop.getInvokeBridgeMessage (path, wasRunning);
	
	bt.send ();
	return 1;
	}


//=================================================================
// Invoking Extension Manager
// Is called by Photoshop to invoke Extension Manager.
//=================================================================

photoshop.invokeExtensionManager = function ()
	{
	// Make sure this can be run, otherwise, return 0	
	if (!photoshop.correctExtensionManagerIsAvailable() )
		return 0;
	
	// We pass this down to ensure the message we create is based
	// off of whether Bridge was running before we attempted to
	// launch it, not after we attempted to launch it.
	var wasRunning = false;
		
	if (BridgeTalk.isRunning (photoshop.versionInfo.extensionManagerTarget))
		{
  		wasRunning = true;
		}
  	else
  		{
  		// Make sure we attempt to launch it explicitly. send() will
		// typically do it, but can get confused and not do it under some
		// circumstances, for example if BridgeTalk previously attempted
		// to launch the target but the target never finished launching
		// for whatever reason (maybe another copy is running on Windows).
  		BridgeTalk.launch (photoshop.versionInfo.extensionManagerTarget);
  		}
	
	return 1;
	}

//=================================================================
// Launching Bridge
// Is called by Photoshop to launch Bridge in the background at
// startup.
//=================================================================

photoshop.launchBridgeInBackground = function ()
	{
	// Make sure this can be run, don't alert the user if it can't (false for no UI).
	if (!photoshop.correctBridgeIsAvailable (false))
		return;
		
	if (!BridgeTalk.isRunning (photoshop.versionInfo.bridgeTarget))
		{
		BridgeTalk.launch (photoshop.versionInfo.bridgeTarget, 'background');
			
		// On Mac we are able to effectively launch Bridge without Photoshop
		// losing focus, so all we have to do is launch Bridge. On Windows we
		// are not so lucky and must employ some trickery to avoid having
		// Bridge take over as the active app.
		if ($.os.charAt (0) == 'M')
			return;
		
		
		// Win trickery
		
		// Get the version number of Bridge so we can locate its
		// app/user specific startup directory.
		var bridgeSpecifier = BridgeTalk.getSpecifier("bridge", photoshop.versionInfo.bridgeTargetVersion);
		var bridgeVersion = null;
		
		if (bridgeSpecifier != null)
			bridgeVersion = bridgeSpecifier.match (/[0-9\.]+/);
		
		// Define a function that will be run inside of Bridge to make
		// Photoshop come to the foreground. This script will be
		// written to a temporary startup script and will self-delete
		// after run.
		var launchBridgeBehindScript = function (bridgeVersion)
			{
			// On Windows, bringToFront is only effective if the calling app is
			// the foreground app, so it can't be called until Bridge has created
			// a window. So if necessary, we insert a handler function that
			// deletes itself after one execution.
			if (app.documents.length > 0)
				{
				// the document has already been created, so just bring PS to the foreground.
				BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
				return;
				}
			
			// define the handler
			var bringPSForwardOnceHandler = function (event)
				{
				// Run on document creation.
				if (event.object.constructor.name == 'Document' && event.type == 'create')
					{
					// Bring Photoshop to the foreground.
					BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
	
					// Remove this handler once it has run.
					for (var index = 0; index < app.eventHandlers.length; index++)
						{
						if (app.eventHandlers[index] == this)
							{
							app.eventHandlers[index] = null;
							break;
							}
						}
					}
				
				 // Return false so Bridge will keep calling other event handlers.
				return { handled: false };
				}
			
			// Install the event handler.
			app.eventHandlers.push ({handler: bringPSForwardOnceHandler});
			
			} // launchBridgeBehindScript

		
		// Send the script defined above to Bridge for it to execute.
		var bt = new BridgeTalk;
		bt.target = photoshop.versionInfo.bridgeTarget;
		bt.body = 'var func = ' + launchBridgeBehindScript.toString () + 'func ("' + bridgeVersion + '");';
		bt.send ();
	
		} // !BridgeTalk.isRunning (photoshop.versionInfo.bridgeTarget)
	}


// ================================================================
// ================================================================
// ================================================================
// Bridge Commands
// The code below is for functionality which is present in Bridge,
// such as the automation commands and File > Place > In Photoshop.
// ================================================================
// ================================================================
// ================================================================


//=================================================================
// Place
// Sets up Place in Photoshop command in Bridge's Place menu.
//=================================================================

//-----------------------------------------------------------------
// Performs the equivalent of the File->Place
// command on the requested file.
//-----------------------------------------------------------------

photoshop.place = function (file, availabilityCheckOptions, linked)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		// customize the behavior
		availabilityCheckOptions.busyAction = AvailabilityCheckOptions.kBusyWarn;
		availabilityCheckOptions.warnBusyText = localize ("$$$/PSBI/Error/PSBusyWarnPlace=Photoshop %1 is currently busy with another task. Please finish that task in Photoshop, open the document you want to place into, and try again.", photoshop.versionInfo.displayVersion);
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
			
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
			
			// Create a new BridgeTalk message for Photoshop to invoke
			// open.
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.place (" + file.toSource () + "," + availabilityCheckOptions.toSource () + "," + linked + ");";    
			btMessage.send();
			}
		else
			{
			app.bringToFront();
			
			var fileArray = photoshop.ExtractFileArray (file);
				
			// This is Photoshop, so just call our DOM routine with the files		
			if (app.documents.length > 0)
				{
				if (fileArray.length > 0)
					{
					var theFile = fileArray[0];
					
					// Set up generic placement information.
					var offsetID = stringIDToTypeID ('offset');
					var horizID = stringIDToTypeID ('horizontal');
					var vertID = stringIDToTypeID ('vertical');
					var distUnitID = stringIDToTypeID ('distanceUnit');
					
					var offsetDesc = new ActionDescriptor ();
					
					offsetDesc.putUnitDouble (horizID, distUnitID, 0.000000);
					offsetDesc.putUnitDouble (vertID, distUnitID, 0.000000);
					
					var nullID = charIDToTypeID ('null');
					var ftcenterID = stringIDToTypeID ('freeTransformCenterState');
					var quadCenterID = stringIDToTypeID ('quadCenterState');
					var avgID = stringIDToTypeID ('QCSAverage');
					
					var placeInfoDesc = new ActionDescriptor ();
					
					placeInfoDesc.putEnumerated (ftcenterID, quadCenterID, avgID);
					placeInfoDesc.putObject (offsetID, offsetID, offsetDesc);
					
					// Set up the file.
					placeInfoDesc.putPath (nullID, theFile);
					
					// Suppress choose file dialog.
					var overrideOpenID = stringIDToTypeID ('overrideOpen');
					placeInfoDesc.putBoolean (overrideOpenID, true);
					
					// Force it to record.
					var forceRecordKey = stringIDToTypeID ('forceRecording');
					placeInfoDesc.putBoolean (forceRecordKey, true);
					
					// Add whether it's linked or embedded. It's a newer parameter, so handle
					// it being undefined.
					if (linked != undefined)
						{
						var linkedKey = stringIDToTypeID ('linked');
						placeInfoDesc.putBoolean (linkedKey, linked);
						}
					
					// Do the Place.
					var placeID = stringIDToTypeID ('placeEvent');
					
					executeAction (placeID, placeInfoDesc, DialogModes.ALL);
					
					// force deletion of ActionDescriptor now
					offsetDesc = null;
					placeInfoDesc = null;
					$.gc();
					}
				
				if (fileArray.length > 1)
					alert (localize ("$$$/PSBI/Place/OnlyFirstFile=Only the first file was placed."));
				}
			else
				{
				for (index = 0; index < fileArray.length; ++index)
					{
					var file = fileArray[index];
					
					// Open as a Smart Object
					app.open (file, undefined, true);
					}
				}
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}

//-----------------------------------------------------------------
// The code below inserts the Place in Photoshop menu item into the 
// place menu and sets up the onSelect routines for it.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// insert a new Place In Photoshop menu item into the Place submenu.
		var placeMenuItem = MenuElement.create ("command",
												localize ("$$$/PSBI/Menu/Place/InPhotoshop=In Photoshop"),
												'at the end of submenu/Place',
												'PlaceInPhotoshop');
			
		placeMenuItem.onSelect = function ()
			{
			try
				{
				if ((app.document == undefined) || (app.document.visibleThumbnails.length <= 0))
					{
					Window.alert (localize ("$$$/PSBI/Automate/NoFiles=There are no files to process."));
					return;
					}
				
				// check selection length before asking for selections (better performance)
				if (app.document.selectionLength != 1) 
					{
					Window.alert (localize ("$$$/PSBI/Place/SelectOneFile=Please select a single file."));
					return;
					}

				var selections = app.document.selections;
					
				if (!selections[0].container)
					{
					// Make sure this can be run.
					var availabilityCheckOptions = new AvailabilityCheckOptions ();
					
					// customize the behavior
					availabilityCheckOptions.busyAction = AvailabilityCheckOptions.kBusyWarn;
					availabilityCheckOptions.warnBusyText = localize ("$$$/PSBI/Error/PSBusyWarnPlace=Photoshop %1 is currently busy with another task. Please finish that task in Photoshop, open the document you want to place into, and try again.", photoshop.versionInfo.displayVersion);
					
					if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
						return;
					
					var thumb = selections[0];
					app.acquirePhysicalFiles (Array (thumb));
					
					if (thumb.spec == undefined)
						{
						Window.alert (localize ("$$$/PSBI/Place/AliasNotResolved=The alias could not be resolved."));
						return;
						}
						
					
					var file = photoshop.resolveFileIfAlias (thumb.spec);
					
					if (file != null)
						photoshop.place (file, availabilityCheckOptions);
					else
						Window.alert (localize ("$$$/PSBI/Place/AliasNotResolved=The alias could not be resolved."));
					}
				else
					{
					if (app.document.selectionLength == 1)
						Window.alert (localize ("$$$/PSBI/Automate/FoldersNotAllowed=Folders cannot be used for this command."));
					else
						Window.alert (localize ("$$$/PSBI/Place/SelectOneFile=Please select a single file."));
					}
				}
			catch (error)
				{
				if (error.number != 8007) // Don't report user cancelled errors.
					alert (error);
				}
			}
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}

//=================================================================
// saveActiveDocumentAsPSBOnDemand
// Utility function to allow saving in psb file format when necessary
//=================================================================

photoshop.saveActiveDocumentAsPSBOnDemand = function( destPath )
	{
	var startRulerUnits = app.preferences.rulerUnits;
	
	try
		{
		var doc = app.activeDocument;
		
		app.preferences.rulerUnits = Units.PIXELS;

		if (doc.height.value > 30000 || doc.width.value > 30000)
			{
			const eventSave                    = app.charIDToTypeID('save');
			const keyAs                        = app.charIDToTypeID('As  ');
			const keyIn                        = app.charIDToTypeID('In  ');
			const klargeDocumentFormatStr      = app.charIDToTypeID('Pht8'); // NOT defined in PITerminology.h

			app.preferences.rulerUnits = startRulerUnits;

			var desc = new ActionDescriptor();
			var bigDesc = new ActionDescriptor();
			desc.putObject( keyAs, klargeDocumentFormatStr, bigDesc );
			desc.putPath( keyIn, new File( destPath ) );
			executeAction( eventSave, desc, DialogModes.NO );
			}
		else
			{
			app.preferences.rulerUnits = startRulerUnits;

			doc.saveAs( File( destPath ) );
			}
						
		}
	catch (error)
		{
		app.preferences.rulerUnits = startRulerUnits;

		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}
	
//=================================================================
// Photomerge
// Sets up Photoshop's Photomerge automation command to be
// accessed from the Bridge.
//=================================================================

// This is like the version below, but does not open any dialogs.
// It's used for the autoCollections feature in Bridge.
photoshop.noDialogPhotomerge = function( files )
	{
	try
		{
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
			
			// Create a new BridgeTalk message for Photoshop to invoke
			// Photomerge with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.noDialogPhotomerge (" + files.toSource () + ");";		
			btMessage.send ();
			}
		else
			{
			var destPath = files.splice(0,1);
			var gFilesFromBridge = files;

			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strPhotomerge = localize ("$$$/PSBI/Automate/Photomerge/Photoshop/FileName=Photomerge.jsx");
			var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strPhotomerge;

			var ipFile = new File (ipFilePath);

			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.NO;
					
			if (ipFile.exists)
				{
				runphotomergeFromScript = true;
				$.evalFile( ipFilePath );
				photomerge.createPanorama( files );
				photoshop.saveActiveDocumentAsPSBOnDemand(destPath);
				app.activeDocument.close();
				runphotomergeFromScript = false;
				}
			else
				alert (localize ("$$$/PSBI/Automate/Photomerge/NotFound=%1 could not be found.", strPhotomerge));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Photomerge with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.photomerge = function (/* Array */ files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
			
			// Create a new BridgeTalk message for Photoshop to invoke
			// Photomerge with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.photomerge (" + files.toSource () + ");";		
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
			
			var gFilesFromBridge = files;

			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strPhotomerge = localize ("$$$/PSBI/Automate/Photomerge/Photoshop/FileName=Photomerge.jsx");
			var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strPhotomerge;

			var ipFile = new File (ipFilePath);

			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.ALL;
					
			if (ipFile.exists)
				{
				$.evalFile( ipFilePath );
				}
			else
				alert (localize ("$$$/PSBI/Automate/Photomerge/NotFound=%1 could not be found.", strPhotomerge));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}

	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's Photomerge menu item is
// chosen.
//-----------------------------------------------------------------
photoshop.photomergeFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, true);
		
		if (files.length != 0)
			photoshop.photomerge (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Photomerge menu item into the 
// Bridge menus.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/Photomerge=Photomerge...");
		menuItemInfo.name = 'Photomerge';
		menuItemInfo.onSelect = photoshop.photomergeFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}


//=================================================================
// Contact Sheet
// Sets up Photoshop's Contact Sheet automation command to be
// accessed from the Bridge.
//=================================================================

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Contact Sheet with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.contactSheet = function (/* Array */ files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
			
			// Create a new BridgeTalk message for Photoshop to invoke
			// Contact Sheet with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.contactSheet (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
			
			photoshop.runActionCommand ('0B71D221-F8CE-11d2-B21B-0008C75B322C', files);
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's Contact Sheet menu item
// is chosen.
//-----------------------------------------------------------------
photoshop.contactSheetFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.contactSheet (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Contact Sheet menu item into the
// Bridge menus. It requires the optional Photoshop ContactSheetII 
// plug-in to be manually installed by the user. Uncomment the following
// Bridge menu insertion code if you want to invoke such functionality
// directly from Bridge.
//-----------------------------------------------------------------

if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/ContactSheet=Contact Sheet II...");
		menuItemInfo.name = 'ContactSheet';
		menuItemInfo.onSelect = photoshop.contactSheetFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}

//=================================================================
// Picture Package
// Sets up Photoshop's Picture Package automation command to be
// accessed from the Bridge.
//=================================================================

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Picture Package with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.picturePackage = function (/* Array */ files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
			
			// Create a new BridgeTalk message for Photoshop to invoke
			// Picture Package with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.picturePackage (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
			
			photoshop.runActionCommand ('4C1ABF40-DD82-11d2-B20F-0008C75B322C', files);
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's Picture Package menu
// item is chosen.
//-----------------------------------------------------------------
photoshop.picturePackageFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.picturePackage (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the PicturePackage menu item into the
// Bridge menus. It requires the optional Photoshop WebContactSheetII 
// plug-in to be manually installed by the user. Uncomment the following
// Bridge menu insertion code if you want to invoke such functionality
// directly from Bridge.
//-----------------------------------------------------------------

/* -------------------------- START -------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/PicturePackage=Picture Package...");
		menuItemInfo.name = 'PicturePackage';
		menuItemInfo.onSelect = photoshop.picturePackageFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}
----------------------------- END -------------------------------*/


//=================================================================
// Batch
// Sets up Photoshop's Batch automation command to be
// accessed from the Bridge.
//=================================================================

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Batch with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.batch = function (/* Array */ files, availabilityCheckOptions)
	{
	try
		{
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		// Make sure this can be run.
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
			
			// Create a new BridgeTalk message for Photoshop to invoke
			// Batch with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.batch (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
			
			photoshop.runActionCommand ('batch', files,
					localize ("$$$/PSBI/Automate/BatchSettingsFile=Batch via Bridge Settings"));
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's Batch menu item is
// chosen.
//-----------------------------------------------------------------
photoshop.batchFromBridge = function ()
	{
	try
		{
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
		
		// Make sure this can be run.
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.batch (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Batch menu item into the Bridge menus.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/Batch=Batch...");
		menuItemInfo.name = 'Batch';
		menuItemInfo.onSelect = photoshop.batchFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}


//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Load Files into Stacks script with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.loadFilesIntoStack = function (files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
	
			// Create a new BridgeTalk message for Photoshop to invoke
			// LoadFilesIntoStack with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.loadFilesIntoStack (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
	
			// Load Files into Stack script will recognize this and use it
			var gFilesFromBridge = files;
	
			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strFile2Stack = "Load Files into Stack.jsx";
			var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strFile2Stack;
			
			var ipFile = new File (ipFilePath);
			
			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.ALL;
					
			if (ipFile.exists)
				{
				$.evalFile( ipFilePath );
//				alert (localize ("$$$/PSBI/Automate/LoadFiles2Stack/CouldNotOpen=%1 could not be opened.", strFile2Stack));
				}
			else
				alert (localize ("$$$/PSBI/Automate/LoadFiles2Stack/NotFound=%1 could not be found.", strFile2Stack));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's loadFilesIntoStack menu
// item is chosen.
//-----------------------------------------------------------------
photoshop.loadFilesIntoStackFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.loadFilesIntoStack (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Load Files into Photoshop Layers menu item into the
// Bridge menus.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/LoadFilesToLayers=Load Files into Photoshop Layers...");
		menuItemInfo.name = 'LoadFilesIntoLayers';
		menuItemInfo.onSelect = photoshop.loadFilesIntoStackFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}

//=================================================================
// LensCorrect
// Sets up Photoshop's LensCorrect JavaScript to be
// accessed from the Bridge.
//=================================================================

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Lens Correct with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.lensCorrect = function (files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
	
			// Create a new BridgeTalk message for Photoshop to invoke
			// MergeToHDR with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.lensCorrect (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
	
			// Lens Correction script will recognize this and use it
			var gFilesFromBridge = files;
	
			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strLensCorrect = localize ("$$$/private/PSBI/Automate/LensCorrect/Photoshop/FileName=Lens Correct.jsx");
			var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strLensCorrect;
			
			var ipFile = new File (ipFilePath);
			
			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.ALL;
					
			if (ipFile.exists)
				{
				$.evalFile( ipFilePath );
//				alert (localize ("$$$/PSBI/Automate/MergeToHDR/CouldNotOpen=%1 could not be opened.", strMerge2HDR));
				}
			else
				alert (localize ("$$$/PSBI/Automate/MergeToHDR/NotFound=%1 could not be found.", strLensCorrect));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's lensCorrect menu
// item is chosen.
//-----------------------------------------------------------------
photoshop.lensCorrectFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.lensCorrect (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Lens Correction menu item into the
// Bridge menus.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/JavaScripts/LensCorrect/Menu=Lens Correction...");
		menuItemInfo.name = 'LensCorrect';
		menuItemInfo.onSelect = photoshop.lensCorrectFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}


//=================================================================
// MergeToHDR
// Sets up Photoshop's MergeToHDR JavaScript to be
// accessed from the Bridge.
//=================================================================

// This is like the version below, but does not open any dialogs
// in Photoshop.  Used by the autocollections feature in Bridge.
photoshop.noDialogMergeToHDR = function( files )
	{
	try
		{
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
	
			// Create a new BridgeTalk message for Photoshop to invoke
			// MergeToHDR with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.noDialogMergeToHDR (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			// Take the first as the destination
			var destPath = files.splice(0,1);

			// Merge to HDR script will recognize this and use it
			var gFilesFromBridge = files;
	
			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strMerge2HDR = localize ("$$$/PSBI/Automate/MergeToHDR/Photoshop/FileName=Merge To HDR.jsx");
			var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strMerge2HDR;
			
			var ipFile = new File (ipFilePath);
			
			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.NO;	//???
					
			if (ipFile.exists)
				{
				runMergeToHDRFromScript = true;
				$.evalFile( ipFilePath );
				mergeToHDR.mergeFilesToHDR( files, true );
				photoshop.saveActiveDocumentAsPSBOnDemand(destPath);
				app.activeDocument.close(  );
//				alert (localize ("$$$/PSBI/Automate/MergeToHDR/CouldNotOpen=%1 could not be opened.", strMerge2HDR));
				runMergeToHDRFromScript = false;
				}
			else
				alert (localize ("$$$/PSBI/Automate/MergeToHDR/NotFound=%1 could not be found.", strMerge2HDR));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke MergeToHDR with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.mergeToHDR = function (files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
	
			// Create a new BridgeTalk message for Photoshop to invoke
			// MergeToHDR with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.mergeToHDR (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
	
			// Merge to HDR script will recognize this and use it
			var gFilesFromBridge = files;
	
			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strMerge2HDR = localize ("$$$/PSBI/Automate/MergeToHDR/Photoshop/FileName=Merge To HDR.jsx");
			var ipFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strMerge2HDR;
			
			var ipFile = new File (ipFilePath);
			
			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.ALL;
					
			if (ipFile.exists)
				{
				$.evalFile( ipFilePath );
//				alert (localize ("$$$/PSBI/Automate/MergeToHDR/CouldNotOpen=%1 could not be opened.", strMerge2HDR));
				}
			else
				alert (localize ("$$$/PSBI/Automate/MergeToHDR/NotFound=%1 could not be found.", strMerge2HDR));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's mergeToHDR menu
// item is chosen.
//-----------------------------------------------------------------
photoshop.mergeToHDRFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.mergeToHDR (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Merge to HDR menu item into the
// Bridge menus.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/MergeToHDR=Merge to HDR Pro...");
		menuItemInfo.name = 'MergeToHDR';
		menuItemInfo.onSelect = photoshop.mergeToHDRFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}


//=================================================================
// ImageProcessor
// Sets up Photoshop's Image Processor JavaScript to be
// accessed from the Bridge.
//=================================================================

//-----------------------------------------------------------------
// This routine takes an array of files. If called by Photoshop,
// it will invoke Image Processor with the files. If called by
// any other app, it will send a BridgeTalk message to Photoshop
// to invoke this routine with the same arguments.
//-----------------------------------------------------------------
photoshop.imageprocessor = function (files, availabilityCheckOptions)
	{
	try
		{
		// Make sure this can be run.
		if (availabilityCheckOptions == null)
			availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		if (BridgeTalk.appName != "photoshop")
			{
			// Bring Photoshop to the foreground.
			BridgeTalk.bringToFront (photoshop.versionInfo.btTargetName);
	
			// Create a new BridgeTalk message for Photoshop to invoke
			// Image Processor with the selected files
			var btMessage = new BridgeTalk;
			btMessage.target = photoshop.versionInfo.btTargetName;
			btMessage.body = "photoshop.imageprocessor (" + files.toSource () + ");";
			btMessage.send ();
			}
		else
			{
			app.bringToFront();
	
			// Image Processor script will recognize this and use it
			var gFilesFromBridge = files;
	
			var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
			var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
			var strImageProcessor = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/FileName=Image Processor.jsx");
			
			var ipFile = new File (app.path + "/" + strPresets + "/" + strScripts + "/" + strImageProcessor);
			
			var rememberDialogModes = displayDialogs;
			displayDialogs = DialogModes.ALL;
					
			if (ipFile.exists)
				{
				if (ipFile.open ('r'))
					{
					var script = ipFile.read ();
					ipFile.close ();
					eval (script);
					}
				else
					alert (localize ("$$$/PSBI/Automate/ImageProcessor/CouldNotOpen=Image Processor.jsx could not be opened."));
				}
			else
				alert (localize ("$$$/PSBI/Automate/ImageProcessor/NotFound=Image Processor.jsx could not be found."));
	
			displayDialogs = rememberDialogModes;
			}
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// This routine is called when the Bridge's Image Processor menu
// item is chosen.
//-----------------------------------------------------------------
photoshop.imageprocessorFromBridge = function ()
	{
	try
		{
		// Make sure this can be run.
		var availabilityCheckOptions = new AvailabilityCheckOptions ();
			
		if (!photoshop.correctPSIsAvailable (availabilityCheckOptions))
			return;
		
		var files = photoshop.getBridgeFileListForAutomateCommand (true, false);
		
		if (files.length != 0)
			photoshop.imageprocessor (files, availabilityCheckOptions);
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// The code below inserts the Image Processor menu item into the
// Bridge menus.
//-----------------------------------------------------------------
if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// Set up the info necessary for inserting this item into the Bridge's menus later.
		var menuItemInfo = new Object;
		menuItemInfo.text = localize ("$$$/PSBI/Menu/Automate/ImageProcessor=Image Processor...");
		menuItemInfo.name = 'ImageProcessor';
		menuItemInfo.onSelect = photoshop.imageprocessorFromBridge;
		
		photoshop.menuItemInfoArray.push (menuItemInfo);
		}
	
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}

//=================================================================
// Setup Tools > Photoshop menu in Bridge.
// Creates the menu, then sorts all the menu items we want to
// create before actually adding them to the menu.
//=================================================================

if ((BridgeTalk.appName == "bridge") && (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.bridgeTargetVersion) == 0))
	{
	
	// Use temp function to keep vars out of global namespace.
	photoshop.tempFunction = function ()
		{
		// The 'Photoshop Services' menu is installed by OLS, the 'Photoshop' menu
		// in installed either by this script, or by the Workflow Automation Scripts
		// (AdobeLibrary1.jsx) which also install menus for other apps. To get the
		// menus in the correct order, all three scripts cooperate - so make sure
		// you are aware of what's happening before changing this code.
		var psServicesMenuExists = MenuElement.find ('Tools/PhotoshopServices') != null;
		
		// Add a new Photoshop submenu in the Bridge's Tools menu.
		var photoshopSubMenu = MenuElement.create (	"menu",
												localize ("$$$/PhotoshopJSX/Menu/Photoshop=Photoshop"),
												psServicesMenuExists ? "-after Tools/PhotoshopServices" : '-after submenu/VersionCue',
												'tools/ps');
			
		
		// Define a function that will sort the menu items for us.
		function menuTextOrder (a, b)
			{
			// Pass 'a' into 'b' to get reverse sort order so that they can be
			// added at the top of the menu and still be in alphabetical order
			// (the WAS scripts install additional menu items that end up below
			// these).
			return b.text.toLocaleLowerCase ().localeCompare (a.text.toLocaleLowerCase ());
			}
		
		// Sort the menu items
		photoshop.menuItemInfoArray.sort (menuTextOrder);
		
		// Add the menu items to the Photoshop menu.
		for (var index = 0; index < photoshop.menuItemInfoArray.length; index++)
			{
			var menuItemInfo = photoshop.menuItemInfoArray[index];

			var menuItem = MenuElement.create (	'command',
												menuItemInfo.text,
												'at the beginning of tools/ps',
												menuItemInfo.name);
			
			menuItem.onSelect = menuItemInfo.onSelect;	
			}
		
		// delete photoshop.menuItemInfoArray; keep this around so we can add Optional plug-ins later
		}
		
	photoshop.tempFunction ();
	delete photoshop.tempFunction;
	}


//-----------------------------------------------------------------
// Opens 'file' using provided ACR descriptor and dialogMode,
// if non-null. Provides lightroom doc id, BridgeTalk id, and save
// descriptor to the app so that it can track them. saveDesc is
// used to specify the save location, format, and options when
// the file is saved, and the lightroom doc id and BridgeTalk id
// are used to notify Lightroom when the file is saved or closed
// (see notifyLightroomDocSaved and notifyLightroomDocClosed).
//-----------------------------------------------------------------

photoshop.openFromLightroom = function (file,					// required. file to open
										acrDesc,			// optional. pass acr descriptor to have PS open file with custom ACR settings
										lightroomDocID,	// optional. include for notifications on save and close
										bridgeTalkID,		// required if lightroomDocID is present. Pass sending app's BT id
										saveDesc,			// optional. pass save desc to have PS use provided format, location, etc for save
										dialogMode)		// optional. defaults to DisplayDialogs.ERROR. used by M2HDR and Photomerge scripts
	{
	var result = false;
		
	// use ERROR dialog mode unless otherwise requested. This will show things like
	// color profile mismatch and missing font dialogs,
	if (dialogMode == null)
		dialogMode = DialogModes.ERROR;

	try
		{
		// construct an open descriptor with all of the info provided
		var openDesc = new ActionDescriptor();
		
		// add the file to open
		openDesc.putPath (stringIDToTypeID ("target"), file);
		
		// force the open to be recorded if recording is on
		openDesc.putBoolean (stringIDToTypeID ("forceRecording"), true);
		
		// Use ACR open parameters descriptor if provided
		if (acrDesc != null)
			{
			openDesc.putObject (stringIDToTypeID("as"), stringIDToTypeID("Adobe Camera Raw"), acrDesc); 
			}
		
		// include the info needed for PS to track the file and notify LR on save and/or close
		if ((lightroomDocID != null) && (bridgeTalkID != null))
			{
			openDesc.putString (stringIDToTypeID ("lightroomDocID"), lightroomDocID);
			openDesc.putString (stringIDToTypeID ("lightroomBridgetalkID"), bridgeTalkID);
			}
	
		// Use save desriptor if provided. At minimum, should include 'as' (format) and
		// 'in' (save location) entries as well as any sub-entries to the format object
		// that are required to keep the options dialog from showing for the format.
		if (saveDesc != null)
			{
			openDesc.putObject (stringIDToTypeID ('lightroomSaveParams'), stringIDToTypeID ('save'), saveDesc);	
			}
		
		// open the file and return the result (Photomerge and Merge To HDR need the value)
		result = app.executeAction (stringIDToTypeID( "open" ), openDesc, dialogMode);
		}
	catch (error)
		{
		if (dialogMode != DialogModes.NO)
			{
			if (error.number != 8007) // Don't report user cancelled errors.
				alert (error);
			}
		}
	
	return result;
	}

//-----------------------------------------------------------------
// Runs Merge to HDR script, providing it with all the parameters
// to this method. Merge to HDR uses them when opening files,
// by invoking openFromLightroom(). See that method for argument
// descriptions.
//-----------------------------------------------------------------

photoshop.mergeToHDRFromLightroom = function (	files,
												acrDescs,
												lightroomDocID,
												bridgeTalkID,
												saveDesc)
	{
	try
		{
		// Merge to HDR script will recognize these and use them
		var gFilesFromLightroom = files;
		var gOpenParamsFromLightroom = acrDescs;
		var gLightroomDocID = lightroomDocID;
		var gBridgeTalkID = bridgeTalkID;
		var gLightroomSaveParams = saveDesc;

		var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
		var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
		var strMerge2HDR = localize ("$$$/PSBI/Automate/MergeToHDR/Photoshop/FileName=Merge To HDR.jsx");
		var scriptFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strMerge2HDR;
		
		var scriptFile = new File (scriptFilePath);
		
		var rememberDialogModes = displayDialogs;
		displayDialogs = DialogModes.ALL;
				
		if (scriptFile.exists)
			{
			$.evalFile( scriptFilePath );
			}
		else
			alert (localize ("$$$/PSBI/Automate/MergeToHDR/NotFound=%1 could not be found.", strMerge2HDR));

		displayDialogs = rememberDialogModes;
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}


//-----------------------------------------------------------------
// Runs Load Files into Stack script, providing it with all the parameters
// to this method. 
//-----------------------------------------------------------------

photoshop.openAsLayersFromLightroom = function ( files,
												 acrDescs,
												 lightroomDocID,
												 bridgeTalkID,
												 saveDesc)
	{
	try
		{
		// OpenAsLayers for lightroom
		var gFilesFromLightroom = files;
		var gOpenParamsFromLightroom = acrDescs;
		var gLightroomDocID = lightroomDocID;
		var gBridgeTalkID = bridgeTalkID;
		var gLightroomSaveParams = saveDesc;

		var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
		var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
		var strOpenAsLayers = "Load Files into Stack.jsx";
		var scriptFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strOpenAsLayers;
		
		var scriptFile = new File (scriptFilePath);
		
		var rememberDialogModes = displayDialogs;
		displayDialogs = DialogModes.ALL;
				
		if (scriptFile.exists)
			{
			$.evalFile( scriptFilePath );
			}
		else
			alert (localize ("$$$/PSBI/Automate/MergeToHDR/NotFound=%1 could not be found.", strOpenAsLayers));

		displayDialogs = rememberDialogModes;
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}

//-----------------------------------------------------------------
// Runs Photomerge script, providing it with all the parameters
// to this method. Photomerge uses them when opening files,
// by invoking openFromLightroom().
//-----------------------------------------------------------------

photoshop.photomergeFromLightroom = function (	files,
												acrDescs,
												lightroomDocID,
												bridgeTalkID,
												saveDesc)
	{
	try
		{
		//  Photomerge script will recognize these and use them
		var gFilesFromLightroom = files;
		var gOpenParamsFromLightroom = acrDescs;
		var gLightroomDocID = lightroomDocID;
		var gBridgeTalkID = bridgeTalkID;
		var gLightroomSaveParams = saveDesc;

		var strPresets = localize ("$$$/ApplicationPresetsFolder/Presets=Presets");
		var strScripts = localize ("$$$/PSBI/Automate/ImageProcessor/Photoshop/Scripts=Scripts");
		var strPhotomerge = localize ("$$$/PSBI/Automate/Photomerge/Photoshop/FileName=Photomerge.jsx");
		var scriptFilePath = app.path + "/" + strPresets + "/" + strScripts + "/" + strPhotomerge;

		var scriptFile = new File (scriptFilePath);

		var rememberDialogModes = displayDialogs;
		displayDialogs = DialogModes.ALL;
				
		if (scriptFile.exists)
			{
			$.evalFile( scriptFilePath );
			}
		else
			alert (localize ("$$$/PSBI/Automate/Photomerge/NotFound=%1 could not be found.", strPhotomerge));
	
		displayDialogs = rememberDialogModes;
		}
	catch (error)
		{
		if (error.number != 8007) // Don't report user cancelled errors.
			alert (error);
		}
	}

//-----------------------------------------------------------------
// Notify 'bridgeTalkID' that the tracked file was
// saved. Puts together an XML string including
// 'lightroomDocID' and 'path' that Lightroom will
// understand.
//-----------------------------------------------------------------

photoshop.notifyLightroomDocSaved = function (bridgeTalkID, lightroomDocID, path)
	{
	if (BridgeTalk.isRunning (bridgeTalkID))
		{
		// Create a new BridgeTalk message to notify Lightroom with
		var msg = new BridgeTalk;
		
		// use the BT id that was initially provided by LR
		msg.target = bridgeTalkID;
		
		// set a custom message type so that the message body does not get translated
		// in preperation for evaluation as JavaScript
		msg.type = 'PsXmlNotification';
		
		// Create a File object and pull fsName out of it so that we end up with a POSIX style path on the Mac.
		var file = new File (path);
		
		// retrieve full path in URI notation: absolute, platform-independent, and escaped
		var preparedPath = file.toString ();
		
		// Get the substance of the notification
		msg.body = photoshop.createLightroomNotificationXML (	'FileSaved',
																lightroomDocID,
																preparedPath);
		
		msg.send();
		}
	}


//-----------------------------------------------------------------
// Notify 'bridgeTalkID' that the tracked file was
// closed. Puts together an XML string including
// 'lightroomDocID' that Lightroom will understand.
//-----------------------------------------------------------------
photoshop.notifyLightroomDocClosed = function (bridgeTalkID, lightroomDocID)
	{	
	if (BridgeTalk.isRunning (bridgeTalkID))
		{
		// Create a new BridgeTalk message to notify Lightroom with
		var msg = new BridgeTalk;
		
		// use the BT id that was initially provided by LR
		msg.target = bridgeTalkID;
		
		// set a custom message type so that the message body does not get translated
		// in preperation for evaluation as JavaScript
		msg.type = 'PsXmlNotification';
		
		// Get the substance of the notification
		msg.body = photoshop.createLightroomNotificationXML (	'FileClosed',
																lightroomDocID);										
		
		msg.send();
		}
	}


//-----------------------------------------------------------------
// Notify 'bridgeTalkID' that the file was not opened.
// Puts together an XML string including
// 'lightroomDocID' that Lightroom will understand.
//-----------------------------------------------------------------
photoshop.notifyLightroomDocNotOpened = function (bridgeTalkID, lightroomDocID, reason)
	{	
	if (BridgeTalk.isRunning (bridgeTalkID))
		{
		// Create a new BridgeTalk message to notify Lightroom with
		var msg = new BridgeTalk;
		
		// use the BT id that was initially provided by LR
		msg.target = bridgeTalkID;
		
		// set a custom message type so that the message body does not get translated
		// in preperation for evaluation as JavaScript
		msg.type = 'PsXmlNotification';
		
		// Get the substance of the notification
		msg.body = photoshop.createLightroomNotificationXML (	'FileNotOpened',
																lightroomDocID,
																null,
																reason);										
		
		msg.send();
		}
	}

// ================================================================
// ================================================================
// ================================================================
// Utility Routines
// ================================================================
// ================================================================
// ================================================================
	

//-----------------------------------------------------------------
// This routine takes an array of thumbnails and returns an array of the
// files represented by those thumbnail objects.
//-----------------------------------------------------------------
photoshop.thumbnailArrayToFileArray = function (/* array of thumbnails */ thumbnails, resolveAliases, requireTwoFiles)
	{
	var thumbsArray = new Array ();
	var filesArray = new Array ();
	
	var foundFolder = false;
	
	for (var index = 0; index < thumbnails.length; index++ )
		{
		// Don't add containers to the list, but note if any were found.
		if (thumbnails[index].container)
			foundFolder = true;
		else
			thumbsArray.push (thumbnails[index]);
		}
	
	if (thumbsArray.length == 0)
		{
		if (foundFolder)
			Window.alert (localize ("$$$/PSBI/Automate/FoldersNotAllowed=Folders cannot be used for this command."));
		else
			Window.alert (localize ("$$$/PSBI/Automate/NoFiles=There are no files to process."));
		}
	else if (requireTwoFiles && (thumbsArray.length == 1))
		{
		Window.alert (localize ("$$$/PSBI/Automate/MoreThanOneRequired=This command requires two or more files."));
		}
	else
		{
		// We have adequate files, now acquire them (make sure VC files have
		// a local replica) and then grab the file specs.
		app.acquirePhysicalFiles (thumbsArray);
		
		var foundAlias = false;
		
		for (var index = 0; index < thumbsArray.length; index++ )
			{
			if (thumbsArray[index].spec != undefined)
				{
				var file = thumbsArray[index].spec;
				
				if (resolveAliases && file.alias)
					{
					foundAlias = true;
					
					file = photoshop.resolveFileIfAlias (file);
					}
				
				if (file != null)
					filesArray.push (file);
				}
			}
	
		// The only way filesArray.length should be zero here is if an alias could not be resolved.
		// or acquire failed for some reason.
		if (filesArray.length == 0)
			Window.alert (localize ("$$$/PSBI/Automate/AliasNotResolved=The alias(es) could not be resolved and there are no other files to process."));
		}
		
	return filesArray;
	}

//-----------------------------------------------------------------
// This routine returns the selected files, or if no files are selected,
// all the files.
//-----------------------------------------------------------------
photoshop.getBridgeFileListForAutomateCommand = function (resolveAliases, requireTwoFiles)
	{	
	var files = new Array;
	var warnNoFiles = false;
	
	if ((app.document != undefined) && (app.document.thumbnail != undefined))
		{
		if (app.document.selectionLength > 0)
			{
			files = photoshop.thumbnailArrayToFileArray (app.document.selections, resolveAliases, requireTwoFiles);
			}
		else if (app.document.visibleThumbnails.length > 0)
			{
			files = photoshop.thumbnailArrayToFileArray (app.document.visibleThumbnails, resolveAliases, requireTwoFiles);
			}
		else
			warnNoFiles = true;
		}
	else
		warnNoFiles = true;
	
	if (warnNoFiles)
		Window.alert (localize ("$$$/PSBI/Automate/NoFiles=There are no files to process."));
		
	return files;
	}
	
//-----------------------------------------------------------------
// This routine tries to return an array of File objects created
// from the 'files' argument. It will convert a single File object
// or a single string into an array of File objects, or it will
// convert an array of string and File objects into an array of
// file objects.
//-----------------------------------------------------------------
photoshop.ExtractFileArray = function (files)
	{
	var fileArray = new Array;
	
	// If it isn't an array, make it a length one array.
	if (!(files instanceof Array))
		files = new Array (files);
	
	// Turn each item in the array into a File, or remove it.
	for (index = 0; index < files.length; ++index)
		{
		var file = files[index];
		
		if (file instanceof File)
			fileArray.push (file);
		else if (typeof file == 'string')
			fileArray.push (File (file));
		else
			{
			// do nothing
			}
		}
	
	return fileArray;
	}
	
//-----------------------------------------------------------------
// This routine executes the specified action. If 'settingsFileName'
// is provided, it uses any saved settings combined with the new
// file list, then saves the updated settings.
//-----------------------------------------------------------------
photoshop.runActionCommand = function (eventString,
										files,
										settingsFileName)
	{
	var eventDesc = null;
	
	// Read in the old settings, if asked.
	if (settingsFileName != null)
		eventDesc = photoshop.readDescriptor (settingsFileName);
	
	// If this is the first time we've run, there won't be a settings
	// file, so create a new blank descriptor.
	if (eventDesc == null)
		eventDesc = new ActionDescriptor ();
	
	if (files != null)
		{
		// Create an action list with the provided files and add them
		// to the descriptor, overriding any previous ones that might
		// have been there.
		var filesListKey = stringIDToTypeID ('filesList');
		var filesList = new ActionList ();
	
		for (var index = 0; index < files.length; index++)
			filesList.putPath (files[index]);
		
		eventDesc.putList (filesListKey, filesList);
		
		filesList = null; // garbage collect this below
		}
	
	// Force it to record.
	var forceRecordKey = stringIDToTypeID ('forceRecording');
	eventDesc.putBoolean (forceRecordKey, true);
	
	// Run the action.
	var eventKey = stringIDToTypeID (eventString);
	var resultDesc = executeAction (eventKey, eventDesc, DialogModes.ALL);
	
	// Don't record the action for Batch
	if (eventString == 'batch')
		resultDesc.erase (stringIDToTypeID ('using'));
	
	// Save the descriptor for next time, if asked.
	if (settingsFileName != null)
		photoshop.saveDescriptor (settingsFileName, resultDesc);
	
	// force deletion of descriptor and list now
	eventDesc = null;
	$.gc();
	}
	
//-----------------------------------------------------------------
// This routine saves the given descriptor to a settings file using
// the given name.
//-----------------------------------------------------------------
photoshop.saveDescriptor = function (name, descriptor)
	{
	// try-catch this routine so if something goes terribly wrong
	// we can still run the command.
	try
		{
		if ((descriptor == null) || (descriptor.count == 0))
			return;
			
		var folder = photoshop.getActionCmdSettingsFolder ();
			
		if (!folder.exists && !folder.create ())
			return;
			
		var stream = descriptor.toStream ();
			
		var file = new File (folder.fsName + "/" + name + '.psp');
		
		if (file.open ('w'))
			{
			file.encoding = 'BINARY';
			file.write (stream);
			file.close ();
			}
		}
	catch (e)
		{
		return null;
		}
	}
	
//-----------------------------------------------------------------
// This routine retrieves a descriptor from a settings file using
// the given name. A descriptor ought to have been previously saved
// under the same name using saveDescriptor ().
//-----------------------------------------------------------------
photoshop.readDescriptor = function (name)
	{
	// try-catch this routine so if something goes terribly wrong
	// we can still run the command.
	try
		{
		var folder = photoshop.getActionCmdSettingsFolder ();
	
		var file = new File (folder.fsName + "/" + name + '.psp');
		
		if (!file.exists)
			return null;
			
		if (!file.open ('r'))
			return null;
			
		file.encoding = 'BINARY';
		var stream = file.read (file.length);
		file.close ();
		
		var descriptor = new ActionDescriptor ();
		descriptor.fromStream (stream);
		
		return descriptor;
		}
	catch (e)
		{
		return null;
		}
	}
	
//-----------------------------------------------------------------
// This routine retrieves a descriptor from a settings file using
// the given name. A descriptor ought to have been previously saved
// under the same name using saveDescriptor ().
//-----------------------------------------------------------------
photoshop.getActionCmdSettingsFolder = function ()
	{
	var settingsFolder = new Folder (app.preferencesFolder);
	
	if (!settingsFolder.exists)
		settingsFolder.create ();
	
	return settingsFolder;
	}


//-----------------------------------------------------------------
// This routine creates and returns a BridgeTalk message that will
// invoke Bridge and tell it what to do based on the arguments. It
// is wrapped in a utility function because it is used by multiple
// other routines.
//-----------------------------------------------------------------
photoshop.getInvokeBridgeMessage = function (path, wasRunning)
	{
	var bt = new BridgeTalk;
	bt.target = photoshop.versionInfo.bridgeTarget;
	
	// If there is no path, we want to pass nothing to Bridge's routines,
	// not an empty File object.
	var file = '';
	
	// toSource is our friend. The 'path' string may have quotes (single or double)
	// in it that start messing things up if we want to use it as part of a bigger
	// string (in particular part of a BridgeTalk message body); specifically, string
	// literals can get terminated early leading to syntax errors. So, we create
	// a File object out of it and call toSource on the File object to get back a
	// string that can be used as part of a larger string (nasty characters like
	// quotes will be replaced with URL friendly equivalents).
	// encodeURI does us one better in making sure some additional characters pass
	// across the wire successfully.
	if (path != null && path != '')
		file = File (encodeURI(path)).toSource ();

	if (wasRunning)
		{
		// Create a function that we can pass across to Bridge in a BridgeTalk message.
		// This allows us to write more freely than trying to construct a string with it.
		// Comments in this function must be of the /* */ form because toSource() is
		// not preserving white space so // comments will kill subsequent lines
		var bridgeScript = function (file)
			{
			if (file != null)
				{
				if (app.documents.length > 0)
					{
					/* New location for existing window, make sure existing window comes forward */
					app.document.thumbnail = new Thumbnail (file); 
					app.document.bringToFront();
					}
				else
					{
					/*
					New window with location.
					Bring new window to front is required if BR is minimized on Windows
					*/
					var newDoc = new Document (file);
					newDoc.bringToFront();
					}
				}
			else
				{
				if (app.documents.length == 0)
					{
					/*
					New window with default location, only occurs on Mac where you can have zero BR windows.
					Document constructor requires a parameter
					*/
					new Document (File()); 
					}
				else
					{
					/* Just bring the exist doc forward at it's existing location */
					app.document.bringToFront();
					}
				}

			} // bridgeScript

		// Turn the function into a string and call it directy with the appropriate parameters
		bt.body = bridgeScript.toSource() + "(" + file + ")";

		}
	else
		{
		// New location for default window
		bt.body = "app.document.thumbnail = new Thumbnail (" + file + ");";		
		}
	
	return bt;
	}
	
//-----------------------------------------------------------------
// Returns true if the required version of Bridge is installed.
//-----------------------------------------------------------------

photoshop.correctBridgeIsAvailable = function (showUI)
	{
	var result = false;
	
	if (BridgeTalk.isRunning (photoshop.versionInfo.bridgeTarget))
		{
		// It's running, so it is definitely available!
		result = true;
		}
	else
		{
		// We cannot ask for the Bridge specifier in a minor-version agnostic way, so now that
		// Bridge uses specifiers like bridge-5.032 and bridge-5.064 we can't simply see if
		// BridgeTalk.getSpecifier ('bridge', photoshop.versionInfo.bridgeTargetVersion) returns
		// null. Instead, ask for the specifier without a version which should give us back a
		// version associated with this version of Photoshop. Then test to ensure the version
		// matches what we expect.
		var bridgeSpecifier = BridgeTalk.getSpecifier ('bridge');
		
		var expectedSpecifierStart = 'bridge-' + photoshop.versionInfo.bridgeTargetVersion;
		
		if (bridgeSpecifier == null ||
			bridgeSpecifier.indexOf (expectedSpecifierStart) != 0)
			{
			if (showUI)
				alert (localize ("$$$/PSBI/Error/MatchingBridgeVersionNotInstalled=Bridge %1 was not found on this system. To use this command, please reinstall Bridge %1.", photoshop.versionInfo.bridgeDisplayVersion));
				
			result = false;
			}
		else
			{
			// The target version is installed and should be launchable, unless a different version
			// is running, which we cannot reliable detect. Hope that is not the case.
			result = true;
			}
		}
		
	return result;
	}


//-----------------------------------------------------------------
// Returns true if the required version of Bridge is installed.
//-----------------------------------------------------------------

photoshop.correctExtensionManagerIsAvailable = function ()
	{
	var result = false;
	
	if (BridgeTalk.isRunning (photoshop.versionInfo.extensionManagerTarget))
		{
		// It's running, so it is definitely available!
		result = true;
		}
	else
		{
		// extension manager uses moniker like exman-7.0
		var bridgeSpecifier = BridgeTalk.getSpecifier ('exman');
		
		var expectedSpecifierStart = 'exman-' + photoshop.versionInfo.extensionManagerTargetVersion;
		
		if (bridgeSpecifier == null ||
			bridgeSpecifier.indexOf (expectedSpecifierStart) != 0)
			{
				// extension manager is not installed
				result = false;
			}
		else
			{
			// The target version is installed and should be launchable, unless a different version
			// is running, which we cannot reliable detect. Hope that is not the case.
			result = true;
			}
		}
		
	return result;
	}


//-----------------------------------------------------------------
// Returns true if the required version of Photoshop is available
// to execute a command in the sense that it is installed and
// running or can be launched. It also indicates that it is
// ready to process a command (not busy) or that the user has
// requested that the command be queued even though Photoshop is
// busy.
//-----------------------------------------------------------------

photoshop.correctPSIsAvailable = function (checkOptions)
	{
	// If no options are passed in, use default ones.
	if (checkOptions == null)
		{
		checkOptions = new AvailabilityCheckOptions ();
		}
	else
		{
		if (checkOptions.alreadyUsed == true)
			return checkOptions.alreadyUsedReturnValue;
		}
	
	var result = false;
		
	// No need to check to see if the correct version is installed because if it
	// isn't installed then this script doesn't get loaded, except inside of the 
	// correct version of Photoshop if it really is installed (and its registration
	// with BridgeTalk is broken).
	
	if (BridgeTalk.appName == "photoshop")
		{
		if (BridgeTalk.appVersion.indexOf (photoshop.versionInfo.rootVersion) == 0)
			{
			// This script is running in the target version of PS.
			result = true;
			}
		else
			{
			// We are running inside a different version of PS than what is required. This really
			// shouldn't happen because this script shouldn't load in a version other than
			// the required version.
			if (checkOptions.warnIfUnavailable)
				alert (checkOptions.warnInsidePSText);
			}
		}
	else if (BridgeTalk.isRunning (photoshop.versionInfo.btTargetName))
		{
		// Above is a quick test to see if it is running. If it is, it can be messaged if necessary.
		var status = BridgeTalk.ping (photoshop.versionInfo.btTargetName, "STATUS");
		
		if (status != "IDLE")
			{
			if (checkOptions.busyAction == AvailabilityCheckOptions.kBusyWarn)
				{
				alert (checkOptions.warnBusyText);
				result = false;
				}
			else if (checkOptions.busyAction == AvailabilityCheckOptions.kBusyAsk)
				{
				result = confirm (checkOptions.askBusyText);
				}
			else if (checkOptions.busyAction == AvailabilityCheckOptions.kBusyAutoQueue)
				result = true;
			else	// AvailabilityCheckOptions.kBusyAutoCancel
				result = false;
			}
		else
			result = true;
		}
	else
		{
		// The target version is installed and should be launchable, unless a different version
		// is running, which we cannot reliable detect. Hope that is not the case.
		result = true;
		}
		
	checkOptions.alreadyUsed = true;
	checkOptions.alreadyUsedReturnValue = result;
	
	return result;
	}
	
//-----------------------------------------------------------------
// If file is an alias: returns file's target if file is
// successfully resolved and the target exists, otherwise null. If
// file is not an alias: returns file.
//-----------------------------------------------------------------

photoshop.resolveFileIfAlias = function (file)
	{
	if (file.alias)
		{
		try
			{
			file = file.resolve ();
			}
		catch (e)
			{
			file = null;
			}
			
		// On Windows, a shorcut may get resolved even if the target file doesn't exist
		if ((file != null) && !file.exists)
			file = null;
		}
	
	return file;
	}
	
//-----------------------------------------------------------------
// Creates and returns a 'PSFileStatusChange' XML string formatted
// for Lightroom to receive and interpret.
//-----------------------------------------------------------------

photoshop.createLightroomNotificationXML = function (message, identifier, path, reason)
	{
	var xmlString = '<?xml version="1.0" encoding="UTF-8"?>';	// processing instructions
	xmlString += '\n<PSFileStatusChange version="1.0"';
	xmlString += '\n message="' + message + '"';
	
	if (reason != null)
		xmlString += '\n reason="' + reason + '"';
		
	xmlString += '\n identifier="' + identifier + '"';
	
	if (path != null)
		xmlString += '\n path="' + path + '"';

	xmlString += ' />'
	
	return xmlString;
	}

} // Overall try catch
catch (e)
{
	// Debugging
//	alert (e + ": line " + e.line);
}
