Esempio n. 1
0
        /// <summary>
        /// The following region handles Event information deletion
        /// </summary>
        #region Delete Event Information

        public bool DeleteEvent(int eId, int userId, string ip)
        {
            bool isSuccessfullyDeleted = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    Event curEvent = ctx.Events.FirstOrDefault(c => c.EventId.Equals(eId));
                    if (curEvent != null)
                    {
                        ctx.Events.Remove(curEvent);
                    }
                    ctx.SaveChanges();
                    isSuccessfullyDeleted = true;
                }
                LogGNGEventDeleted(userId.ToString(), eId, ip);
                return(isSuccessfullyDeleted);
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfullyDeleted);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Updates current user rating with a new rating
        /// </summary>
        /// <param name="rating">new Rating information</param>
        /// <param name="ip">user ip</param>
        /// <returns></returns>
        public bool UpdateRating(UserRating rating, string ip)
        {
            var userRating = new UserRating();

            try
            {
                using (var context = new GreetNGroupContext())
                {
                    var query = context.UserRatings.Where(s => s.RaterId1 == rating.RaterId1 && s.RatedId1 == rating.RatedId1).FirstOrDefault <UserRating>();
                    if (query.Rating == rating.Rating)
                    {
                        query.Rating = 0;
                    }
                    else
                    {
                        query.Rating = rating.Rating;
                    }
                    context.SaveChanges();
                }
                return(true);
            }
            catch (Exception e)
            {
                _gngLoggerService.LogGNGInternalErrors(e.ToString());
                return(false);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// The following region handles deletion of data from the user table in the database
        /// </summary>
        #region Delete User Information

        /*
         * For our application, the DeleteUser function is made to set user values to null
         * apart from UserId and userName which is used as reference
         */
        public bool DeleteUser(User userToDelete)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    /*
                     * User(int uId, string firstName, string lastName, string userName, string city,
                     *  string state, string country, DateTime dob, bool isActivated)
                     */
                    var user      = ctx.Users.FirstOrDefault(c => c.UserId.Equals(userToDelete.UserId));
                    var blankUser = new User(user.UserId, null, null, "User has been deleted", null, null,
                                             null, DateTime.Now, false);
                    if (user != null)
                    {
                        //ctx.Users.Remove(user);
                        user = blankUser;
                        ctx.SaveChanges();
                        return(true);
                    }
                    return(false);
                }
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(false);
            }
        }
Esempio n. 4
0
 public bool InvalidateToken(string jwtToken)
 {
     try
     {
         using (var ctx = new GreetNGroupContext())
         {
             var userID         = GetUserIDFromToken(jwtToken);
             var retrievedToken = ctx.JWTTokens.Where(j => j.Token == jwtToken)
                                  .Where(j => j.UserId == userID)
                                  .First();
             if (retrievedToken != null)
             {
                 retrievedToken.isValid          = false;
                 ctx.Entry(retrievedToken).State = EntityState.Modified;
                 ctx.SaveChanges();
                 return(true);
             }
             return(false);
         }
     }
     catch
     {
         return(false);
     }
 }
Esempio n. 5
0
        /*
         * The functions within this service make use of the database context
         * and similarly attempt to catch
         *      ObjectDisposedException
         * to ensure the context is still valid and we want to catch the error
         * where it has been made
         *
         */

        /// <summary>
        /// The following region handles inserts into the user table of the database
        /// </summary>
        #region Insert User Information

        // Inserts given user object into database
        public bool InsertUser(User user)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    // Catch existing users
                    if (user.UserName != null)
                    {
                        if (ctx.Users.Any(c => c.UserName.Equals(user.UserName)))
                        {
                            return(false);
                        }
                    }

                    // Adds user
                    ctx.Users.Add(user);
                    ctx.SaveChanges();
                    return(true);
                }
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(false);
            }
        }
Esempio n. 6
0
        public bool AddDefaultClaims(User newUser)
        {
            var isSuccessfulAdd = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var userID      = newUser.UserId;
                    var claimToAdd  = ctx.Claims.FirstOrDefault(c => c.ClaimId.Equals(1));
                    var claimToAdd2 = ctx.Claims.FirstOrDefault(c => c.ClaimId.Equals(2));
                    var claimToAdd3 = ctx.Claims.FirstOrDefault(c => c.ClaimId.Equals(8));
                    var claimToAdd4 = ctx.Claims.FirstOrDefault(c => c.ClaimId.Equals(9));

                    var userClaim  = new UserClaim(userID, claimToAdd);
                    var userClaim2 = new UserClaim(userID, claimToAdd2);
                    var userClaim3 = new UserClaim(userID, claimToAdd3);
                    var userClaim4 = new UserClaim(userID, claimToAdd4);

                    ctx.UserClaims.Add(userClaim);
                    ctx.UserClaims.Add(userClaim2);
                    ctx.UserClaims.Add(userClaim3);
                    ctx.UserClaims.Add(userClaim4);
                    ctx.SaveChanges();
                    isSuccessfulAdd = true;
                    return(isSuccessfulAdd);
                }
            }
            catch (Exception od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfulAdd);
            }
        }
