internal static void MakerSettingChangePreview(ChaControl chaCtrl, AccTriggerInfo Part)
        {
            AccStateSyncController pluginCtrl = GetController(chaCtrl);

            if (MathfEx.RangeEqualOn(0, Part.Kind, 7))
            {
                int  state = chaCtrl.fileStatus.clothesState[Part.Kind];
                bool vis   = Part.State[state];
                Part.Group = "";
                chaCtrl.SetAccessoryState(Part.Slot, vis);
            }
            else if (Part.Kind >= 9)
            {
                if (Part.Kind == 9)
                {
                    List <ChaFileAccessory.PartsInfo> PartsInfo = MoreAccessories_Support.GetAccessoriesInfos(chaCtrl);
                    Part.Group = PartsInfo[Part.Slot].parentKey;
                }
                else
                {
                    Part.Group = "custom_" + (Part.Kind - 9).ToString();
                }

                bool vis = true;
                if (pluginCtrl.VirtualGroupStates.ContainsKey(Part.Group))
                {
                    vis = pluginCtrl.VirtualGroupStates[Part.Group] ? Part.State[0] : Part.State[3];
                }
                chaCtrl.SetAccessoryState(Part.Slot, vis);
            }
        }
        internal static void CreateMakerVirtualGroupToggle(string group)
        {
            Transform origin = GameObject.Find("tglSlot01/Slot01Top/tglNoShake").transform;
            Transform copy   = Object.Instantiate(origin, GameObject.Find("04_AccessoryTop/AcsMoveWindow01/grpParent").transform, false);

            copy.GetComponentInChildren <TextMeshProUGUI>().text = (AccParentNames.ContainsKey(group)) ? AccParentNames[group] : group;

            RectTransform copyRt = copy.GetComponent <RectTransform>();

            copyRt.offsetMin      = new Vector2(0, AnchorOffsetMinY);
            copyRt.offsetMax      = new Vector2(0, AnchorOffsetMinY + 40);
            copyRt.transform.name = "tglASS_" + group;

            Toggle toggle = copy.GetComponentInChildren <Toggle>();

            toggle.onValueChanged.RemoveAllListeners();
            toggle.image.raycastTarget   = true;
            toggle.graphic.raycastTarget = true;

            ChaControl             chaCtrl    = MakerAPI.GetCharacterControl();
            AccStateSyncController pluginCtrl = GetController(chaCtrl);

            pluginCtrl.VirtualGroupNames.Add("tglASS_" + group);
            toggle.isOn = pluginCtrl.VirtualGroupStates[group];

            toggle.onValueChanged.AddListener(_ =>
            {
                bool show = toggle.isOn;
                pluginCtrl.ToggleByVirtualGroup(group, show);
            });

            copy.gameObject.SetActive(true);
            AnchorOffsetMinY -= 40;
        }
Beispiel #3
0
 internal static void RegisterEvents()
 {
     JetPack.CharaHscene.OnHSceneFinishedLoading += (_sender, _args) =>
     {
         ClearUI();
         UpdateUI();
     };
     JetPack.CharaHscene.OnHSceneSetClothStateStartMotion += (_sender, _args) =>
     {
         foreach (ChaControl _chaCtrl in _args.Female)
         {
             DebugMsg(LogLevel.Info, $"[OnHSceneSetClothStateStartMotion][{_chaCtrl.GetFullName()}]");
             AccStateSyncController _pluginCtrl = GetController(_chaCtrl);
             if (_pluginCtrl != null)
             {
                 foreach (TriggerGroup _group in _pluginCtrl.TriggerGroupList)
                 {
                     _group.State = (_group.Secondary > -1) ? _group.Secondary : _group.Startup;
                 }
                 _pluginCtrl.RefreshCache();
                 _pluginCtrl.SyncAllAccToggle("OnHSceneSetClothStateStartMotion");
             }
         }
     };
 }
