Example #1
0
        /// <summary>
        /// Handles pre-flight requests.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="request"></param>
        /// <param name="origin"></param>
        private void HandlePreflight(PipelineContext context, PipelineRequest request, string origin)
        {
            var response  = context.Response;
            var forbidden = true;

            if (OriginIsAllowed(origin))
            {
                var requestMethod = (request.Headers["Access-Control-Request-Method"] ?? "").Trim().ToUpperInvariant();
                if (requestMethod != "")
                {
                    forbidden = false;

                    response.Headers.Add("Access-Control-Allow-Origin", new string[] { origin });
                    response.Headers.Add("Access-Control-Allow-Methods", _DefaultAllowableMethods);

                    if (!_DefaultAllowableMethods.Contains(requestMethod))
                    {
                        response.Headers.Append("Access-Control-Allow-Methods", requestMethod);
                    }

                    var requestHeaders = request.Headers.GetCommaSeparatedValues("Access-Control-Request-Headers");
                    if (requestHeaders != null)
                    {
                        response.Headers.Add("Access-Control-Allow-Headers", requestHeaders.ToArray());
                    }
                }
            }

            response.StatusCode = forbidden ? (int)HttpStatusCode.Forbidden : (int)HttpStatusCode.OK;
        }
Example #2
0
        public AzureSynapseService(PipelineRequest request, ILogger logger)
        {
            _logger = logger;
            _logger.LogInformation("Creating SYN connectivity clients.");

            //Auth details
            var context = new AuthenticationContext("https://login.windows.net/" + request.TenantId);
            var cc      = new ClientCredential(request.ApplicationId, request.AuthenticationKey);
            var result  = context.AcquireTokenAsync("https://management.azure.com/", cc).Result;
            var cred    = new TokenCredentials(result.AccessToken);

            //Management Client
            _synManagementClient = new SynapseManagementClient(cred)
            {
                SubscriptionId = request.SubscriptionId
            };

            //Pipeline Clients
            Uri             synapseDevEndpoint = new Uri("https://" + request.OrchestratorName.ToLower() + ".dev.azuresynapse.net");
            TokenCredential token = new ClientSecretCredential
                                    (
                request.TenantId,
                request.ApplicationId,
                request.AuthenticationKey
                                    );

            _pipelineClient    = new PipelineClient(synapseDevEndpoint, token);
            _pipelineRunClient = new PipelineRunClient(synapseDevEndpoint, token);
        }
Example #3
0
        /// <summary>
        /// Creates a new object.
        /// </summary>
        public MockOwinEnvironment()
        {
            Request  = new PipelineRequest(Environment);
            Response = new PipelineResponse(Environment);

            AddRequiredFields();
        }
        public static IApplicationBuilder UseProxyMiddleware(this IApplicationBuilder builder, Action <PipelineRequest> pipelineRequestAction, PipelineMiddlewareConfiguration configuration = null)
        {
            PipelineRequest request = new PipelineRequest();

            pipelineRequestAction?.Invoke(request);
            return(UseProxyMiddleware(builder, request, configuration));
        }
Example #5
0
        /// <summary>
        /// Extracts information about the required image from the request.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private ImageRequest ExtractImageRequest(PipelineRequest request)
        {
            var          requestFileName = request.FileName;
            ImageRequest result          = new ImageRequest()
            {
                ImageName = Path.GetFileNameWithoutExtension(requestFileName).ToUpper(),
            };

            switch (Path.GetExtension(requestFileName).ToUpper())
            {
            case ".PNG":    result.ImageFormat = ImageFormat.Png; break;

            case ".GIF":    result.ImageFormat = ImageFormat.Gif; break;

            case ".BMP":    result.ImageFormat = ImageFormat.Bmp; break;

            default:        result = null; break;
            }

            if (result != null)
            {
                result = ParsePathParts(result, request);
            }

            return(result);
        }
Example #6
0
 public ConcurrentPipelines Add(PipelineRequest request, PipelineContext context)
 {
     _requestAndPipeline.Add(new RequestAndContext()
     {
         Request = request, Context = context
     });
     return(this);
 }