Esempio n. 7
0
        // Removes pair of tagId and eventId where values match in database
        public bool DeleteEventTag(int eventId, string tag)
        {
            var isSuccessfulDelete = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var eventTags   = ctx.EventTags.Where(e => e.EventId.Equals(eventId));
                    var targetTagId = ctx.Tags.FirstOrDefault(t => t.TagName.Equals(tag)).TagId;

                    foreach (var tags in eventTags)
                    {
                        if (tags.TagId.Equals(targetTagId))
                        {
                            ctx.EventTags.Remove(tags);
                            isSuccessfulDelete = true;
                        }
                    }

                    ctx.SaveChanges();
                }
                return(isSuccessfulDelete);
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfulDelete);
            }
        }
Esempio n. 8
0
        public bool SetEventToExpired(int eId)
        {
            var isSuccessfulEventUpdate = false;

            try
            {
                if (IsEventExpired(eId) == true)
                {
                    using (var ctx = new GreetNGroupContext())
                    {
                        var eventToUpdate = ctx.Events.FirstOrDefault(e => e.EventId.Equals(eId));
                        eventToUpdate.IsEventExpired = true;
                        ctx.SaveChanges();
                    }
                }
                else
                {
                    return(isSuccessfulEventUpdate);
                }
                return(isSuccessfulEventUpdate);
            }
            catch (Exception e)
            {
                _gngLoggerService.LogGNGInternalErrors(e.ToString());
                return(isSuccessfulEventUpdate);
            }
        }
Esempio n. 9
0
 public Attendance UpdateAttendance(Attendance updatedAtendance)
 {
     using (var _db = new GreetNGroupContext())
     {
         _db.Entry(updatedAtendance).State = EntityState.Modified;
         _db.SaveChanges();
         return(updatedAtendance);
     }
 }
Esempio n. 10
0
        public HttpResponseMessage DeleteUser(string email)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var retrievedUser = ctx.Users.Where(u => u.UserName == email).FirstOrDefault <User>();

                    if (retrievedUser == null)
                    {
                        var httpResponseFail = new HttpResponseMessage(HttpStatusCode.NotFound)
                        {
                            Content = new StringContent("User not found in system")
                        };
                        return(httpResponseFail);
                    }

                    ctx.JWTTokens.RemoveRange(ctx.JWTTokens.Where(j => j.UserId == retrievedUser.UserId));
                    ctx.UserRatings.RemoveRange(ctx.UserRatings.Where(u => u.RatedId1 == retrievedUser.UserId));
                    ctx.UserRatings.RemoveRange(ctx.UserRatings.Where(u => u.RaterId1 == retrievedUser.UserId));
                    var retrievedClaims = ctx.UserClaims.Where(c => c.UId == retrievedUser.UserId).FirstOrDefault <UserClaim>();
                    ctx.UserClaims.Remove(retrievedClaims);

                    retrievedUser.FirstName   = "Deleted";
                    retrievedUser.LastName    = "User";
                    retrievedUser.UserName    = "******";
                    retrievedUser.State       = "CA";
                    retrievedUser.City        = "LB";
                    retrievedUser.Country     = "USA";
                    retrievedUser.DoB         = DateTime.Now;
                    retrievedUser.IsActivated = false;
                    ctx.SaveChanges();

                    var httpResponseSuccess = new HttpResponseMessage(HttpStatusCode.OK)
                    {
                        Content = new StringContent("User was deleted from GreetNGroup")
                    };
                    return(httpResponseSuccess);
                }
            }
            catch (Exception ex)
            {
                _gngLoggerService.LogGNGInternalErrors(ex.ToString());
                var httpResponse = new HttpResponseMessage(HttpStatusCode.InternalServerError)
                {
                    Content = new StringContent(ex.ToString())
                };
                return(httpResponse);
            }
        }
