Пример #1
0
        protected virtual void CreateMemberInZone()
        {
            var npc = (Npc)EntityService.Factory.Create(Configuration.EntityDefault, EntityIDGenerator.Random);

            npc.Behavior = GetBehavior();

            var gen = new CompositeLootGenerator(
                new LootGenerator(LootService.GetNpcLootInfos(npc.Definition)),
                new LootGenerator(LootService.GetFlockLootInfos(Id))
                );

            npc.LootGenerator = gen;
            npc.HomeRange     = HomeRange;
            npc.HomePosition  = SpawnOrigin;
            npc.CallForHelp   = Configuration.IsCallForHelp;

            var zone          = Presence.Zone;
            var spawnPosition = GetSpawnPosition(SpawnOrigin);
            var finder        = new ClosestWalkablePositionFinder(zone, spawnPosition, npc);

            if (!finder.Find(out spawnPosition))
            {
                Log($"invalid spawnposition in CreateMemberInZone: {spawnPosition} {Configuration.Name} {Presence.Configuration.name} zone:{zone.Id}");
            }

            OnNpcCreated(npc);

            npc.AddToZone(zone, spawnPosition, ZoneEnterType.NpcSpawn);

            AddMember(npc);
            Log($"member spawned to zone:{zone.Id} EID:{npc.Eid}");
        }
Пример #2
0
        private LootService CreateLootService()                  // Verification to set the new information to the user's list
        {
            var userId  = Guid.Parse(User.Identity.GetUserId()); // Gets the user's Id
            var service = new LootService(userId);               // Sets service to the logged in user as the Guid

            return(service);                                     // Returns the user's id
        }
Пример #3
0
        // GET: Loot
        public ActionResult Index()
        {
            var userId  = Guid.Parse(User.Identity.GetUserId());
            var service = new LootService(userId);
            var model   = service.GetLoot();

            return(View(model));
        }
Пример #4
0
        public void SetUp()
        {
            _unitOfWorkFactory          = new FakeUnitOfWorkFactory();
            _authorizationUtil          = Substitute.For <IAuthorizationUtil>();
            _notificationSessionFactory = Substitute.For <INotificationSessionFactory>();
            _itemService = Substitute.For <IItemService>();

            _service = new LootService(
                _unitOfWorkFactory,
                _authorizationUtil,
                _notificationSessionFactory,
                _itemService
                );
        }
