Esempio n. 1
0
        protected override void Perform(ActionEvent evt, Player player, MapElementInfo info, NVector pos,
                                        ActionHolder holder)
        {
            //create found window
            WindowPanelBuilder win = WindowPanelBuilder.Create("Found a new town");

            /*GameObject name = win.panel.AddInput("town name",NGenTown.GetTownName(PlayerMgmt.ActPlayer().Nation().TownNameGenerator),s => {});
             * win.panel.AddButton("Generate new name", () =>
             * {
             *  name.GetComponent<InputField>().text = NGenTown.GetTownName(PlayerMgmt.ActPlayer().Nation().TownNameGenerator);
             *  //name.GetComponentsInChildren<Text>()[0].text = NGenTown.GetTownName(PlayerMgmt.Get().GetActPlayer().nation);
             *  //name.GetComponentsInChildren<Text>()[1].text = NGenTown.GetTownName(PlayerMgmt.Get().GetActPlayer().nation);
             * }, "random", "random");*/

            Button button = null;

            InputField townName = win.panel.AddInputRandom("town name",
                                                           LClass.s.NameGenerator(S.ActPlayer().Nation().TownNameGenerator), s => { },
                                                           () => LClass.s.NameGenerator(S.ActPlayer().Nation().TownNameGenerator));

            var coats    = L.b.coats.GetAllByCategory("town");
            var dropdown = win.panel.AddDropdown(coats, coats.ElementAt(S.Towns().GetAll().Length % coats.Count).id,
                                                 coat =>
            {
                UIHelper.UpdateButtonImageColor(button, L.b.coats[coat].color);
            });

            button = win.panel.AddImageTextButton("Found the town", DataAction().Icon, () =>
            {
                win.Close();
                FoundTown(info, pos, townName.text, coats[dropdown.value].id, holder.data.ContainsKey("kill"));
            }, DataAction().sound);
            UIHelper.UpdateButtonImageColor(button, L.b.coats[coats[dropdown.value].id].color);
            win.Finish(400);
        }
