예제 #1
0
        //Filter portraits based on filter selections
        //If no tag selected, returns all portrait IDs
        //Used in PortraitList
        //0 - ignore, 1 - require, 2 - exclude
        public static string[] FilterPortraitIDs(string filterName,
                                                 Tags.FilterState filterValue,
                                                 Dictionary <string, TagData> allPortraitsData,
                                                 Dictionary <string, Tags.FilterState> tagListAll)
        {
            string[] result = new string[] { };
            tagListAll[filterName] = filterValue;
            if (!tagListAll.ContainsValue(Tags.FilterState.Exclude) && !tagListAll.ContainsValue(Tags.FilterState.Require))
            {
                result = allPortraitsData.Values.Select(type => type?.CustomId).ToArray();
                return(result);
            }
            var requiredTags  = tagListAll.Where(p => p.Value == Tags.FilterState.Require).Select(kvp => kvp.Key).ToList();
            var forbiddenTags = tagListAll.Where(p => p.Value == Tags.FilterState.Exclude).Select(kvp => kvp.Key).ToList();

            result = allPortraitsData.Where(kvp => {
                bool tresult = true;
                foreach (string filteredTag in requiredTags)
                {
                    if (!kvp.Value.tags.Contains(filteredTag))
                    {
                        return(false);
                    }
                }
                foreach (string filteredTag in forbiddenTags)
                {
                    if (kvp.Value.tags.Contains(filteredTag))
                    {
                        return(false);
                    }
                }
                return(tresult);
            }).Select(kvp => kvp.Value.CustomId).ToArray();
            return(result);
        }