Пример #5
0
        public void Main()
        {
            NWPlaceable drill       = _.OBJECT_SELF;
            string      structureID = drill.GetLocalString("PC_BASE_STRUCTURE_ID");

            if (string.IsNullOrWhiteSpace(structureID))
            {
                string areaName = drill.Area.Name;
                Console.WriteLine("There was an error retrieving the PC_BASE_STRUCTURE_ID variable on drill in area: " + areaName);
                return;
            }

            Guid            structureGUID = new Guid(structureID);
            PCBaseStructure pcStructure   = DataService.PCBaseStructure.GetByID(structureGUID);
            PCBase          pcBase        = DataService.PCBase.GetByID(pcStructure.PCBaseID);
            PCBaseStructure tower         = BaseService.GetBaseControlTower(pcBase.ID);

            if (tower == null)
            {
                Console.WriteLine("Could not locate valid tower in Drill OnHeartbeat. PCBaseID = " + pcBase.ID);
                return;
            }

            // Check whether there's space in this tower.
            int capacity = BaseService.CalculateResourceCapacity(pcBase.ID);
            int count    = DataService.PCBaseStructureItem.GetNumberOfItemsContainedBy(tower.ID) + 1;

            if (count > capacity)
            {
                return;
            }

            BaseStructure baseStructure = DataService.BaseStructure.GetByID(pcStructure.BaseStructureID);
            DateTime      now           = DateTime.UtcNow;

            var outOfPowerEffect = drill.Effects.SingleOrDefault(x => _.GetEffectTag(x) == "CONTROL_TOWER_OUT_OF_POWER");

            if (now >= pcBase.DateFuelEnds)
            {
                if (outOfPowerEffect == null)
                {
                    outOfPowerEffect = _.EffectVisualEffect(VisualEffect.Vfx_Dur_Aura_Red);
                    outOfPowerEffect = _.TagEffect(outOfPowerEffect, "CONTROL_TOWER_OUT_OF_POWER");
                    _.ApplyEffectToObject(DurationType.Permanent, outOfPowerEffect, drill);
                }

                return;
            }
            else if (now < pcBase.DateFuelEnds && outOfPowerEffect != null)
            {
                _.RemoveEffect(drill, outOfPowerEffect);
            }

            int minuteReduce    = 2 * pcStructure.StructureBonus;
            int increaseMinutes = 60 - minuteReduce;
            int retrievalRating = baseStructure.RetrievalRating;

            if (increaseMinutes <= 20)
            {
                increaseMinutes = 20;
            }
            if (pcStructure.DateNextActivity == null)
            {
                pcStructure.DateNextActivity = now.AddMinutes(increaseMinutes);
                DataService.SubmitDataChange(pcStructure, DatabaseActionType.Update);
            }

            if (!(now >= pcStructure.DateNextActivity))
            {
                return;
            }

            // Time to spawn a new item and reset the timer.
            var    dbArea      = DataService.Area.GetByResref(pcBase.AreaResref);
            string sector      = pcBase.Sector;
            int    lootTableID = 0;

            switch (sector)
            {
            case "NE": lootTableID = dbArea.NortheastLootTableID ?? 0; break;

            case "NW": lootTableID = dbArea.NorthwestLootTableID ?? 0; break;

            case "SE": lootTableID = dbArea.SoutheastLootTableID ?? 0; break;

            case "SW": lootTableID = dbArea.SouthwestLootTableID ?? 0; break;
            }

            if (lootTableID <= 0)
            {
                Console.WriteLine("WARNING: Loot table ID not defined for area " + dbArea.Name + ". Drills cannot retrieve items.");
                return;
            }

            pcStructure.DateNextActivity = now.AddMinutes(increaseMinutes);

            var controlTower = BaseService.GetBaseControlTower(pcStructure.PCBaseID);

            if (controlTower == null)
            {
                Console.WriteLine("Could not locate control tower in drill heartbeat. PCBaseID = " + pcStructure.PCBaseID);
                return;
            }

            var itemDetails = LootService.PickRandomItemFromLootTable(lootTableID);

            var    tempStorage = _.GetObjectByTag("TEMP_ITEM_STORAGE");
            NWItem item        = _.CreateItemOnObject(itemDetails.Resref, tempStorage, itemDetails.Quantity);

            // Guard against invalid resrefs and missing items.
            if (!item.IsValid)
            {
                Console.WriteLine("ERROR: Could not create base drill item with resref '" + itemDetails.Resref + "'. Is this item valid?");
                return;
            }

            if (!string.IsNullOrWhiteSpace(itemDetails.SpawnRule))
            {
                var rule = SpawnService.GetSpawnRule(itemDetails.SpawnRule);
                rule.Run(item, retrievalRating);
            }

            var dbItem = new PCBaseStructureItem
            {
                PCBaseStructureID = controlTower.ID,
                ItemGlobalID      = item.GlobalID.ToString(),
                ItemName          = item.Name,
                ItemResref        = item.Resref,
                ItemTag           = item.Tag,
                ItemObject        = SerializationService.Serialize(item)
            };

            DataService.SubmitDataChange(pcStructure, DatabaseActionType.Update);
            DataService.SubmitDataChange(dbItem, DatabaseActionType.Insert);
            item.Destroy();
        }
