Пример #1
0
 private async Task ShowServiceMethods(string serviceName, TelegramClientInfo clientInfo, Message message)
 {
     clientInfo.CurrentServiceName = serviceName;
     clientInfo.CurrentMethodName  = null;
     if (Services.TryGetValue(serviceName, out Type service))
     {
         List <List <BotButtonInfo> > buttons = GetServiceMethodsButtons(service, clientInfo);
         CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Services, serviceName, null, clientInfo);
         ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
         {
             Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
         };
         await _botClient.SendTextMessageAsync(
             chatId : message.Chat,
             text : CurrentBotStructureInfo.GetServiceSelectedText(GetServiceName(service), GetServiceCaption(service), service, clientInfo),
             replyMarkup : replyMarkup
             );
     }
     else
     {
         await _botClient.SendTextMessageAsync(
             chatId : message.Chat,
             text : CurrentBotStructureInfo.GetServiceNotFoundText(serviceName, clientInfo)
             );
     }
 }
Пример #2
0
        private void _botClient_OnCallbackQuery(object sender, CallbackQueryEventArgs e)
        {
            try
            {
                if (!ConnectedClients.TryGetValue(e.CallbackQuery.Message.From.Id, out TelegramClientInfo clientInfo))
                {
                    clientInfo = new TelegramClientInfo(_serverBase)
                    {
                        ConnectedDateTime  = DateTime.Now,
                        ClientId           = Guid.NewGuid().ToString(),
                        Message            = e.CallbackQuery.Message,
                        SignalGoBotManager = this
                    };
                    _serverBase.Clients.TryAdd(clientInfo.ClientId, clientInfo);
                    ConnectedClients.TryAdd(e.CallbackQuery.Message.From.Id, clientInfo);
                    CurrentBotStructureInfo.OnClientConnected(clientInfo, this);
                }

                if (CustomInlineButtons.TryGetValue(e.CallbackQuery.Data, out Action <TelegramClientInfo> action))
                {
                    action?.Invoke(clientInfo);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
Пример #3
0
 private async Task GetParameterValueFromClient(MethodInfo methodInfo, ParameterInfo parameterInfo, TelegramClientInfo clientInfo, MessageEventArgs e)
 {
     if (!CurrentBotStructureInfo.OnParameterSelecting(methodInfo, parameterInfo, clientInfo, e.Message.Text))
     {
         if (parameterInfo == null)
         {
             List <List <BotButtonInfo> > buttons = GetMethodParametersButtons(methodInfo, clientInfo);
             CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Parameters, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo);
             ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
             {
                 Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
             };
             await _botClient.SendTextMessageAsync(
                 chatId : e.Message.Chat,
                 text : CurrentBotStructureInfo.GetParameterNotFoundText(e.Message.Text, clientInfo),
                 replyMarkup : replyMarkup
                 );
         }
         else
         {
             clientInfo.CurrentParameterName = parameterInfo.Name;
             List <List <BotButtonInfo> > buttons = GetMethodParametersButtons(methodInfo, clientInfo);
             CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Parameters, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo);
             ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
             {
                 Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
             };
             await _botClient.SendTextMessageAsync(
                 chatId : e.Message.Chat,
                 text : CurrentBotStructureInfo.GetParameterSelectedText(GetParameterCaption(methodInfo, parameterInfo), clientInfo),
                 replyMarkup : replyMarkup
                 );
         }
     }
 }
Пример #4
0
        private async Task ShowResultValue(Shared.Models.CallMethodResultInfo <OperationContext> callMethodResultInfo, MethodInfo methodInfo, TelegramClientInfo clientInfo, Message message)
        {
            clientInfo.CurrentParameterName = null;
            List <List <BotButtonInfo> > buttons = GetMethodParametersButtons(methodInfo, clientInfo);

            CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Parameters, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo);
            ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
            {
                Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
            };

            if (callMethodResultInfo.CallbackInfo.Data.Length > 4000)
            {
                using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(callMethodResultInfo.CallbackInfo.Data)))
                {
                    stream.Seek(0, SeekOrigin.Begin);
                    InputOnlineFile inputOnlineFile = new InputOnlineFile(stream);
                    inputOnlineFile.FileName = "reponse.txt";
                    await _botClient.SendDocumentAsync(
                        chatId : message.Chat,
                        document : inputOnlineFile,
                        caption : $"Response of {methodInfo.Name}",
                        replyMarkup : replyMarkup
                        );
                }
            }
            else
            {
                await _botClient.SendTextMessageAsync(
                    chatId : message.Chat,
                    text : callMethodResultInfo.CallbackInfo.Data,
                    replyMarkup : replyMarkup
                    );
            }
        }
