Exemplo n.º 1
0
        /// <summary>
        /// 发送客服文本消息
        /// </summary>
        /// <param name="wid"></param>
        /// <param name="openid"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public async Task <ServiceResult <CommonResultStateOutput> > SendText(WxMP_KfMsgTextMsgInput input)
        {
            try
            {
                input.CheckNull(nameof(WxMP_KfMsgTextMsgInput));
                input.guid.CheckEmpty(nameof(input.guid));
                input.openid.CheckEmpty(nameof(input.openid));
                input.content.CheckEmpty(nameof(input.content));

                var token = _tokenService.GetAccessToken(new WxMP_AuthorizeAccessTokenInput {
                    guid = input.guid
                });
                if (token.code != 200)
                {
                    return(ServiceResult <CommonResultStateOutput> .Failed(StatusCodes.Status400BadRequest, token.msg));
                }
                var text = new WxMP_KfTextMessage();
                text.touser       = input.openid;
                text.text.content = input.content;
                var result = await WxMPContext.KfMessageAPI.SendKfMessage(token.data.access_token, text);

                return(ServiceResult <CommonResultStateOutput> .Success(new CommonResultStateOutput { result_state = result.errmsg }));
            }
            catch (Exception ex)
            {
                return(ServiceResult <CommonResultStateOutput> .Exception(ex.Message));
            }
        }
Exemplo n.º 2
0
        public ServiceResult <string> Post(string url, string postData, Dictionary <string, string> headers = null)
        {
            var result = new ServiceResult <string>();

            try
            {
                using (var client = new WebClient())
                {
                    //设置请求头信息
                    if (headers != null)
                    {
                        foreach (var item in headers)
                        {
                            client.Headers.Add(item.Key, item.Value);
                        }
                    }
                    var sendData = Encoding.UTF8.GetBytes(postData);
                    client.Headers.Add("ContentLength", sendData.Length.ToString());
                    var buffer = client.UploadData(url, "POST", sendData);
                    result.data = Encoding.UTF8.GetString(buffer);
                }
            }
            catch (Exception ex)
            {
                result = ServiceResult <string> .Exception(ex.Message);
            }
            return(result);
        }
Exemplo n.º 3
0
        public ServiceResult <string> Get(string url, Dictionary <string, string> headers = null)
        {
            var result = new ServiceResult <string>();

            try
            {
                using (var client = new WebClient())
                {
                    //设置请求头信息
                    if (headers != null)
                    {
                        foreach (var item in headers)
                        {
                            client.Headers.Add(item.Key, item.Value);
                        }
                    }
                    client.Encoding = Encoding.UTF8;
                    result.data     = client.DownloadString(url);
                }
            }
            catch (Exception ex)
            {
                result = ServiceResult <string> .Exception(ex.Message);
            }
            return(result);
        }