Example #7
0
        public void PipelineRequest_Constructor_Initialises_To_Known_State()
        {
            Assert.AreSame(_Environment, _Request.Environment);

            var defaultCtor = new PipelineRequest();

            Assert.IsNotNull(defaultCtor.Environment);
        }
Example #8
0
        /// <summary>
        /// Adds Allow-Origin headers to simple requests that match the origin.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="request"></param>
        /// <param name="origin"></param>
        private void HandleSimpleRequest(PipelineContext context, PipelineRequest request, string origin)
        {
            var response = context.Response;

            if (OriginIsAllowed(origin))
            {
                response.Headers.Add("Access-Control-Allow-Origin", new string[] { origin });
            }
        }
Example #9
0
        public object Get(PipelineRequest request)
        {
            Pipeline pipeline = Repository.GetPipeline(request.PipelineId);
            if (pipeline == null)
            {
                base.Response.StatusCode = (int) HttpStatusCode.NotFound;
                return new {ErrorMessage = "The pipeline was not found."};
            }

            return pipeline;
        }
Example #10
0
        public override PipelineDescription ValidatePipeline(PipelineRequest request)
        {
            _logger.LogInformation("Validating SYN pipeline.");

            PipelineResource pipelineResource;

            try
            {
                pipelineResource = _pipelineClient.GetPipeline
                                   (
                    request.PipelineName
                                   );

                _logger.LogInformation(pipelineResource.Id.ToString());

                return(new PipelineDescription()
                {
                    PipelineExists = "True",
                    PipelineName = pipelineResource.Name,
                    PipelineId = pipelineResource.Id,
                    PipelineType = pipelineResource.Type,
                    ActivityCount = pipelineResource.Activities.Count
                });
            }
            catch (System.InvalidOperationException) //for bug in underlying activity classes, pipeline does exist
            {
                return(new PipelineDescription()
                {
                    PipelineExists = "True",
                    PipelineName = request.PipelineName,
                    PipelineId = "Unknown",
                    PipelineType = "Unknown",
                    ActivityCount = 0
                });
            }
            catch (Azure.RequestFailedException) //expected exception when pipeline doesnt exist
            {
                return(new PipelineDescription()
                {
                    PipelineExists = "False",
                    PipelineName = request.PipelineName,
                    PipelineId = "Unknown",
                    PipelineType = "Unknown",
                    ActivityCount = 0
                });
            }
            catch (Exception ex) //other unknown issue
            {
                _logger.LogInformation(ex.Message);
                _logger.LogInformation(ex.GetType().ToString());
                throw new InvalidRequestException("Failed to validate pipeline. ", ex);
            }
        }
Example #11
0
 public object Post(PipelineRequest request)
 {
     var pipeline = new Pipeline(0,
                                 request.ProjectName,
                                 request.Revision,
                                 request.BranchName,
                                 DateTime.Now,
                                 "NN",
                                 request.PackagePath);
     Repository.AddPipeline(pipeline);
     return pipeline.PipelineId;
 }
Example #12
0
 public static PipelineRequest AddDelegateHandler(
     this PipelineRequest pipelineRequest,
     Action <PipelineContext> beforeNextInvokeAction,
     Action <PipelineContext> afterNextInvokeAction = null)
 {
     pipelineRequest.AddHandler(
         new DelegateHandler()
     {
         BeforeNextInvokeAction = beforeNextInvokeAction,
         AfterNextInvokeAction  = afterNextInvokeAction
     });
     return(pipelineRequest);
 }
        public override PipelineRunStatus ExecutePipeline(PipelineRequest request)
        {
            if (request.PipelineParameters == null)
            {
                _logger.LogInformation("Calling pipeline without parameters.");
            }
            else
            {
                _logger.LogInformation("Calling pipeline with parameters.");
            }

            var runResponse = _adfManagementClient.Pipelines.CreateRunWithHttpMessagesAsync
                              (
                request.ResourceGroupName,
                request.OrchestratorName,
                request.PipelineName,
                parameters: request.ParametersAsObjects
                              ).Result.Body;

            _logger.LogInformation("Pipeline run ID: " + runResponse.RunId);

            //Wait and check for pipeline to start...
            PipelineRun pipelineRun;

            _logger.LogInformation("Checking ADF pipeline status.");
            while (true)
            {
                pipelineRun = _adfManagementClient.PipelineRuns.Get
                              (
                    request.ResourceGroupName,
                    request.OrchestratorName,
                    runResponse.RunId
                              );

                _logger.LogInformation("Waiting for pipeline to start, current status: " + pipelineRun.Status);

                if (pipelineRun.Status != "Queued")
                {
                    break;
                }
                Thread.Sleep(internalWaitDuration);
            }

            return(new PipelineRunStatus()
            {
                PipelineName = request.PipelineName,
                RunId = runResponse.RunId,
                ActualStatus = pipelineRun.Status
            });
        }