Beispiel #4
0
            internal static void UpdateUI()
            {
                if (!JetPack.CharaHscene.Loaded)
                {
                    return;
                }
                DebugMsg(LogLevel.Info, $"[UpdateUI] Fired!!");

                ContainerOffsetMinY   = -144;
                MenuitemHeightOffsetY = -24;

                int i = 0, _counter = 0;

                foreach (ChaControl _chaCtrl in JetPack.CharaHscene.Heroine)
                {
                    AccStateSyncController _pluginCtrl = GetController(_chaCtrl);
                    if (_pluginCtrl != null)
                    {
                        _pluginCtrl.RefreshCache();
                        if (_pluginCtrl._cachedCoordinateGroupList.Count > 0)
                        {
                            foreach (TriggerGroup _group in _pluginCtrl._cachedCoordinateGroupList)
                            {
                                if (_pluginCtrl._cachedCoordinateGroupPropertyList.Where(x => x.RefKind == _group.Kind).Count() > 0)
                                {
                                    CreateButton(_chaCtrl, _counter, i, _group);
                                    i++;
                                }
                            }
                            i = 0;
                        }
                    }
                    _counter++;
                }
            }
Beispiel #5
0
                internal static void SetAccessoryStateAll(ChaControl _chaCtrl, bool _show)
                {
                    int _currentCoordinateIndex = _chaCtrl.fileStatus.coordinateType;
                    List <ChaFileAccessory.PartsInfo> _partsInfo = _chaCtrl.ListPartsInfo(_currentCoordinateIndex);

                    AccStateSyncController _pluginCtrl = GetController(_chaCtrl);

                    if (_pluginCtrl == null)
                    {
                        for (int _slotIndex = 0; _slotIndex < _partsInfo.Count; _slotIndex++)
                        {
                            _chaCtrl.SetAccessoryState(_slotIndex, _show);
                        }
                        return;
                    }

                    HashSet <int> _triggers = new HashSet <int>(_pluginCtrl.TriggerPropertyList.Where(x => x.Coordinate == _currentCoordinateIndex).Select(x => x.Slot));

                    for (int _slotIndex = 0; _slotIndex < _partsInfo.Count; _slotIndex++)
                    {
                        if (_triggers.Contains(_slotIndex))
                        {
                            continue;
                        }
                        _chaCtrl.SetAccessoryState(_slotIndex, _show);
                    }
                }
Beispiel #6
0
            private static void ChaControl_ChangeCoordinateType_Postfix(ChaControl __instance)
            {
                AccStateSyncController _pluginCtrl = GetController(__instance);

                if (_pluginCtrl != null)
                {
                    _pluginCtrl.InitCurOutfitTriggerInfo("ChaControl_ChangeCoordinateType_Postfix");
                }
            }
Beispiel #7
0
            internal static void ChaControl_SetClothesState_Postfix(ChaControl __instance, int clothesKind)
            {
                AccStateSyncController _pluginCtrl = GetController(__instance);

                if (_pluginCtrl != null)
                {
                    _pluginCtrl.ToggleByRefKind(clothesKind);
                }
            }
Beispiel #8
0
            private static void OCIChar_ChangeChara_Prefix(OCIChar __instance, string _path)
            {
                AccStateSyncController _pluginCtrl = GetController(__instance?.charInfo);

                if (_pluginCtrl != null)
                {
                    _pluginCtrl.TriggerEnabled = false;
                }
            }
            internal static void SetClothesStatePostfix(ChaControl __instance, int clothesKind)
            {
                AccStateSyncController controller = GetController(__instance);

                if (controller != null)
                {
                    int state = __instance.fileStatus.clothesState[clothesKind];
                    controller.ToggleByClothesState(__instance, clothesKind, state);
                }
            }
            internal static void SetAccessoryStateCategoryPostfix(ChaControl __instance, int cateNo, bool show)
            {
                AccStateSyncController controller = GetController(__instance);

                if (controller != null)
                {
                    if (controller.CoroutineCounter <= CoroutineCounterMax.Value)
                    {
                        controller.CoroutineCounter++;
                    }
                }
            }
 internal static void SetClothStateStartMotionPostfix(HSceneProc __instance)
 {
     foreach (var heroine in __instance.flags.lstHeroine)
     {
         ChaControl chaCtrl = heroine.chaCtrl;
         Logger.Log(DebugLogLevel, $"[Harmony][HSceneProc][SetClothStateStartMotion][Postfix][{chaCtrl.chaFile.parameter?.fullname}]");
         AccStateSyncController controller = GetController(chaCtrl);
         if (controller != null)
         {
             controller.SyncAllAccToggle();
         }
     }
 }
