/// <summary>
        /// Execute the task.
        /// </summary>
        /// <param name="Job">Information about the current job</param>
        /// <param name="BuildProducts">Set of build products produced by this node.</param>
        /// <param name="TagNameToFileSet">Mapping from tag names to the set of files they include</param>
        /// <returns>True if the task succeeded</returns>
        public override bool Execute(JobContext Job, HashSet <FileReference> BuildProducts, Dictionary <string, HashSet <FileReference> > TagNameToFileSet)
        {
            // Get the project path, and check it exists
            FileReference ProjectFile = null;

            if (Parameters.Project != null)
            {
                ProjectFile = ResolveFile(Parameters.Project);
                if (!ProjectFile.Exists())
                {
                    CommandUtils.LogError("Couldn't find project '{0}'", ProjectFile.FullName);
                    return(false);
                }
            }

            // Get the directories used for staging this project
            DirectoryReference SourceEngineDir  = UnrealBuildTool.UnrealBuildTool.EngineDirectory;
            DirectoryReference SourceProjectDir = (ProjectFile == null)? SourceEngineDir : ProjectFile.Directory;

            // Get the output directories. We flatten the directory structure on output.
            DirectoryReference TargetDir        = ResolveDirectory(Parameters.ToDir);
            DirectoryReference TargetEngineDir  = DirectoryReference.Combine(TargetDir, "Engine");
            DirectoryReference TargetProjectDir = DirectoryReference.Combine(TargetDir, ProjectFile.GetFileNameWithoutExtension());

            // Get the path to the receipt
            string ReceiptFileName = TargetReceipt.GetDefaultPath(SourceProjectDir.FullName, Parameters.Target, Parameters.Platform, Parameters.Configuration, Parameters.Architecture);

            // Try to load it
            TargetReceipt Receipt;

            if (!TargetReceipt.TryRead(ReceiptFileName, out Receipt))
            {
                CommandUtils.LogError("Couldn't read receipt '{0}'", ReceiptFileName);
                return(false);
            }

            // Expand all the paths from the receipt
            Receipt.ExpandPathVariables(SourceEngineDir, SourceProjectDir);

            // Stage all the build products needed at runtime
            HashSet <FileReference> SourceFiles = new HashSet <FileReference>();

            foreach (BuildProduct BuildProduct in Receipt.BuildProducts.Where(x => x.Type != BuildProductType.StaticLibrary && x.Type != BuildProductType.ImportLibrary))
            {
                SourceFiles.Add(new FileReference(BuildProduct.Path));
            }
            foreach (RuntimeDependency RuntimeDependency in Receipt.RuntimeDependencies.Where(x => x.Type != StagedFileType.UFS))
            {
                SourceFiles.UnionWith(CommandUtils.ResolveFilespec(CommandUtils.RootDirectory, RuntimeDependency.Path, new string[] { ".../*.umap", ".../*.uasset" }));
            }

            // Get all the target files
            List <FileReference> TargetFiles = new List <FileReference>();

            foreach (FileReference SourceFile in SourceFiles)
            {
                // Get the destination file to copy to, mapping to the new engine and project directories as appropriate
                FileReference TargetFile;
                if (SourceFile.IsUnderDirectory(SourceEngineDir))
                {
                    TargetFile = FileReference.Combine(TargetEngineDir, SourceFile.MakeRelativeTo(SourceEngineDir));
                }
                else
                {
                    TargetFile = FileReference.Combine(TargetProjectDir, SourceFile.MakeRelativeTo(SourceProjectDir));
                }

                // Fixup the case of the output file. Would expect Platform.DeployLowerCaseFilenames() to return true here, but seems not to be the case.
                if (Parameters.Platform == UnrealTargetPlatform.PS4)
                {
                    TargetFile = FileReference.Combine(TargetDir, TargetFile.MakeRelativeTo(TargetDir).ToLowerInvariant());
                }

                // Only copy the output file if it doesn't already exist. We can stage multiple targets to the same output directory.
                if (Parameters.Overwrite || !TargetFile.Exists())
                {
                    TargetFile.Directory.CreateDirectory();
                    CommandUtils.CopyFile(SourceFile.FullName, TargetFile.FullName);
                }

                // Add it to the list of target files
                TargetFiles.Add(TargetFile);
            }

            // Apply the optional tag to the build products
            foreach (string TagName in FindTagNamesFromList(Parameters.Tag))
            {
                FindOrAddTagSet(TagNameToFileSet, TagName).UnionWith(TargetFiles);
            }

            // Add the target file to the list of build products
            BuildProducts.UnionWith(TargetFiles);
            return(true);
        }