Example #14
0
        public const int internalWaitDuration = 5000; //ms

        public static PipelineService GetServiceForRequest(PipelineRequest pr, ILogger logger)
        {
            if (pr.OrchestratorType == PipelineServiceType.ADF)
            {
                return(new AzureDataFactoryService(pr, logger));
            }

            if (pr.OrchestratorType == PipelineServiceType.SYN)
            {
                return(new AzureSynapseService(pr, logger));
            }

            throw new InvalidRequestException("Unsupported orchestrator type: " + (pr.OrchestratorType?.ToString() ?? "<null>"));
        }
Example #15
0
        public override PipelineRunStatus ExecutePipeline(PipelineRequest request)
        {
            if (request.PipelineParameters == null)
            {
                _logger.LogInformation("Calling pipeline without parameters.");
            }
            else
            {
                _logger.LogInformation("Calling pipeline with parameters.");
            }

            CreateRunResponse runResponse;

            runResponse = _pipelineClient.CreatePipelineRun
                          (
                request.PipelineName,
                parameters: request.ParametersAsObjects
                          );

            _logger.LogInformation("Pipeline run ID: " + runResponse.RunId);

            //Wait and check for pipeline to start...
            PipelineRun pipelineRun;

            _logger.LogInformation("Checking ADF pipeline status.");
            while (true)
            {
                pipelineRun = _pipelineRunClient.GetPipelineRun
                              (
                    runResponse.RunId
                              );

                _logger.LogInformation("Waiting for pipeline to start, current status: " + pipelineRun.Status);

                if (pipelineRun.Status != "Queued")
                {
                    break;
                }
                Thread.Sleep(internalWaitDuration);
            }

            return(new PipelineRunStatus()
            {
                PipelineName = request.PipelineName,
                RunId = runResponse.RunId,
                ActualStatus = pipelineRun.Status
            });
        }
Example #16
0
        public override Task Execute(PipelineRequest request)
        {
            _currentExecutingMidlewareIndex = 0;
            var middleware  = _middlewares[_currentExecutingMidlewareIndex];
            var executionId = Guid.NewGuid();

            var middlewareRequest = new MiddlewareRequest()
            {
                Request   = request.RequestObject,
                InvokedAt = DateTime.UtcNow,
                ExecutionConfiguration = request.Configuration,
                ExecutionId            = executionId
            };

            return(middleware.Invoke(middlewareRequest));
        }
        public AzureDataFactoryService(PipelineRequest request, ILogger logger)
        {
            _logger = logger;
            _logger.LogInformation("Creating ADF connectivity clients.");

            //Auth details
            var context = new AuthenticationContext("https://login.windows.net/" + request.TenantId);
            var cc      = new ClientCredential(request.ApplicationId, request.AuthenticationKey);
            var result  = context.AcquireTokenAsync("https://management.azure.com/", cc).Result;
            var cred    = new TokenCredentials(result.AccessToken);

            //Management Client
            _adfManagementClient = new DataFactoryManagementClient(cred)
            {
                SubscriptionId = request.SubscriptionId
            };
        }