Beispiel #12
0
            private static void ChaControl_ChangeCoordinateType_Prefix(ChaControl __instance)
            {
                if (!JetPack.CharaMaker.Inside)
                {
                    return;
                }

                AccStateSyncController _pluginCtrl = GetController(__instance);

                if (_pluginCtrl != null)
                {
                    _pluginCtrl._duringLoadChange = true;
                }
            }
Beispiel #13
0
            internal static void ChaFileStatus_ShoesType_Postfix(ChaFileStatus __instance)
            {
                ChaControl _chaCtrl = FindObjectsOfType <ChaControl>().Where(x => x?.chaFile?.status == __instance).FirstOrDefault();

                if (_chaCtrl != null)
                {
                    AccStateSyncController _pluginCtrl = GetController(_chaCtrl);
                    if (_pluginCtrl != null)
                    {
                        int clothesKind = __instance.shoesType == 0 ? 7 : 8;
                        _pluginCtrl.ToggleByRefKind(clothesKind);
                    }
                }
            }
Beispiel #14
0
            internal static void UpdateUI()
            {
                if ((_curOCIChar == null) || (_curOCIChar.charInfo == null))
                {
                    return;
                }
                AccStateSyncController _pluginCtrl = GetController(_curOCIChar);

                if (_pluginCtrl == null)
                {
                    return;
                }

                _pluginCtrl._treeNodeObjID = _curTreeNodeObjID;
            }
Beispiel #15
0
            internal static IEnumerator StatusPanelUpdateCoroutine()
            {
                yield return(JetPack.Toolbox.WaitForEndOfFrame);

                yield return(JetPack.Toolbox.WaitForEndOfFrame);

                AccStateSyncController _pluginCtrl = GetController(_curOCIChar);

                if (_pluginCtrl != null && _pluginCtrl.TriggerEnabled)
                {
                    if (JetPack.CharaStudio.RefreshCharaStatePanel())
                    {
                        MoreAccessories.UpdateUI();
                    }
                }
            }
Beispiel #16
0
        internal static void CreateStudioUIToggle(string name, int i, bool show)
        {
            Toggle tglNew = Instantiate(GetPanelObject <Toggle>("Toggle Function"), ASSPanel.transform);

            tglNew.name = name;
            tglNew.isOn = show;
            tglNew.transform.localPosition = new Vector3(tglNew.transform.localPosition.x - 75, ContainerOffsetMinY + (MenuitemHeightOffsetY * i), tglNew.transform.localPosition.z);
            tglNew.onValueChanged.RemoveAllListeners();
            tglNew.onValueChanged.AddListener(delegate(bool value)
            {
                AccStateSyncController controller = CurOCIChar.charInfo.GetComponent <AccStateSyncController>();
                if (controller == null)
                {
                    return;
                }
                controller.ToggleByVirtualGroup(name, value);
            });
        }
