public override IEnumerable<ReactiveStreamContext> GenerateBranch(ReactiveStreamContext context)
		{
			return FileFilter(context.WorkFolder)
				.Select(x => new ReactiveStreamContext(context.WorkFolder, x.FullName))
				// 遅延評価されると複数回Selectが実行されるため、配列化する
				.ToArray();
		}
		public override void Execute(ReactiveStreamContext context)
		{
			// ファイルやフォルダが更新された作成されていた場合にObservableシーケンスを後続に流す
			if (false == CheckItemNeedUpdate(context))
			{ 
				context.Done();
			}
		}
		public override IEnumerable<ReactiveStreamContext> GenerateBranch(ReactiveStreamContext context)
		{
			return DirectoryFilter(context.WorkFolder)
				.Select(x => new ReactiveStreamContext(context.WorkFolder, x.FullName))
				// 遅延評価によってSelectが複数回呼ばれることを防止するため配列化
				.ToArray(); 

		}
		public bool CheckItemNeedUpdate(ReactiveStreamContext payload)
		{
			var previewProcessedFile = SourceFiles.SingleOrDefault(x =>
			{
				return x.Source.Path == payload.OriginalPath;
			});

			return previewProcessedFile?.IsNeedUpdate ?? true;
		}
		public bool Validate(ReactiveStreamContext context)
		{
			if (AppPolicy == null)
			{
				return false;
			}

			if (false == AppPolicy.IsExistApplicationFile)
			{
				return false;
			}

			// TODO: Optionsのチェック

			return true;
		}
		public void OnContextComplete(ReactiveStreamContext context)
		{
			// 対象アイテムの更新を記録する
			PreserveItemOnFirstUpdate(context.OriginalPath, context.OutputPath);
		}
		public override void Execute(ReactiveStreamContext context)
		{
			// アップデートタイミングではない場合はfalseを返してStreamを終了させる
			if (false == CheckTimingAndUpdateNextTime())
			{
				context.Done();
			}
		}
		public override void Execute(ReactiveStreamContext context)
		{
			// TODO: SourcePathのファイルが存在しなかったら終了

			var sourcePath = context.SourcePath;
			var tempOutputFolder = context.TempOutputFolder;

			try
			{
				var sandbox = CreateSandbox();

				if (sandbox.Execute(sourcePath, tempOutputFolder))
				{
					context.SetNextWorkingPath(sandbox.ResultPath);
				}
				else
				{
					context.Failed("Execute failed or timeout");
				} 
			}
			catch (Exception e)
			{
				context.Failed("ReactiveStreamFailed on Update", e);
			}
		}
		public static string FormatedString(string renamePattern, ReactiveStreamContext context)
		{
			if (String.IsNullOrWhiteSpace(renamePattern))
			{
				return FormatMap[DefaultRenamePattern](context);
			}

			var text = renamePattern;
			foreach(var key in FormatMap.Keys)
			{
				if (false == text.Contains("%"))
				{
					break;
				}

				if (text.Contains(key))
				{
					text = text.Replace(key, FormatMap[key](context));
				}
			}

			return text;
		}
		private string FinalizeFolder(ReactiveStreamContext context, string outputName, DirectoryInfo destFolder)
		{
			var outputFolderInfo = new DirectoryInfo(context.SourcePath);
			if (false == outputFolderInfo.Exists)
			{
				return null;
			}


			var finalizeFolderPath = Path.Combine(
				destFolder.FullName,
				outputName
			);

			var finalizeFolderInfo = new DirectoryInfo(finalizeFolderPath);
			try
			{
				if (finalizeFolderInfo.Exists)
				{
					finalizeFolderInfo.Delete();
				}

				outputFolderInfo.MoveTo(finalizeFolderPath);
				return finalizeFolderPath;
			}
			catch (Exception e)
			{
				context.Failed("ReactiveStreamFailed on Finalize folder", e);
			}

			return null;
		}
		private string FinalizeFile(ReactiveStreamContext context, string outputName, DirectoryInfo destFolder)
		{

			var outputFileInfo = new FileInfo(context.SourcePath);
			if (false == outputFileInfo.Exists)
			{
				return null;
			}

			var extention = Path.GetExtension(context.SourcePath);

			var finalizeFilePath = Path.Combine(
				destFolder.FullName,
				Path.ChangeExtension(
					outputName,
					extention
				)
			);

			try
			{
				var destFileInfo = new FileInfo(finalizeFilePath);
				if (destFileInfo.Exists)
				{
					destFileInfo.Delete();
				}
				outputFileInfo.CopyTo(destFileInfo.FullName);
				return finalizeFilePath;
			}
			catch (Exception e)
			{
				context.Failed("ReactiveStreamFailed on Finalize file", e);
			}

			return null;
		}
		public override void Execute(ReactiveStreamContext context)
		{
			// TODO: OutputNameを状態として保持するのは変やで、一時変数に変更しよう
			var outputPath = FormatedString(this.OutputNamePattern, context);

			try
			{


				// やること
				// アウトプットしたいファイルまたはフォルダをNameに変更した上でDestinationFolderに移動させる

				// 例外状況
				// DestinationFolderとWorkFolderが同じ場合、かつ
				// 拡張子を含むOriginalのファイル名とOutputPathのファイル名が同じ場合、かつ
				// IsProtecteOriginalがtrueのときに
				// Destinationへの配置が実行できない状況が生まれる



				// 検証が必要:フォルダでも同様に配置不可な状況が検知できるか

				var destFolder = GetDestinationFolder();
				if (context.WorkFolder.FullName == destFolder.FullName &&
					Path.GetFileName(context.OriginalPath) == Path.GetFileName(context.SourcePath) &&
					context.IsProtectOriginal == true
					)
				{
					// Finalizeに失敗?
					outputPath = null;
					throw new Exception("OutputItem cant deployment to destination folder.");
				}

				// OutputPathで指定されたファイルをfinalizer.DestinationFolderにコピーする
				// コピーする前にファイル名をNameに変更する(拡張子はOutputPathのものを引き継ぐ)

				string outputName = Path.GetFileNameWithoutExtension(context.OriginalPath);
				if (false == String.IsNullOrWhiteSpace(outputName))
				{
					outputName = outputPath;
				}

				if (context.IsFile)
				{
					outputPath = FinalizeFile(context, outputName, destFolder);
				}
				else
				{
					outputPath = FinalizeFolder(context, outputName, destFolder);
				}

				if (outputPath != null)
				{
					context.Complete(outputPath);
				}
			}
			catch (Exception e)
			{
				context.Failed("ReactiveStreamFailed on Finalize", e);
			}
		}