Example #18
0
        public static async Task <IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest httpRequest,
            ILogger logger)
        {
            logger.LogInformation("ValidatePipeline Function triggered by HTTP request.");

            logger.LogInformation("Parsing body from request.");
            PipelineRequest request = await new BodyReader(httpRequest).GetRequestBodyAsync();

            request.Validate(logger);

            using (var service = PipelineService.GetServiceForRequest(request, logger))
            {
                PipelineDescription result = service.ValidatePipeline(request);
                logger.LogInformation("ValidatePipeline Function complete.");
                return(new OkObjectResult(JsonConvert.SerializeObject(result)));
            }
        }
        public override PipelineDescription ValidatePipeline(PipelineRequest request)
        {
            _logger.LogInformation("Validating ADF pipeline.");

            try
            {
                var pipelineResource = _adfManagementClient.Pipelines.Get
                                       (
                    request.ResourceGroupName,
                    request.OrchestratorName,
                    request.PipelineName
                                       );

                _logger.LogInformation(pipelineResource.Id.ToString());

                return(new PipelineDescription()
                {
                    PipelineExists = "True",
                    PipelineName = pipelineResource.Name,
                    PipelineId = pipelineResource.Id,
                    PipelineType = pipelineResource.Type,
                    ActivityCount = pipelineResource.Activities.Count
                });
            }
            catch (Microsoft.Rest.Azure.CloudException) //expected exception when pipeline doesnt exist
            {
                return(new PipelineDescription()
                {
                    PipelineExists = "False",
                    PipelineName = request.PipelineName,
                    PipelineId = "Unknown",
                    PipelineType = "Unknown",
                    ActivityCount = 0
                });
            }
            catch (Exception ex) //other unknown issue
            {
                _logger.LogInformation(ex.Message);
                _logger.LogInformation(ex.GetType().ToString());
                throw new InvalidRequestException("Failed to validate pipeline. ", ex);
            }
        }
        public Pipeline createPipeline(Pipeline pipeline)
        {
            JavaScriptSerializer javascript        = new JavaScriptSerializer();
            PipelineRequest      pipelineRequest   = new PipelineRequest();
            List <Signal>        signalList        = new List <Signal>();
            List <SignalRequest> signalRequestList = new List <SignalRequest>();
            int len_input_list = pipeline.inputList.Count;

            signalList = pipeline.inputList;
            for (int i = 0; i < len_input_list; i++)
            {
                SignalRequest signalRequest = new SignalRequest();
                signalRequest.name      = (signalList[i].name);
                signalRequest.eventType = (signalList[i].eventType);
                signalRequest.valueType = (signalList[i].valueType);
                signalRequestList.Add(signalRequest);
            }
            int len_assessment_list = pipeline.assessmentList.Count;
            List <Assessment>        assessmentList        = pipeline.assessmentList;
            List <AssessmentRequest> assessmentRequestList = new List <AssessmentRequest>();

            for (int i = 0; i < len_assessment_list; i++)
            {
                AssessmentRequest assessmentRequest = new AssessmentRequest();
                assessmentRequest.name                 = (assessmentList[i].name);
                assessmentRequest.inputList            = (assessmentList[i].inputList);
                assessmentRequest.aprioriConditionList = (assessmentList[i].aprioriConditionList);
                assessmentRequestList.Add(assessmentRequest);
            }
            pipelineRequest.name           = pipeline.name;
            pipelineRequest.interval       = pipeline.interval;
            pipelineRequest.input          = pipeline.input;
            pipelineRequest.inputList      = signalRequestList;
            pipelineRequest.assessmentList = assessmentRequestList;


            string data = javascript.Serialize(pipelineRequest);

            string pipeline_json = http.post("/pipeline", data);

            return(javascript.Deserialize <Pipeline>(pipeline_json));
        }
Example #21
0
        /// <summary>
        /// Raises the TextLoadedFromFile event on the singleton configuration object if the mime type indicates
        /// that it's a recognised text file.
        /// </summary>
        /// <param name="request"></param>
        /// <param name="content"></param>
        /// <param name="mimeType"></param>
        /// <returns></returns>
        private byte[] RaiseTextLoadedFromFile(PipelineRequest request, byte[] content, string mimeType)
        {
            if (mimeType == MimeType.Css ||
                mimeType == MimeType.Html ||
                mimeType == MimeType.Javascript ||
                mimeType == MimeType.Text)
            {
                var textContent = TextContent.Load(content);
                var args        = new TextContentEventArgs(
                    request.FlattenedPath,
                    textContent.Content,
                    textContent.Encoding,
                    mimeType
                    );
                _Configuration.RaiseTextLoadedFromFile(args);

                textContent.Content = args.Content;
                content             = textContent.GetBytes(includePreamble: true);
            }

            return(content);
        }