Beispiel #17
0
            internal static void CreateButton(ChaControl _chaCtrl, int _counter, int i, TriggerGroup _group)
            {
                foreach (HSprite _sprite in JetPack.CharaHscene.Sprites)
                {
                    Transform _parent;
                    if (JetPack.CharaHscene.Heroine.Count > 1)
                    {
                        _parent = _sprite.lstMultipleFemaleDressButton[_counter].accessoryAll.transform;
                    }
                    else
                    {
                        _parent = _sprite.categoryAccessoryAll.transform;
                    }

                    Transform _origin = _sprite.categoryAccessory.lstButton[0].transform;
                    Transform _copy   = Instantiate(_origin.transform, _parent, false);
                    _copy.name = $"btnASS_{_counter}_{_group.Kind}";

                    AccStateSyncController _pluginCtrl = GetController(_chaCtrl);
                    _copy.GetComponentInChildren <TextMeshProUGUI>().text = _group.Label;

                    RectTransform _copyRt = _copy.GetComponent <RectTransform>();
                    _copyRt.offsetMin = new Vector2(0, ContainerOffsetMinY + (MenuitemHeightOffsetY * (i + 1)));                 // -168
                    _copyRt.offsetMax = new Vector2(112, ContainerOffsetMinY + (MenuitemHeightOffsetY * i));                     // -144

                    Button _button = _copy.GetComponentInChildren <Button>();
                    for (int n = 0; n < _button.onClick.GetPersistentEventCount(); n++)
                    {
                        _button.onClick.SetPersistentListenerState(n, UnityEventCallState.Off);
                    }
                    _button.onClick.RemoveAllListeners();
                    _button.onClick             = new Button.ButtonClickedEvent();
                    _button.image.raycastTarget = true;

                    _button.onClick.AddListener(delegate()
                    {
                        _pluginCtrl.SetGroupStateNext(_group.Kind);
                        Illusion.Game.Utils.Sound.Play(Illusion.Game.SystemSE.sel);
                    });

                    _copy.gameObject.SetActiveIfDifferent(true);
                }
            }
        internal static void CreateFreeHbutton(ChaControl chaCtrl, int Heroine, string group, int i)
        {
            foreach (HSprite sprite in HSprites)
            {
                Transform parent;
                if (HSceneHeroine.Count() == 2)
                {
                    parent = (Heroine == 0) ? sprite.lstMultipleFemaleDressButton[0].accessoryAll.transform : sprite.lstMultipleFemaleDressButton[1].accessoryAll.transform;
                }
                else
                {
                    parent = sprite.categoryAccessoryAll.transform;
                }

                Transform origin = sprite.categoryAccessory.lstButton[0].transform;
                Transform copy   = Object.Instantiate(origin.transform, parent, false);
                copy.GetComponentInChildren <TextMeshProUGUI>().text = (AccParentNames.ContainsKey(group)) ? AccParentNames[group] : group;

                RectTransform copyRt = copy.GetComponent <RectTransform>();
                copyRt.offsetMin      = new Vector2(0, ContainerOffsetMinY + (MenuitemHeightOffsetY * (i + 1)));        // -168
                copyRt.offsetMax      = new Vector2(112, ContainerOffsetMinY + (MenuitemHeightOffsetY * i));            // -144
                copyRt.transform.name = $"btnASS_{Heroine}_{group}";

                Button button = copy.GetComponentInChildren <Button>();
                button.onClick.SetPersistentListenerState(0, UnityEngine.Events.UnityEventCallState.Off);
                button.onClick.RemoveAllListeners();
                button.onClick             = new Button.ButtonClickedEvent();
                button.image.raycastTarget = true;

                button.onClick.AddListener(() =>
                {
                    AccStateSyncController pluginCtrl = GetController(chaCtrl);
                    bool show = !pluginCtrl.VirtualGroupStates[group];
                    pluginCtrl.ToggleByVirtualGroup(group, show);
                    Illusion.Game.Utils.Sound.Play(Illusion.Game.SystemSE.sel);
                });

                copy.gameObject.SetActive(true);
            }
        }
