Exemplo n.º 1
0
        static void TimerExecution()
        {
            //Atualiza a config
            try
            {
                String      ConfigJson = Encoding.UTF8.GetString(File.ReadAllBytes(Path.Combine(basePath, "config.json")));
                ProxyConfig tmpConfig  = new ProxyConfig();
                tmpConfig.FromJsonString(ConfigJson);
                ConfigJson = null;

                config = tmpConfig;
            }
            catch { }

            System.Reflection.Assembly asm = System.Reflection.Assembly.GetAssembly(plugin.GetType());

            foreach (PluginConfig p in config.plugins)
            {
                //Pode haver varios plugins com o mesmo nome, porém estarão em "resources" diferente
                if (p.uri.ToLower() == plugin.GetPluginId().AbsoluteUri.ToLower())
                {
                    DateTime nextExecute = new DateTime(1970, 01, 01);

                    String nextExFile = Path.GetFullPath(asm.Location) + "-" + p.resource.ToString() + ".nextex";

                    if (File.Exists(nextExFile))
                    {
                        String tmp = File.ReadAllText(nextExFile, Encoding.UTF8);
                        DateTime.TryParseExact(tmp, "yyyy-MM-dd HH:mm:ss", null, System.Globalization.DateTimeStyles.None, out nextExecute);
                    }

                    DateTime date = DateTime.Now;
                    TimeSpan ts   = date - new DateTime(1970, 01, 01);

                    Schedule schedule = new Schedule();
                    try
                    {
                        schedule.FromJsonString(p.schedule);
                    }
                    catch {
                        schedule = null;
                    }

                    if (schedule == null)
                    {
                        continue;
                    }

                    //Check Start date
                    if (nextExecute.Year == 1970)
                    {
                        nextExecute = new DateTime(schedule.StartDate.Year, schedule.StartDate.Month, schedule.StartDate.Day, schedule.TriggerTime.Hour, schedule.TriggerTime.Minute, 0);
                        File.WriteAllText(nextExFile, nextExecute.ToString("yyyy-MM-dd HH:mm:ss"), Encoding.UTF8);
                    }

                    TimeSpan stDateTs = nextExecute - new DateTime(1970, 01, 01);
                    if (ts.TotalSeconds >= stDateTs.TotalSeconds) //Data e hora atual maior ou igual a data que se deve iniciar
                    {
                        TextLog.Log("PluginStarter", "[" + p.resource + "] Starting execution");

                        try
                        {
                            switch (plugin.GetPluginId().Scheme)
                            {
                            case "connector":
                                ExecuteConnector();
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            TextLog.Log("PluginStarter", "[" + p.resource + "] Error on execution " + ex.Message);
                        }
                        finally
                        {
                            TextLog.Log("PluginStarter", "[" + p.resource + "] Execution completed");

                            //Agenda a próxima execução
                            DateTime calcNext = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, schedule.TriggerTime.Hour, schedule.TriggerTime.Minute, 0);
                            nextExecute = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, 0);
                            switch (schedule.Trigger)
                            {
                            case ScheduleTtiggers.Dialy:
                                calcNext = calcNext.AddDays(1);
                                break;

                            case ScheduleTtiggers.Monthly:
                                calcNext = calcNext.AddMonths(1);
                                break;

                            case ScheduleTtiggers.Annually:
                                calcNext = calcNext.AddYears(1);
                                break;
                            }

                            //TextLog.Log("PluginStarter", "Calc 1 " + calcNext.ToString("yyyy-MM-dd HH:mm:ss"));

                            if (schedule.Repeat > 0)
                            {
                                if (nextExecute.AddMinutes(schedule.Repeat).CompareTo(calcNext) < 0)
                                {
                                    nextExecute = nextExecute.AddMinutes(schedule.Repeat);
                                    //TextLog.Log("PluginStarter", "Calc 2 " + nextExecute.ToString("yyyy-MM-dd HH:mm:ss"));
                                }
                                else
                                {
                                    nextExecute = calcNext;
                                }
                            }
                            else
                            {
                                nextExecute = calcNext;
                            }

                            TextLog.Log("PluginStarter", "[" + p.resource + "] Next execution scheduled to " + nextExecute.ToString("yyyy-MM-dd HH:mm:ss"));
                            File.WriteAllText(nextExFile, nextExecute.ToString("yyyy-MM-dd HH:mm:ss"), Encoding.UTF8);
                        }
                    }
                    else
                    {
                        //Não está na hora da execução programada, mas verifica se há deploy a se fazer
                        try
                        {
                            DirectoryInfo dirFrom = new DirectoryInfo(Path.Combine(basePath, "In\\" + Path.GetFileNameWithoutExtension(asm.Location)));
                            if (!dirFrom.Exists) //Diretório inexistente
                            {
                                return;
                            }

                            if (dirFrom.GetFiles("*.iamdat", SearchOption.AllDirectories).Length > 0)
                            {
                                TextLog.Log("PluginStarter", "[" + p.resource + "] Deploy files identified, starting deploy only execution");
                                try
                                {
                                    ExecuteConnector(true);
                                }
                                catch (Exception ex)
                                {
                                    TextLog.Log("PluginStarter", "[" + p.resource + "] Error on execution " + ex.Message);
                                }
                                finally
                                {
                                    TextLog.Log("PluginStarter", "[" + p.resource + "] Execution completed");
                                }
                            }
                        }
                        catch { }
                    }
                }
            }
        }