Пример #6
0
        public void Main()
        {
            NWPlaceable point = (_.OBJECT_SELF);
            NWPlayer    oPC   = (_.GetLastOpenedBy());

            if (!oPC.IsPlayer)
            {
                return;
            }

            var       effectiveStats           = PlayerStatService.GetPlayerItemEffectiveStats(oPC);
            const int baseChanceToFullyHarvest = 50;

            bool hasBeenSearched = point.GetLocalInt("SCAVENGE_POINT_FULLY_HARVESTED") == 1;

            if (hasBeenSearched)
            {
                oPC.SendMessage("There's nothing left to harvest here...");
                return;
            }


            if (!oPC.IsPlayer && !oPC.IsDM)
            {
                return;
            }
            int rank        = SkillService.GetPCSkillRank(oPC, SkillType.Scavenging);
            int lootTableID = point.GetLocalInt("SCAVENGE_POINT_LOOT_TABLE_ID");
            int level       = point.GetLocalInt("SCAVENGE_POINT_LEVEL");
            int delta       = level - rank;

            if (delta > 8)
            {
                oPC.SendMessage("You aren't skilled enough to scavenge through this. (Required Level: " + (level - 8) + ")");
                oPC.AssignCommand(() => _.ActionInteractObject(point.Object));
                return;
            }

            int dc = 6 + delta;

            if (dc <= 4)
            {
                dc = 4;
            }
            int searchAttempts = 1 + CalculateSearchAttempts(oPC);

            int luck = PerkService.GetCreaturePerkLevel(oPC, PerkType.Lucky) + effectiveStats.Luck;

            if (RandomService.Random(100) + 1 <= luck / 2)
            {
                dc--;
            }

            oPC.AssignCommand(() => _.ActionPlayAnimation(Animation.LoopingGetLow, 1.0f, 2.0f));

            for (int attempt = 1; attempt <= searchAttempts; attempt++)
            {
                int roll = RandomService.Random(20) + 1;
                if (roll >= dc)
                {
                    oPC.FloatingText(ColorTokenService.SkillCheck("Search: *success*: (" + roll + " vs. DC: " + dc + ")"));
                    ItemVO spawnItem = LootService.PickRandomItemFromLootTable(lootTableID);

                    if (spawnItem == null)
                    {
                        return;
                    }

                    if (!string.IsNullOrWhiteSpace(spawnItem.Resref) && spawnItem.Quantity > 0)
                    {
                        _.CreateItemOnObject(spawnItem.Resref, point.Object, spawnItem.Quantity);
                    }

                    float xp = SkillService.CalculateRegisteredSkillLevelAdjustedXP(200, level, rank);
                    SkillService.GiveSkillXP(oPC, SkillType.Scavenging, (int)xp);
                }
                else
                {
                    oPC.FloatingText(ColorTokenService.SkillCheck("Search: *failure*: (" + roll + " vs. DC: " + dc + ")"));

                    float xp = SkillService.CalculateRegisteredSkillLevelAdjustedXP(50, level, rank);
                    SkillService.GiveSkillXP(oPC, SkillType.Scavenging, (int)xp);
                }
                dc += RandomService.Random(3) + 1;
            }

            // Chance to destroy the scavenge point.
            int chanceToFullyHarvest = baseChanceToFullyHarvest - (PerkService.GetCreaturePerkLevel(oPC, PerkType.CarefulScavenger) * 5);

            if (chanceToFullyHarvest <= 5)
            {
                chanceToFullyHarvest = 5;
            }

            point.SetLocalInt("SCAVENGE_POINT_FULLY_HARVESTED", 1);
            oPC.SendMessage("This resource has been fully harvested...");

            point.SetLocalInt("SCAVENGE_POINT_DESPAWN_TICKS", 30);
        }
