/// <summary>
        /// The event handler for the tree view item selection changed
        /// </summary>
        private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e)
        {
            TextureMapComboBox.Items.Clear();
            ModelTypeComboBox.Items.Clear();
            MaterialComboBox.Items.Clear();
            CustomTextureTextBox.Text = string.Empty;
            CustomModelTextBox.Text   = string.Empty;

            var selectedItem = e.NewValue as Category;

            var modList = JsonConvert.DeserializeObject <ModList>(File.ReadAllText(_modListDirectory.FullName));

            var modItems =
                from mod in modList.Mods
                where mod.name.Equals(selectedItem.Name)
                select mod;

            foreach (var modItem in modItems)
            {
                var itemPath = modItem.fullPath;
                var modCB    = new ModComboBox();
                var ttp      = new TexTypePath
                {
                    Path     = itemPath,
                    DataFile = XivDataFiles.GetXivDataFile(modItem.datFile)
                };

                // Textures
                if (itemPath.Contains("_d."))
                {
                    modCB.Name        = $"{XivTexType.Diffuse} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Diffuse;
                }
                else if (itemPath.Contains("_n."))
                {
                    modCB.Name        = $"{XivTexType.Normal} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Normal;
                }
                else if (itemPath.Contains("_s."))
                {
                    modCB.Name        = $"{XivTexType.Specular} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Specular;
                }
                else if (itemPath.Contains("_m."))
                {
                    modCB.Name        = $"{XivTexType.Multi} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Multi;
                }
                else if (itemPath.Contains("material"))
                {
                    modCB.Name        = $"{XivTexType.ColorSet} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.ColorSet;
                }
                else if (itemPath.Contains("decal"))
                {
                    modCB.Name        = $"{XivTexType.Mask} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Mask;
                }
                else if (itemPath.Contains("vfx"))
                {
                    modCB.Name        = $"{XivTexType.Vfx} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Vfx;
                }
                else if (itemPath.Contains("ui/"))
                {
                    if (itemPath.Contains("icon"))
                    {
                        modCB.Name        = $"{XivTexType.Icon} ({Path.GetFileNameWithoutExtension(itemPath)})";
                        modCB.SelectedMod = modItem;
                        ttp.Type          = XivTexType.Icon;
                    }
                    else if (itemPath.Contains("map"))
                    {
                        modCB.Name        = $"{XivTexType.Map} ({Path.GetFileNameWithoutExtension(itemPath)})";
                        modCB.SelectedMod = modItem;
                        ttp.Type          = XivTexType.Map;
                    }
                    else
                    {
                        modCB.Name        = $"UI ({Path.GetFileNameWithoutExtension(itemPath)})";
                        modCB.SelectedMod = modItem;
                        ttp.Type          = XivTexType.Other;
                    }
                }

                if (modCB.Name != null)
                {
                    modCB.TexTypePath = ttp;
                    TextureMapComboBox.Items.Add(modCB);
                }

                // Models
                if (itemPath.Contains(".mdl"))
                {
                    modCB.Name        = $"{((IItemModel)selectedItem.Item).ModelInfo.ModelID} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    modCB.TexTypePath = null;

                    ModelTypeComboBox.Items.Add(modCB);
                }

                // Material
                if (itemPath.Contains(".mtrl"))
                {
                    modCB.Name        = $"Material ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    modCB.TexTypePath = null;

                    MaterialComboBox.Items.Add(modCB);
                    MaterialTabItem.IsEnabled = true;
                }
            }

            if (TextureMapComboBox.Items.Count > 0)
            {
                AddCurrentTextureButton.IsEnabled = true;
                GetCustomTextureButton.IsEnabled  = true;
                CustomTextureTextBox.IsEnabled    = true;
                AddCustomTextureButton.IsEnabled  = false;
                TextureMapComboBox.SelectedIndex  = 0;
                NoTextureModsLabel.Content        = string.Empty;
            }
            else
            {
                AddCurrentTextureButton.IsEnabled = false;
                GetCustomTextureButton.IsEnabled  = false;
                CustomTextureTextBox.IsEnabled    = false;
                AddCustomTextureButton.IsEnabled  = false;
                NoTextureModsLabel.Content        = "There are no Texture mods present.\n\nIf you would like to enable this, first import a texture for the selected item.";
            }

            if (ModelTypeComboBox.Items.Count > 0)
            {
                AddCurrentModelButton.IsEnabled = true;
                GetCustomModelButton.IsEnabled  = true;
                CustomModelTextBox.IsEnabled    = true;
                AdvOptionsButton.IsEnabled      = true;
                AddCustomModelButton.IsEnabled  = false;
                ModelTypeComboBox.SelectedIndex = 0;
                NoModelModsLabel.Content        = string.Empty;
            }
            else
            {
                AddCurrentModelButton.IsEnabled = false;
                GetCustomModelButton.IsEnabled  = false;
                CustomModelTextBox.IsEnabled    = false;
                AdvOptionsButton.IsEnabled      = false;
                AddCustomModelButton.IsEnabled  = false;
                NoModelModsLabel.Content        = "There are no 3D Model mods present.\n\nIf you would like to enable this, first import a model for the selected item.";
            }

            if (MaterialComboBox.Items.Count > 0)
            {
                AddCurrentMaterialButton.IsEnabled = true;
                MaterialComboBox.SelectedIndex     = 0;
                NoMaterialsModsLabel.Content       = string.Empty;
            }
            else
            {
                AddCurrentMaterialButton.IsEnabled = false;
                NoMaterialsModsLabel.Content       = "There are no Material mods present.\n\nIf you would like to enable this, first import a Material for the selected item.";
            }

            SelectModGroup.IsEnabled = true;
        }
        /// <summary>
        /// The event handler for the tree view item selection changed
        /// </summary>
        private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e)
        {
            var selectedItem = e.NewValue as Category;

            if (selectedItem == null || selectedItem.Item == null)
            {
                return;
            }

            TextureMapComboBox.Items.Clear();
            ModelTypeComboBox.Items.Clear();
            MaterialComboBox.Items.Clear();
            CustomTextureTextBox.Text = string.Empty;


            var modding = new Modding(_gameDirectory);
            var modList = modding.GetModList();

            var modItems =
                from mod in modList.Mods
                where mod.name.Equals(selectedItem.Name)
                select mod;

            foreach (var modItem in modItems)
            {
                var itemPath = modItem.fullPath;
                var modCB    = new ModComboBox();
                var ttp      = new TexTypePath
                {
                    Path     = itemPath,
                    DataFile = XivDataFiles.GetXivDataFile(modItem.datFile)
                };

                // Textures
                if (itemPath.Contains("_d."))
                {
                    modCB.Name        = $"{XivTexType.Diffuse} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Diffuse;
                }
                else if (itemPath.Contains("_n."))
                {
                    modCB.Name        = $"{XivTexType.Normal} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Normal;
                }
                else if (itemPath.Contains("_s."))
                {
                    modCB.Name        = $"{XivTexType.Specular} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Specular;
                }
                else if (itemPath.Contains("_m."))
                {
                    modCB.Name        = $"{XivTexType.Multi} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Multi;
                }
                else if (itemPath.Contains("material"))
                {
                    modCB.Name        = $"{XivTexType.ColorSet} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.ColorSet;
                }
                else if (itemPath.Contains("decal"))
                {
                    modCB.Name        = $"{XivTexType.Mask} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Mask;
                }
                else if (itemPath.Contains("vfx"))
                {
                    modCB.Name        = $"{XivTexType.Vfx} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Vfx;
                }
                else if (itemPath.Contains("ui/"))
                {
                    if (itemPath.Contains("icon"))
                    {
                        modCB.Name        = $"{XivTexType.Icon} ({Path.GetFileNameWithoutExtension(itemPath)})";
                        modCB.SelectedMod = modItem;
                        ttp.Type          = XivTexType.Icon;
                    }
                    else if (itemPath.Contains("map"))
                    {
                        modCB.Name        = $"{XivTexType.Map} ({Path.GetFileNameWithoutExtension(itemPath)})";
                        modCB.SelectedMod = modItem;
                        ttp.Type          = XivTexType.Map;
                    }
                    else
                    {
                        modCB.Name        = $"UI ({Path.GetFileNameWithoutExtension(itemPath)})";
                        modCB.SelectedMod = modItem;
                        ttp.Type          = XivTexType.Other;
                    }
                }
                else if (itemPath.Contains(".tex"))
                {
                    modCB.Name        = $"{XivTexType.Other} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    modCB.SelectedMod = modItem;
                    ttp.Type          = XivTexType.Other;
                }

                if (modCB.Name != null)
                {
                    modCB.TexTypePath = ttp;
                    TextureMapComboBox.Items.Add(modCB);
                }

                // Models
                if (itemPath.Contains(".mdl"))
                {
                    //esrinzou for Repair program crash when selecting [character/Body] item
                    //modCB.Name = $"{((IItemModel)selectedItem.Item).ModelInfo.ModelID} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    //esrinzou begin
                    if (((IItemModel)selectedItem.Item).ModelInfo == null)
                    {
                        modCB.Name = $"{((IItemModel)selectedItem.Item).Name} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    }
                    else
                    {
                        var modelId = ((IItemModel)selectedItem.Item).ModelInfo.PrimaryID;

                        if (selectedItem.Item.PrimaryCategory.Equals(XivStrings.Character))
                        {
                            var item = selectedItem.Item;

                            if (item.Name.Equals(XivStrings.Body))
                            {
                                modelId = int.Parse(
                                    itemPath.Substring(itemPath.IndexOf("/body", StringComparison.Ordinal) + 7, 4));
                            }
                            else if (item.Name.Equals(XivStrings.Hair))
                            {
                                modelId = int.Parse(
                                    itemPath.Substring(itemPath.IndexOf("/hair", StringComparison.Ordinal) + 7, 4));
                            }
                            else if (item.Name.Equals(XivStrings.Face))
                            {
                                modelId = int.Parse(
                                    itemPath.Substring(itemPath.IndexOf("/face", StringComparison.Ordinal) + 7, 4));
                            }
                            else if (item.Name.Equals(XivStrings.Tail))
                            {
                                modelId = int.Parse(
                                    itemPath.Substring(itemPath.IndexOf("/tail", StringComparison.Ordinal) + 7, 4));
                            }
                        }

                        modCB.Name = $"{modelId} ({Path.GetFileNameWithoutExtension(itemPath)})";
                    }
                    //esrinzou end
                    modCB.SelectedMod = modItem;
                    modCB.TexTypePath = null;

                    ModelTypeComboBox.Items.Add(modCB);
                }

                // Material
                if (itemPath.Contains(".mtrl"))
                {
                    var materialModCB = new ModComboBox
                    {
                        Name        = $"Material ({Path.GetFileNameWithoutExtension(itemPath)})",
                        SelectedMod = modItem,
                        TexTypePath = null
                    };

                    MaterialComboBox.Items.Add(materialModCB);
                    MaterialTabItem.IsEnabled = true;
                }
            }

            if (TextureMapComboBox.Items.Count > 0)
            {
                AddCurrentTextureButton.IsEnabled = true;
                GetCustomTextureButton.IsEnabled  = true;
                CustomTextureTextBox.IsEnabled    = true;
                AddCustomTextureButton.IsEnabled  = false;
                TextureMapComboBox.SelectedIndex  = 0;
                NoTextureModsLabel.Content        = string.Empty;
            }
            else
            {
                AddCurrentTextureButton.IsEnabled = false;
                GetCustomTextureButton.IsEnabled  = false;
                CustomTextureTextBox.IsEnabled    = false;
                AddCustomTextureButton.IsEnabled  = false;
                NoTextureModsLabel.Content        = UIStrings.No_Texture_Mods;
            }

            if (ModelTypeComboBox.Items.Count > 0)
            {
                AddCurrentModelButton.IsEnabled = true;
                AdvOptionsButton.IsEnabled      = true;
                ModelTypeComboBox.SelectedIndex = 0;
                NoModelModsLabel.Content        = string.Empty;
            }
            else
            {
                AddCurrentModelButton.IsEnabled = false;
                AdvOptionsButton.IsEnabled      = false;
                NoModelModsLabel.Content        = UIStrings.No_3D_Mods;
            }

            if (MaterialComboBox.Items.Count > 0)
            {
                AddCurrentMaterialButton.IsEnabled = true;
                MaterialComboBox.SelectedIndex     = 0;
                NoMaterialsModsLabel.Content       = string.Empty;
            }
            else
            {
                AddCurrentMaterialButton.IsEnabled = false;
                NoMaterialsModsLabel.Content       = UIStrings.No_Material_Mods;
            }

            SelectModGroup.IsEnabled = true;
        }
Ejemplo n.º 3
0
        public MainForm()
        {
            // Create form controls
            InitializeComponent();

            // Set instance
            Instance = this;

            // Make sure the basic configuration settings are setup by the user,
            // and load the BF2 server and installed mods
            if (!SetupManager.Run())
            {
                this.Load += (s, e) => this.Close();
                return;
            }

            // Load Bf2 mods
            LoadModList();

            // Load client settings
            ClientSettings.Load();
            ReloadProviders();
            ReloadServers();

            // Setup theme
            metroStyleManager1.Theme = MetroThemeStyle.Light;
            metroStyleManager1.Style = MetroColorStyle.Blue;

            // Set default texts
            InstallDirTextbox.Text = Program.Config.Bf2InstallDir;

            // Load Redirector
            bool AllSystemsGo = Redirector.Initialize();

            // Select provider if we have redirects detected
            if (Redirector.RedirectsEnabled)
            {
                ServiceProvider Provider;
                if (String.IsNullOrEmpty(Program.Config.LastUsedProvider))
                {
                    Provider = ClientSettings.ServiceProviders
                               .Where(x => x.StatsAddress == Redirector.StatsServerAddress.ToString() &&
                                      x.GamespyAddress == Redirector.GamespyServerAddress.ToString())
                               .FirstOrDefault();
                }
                else
                {
                    Provider = ClientSettings.ServiceProviders
                               .Where(x => x.Name == Program.Config.LastUsedProvider)
                               .FirstOrDefault();
                }

                // Set the last used provider if we have one
                if (Provider != null)
                {
                    ProviderComboBox.SelectedItem = Provider;
                }
            }

            // Set redirect mode
            IcsRadioButton.Checked = false;
            switch (Program.Config.RedirectMode)
            {
            case RedirectMode.HostsIcsFile:
                IcsRadioButton.Checked = true;
                break;

            case RedirectMode.HostsFile:
                HostsRadioButton.Checked = true;
                break;

            case RedirectMode.DnsServer:
                DnsRadioButton.Checked = true;
                break;
            }

            // Set redirect removal
            switch (Program.Config.RedirectRemoveMethod)
            {
            case RedirectRemoveMethod.Never:
                NeverRadioButton.Checked = true;
                break;

            case RedirectRemoveMethod.OnAppClose:
                AppExitsRadioButton.Checked = true;
                break;

            case RedirectRemoveMethod.OnGameClose: break;
            }

            // Auto Login Settings
            CredentialsCheckBox.Checked   = Program.Config.PromptCredentials;
            ProgramUpdateCheckBox.Checked = Program.Config.CheckForUpdates;

            // Load our params
            Params = new ParamsCollection(Program.Config.LaunchParams);
            LaunchParamsTextBox.Text = Params.BuildString(false);

            // Register for events
            BF2Client.PathChanged += LoadModList;
            BF2Client.Started     += BF2Client_Started;
            BF2Client.Exited      += BF2Client_Exited;

            // Focus the mod select first on the Launcher tab!
            MainTabControl.SelectedIndex = 0;

            // Start updater
            if (Program.Config.CheckForUpdates)
            {
                ProgramUpdater.CheckCompleted += ProgramUpdater_CheckCompleted;
                ProgramUpdater.CheckForUpdateAsync();
            }


            // Once the form is shown, asynchronously load the redirect service
            this.Shown += (s, e) =>
            {
                // Focus the mod select combobox
                ModComboBox.Focus();

                // Since we werent registered for Bf2Client events before, do this here
                if (BF2Client.IsRunning)
                {
                    BF2Client_Started();
                }
            };
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Event fired when the Launch Battlefield 2 button is pushed on the Launcher Tab
        /// </summary>
        private async void LaunchButton_Click(object sender, EventArgs args)
        {
            // Lock button to prevent spam
            LaunchButton.Enabled = false;

            // Close the app
            if (BF2Client.IsRunning)
            {
                BF2Client.Stop();
                return;
            }

            // Show overlay first, which provides the smokey (Modal) background
            using (ModalOverlay overlay = new ModalOverlay(this, 0.3))
            {
                // Show overlay
                overlay.Show(this);

                // Make sure a mod is selected
                if (ModComboBox.SelectedIndex < 1)
                {
                    MetroMessageBox.Show(overlay,
                                         "Please select a Bf2 Mod before attempting to start the game!",
                                         "No Mod Selected", MessageBoxButtons.OK, MessageBoxIcon.Asterisk, 150
                                         );
                    overlay.Close();

                    // Reset button
                    BF2Client_Exited();

                    // Focus the mod select
                    ModComboBox.Focus();
                    return;
                }

                // Grab our mod and provider
                BF2Mod          Mod      = ModComboBox.SelectedItem as BF2Mod;
                ServiceProvider Provider = ProviderComboBox.SelectedItem as ServiceProvider;
                Server          Server   = ServerComboBox.SelectedItem as Server;

                // Remove old redirects
                Redirector.RemoveRedirects();

                // If we arent using a provider, skip to just launching the game
                if (Provider == null)
                {
                    goto StartClient;
                }

                // Apply redirects in a new thread
                SyncProgress <TaskStep> MyProgress = new SyncProgress <TaskStep>(RedirectStatusUpdate);
                bool Success = await Redirector.ApplyRedirectsAsync(Provider, MyProgress);

                if (!Success)
                {
                    // Show error
                    MetroMessageBox.Show(overlay, ErrorStep.Description, "Redirect Error", MessageBoxButtons.OK, MessageBoxIcon.Error, 180);
                    overlay.Close();

                    // Reset button
                    BF2Client_Exited();
                    return;
                }

                // Show the Task Form
                TaskForm.Show(this, "Launching Battlefield 2", $"Starting Battlefield 2 with mod \"{Mod.Title}\"", false, ProgressBarStyle.Marquee, 0);

                // Our goto to start the game
StartClient:
                {
                    try
                    {
                        // ===
                        // ALWAYS Remove all temporary keys before this next point
                        // ===
                        Params.Reload(LaunchParamsTextBox.Text);
                        Params.ClearTempParams();

                        // If we are auto joining a server, we must login!
                        if (Provider != null && (Server != null || CredentialsCheckBox.Checked))
                        {
                            // Prompt user to login!
                            using (LoginForm f = new LoginForm(Provider))
                            {
                                DialogResult Res = f.ShowDialog(overlay);
                                if (Res == DialogResult.Cancel)
                                {
                                    // Reset button
                                    TaskForm.CloseForm();
                                    BF2Client_Exited();
                                    return;
                                }

                                // Set server params
                                if (Server != null)
                                {
                                    Params.AddOrSet("joinServer", Server.Address);
                                    Params.AddOrSet("port", Server.Port.ToString());
                                }

                                // Set login params
                                Params.AddOrSet("playerName", f.UsernameTextBox.Text);
                                Params.AddOrSet("playerPassword", f.PasswordTextBox.Text);
                            }
                        }

                        // Start the client executable
                        BF2Client.Start(Mod, Params.BuildString(true));
                    }
                    catch (Exception e)
                    {
                        // Show error
                        MetroMessageBox.Show(overlay, e.Message, "Failure to Launch", MessageBoxButtons.OK, MessageBoxIcon.Error, 180);
                        BF2Client_Exited();
                    }
                }

                // Close the task form
                TaskForm.CloseForm();

                // Close Task form and overlay
                using (RunningOverlay = new GameRunningForm(this))
                {
                    RunningOverlay.ShowDialog(overlay);
                }

                // Close Overlay
                overlay.Close();
                LaunchButton.Focus();
            }
        }
Ejemplo n.º 5
0
        private async void ProgramUpdater_CheckCompleted(object sender, EventArgs e)
        {
            if (ProgramUpdater.UpdateAvailable)
            {
                // Show overlay first, which provides the smokey (Modal) background
                using (ModalOverlay overlay = new ModalOverlay(this, 0.3))
                {
                    // Show overlay
                    overlay.Show(this);

                    // Make sure a mod is selected
                    DialogResult r = MetroMessageBox.Show(overlay,
                                                          "An Update for this program is avaiable for download (" + ProgramUpdater.NewVersion + ")."
                                                          + Environment.NewLine.Repeat(1)
                                                          + "Would you like to download and install this update now?",
                                                          "Update Available",
                                                          MessageBoxButtons.YesNo, MessageBoxIcon.Question, 150
                                                          );

                    // Apply update
                    if (r == DialogResult.Yes)
                    {
                        bool success = false;
                        try
                        {
                            success = await ProgramUpdater.DownloadUpdateAsync(overlay);
                        }
                        catch (Exception ex)
                        {
                            // Create Exception Log
                            TraceLog.TraceWarning("Unable to Download new update archive :: Generating Exception Log");
                            ExceptionHandler.GenerateExceptionLog(ex);

                            // Alert User
                            MetroMessageBox.Show(overlay,
                                                 "Failed to download update archive! Reason: " + ex.Message
                                                 + Environment.NewLine.Repeat(1)
                                                 + "An exception log has been generated and created inside the My Documents/BF2Statistics folder.",
                                                 "Download Failed",
                                                 MessageBoxButtons.OK,
                                                 MessageBoxIcon.Error
                                                 );
                        }

                        // If the file downloaded successfully
                        if (success)
                        {
                            try
                            {
                                ProgramUpdater.RunUpdate();
                            }
                            catch (Exception ex)
                            {
                                MetroMessageBox.Show(overlay,
                                                     "An Occured while trying to install the new update. You will need to manually apply the update."
                                                     + Environment.NewLine.Repeat(1) + "Error Message: " + ex.Message,
                                                     "Installation Error",
                                                     MessageBoxButtons.OK,
                                                     MessageBoxIcon.Error
                                                     );
                            }
                        }
                    }

                    // Close overlay
                    overlay.Close();

                    // Focus the mod select
                    ModComboBox.Focus();
                }
            }
        }