Exemplo n.º 2
0
        static Int32 Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            if (args.Length == 0)
            {
                return(1);
            }

            System.Reflection.Assembly asm = System.Reflection.Assembly.GetAssembly(typeof(Program));
            basePath = Path.GetDirectoryName(asm.Location);

            if (!File.Exists(Path.Combine(basePath, "config.json")))
            {
                TextLog.Log("PluginStarter", "Json config file not found");
                return(2);
            }

            String ConfigJson = Encoding.UTF8.GetString(File.ReadAllBytes(Path.Combine(basePath, "config.json")));

            try
            {
                List <PluginBase> plugins = Plugins.GetPlugins <PluginBase>(Path.Combine(basePath, "plugins"));

                foreach (PluginBase p in plugins)
                {
                    if (p.GetPluginId().AbsoluteUri.ToLower() == args[0].ToLower())
                    {
                        plugin = p;
                    }
                }
            }
            catch (Exception ex)
            {
                TextLog.Log("PluginStarter", "Error loading plugins");
                return(3);
            }


            if (plugin == null)
            {
                TextLog.Log("PluginStarter", "Error startin with plugin " + args[0]);
                return(4);
            }

            config = new ProxyConfig();
            config.FromJsonString(ConfigJson);
            ConfigJson = null;

            logProxy = new LogProxy(basePath, config.server_cert);

            pluginsTimer = new Timer(new TimerCallback(TimerCallback), null, 1000, 60000);

            TextLog.Log("PluginStarter", "Successfully started with plugin " + plugin.GetPluginId().AbsoluteUri);
            Console.WriteLine("Successfully started with plugin " + plugin.GetPluginId().AbsoluteUri);

            while (true)
            {
                Console.ReadLine();
            }

            return(0);
        }