Пример #7
0
        public bool Run(params object[] args)
        {
            NWPlaceable point = (Object.OBJECT_SELF);
            NWPlayer    oPC   = (_.GetLastOpenedBy());

            if (!oPC.IsPlayer)
            {
                return(false);
            }

            var       effectiveStats           = PlayerStatService.GetPlayerItemEffectiveStats(oPC);
            const int baseChanceToFullyHarvest = 50;
            bool      alwaysDestroys           = point.GetLocalInt("SCAVENGE_POINT_ALWAYS_DESTROYS") == 1;

            bool hasBeenSearched = point.GetLocalInt("SCAVENGE_POINT_FULLY_HARVESTED") == 1;

            if (hasBeenSearched)
            {
                oPC.SendMessage("There's nothing left to harvest here...");
                return(true);
            }

            // Not fully harvested but the timer hasn't counted down yet.
            int refillTick = point.GetLocalInt("SCAVENGE_POINT_REFILL_TICKS");

            if (refillTick > 0)
            {
                oPC.SendMessage("You couldn't find anything new here. Check back later...");
                return(true);
            }

            if (!oPC.IsPlayer && !oPC.IsDM)
            {
                return(false);
            }
            int rank        = SkillService.GetPCSkillRank(oPC, SkillType.Scavenging);
            int lootTableID = point.GetLocalInt("SCAVENGE_POINT_LOOT_TABLE_ID");
            int level       = point.GetLocalInt("SCAVENGE_POINT_LEVEL");
            int delta       = level - rank;

            if (delta > 8)
            {
                oPC.SendMessage("You aren't skilled enough to scavenge through this. (Required Level: " + (level - 8) + ")");
                oPC.AssignCommand(() => _.ActionInteractObject(point.Object));
                return(true);
            }

            int dc = 6 + delta;

            if (dc <= 4)
            {
                dc = 4;
            }
            int searchAttempts = 1 + CalculateSearchAttempts(oPC);

            int luck = PerkService.GetPCPerkLevel(oPC, PerkType.Lucky) + effectiveStats.Luck;

            if (RandomService.Random(100) + 1 <= luck / 2)
            {
                dc--;
            }

            oPC.AssignCommand(() => _.ActionPlayAnimation(_.ANIMATION_LOOPING_GET_LOW, 1.0f, 2.0f));

            for (int attempt = 1; attempt <= searchAttempts; attempt++)
            {
                int roll = RandomService.Random(20) + 1;
                if (roll >= dc)
                {
                    oPC.FloatingText(ColorTokenService.SkillCheck("Search: *success*: (" + roll + " vs. DC: " + dc + ")"));
                    ItemVO spawnItem = LootService.PickRandomItemFromLootTable(lootTableID);

                    if (spawnItem == null)
                    {
                        return(false);
                    }

                    if (!string.IsNullOrWhiteSpace(spawnItem.Resref) && spawnItem.Quantity > 0)
                    {
                        NWItem resource = _.CreateItemOnObject(spawnItem.Resref, point.Object, spawnItem.Quantity);

                        var componentIP = resource.ItemProperties.FirstOrDefault(x => _.GetItemPropertyType(x) == (int)CustomItemPropertyType.ComponentType);
                        if (componentIP != null)
                        {
                            // Add properties to the item based on Scavenging skill.  Similar logic to the resource harvester.
                            var             chance = RandomService.Random(1, 100) + PerkService.GetPCPerkLevel(oPC, PerkType.Lucky) + effectiveStats.Luck;
                            ResourceQuality quality;

                            if (chance < 50)
                            {
                                quality = ResourceQuality.Low;
                            }
                            else if (chance < 75)
                            {
                                quality = ResourceQuality.Normal;
                            }
                            else if (chance < 95)
                            {
                                quality = ResourceQuality.High;
                            }
                            else
                            {
                                quality = ResourceQuality.VeryHigh;
                            }

                            int ipBonusChance = ResourceService.CalculateChanceForComponentBonus(oPC, (level / 10 + 1), quality, true);

                            if (RandomService.Random(1, 100) <= ipBonusChance)
                            {
                                var ip = ResourceService.GetRandomComponentBonusIP(ResourceQuality.Normal);
                                BiowareXP2.IPSafeAddItemProperty(resource, ip.Item1, 0.0f, AddItemPropertyPolicy.IgnoreExisting, true, true);

                                switch (ip.Item2)
                                {
                                case 0:
                                    resource.Name = ColorTokenService.Green(resource.Name);
                                    break;

                                case 1:
                                    resource.Name = ColorTokenService.Blue(resource.Name);
                                    break;

                                case 2:
                                    resource.Name = ColorTokenService.Purple(resource.Name);
                                    break;

                                case 3:
                                    resource.Name = ColorTokenService.Orange(resource.Name);
                                    break;
                                }
                            }
                        }
                    }

                    float xp = SkillService.CalculateRegisteredSkillLevelAdjustedXP(200, level, rank);
                    SkillService.GiveSkillXP(oPC, SkillType.Scavenging, (int)xp);
                }
                else
                {
                    oPC.FloatingText(ColorTokenService.SkillCheck("Search: *failure*: (" + roll + " vs. DC: " + dc + ")"));

                    float xp = SkillService.CalculateRegisteredSkillLevelAdjustedXP(50, level, rank);
                    SkillService.GiveSkillXP(oPC, SkillType.Scavenging, (int)xp);
                }
                dc += RandomService.Random(3) + 1;
            }

            // Chance to destroy the scavenge point.
            int    chanceToFullyHarvest = baseChanceToFullyHarvest - (PerkService.GetPCPerkLevel(oPC, PerkType.CarefulScavenger) * 5);
            string growingPlantID       = point.GetLocalString("GROWING_PLANT_ID");

            if (!string.IsNullOrWhiteSpace(growingPlantID))
            {
                Data.Entity.GrowingPlant growingPlant = FarmingService.GetGrowingPlantByID(new Guid(growingPlantID));
                chanceToFullyHarvest = chanceToFullyHarvest - (growingPlant.LongevityBonus);
            }

            if (chanceToFullyHarvest <= 5)
            {
                chanceToFullyHarvest = 5;
            }

            if (alwaysDestroys || RandomService.Random(100) + 1 <= chanceToFullyHarvest)
            {
                point.SetLocalInt("SCAVENGE_POINT_FULLY_HARVESTED", 1);
                oPC.SendMessage("This resource has been fully harvested...");
            }
            // Otherwise the scavenge point will be refilled in 10-20 minutes.
            else
            {
                point.SetLocalInt("SCAVENGE_POINT_REFILL_TICKS", 100 + RandomService.Random(100));
            }

            point.SetLocalInt("SCAVENGE_POINT_DESPAWN_TICKS", 30);

            return(true);
        }
