public static ImageSource GetLogo(string sid)
        {
            try
            {
                if (App.Settings.Vendor.BuildType == AppBuildType.Embedded)
                {
                    return(ImageSource.FromFile(App.Settings.Vendor.Logo));
                }
                else
                {
                    INativeHelper helper = DependencyService.Get <INativeHelper>();

                    byte[] bytes = helper.GetFile($"{App.Settings.AppDirectory}/{sid.ToUpper()}/logo.png");
                    if (bytes != null)
                    {
                        return(ImageSource.FromStream(() => new MemoryStream(bytes)));
                    }
                }
            }
            catch (Exception ex)
            {
                EbLog.Error("GetLogo" + ex.Message);
            }
            return(null);
        }
Esempio n. 2
0
        public static List <FileWrapper> GetFilesByPattern(string Patten, string ControlName = null)
        {
            List <FileWrapper> Files = new List <FileWrapper>();

            try
            {
                INativeHelper helper = DependencyService.Get <INativeHelper>();

                string sid  = App.Settings.Sid.ToUpper();
                string root = App.Settings.AppDirectory;

                string[] filenames = helper.GetFiles($"{root}/{sid}/FILES", Patten);

                foreach (string filepath in filenames)
                {
                    string filename = Path.GetFileName(filepath);

                    var bytes = helper.GetFile($"{root}/{sid}/FILES/{filename}");

                    Files.Add(new FileWrapper
                    {
                        Name        = Path.GetFileNameWithoutExtension(filename),
                        Bytea       = bytes,
                        FileName    = filename,
                        ControlName = ControlName
                    });
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return(Files);
        }
Esempio n. 3
0
        public void AppendEbColValues(bool addCreatedAt, bool isPrimaryTable)
        {
            this.Columns.Add(new MobileTableColumn {
                Name = "eb_loc_id", Type = EbDbTypes.Int32, Value = App.Settings.CurrentLocId
            });

            if (isPrimaryTable)
            {
                if (addCreatedAt)//eb_created_at_device for Offline submission
                {
                    this.Columns.Add(new MobileTableColumn {
                        Name = "eb_created_at_device", Type = EbDbTypes.DateTime, Value = DateTime.UtcNow
                    });
                }

                try
                {
                    INativeHelper helper     = DependencyService.Get <INativeHelper>();
                    string        appversion = string.Format("{0}({1} {2}:{3})-{4}", DeviceInfo.Manufacturer, DeviceInfo.Model, DeviceInfo.Platform, DeviceInfo.VersionString, helper.AppVersion);

                    this.Columns.Add(new MobileTableColumn {
                        Name = "eb_device_id", Type = EbDbTypes.String, Value = helper.DeviceId
                    });
                    this.Columns.Add(new MobileTableColumn {
                        Name = "eb_appversion", Type = EbDbTypes.String, Value = appversion
                    });
                }
                catch (Exception ex)
                {
                    EbLog.Error(ex.Message);
                }
            }
        }
        private async void DeviceId_Clicked(object sender, EventArgs e)
        {
            INativeHelper helper = DependencyService.Get <INativeHelper>();
            await Clipboard.SetTextAsync(helper.DeviceId);

            Utils.Toast("Copied to clipboard");
        }
Esempio n. 5
0
        public async Task UpdateAuthInfo(ApiAuthResponse resp, string username)
        {
            try
            {
                await Store.SetValueAsync(AppConst.BTOKEN, resp.BToken);

                await Store.SetValueAsync(AppConst.RTOKEN, resp.RToken);

                App.Settings.RToken      = resp.RToken;
                App.Settings.BToken      = resp.BToken;
                App.Settings.CurrentUser = resp.User;

                await Store.SetJSONAsync(AppConst.USER_OBJECT, resp.User);

                if (resp.DisplayPicture != null)
                {
                    INativeHelper helper = DependencyService.Get <INativeHelper>();

                    string url = helper.NativeRoot + $"/{App.Settings.AppDirectory}/{ App.Settings.Sid.ToUpper()}/user.png";
                    File.WriteAllBytes(url, resp.DisplayPicture);
                }
            }
            catch (Exception ex)
            {
                EbLog.Error("UpdateAuthInfo---" + ex.Message);
            }
        }
 public async Task ShowMsgIfLatestAppAvailable(bool force)
 {
     try
     {
         if (Utils.HasInternet && App.Settings.SyncInfo.LatestAppVersion != null)
         {
             if (force || App.Settings.SyncInfo.AppUpdateLastNotifyTs < DateTime.Now.Subtract(new TimeSpan(4, 0, 0)))
             {
                 INativeHelper helper = DependencyService.Get <INativeHelper>();
                 if (Version.Parse(App.Settings.SyncInfo.LatestAppVersion).CompareTo(Version.Parse(helper.AppVersion)) > 0)
                 {
                     string msg = $"Latest app version {App.Settings.SyncInfo.LatestAppVersion} is available. \n(Current version: {helper.AppVersion})";
                     MessageDialog.ShowUpdateMessage(msg);
                     App.Settings.SyncInfo.AppUpdateLastNotifyTs = DateTime.Now;
                 }
                 else
                 {
                     App.Settings.SyncInfo.LatestAppVersion = null;
                 }
                 await Store.SetJSONAsync(AppConst.LAST_SYNC_INFO, App.Settings.SyncInfo);
             }
         }
     }
     catch (Exception ex)
     {
         EbLog.Error("ShowMsgIfLatestAppAvailable: " + ex.Message);
     }
 }
        protected override bool OnBackButtonPressed()
        {
            try
            {
                // Begin an asyncronous task on the UI thread because we intend to ask the users permission.
                Device.BeginInvokeOnMainThread(async() =>
                {
                    if (await DisplayAlert("Exit page?", "Are you sure you want to exit this page? You will not be able to continue it.", "Yes", "No"))
                    {
                        INativeHelper nativeHelper = null;
                        nativeHelper = DependencyService.Get <INativeHelper>();
                        if (nativeHelper != null)
                        {
                            nativeHelper.CloseApp();
                        }
                        base.OnBackButtonPressed();

                        //await Navigation.PopAsync();
                    }
                });
            }
            catch (Exception ex)
            {
                Logging.Write(ex, "OnBackButtonPressed");
            }
            // Always return true because this method is not asynchronous.
            // We must handle the action ourselves: see above.
            return(true);
        }
        public void OnDynamicContentRendering()
        {
            LoginButtonLabel.Text = PageContent["NewSolutionButtonText"];
            INativeHelper helper = DependencyService.Get <INativeHelper>();

            DeviceIdButton.Text = helper.DeviceId;
            DeviceVersion.Text  = "v" + helper.AppVersion;
        }
 protected BaseHidDevice(IHidDeviceInfo deviceInfo, INativeHelper helper)
 {
     DeviceInfo   = deviceInfo ?? throw new ArgumentNullException($"{nameof(deviceInfo)} is null");
     Helper       = helper ?? throw new ArgumentNullException($"{nameof(helper)} is null");
     DisposeToken = DisposeTokenSource.Token;
     ReadHandle   = new SafeFileHandle(IntPtr.Zero, true);
     WriteHandle  = new SafeFileHandle(IntPtr.Zero, true);
 }
Esempio n. 10
0
        public void PushFilesToDir(string TableName, int RowId)
        {
            INativeHelper helper = DependencyService.Get <INativeHelper>();

            List <FileWrapper> files = XamControl.GetFiles(this.Name);

            foreach (FileWrapper wrapr in files)
            {
                wrapr.Name = $"{TableName}-{RowId}-{this.Name}-{Guid.NewGuid().ToString("n").Substring(0, 10)}.jpg";
                File.WriteAllBytes(helper.NativeRoot + $"/{App.Settings.AppDirectory}/{ App.Settings.Sid.ToUpper()}/FILES/{wrapr.Name}", wrapr.Bytea);
            }
        }
        protected BaseHidDeviceInfo(string devicePath, string description, INativeHelper helper)
        {
            DevicePath  = devicePath ?? throw new ArgumentNullException($"{nameof(devicePath)} is null");
            Description = description;
            Helper      = helper ?? throw new ArgumentNullException($"{nameof(helper)} is null");

            // Just open to get capabilities and attributes
            using (var hidHandle = Helper.OpenDevice(DevicePath, DesiredAccesses.AccessNone,
                                                     ShareModes.FileShareRead | ShareModes.FileShareWrite, FileFlags.FileFlagNone))
            {
                Capabilities = helper.GetCapabilities(hidHandle);
                Attributes   = helper.GetAttributes(hidHandle);
            }
        }
Esempio n. 12
0
        private static EJDB2Facade Initialize()
        {
            INativeHelper helper = NativeHelper.Create();
            var           e      = new ExceptionHelper(helper);

            ulong rc = helper.ejdb_init();

            if (rc != 0)
            {
                throw new InvalidOperationException("ejdb_init failed. Error code: " + rc);
            }

            return(new EJDB2Facade(helper));
        }
Esempio n. 13
0
        protected override bool OnBackButtonPressed()
        {
            INativeHelper nativeHelper = null;

            nativeHelper = DependencyService.Get <INativeHelper>();
            if (nativeHelper != null)
            {
                nativeHelper.CloseApp();
            }
            nativeHelper.CloseApp();
            base.OnBackButtonPressed();
            // Always return true because this method is not asynchronous.
            // We must handle the action ourselves: see above.
            return(true);
        }
Esempio n. 14
0
        public void SetLogo()
        {
            INativeHelper helper = DependencyService.Get <INativeHelper>();

            try
            {
                byte[] bytes = helper.GetFile($"{App.Settings.AppDirectory}/{this.SolutionName}/logo.png");

                if (bytes != null)
                {
                    this.Logo = ImageSource.FromStream(() => new MemoryStream(bytes));
                }
            }
            catch (Exception ex)
            {
                EbLog.Error("Login_SetLogo" + ex.Message);
            }
        }
Esempio n. 15
0
        public byte[] GetLocalFile(string filename)
        {
            try
            {
                INativeHelper helper = DependencyService.Get <INativeHelper>();

                byte[] bytes = helper.GetFile($"{App.Settings.AppDirectory}/{App.Settings.Sid.ToUpper()}/FILES/{filename}");
                if (bytes != null)
                {
                    return(bytes);
                }
            }
            catch (Exception ex)
            {
                EbLog.Error("GetLocalFile in Dataservice got some error :: " + ex.Message);
            }
            return(null);
        }
        public void SaveLogo(string solutionname, byte[] imageByte)
        {
            try
            {
                INativeHelper helper = DependencyService.Get <INativeHelper>();
                string        root   = App.Settings.AppDirectory;

                if (!helper.Exist($"{root}/{solutionname}/logo.png", SysContentType.File))
                {
                    File.WriteAllBytes(helper.NativeRoot + $"/{root}/{solutionname}/logo.png", imageByte);
                }
            }
            catch (Exception ex)
            {
                EbLog.Info($"Unable to create logo for solution '{solutionname}'");
                EbLog.Error(ex.Message);
            }
        }
Esempio n. 17
0
        public static void WriteFilesLocal(string filename, byte[] fileBytea)
        {
            try
            {
                INativeHelper helper = DependencyService.Get <INativeHelper>();

                string path = $"{App.Settings.AppDirectory}/{App.Settings.Sid.ToUpper()}/FILES/{filename}";

                if (!helper.Exist(path, SysContentType.File))
                {
                    File.WriteAllBytes(helper.NativeRoot + $"/{path}", fileBytea);
                }
            }
            catch (Exception ex)
            {
                EbLog.Error(ex.Message);
                EbLog.Error(ex.StackTrace);
            }
        }
Esempio n. 18
0
        public async Task <ApiAuthResponse> AuthenticateAsync(string username, string password, bool anonymous = false)
        {
            ApiAuthResponse resp;

            try
            {
                RestRequest request = new RestRequest(ApiConstants.AUTHETICATE, Method.GET);

                request.AddParameter("username", username.Trim().ToLower());
                request.AddParameter("password", string.Concat(password, username).ToMD5());
                INativeHelper helper = DependencyService.Get <INativeHelper>();
                request.AddParameter("deviceid", helper.DeviceId);

                if (anonymous)
                {
                    request.AddParameter("anonymous", true);
                }

                IRestResponse response = await HttpClient.ExecuteAsync(request);

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    resp = JsonConvert.DeserializeObject <ApiAuthResponse>(response.Content);
                }
                else
                {
                    resp = new ApiAuthResponse {
                        IsValid = false, Message = "Auth failed: " + response.ErrorMessage
                    }
                };
            }
            catch (Exception ex)
            {
                EbLog.Error(ex.Message);
                resp = new ApiAuthResponse {
                    IsValid = false, Message = "Auth failed: " + ex.Message
                };
            }
            return(resp);
        }
        public void OnDynamicContentRendering()
        {
            try
            {
                INativeHelper helper = DependencyService.Get <INativeHelper>();

                DeviceId.Text = $"DEVICE ID : {helper.DeviceId}";

                AppVersion.Text = $"Version {helper.AppVersion}";

                VendorDescription.Text = PageContent["Description"];

                if (PageContent.TryGetValue("Url", out string url) && Utils.HasInternet)
                {
                    StaticContent.IsVisible   = false;
                    ExternalWebLink.Source    = url;
                    ExternalWebLink.IsVisible = true;
                }
            }
            catch (Exception ex)
            {
                EbLog.Error(ex.Message + ex.StackTrace);
            }
        }
Esempio n. 20
0
        //version 2
        public async Task <SyncResponse> GetSolutionDataAsyncV2(Loader loader)
        {
            EbLog.BackupLogFiles();
            SyncResponse resp   = new SyncResponse();
            RestClient   client = new RestClient(App.Settings.RootUrl)
            {
                Timeout = ApiConstants.TIMEOUT_IMPORT
            };
            RestRequest request = new RestRequest(ApiConstants.GET_SOLUTION_DATAv2, Method.POST);

            request.AddHeader(AppConst.BTOKEN, App.Settings.BToken);
            request.AddHeader(AppConst.RTOKEN, App.Settings.RToken);

            Dictionary <string, object> metaDict = new Dictionary <string, object>();
            LastSyncInfo syncInfo = App.Settings.SyncInfo;

            if (syncInfo == null)
            {
                syncInfo = new LastSyncInfo();
            }

            if (syncInfo.LastSyncTs != DateTime.MinValue)
            {
                metaDict.Add(AppConst.last_sync_ts, syncInfo.LastSyncTs);
            }
            metaDict.Add(AppConst.draft_ids, GetErrorDraftIds());
            INativeHelper helper = DependencyService.Get <INativeHelper>();

            metaDict.Add(AppConst.app_version, helper.AppVersion);
            metaDict.Add(AppConst.device_id, helper.DeviceId);
            request.AddParameter(AppConst.metadata, JsonConvert.SerializeObject(metaDict));

            EbMobileSolutionData solutionData = null;

            try
            {
                IRestResponse response = await client.ExecuteAsync(request);

                if (response.IsSuccessful)
                {
                    Device.BeginInvokeOnMainThread(() => { loader.Message = "Processing pulled data..."; });

                    solutionData = JsonConvert.DeserializeObject <EbMobileSolutionData>(response.Content);

                    (bool incorrectDate, bool maintenanceMode, string msg) = await UpdateLastSyncInfo(solutionData, syncInfo, helper.AppVersion);

                    resp.Message = msg;

                    if (!maintenanceMode)
                    {
                        List <AppData> oldAppData = Store.GetJSON <List <AppData> >(AppConst.APP_COLLECTION);
                        MergeObjectsInSolutionData(solutionData, oldAppData);
                        await ImportSolutionData(solutionData);

                        Device.BeginInvokeOnMainThread(() => { loader.Message = "Importing latest document ids..."; });
                        EbLog.Info("Importing latest document ids...");
                        if (await GetLatestAutoId(solutionData.Applications))
                        {
                            if (!incorrectDate)
                            {
                                syncInfo.LastSyncTs        = solutionData.last_sync_ts;
                                syncInfo.LastOfflineSaveTs = solutionData.last_sync_ts;
                            }
                            resp.Status          = true;
                            syncInfo.PullSuccess = true;
                            await Store.SetJSONAsync(AppConst.LAST_SYNC_INFO, syncInfo);

                            EbLog.Info("[GetSolutionDataAsyncV2] api success");
                        }
                        else
                        {
                            resp.Message = "Failed to import latest doc ids";
                        }
                    }
                    else
                    {
                        syncInfo.PullSuccess = true;
                        await Store.SetJSONAsync(AppConst.LAST_SYNC_INFO, syncInfo);
                    }
                }
                else
                {
                    //callback?.Invoke(response.ResponseStatus);
                    resp.Message = "Pull failed. Try after sometime.";
                    EbLog.Info("[GetSolutionData] api failure, callback invoked");
                }
            }
            catch (Exception ex)
            {
                resp.Message = "Exception: " + ex.Message;
                EbLog.Error("Error on [GetSolutionData] request" + ex.Message);
            }
            return(resp);
        }
 public MockDeviceInfoCollection(INativeHelper helper) : base(helper)
 {
 }
Esempio n. 22
0
 public ExceptionHelper(INativeHelper helper)
 {
     _helper = helper ?? throw new ArgumentNullException(nameof(helper));
 }
 public MockDeviceInfo(string devicePath, string description, INativeHelper helper) : base(devicePath, description, helper)
 {
 }
Esempio n. 24
0
 public SafePreParsedDataHandle(INativeHelper helper) : base(IntPtr.Zero, true)
 {
     Helper = helper ?? throw new ArgumentNullException($"{nameof(helper)} is null");
 }
Esempio n. 25
0
 public ExecuteVisitor(INativeHelper helper, JQLCallback callback)
 {
     _helper   = helper;
     _callback = callback;
     _e        = new ExceptionHelper(helper);
 }
Esempio n. 26
0
 private JQLFacade(INativeHelper helper)
 {
     _helper = helper ?? throw new ArgumentNullException(nameof(helper));
     _e      = new ExceptionHelper(helper);
 }
Esempio n. 27
0
 public SafeDevInfoHandle(IntPtr existingHandle, INativeHelper helper) : base(existingHandle, true)
 {
     Helper = helper ?? throw new ArgumentNullException($"{nameof(helper)} is null");
 }
        public async Task <bool> Print(int rowId)
        {
            bool success = false;

            try
            {
                if (this.PrintDocs?.Count > 0)
                {
                    PdfService   PdfService = new PdfService();
                    List <Param> param      = new List <Param>();
                    if (this.RenderAsFilterDialog)
                    {
                        foreach (KeyValuePair <string, EbMobileControl> pair in this.ControlDictionary)
                        {
                            EbMobileControl ctrl = pair.Value;
                            if (ctrl is IFileUploadControl || ctrl is EbMobileDataGrid)
                            {
                                continue;
                            }
                            param.Add(new Param
                            {
                                Name  = ctrl.Name,
                                Type  = ((int)ctrl.EbDbType).ToString(),
                                Value = Convert.ToString(ctrl.GetValue())
                            });
                        }
                    }
                    else
                    {
                        param.Add(new Param
                        {
                            Name  = "id",
                            Type  = ((int)EbDbTypes.Int32).ToString(),
                            Value = rowId.ToString()
                        });
                    }

                    ReportRenderResponse r = null;

                    if (NetworkType == NetworkMode.Online)
                    {
                        if (!Utils.IsNetworkReady(this.NetworkType))
                        {
                            Utils.Alert_NoInternet();
                            return(false);
                        }
                        r = await PdfService.GetPdfOnline(this.PrintDocs[0].ObjRefId, JsonConvert.SerializeObject(param));
                    }
                    else if (NetworkType == NetworkMode.Offline)
                    {
                        r = PdfService.GetPdfOffline(this.PrintDocs[0].ObjRefId, JsonConvert.SerializeObject(param));
                    }

                    if (r?.ReportBytea != null)
                    {
                        INativeHelper helper = DependencyService.Get <INativeHelper>();
                        string        root   = App.Settings.AppDirectory;
                        string        path   = helper.NativeRoot + $"/{root}/{AppConst.SHARED_MEDIA}/{App.Settings.Sid.ToUpper()}/PDF{(DateTime.UtcNow.ToString("yyyyMMddHHmmss"))}.pdf";
                        File.WriteAllBytes(path, r.ReportBytea);

                        IAppHandler handler = DependencyService.Get <IAppHandler>();
                        string      res     = await handler.PrintPdfFile(path);

                        if (res != "success")
                        {
                            await Launcher.OpenAsync(new OpenFileRequest
                            {
                                File = new ReadOnlyFile(path)
                            });
                        }
                        success = true;
                    }
                }
            }
            catch (Exception ex)
            {
                Utils.Toast("Error: " + ex.Message);
                EbLog.Error("Error in [EbMobileForm.Print] " + ex.Message + " " + ex.StackTrace);
            }
            return(success);
        }
 protected BaseHidDeviceInfoCollection(INativeHelper helper)
 {
     Helper     = helper ?? throw new ArgumentNullException($"{nameof(helper)} is null");
     _innerList = helper.EnumerateDeviceInfo()?.ToList() ?? new List <IHidDeviceInfo>();
 }
Esempio n. 30
0
        public async Task <EbMobileSolutionData> GetSolutionDataAsync(Loader loader)
        {
            if (App.Settings.SyncInProgress)
            {
                EbLog.Info(App.Settings.Sid + ": Sync in progress...");
                return(null);
            }
            App.Settings.SyncInProgress = true;
            EbLog.BackupLogFiles();
            EbMobileSolutionData solutionData = null;
            bool flag = false;

            try
            {
                loader.Message = "Sync started...";
                EbLog.Info("Sync started...");

                LocalDBServie service  = new LocalDBServie();
                SyncResponse  response = await service.PushDataToCloud(loader);

                if (response.Status)
                {
                    loader.Message = string.Empty;
                }
                else
                {
                    loader.Message = response.Message + " \n";
                }

                loader.Message += "Fetching data from server...";
                EbLog.Info("Fetching data from server...");

                RestClient client = new RestClient(App.Settings.RootUrl)
                {
                    Timeout = ApiConstants.TIMEOUT_IMPORT
                };
                RestRequest request = new RestRequest(ApiConstants.GET_SOLUTION_DATAv2, Method.POST);

                request.AddHeader(AppConst.BTOKEN, App.Settings.BToken);
                request.AddHeader(AppConst.RTOKEN, App.Settings.RToken);
                Dictionary <string, object> metaDict = new Dictionary <string, object>();
                metaDict.Add(AppConst.draft_ids, GetErrorDraftIds());
                INativeHelper helper = DependencyService.Get <INativeHelper>();
                metaDict.Add(AppConst.app_version, helper.AppVersion);
                metaDict.Add(AppConst.device_id, helper.DeviceId);
                request.AddParameter(AppConst.metadata, JsonConvert.SerializeObject(metaDict));

                IRestResponse resp = await client.ExecuteAsync(request);

                if (resp.IsSuccessful)
                {
                    loader.Message = "Processing pulled data...";

                    LastSyncInfo syncInfo = App.Settings.SyncInfo;
                    if (syncInfo == null)
                    {
                        syncInfo = new LastSyncInfo();
                    }
                    solutionData = JsonConvert.DeserializeObject <EbMobileSolutionData>(resp.Content);

                    (bool incorrectDate, bool maintenanceMode, string msg) = await UpdateLastSyncInfo(solutionData, syncInfo, helper.AppVersion);

                    if (!maintenanceMode)
                    {
                        await ImportSolutionData(solutionData);

                        loader.Message = "Importing latest document ids...";
                        EbLog.Info("Importing latest document ids...");
                        if (await GetLatestAutoId(solutionData.Applications))
                        {
                            if (!incorrectDate)
                            {
                                syncInfo.LastSyncTs        = solutionData.last_sync_ts;
                                syncInfo.LastOfflineSaveTs = solutionData.last_sync_ts;
                            }
                            else
                            {
                                Utils.Toast(msg);
                            }

                            syncInfo.PullSuccess = true;
                            await Store.SetJSONAsync(AppConst.LAST_SYNC_INFO, syncInfo);

                            flag = true;
                        }
                        else
                        {
                            Utils.Toast("Failed to import latest doc ids");
                        }
                    }
                    else
                    {
                        Utils.Toast(msg);
                        syncInfo.PullSuccess = true;
                        await Store.SetJSONAsync(AppConst.LAST_SYNC_INFO, syncInfo);
                    }
                }
                else
                {
                    Utils.Toast(response.Message ?? "Sync failed");
                    EbLog.Warning(response.Message ?? "Sync failed");
                }
            }
            catch (Exception ex)
            {
                EbLog.Error("Error on [GetSolutionData] request" + ex.Message);
                Utils.Toast(ex.Message);
            }
            loader.IsVisible            = false;
            App.Settings.SyncInProgress = false;
            return(flag ? solutionData : null);
        }