Exemplo n.º 3
0
        static void ProcessImport(Int64 resource, Dictionary <String, Object> connectorConf, Dictionary <String, String> mapping)
        {
            TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Starting import thread...");

            try
            {
                if (connectorConf == null)
                {
                    throw new Exception("connectorConf is null");
                }

                if (mapping == null)
                {
                    throw new Exception("mapping is null");
                }

                String id = Guid.NewGuid().ToString();

                JsonGeneric records = new JsonGeneric();
                records.function = "ProcessImport";
                records.fields   = new String[] { "resource", "uri", "importid", "registryid", "dataname", "datavalue", "datatype" };

                String uri = plugin.GetPluginId().AbsoluteUri.ToLower();

                String lastRegistryId = "";

                RegistryEvent reg = new RegistryEvent(delegate(String importId, String registryId, String dataName, String dataValue, String dataType)
                {
                    records.data.Add(new String[] { resource.ToString(), uri, importId, registryId, dataName, dataValue, dataType });

                    //Contabiliza a quantidade de registros para separar em vários arquivos
                    if (records.data.Count >= 2000)
                    {
                        //Após 2000 registros monitora a troca de registryId para salvar o arquivo
                        //Evitando que o mesmo registryId tenha dados em arquivos diferentes
                        //Isso evita problemas no servidor

                        if (lastRegistryId != registryId)
                        {
                            try
                            {
                                SaveToSend(records, importId);
                                records.data.Clear();
                            }
                            catch { }
                        }
                    }

                    lastRegistryId = registryId;
                });

                LogEvent log = new LogEvent(delegate(PluginBase sender, PluginLogType type, string text)
                {
                    TextLog.Log("PluginStarter", "{" + sender.GetPluginId().AbsoluteUri + "} " + type + ", " + text);
                });


                LogEvent2 log2 = new LogEvent2(delegate(PluginBase sender, PluginLogType type, Int64 entityId, Int64 identityId, String text, String additionalData)
                {
                    logProxy.AddLog("Proxy", resource.ToString(), sender.GetPluginId().AbsoluteUri, (UserLogLevel)((Int32)type), entityId, identityId, text, additionalData);
                });


                plugin.Registry += reg;
                plugin.Log      += log;
                plugin.Log2     += log2;

                plugin.ProcessImport(id, connectorConf, mapping);

                plugin.Registry -= reg;
                plugin.Log      -= log;
                plugin.Log2     -= log2;

                reg = null;
                log = null;
                uri = null;

                //Salva os registros remanescentes
                if (records.data.Count > 0)
                {
                    SaveToSend(records, id);
                }

                //Salva os logs para envio
                logProxy.SaveToSend(resource.ToString() + "log");
            }
            finally
            {
                TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Finishing import thread");
            }
        }