Exemplo n.º 4
0
        public async Task <ServiceResult <string> > GetAsync(string url, Dictionary <string, string> headers = null)
        {
            var result = new ServiceResult <string>();

            try
            {
                using (var httpClient = new HttpClient())
                {
                    //异步Post
                    var response = await httpClient.GetAsync(url);

                    //输出Http响应状态码
                    result.code = (int)response.StatusCode;
                    //确保Http响应成功
                    if (response.IsSuccessStatusCode)
                    {
                        //异步读取json
                        result.data = await response.Content.ReadAsStringAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                result = ServiceResult <string> .Exception(ex.Message);
            }
            return(result);
        }
Exemplo n.º 5
0
        /// <summary>
        /// 授权用户信息
        /// </summary>
        public async Task <ServiceResult <string> > AuthorizeUserinfo(string code, string state)
        {
            if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(state))
            {
                return(ServiceResult <string> .Failed(StatusCodes.Status400BadRequest, "无效授权"));
            }
            //验证参数
            var ids  = state.Split('|');
            var weid = ids[0].ToInt();

            if (ids.Length > 1 && weid <= 0)
            {
                return(ServiceResult <string> .Failed(StatusCodes.Status400BadRequest, "无效授权"));
            }
            var returnUrl = ids[1];

            try
            {
                //读取微信配置
                var wechat = _middleDB.WechatEeappConfig.FirstOrDefault(w => w.Id == weid);
                if (wechat == null)
                {
                    return(ServiceResult <string> .Failed(StatusCodes.Status404NotFound, "微信配置无效"));
                }
                //获取授权access_token
                var access_token = GetAccessToken(new WxEE_AuthorizeAccessTokenInput {
                    guid = wechat.Guid
                });
                //code转换用户信息
                var userinfo = await WxEEContext.UserApi.GetUserinfo(
                    access_token.data.access_token,
                    code);

                if (userinfo.errcode != 0)
                {
                    return(ServiceResult <string> .Failed(StatusCodes.Status401Unauthorized, userinfo.errmsg));
                }

                //企业微信用户
                var wechatUser = _middleDB.WechatEeappUser.FirstOrDefault(w => w.UserId == userinfo.UserId);
                //用户已授权
                if (wechatUser != null)
                {
                    await UpdateUser(wechatUser.UserId, access_token.data.access_token);

                    returnUrl = $"{returnUrl}{(returnUrl.Contains("?") ? "&" : "?")}eeid={wechatUser.Guid}";
                    return(ServiceResult <string> .Success(returnUrl));
                }
                //保存信息
                var eeUser = await CreateUser(weid, userinfo.DeviceId, userinfo.UserId, access_token.data.access_token);

                returnUrl = $"{returnUrl}{(returnUrl.Contains("?") ? "&" : "?")}eeid={eeUser.Guid}";
                return(ServiceResult <string> .Success(returnUrl));
            }
            catch (Exception ex)
            {
                return(ServiceResult <string> .Exception(ex.Message));
            }
        }
Exemplo n.º 6
0
        private async Task ErrorEvent(HttpContext context)
        {
            var feature = context.Features.Get <IExceptionHandlerFeature>();
            var error   = feature?.Error;
            var result  = ServiceResult <string> .Exception(error.Message);

            await context.Response.WriteAsync(ApplicationContext.Json.ObjectToJson(result));
        }
Exemplo n.º 7
0
        /// <summary>
        /// 获取jssdk票据
        /// </summary>
        /// <param name="mid"></param>
        /// <param name="access_token"></param>
        /// <returns></returns>
        public ServiceResult <WxMP_JssdkJsapiTicketOutput> GetJsapiTicket(WxMP_JssdkJsapiTicketInput input)
        {
            try
            {
                input.CheckNull(nameof(WxMP_JssdkJsapiTicketInput));
                input.guid.CheckEmpty(nameof(input.guid));
                input.access_token.CheckEmpty(nameof(input.access_token));

                var result = new ServiceResult <WxMP_JssdkJsapiTicketOutput>();
                result.data = new WxMP_JssdkJsapiTicketOutput();
                //NOLOCK
                var wechatConfig = ApplicationContext.EF.WithNolock <WechatConfig>(() =>
                {
                    //微信配置
                    return(_middleDB.WechatConfig.FirstOrDefault(w => w.Guid == input.guid));
                });
                if (wechatConfig == null)
                {
                    return(ServiceResult <WxMP_JssdkJsapiTicketOutput> .Failed(StatusCodes.Status404NotFound, "微信配置获取失败,请联系系统客服"));
                }
                //数据库中
                if (!string.IsNullOrEmpty(wechatConfig.JssdkTicket) &&
                    DateTime.Now < (wechatConfig.JssdkTicketUpdateTime ?? DateTime.Now.AddMinutes(-1)))
                {
                    result.data.jsapi_ticket = wechatConfig.JssdkTicket;
                }
                else
                {
                    //双重验证
                    if (string.IsNullOrEmpty(result.data.jsapi_ticket))
                    {
                        lock (lock_ticket)
                        {
                            if (string.IsNullOrEmpty(result.data.jsapi_ticket))
                            {
                                //从微信获取
                                var ticket = WxMPContext.JsAPI.GetTicket(input.access_token);
                                //修改
                                wechatConfig.JssdkTicket           = ticket.ticket;
                                wechatConfig.JssdkTicketUpdateTime = DateTime.Now.AddMinutes(60);
                                _middleDB.SaveChanges();

                                result.data.jsapi_ticket = ticket.ticket;
                            }
                        }
                    }
                }
                return(result);
            }
            catch (Exception ex)
            {
                return(ServiceResult <WxMP_JssdkJsapiTicketOutput> .Exception(ex.Message));
            }
        }
Exemplo n.º 8
0
        private static Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            const HttpStatusCode code = HttpStatusCode.InternalServerError; // 500 if unexpected

            //if (exception is MyNotFoundException) code = HttpStatusCode.NotFound;
            //else if (exception is MyUnauthorizedException) code = HttpStatusCode.Unauthorized;
            //else if (exception is MyException) code = HttpStatusCode.BadRequest;

            var result = JsonConvert.SerializeObject(ServiceResult.Exception(exception));

            context.Response.ContentType = "application/json";
            context.Response.StatusCode  = (int)code;
            return(context.Response.WriteAsync(result));
        }