Esempio n. 11
0
        /*
         * The functions within this service make use of the database context
         * and similarly attempt to catch
         *      ObjectDisposedException
         * to ensure the context is still valid and we want to catch the error
         * where it has been made
         *
         */

        /// <summary>
        /// The following region inserts an event/event details into the event database
        /// </summary>
        #region Insert Event Information

        public bool InsertMadeEvent(Event e)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    ctx.Events.Add(e);
                    ctx.SaveChanges();
                    return(true);
                }
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(false);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// The following region handles updating user information within the database
        /// </summary>
        #region Update User Information

        // Updates user by replacing user object in database with new user object with updated fields
        public bool UpdateUser(User updatedUser)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    ctx.Entry(updatedUser).State = EntityState.Modified;
                    ctx.SaveChanges();
                    return(true);
                }
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(false);
            }
        }
Esempio n. 13
0
        public Event InsertEvent(int userId, DateTime startDate, string eventName,
                                 string address, string city, string state, string zip, List <string> eventTags, string eventDescription,
                                 string ip, string url)
        {
            Event userEvent = null;

            try
            {
                string eventLocation = ParseAddress(address, city, state, zip);

                using (var ctx = new GreetNGroupContext())
                {
                    userEvent = new Event(userId, eventId, startDate, eventName, eventLocation, eventDescription);

                    ctx.Events.Add(userEvent);
                    ctx.SaveChanges();
                    foreach (var tags in eventTags)
                    {
                        if (_eventTagService.InsertEventTag(eventId, tags) == false)
                        {
                            userEvent = null;
                            _gngLoggerService.LogErrorsEncountered(userId.ToString(), "409 Conflict",
                                                                   url, "The event failed to be created", ip);
                            return(userEvent);
                        }
                        if (InsertEventCheckinCode(eventId) == false)
                        {
                            userEvent = null;
                            _gngLoggerService.LogErrorsEncountered(userId.ToString(), "409 Conflict",
                                                                   url, "The event failed to be created", ip);
                        }
                    }
                    LogGNGEventsCreated(userId.ToString(), eventId, ip);
                    eventId++;
                    Environment.SetEnvironmentVariable("EventId", eventId.ToString(), EnvironmentVariableTarget.User);
                }

                return(userEvent);
            }
            catch (Exception od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(userEvent);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// This region handles inserting claim information into the database
        /// </summary>
        #region Insert Claim Information

        // Inserts claim with corresponding claim id into database
        public void InsertClaim(int claimId, string claimName)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var claim = new Claim(claimId, claimName);

                    ctx.Claims.Add(claim);

                    ctx.SaveChanges();
                }
            }
            catch (ObjectDisposedException od) // check for context availability : should pass
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
            }
        }
Esempio n. 15
0
 /// <summary>
 /// Inserts an attendee to the attandee table
 /// </summary>
 /// <param name="attendee">the current attendee</param>
 /// <returns>boolean if the attendee was successfully added or not</returns>
 public bool InsertAttendee(int eventId, int userId)
 {
     try
     {
         Attendance attendee = new Attendance(eventId, userId, false);
         using (var ctx = new GreetNGroupContext())
         {
             ctx.Attendees.Add(attendee);
             ctx.SaveChanges();
             return(true);
         }
     }
     catch (ObjectDisposedException od)
     {
         _gngLoggerService.LogGNGInternalErrors(od.ToString());
         return(false);
     }
 }
Esempio n. 16
0
 public bool CreateRating(UserRating rating, string ip)
 {
     try
     {
         using (var ctx = new GreetNGroupContext())
         {
             ctx.UserRatings.Add(rating);
             ctx.SaveChanges();
             // LogGNGUserRating(rating.RaterId.ToString(), rating.RatedId.ToString(), ip);
             return(true);
         }
     }
     catch (Exception e)
     {
         _gngLoggerService.LogGNGInternalErrors(e.ToString());
         Console.WriteLine(e);
         return(false);
     }
 }
Esempio n. 17
0
        /// <summary>
        /// This region removes Claims from the database
        /// </summary>
        #region Delete Claim Information

        // Removes claim from database given proper claimId
        public void DeleteClaimById(int claimId)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var claim = ctx.Claims.FirstOrDefault(c => c.ClaimId.Equals(claimId));

                    if (claim != null)
                    {
                        ctx.Claims.Remove(claim);
                    }

                    ctx.SaveChanges();
                }
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
            }
        }