Example #22
0
        static void Main(string[] args)
        {
            var items = new List <Item>
            {
                new Item()
                {
                    Id          = 1,
                    Name        = "Item_1",
                    Description = "Item_1 Description",
                    Cost        = 12.32M,
                    CreatedBy   = "*****@*****.**",
                    CreatedOn   = DateTime.UtcNow
                },
                new Item()
                {
                    Id          = 2,
                    Name        = "Item_2",
                    Description = "Item_2 Description",
                    Cost        = 17.89M,
                    CreatedBy   = "*****@*****.**",
                    CreatedOn   = DateTime.UtcNow
                }
            };

            var requestObject   = JsonConvert.SerializeObject(items);
            var pipelineRequest = new PipelineRequest()
            {
                ExecutedBy    = "*****@*****.**",
                RequestObject = requestObject,
                Configuration = new Dictionary <string, object>()
            };

            var pipeline = ItemCreationInMemoryPipeline.CreatePipeline();

            pipeline.Execute(pipelineRequest);

            Console.ReadLine();
        }
Example #23
0
        /// <summary>
        /// Constructs the URL to jump to.
        /// </summary>
        /// <param name="request"></param>
        /// <param name="newPath"></param>
        /// <returns></returns>
        private string BuildNewPath(PipelineRequest request, string newPath)
        {
            var isHttp  = String.Equals(request.Scheme, "http", StringComparison.OrdinalIgnoreCase);
            var isHttps = !isHttp && String.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase);

            var host = request.Host.Value ?? "";

            if (isHttp && host.EndsWith(":80"))
            {
                host = host.Substring(0, host.Length - 3);
            }
            else if (isHttps && host.EndsWith(":443"))
            {
                host = host.Substring(0, host.Length - 4);
            }

            return(PipelineContext.ConstructUrl(
                       request.Scheme,
                       host,
                       request.PathBase.Value,
                       newPath,
                       request.QueryString.Value
                       ));
        }
        public static IApplicationBuilder UseProxyMiddleware(this IApplicationBuilder builder, PipelineRequest pipelineRequest, PipelineMiddlewareConfiguration configuration = null)
        {
            var args = new object [] { pipelineRequest, configuration }.Where(x => x != null).ToArray();

            return(builder.UseMiddleware <PipelineMiddleware>(args));
        }
Example #25
0
 public void TestInitialise()
 {
     _Environment = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);
     _Environment["owin.RequestHeaders"] = new Dictionary <string, string[]>(StringComparer.OrdinalIgnoreCase);
     _Request = new PipelineRequest(_Environment);
 }
Example #26
0
 public PipelineMiddleware(RequestDelegate next, PipelineRequest pipelineRequest, PipelineMiddlewareConfiguration middlewareConfiguration)
 {
     _next                    = next;
     _pipelineRequest         = pipelineRequest;
     _middlewareConfiguration = middlewareConfiguration ?? new PipelineMiddlewareConfiguration();
 }
Example #27
0
 public abstract PipelineRunStatus ExecutePipeline(PipelineRequest request);
Example #28
0
 public abstract PipelineDescription ValidatePipeline(PipelineRequest request);
Example #29
0
        public async Task <IActionResult> GetAllByLineAndDirection([FromRoute] string line, [FromRoute] string direction)
        {
            string[] directions = { "inbound", "outbound" };

            if (!directions.Any(x => string.Compare(x, direction, true) == 0))
            {
                return(BadRequest(new { error = "Invalid direction specified", directions }));
            }

            var context = await GetLuasStopListPipeline().InvokeAsync();

            if (!context.GetFirst(out LuasLines stopList))
            {
                return(BadRequest(new { error = "Error retrieving stop info" }));
            }

            var index = stopList.GetIndexOfShortName(line);

            if (index == -1)
            {
                return(BadRequest(new { error = "Invalid line specified", lines = stopList.GetLineShortNames() }));
            }

            var names = stopList.Line[index].Stops.Select(x => x.Abrev).ToArray();

            var pipeline = new PipelineRequest()
                           .AddHandler <ConcurrentPipelines>(handler =>
            {
                foreach (var name in names)
                {
                    handler.Add(GetStopInfoPipeline(),
                                new PipelineContext().Add("stop", name));
                }
            });

            context = await pipeline.InvokeAsync();

            var contexts = context.Get <PipelineContext>();

            List <object> objects = new List <object>();

            foreach (var ctx in contexts)
            {
                var luasStops = ctx.Get <LuasStop>("response");
                var res       = new
                {
                    stop    = luasStops.Stop,
                    stopAbv = luasStops.StopAbv,
                    direction,
                    trams = luasStops.Direction
                            .Where(x => string.Compare(x.Name, direction, true) == 0)
                            .Select(x =>
                                    x.Tram.Select(
                                        y => new
                    {
                        dueMins     = y.DueMins,
                        destination = y.Destination
                    }))
                };
                objects.Add(res);
            }

            return(Ok(objects.ToArray()));
        }