Пример #8
0
        public Session()
        {
            AccountService        = new Riot.Services.AccountService(this);
            ChampionTradeService  = new Riot.Services.ChampionTradeService(this);
            ClientFacadeService   = new Riot.Services.ClientFacadeService(this);
            GameInvitationService = new Riot.Services.GameInvitationService(this);
            GameService           = new Riot.Services.GameService(this);
            InventoryService      = new Riot.Services.InventoryService(this);
            LcdsProxyService      = new Riot.Services.LcdsProxyService(this);
            LeaguesService        = new Riot.Services.LeaguesService(this);
            LoginService          = new Riot.Services.LoginService(this);
            MasteryBookService    = new Riot.Services.MasteryBookService(this);
            MatchmakingService    = new Riot.Services.MatchmakingService(this);
            PlayerStatsService    = new Riot.Services.PlayerStatsService(this);
            RerollService         = new Riot.Services.RerollService(this);
            SpellBookService      = new Riot.Services.SpellBookService(this);
            SummonerIconService   = new Riot.Services.SummonerIconService(this);
            SummonerRuneService   = new Riot.Services.SummonerRuneService(this);
            SummonerService       = new Riot.Services.SummonerService(this);
            SummonerTeamService   = new Riot.Services.SummonerTeamService(this);

            LootService             = new LootService(this, LcdsProxyService);
            ChampionMasteryService  = new ChampionMasteryService(this, LcdsProxyService);
            TeambuilderDraftService = new TeambuilderDraftService(this, LcdsProxyService);

            PlayerPreferencesService = new PlayerPreferencesService(this);
            MatchHistoryService      = new MatchHistoryService(this);

            var patcher = new PatcherService(this);

            this.chat = new ChatService(this);

            this.Maestro = new Maestro(chat, patcher);

            var settings = new SettingsService(this);

            var hextech   = new HextechService(this);
            var champions = new ChampionsService(this);
            var masteries = new MasteriesService(this);
            var runes     = new RunesService(this);

            var matches = new Server.Profile.MatchHistoryService(this);

            this.summoner = new SummonerService(this);
            this.Assets   = new AssetsService(patcher);

            var rooms = new ChatRoomService(this, chat);
            var login = new AuthService(this);

            var game   = new PlayLoopService(this, rooms);
            var invite = new InviteService(this, game);

            var meta  = new MetaService(this);
            var debug = new DebugService(this);

            var replay = new ReplayService(this);

            patcher.FinishWAD();

            var info = new InfoService(this, patcher);
        }