Esempio n. 18
0
 // Updates city information on user
 public bool UpdateUserCity(int uId, string city)
 {
     try
     {
         using (var ctx = new GreetNGroupContext())
         {
             User curUser = ctx.Users.FirstOrDefault(c => c.UserId.Equals(uId));
             if (curUser != null)
             {
                 curUser.City = city;
                 ctx.SaveChanges();
                 return(true);
             }
             return(false);
         }
     }
     catch (ObjectDisposedException od)
     {
         _gngLoggerService.LogGNGInternalErrors(od.ToString());
         return(false);
     }
 }
Esempio n. 19
0
        public bool InsertEventCheckinCode(int eventId)
        {
            bool isSuccessfullyAdded = false;

            try
            {
                var checkinCode = GenerateCheckinCode(4);
                using (var ctx = new GreetNGroupContext())
                {
                    var eventToAddCode = ctx.Events.FirstOrDefault(e => e.EventId.Equals(eventId));
                    eventToAddCode.EventCheckinCode = checkinCode;
                    ctx.SaveChanges();
                    isSuccessfullyAdded = true;
                    return(isSuccessfullyAdded);
                }
            }
            catch (Exception e)
            {
                _gngLoggerService.LogGNGInternalErrors(e.ToString());
                return(isSuccessfullyAdded);
            }
        }
Esempio n. 20
0
        public bool AddTokenToDB(string jwtToken, int userID)
        {
            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var newTokenID = GetNextJWTTokenID();
                    if (newTokenID == -1)
                    {
                        return(false);
                    }

                    var JWTTokenToAdd = new JWTToken(newTokenID, jwtToken, userID, true);

                    ctx.JWTTokens.Add(JWTTokenToAdd);
                    ctx.SaveChanges();
                    return(true);
                }
            }
            catch (Exception e)
            {
                return(false);
            }
        }
Esempio n. 21
0
 public bool DeleteTokenFromDB(string jwtToken)
 {
     try
     {
         using (var ctx = new GreetNGroupContext())
         {
             var userID        = GetUserIDFromToken(jwtToken);
             var TokenToRemove = ctx.JWTTokens.Where(j => j.Token == jwtToken)
                                 .Where(j => j.UserId == userID)
                                 .First();
             if (TokenToRemove != null)
             {
                 ctx.JWTTokens.Remove(TokenToRemove);
                 ctx.SaveChanges();
                 return(true);
             }
             return(false);
         }
     }
     catch
     {
         return(false);
     }
 }
Esempio n. 22
0
        // Inserts EventTag into the database, creates a link between an event and a tag
        public bool InsertEventTag(int eventId, string tag)
        {
            var isSuccessfulAdd = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var tagToAdd = ctx.Tags.FirstOrDefault(t => t.TagName.Equals(tag));
                    var tagIdNum = tagToAdd.TagId;
                    var eventTag = new EventTag(eventId, tagIdNum);
                    ctx.EventTags.Add(eventTag);

                    ctx.SaveChanges();
                    isSuccessfulAdd = true;
                }
                return(isSuccessfulAdd);
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfulAdd);
            }
        }
Esempio n. 23
0
        public bool AddClaimToUser(string username, Claim claim)
        {
            var isSuccessfulAdd = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var       user       = ctx.Users.FirstOrDefault(u => u.UserName.Equals(username));
                    var       userId     = user.UserId;
                    var       claimToAdd = ctx.Claims.FirstOrDefault(c => c.ClaimName.Equals(claim.ClaimName));
                    UserClaim userClaim  = new UserClaim(userId, claimToAdd);
                    ctx.UserClaims.Add(userClaim);
                    ctx.SaveChanges();
                    isSuccessfulAdd = true;
                }
                return(isSuccessfulAdd);
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfulAdd);
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Removes attendee from table
        /// </summary>
        /// <param name="eventId">event id </param>
        /// <param name="userId">user id</param>
        /// <returns>Removes the specififed attendee from the table</returns>
        public bool DeleteAttendee(int eventId, int userId)
        {
            var isSuccessfullyDeleted = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    Attendance curAttendee = ctx.Attendees.FirstOrDefault(c => c.EventId.Equals(eventId) && c.UserId.Equals(userId));
                    if (curAttendee != null)
                    {
                        ctx.Attendees.Remove(curAttendee);
                    }
                    ctx.SaveChanges();
                    isSuccessfullyDeleted = true;
                }
                return(isSuccessfullyDeleted);
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfullyDeleted);
            }
        }