Пример #5
0
        /// <summary>
        /// get buttons of all services
        /// </summary>
        /// <returns></returns>
        private List <List <BotButtonInfo> > GetListOfServicesButtons(TelegramClientInfo clientInfo)
        {
            List <BotButtonInfo> columns = new List <BotButtonInfo>();

            List <List <BotButtonInfo> > rows = new List <List <BotButtonInfo> >();

            int columnIndex             = 0;
            List <System.Type> services = _serverBase.GetListOfRegistredTypes().ToList();

            for (int i = 0; i < services.Count; i++)
            {
                System.Type item = services[i];
                ServiceContractAttribute attribute = item.GetCustomAttribute <ServiceContractAttribute>();
                if (attribute.ServiceType != ServiceType.HttpService)
                {
                    continue;
                }
                string serviceName = "";
                if (CurrentBotStructureInfo.InitializeServicesFromAttributes)
                {
                    BotDisplayNameAttribute nameAttribute = item.GetCustomAttribute <BotDisplayNameAttribute>();
                    if (nameAttribute == null)
                    {
                        continue;
                    }
                    //serviceName = nameAttribute.Content;
                }

                serviceName = attribute.Name;
                if (!CurrentBotStructureInfo.OnServiceGenerating(serviceName, clientInfo))
                {
                    continue;
                }
                if (!Services.ContainsKey(attribute.Name))
                {
                    Services.Add(serviceName, item);
                }
                if (columnIndex == 3)
                {
                    columnIndex = 0;
                    rows.Add(columns.ToList());
                    columns.Clear();
                }
                columns.Add(GetServiceCaption(item));
                columnIndex++;
            }
            if (rows.Count == 0)
            {
                rows.Add(columns);
            }
            return(rows);
        }
Пример #6
0
        private async Task ShowServiceMethods(MethodInfo method, TelegramClientInfo clientInfo, Message message, string customText = null)
        {
            clientInfo.CurrentMethodName = method.Name;
            List <List <BotButtonInfo> > buttons = GetMethodParametersButtons(method, clientInfo);

            CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Parameters, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo);
            ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
            {
                Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
            };
            await _botClient.SendTextMessageAsync(
                chatId : message.Chat,
                text : string.IsNullOrEmpty(customText)?CurrentBotStructureInfo.GetMethodSelectedText(method.Name, clientInfo) : customText,
                replyMarkup : replyMarkup
                );
        }
Пример #7
0
        /// <summary>
        /// get buttons of service
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        private List <List <BotButtonInfo> > GetServiceMethodsButtons(Type service, TelegramClientInfo clientInfo)
        {
            List <BotButtonInfo> columns = new List <BotButtonInfo>();

            List <List <BotButtonInfo> > rows = new List <List <BotButtonInfo> >();

            int columnIndex = 0;

            List <MethodInfo> methods = service.GetFullServiceLevelMethods().ToList();

            for (int i = 0; i < methods.Count; i++)
            {
                MethodInfo item       = methods[i];
                string     methodName = "";
                if (CurrentBotStructureInfo.InitializeServicesFromAttributes)
                {
                    BotDisplayNameAttribute nameAttribute = item.GetCustomAttribute <BotDisplayNameAttribute>();
                    if (nameAttribute == null)
                    {
                        continue;
                    }
                    methodName = nameAttribute.Content;
                }
                else
                {
                    methodName = item.Name;
                }
                //create new row after 2 columns
                if (columnIndex == 2)
                {
                    columnIndex = 0;
                    rows.Add(columns.ToList());
                    columns.Clear();
                }
                columns.Add(methodName);
                columnIndex++;
            }
            if (rows.Count == 0)
            {
                rows.Add(columns);
            }
            rows.Add(new List <BotButtonInfo>()
            {
                new BotButtonInfo(CurrentBotStructureInfo.GetCancelButtonText(clientInfo))
            });
            return(rows);
        }
Пример #8
0
 public async void ShowServices(TelegramClientInfo clientInfo, List <List <BotButtonInfo> > inlineButtonInfos, string message = null)
 {
     try
     {
         clientInfo.CurrentServiceName = null;
         InlineKeyboardMarkup replyMarkup = new InlineKeyboardMarkup(BotButtonsToKeyboardButtons(inlineButtonInfos));
         await _botClient.SendTextMessageAsync(
             chatId : clientInfo.Message.Chat,
             text : message == null?CurrentBotStructureInfo.GetServicesGeneratedText(clientInfo) : message,
             replyMarkup : replyMarkup
             );
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex);
     }
 }
