/// <summary>
        ///
        /// </summary>
        public void Synchronize()
        {
            Directory.CreateDirectory(Source);
            Directory.CreateDirectory(Target);
            var  src      = new DirectoryStructure(Source);
            var  trg      = new DirectoryStructure(Target);
            bool waserror = false;

            foreach (var fileItem in src.GetDiff(trg))
            {
                try{
                    Log.Trace("start " + fileItem);
                    Apply(fileItem);
                    Log.Info("complete " + fileItem);
                }
                catch (Exception ex) {
                    Log.Error("error " + fileItem, ex);
                    waserror = true;
                }
            }
            if (!waserror)
            {
                var hash = src.GetStampFile().ToString();
                File.WriteAllText(Path.Combine(Target, DirectoryStructure.SyncFileName), hash);
                File.WriteAllText(Path.Combine(Source, DirectoryStructure.SyncFileName), hash);
                Log.Info("stamp file wrote");
            }
            else
            {
                Log.Error("stamp not written due to some exceptions");
            }
        }
        /// <summary>
        /// Получить разницу между исходной и целевой директорией
        /// </summary>
        /// <returns></returns>
        public IEnumerable <FileItem> GetDifference()
        {
            var src = new DirectoryStructure(Source);
            var trg = new DirectoryStructure(Target);

            return(src.GetDiff(trg));
        }
        /// <summary>
        /// Получить разницу между директориями
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public IEnumerable <FileItem> GetDiff(DirectoryStructure other)
        {
            var src = this.GetStampFile();
            var trg = other.GetStampFile();

            if (src.ToString() == trg.ToString())
            {
                yield break;
            }
            var srce          = src.Elements().Select(_ => new FileItem(_, FileOperation.None)).ToArray();
            var trge          = trg.Elements().Select(_ => new FileItem(_, FileOperation.None)).ToArray();
            var leftOuterJoin = from s in srce
                                join t in trge
                                on s.Name equals t.Name
                                into temp
                                from t in temp.DefaultIfEmpty(new FileItem())
                                select new FileItem {
                Hash = s.Hash, Name = s.Name, OtherHash = t.Hash
            };
            var rightOuterJoin = from t in trge
                                 join s in srce
                                 on t.Name equals s.Name
                                 into temp
                                 from s in temp.DefaultIfEmpty(new FileItem())
                                 select new FileItem {
                Hash = s.Hash, Name = t.Name, OtherHash = t.Hash
            };
            var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin.Where(_ => string.IsNullOrWhiteSpace(_.Hash))).ToArray();

            foreach (FileItem i in fullOuterJoin)
            {
                if (i.Hash == i.OtherHash)
                {
                    continue;
                }
                if (string.IsNullOrWhiteSpace(i.Hash))
                {
                    i.Operation = FileOperation.Delete;
                    yield return(i);
                }
                else if (string.IsNullOrWhiteSpace(i.OtherHash))
                {
                    i.Operation = FileOperation.Create;
                    yield return(i);
                }
                else
                {
                    i.Operation = FileOperation.Update;
                    yield return(i);
                }
            }
        }
		/// <summary>
		/// Получить разницу между директориями
		/// </summary>
		/// <param name="other"></param>
		/// <returns></returns>
		public IEnumerable<FileItem> GetDiff(DirectoryStructure other){
			var src = this.GetStampFile();
			var trg = other.GetStampFile();
			if (src.ToString() == trg.ToString()){
				yield break;
			}
			var srce = src.Elements().Select(_=>new FileItem(_,FileOperation.None)).ToArray();
			var trge = trg.Elements().Select(_ => new FileItem(_, FileOperation.None)).ToArray();
			var leftOuterJoin = from s in srce
			                    join t in trge
				                    on s.Name equals t.Name
				                    into temp
			                    from t in temp.DefaultIfEmpty(new FileItem())
			                    select new FileItem{Hash = s.Hash, Name = s.Name, OtherHash = t.Hash};
			var rightOuterJoin = from t in trge
								 join s in srce
									 on t.Name equals s.Name
									 into temp
								 from s in temp.DefaultIfEmpty(new FileItem())
								 select new FileItem { Hash = s.Hash, Name = t.Name, OtherHash = t.Hash };
			var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin.Where(_=>string.IsNullOrWhiteSpace(_.Hash))).ToArray();
			foreach (FileItem i in fullOuterJoin){
				if (i.Hash == i.OtherHash) continue;
				if (string.IsNullOrWhiteSpace(i.Hash)){
					i.Operation = FileOperation.Delete;
					yield return i;
				}else if (string.IsNullOrWhiteSpace(i.OtherHash)){
					i.Operation = FileOperation.Create;
					yield return i;
				}
				else{
					i.Operation = FileOperation.Update;
					yield return i;
				}
			}

		}