Example #30
0
 /// <summary>
 /// Creates a new object.
 /// </summary>
 /// <param name="pipelineRequest"></param>
 public Request(PipelineRequest pipelineRequest)
 {
     _Request            = pipelineRequest;
     MaximumPostBodySize = 4 * 1024 * 1024;
 }
Example #31
0
 public PipelineMiddleware(RequestDelegate next, PipelineRequest pipelineRequest) : this(next, pipelineRequest, null)
 {
 }
Example #32
0
        private ImageRequest ParsePathParts(ImageRequest result, PipelineRequest request)
        {
            foreach (var pathPart in request.PathParts)
            {
                var caselessPart = pathPart.ToUpper();

                if (caselessPart.StartsWith("ALT-"))
                {
                    result.ShowAltitudeStalk = true;
                }

                if (caselessPart.StartsWith("ROTATE-"))
                {
                    result.RotateDegrees = ParseDouble(pathPart.Substring(7), 0.0, 359.99);
                }
                else if (caselessPart.StartsWith("HGHT-"))
                {
                    result.Height = ParseInt(pathPart.Substring(5), 0, 4096);
                }
                else if (caselessPart.StartsWith("WDTH-"))
                {
                    result.Width = ParseInt(pathPart.Substring(5), 0, 4096);
                }
                else if (caselessPart.StartsWith("CENX-"))
                {
                    result.CentreX = ParseInt(pathPart.Substring(5), 0, 4096);
                }
                else if (caselessPart.StartsWith("FILE-"))
                {
                    result.File = pathPart.Substring(5).Replace("\\", "");
                }
                else if (caselessPart.StartsWith("SIZE-"))
                {
                    result.Size = ParseStandardSize(pathPart.Substring(5));
                }
                else if (caselessPart == "HIDPI")
                {
                    result.IsHighDpi = true;
                }
                else if (caselessPart == "LEFT")
                {
                    result.CentreImageHorizontally = false;
                }
                else if (caselessPart == "TOP")
                {
                    result.CentreImageVertically = false;
                }
                else if (caselessPart == "NO-CACHE")
                {
                    result.NoCache = !request.IsInternet;
                }
                else if (caselessPart.StartsWith("WEB"))
                {
                    var pathAndFileName = new StringBuilder("/images/");
                    var hyphenPosn      = pathPart.IndexOf('-');
                    if (hyphenPosn != -1)
                    {
                        var folder = pathPart.Substring(hyphenPosn + 1).Replace("\\", "/").Trim();
                        if (folder.Length > 0)
                        {
                            pathAndFileName.AppendFormat("{0}{1}", folder, folder[folder.Length - 1] == '/' ? "" : "/");
                        }
                    }
                    pathAndFileName.Append(Path.GetFileName(request.FileName));
                    result.WebSiteFileName = pathAndFileName.ToString();
                }
                else if (caselessPart.StartsWith("PL"))
                {
                    var hyphenPosn = caselessPart.IndexOf('-');
                    if (hyphenPosn >= 2)
                    {
                        var rowText = caselessPart.Substring(2, hyphenPosn - 2);
                        if (int.TryParse(rowText, out int row) && row >= 1 && row <= 9)
                        {
                            --row;
                            while (result.TextLines.Count <= row)
                            {
                                result.TextLines.Add(null);
                            }
                            result.TextLines[row] = pathPart.Substring(hyphenPosn + 1);
                        }
                    }
                }
            }

            return(result);
        }