Пример #9
0
        private async Task ShowServices(TelegramClientInfo clientInfo, MessageEventArgs e)
        {
            string text = CurrentBotStructureInfo.GetServicesGeneratedText(clientInfo);

            clientInfo.CurrentServiceName = null;
            List <List <BotButtonInfo> > buttons = GetListOfServicesButtons(clientInfo);

            CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Services, null, null, clientInfo);
            ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
            {
                Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
            };
            await _botClient.SendTextMessageAsync(
                chatId : e.Message.Chat,
                text : text,
                replyMarkup : replyMarkup
                );
        }
Пример #10
0
        public async Task Start(string token, ServerBase serverBase, IBotStructureInfo botStructureInfo = null, System.Net.Http.HttpClient httpClient = null)
        {
            if (botStructureInfo == null)
            {
                CurrentBotStructureInfo = new BotStructureInfo();
            }
            else
            {
                CurrentBotStructureInfo = botStructureInfo;
            }
            _serverBase = serverBase;
            _botClient  = new TelegramBotClient(token, httpClient);

            User me = await _botClient.GetMeAsync();

            _botClient.OnCallbackQuery += _botClient_OnCallbackQuery;
            _botClient.OnMessage       += Bot_OnMessage;
            _botClient.StartReceiving();
            CurrentBotStructureInfo.OnStarted(this);
        }
Пример #11
0
        private async Task SetParameterValueFromClient(MethodInfo methodInfo, ParameterInfo parameterInfo, TelegramClientInfo clientInfo, MessageEventArgs e)
        {
            string value = e.Message.Text;

            clientInfo.CurrentParameterName = null;
            List <List <BotButtonInfo> > buttons = GetMethodParametersButtons(methodInfo, clientInfo);

            CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Parameters, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo);
            ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
            {
                Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
            };

            ChangeParameterValue(methodInfo, parameterInfo, clientInfo, value);
            await _botClient.SendTextMessageAsync(
                chatId : e.Message.Chat,
                text : CurrentBotStructureInfo.GetParameterValueChangedText(GetParameterCaption(methodInfo, parameterInfo), clientInfo),
                replyMarkup : replyMarkup
                );
        }
Пример #12
0
        private async Task ShowResultValue(string response, MethodInfo methodInfo, TelegramClientInfo clientInfo, MessageEventArgs e)
        {
            if (string.IsNullOrEmpty(response))
            {
                return;
            }
            clientInfo.CurrentParameterName = null;
            List <List <BotButtonInfo> > buttons = GetMethodParametersButtons(methodInfo, clientInfo);

            CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Parameters, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo);
            ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
            {
                Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
            };
            await _botClient.SendTextMessageAsync(
                chatId : e.Message.Chat,
                text : response,
                replyMarkup : replyMarkup
                );
        }
Пример #13
0
 public async void SendText(string text, TelegramClientInfo clientInfo, List <List <BotButtonInfo> > botButtons)
 {
     try
     {
         clientInfo.CurrentServiceName = null;
         CurrentBotStructureInfo.OnButtonsGenerating(botButtons, BotLevelType.Services, null, null, clientInfo);
         ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
         {
             Keyboard = BotButtonsToKeyboardButtons(botButtons, clientInfo)
         };
         await _botClient.SendTextMessageAsync(
             chatId : clientInfo.Message.Chat,
             text : text,
             replyMarkup : replyMarkup
             );
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex);
     }
 }
Пример #14
0
 public async void ShowServices(TelegramClientInfo clientInfo, string message = null)
 {
     try
     {
         clientInfo.CurrentServiceName = null;
         List <List <BotButtonInfo> > buttons = GetListOfServicesButtons(clientInfo);
         CurrentBotStructureInfo.OnButtonsGenerating(buttons, BotLevelType.Services, null, null, clientInfo);
         ReplyKeyboardMarkup replyMarkup = new ReplyKeyboardMarkup
         {
             Keyboard = BotButtonsToKeyboardButtons(buttons, clientInfo)
         };
         await _botClient.SendTextMessageAsync(
             chatId : clientInfo.Message.Chat,
             text : message == null?CurrentBotStructureInfo.GetServicesGeneratedText(clientInfo) : message,
             replyMarkup : replyMarkup
             );
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex);
     }
 }
