public SyncData(FileData fD, SyncConflictState sCS, SyncDirection sP, SyncActionState sAS) { FD = fD; SCS = sCS; SD = sP; SAS = sAS; }
public void SyncDirectionAllowInboundTest() { Assert.IsTrue(SyncDirection.AllowInbound(SyncDirection.Direction.BiDirectional), "Bidirectional includes both"); Assert.IsTrue(SyncDirection.AllowInbound(SyncDirection.Direction.Export), "Explicitly inbound"); Assert.IsFalse(SyncDirection.AllowInbound(SyncDirection.Direction.Import), "Explicitly not inbound"); Assert.IsFalse(SyncDirection.AllowInbound(SyncDirection.Direction.Neither), "Neither excludes both"); }
public void SyncDirectionToStringTest() { Assert.AreEqual("None", SyncDirection.ToString(SyncDirection.Direction.Neither)); Assert.AreEqual("From CRM to Outlook", SyncDirection.ToString(SyncDirection.Direction.Export)); Assert.AreEqual("From Outlook to CRM", SyncDirection.ToString(SyncDirection.Direction.Import)); Assert.AreEqual("Both", SyncDirection.ToString(SyncDirection.Direction.BiDirectional)); }
/// <summary> /// This method assumes that RemoteRepo.Load() was already called. /// </summary> /// <param name="app"></param> /// <returns></returns> public List<RemoteVsLocalFile> GroupFilesByName (string localFoldrPath, IRepository<SyncableFileRemote> repo, SyncDirection syncDirection) { var list = new List<RemoteVsLocalFile>(); var locals = _fileSeeker.GetFiles(localFoldrPath); foreach (var loc in locals) { var rem = repo.One(x => x.Name == loc.Name); list.Add(RemVsLoc(loc, rem, syncDirection)); } foreach (var rem in repo.Any(r => !list.Has(l => l.Filename == r.Name))) { var loc = locals.One(x => x.Name == rem.Name); list.Add(RemVsLoc(loc, rem, syncDirection)); } // if no files in folder, or no folder at all, // - assume that it's a first run : download all // if (locals.Count == 0) list.ForEach(x => x.DoNext(Target.Local, FileTask.Create)); return list; }
/// <summary> /// This method assumes that RemoteRepo.Load() was already called. /// </summary> /// <param name="app"></param> /// <returns></returns> public List <RemoteVsLocalFile> GroupFilesByName (string localFoldrPath, IRepository <SyncableFileRemote> repo, SyncDirection syncDirection) { var list = new List <RemoteVsLocalFile>(); var locals = _fileSeeker.GetFiles(localFoldrPath); foreach (var loc in locals) { var rem = repo.One(x => x.Name == loc.Name); list.Add(RemVsLoc(loc, rem, syncDirection)); } foreach (var rem in repo.Any(r => !list.Has(l => l.Filename == r.Name))) { var loc = locals.One(x => x.Name == rem.Name); list.Add(RemVsLoc(loc, rem, syncDirection)); } // if no files in folder, or no folder at all, // - assume that it's a first run : download all // if (locals.Count == 0) { list.ForEach(x => x.DoNext(Target.Local, FileTask.Create)); } return(list); }
/// <summary> /// Function that prioriteze all the SyncData for a specific SyncDirection. /// </summary> /// <param name="SDList">The list of the SyncData to be prioritized.</param> /// <param name="SPToSet">Specific SyncDirection to be set.</param> public static void PrioritizeConflictFileDataListAll(List <SyncData> SDList, SyncDirection SPToSet) { for (int i = 0; i < SDList.Count; i++) { SDList[i].SD = SPToSet; } }
public UnmappedValueException(SyncDirection syncDirection, string valueWithoutMap) : base("A value was not found within the field map.") { SyncDirection = syncDirection; ValueWithoutMap = valueWithoutMap; }
public SqliteSyncConfigurationBuilder Table <T>( string name = null, SyncDirection syncDirection = SyncDirection.UploadAndDownload, bool skipInitialSnapshot = false, string selectIncrementalQuery = null, string customSnapshotQuery = null) { if (name == null) { var tableAttribute = (TableAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(TableAttribute)); if (tableAttribute != null) { name = tableAttribute.Name; } } if (name == null) { name = typeof(T).Name; } if (_tables.Any(_ => string.CompareOrdinal(_.Name, name) == 0)) { throw new InvalidOperationException($"Table with name '{name}' already added"); } return(Table(name, typeof(T), syncDirection, skipInitialSnapshot, selectIncrementalQuery, customSnapshotQuery)); }
internal SqliteSyncTable(string name, Type recordType = null, SyncDirection syncDirection = SyncDirection.UploadAndDownload, bool skipInitialSnapshot = false, string selectIncrementalQuery = null, string customSnapshotQuery = null) : base(name, syncDirection, skipInitialSnapshot, selectIncrementalQuery, customSnapshotQuery) { Validate.NotNullOrEmptyOrWhiteSpace(name, nameof(name)); RecordType = recordType; }
public SqlSyncConfigurationBuilder Table <T>( SyncDirection syncDirection = SyncDirection.UploadAndDownload, string schema = null, bool skipInitialSnapshot = false, string selectIncrementalQuery = null, string customSnapshotQuery = null) { var name = typeof(T).Name; var tableAttribute = (TableAttribute)Attribute.GetCustomAttribute(typeof(T), typeof(TableAttribute)); if (tableAttribute != null) { name = tableAttribute.Name; schema = tableAttribute.Schema; } var nameWithSchema = $"{(schema == null ? string.Empty : "[" + schema + "].")}[{name}]"; if (_tables.Any(_ => string.CompareOrdinal(_.NameWithSchema, nameWithSchema) == 0)) { throw new InvalidOperationException($"Table with name '{nameWithSchema}' already added"); } return(Table(name, syncDirection, schema ?? _schema, skipInitialSnapshot, selectIncrementalQuery, customSnapshotQuery)); }
public SyncData(FileData fD, SyncConflictState sCS, SyncDirection sP) { FD = fD; SCS = sCS; SD = sP; SAS = SyncActionState.Skip; }
private void Application_NewMail(string EntryID) { log.Debug(catalogue.GetString("Outlook NewMail: email received event")); try { if (this.IsLicensed) { var item = Application.Session.GetItemFromID(EntryID); if (item is Outlook.MailItem && Properties.Settings.Default.AutoArchive) { ProcessNewMailItem(EmailArchiveReason.Inbound, item as Outlook.MailItem, Settings.Default.ExcludedEmails); } else if (item is Outlook.MeetingItem && SyncDirection.AllowOutbound(Properties.Settings.Default.SyncMeetings)) { ProcessNewMeetingItem(item as Outlook.MeetingItem); } } } catch (Exception ex) { ErrorHandler.Handle(catalogue.GetString("Failed while trying to handle a received email"), ex); } }
internal SqlSyncTable(string name, SyncDirection syncDirection = SyncDirection.UploadAndDownload, string schema = "dbo", bool skipInitialSnapshot = false, string selectIncrementalQuery = null, string customSnapshotQuery = null) : base(name, syncDirection, skipInitialSnapshot, selectIncrementalQuery, customSnapshotQuery) { Validate.NotNullOrEmptyOrWhiteSpace(name, nameof(name)); Validate.NotNullOrEmptyOrWhiteSpace(schema, nameof(schema)); Schema = schema; }
public void Init(SyncObjectFactory.SyncObjectActivator info, SyncComponent sync, SyncDirection direction, ulong id) { TypeInfo = info; SyncDirection = direction; SyncComponent = sync; SyncObjectID = id; }
protected SyncTable(string name, SyncDirection syncDirection = SyncDirection.UploadAndDownload, bool skipInitialSnapshot = false) { Validate.NotNullOrEmptyOrWhiteSpace(name, nameof(name)); Name = name; SyncDirection = syncDirection; SkipInitialSnapshot = skipInitialSnapshot; }
public SyncMap(SyncProfile profile, SyncDirection direction, SyncAction defaultAction) { this._profile = profile; _defaultSyncAction = defaultAction; _syncDirection = direction; }
/// <summary> /// create a link providing synchronisation information /// </summary> /// <param name="title"></param> /// <param name="path1">absolute path to folder 1</param> /// <param name="path2">absolute path to folder 2</param> /// <param name="direction"></param> /// <param name="remove">enables removing files and folders in destination directory if the source file doesn't exist</param> /// <param name="drive1Label"> /// if not empty or null the drive of Path1 is recognized by its label instead of its letter <para /> /// the drive of path 1 will be changed to match the drive label /// </param> /// <param name="drive2Label"> /// if not empty or null the drive of Path2 is recognized by its label instead of its letter /// the drive of path 1 will be changed to match the drive label /// </param> public Link(string title, string path1, string path2, SyncDirection direction, bool remove, string drive1Label, string drive2Label) { Title = title; Path1 = path1; Path2 = path2; Direction = direction; Remove = remove; Drive1Label = drive1Label == "" ? null : drive1Label; Drive2Label = drive2Label == "" ? null : drive2Label; }
void Awake() { m_Direction = GetComponent <SyncDirection>(); m_NotEnoughGold = GameObject.Find("Game_HUD/Unit/NotEnoughGold").GetComponent <Text>(); m_Anim = GameObject.Find("Game_HUD").transform.FindChild("Unit").GetComponent <Animator>(); m_UpgradeAnim = GameObject.Find("Game_HUD").transform.FindChild("UnitUpgrade").GetComponent <Animator>(); m_MeleeSpeed = 0; m_MeleeArmour = 0; }
public override void ReadFrom(MemoryStream input) { base.ReadFrom(input); input.Read(ref ObjectID); input.Read(ref ObjectType); byte dir = 0; input.Read(ref dir); SyncDirection = (SyncDirection)dir; }
protected SyncTable(string name, SyncDirection syncDirection = SyncDirection.UploadAndDownload, bool skipInitialSnapshot = false, string selectIncrementalQuery = null, string customSnapshotQuery = null) { Validate.NotNullOrEmptyOrWhiteSpace(name, nameof(name)); Name = name; SyncDirection = syncDirection; SkipInitialSnapshot = skipInitialSnapshot; SelectIncrementalQuery = selectIncrementalQuery; CustomSnapshotQuery = customSnapshotQuery; }
/// <summary> /// Writes log message. /// </summary> /// <param name="context"><see cref="SyncContext"/> instance.</param> /// <param name="action"><see cref="SyncAction"/> enumeration.</param> /// <param name="syncDirection"><see cref="SyncDirection"/> enumeration.</param> /// <param name="format">String a composite format.</param> /// <param name="ex">Exception.</param> /// <param name="args">An array of additional parameters.</param> public virtual void LogMessage(SyncContext context, SyncAction action, SyncDirection syncDirection, string format, Exception ex, params object[] args) { if (ex == null) { context.LogInfo(action, syncDirection, format, args); } else { context.LogError(action, syncDirection, format, ex, args); } }
/// <summary> /// Populate one of the two synchronisation direction menus. /// </summary> /// <param name="directionMenu">The menu to populate.</param> private void PopulateDirectionsMenu(ComboBox directionMenu) { var syncDirectionItems = Enum.GetValues(typeof(SyncDirection.Direction)) .Cast <SyncDirection.Direction>() .Select(p => new { Key = (int)p, Value = SyncDirection.ToString(p) }) .OrderBy(o => o.Key) .ToList(); directionMenu.ValueMember = "Key"; directionMenu.DisplayMember = "Value"; directionMenu.DataSource = syncDirectionItems; }
/// <summary> /// create link from line /// </summary> /// <param name="line"></param> /// <returns>the created link or null if the format isn't valid</returns> public static Link CreateFromLine(string line) { const int argCount = 7; string[] parts = line.Split('\"'); if (parts.Length != 1 + 2 * argCount) { return(null); } if (!parts[2].Trim().Equals(":") || parts.Where((x, i) => i > 2 && i < 2 * argCount && i % 2 == 0 && x.Trim() != ",").Count() > 0) { return(null); } /*!parts[4].Trim().Equals(",") || !parts[6].Trim().Equals(",") || !parts[8].Trim().Equals(",") || !parts[10].Trim().Equals(","))*/ int argIndex = 1; string title = parts[argIndex]; string path1 = parts[argIndex += 2]; string path2 = parts[argIndex += 2]; SyncDirection direction; bool remove; try { direction = SyncDirection.Parse(parts[argIndex += 2]); remove = bool.Parse(parts[argIndex += 2]); } catch (Exception) { return(null); } string drive1Label = parts[argIndex += 2]; string drive2Label = parts[argIndex += 2]; Link l = new Link(title, path1, path2, direction, remove, drive1Label, drive2Label); if (l.Drive1Label != null) { l.UpdatePath1DriveLetter(); } if (l.Drive2Label != null) { l.UpdatePath2DriveLetter(); } return(l); }
public RemoteVsLocalFile(string filename, SyncableFileRemote remoteFile, SyncableFileLocal localFile, SyncDirection syncDirection) { Filename = filename; Remote = remoteFile; Local = localFile; Status = "Comparing..."; Comparison = GetComparison(Remote, Local, syncDirection); Status = "Idle."; }
/// <summary> /// Initializes a new instance of the <see cref="GenericSynchronisationService<TType, TKey>"/> class. /// </summary> /// <param name="keySelector">The key selector.</param> /// <param name="localProvider">The local provider.</param> /// <param name="remoteProvider">The remote provider.</param> /// <param name="settings">The settings.</param> /// <param name="syncDirection">The sync direction.</param> public GenericSynchronisationService( Func <TType, TKey> keySelector, ISynchronisationProvider <TType, TKey> localProvider, ISynchronisationProvider <TType, TKey> remoteProvider, ISyncSettings settings, SyncDirection syncDirection) { _keySelector = keySelector; _localProvider = localProvider; _remoteProvider = remoteProvider; _settings = settings; _syncDirection = syncDirection; }
private RemoteVsLocalFile RemVsLoc(SyncableFileLocal locFile, SyncableFileRemote remNode, SyncDirection syncDirection) { //return new RemoteVsLocalFile(locFile?.Name ?? remNode.Name) //{ // Local = locFile, // Remote = RemoteFileInfo(remNode) //}; var fName = locFile?.Name ?? remNode.Name; var remFile = RemoteFileInfo(remNode); return new RemoteVsLocalFile(fName, remFile, locFile, syncDirection); }
public void SyncDirectory(SyncDirection syncDirection, string fromDir, string toDir) { var syncDirectionOutput = syncDirection switch { SyncDirection.FromTo => "->", SyncDirection.Both => "<->", _ => "?-?" }; Console.WriteLine($"SYSOP: Sync dir '{fromDir}' {syncDirectionOutput} '{toDir}"); Thread.Sleep(500); }
private static void OnSyncGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (!(d is ScrollViewer scrollViewer)) { return; } object oldGroup = e.OldValue; object newGroup = e.NewValue; if (oldGroup != null) { if (_svTable.ContainsKey(scrollViewer)) { scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged; _svTable.Remove(scrollViewer); } } if (newGroup != null) { SyncDirection direction = GetSyncDirection(scrollViewer); if (_hOffsets.ContainsKey(newGroup)) { if (direction.HasFlag(SyncDirection.Horizontal)) { scrollViewer.ScrollToHorizontalOffset(_hOffsets[newGroup]); } } else { _hOffsets.Add(newGroup, scrollViewer.HorizontalOffset); } if (_vOffsets.ContainsKey(newGroup)) { if (direction.HasFlag(SyncDirection.Vertical)) { scrollViewer.ScrollToVerticalOffset(_vOffsets[newGroup]); } } else { _vOffsets.Add(newGroup, scrollViewer.VerticalOffset); } _svTable.Add(scrollViewer, newGroup); scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged; } }
/// <summary> /// Initializes a new instance of the DmTableSurrogate class. /// </summary> public DmTableSurrogate(DmTable dt) { if (dt == null) { throw new ArgumentNullException("dt", "DmTable"); } this.TableName = dt.TableName; this.CultureInfoName = dt.Culture.Name; this.CaseSensitive = dt.CaseSensitive; this.Schema = dt.Schema; this.OriginalProvider = dt.OriginalProvider; this.SyncDirection = dt.SyncDirection; for (int i = 0; i < dt.Columns.Count; i++) { this.Columns.Add(new DmColumnSurrogate(dt.Columns[i])); } // Primary Keys if (dt.PrimaryKey != null && dt.PrimaryKey.Columns != null && dt.PrimaryKey.Columns.Length > 0) { for (int i = 0; i < dt.PrimaryKey.Columns.Length; i++) { this.PrimaryKeys.Add(dt.PrimaryKey.Columns[i].ColumnName); } } // Fill the rows if (dt.Rows.Count <= 0) { return; } // the BitArray contains bit values initialized to false. We will use it to store row state this.RowStates = new int[dt.Rows.Count]; // Records in a straightforward object array this.Records = new Dictionary <int, List <object> >(dt.Columns.Count); for (int j = 0; j < dt.Columns.Count; j++) { this.Records[j] = new List <object>(dt.Rows.Count); } for (int k = 0; k < dt.Rows.Count; k++) { this.RowStates[k] = (int)dt.Rows[k].RowState; this.ConvertToSurrogateRecords(dt.Rows[k]); } }
private RemoteVsLocalFile RemVsLoc(SyncableFileLocal locFile, SyncableFileRemote remNode, SyncDirection syncDirection) { //return new RemoteVsLocalFile(locFile?.Name ?? remNode.Name) //{ // Local = locFile, // Remote = RemoteFileInfo(remNode) //}; var fName = locFile?.Name ?? remNode.Name; var remFile = RemoteFileInfo(remNode); return(new RemoteVsLocalFile(fName, remFile, locFile, syncDirection)); }
public SyncProgressWindow(IGrooveClient client, MusicBeeApiInterface mbApiInterface, SyncDirection syncDirection, List <MusicBeePlaylist> musicBeePlaylists, List <Playlist> groovePlaylists) { InitializeComponent(); _syncHelper = new SyncHelper(client, mbApiInterface, this); _syncDirection = syncDirection; _musicBeePlaylists = musicBeePlaylists; _groovePlaylists = groovePlaylists; ErrorResponses = new List <PlaylistActionResponse>(); ApplyMusicBeeTheme(mbApiInterface); StartSync(); }
private void CoordinateSync(LiveConnectSession session, string syncFilename, string syncInternalFilename, Action <BookmarkserviceImportCompletedEventArgs> completedAction, BookmarkserviceImportCompletedEventArgs completedEventArgs) { //if device is sync priority, then not necessary to retrieve existing bookmarks //this would act as backup SyncDirection syncDirection = AppSettings.GetValueOrDefault <SyncDirection>(AppSettings.CloudSync.SyncDirection, SyncDirection.DeviceToCloud); if (syncDirection == SyncDirection.DeviceToCloud) { PerformDeviceToCloudSync(session, syncFilename, completedAction, completedEventArgs); } else { PerformCloudToDeviceSync(session, syncFilename, syncInternalFilename, completedAction, completedEventArgs); } }
public Session StartSession(SyncDirection direction) { using (var db = _ctxFactory()) { var session = new Session { StartedOn = DateTime.Now, Direction = direction, Result = SessionResult.InProgress }; db.Sessions.Add(session); db.SaveChanges(); return(session); } }
public static string FromHash(SyncProfile sp, SyncDirection direction, string hash) { ////////////////////TAKEN FROM pre-absorbtion NwdSynergy.ObjectGridWindow///////////// // ////load displayNameIndex.txt //List<DisplayNameIndexEntry> displayNames = new List<DisplayNameIndexEntry>(); //string path = Configuration.GetPhoneSyncConfigFilePath("displayNameIndex"); //foreach (string line in File.ReadAllLines(path)) //{ // displayNames.Add(new DisplayNameIndexEntry() // { // DisplayName = p.Extract("displayName", line), // DevicePath = p.Extract("path", line) // }); //} ////load fileHashIndex.txt //List<FileHashIndexEntry> fileHashes = new List<FileHashIndexEntry>(); //path = Configuration.GetPhoneSyncConfigFilePath("fileHashIndex"); //foreach (string line in File.ReadAllLines(path)) //{ // fileHashes.Add(new FileHashIndexEntry() // { // DevicePath = p.Extract("path", line), // SHA1Hash = p.Extract("sha1Hash", line) // }); //} //IEnumerable<SynergyRowObject> joinResult = // from displayName in displayNames // join fileHash in fileHashes // on displayName.DevicePath equals fileHash.DevicePath // select new SynergyRowObject // { // SHA1Hash = fileHash.SHA1Hash, // DisplayName = displayName.DisplayName, // DevicePath = fileHash.DevicePath // }; return ""; }
public void Synchronize(IPersistenceEngine client, IPersistenceEngine server, SyncDirection syncDirection) { Synchronize(client, server, syncDirection, ((SyncEngine)client).ClientId); }
private FileDiff GetComparison(SyncableFileBase remoteFile, SyncableFileBase localFile, SyncDirection syncDirection) { if (localFile == null && remoteFile == null) { DoNext(Target.Both, FileTask.Analyze); return FileDiff.Unavailable; } if (localFile == null) { if (syncDirection == SyncDirection.Upload) DoNext(Target.Remote, FileTask.Delete); else if (syncDirection == SyncDirection.Download) DoNext(Target.Local, FileTask.Create); return FileDiff.NotInLocal; } if (remoteFile == null) { if (syncDirection == SyncDirection.Upload) DoNext(Target.Remote, FileTask.Create); else if (syncDirection == SyncDirection.Download) DoNext(Target.Local, FileTask.Ignore); return FileDiff.NotInRemote; } if (remoteFile.Size != localFile.Size) { OddProperty = nameof(localFile.Size); PropertyDiffs = $"↑ {remoteFile.Size.KB()}{L.f}↓ {localFile.Size.KB()}"; if (syncDirection == SyncDirection.Upload) DoNext(Target.Remote, FileTask.Replace); else if (syncDirection == SyncDirection.Download) DoNext(Target.Local, FileTask.Replace); return FileDiff.Changed; } if (remoteFile.Version != localFile.Version) { OddProperty = nameof(localFile.Version); PropertyDiffs = $"↑ “{remoteFile.Version}”{L.f}↓ “{localFile.Version}”"; if (syncDirection == SyncDirection.Upload) DoNext(Target.Remote, FileTask.Replace); else if (syncDirection == SyncDirection.Download) DoNext(Target.Local, FileTask.Replace); return FileDiff.Changed; } if (remoteFile.SHA1 != localFile.SHA1) { OddProperty = nameof(localFile.SHA1); PropertyDiffs = $"↑ {remoteFile.SHA1}{L.f}↓ {localFile.SHA1}"; if (syncDirection == SyncDirection.Upload) DoNext(Target.Remote, FileTask.Replace); else if (syncDirection == SyncDirection.Download) DoNext(Target.Local, FileTask.Replace); return FileDiff.Changed; } DoNext(Target.Both, FileTask.Ignore); return FileDiff.Same; }
public override void InsertOrIgnoreDirection(SyncDirection direction, SQLiteCommand cmd) { string directionVal = direction.ToString(); cmd.Parameters.Clear(); cmd.CommandText = //"INSERT OR IGNORE INTO SyncDirection (SyncDirectionValue) VALUES (@directionVal)"; "INSERT OR IGNORE INTO " + NwdContract.TABLE_SYNC_DIRECTION + " (" + NwdContract.COLUMN_SYNC_DIRECTION_VALUE + ") VALUES (@directionVal)"; cmd.Parameters.AddWithValue("@directionVal", directionVal); cmd.ExecuteNonQuery(); }
/// <summary> /// Synchronizes the specified client. /// </summary> /// <param name="client">The client.</param> /// <param name="server">The server.</param> /// <param name="syncDirection">The sync direction.</param> /// <param name="clientId">The client id.</param> public void Synchronize(IPersistenceEngine client, IPersistenceEngine server, SyncDirection syncDirection, string clientId) { switch (syncDirection) { case SyncDirection.FullDownload: FullDownload(client, server, true); break; case SyncDirection.FullDownloadNoBulk: FullDownload(client, server, false); break; case SyncDirection.SmartDownload: SmartDownload(client, server as SyncEngine, clientId); break; case SyncDirection.SmartUpload: SmartUpload(client as SyncEngine, server); break; case SyncDirection.SmartUploadDownload: SmartUploadDownload(client as SyncEngine, server as SyncEngine); break; } }
public abstract void InsertOrIgnoreDirection(SyncDirection direction, SQLiteCommand cmd);
public int GetDirectionId(SyncDirection direction) { return directionIds[direction]; }
public void InsertOrIgnoreDirection(SyncDirection direction, SQLiteCommand cmd) { db.InsertOrIgnoreDirection(direction, cmd); }