Пример #9
0
        public bool Run(params object[] args)
        {
            NWPlaceable point = (Object.OBJECT_SELF);
            NWPlayer    oPC   = (_.GetLastOpenedBy());

            if (!oPC.IsPlayer)
            {
                return(false);
            }

            var       effectiveStats           = PlayerStatService.GetPlayerItemEffectiveStats(oPC);
            const int baseChanceToFullyHarvest = 50;
            bool      alwaysDestroys           = point.GetLocalInt("SCAVENGE_POINT_ALWAYS_DESTROYS") == 1;

            bool hasBeenSearched = point.GetLocalInt("SCAVENGE_POINT_FULLY_HARVESTED") == 1;

            if (hasBeenSearched)
            {
                oPC.SendMessage("There's nothing left to harvest here...");
                return(true);
            }

            // Not fully harvested but the timer hasn't counted down yet.
            int refillTick = point.GetLocalInt("SCAVENGE_POINT_REFILL_TICKS");

            if (refillTick > 0)
            {
                oPC.SendMessage("You couldn't find anything new here. Check back later...");
                return(true);
            }

            if (!oPC.IsPlayer && !oPC.IsDM)
            {
                return(false);
            }
            int rank        = SkillService.GetPCSkillRank(oPC, SkillType.Scavenging);
            int lootTableID = point.GetLocalInt("SCAVENGE_POINT_LOOT_TABLE_ID");
            int level       = point.GetLocalInt("SCAVENGE_POINT_LEVEL");
            int delta       = level - rank;

            if (delta > 8)
            {
                oPC.SendMessage("You aren't skilled enough to scavenge through this. (Required Level: " + (level - 8) + ")");
                oPC.AssignCommand(() => _.ActionInteractObject(point.Object));
                return(true);
            }

            int dc = 6 + delta;

            if (dc <= 4)
            {
                dc = 4;
            }
            int searchAttempts = 1 + CalculateSearchAttempts(oPC);

            int luck = PerkService.GetCreaturePerkLevel(oPC, PerkType.Lucky) + effectiveStats.Luck;

            if (RandomService.Random(100) + 1 <= luck / 2)
            {
                dc--;
            }

            oPC.AssignCommand(() => _.ActionPlayAnimation(_.ANIMATION_LOOPING_GET_LOW, 1.0f, 2.0f));

            for (int attempt = 1; attempt <= searchAttempts; attempt++)
            {
                int roll = RandomService.Random(20) + 1;
                if (roll >= dc)
                {
                    oPC.FloatingText(ColorTokenService.SkillCheck("Search: *success*: (" + roll + " vs. DC: " + dc + ")"));
                    ItemVO spawnItem = LootService.PickRandomItemFromLootTable(lootTableID);

                    if (spawnItem == null)
                    {
                        return(false);
                    }

                    if (!string.IsNullOrWhiteSpace(spawnItem.Resref) && spawnItem.Quantity > 0)
                    {
                        _.CreateItemOnObject(spawnItem.Resref, point.Object, spawnItem.Quantity);
                    }

                    float xp = SkillService.CalculateRegisteredSkillLevelAdjustedXP(200, level, rank);
                    SkillService.GiveSkillXP(oPC, SkillType.Scavenging, (int)xp);
                }
                else
                {
                    oPC.FloatingText(ColorTokenService.SkillCheck("Search: *failure*: (" + roll + " vs. DC: " + dc + ")"));

                    float xp = SkillService.CalculateRegisteredSkillLevelAdjustedXP(50, level, rank);
                    SkillService.GiveSkillXP(oPC, SkillType.Scavenging, (int)xp);
                }
                dc += RandomService.Random(3) + 1;
            }

            // Chance to destroy the scavenge point.
            int    chanceToFullyHarvest = baseChanceToFullyHarvest - (PerkService.GetCreaturePerkLevel(oPC, PerkType.CarefulScavenger) * 5);
            string growingPlantID       = point.GetLocalString("GROWING_PLANT_ID");

            if (!string.IsNullOrWhiteSpace(growingPlantID))
            {
                Data.Entity.GrowingPlant growingPlant = FarmingService.GetGrowingPlantByID(new Guid(growingPlantID));
                chanceToFullyHarvest = chanceToFullyHarvest - (growingPlant.LongevityBonus);
            }

            if (chanceToFullyHarvest <= 5)
            {
                chanceToFullyHarvest = 5;
            }

            if (alwaysDestroys || RandomService.Random(100) + 1 <= chanceToFullyHarvest)
            {
                point.SetLocalInt("SCAVENGE_POINT_FULLY_HARVESTED", 1);
                oPC.SendMessage("This resource has been fully harvested...");
            }
            // Otherwise the scavenge point will be refilled in 10-20 minutes.
            else
            {
                point.SetLocalInt("SCAVENGE_POINT_REFILL_TICKS", 100 + RandomService.Random(100));
            }

            point.SetLocalInt("SCAVENGE_POINT_DESPAWN_TICKS", 30);

            return(true);
        }