Пример #15
0
        private List <List <BotButtonInfo> > GetMethodParametersButtons(MethodInfo method, TelegramClientInfo clientInfo)
        {
            List <BotButtonInfo> columns = new List <BotButtonInfo>();

            List <List <BotButtonInfo> > rows = new List <List <BotButtonInfo> >();

            int columnIndex = 0;

            List <ParameterInfo>    parameters    = method.GetParameters().ToList();
            BotDisplayNameAttribute nameAttribute = method.GetCustomAttribute <BotDisplayNameAttribute>();

            for (int i = 0; i < parameters.Count; i++)
            {
                ParameterInfo item          = parameters[i];
                string        parameterName = "";
                if (CurrentBotStructureInfo.InitializeServicesFromAttributes)
                {
                    if (nameAttribute != null)
                    {
                        parameterName = nameAttribute.FindValue(item.Name);
                        //for take parameter attribute
                        if (parameterName == null)
                        {
                            nameAttribute = null;
                        }
                    }
                    //take attribute of parameter
                    if (nameAttribute == null)
                    {
                        nameAttribute = item.GetCustomAttribute <BotDisplayNameAttribute>();
                    }
                    if (nameAttribute == null)
                    {
                        continue;
                    }
                    //if parametername not found
                    if (string.IsNullOrEmpty(parameterName))
                    {
                        parameterName = nameAttribute.Content;
                    }
                }
                else
                {
                    parameterName = item.Name;
                }
                if (columnIndex == 2)
                {
                    columnIndex = 0;
                    rows.Add(columns.ToList());
                    columns.Clear();
                }
                columns.Add(parameterName);
                columnIndex++;
            }
            if (rows.Count == 0)
            {
                rows.Add(columns);
            }
            rows.Add(new List <BotButtonInfo>()
            {
                new BotButtonInfo(CurrentBotStructureInfo.GetSendButtonText(clientInfo))
            });
            rows.Add(new List <BotButtonInfo>()
            {
                new BotButtonInfo(CurrentBotStructureInfo.GetCancelButtonText(clientInfo))
            });
            return(rows);
        }