Exemplo n.º 4
0
        static void ProcessDeploy(Int64 resource, Dictionary <String, Object> connectorConf, Dictionary <String, String> mapping)
        {
            TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Starting deploy thread...");


            JsonGeneric notify = new JsonGeneric();

            notify.function = "notify";
            notify.fields   = new String[] { "source", "resource", "uri", "entityid" };


            try
            {
                System.Reflection.Assembly asm = System.Reflection.Assembly.GetAssembly(plugin.GetType());
                DirectoryInfo dirFrom          = new DirectoryInfo(Path.Combine(basePath, "In\\" + Path.GetFileNameWithoutExtension(asm.Location) + "\\" + resource));
                if (!dirFrom.Exists) //Diretório inexistente
                {
                    return;
                }

                //Ordena os arquivos, do mais antigo para o mais novo
                sortOndate      sod   = new sortOndate();
                List <FileInfo> files = new List <FileInfo>();
                files.AddRange(dirFrom.GetFiles("*.iamdat"));
                files.Sort(sod);

                foreach (FileInfo f in files)
                {
                    try
                    {
                        List <PluginBaseDeployPackage> fData = null;
                        try
                        {
                            fData = LoadFile(f);
                        }
                        catch (Exception ex)
                        {
                            TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Error reading file " + f.FullName.Replace(basePath, "") + ", " + ex.Message);
                            logProxy.AddLog("Proxy", resource.ToString(), plugin.GetPluginId().AbsoluteUri, UserLogLevel.Error, 0, 0, "Error reading file " + f.FullName.Replace(basePath, "") + ", " + ex.Message, "");
                        }

                        if (fData == null)
                        {
                            continue;
                        }

                        if (fData.Count == 0)
                        {
                            throw new Exception("Package is empty");
                        }

                        TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} [" + resource + "]" + fData.Count + " packages in " + f.Name);

                        LogEvent log = new LogEvent(delegate(PluginBase sender, PluginLogType type, String text)
                        {
                            TextLog.Log("PluginStarter", "{" + sender.GetPluginId().AbsoluteUri + "} " + type + ", " + text);
                        });

                        LogEvent2 log2 = new LogEvent2(delegate(PluginBase sender, PluginLogType type, Int64 entityId, Int64 identityId, String text, String additionalData)
                        {
                            logProxy.AddLog("Proxy", resource.ToString(), sender.GetPluginId().AbsoluteUri, (UserLogLevel)((Int32)type), entityId, identityId, text, additionalData);
                        });

                        NotityChangeUserEvent log3 = new NotityChangeUserEvent(delegate(PluginBase sender, Int64 entityId)
                        {
                            notify.data.Add(new String[] { "Proxy", resource.ToString(), sender.GetPluginId().AbsoluteUri, entityId.ToString() });
                        });

                        plugin.Log              += log;
                        plugin.Log2             += log2;
                        plugin.NotityChangeUser += log3;

                        try
                        {
                            foreach (PluginBaseDeployPackage pkg in fData)
                            {
                                try
                                {
                                    plugin.ProcessDeploy(pkg, connectorConf, mapping);
                                }
                                catch (Exception ex)
                                {
                                    logProxy.AddLog("Proxy", resource.ToString(), plugin.GetPluginId().AbsoluteUri, UserLogLevel.Error, pkg.entityId, 0, "error on ProcessDeploy thread of file " + f.FullName.Replace(basePath, "") + ", " + ex.Message + (ex.InnerException != null ? " - " + ex.InnerException.Message : ""), "");
                                }
                            }
                        }
                        finally
                        {
                            plugin.Log              -= log;
                            plugin.Log2             -= log2;
                            plugin.NotityChangeUser -= log3;

                            log  = null;
                            log2 = null;
                            log3 = null;
                        }


                        //Salva as notificações
                        if (notify.data.Count > 0)
                        {
                            SaveToSend(notify, resource.ToString() + "notify");
                        }

                        //Salva os logs para envio
                        logProxy.SaveToSend(resource.ToString() + "log");

                        try
                        {
                            f.Delete();

                            if (dirFrom.GetFiles("*.iamdat").Length == 0)
                            {
                                dirFrom.Delete();
                            }

                            if (dirFrom.Parent.GetFiles("*.iamdat").Length == 0)
                            {
                                dirFrom.Parent.Delete();
                            }
                        }
                        catch { }
                    }
                    catch (Exception ex)
                    {
                        logProxy.AddLog("Proxy", resource.ToString(), plugin.GetPluginId().AbsoluteUri, UserLogLevel.Error, 0, 0, "Erro on deploy thread of file " + f.FullName.Replace(basePath, "") + ", " + ex.Message + (ex.InnerException != null ? " - " + ex.InnerException.Message : ""), "");
                    }
                }

                files.Clear();
            }
            catch (Exception ex)
            {
                logProxy.AddLog("Proxy", resource.ToString(), plugin.GetPluginId().AbsoluteUri, UserLogLevel.Error, 0, 0, "Erro on deploy thread: " + ex.Message, "");
                throw ex;
            }
            finally
            {
                //Salva as notificações
                if (notify.data.Count > 0)
                {
                    SaveToSend(notify, resource.ToString() + "notify");
                }

                //Salva os logs para envio
                logProxy.SaveToSend(resource.ToString() + "log");

                TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Finishing deploy thread...");
            }
        }