Beispiel #19
0
        internal static void UpdateStudioUI()
        {
            ClearStudioUI();

            AccStateSyncController controller = CurOCIChar.charInfo.GetComponent <AccStateSyncController>();

            if (controller == null)
            {
                return;
            }

            int i = 0;
            Dictionary <string, bool> VirtualGroupStates = controller.VirtualGroupStates;

            foreach (KeyValuePair <string, bool> group in VirtualGroupStates)
            {
                string label = (AccParentNames.ContainsKey(group.Key)) ? AccParentNames[group.Key] : group.Key;
                CreateStudioUIText(group.Key, i, label);
                CreateStudioUIToggle(group.Key, i, group.Value);
                i++;
            }
        }
        internal static void UpdateHUI()
        {
            if (!InsideHScene)
            {
                return;
            }
            Logger.Log(DebugLogLevel, $"[UpdateHUI] Fired!!");

            ContainerOffsetMinY   = -144;
            MenuitemHeightOffsetY = -24;

            foreach (HSprite sprite in HSprites)
            {
                if (HSceneHeroine.Count() == 2)
                {
                    ClearFreeHbutton(sprite.lstMultipleFemaleDressButton[0].accessoryAll.gameObject);
                    ClearFreeHbutton(sprite.lstMultipleFemaleDressButton[1].accessoryAll.gameObject);
                }
                else
                {
                    ClearFreeHbutton(sprite.categoryAccessoryAll.gameObject);
                }
            }

            int i = 0, Heroine = 0;

            foreach (ChaControl chaCtrl in HSceneHeroine)
            {
                AccStateSyncController controller = GetController(chaCtrl);
                foreach (KeyValuePair <string, bool> group in controller.VirtualGroupStates)
                {
                    CreateFreeHbutton(chaCtrl, Heroine, group.Key, i);
                    i++;
                }
                i = 0;
                Heroine++;
            }
        }
        internal static void CreateMakerStateToggle(int i)
        {
            Transform origin = GameObject.Find("tglSlot01/Slot01Top/tglNoShake").transform;
            Transform copy   = Object.Instantiate(origin, GameObject.Find("04_AccessoryTop/AcsMoveWindow01/grpParent").transform, false);

            copy.GetComponentInChildren <TextMeshProUGUI>().text = clothesStateText[i];

            RectTransform copyRt = copy.GetComponent <RectTransform>();

            copyRt.offsetMin      = new Vector2(i * 100, AnchorOffsetMinY);
            copyRt.offsetMax      = new Vector2(i * 100, AnchorOffsetMinY + 40);
            copyRt.transform.name = "tglASS" + i;

            Toggle toggle = copy.GetComponentInChildren <Toggle>();

            toggle.onValueChanged.RemoveAllListeners();
            toggle.image.raycastTarget   = true;
            toggle.graphic.raycastTarget = true;
            toggle.isOn = clothesStates[0][i];

            toggle.onValueChanged.AddListener(_ =>
            {
                ChaControl chaCtrl = MakerAPI.GetCharacterControl();
                AccStateSyncController pluginCtrl = GetController(chaCtrl);
                AccTriggerInfo Part = pluginCtrl.CurSlotTriggerInfo;
                if (Part == null)
                {
                    Logger.LogError($"[btnASSsave][{chaCtrl.chaFile.parameter?.fullname}] CurSlotTriggerInfo is Null");
                    return;
                }

                Part.State[i] = toggle.isOn;
                MakerSettingChangePreview(chaCtrl, Part);
                Logger.Log(DebugLogLevel, $"[tglASS{i}][{chaCtrl.chaFile.parameter?.fullname}][Slot: {Part.Slot}][Kind: {Part.Kind}][State: {Part.State[0]}|{Part.State[1]}|{Part.State[2]}|{Part.State[3]}]");
            });

            copy.gameObject.SetActive(true);
        }
        internal static void CreateMakerDropdownItems(List <string> labels)
        {
            Transform copy = GameObject.Find("ddASSList").transform;

            copy.gameObject.SetActive(false);
            TMP_Dropdown dropdown = copy.GetComponentInChildren <TMP_Dropdown>();

            dropdown.onValueChanged.RemoveAllListeners();
            dropdown.ClearOptions();
            dropdown.GetComponent <Image>().raycastTarget = true;
            dropdown.options.AddRange(ddASSListLabels.Select(x => new TMP_Dropdown.OptionData(x)));
            dropdown.options.AddRange(labels.Select(x => new TMP_Dropdown.OptionData(x)));
            dropdown.value = 0;
            dropdown.onValueChanged.AddListener(_ =>
            {
                ChaControl chaCtrl = MakerAPI.GetCharacterControl();
                AccStateSyncController pluginCtrl = GetController(chaCtrl);
                AccTriggerInfo Part = pluginCtrl.CurSlotTriggerInfo;
                if (Part == null)
                {
                    Logger.LogError($"[ddASSList][{chaCtrl.chaFile.parameter?.fullname}] AccessoriesApi.SelectedMakerAccSlot {AccessoriesApi.SelectedMakerAccSlot} out of range!!");
                    return;
                }

                int refIndex = dropdown.value < 10 ? dropdown.value : 9;
                GameObject.Find("tglASS0").GetComponentInChildren <TextMeshProUGUI>().alpha = clothesStates[refIndex][0] ? 1f : 0.2f;
                GameObject.Find("tglASS1").GetComponentInChildren <TextMeshProUGUI>().alpha = clothesStates[refIndex][1] ? 1f : 0.2f;
                GameObject.Find("tglASS2").GetComponentInChildren <TextMeshProUGUI>().alpha = clothesStates[refIndex][2] ? 1f : 0.2f;
                GameObject.Find("tglASS3").GetComponentInChildren <TextMeshProUGUI>().alpha = clothesStates[refIndex][3] ? 1f : 0.2f;
                Part.Kind = dropdown.value < 10 ? ddASSListVals[dropdown.value] : dropdown.value;

                MakerSettingChangePreview(chaCtrl, Part);
                Logger.Log(DebugLogLevel, $"[ddASSList][{chaCtrl.chaFile.parameter?.fullname}][Slot: {Part.Slot}][Kind: {Part.Kind}][State: {Part.State[0]}|{Part.State[1]}|{Part.State[2]}|{Part.State[3]}]");
            });
            copy.gameObject.SetActive(true);
        }
        internal static void CreateMakerInterface()
        {
            GameObject accw = GameObject.Find("04_AccessoryTop/AcsMoveWindow01");

            RectTransform windRt = accw.transform.Find("BasePanel/imgWindowBack").GetComponent <RectTransform>();

            ContainerOffsetMinY = (int)windRt.offsetMin.y - 90;              // -90
            windRt.offsetMin    = new Vector2(0, ContainerOffsetMinY);

            Transform toggleParent = accw.transform.Find("grpParent");

            Transform     button   = accw.transform.Find("button");
            RectTransform buttonRt = button.GetComponent <RectTransform>();

            AnchorOffsetMinY = (int)buttonRt.offsetMin.y;

// sep
            AnchorOffsetMinY += 40;
            Transform     sep   = Object.Instantiate(accw.transform.Find("grpParent/imgSeparete"), toggleParent, false);
            RectTransform sepRt = sep.GetComponent <RectTransform>();

            sepRt.offsetMin      = new Vector2(0, AnchorOffsetMinY);        // -408
            sepRt.offsetMax      = new Vector2(0, AnchorOffsetMinY + 4);    // -404
            sepRt.transform.name = "imgSeparete";
            sep.gameObject.SetActive(true);

// state toggles
            AnchorOffsetMinY -= 40;
            for (int i = 0; i < 4; i++)
            {
                CreateMakerStateToggle(i);
            }

// dropdown
            AnchorOffsetMinY -= 40;
            CreateMakerDropdown();

// save button
            AnchorOffsetMinY -= 40;
            Transform btnSave = Object.Instantiate(accw.transform.Find("grpParent/grpMove/X/btnReset"), toggleParent, true);

            btnSave.GetComponentInChildren <TextMeshProUGUI>().text = "Save";
            RectTransform dropdownRt = GameObject.Find("ddASSList").GetComponent <RectTransform>();
            RectTransform btnSaveRt  = btnSave.GetComponent <RectTransform>();

            btnSaveRt.offsetMin      = new Vector2(btnSaveRt.offsetMin.x, dropdownRt.offsetMin.y + 412);        // -76
            btnSaveRt.offsetMax      = new Vector2(btnSaveRt.offsetMax.x, dropdownRt.offsetMin.y + 412 - 380);  // -456
            btnSaveRt.transform.name = "btnASSsave";
            Button btnSaveButton = btnSave.GetComponentInChildren <Button>();

            btnSaveButton.onClick.RemoveAllListeners();
            btnSaveButton.targetGraphic.raycastTarget = true;
            btnSaveButton.onClick.AddListener(() =>
            {
                ChaControl chaCtrl = MakerAPI.GetCharacterControl();
                AccStateSyncController pluginCtrl = GetController(chaCtrl);

                if (pluginCtrl.CurSlotTriggerInfo == null)
                {
                    Logger.LogError($"[btnASSsave][{chaCtrl.chaFile.parameter?.fullname}] CurSlotTriggerInfo is Null");
                    return;
                }

                int SlotNo = pluginCtrl.CurSlotTriggerInfo.Slot;
                pluginCtrl.CopySlotTriggerInfo(pluginCtrl.CurSlotTriggerInfo, pluginCtrl.CurOutfitTriggerInfo.Parts[SlotNo]);

                if ((pluginCtrl.CurSlotTriggerInfo.Kind >= 9) && (!pluginCtrl.CurSlotTriggerInfo.Group.IsNullOrEmpty()))
                {
                    if (!pluginCtrl.VirtualGroupStates.ContainsKey(pluginCtrl.CurSlotTriggerInfo.Group))
                    {
                        pluginCtrl.VirtualGroupStates[pluginCtrl.CurSlotTriggerInfo.Group] = true;
                    }
                }

                Logger.LogMessage($"SlotNo: {SlotNo + 1:00} updated");
            });
            btnSave.gameObject.SetActive(true);
        }