Пример #16
0
        private async void Bot_OnMessage(object sender, MessageEventArgs e)
        {
            try
            {
                if (e.Message.Text != null)
                {
                    if (!ConnectedClients.TryGetValue(e.Message.From.Id, out TelegramClientInfo clientInfo))
                    {
                        clientInfo = new TelegramClientInfo(_serverBase)
                        {
                            ConnectedDateTime  = DateTime.Now,
                            ClientId           = Guid.NewGuid().ToString(),
                            Message            = e.Message,
                            SignalGoBotManager = this
                        };
                        _serverBase.Clients.TryAdd(clientInfo.ClientId, clientInfo);
                        ConnectedClients.TryAdd(e.Message.From.Id, clientInfo);
                        CurrentBotStructureInfo.OnClientConnected(clientInfo, this);
                    }
                    if (Services.Count == 0)
                    {
                        GetListOfServicesButtons(clientInfo);
                    }
                    BotButtonInfo buttonInfo = null;
                    if (UsersBotButtons.TryGetValue(clientInfo, out Dictionary <string, BotButtonInfo> buttons))
                    {
                        if (buttons.TryGetValue(e.Message.Text, out buttonInfo))
                        {
                            if (buttonInfo.ServiceName != null)
                            {
                                clientInfo.CurrentServiceName = buttonInfo.ServiceName;
                            }
                            if (buttonInfo.MethodName != null)
                            {
                                clientInfo.CurrentMethodName = buttonInfo.MethodName;
                            }
                        }
                    }
                    if (buttonInfo != null && buttonInfo.Click != null)
                    {
                        buttonInfo.Click(clientInfo);
                    }
                    else if (e.Message.Text == CurrentBotStructureInfo.GetCancelButtonText(clientInfo))
                    {
                        clientInfo.ParameterInfoes.Clear();
                        if (!string.IsNullOrEmpty(clientInfo.CurrentMethodName) && !string.IsNullOrEmpty(clientInfo.CurrentServiceName))
                        {
                            await ShowServiceMethods(clientInfo.CurrentServiceName, clientInfo, e.Message);
                        }
                        else
                        {
                            await ShowServices(clientInfo, e);
                        }
                    }
                    else if (e.Message.Text == CurrentBotStructureInfo.GetSendButtonText(clientInfo) && !string.IsNullOrEmpty(clientInfo.CurrentServiceName) && !string.IsNullOrEmpty(clientInfo.CurrentMethodName))
                    {
                        if (Services.TryGetValue(clientInfo.CurrentServiceName, out Type service))
                        {
                            if (CurrentBotStructureInfo.OnBeforeMethodCall(_serverBase, clientInfo, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo.ParameterInfoes))
                            {
                                Shared.Models.CallMethodResultInfo <OperationContext> result = await CallMethod(clientInfo);

                                MethodInfo method = service.GetFullServiceLevelMethods().FirstOrDefault(x => x.Name.Equals(clientInfo.CurrentMethodName, StringComparison.OrdinalIgnoreCase));
                                if (OverridedMethodResponses.TryGetValue(service, out Dictionary <string, Delegate> methods) && methods.TryGetValue(clientInfo.CurrentMethodName, out Delegate function))
                                {
                                    BotCustomResponse   botCustomResponse = new BotCustomResponse();
                                    BotResponseInfoBase response          = (BotResponseInfoBase)function.DynamicInvoke(result.Context, botCustomResponse, result.Result);
                                    await ShowResultValue(response.Message, method, clientInfo, e);

                                    botCustomResponse.OnAfterComeplete?.Invoke();
                                }
                                else
                                {
                                    string customResponse = CurrentBotStructureInfo.OnCustomResponse(_serverBase, clientInfo, clientInfo.CurrentServiceName, clientInfo.CurrentMethodName, clientInfo.ParameterInfoes, result, out bool responseChanged);
                                    if (responseChanged)
                                    {
                                        await ShowResultValue(customResponse, method, clientInfo, e);
                                    }
                                    else
                                    {
                                        await ShowResultValue(result, method, clientInfo, e.Message);
                                    }
                                }
                            }
                        }
                    }
                    else if (string.IsNullOrEmpty(clientInfo.CurrentServiceName))
                    {
                        string serviceName = GetServiceNameByCaption(e.Message.Text);
                        if (Services.ContainsKey(serviceName))
                        {
                            await ShowServiceMethods(serviceName, clientInfo, e.Message);
                        }
                        else
                        {
                            if (string.IsNullOrEmpty(clientInfo.CurrentMethodName) && !string.IsNullOrEmpty(clientInfo.CurrentServiceName))
                            {
                                await ShowServiceMethods(clientInfo.CurrentServiceName, clientInfo, e.Message);
                            }
                            else if (string.IsNullOrEmpty(clientInfo.CurrentServiceName))
                            {
                                await ShowServices(clientInfo, e);
                            }
                        }
                    }
                    else if (string.IsNullOrEmpty(clientInfo.CurrentMethodName))
                    {
                        if (Services.TryGetValue(clientInfo.CurrentServiceName, out Type service))
                        {
                            //MethodInfo method = service.GetFullServiceLevelMethods().FirstOrDefault(x => x.Name.Equals(e.Message.Text, StringComparison.OrdinalIgnoreCase));
                            MethodInfo method = GetMethodByCaption(service, e.Message.Text);
                            if (method != null)
                            {
                                await ShowServiceMethods(method, clientInfo, e.Message);
                            }
                            else
                            {
                                await ShowServiceMethods(clientInfo.CurrentServiceName, clientInfo, e.Message);
                            }
                        }
                    }
                    else if (string.IsNullOrEmpty(clientInfo.CurrentParameterName))
                    {
                        if (Services.TryGetValue(clientInfo.CurrentServiceName, out Type service))
                        {
                            MethodInfo method = FindMethod(service, clientInfo.CurrentMethodName);
                            //MethodInfo method = FindMethodByName(service, clientInfo.CurrentMethodName);
                            //ParameterInfo parameter = method.GetParameters().FirstOrDefault(x => x.Name.Equals(e.Message.Text, StringComparison.OrdinalIgnoreCase));
                            ParameterInfo parameter = FindParameterByName(method, e.Message.Text, true);
                            await GetParameterValueFromClient(method, parameter, clientInfo, e);
                        }
                    }
                    else
                    {
                        if (Services.TryGetValue(clientInfo.CurrentServiceName, out Type service))
                        {
                            MethodInfo method = FindMethod(service, clientInfo.CurrentMethodName);
                            //MethodInfo method = FindMethodByName(service, clientInfo.CurrentMethodName);
                            // ParameterInfo parameter = method.GetParameters().FirstOrDefault(x => x.Name.Equals(clientInfo.CurrentParameterName, StringComparison.OrdinalIgnoreCase));
                            ParameterInfo parameter = FindParameterByName(method, clientInfo.CurrentParameterName, false);
                            await SetParameterValueFromClient(method, parameter, clientInfo, e);
                        }
                    }
                }
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex);
            }
        }