Esempio n. 2
0
        public static void WaitRound(ActionHolders holder, ActionHolder action, MapElementInfo info, NVector pos, int cost = -1, string sett = null, ActionEvent evt = ActionEvent.Direct)
        {
            FDataAction da = action.DataAction();

            cost = cost == -1 ? action.cost : cost;
            int round = (int)Math.Ceiling((1f * cost - info.data.ap) / info.data.apMax);

            WindowPanelBuilder wpb = WindowPanelBuilder.Create($"Wait for {da.Name()}?");

            wpb.panel.RichText(da.Desc());
            wpb.panel.AddImageLabel($"Action {da.Name()} need {cost - info.data.ap} AP more. You can wait {round} rounds.",
                                    "round");
            wpb.panel.AddButton($"Wait {round} rounds", () =>
            {
                var aw   = new ActionWaiting(action, holder, pos);
                aw.apMax = cost;
                aw.sett  = sett;
                aw.evt   = evt;
                info.SetWaitingAction(aw);
                L.b.animations.Create("sandClock", pos);

                OnMapUI.Get().UpdatePanel(info.Pos());
                wpb.Close();
            });
            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 3
0
        protected override void Run(Player player)
        {
            WindowPanelBuilder wpb = WindowPanelBuilder.Create(Data().Name());
            var saveonexit         = LSys.tem.options["saveonexit"];

            saveonexit.AddOption(wpb.panel);
            wpb.panel.AddButton("to main menu", () =>
            {
                if (saveonexit.Bool())
                {
                    LoadSaveMgmt.UpdateSave("quicksave", "quick save");
                }
                SceneManager.LoadScene(0, LoadSceneMode.Single);
            });

            wpb.panel.AddButton("exit game", () =>
            {
                if (saveonexit.Bool())
                {
                    LoadSaveMgmt.UpdateSave("quicksave", "quick save");
                }
                Application.Quit();
            });
            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 4
0
        private bool WinLose()
        {
            if (status == "win")
            {
                WindowPanelBuilder w = WindowPanelBuilder.Create(S.T("endGameWin"));
                w.panel.AddLabel(S.T("endGamePoints", points, S.Round().Round));
                w.panel.AddButtonT("endgame", () => { SceneManager.LoadScene(0); });
                w.panel.AddButtonT("endGameWinButton", () => { });
                w.Finish();
                NAudio.PlayMusic("win", false);
                status = null;
                return(true);
            }

            if (status == "lose")
            {
                WindowPanelBuilder w = WindowPanelBuilder.Create(S.T("endGameLose"));
                w.panel.AddLabel(S.T("endGamePoints", points, S.Round().Round));
                w.panel.AddButtonT("endgame", () =>
                {
                    w.Close();
                });
                w.onClose = () =>
                {
                    S.Players().KillPlayer(id);
                };
                w.Finish();
                NAudio.PlayMusic("lose", false);
                status = null;
                return(true);
            }

            return(false);
        }
Esempio n. 5
0
        protected override void Perform(ActionEvent evt, Player player, ActionHolder holder)
        {
            var towns = S.Towns().GetByPlayer(player.id);

            if (towns.Count == 0)
            {
                OnMapUI.Get().ShowPanelMessageError("No town for trading.");
                return;
            }

            if (towns.Count == 1)
            {
                new ActionTradeWindow(towns[0], holder.data["trade"]);
                return;
            }

            WindowPanelBuilder wpb = WindowPanelBuilder.Create("Where do you want to trade?");

            foreach (var town in towns)
            {
                wpb.panel.AddImageTextButton(town.name, town.GetIcon(),
                                             () => { new ActionTradeWindow(town, holder.data["trade"]); wpb.Close(); });
            }

            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 6
0
        private void SelectDest(Player player, ActionHolder holder, Town t)
        {
            Town dest  = null;
            var  towns = S.Towns().GetByPlayer(player.id);

            if (towns.Count == 2)
            {
                dest = t == towns[0] ? towns[1] : towns[0];
                new ActionSendResWindow(t, dest, holder.data["trade"]);
                return;
            }

            //ask user
            WindowPanelBuilder wpb = WindowPanelBuilder.Create(S.T("sendResTo", L.b.actions["sendRes"].Name()));

            foreach (var town in towns)
            {
                if (town != t)
                {
                    wpb.panel.AddImageTextButton(town.name, town.GetIcon(),
                                                 () =>
                    {
                        new ActionSendResWindow(t, town, holder.data["trade"]);
                        wpb.Close();
                    });
                }
            }

            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 7
0
        protected override void Run(Player player)
        {
            //create it
            WindowPanelBuilder win = WindowPanelBuilder.Create("Main menu");

            L.b.gameButtons.BuildMenu(S.ActPlayer(), "game", null, true, win.panel.panel.transform);
            win.Finish();
        }
Esempio n. 8
0
        protected override void Perform(ActionEvent evt, Player player, MapElementInfo info, NVector pos,
                                        ActionHolder holder)
        {
            DataTerrain terrain = GameMgmt.Get().newMap.Terrain(pos);

            //which is possible?
            List <(string key, string value)> opts = new List <(string key, string value)>();
            int i = 0;

            while (holder.data.ContainsKey(i.ToString()))
            {
                var d = SplitHelper.Split(holder.data[i.ToString()]);
                if (terrain.id == d.key)
                {
                    opts.Add(d);
                }
                i++;
            }

            //found it?
            if (opts.Count == 0)
            {
                OnMapUI.Get().unitUI.ShowPanelMessageError($"No terraform possible for {terrain.Name()}");
                return;
            }

            Vector3Int v3 = new Vector3Int(pos.x, pos.y, 1); //TODO find right pos

            if (opts.Count == 1)
            {
                GameMgmt.Get().newMap.levels[pos.level]
                .SetTile(v3, opts[0].value == "remove" ? null : L.b.terrains[opts[0].value]);
                return;
            }

            //multiple?
            WindowPanelBuilder wpb = WindowPanelBuilder.Create($"Terraform {terrain.Name()}");

            foreach (var opt in opts)
            {
                wpb.panel.AddImageTextButton(CreateTitle(opt), terrain.Sprite(), () =>
                {
                    GameMgmt.Get().newMap.levels[pos.level]
                    .SetTile(v3, opt.value == "remove" ? null : L.b.terrains[opt.value]);
                    wpb.Close();
                });
            }

            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 9
0
        private void MoveUnit(MapElementInfo info, NVector pos)
        {
            UnitInfo ui = (UnitInfo)info;
            int      l  = GameMgmt.Get().data.map.levels.Count;

            //TODO check if go up/down possible?

            //how many level i have?
            if (l == 1)
            {
                OnMapUI.Get().unitUI.ShowPanelMessageError($"{info.name} can not move between the levels, there is no second level");
                return;
            }

            if (l == 2)
            {
                //switch it
                TryMoveUnit(ui, new NVector(pos.x, pos.y, (pos.level + 1) % 2));
                return;
            }

            if (pos.level == 0)
            {
                //go up
                TryMoveUnit(ui, pos.DiffLevel(+1));
                return;
            }

            if (pos.level + 1 == l)
            {
                //go down
                TryMoveUnit(ui, pos.DiffLevel(-1));
                return;
            }

            //ask
            WindowPanelBuilder wpb = WindowPanelBuilder.Create("Where do you want to go?");

            wpb.panel.AddButton($"Go up to {GameMgmt.Get().data.map.levels[pos.level + 1].name}", () =>
            {
                TryMoveUnit(ui, pos.DiffLevel(+1));
                wpb.Close();
            });
            wpb.panel.AddButton($"Go down to {GameMgmt.Get().data.map.levels[pos.level - 1].name}", () =>
            {
                TryMoveUnit(ui, pos.DiffLevel(-1));
                wpb.Close();
            });
            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 10
0
        protected override void Run(Player player)
        {
            string[] s = SplitHelper.Separator(PlayerPrefs.GetString("update.txt", "false"));

            if (s[0].Equals("false"))
            {
                return;
            }

            WindowPanelBuilder w = WindowPanelBuilder.Create($"Update to {s[1]}");

            w.panel.AddLabel(s[2]);
            w.panel.AddButton($"Download {s[1]}", (() => Application.OpenURL("http://9nations.de/download")));
            w.AddClose();
            w.Finish();
        }
Esempio n. 11
0
        public void ShowImportant()
        {
            WindowPanelBuilder w = WindowPanelBuilder.Create(title);

            w.panel.RichText(desc);

            if (action == null)
            {
                w.AddClose();
            }
            else
            {
                w.panel.AddButton("Ok", CallAction);
            }

            w.Finish();
        }
Esempio n. 12
0
        private void MoveBuilding(MapElementInfo info, NVector pos, ActionHolder holder)
        {
            BuildingInfo ui = (BuildingInfo)info;

            //check status
            if (!info.data.data.ContainsKey("level"))
            {
                //build stairs
                int l = GameMgmt.Get().data.map.levels.Count;
                //blocked by buildings?
                bool up   = pos.level + 1 < l && S.Building().Free(pos.DiffLevel(1));
                bool down = pos.level > 0 && S.Building().Free(pos.DiffLevel(-1));

                if (!up && !down)
                {
                    OnMapUI.Get().unitUI.ShowPanelMessageError($"{info.name} can not work between the levels, there is no second level or it is blocked.");
                    return;
                }

                //ask?
                if (up && down)
                {
                    WindowPanelBuilder wpb = WindowPanelBuilder.Create("Where do you want to build your stairs?");
                    wpb.panel.AddButton($"Build stairs up to {GameMgmt.Get().data.map.levels[pos.level + 1].name}", () =>
                    {
                        Build(true, info, pos, holder);
                        wpb.Close();
                    });
                    wpb.panel.AddButton($"Build stairs down to {GameMgmt.Get().data.map.levels[pos.level - 1].name}", () =>
                    {
                        Build(false, info, pos, holder);
                        wpb.Close();
                    });
                    wpb.AddClose();
                    wpb.Finish();
                    return;
                }

                Build(up, info, pos, holder);
            }

            //move unit
            int diff = ConvertHelper.Int(info.data.data["level"]);

            TryMoveUnit(S.Unit().At(pos), pos.DiffLevel(diff));
        }
Esempio n. 13
0
        protected override void Run(Player player)
        {
            WindowPanelBuilder wpb = WindowPanelBuilder.Create(Data().Name());

            foreach (var ol in L.b.overlays.Values())
            {
                wpb.panel.AddImageTextButton(ol.Name(), ol.Icon, () =>
                {
                    player.overlay.ViewOverlay(ol.id);
                    wpb.Close();
                });
            }

            wpb.panel.AddButton(S.T("reset"), () =>
            {
                player.overlay.ViewOverlay(null);
                wpb.Close();
            });
            wpb.Finish();
        }
Esempio n. 14
0
        /// <summary>
        /// Show and throw again
        /// </summary>
        /// <param name="e"></param>
        /// <exception cref="Exception"></exception>
        public static void ShowException(Exception e)
        {
            string stack = e.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None)[0];

            WindowPanelBuilder w = WindowPanelBuilder.Create("A error happened");

            w.panel.AddLabel(e.GetType().ToString());
            w.panel.AddLabel(e.Message);
            w.panel.AddLabel(stack);
            w.panel.AddLabel("The error will sent automatically.");

            //add reset?
            if (S.IsGame())
            {
                w.panel.AddButton("Reset round", S.Players().ResetRound);
            }

            w.AddClose();
            w.Finish();
            throw new Exception("Exception Handler", e);
        }
Esempio n. 15
0
        protected override void Run(Player player)
        {
            WindowPanelBuilder wpb = WindowPanelBuilder.Create("Move level");

            foreach (var gml in S.Map().levels)
            {
                var b = wpb.panel.AddButton(gml.name, () =>
                {
                    S.Map().view.View(gml.level);
                    wpb.Close();
                });

                if (gml.level == S.Map().view.ActiveLevel)
                {
                    b.enabled = false;
                }
            }

            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 16
0
        protected override void Perform(ActionEvent evt, Player player, MapElementInfo info, NVector pos,
                                        ActionHolder holder)
        {
            //dying?
            if (holder.trigger == ActionEvent.NextRound)
            {
                info.Kill();
                info.AddNoti(S.T("destroyDie", info.name), DataAction().Icon);
                return;
            }

            WindowPanelBuilder wpb = WindowPanelBuilder.Create(S.T("destroyKill", info.name));

            wpb.panel.AddImageTextButton(S.T("destroyKill", info.name), info.Sprite(), (() =>
            {
                info.Kill();
                OnMapUI.Get().UpdatePanel(info.Pos());
                wpb.Close();
            }));
            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 17
0
        public IEnumerator NextPlayer()
        {
            actPlayer++;
            //next round?
            if (actPlayer >= players.Count)
            {
                actPlayer = -1;
                yield return(S.Round().NextRound());

                actPlayer = 0;
            }

            //a human player left?
            if (CountHumanPlayer() == 0)
            {
                WindowPanelBuilder w = WindowPanelBuilder.Create(S.T("endGame"));
                w.panel.AddLabelT("endGamePlayer");
                w.AddClose();
                w.onClose = () =>
                {
                    SceneManager.LoadScene(0);
                };
                w.Finish();
                yield break;
            }

            //is a human?
            if (players[actPlayer].Type().id == PlayerType.Human)
            {
                yield return(GameMgmt.Get().load.ShowMessage($"Start turn for {S.ActPlayer().name}"));

                S.ActPlayer().StartRound();
            }
            else
            {
                yield return(NextPlayer());
            }
        }
Esempio n. 18
0
        public InputKeyChange(InputKey key)
        {
            this._key = key;

            WindowPanelBuilder wpb = WindowPanelBuilder.Create("Set new Key");

            wpb.panel.AddLabel($"Press a new key for {key.Name()}");
            Button change = wpb.panel.AddButton("Press any new key", () =>
            {
                key.SetNewKey(_newKey);
                S.InputAction().findKey = null;
                wpb.Close();
            });

            change.enabled = false;
            wpb.panel.AddButton($"Reset to {key.key}", () =>
            {
                key.SetNewKey(key.key);
                S.InputAction().findKey = null;
                wpb.Close();
            });
            wpb.AddClose();
            wpb.Finish();

            S.InputAction().findKey = code =>
            {
                if (code.ToString().StartsWith("Mouse"))
                {
                    return;
                }

                _newKey        = code.ToString();
                change.enabled = true;
                UIHelper.UpdateButtonText(change, $"Set new key to {_newKey}");
            };
        }
Esempio n. 19
0
        protected override void Perform(ActionEvent evt, Player player, MapElementInfo info, NVector pos,
                                        ActionHolder holder)
        {
            Debug.Log(evt + " " + info.name);
            if (evt == ActionEvent.NextRound)
            {
                Repeat(player, info, pos, holder);
                return;
            }

            PerformRepeat(player, info, pos, holder);
            //build it
            WindowPanelBuilder wpb = WindowPanelBuilder.Create(S.T("examine"));

            //show all res
            S.Map().Terrain(pos).ShowRes(wpb.panel, player, pos);
            wpb.panel.AddButtonT("examineRepeat", () =>
            {
                SetRepeat(info, pos, holder);
                wpb.Close();
            });
            wpb.AddClose();
            wpb.Finish();
        }
Esempio n. 20
0
        IEnumerator Start2()
        {
            NAudio.PlayMusic("title", true);
            //load database
            yield return(LSys.Init(GameObject.Find("UICanvas").GetComponentInChildren <LoadingScreen>(true)));

            yield return(L.Init());

            yield return(LSys.tem.Load.ShowMessage("Prepare main menu"));

            Debug.Log($"Start main menu V{Application.version}-{Application.platform}");

            version.text =
                $"{Application.productName} V{Application.version}-{Application.platform} - {Application.companyName}";
            warning.text = LSys.tem.helps["beta"].Desc().Replace(";;", Environment.NewLine);

            OptionHelper.RunStartOptions();

            L.b.gameButtons.BuildMenu(null, "title", null, true, panel.transform);

            //show it
            LSys.tem.Load.FinishLoading();


            // first start?
            if (!PlayerPrefs.HasKey("lastVersion"))
            {
                //todo dynamic
                if (Application.platform == RuntimePlatform.Android)
                {
                    new AndroidStartUp().Run();
                }
                else
                {
                    new ComputerStartUp().Run();
                }
            }

            //show message?
            if (PlayerPrefs.GetString("lastVersion", "x") != Application.version)
            {
                PlayerPrefs.SetString("lastVersion", Application.version);
                PlayerPrefs.Save();

                WindowPanelBuilder w = WindowPanelBuilder.Create("Good to know");

                foreach (var help in LSys.tem.helps.GetAllByCategory("start"))
                {
                    if (!help.req.Check(null))
                    {
                        continue;
                    }

                    w.panel.AddHeaderLabel(help.Name());
                    w.panel.RichText(help.Desc());
                }
                w.AddClose();
                w.Finish();
            }

            StartCoroutine(CheckUpdate());
        }
Esempio n. 21
0
        protected override void Run(Player player)
        {
            //create it
            WindowPanelBuilder p = WindowPanelBuilder.Create("Debug Window");

            p.panel.AddButton("Give 500 gold", () =>
            {
                Town t = S.Towns().GetByActPlayer().First();

                t.AddRes("gold", 500, ResType.Gift);
            });
            p.panel.AddButton("Trade", () =>
            {
                ActionHolder ah  = new ActionHolder();
                ah.data["trade"] = null;
                LClass.s.GetNewAction("trade").PerformCheck(ActionEvent.Direct, S.ActPlayer(), ah);
            });
            p.panel.AddButton("Give research", () =>
            {
                Town t = S.Towns().GetByActPlayer()[0];

                t.AddRes("research", 100, ResType.Gift);
            });
            p.panel.AddButton("Finish all research", () =>
            {
                foreach (Research r in L.b.researches.Values())
                {
                    S.ActPlayer().research.Set(r.id, true);
                }
            });
            p.panel.AddButton("Unfinish all research", () =>
            {
                foreach (Research r in L.b.researches.Values())
                {
                    S.ActPlayer().research.Set(r.id, false);
                }
            });
            p.panel.AddButton("Switch Fog", () =>
            {
                foreach (TileMapConfig16 t in S.ActPlayer().fog.tileMap)
                {
                    t.gameObject.SetActive(!t.gameObject.activeSelf);
                }
            });
            p.panel.AddButton("Show player features", () =>
            {
                WindowPanelBuilder wp = WindowPanelBuilder.Create("features");
                foreach (var fp in L.b.playerOptions.Values())
                {
                    wp.panel.AddLabel(fp.Name() + ": " + S.ActPlayer().GetFeature(fp.id) + " (" + fp.standard + ")");
                }
                wp.Finish();
            });
            p.panel.AddButton("Show game features", () =>
            {
                WindowPanelBuilder wp = WindowPanelBuilder.Create("features");
                foreach (var fp in L.b.gameOptions.Values())
                {
                    wp.panel.AddLabel(fp.Name() + ": " + fp.Value() + " (" + fp.standard + ")");
                }
                wp.Finish();
            });
            p.panel.AddButton("Reload game library", () =>
            {
                GameMgmt.Get().ReloadGameLib();
                p.Close();
            });
            p.panel.AddButton("Give unit", () =>
            {
                WindowPanelBuilder wp = WindowPanelBuilder.Create("units");
                if (S.Towns().GetByActPlayer().Count > 0 && S.Unit().Free(S.Towns().GetByActPlayer()[0].pos))
                {
                    foreach (var du in L.b.units.Values())
                    {
                        wp.panel.AddImageTextButton(du.Name(), du.Sprite(), (() =>
                        {
                            S.Unit().Create(S.ActPlayerID(), du.id, S.Towns().GetByActPlayer()[0].pos).FinishConstruct();
                            wp.Close();
                            p.Close();
                        }));
                    }
                }
                else
                {
                    wp.panel.AddLabel("Field is blocked");
                }
                wp.Finish();
            });
            p.panel.AddButton("Reset round", () =>
            {
                S.Players().ResetRound();
            });
            p.panel.AddLabel("DPI: " + Screen.dpi);
            p.Finish();
        }
Esempio n. 22
0
        private void BuildWindow(string settings)
        {
            WindowPanelBuilder w = WindowPanelBuilder.Create(L.b.actions["trade"].Name());

            //build res list
            List <string> values = new List <string>();
            List <string> titles = new List <string>();

            //sell
            foreach (Resource r in L.b.res.Values())
            {
                if (settings != null && settings.StartsWith("sell") && !settings.Contains(r.id))
                {
                    continue;
                }

                if (r.price > 0 && _town.GetRes(r.id) > 0)
                {
                    values.Add(r.id);
                    titles.Add(r.Text(_town.GetRes(r.id)));
                }
            }

            //todo sort sell

            //found something?
            if (values.Count == 0)
            {
                w.panel.AddLabelT("tradeSellError");
                w.Finish();
                return;
            }

            _sell = values[0];
            w.panel.AddHeaderLabelT("tradeSell");
            w.panel.AddDropdown(values.ToArray(), values[0], titles.ToArray(), s =>
            {
                _sell = s;
                UpdateButton();
            });

            values = new List <string>();
            titles = new List <string>();

            //buy
            foreach (Resource r in L.b.res.Values())
            {
                if (settings != null && settings.StartsWith("buy") && !settings.Contains(r.id))
                {
                    continue;
                }

                if (r.price > 0)
                {
                    values.Add(r.id);
                    titles.Add(r.Name());
                }
            }

            //found something?
            if (values.Count == 0)
            {
                w.panel.AddLabelT("tradeBuyError");
                w.Finish();
                return;
            }

            _buy = values[0];
            w.panel.AddHeaderLabelT("tradeBuy");
            w.panel.AddDropdown(values.ToArray(), values[0], titles.ToArray(), s =>
            {
                _buy = s;
                UpdateButton();
            });

            var sound = L.b.actions["trade"].sound;

            //add button
            shop1 = w.panel.AddButton("", () =>
            {
                Shop(1);
                w.Close();
            }, sound);

            //add button
            shop10 = w.panel.AddButton("", () =>
            {
                Shop(10);
                w.Close();
            }, sound);

            //add button
            shop100 = w.panel.AddButton("", () =>
            {
                Shop(100);
                w.Close();
            }, sound);

            //add button
            shop1000 = w.panel.AddButton("", () =>
            {
                Shop(1000);
                w.Close();
            }, sound);

            w.Finish();
            UpdateButton();
        }