Exemplo n.º 5
0
        static void ExecuteConnector(Boolean deployOnly)
        {
            List <Int64> resource = new List <Int64>();

            //Separa os contextos
            String certPass = CATools.SHA1Checksum(Encoding.UTF8.GetBytes(config.fqdn));

            OpenSSL.X509.X509Certificate cert = CATools.LoadCert(Convert.FromBase64String(config.client_cert), certPass);
            foreach (PluginConfig p in config.plugins)
            {
                if (p.uri.ToLower() == plugin.GetPluginId().AbsoluteUri.ToLower())
                {
                    JsonGeneric pgConf = new JsonGeneric();
                    try
                    {
                        using (CryptApi cApi = CryptApi.ParsePackage(cert, Convert.FromBase64String(p.parameters)))
                            pgConf.FromJsonString(Encoding.UTF8.GetString(cApi.clearData));
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("Decrypt error1 " + ex.Message);
                    }
                    finally
                    {
                        pgConf = null;
                    }

                    if (!resource.Contains(p.resource))
                    {
                        resource.Add(p.resource);
                    }
                }
            }


            foreach (Int64 r in resource)
            {
                Dictionary <String, Object> connectorConf = new Dictionary <String, Object>();
                Dictionary <String, String> mapping       = new Dictionary <String, String>();

                Boolean enableDeploy = false;

                try
                {
                    foreach (PluginConfig p in config.plugins)
                    {
                        if ((p.uri.ToLower() == plugin.GetPluginId().AbsoluteUri.ToLower()) && (p.resource == r))
                        {
                            mapping      = p.mappingDataTypeDic;
                            enableDeploy = p.enable_deploy;

                            JsonGeneric pgConf = new JsonGeneric();
                            try
                            {
                                if (cert == null)
                                {
                                    throw new Exception("Certificate is null");
                                }

                                using (CryptApi cApi = CryptApi.ParsePackage(cert, Convert.FromBase64String(p.parameters)))
                                    pgConf.FromJsonString(Encoding.UTF8.GetString(cApi.clearData));
                            }
                            catch (Exception ex)
                            {
                                throw new Exception("Decrypt error: " + ex.Message);
                            }

                            if ((pgConf.data == null) || (pgConf.data.Count == 0))
                            {
                                continue;
                            }

                            Int32 kCol = pgConf.GetKeyIndex("key");
                            Int32 vCol = pgConf.GetKeyIndex("value");

                            if (!String.IsNullOrWhiteSpace(p.mail_domain))
                            {
                                connectorConf.Add("iam_mail_domain", p.mail_domain);
                            }

                            foreach (String[] d1 in pgConf.data)
                            {
                                if (!connectorConf.ContainsKey(d1[kCol]))
                                {
                                    connectorConf.Add(d1[kCol], d1[vCol].ToString());
                                }
                            }
                        }
                    }

                    //Deploy ocorre antes da importação
                    //Para que na importação ja apareça os registros que foram publicados pelo deploy
                    try
                    {
                        if (enableDeploy)
                        {
                            ProcessDeploy(r, connectorConf, mapping);
                        }
                        else
                        {
                            TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Deploy disabled");

                            //Exclui os arquivos
                            System.Reflection.Assembly asm = System.Reflection.Assembly.GetAssembly(plugin.GetType());
                            DirectoryInfo dirFrom          = new DirectoryInfo(Path.Combine(basePath, "In\\" + Path.GetFileNameWithoutExtension(asm.Location) + "\\" + resource));
                            if (dirFrom.Exists)
                            {
                                foreach (FileInfo f in dirFrom.GetFiles("*.iamdat"))
                                {
                                    f.Delete();
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Error on deploy: " + ex.Message);
                    }


                    if (!deployOnly)
                    {
                        try
                        {
                            //O import não é desabilitado, pois ele é necessário para relatório de consistência
                            //o Engine não utilizará ele para adicionar novas entidades
                            ProcessImport(r, connectorConf, mapping);
                        }
                        catch (Exception ex)
                        {
                            TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Error on import: " + ex.Message);
                        }
                    }
                }
                catch (Exception ex)
                {
                    TextLog.Log("PluginStarter", "{" + plugin.GetPluginId().AbsoluteUri + "} Error on parse config: " + ex.Message);
                }
                finally
                {
                    connectorConf.Clear();
                    connectorConf = null;

                    mapping.Clear();
                    mapping = null;
                }
            }

            cert     = null;
            certPass = null;
        }
Exemplo n.º 6
0
        static void Main(string[] args)
        {
            localConfig = new ServerLocalConfig();
            localConfig.LoadConfig();

            if ((localConfig.SqlServer == null) || (localConfig.SqlServer.Trim() == ""))
            {
                StopOnError("Parâmetro 'sqlserver' não localizado no arquivo de configuração 'server.conf'", null);
            }

            if ((localConfig.SqlDb == null) || (localConfig.SqlDb.Trim() == ""))
            {
                StopOnError("Parâmetro 'sqldb' não localizado no arquivo de configuração 'server.conf'", null);
            }

            if ((localConfig.SqlUsername == null) || (localConfig.SqlUsername.Trim() == ""))
            {
                StopOnError("Parâmetro 'sqlusername' não localizado no arquivo de configuração 'server.conf'", null);
            }

            if ((localConfig.SqlPassword == null) || (localConfig.SqlPassword.Trim() == ""))
            {
                StopOnError("Parâmetro 'sqlpassword' não localizado no arquivo de configuração 'server.conf'", null);
            }

            Int32 cnt      = 0;
            Int32 stepWait = 15000;

            while (cnt <= 10)
            {
                try
                {
                    MSSQLDB db = new MSSQLDB(localConfig.SqlServer, localConfig.SqlDb, localConfig.SqlUsername, localConfig.SqlPassword);
                    db.openDB();

                    db.closeDB();

                    break;
                }
                catch (Exception ex)
                {
                    if (cnt < 10)
                    {
                        TextLog.Log("Engine", "Falha ao acessar o banco de dados: " + ex.Message);
                        Thread.Sleep(stepWait);
                        stepWait = stepWait * 2;
                        cnt++;
                    }
                    else
                    {
                        StopOnError("Falha ao acessar o banco de dados", ex);
                    }
                }
            }


            /*************
             * Gera os certificados do servidor
             * Verifica se o certificade está próximo de vencer
             */
            MSSQLDB db2 = new MSSQLDB(localConfig.SqlServer, localConfig.SqlDb, localConfig.SqlUsername, localConfig.SqlPassword);

            db2.openDB();


            DataTable created = db2.Select("select * from vw_entity_mails where create_date between CONVERT(datetime, convert(varchar(10),DATEADD(DAY, -1, GETDATE()),120) + ' 00:00:00', 120) and CONVERT(datetime, convert(varchar(10),getdate(),120) + ' 23:59:59', 120) order by context_name, full_name");
            DataTable all     = db2.Select("select * from vw_entity_mails order by context_name, full_name");
            Dictionary <String, String> title = new Dictionary <string, string>();

            title.Add("context_name", "Contexto");
            title.Add("full_name", "Nome completo");
            title.Add("login", "Login");
            title.Add("create_date", "Data de criação");
            title.Add("last_login", "Ultimo login");
            title.Add("mail", "E-mail");
            title.Add("locked", "Bloqueado");

            ReportBase rep1 = new ReportBase(created, title);
            ReportBase rep2 = new ReportBase(all, title);

            List <Attachment> atts = new List <Attachment>();

            using (MemoryStream ms1 = new MemoryStream(Encoding.UTF8.GetBytes(rep1.GetTXT())))
                using (MemoryStream ms2 = new MemoryStream(Encoding.UTF8.GetBytes(rep1.GetXML("Usuários", ""))))
                    using (MemoryStream ms3 = new MemoryStream(Encoding.UTF8.GetBytes(rep2.GetTXT())))
                        using (MemoryStream ms4 = new MemoryStream(Encoding.UTF8.GetBytes(rep2.GetXML("Usuários", ""))))
                        {
                            atts.Add(new Attachment(ms1, "created.txt"));
                            atts.Add(new Attachment(ms2, "created.xls"));
                            atts.Add(new Attachment(ms3, "all.txt"));
                            atts.Add(new Attachment(ms4, "all.xls"));

                            List <String> to = new List <string>();
                            to.Add("*****@*****.**");
                            to.Add("*****@*****.**");
                            to.Add("*****@*****.**");

                            sendEmail(db2, "Listagem de usuários em " + DateTime.Now.ToString("dd/MM/yyyy"), to, created.Rows.Count + " usuários criados de " + DateTime.Now.AddDays(-1).ToString("dd/MM/yyyy") + " até " + DateTime.Now.ToString("dd/MM/yyyy"), false, atts);
                        }
            db2.closeDB();
        }