Exemplo n.º 9
0
        /// <summary>
        /// 获取jssdk配置
        /// </summary>
        /// <param name="mid"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        public ServiceResult <WxMP_JssdkConfigOutput> GetConfig(WxMP_JssdkConfigInput input)
        {
            try
            {
                input.CheckNull(nameof(WxMP_JssdkConfigInput));
                input.guid.CheckEmpty(nameof(input.guid));
                input.url.CheckEmpty(nameof(input.url));

                var config = new WxMP_JssdkConfigOutput();
                //时间戳
                config.time_stamp = WxContext.Common.GenerateTimeStamp();
                //随机字符
                config.nonce_str = WxContext.Common.GenerateNonceStr();
                //获取微信配置
                var wechatConfig = _middleDB.WechatConfig.Select(s => new { s.Id, s.Guid, s.AppId }).FirstOrDefault(w => w.Guid == input.guid);
                config.app_id = wechatConfig.AppId;
                //token
                var token = _configService.GetAccessToken(new WxMP_AuthorizeAccessTokenInput {
                    wid = wechatConfig.Id
                });
                if (token.code != StatusCodes.Status200OK)
                {
                    return(ServiceResult <WxMP_JssdkConfigOutput> .Failed(token.code, token.msg));
                }
                //jsapi_ticket
                var ticket = GetJsapiTicket(new WxMP_JssdkJsapiTicketInput {
                    guid = wechatConfig.Guid, access_token = token.data.access_token
                });
                //signature
                config.signature = WxContext.Common.GenerateSignature(config.time_stamp, config.nonce_str, ticket.data.jsapi_ticket, input.url);
                return(ServiceResult <WxMP_JssdkConfigOutput> .Success(config));
            }
            catch (Exception ex)
            {
                return(ServiceResult <WxMP_JssdkConfigOutput> .Exception(ex.Message));
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// 获取微信配置
        /// </summary>
        /// <param name="mp_id"></param>
        /// <returns></returns>
        public ServiceResult <WxMP_AuthorizeAccessTokenOutput> GetAccessToken(WxMP_AuthorizeAccessTokenInput input)
        {
            try
            {
                input.CheckNull(nameof(WxMP_AuthorizeAccessTokenInput));

                var result = new ServiceResult <WxMP_AuthorizeAccessTokenOutput>();
                result.data = new WxMP_AuthorizeAccessTokenOutput();
                WechatConfig wechatConfig = null;
                //微信配置
                if (input.wid == 0)
                {
                    input.guid.CheckEmpty(nameof(input.guid));
                    wechatConfig = _middleDB.WechatConfig.FirstOrDefault(w => w.Guid == input.guid);
                }
                else
                {
                    wechatConfig = _middleDB.WechatConfig.FirstOrDefault(w => w.Id == input.wid);
                }
                if (wechatConfig == null)
                {
                    return(ServiceResult <WxMP_AuthorizeAccessTokenOutput> .Failed(StatusCodes.Status404NotFound, "微信配置获取失败,请联系系统客服"));
                }
                //数据库中
                if (!string.IsNullOrEmpty(wechatConfig.AccessToken) &&
                    DateTime.Now < (wechatConfig.TokenUpdateTime ?? DateTime.Now.AddMinutes(-1)))
                {
                    result.data.access_token = wechatConfig.AccessToken;
                }
                else
                {
                    //双重验证
                    if (string.IsNullOrEmpty(result.data.access_token))
                    {
                        lock (lock_token)
                        {
                            if (string.IsNullOrEmpty(result.data.access_token))
                            {
                                //从微信获取
                                var token = WxMPContext.BaseAPI.GetAccessToken(wechatConfig.AppId, wechatConfig.AppSecret);
                                if (token.errcode != 0)
                                {
                                    result.data.access_token = token.errmsg;
                                    return(result);
                                }
                                //修改
                                wechatConfig.Token           = token.access_token;
                                wechatConfig.TokenUpdateTime = DateTime.Now.AddMinutes(60);
                                _middleDB.SaveChanges();

                                result.data.access_token = token.access_token;
                            }
                        }
                    }
                }
                return(result);
            }
            catch (Exception ex)
            {
                return(ServiceResult <WxMP_AuthorizeAccessTokenOutput> .Exception(ex.Message));
            }
        }
Exemplo n.º 11
0
        public async Task <ServiceResult <Routine2ChangeStepResult> > ChangeStep(int RoutineId, int EntityId, Routine2Actions Action, string Description)
        {
            try
            {
                // گرفتن رکورد مورد نظر
                var entity = table.Find(EntityId);


                // درصورتی که رکورد مورد نظر وجود نداشت باید خطا برگردانده شود
                if (entity == null)
                {
                    throw new Exception($"داده‌ای با شناسه {EntityId} یافت نشد");
                }


                // مرحله بعدی فرآیند دراین قسمت به دست می‌آید
                var nextStep = GetNextStep(Action, entity, RoutineId);

                // درصورتی که مرحله بعدی -1 باشد باید خطا نمایش داده شود
                if (nextStep == -1)
                {
                    throw new Exception("Something went wrong, next dashboard couldn't be -1");
                }


                //=========================================================
                int userId   = _userResolverService.GetUserId();
                var fromStep = entity.RoutineStep;
                //=========================================================


                // ثبت لاگ جدید برای این کاربر که رکورد مورد را از یک مرحله به مرحله دیگر انتقال داده است
                _routine2Repository.CreateLog(new CreateRoutine2LogViewModel
                {
                    RoutineId        = RoutineId,
                    EntityId         = EntityId,
                    Description      = Description,
                    Action           = _routine2Repository.GetActionTitle(RoutineId, fromStep, Action),
                    Step             = fromStep,
                    ToStep           = nextStep,
                    UserId           = userId,
                    CreatorUserId    = userId,
                    RoutineRoleTitle = _routine2Repository.GetRoutineRoleTitle(RoutineId, entity.RoutineStep),
                });


                var routineVm = new EditRoutine2ViewModel(nextStep, entity.RoutineFlownDate);

                // اگر در مرحله آخر باشیم، باید به روال برچست تمام شده بزنیم
                if (entity.DoneSteps.Contains(nextStep))
                {
                    routineVm.RoutineIsDone = true;
                }

                // به صورت پیش‌فرض طرح رد شده است، مگر اینکه در مراحل تایید باشیم
                if (entity.SucceededSteps.Contains(nextStep))
                {
                    routineVm.RoutineIsSucceeded = true;
                }


                entity.RoutineStep           = nextStep;
                entity.RoutineFlownDate      = DateTime.Now;
                entity.RoutineStepChangeDate = DateTime.Now;

                _context.SaveChanges();

                var changeStepResult = new Routine2ChangeStepResult
                {
                    Action      = Action,
                    Description = Description,
                    UserId      = userId,
                    ToStep      = nextStep,
                    FromStep    = fromStep,
                    EntityId    = EntityId,
                    RoutineId   = RoutineId,
                };

                try { await _routine2Repository.SendNoticeAsync(changeStepResult); } catch (Exception) { }

                return(ServiceResult <Routine2ChangeStepResult> .Okay(changeStepResult));
            }
            catch (Exception ex)
            {
                return(ServiceResult <Routine2ChangeStepResult> .Exception(ex));
            }
        }
Exemplo n.º 12
0
        /// <summary>
        /// 生成二维码
        /// </summary>
        public async Task <ServiceResult <WxMP_QrcodeStreamOutput> > GenerateStream(WxMP_QrcodeStreamInput input)
        {
            try
            {
                input.CheckNull(nameof(WxMP_QrcodeStreamInput));
                input.wid.CheckZero(nameof(input.wid));
                input.business_id.CheckEmpty(nameof(input.business_id));
                input.module_type.CheckEmpty(nameof(input.module_type));

                var result = new ServiceResult <WxMP_QrcodeStreamOutput>();
                result.data = new WxMP_QrcodeStreamOutput();
                //获取临时二维码(业务ID)
                var scene = _middleDB.WechatQrscene.FirstOrDefault(w =>
                                                                   w.WechatId == input.wid && w.BusinessId == input.business_id && w.ModuleType == input.module_type);
                var ticket  = string.Empty;
                var sceneId = 0;
                //未创建
                if (scene == null)
                {
                    scene = new WechatQrscene
                    {
                        BusinessId = input.business_id,
                        WechatId   = input.wid,
                        ModuleType = input.module_type,
                        ActionName = WxMP_QRSceneActionType.QR_SCENE.ToString(),
                        ExpireTime = DateTime.Now.AddMinutes(-5),//5分钟之前
                        CreateTime = DateTime.Now
                    };
                    //添加数据
                    _middleDB.WechatQrscene.Add(scene);
                    _middleDB.SaveChanges();
                    sceneId = scene.SceneId;
                }
                else
                {
                    sceneId = scene.SceneId;
                    ticket  = scene.Ticket;
                }

                //临时二维码,网址访问,到期后自动延时
                if (scene.ExpireTime < DateTime.Now || input.is_new)
                {
                    var access_token = _configService.GetAccessToken(new WxMP_AuthorizeAccessTokenInput {
                        wid = input.wid
                    });
                    //创建临时二维码,30天
                    var createResult = await WxMPContext.AcountAPI.CreateTempQRSceneById(access_token.data.access_token, sceneId, 60 * 60 * 24 * 30);

                    ticket = createResult.ticket;
                    //自动延时 30天-5分钟
                    var expireTime = DateTime.Now.AddSeconds(createResult.expire_seconds - (60 * 5));
                    //更新二维码信息
                    scene.Ticket        = createResult.ticket;
                    scene.ExpireSeconds = createResult.expire_seconds;
                    scene.Url           = createResult.url;
                    scene.ExpireTime    = expireTime;
                    _middleDB.SaveChanges();
                }
                //获取图片
                var stream = await WxMPContext.AcountAPI.GetQRSceneImgStream(ticket);

                var image = new Bitmap(stream);
                var ms    = new MemoryStream();
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

                result.data.stream = ms;
                return(result);
            }
            catch (Exception ex)
            {
                return(ServiceResult <WxMP_QrcodeStreamOutput> .Exception(ex.Message));
            }
        }
Exemplo n.º 13
0
        public async Task <ServiceResult <CommonResultStateOutput> > Send(WxMP_TmplMsgInput input)
        {
            try
            {
                input.CheckNull(nameof(WxMP_KfMsgTextMsgInput));
                input.guid.CheckEmpty(nameof(input.guid));
                input.openid.CheckEmpty(nameof(input.openid));
                input.first.value.CheckEmpty(nameof(input.first));
                input.remark.value.CheckEmpty(nameof(input.remark));

                var token = _tokenService.GetAccessToken(new WxMP_AuthorizeAccessTokenInput {
                    guid = input.guid
                });
                if (token.code != 200)
                {
                    return(ServiceResult <CommonResultStateOutput> .Failed(StatusCodes.Status400BadRequest, token.msg));
                }
                var msg = new WxMP_TemplateMessage();
                msg.touser      = input.openid;
                msg.template_id = input.template_id;
                msg.url         = "http://www.baidu.com";
                if (input.miniprogram != null)
                {
                    msg.miniprogram = new WxMP_TemplateMessageMiniProgram
                    {
                        appid    = input.miniprogram.appid,
                        pagepath = input.miniprogram.pagepath
                    };
                }
                msg.data.first.value = input.first.value;
                msg.data.first.color = input.first.color;
                #region keyword1-6
                if (input.items.Count > 0)
                {
                    msg.data.keyword1 = new WxMP_TemplateMessageDataItem
                    {
                        value = input.items[0].value,
                        color = input.items[0].color
                    };
                }
                if (input.items.Count > 1)
                {
                    msg.data.keyword2 = new WxMP_TemplateMessageDataItem
                    {
                        value = input.items[1].value,
                        color = input.items[1].color
                    };
                }
                if (input.items.Count > 2)
                {
                    msg.data.keyword3 = new WxMP_TemplateMessageDataItem
                    {
                        value = input.items[2].value,
                        color = input.items[2].color
                    };
                }
                if (input.items.Count > 3)
                {
                    msg.data.keyword4 = new WxMP_TemplateMessageDataItem
                    {
                        value = input.items[3].value,
                        color = input.items[3].color
                    };
                }
                if (input.items.Count > 4)
                {
                    msg.data.keyword5 = new WxMP_TemplateMessageDataItem
                    {
                        value = input.items[4].value,
                        color = input.items[4].color
                    };
                }
                if (input.items.Count > 5)
                {
                    msg.data.keyword6 = new WxMP_TemplateMessageDataItem
                    {
                        value = input.items[5].value,
                        color = input.items[5].color
                    };
                }
                #endregion

                msg.data.remark.value = input.remark.value;
                msg.data.remark.color = input.remark.color;
                var result = await WxMPContext.MessageAPI.SendTmplMessage(token.data.access_token, msg);

                if (result.errcode != 0)
                {
                    return(ServiceResult <CommonResultStateOutput> .Failed(StatusCodes.Status400BadRequest, $"{result.errcode}:{result.errmsg}"));
                }
                return(ServiceResult <CommonResultStateOutput> .Success(new CommonResultStateOutput { result_state = result.errmsg }));
            }
            catch (Exception ex)
            {
                return(ServiceResult <CommonResultStateOutput> .Exception(ex.Message));
            }
        }
Exemplo n.º 14
0
        public async Task <ServiceResult <Routine2ChangeStepResult> > ChangeStep(int id, Routine2Actions action, string description, int userId)
        {
            try
            {
                var entity = _context.Test.FirstOrDefault(q => q.Id == id);
                if (entity == null)
                {
                    throw new Exception($"داده‌ای با شناسه {id} یافت نشد");
                }

                var nextStep = GetNextStep(id, action);
                if (nextStep == -1)
                {
                    throw new Exception("Something went wrong, next dashboard couldn't be -1");
                }


                var fromStep = entity.RoutineStep;

                _routine2Repository.CreateLog(new CreateRoutine2LogViewModel
                {
                    RoutineId        = TestRoutine.RoutineId,
                    EntityId         = id,
                    Description      = description,
                    Action           = _routine2Repository.GetActionTitle(TestRoutine.RoutineId, fromStep, action),
                    Step             = fromStep,
                    ToStep           = nextStep,
                    UserId           = userId,
                    CreatorUserId    = userId,
                    RoutineRoleTitle = _routine2Repository.GetRoutineRoleTitle(TestRoutine.RoutineId, entity.RoutineStep),
                });

                var routineVm = new EditRoutine2ViewModel(nextStep, entity.RoutineFlownDate);
                // اگر در مرحله آخر باشیم، باید به روال برچست تمام شده بزنیم
                if (TestRoutine.DoneSteps.Contains(nextStep))
                {
                    routineVm.RoutineIsDone = true;
                }

                // به صورت پیش‌فرض طرح رد شده است، مگر اینکه در مراحل تایید باشیم
                if (TestRoutine.SucceededSteps.Contains(nextStep))
                {
                    routineVm.RoutineIsSucceeded = true;
                }

                Mapper.Map(routineVm, entity);
                _context.SaveChanges();

                var changeStepResult = new Routine2ChangeStepResult
                {
                    Action      = action,
                    Description = description,
                    UserId      = userId,
                    ToStep      = nextStep,
                    FromStep    = fromStep,
                    EntityId    = entity.Id,
                    RoutineId   = TestRoutine.RoutineId,
                };

                //try { await _routine2Repository.SendNoticeAsync(changeStepResult); } catch (Exception ex) { }

                return(ServiceResult <Routine2ChangeStepResult> .Okay(changeStepResult));
            }
            catch (Exception ex)
            {
                return(ServiceResult <Routine2ChangeStepResult> .Exception(ex));
            }
        }