Esempio n. 25
0
        protected override Task <HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            using (var _db = new GreetNGroupContext())
            {
                try
                {
                    var existingConnection = _db.Database.Exists();
                    if (!existingConnection)
                    {
                        var httpResponseError = new HttpResponseMessage(HttpStatusCode.InternalServerError)
                        {
                            Content = new StringContent("GreetNGroup is offline, database connection error")
                        };
                        var tscError = new TaskCompletionSource <HttpResponseMessage>();
                        tscError.SetResult(httpResponseError);   // Also sets the task state to "RanToCompletion"
                        return(tscError.Task);
                    }
                    _db.SaveChanges();

                    Ping        pingSender = new Ping();
                    PingOptions options    = new PingOptions
                    {
                        // Use the default Ttl value which is 128,
                        // but change the fragmentation behavior.
                        DontFragment = true
                    };


                    byte[]    buffer = Encoding.ASCII.GetBytes(data);
                    PingReply reply  = pingSender.Send(awsInstanceIPAddress, timeout, buffer, options);
                    if (reply.Status == IPStatus.Success)
                    {
                        var httpResponseSuccess = new HttpResponseMessage(HttpStatusCode.OK)
                        {
                            Content = new StringContent("GreetNGroup is online")
                        };
                        var tscSuccess = new TaskCompletionSource <HttpResponseMessage>();
                        tscSuccess.SetResult(httpResponseSuccess);   // Also sets the task state to "RanToCompletion"
                        return(tscSuccess.Task);
                    }

                    var httpResponse = new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content = new StringContent("GreetNGroup is offline")
                    };
                    var tsc = new TaskCompletionSource <HttpResponseMessage>();
                    tsc.SetResult(httpResponse);   // Also sets the task state to "RanToCompletion"
                    return(tsc.Task);
                }
                catch (Exception) // catch error when trying to call db, return status of internal problems
                {
                    var httpResponse = new HttpResponseMessage(HttpStatusCode.InternalServerError)
                    {
                        Content = new StringContent("GreetNGroup is offline")
                    };
                    var tsc = new TaskCompletionSource <HttpResponseMessage>();
                    tsc.SetResult(httpResponse);   // Also sets the task state to "RanToCompletion"
                    return(tsc.Task);
                }
            }
        }
Esempio n. 26
0
        /// <summary>
        /// The following region handles update of Event specific information
        /// </summary>
        #region Update Event Information

        public bool UpdateEvent(int eId, int userId, DateTime startDate, string eventName,
                                string address, string city, string state, string zip, List <string> eventTags, string eventDescription,
                                string url, string ip)
        {
            var isSuccessfullyUpdated     = false;
            var isTagsSuccessfullyUpdated = false;

            try
            {
                using (var ctx = new GreetNGroupContext())
                {
                    var currentEvent = ctx.Events.FirstOrDefault(e => e.EventId.Equals(eId));
                    if (currentEvent != null)
                    {
                        currentEvent.UserId           = userId;
                        currentEvent.EventName        = eventName;
                        currentEvent.StartDate        = startDate;
                        currentEvent.EventLocation    = ParseAddress(address, city, state, zip);
                        currentEvent.EventDescription = eventDescription;
                        ctx.SaveChanges();

                        if (eventTags.Count != 0)
                        {
                            var currentEventTags = ctx.EventTags.Where(e => e.EventId.Equals(eId));

                            foreach (var tags in currentEventTags)
                            {
                                if (!eventTags.Contains(tags.Tag.TagName))
                                {
                                    isTagsSuccessfullyUpdated = _eventTagService.DeleteEventTag(eId, tags.Tag.TagName);
                                }
                                else
                                {
                                    eventTags.Remove(tags.Tag.TagName);
                                }
                            }

                            foreach (var tags in eventTags)
                            {
                                isTagsSuccessfullyUpdated = _eventTagService.InsertEventTag(eId, tags);
                            }
                        }
                        if (isTagsSuccessfullyUpdated == true)
                        {
                            isSuccessfullyUpdated = true;
                            LogGNGEventUpdate(eventId, userId.ToString(), ip);
                        }
                    }
                    else
                    {
                        _gngLoggerService.LogErrorsEncountered(userId.ToString(), "409 Conflict", url, "The event failed" +
                                                               "to be updated", ip);
                        return(isSuccessfullyUpdated);
                    }
                }
                return(isSuccessfullyUpdated);
            }
            catch (ObjectDisposedException od)
            {
                _gngLoggerService.LogGNGInternalErrors(od.ToString());
                return(isSuccessfullyUpdated);
            }
        }