예제 #2
0
        //Filter portraits based on filter selections
        //If no tag selected, returns all PortraitData
        //Used in PortraitPacks
        public static Dictionary <string, TagData> FilterPortraitData(string filterName,
                                                                      Tags.FilterState filterValue,
                                                                      Dictionary <string, TagData> allPortraitsData,
                                                                      Dictionary <string, Tags.FilterState> tagListAll)
        {
            Dictionary <string, TagData> result = new Dictionary <string, TagData>();

            tagListAll[filterName] = filterValue;
            if (!tagListAll.ContainsValue(Tags.FilterState.Exclude) && !tagListAll.ContainsValue(Tags.FilterState.Require))
            {
                result = new Dictionary <string, TagData> (allPortraitsData);
                return(result);
            }
            var requiredTags  = tagListAll.Where(p => p.Value == Tags.FilterState.Require).Select(kvp => kvp.Key).ToList();
            var forbiddenTags = tagListAll.Where(p => p.Value == Tags.FilterState.Exclude).Select(kvp => kvp.Key).ToList();

            result = new Dictionary <string, TagData> (allPortraitsData.Where(kvp => {
                bool tresult = true;
                foreach (string filteredTag in requiredTags)
                {
                    if (!kvp.Value.tags.Contains(filteredTag))
                    {
                        return(false);
                    }
                }
                foreach (string filteredTag in forbiddenTags)
                {
                    if (kvp.Value.tags.Contains(filteredTag))
                    {
                        return(false);
                    }
                }
                return(tresult);
            }).ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
            return(result);
        }
예제 #3
0
        public void OnGUI(UnityModManager.ModEntry modEntry)
        {
            if (Mod == null || !Mod.Enabled)
            {
                return;
            }
            if (_buttonStyle == null)
            {
                _buttonStyle = new GUIStyle(GUI.skin.button)
                {
                    alignment = TextAnchor.MiddleLeft
                }
            }
            ;
            if (_fixedStyle == null)
            {
                _fixedStyle = new GUIStyle(GUI.skin.button)
                {
                    fixedWidth = 150f, wordWrap = true
                }
            }
            ;
            List <string> allToggleTags = new List <string>();

            //Overall list operations
            using (new GUILayout.HorizontalScope())
            {
                GUILayout.Space(10f);
                if (GUILayout.Button(Local["Menu_PortraitList_Btn_LoadPortraits"], _buttonStyle, GUILayout.ExpandWidth(false)))
                {
                    PortraitTagSelector.portraitIDsUI = new string[] { };
                    tagsData         = Tags.LoadTagsData(false);
                    allPortraitsData = new Dictionary <string, TagData>();
                    allPortraitsData = Helpers.LoadAllPortraitsTags(tagsData, ToggleIgnoreDefaultPortraits);
                    portraitIDs      = allPortraitsData.Values.Select(type => type?.CustomId).ToArray();
                    portraitIndex    = -1;
                    portraitData     = null;
                    tagListAll       = Tags.AllTagsFilter(tagsData);
                    _tagList         = new string[] { };
                    _tagData         = null;
#if (DEBUG)
                    modEntry.Logger.Log($"allPortraitsData count: {allPortraitsData.Count}");
#endif
                }
                if (GUILayout.Button(Local["Menu_PortraitList_Btn_UnloadPortraits"], _buttonStyle, GUILayout.ExpandWidth(false)))
                {
                    Unload();
                }
                //Save all non-default data to the filesystem
                if (GUILayout.Button(Local["Menu_PortraitList_Btn_SavePortraitDataAll"], _buttonStyle, GUILayout.ExpandWidth(false)))
                {
                    if (tagsData != null)
                    {
                        var changedTagsData = tagsData.Where(kvp =>
                        {
                            bool tresult = false;
                            if (allPortraitsData.ContainsKey(kvp.Key))
                            {
                                IEnumerable <string> tdifference = allPortraitsData[kvp.Key].tags.Except(kvp.Value.tags);
                                if (!tdifference.Any())
                                {
                                    tresult = true;
                                }
                            }
                            return(tresult);
                        }).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
                        Tags.SaveTagsData(changedTagsData, false);
                        allPortraitsData = Helpers.LoadAllPortraitsTags(tagsData, ToggleIgnoreDefaultPortraits);
                        tagListAll       = Tags.AllTagsFilter(tagsData);
                    }
                }
            }
            //Filter portrait list by tags
            if (tagListAll != null)
            {
                GUILayout.Label(Local["Menu_PortraitList_Lbl_Filters"]);
                if (GUILayout.Button(Local["Menu_PortraitList_Btn_AllTags"], _fixedStyle, GUILayout.ExpandWidth(false)))
                {
                    portraitIDs   = allPortraitsData.Values.Select(type => type?.CustomId).ToArray();
                    tagListAll    = tagListAll.ToDictionary(p => p.Key, p => Tags.FilterState.Allow);
                    portraitIndex = -1;
                    portraitData  = null;
                    _tagList      = new string[] { };
                    _tagData      = null;
                }
                //Apply filters to the game UI. Requires working harmony patch and a published assembly to complie
                if (GUILayout.Button(Local["Menu_PortraitList_Btn_ApplyFilters"], _fixedStyle, GUILayout.ExpandWidth(false)))
                {
                    PortraitTagSelector.portraitIDsFilter = new string[portraitIDs.Count()];
                    portraitIDs.CopyTo(PortraitTagSelector.portraitIDsFilter, 0);
                    if (Game.Instance.IsControllerMouse)
                    {
                        if (Game.Instance.UI.CharacterBuildController.Portrait != null)
                        {
                            if (Game.Instance.UI.CharacterBuildController.Portrait.IsUnlocked)
                            {
                                if (Mod.Core.UI.PortraitTagSelector)
                                {
                                    Mod.Core.UI.PortraitTagSelector.HandleChooseElement(Mod.Core.UI.PortraitTagSelector.m_Tags, 1);
                                }
//                                Game.Instance?.UI.CharacterBuildController.Portrait.PortraitSelector.HandleClickUpload(false);
                            }
                            else
                            {
                                UIHelpers.KbmUpdateCustomPortraits();
                            }
                        }
                    }
                    //Reserved for when you'll be able to select a custom portrait from the gamepad UI

/*                    if (Game.Instance.IsControllerGamepad)
 *                  {
 *
 *                  }*/
                }
                //Portrait filters
                using (new GUILayout.HorizontalScope())
                {
                    var filterKeys = new List <string> (tagListAll.Keys);
                    foreach (string filterName in filterKeys)
                    {
                        Tags.FilterState FilterValue = tagListAll[filterName];
                        FilterValue            = (Tags.FilterState)UIHelpers.MultiToggle((int)FilterValue, filterName, 2, _fixedStyle);
                        portraitIDs            = Helpers.FilterPortraitIDs(filterName, (Tags.FilterState)FilterValue, allPortraitsData, tagListAll);
                        tagListAll[filterName] = FilterValue;
                    }
                }
            }
            //Portraits list
            //1st column - portrait list
            //2rd column - buttons. Open folder. Tags. Clear tags.
            //3nd column - portrait image
            if (portraitIDs != null)
            {
                using (new GUILayout.HorizontalScope())
                {
                    using (new GUILayout.VerticalScope(GUILayout.Width(120)))
                    {
                        GUILayout.Label(Local["Menu_PortraitList_Lbl_PortraitListHeader"]);
                        GUILayout.Space(10f);
                        using (var ScrollView = new GUILayout.ScrollViewScope(_scrollPosition))
                        {
                            _scrollPosition = ScrollView.scrollPosition;
                            GUIHelper.SelectionGrid(ref portraitIndex, portraitIDs, 1,
                                                    () =>
                            {
                                if (_tagData != null)
                                {
                                    //TODO check overwrite settings
                                    _tagData.Hash = Helpers.GetPseudoHash(portraitData.FullLengthPortrait.texture).ToString();
                                    tagsData[portraitData.CustomId] = _tagData;
                                }
                                portraitData = Helpers.LoadPortraitData(allPortraitsData[portraitIDs[portraitIndex]].CustomId);
                                inputTagName = "";
                                if (tagsData.ContainsKey(portraitData.CustomId))
                                {
                                    _tagData = new TagData(
                                        Helpers.GetPseudoHash(portraitData.FullLengthPortrait.texture).ToString(),
                                        portraitData.CustomId,
                                        tagsData[portraitData.CustomId].tags);
                                    _tagList = _tagData.tags.ToArray();
                                }
                                else
                                {
                                    _tagData = new TagData(
                                        Helpers.GetPseudoHash(portraitData.FullLengthPortrait.texture).ToString(),
                                        portraitData.CustomId,
                                        new List <string>());
                                    _tagList = new string[] { };
                                }
                                _tagIndex = -1;
                            }, _buttonStyle, GUILayout.ExpandWidth(false));
                        }
                    }
                    if (portraitData != null)
                    {
                        using (new GUILayout.HorizontalScope())
                        {
                            using (new GUILayout.VerticalScope(GUILayout.MaxWidth(240), GUILayout.ExpandWidth(false)))
                            {
                                GUILayout.Label(Local["Menu_PortraitList_Lbl_tagList"]);
                                GUILayout.Space(10f);
                                allToggleTags = new List <string>(tagListAll.Keys);
                                allToggleTags.Sort();
                                foreach (string toggleTagName in allToggleTags)
                                {
                                    bool tagToggleValue = _tagData.tags.Contains(toggleTagName);
                                    GUIHelper.ToggleButton(ref tagToggleValue, toggleTagName, () =>
                                    {
                                        if (!_tagData.tags.Contains(toggleTagName))
                                        {
                                            _tagData.tags.Add(toggleTagName);
                                        }
                                    }, () =>
                                    {
                                        if (_tagData.tags.Contains(toggleTagName))
                                        {
                                            _tagData.tags.Remove(toggleTagName);
                                        }
                                    },
                                                           _fixedStyle);
                                }
                            }
                            using (new GUILayout.VerticalScope(GUILayout.MaxWidth(360), GUILayout.ExpandWidth(false)))
                            {
                                GUILayout.Label(Local["Menu_PortraitList_Lbl_tagMsg"]);
                                using (new GUILayout.HorizontalScope())
                                {
                                    GUIHelper.TextField(ref inputTagName, _fixedStyle);
                                    if (GUILayout.Button(Local["Menu_PortraitList_Btn_AddTag"], _buttonStyle, GUILayout.ExpandWidth(false)))
                                    {
                                        if (Array.IndexOf(ReservedTags, inputTagName.ToLower()) < 0 && !(_tagData.tags.Contains(inputTagName.ToLower())))
                                        {
                                            _tagData.tags.Add(inputTagName.ToLower());
                                            _tagList = _tagList.Concat(new string[] { inputTagName.ToLower() }).ToArray();
                                            if (!allToggleTags.Contains(inputTagName.ToLower()))
                                            {
                                                allToggleTags.Add(inputTagName.ToLower());
                                                allToggleTags.Sort();
                                                tagListAll[inputTagName.ToLower()] = Tags.FilterState.Allow;
                                            }
                                        }
                                    }
                                }
                                if (GUILayout.Button(Local["Menu_PortraitList_Btn_ClearTags"], _fixedStyle, GUILayout.ExpandWidth(false)))
                                {
                                    _tagData.tags.Clear();
                                    _tagList     = new string[] { };
                                    inputTagName = "";
                                    _tagIndex    = -1;
                                }
                                if (GUILayout.Button(Local["Menu_PortraitList_Btn_CancelPortrait"], _fixedStyle, GUILayout.ExpandWidth(false)))
                                {
                                    _tagData = new TagData(
                                        _tagData.Hash,
                                        _tagData.CustomId,
                                        new List <string>(allPortraitsData[portraitData.CustomId].tags));
                                    modEntry.Logger.Log(string.Join(", ", _tagData.tags.ToArray()));
                                    _tagList = _tagData.tags.ToArray();
                                }
                                if (GUILayout.Button(Local["Menu_PortraitList_Btn_SavePortraitData"], _fixedStyle, GUILayout.ExpandWidth(false)))
                                {
                                    _tagData.SaveData(false);
                                    tagsData[_tagData.CustomId] = new TagData(
                                        _tagData.CustomId,
                                        _tagData.Hash,
                                        new List <string>(_tagData.tags));
                                    allPortraitsData[_tagData.CustomId] = _tagData;
                                    tagListAll = Tags.AllTagsFilter(tagsData);
                                }
                                GUILayout.Label(string.Format(Local["Menu_PortraitList_Lbl_IsCustom"], portraitData.IsCustom));
                                GUILayout.Label(string.Format(Local["Menu_PortraitList_Lbl_PortraitID"], portraitData.CustomId));
                                //Note: hash is calculated only based on the FulLengthPortrait
                                string HashText = string.Format(Local["Menu_PortraitList_Lbl_Hash"], Helpers.GetPseudoHash(portraitData.FullLengthPortrait.texture));
                                if (!tagsData.ContainsKey(portraitData.CustomId))
                                {
                                    GUILayout.Label(HashText);
                                }
                                else
                                if ((_tagData.Hash == tagsData[portraitData.CustomId].Hash))
                                {
                                    GUILayout.Label(HashText);
                                }
                                else
                                {
                                    GUILayout.Label(HashText.Color(RGBA.red));
                                }
                                if (GUILayout.Button(Local["Menu_PortraitList_Btn_OpenFolder"], _fixedStyle, GUILayout.ExpandWidth(false)))
                                {
                                    if (CustomPortraitsManager.Instance == null)
                                    {
                                        return;
                                    }
                                    CustomPortraitsManager.Instance.OpenPortraitFolder(portraitData.CustomId);
                                }
                            }

                            using (new GUILayout.VerticalScope(GUI.skin.box, GUILayout.MinWidth(340f), GUILayout.MinHeight(500f)))
                            {
                                //TODO: all 3 images or only 1? AreaScopes?
                                Texture tex = portraitData.FullLengthPortrait.texture;
                                if (tex)
                                {
                                    GUILayout.Label(Local["Menu_PortraitList_Lbl_PortraitImage"]);
                                    if (Event.current.type == EventType.Repaint && positioningRect.x == 0)
                                    {
                                        positioningRect = GUILayoutUtility.GetLastRect();
                                    }
                                    GUILayout.BeginArea(new Rect(positioningRect.x, positioningRect.yMax, 320f, 473f));
                                    GUILayout.Box(tex);
                                    GUILayout.EndArea();
                                }
                                else
                                {
                                    modEntry.Logger.Error("Error getting portrait texture");
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #4
0
        public void OnGUI(UnityModManager.ModEntry modEntry)
        {
            string defaultHash = Helpers.GetPseudoHash(BlueprintRoot.Instance.CharGen.BasePortraitBig.texture).ToString();

            if (Mod == null || !Mod.Enabled)
            {
                return;
            }
            if (_buttonStyle == null)
            {
                _buttonStyle = new GUIStyle(GUI.skin.button)
                {
                    alignment = TextAnchor.MiddleLeft
                }
            }
            ;
            if (allPortraitTagsData == null)
            {
                allPortraitTagsData = new Dictionary <string, TagData>();
            }
            if (currentPortraitTagsData == null)
            {
                currentPortraitTagsData = new Dictionary <string, TagData>();
            }
            if (importingPortraitTagsData == null)
            {
                importingPortraitTagsData = new Dictionary <string, TagData>();
            }
            if (exportMessage == null)
            {
                exportMessage = "";
            }
            if (importMessage == null)
            {
                importMessage = "";
            }
            GUILayout.Label(Local["Menu_PortraitPacks_Lbl_ExportHeader"]);
            GUILayout.Space(10f);
            using (new GUILayout.HorizontalScope())
            {
                //Exporting portraits
                //TODO: Remove duplicates
                //All portrait data
                using (new GUILayout.VerticalScope(GUILayout.MaxWidth(250), GUILayout.ExpandWidth(false)))
                {
                    GUILayout.Label(Local["Menu_PortraitPacks_Lbl_CurrentData"]);
                    if (GUILayout.Button(Local["Menu_PortraitPacks_Btn_LoadPortraits"], _buttonStyle, GUILayout.ExpandWidth(false)))
                    {
                        allTagDirData       = Tags.LoadTagsData(false);
                        allPortraitTagsData = Helpers.LoadAllPortraitsTags(allTagDirData, true);
                    }
                    if (allPortraitTagsData.Count > 0)
                    {
                        GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsTotal"], allPortraitTagsData.Count()));
                        GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsTagged"], allPortraitTagsData.Where(
                                                          kvp => kvp.Value.tags.Count() > 0).ToList().Count()));
                    }
                }
                //Tag selector
                using (new GUILayout.VerticalScope())
                {
                    GUILayout.Label(Local["Menu_PortraitPacks_Lbl_ExportHint"]);
                    if (allPortraitTagsData.Count > 0)
                    {
                        if (exportTagList == null)
                        {
                            exportTagList = Tags.AllTagsFilter(allPortraitTagsData);
                        }
                        GUILayout.Label(Local["Menu_PortraitList_Lbl_Filters"]);
                        using (new GUILayout.HorizontalScope())
                        {
                            var exportFilterKeys = new List <string>(exportTagList.Keys);
                            foreach (string filterName in exportFilterKeys)
                            {
                                Tags.FilterState FilterValue = exportTagList[filterName];
                                FilterValue               = (Tags.FilterState)UIHelpers.MultiToggle((int)FilterValue, filterName, 2, _fixedStyle);
                                currentPortraitTagsData   = Helpers.FilterPortraitData(filterName, FilterValue, allPortraitTagsData, exportTagList);
                                exportTagList[filterName] = FilterValue;
                            }
                        }
                        if (currentPortraitTagsData != null)
                        {
                            GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsSelected"], currentPortraitTagsData.Count()));
                        }
                    }
                }
                //Exporting
                using (new GUILayout.VerticalScope(GUILayout.MaxWidth(250), GUILayout.ExpandWidth(false)))
                {
                    if (allPortraitTagsData.Count > 0)
                    {
                        if (GUILayout.Button(Local["Menu_PortraitPacks_Btn_Export"], _buttonStyle, GUILayout.ExpandWidth(false)))
                        {
                            if (currentPortraitTagsData != null)
                            {
                                exportMessage = Helpers.ExportPortraits(currentPortraitTagsData);
                            }
                            else
                            {
                                exportMessage = Helpers.ExportPortraits(allPortraitTagsData);
                            }
                        }
                        if (exportMessage != "")
                        {
                            GUILayout.Label(exportMessage);
                        }
                    }
                }
            }
            GUILayout.Space(10f);
            GUILayout.Label(Local["Menu_PortraitPacks_Lbl_ImportHeader"]);
            GUILayout.Space(10f);
            using (new GUILayout.HorizontalScope())
            {
                //Importing portrait pack
                if (allPortraitTagsData.Count > 0)
                {
                    //Loading data from import folder
                    using (new GUILayout.VerticalScope(GUILayout.MaxWidth(250), GUILayout.ExpandWidth(false)))
                    {
                        GUILayout.Label(Local["Menu_PortraitPacks_Lbl_ImportingData"]);
                        if (GUILayout.Button(Local["Menu_PortraitPacks_Btn_LoadPortraitsImport"], _buttonStyle, GUILayout.ExpandWidth(false)))
                        {
                            importingTagsData         = Tags.LoadTagsData(true);
                            importingPortraitTagsData = Helpers.ImportPortraitsTags(importingTagsData, false);
#if (DEBUG)
                            foreach (var kvp in importingPortraitTagsData)
                            {
                                Mod.Log(string.Join(", ", kvp.Key, kvp.Value.Hash, string.Join(",", kvp.Value.tags)));
                            }
#endif
                        }
                        if (importingPortraitTagsData.Count > 0)
                        {
                            GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsTotal"], importingPortraitTagsData.Count()));
                            GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsError"], importingPortraitTagsData.Where(
                                                              kvp => kvp.Value.Hash == defaultHash).Count()));
                            GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsTagged"], importingPortraitTagsData.Where(
                                                              kvp => kvp.Value.tags.Count() > 0).ToList().Count));
                            IEnumerable <string> idDuplicates = allPortraitTagsData.Keys.Intersect(importingPortraitTagsData.Keys);
                            GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsDuplicateHash"],
                                                          Tags.HashDuplicatesTagDictionary(allPortraitTagsData, importingPortraitTagsData)));
                        }
                    }
                    //Tag selector
                    using (new GUILayout.VerticalScope())
                    {
                        GUILayout.Label(Local["Menu_PortraitPacks_Lbl_ImportHint"]);
                        if (importingPortraitTagsData.Count > 0)
                        {
                            if (importTagList == null)
                            {
                                importTagList = Tags.AllTagsFilter(importingPortraitTagsData);
                            }
                            GUILayout.Label(Local["Menu_PortraitList_Lbl_Filters"]);
                            using (new GUILayout.HorizontalScope())
                            {
                                var filterKeys = new List <string>(importTagList.Keys);
                                foreach (string filterName in filterKeys)
                                {
                                    Tags.FilterState FilterValue2 = importTagList[filterName];
                                    FilterValue2 = (Tags.FilterState)UIHelpers.MultiToggle((int)FilterValue2, filterName, 2, _fixedStyle);
                                    importingSelectedTagsData = Helpers.FilterPortraitData(filterName, FilterValue2, importingPortraitTagsData, importTagList);
                                    importTagList[filterName] = FilterValue2;
                                }
                            }
                            if (importingSelectedTagsData != null)
                            {
                                GUILayout.Label(string.Format(Local["Menu_PortraitPacks_Lbl_PortraitsSelected"], importingSelectedTagsData.Count()));
                            }
                        }
                    }
                    //Importing data
                    using (new GUILayout.VerticalScope(GUILayout.MaxWidth(250), GUILayout.ExpandWidth(false)))
                    {
                        GUIHelper.ToggleButton(ref MergeTags, Local["Menu_PortraitPacks_Tgl_MergeTags"]);
                        if (GUILayout.Button(Local["Menu_PortraitPacks_Btn_Import"], _buttonStyle, GUILayout.ExpandWidth(false)))
                        {
                            if (importingSelectedTagsData != null)
                            {
                                if (importingSelectedTagsData.Count > 0)
                                {
                                    importMessage = Helpers.ImportPortraits(allPortraitTagsData, importingSelectedTagsData, MergeTags);
                                }
                                else
                                {
                                    importMessage = Helpers.ImportPortraits(allPortraitTagsData, importingPortraitTagsData, MergeTags);
                                }
                            }
                            PortraitList.Unload();
                        }
                        if (importMessage != "")
                        {
                            GUILayout.Label(importMessage);
                        }
                    }
                }
            }
        }
    }