public BoxScoreListWindow() { InitializeComponent(); _db = new SQLiteDatabase(MainWindow.CurrentDB); /* string q = "select * from GameResults ORDER BY Date DESC"; res = db.GetDataTable(q); dgvBoxScores.DataContext = res.DefaultView; */ MainWindow.BSHist = SQLiteIO.GetAllBoxScoresFromDatabase(MainWindow.CurrentDB, MainWindow.TST, MainWindow.PST); _bsHist = new ObservableCollection<BoxScoreEntry>(MainWindow.BSHist); dgvBoxScores.ItemsSource = _bsHist; }
/// <summary>Checks for teams in divisions that don't exist anymore, and reassings them to the first available division.</summary> public static void CheckForInvalidDivisions() { var db = new SQLiteDatabase(MainWindow.CurrentDB); var usedIDs = new List<int>(); db.GetDataTable("SELECT ID FROM Divisions") .Rows.Cast<DataRow>() .ToList() .ForEach(row => usedIDs.Add(ParseCell.GetInt32(row, "ID"))); var teamsChanged = new List<string>(); var maxSeason = SQLiteIO.GetMaxSeason(MainWindow.CurrentDB); for (var i = maxSeason; i >= 1; i--) { var teamsT = "Teams"; var plTeamsT = "PlayoffTeams"; var oppT = "Opponents"; var plOppT = "PlayoffOpponents"; if (i != maxSeason) { var toAdd = "S" + i; teamsT += toAdd; plTeamsT += toAdd; oppT += toAdd; plOppT += toAdd; } var tables = new List<string> { teamsT, plTeamsT, oppT, plOppT }; foreach (var table in tables) { var q = "SELECT ID, Name, Division FROM " + table; var res = db.GetDataTable(q); foreach (DataRow r in res.Rows) { if (usedIDs.Contains(ParseCell.GetInt32(r, "Division")) == false) { db.Update( table, new Dictionary<string, string> { { "Division", MainWindow.Divisions.First().ID.ToString() } }, "ID = " + ParseCell.GetString(r, "ID")); var teamid = MainWindow.TST.Values.Single(ts => ts.Name == ParseCell.GetString(r, "Name")).ID; MainWindow.TST[teamid].Division = MainWindow.Divisions.First().ID; if (teamsChanged.Contains(MainWindow.TST[teamid].DisplayName) == false) { teamsChanged.Add(MainWindow.TST[teamid].DisplayName); } } } } } if (teamsChanged.Count > 0) { teamsChanged.Sort(); var s = "Some teams were in divisions that were deleted and have been reset to the " + MainWindow.Divisions.First().Name + " division.\n\n"; teamsChanged.ForEach(s1 => s += s1 + "\n"); s = s.TrimEnd(new[] { '\n' }); SQLiteIO.SaveSeasonToDatabase(); MessageBox.Show(s); } }
/// <summary>Determines whether the team is hidden for the current season.</summary> /// <param name="file">The file.</param> /// <param name="id">The name of the team.</param> /// <param name="season">The season ID.</param> /// <returns> /// <c>true</c> if the team is hidden; otherwise, <c>false</c>. /// </returns> public static bool IsTeamHiddenInSeason(string file, int id, int season) { var db = new SQLiteDatabase(file); var maxSeason = SQLiteIO.GetMaxSeason(file); var teamsT = "Teams"; if (season != maxSeason) { teamsT += "S" + season; } var q = "select isHidden from " + teamsT + " where ID = " + id + ""; var isHidden = ParseCell.GetBoolean(db.GetDataTable(q).Rows[0], "isHidden"); return isHidden; }
/// <summary>Handles the Click event of the btnAdd control. Allows the user to add a new item.</summary> /// <param name="sender">The source of the event.</param> /// <param name="e"> /// The <see cref="RoutedEventArgs" /> instance containing the event data. /// </param> private void btnAdd_Click(object sender, RoutedEventArgs e) { var ibw = new InputBoxWindow("Enter the name for the new conference:"); if (ibw.ShowDialog() == true) { var name = InputBoxWindow.UserInput.Replace(':', '-'); if (MainWindow.Conferences.Any(conference => conference.Name == name)) { MessageBox.Show("There's already a conference with the name " + name + "."); return; } var usedIDs = new List<int>(); MainWindow.Conferences.ForEach(conference => usedIDs.Add(conference.ID)); var i = 0; while (usedIDs.Contains(i)) { i++; } MainWindow.Conferences.Add(new Conference { ID = i, Name = name }); var db = new SQLiteDatabase(MainWindow.CurrentDB); db.Insert("Conferences", new Dictionary<string, string> { { "ID", i.ToString() }, { "Name", name } }); lstData.ItemsSource = null; lstData.ItemsSource = MainWindow.Conferences; var confToEdit = new Conference(); foreach (Conference item in lstData.Items) { if (item.Name == name) { confToEdit = item; break; } } showEditConferenceWindow(confToEdit); } }
private void prepareHeadToHeadTab(out List<PlayerStatsRow> teamPMSRList, out List<PlayerStatsRow> oppPMSRList) { var iown = _curTeam; var iopp = _curOpp; var dtHTHBS = new DataTable(); dtHTHBS.Columns.Add("Date"); dtHTHBS.Columns.Add("Home-Away"); dtHTHBS.Columns.Add("Result"); dtHTHBS.Columns.Add("Score"); dtHTHBS.Columns.Add("GameID"); var ts = new TeamStats(_curTeam); var tsopp = new TeamStats(_curOpp); _db = new SQLiteDatabase(MainWindow.CurrentDB); if (_dtHTH.Rows.Count > 1) { _dtHTH.Rows.RemoveAt(_dtHTH.Rows.Count - 1); } var bsHist = MainWindow.BSHist; var bseList = bsHist.Where( bse => (bse.BS.Team1ID == _curTeam && bse.BS.Team2ID == _curOpp) || (bse.BS.Team1ID == _curOpp && bse.BS.Team2ID == _curTeam)).ToList(); if (rbHTHStatsAnyone.IsChecked.GetValueOrDefault()) { ts = _tst[iown]; ts.CalcAvg(); tsopp = _tst[iopp]; tsopp.CalcAvg(); } else { foreach (var bse in bseList) { TeamStats.AddTeamStatsFromBoxScore(bse.BS, ref ts, ref tsopp, true); } } //ts.CalcMetrics(tsopp); //tsopp.CalcMetrics(ts); var ls = new TeamStats(); ls.AddTeamStats(ts, Span.SeasonAndPlayoffsToSeason); ls.AddTeamStats(tsopp, Span.SeasonAndPlayoffsToSeason); var keys = _pst.Keys.ToList(); teamPMSRList = new List<PlayerStatsRow>(); oppPMSRList = new List<PlayerStatsRow>(); foreach (var key in keys) { if (_pst[key].TeamF == ts.ID) { teamPMSRList.Add(new PlayerStatsRow(_pst[key])); } else if (_pst[key].TeamF == tsopp.ID) { oppPMSRList.Add(new PlayerStatsRow(_pst[key])); } } foreach (var bse in bseList) { int t1PTS = bse.BS.PTS1; int t2PTS = bse.BS.PTS2; var bsr = dtHTHBS.NewRow(); bsr["Date"] = bse.BS.GameDate.ToString().Split(' ')[0]; if (bse.BS.Team1ID.Equals(_curTeam)) { bsr["Home-Away"] = "Away"; if (t1PTS > t2PTS) { bsr["Result"] = "W"; } else { bsr["Result"] = "L"; } } else { bsr["Home-Away"] = "Home"; if (t2PTS > t1PTS) { bsr["Result"] = "W"; } else { bsr["Result"] = "L"; } } bsr["Score"] = bse.BS.PTS1 + "-" + bse.BS.PTS2; bsr["GameID"] = bse.BS.ID.ToString(); dtHTHBS.Rows.Add(bsr); } _dtHTH.Clear(); var dr = _dtHTH.NewRow(); createDataRowFromTeamStats(ts, ref dr, "Averages"); _dtHTH.Rows.Add(dr); dr = _dtHTH.NewRow(); createDataRowFromTeamStats(tsopp, ref dr, "Opp Avg"); _dtHTH.Rows.Add(dr); dr = _dtHTH.NewRow(); createDataRowFromTeamStats(ts, ref dr, "Playoffs", true); _dtHTH.Rows.Add(dr); dr = _dtHTH.NewRow(); createDataRowFromTeamStats(tsopp, ref dr, "Opp Pl Avg", true); _dtHTH.Rows.Add(dr); _dvHTH = new DataView(_dtHTH) { AllowNew = false, AllowEdit = false }; dgvHTHStats.DataContext = _dvHTH; var dvHTHBS = new DataView(dtHTHBS) { AllowNew = false, AllowEdit = false }; dgvHTHBoxScores.DataContext = dvHTHBS; }
/// <summary> /// Handles the Click event of the btnOK control. The conference is renamed, the divisions are deleted and recreated, and if any /// teams are left in division IDs that no longer exist, they get reassigned. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e"> /// The <see cref="RoutedEventArgs" /> instance containing the event data. /// </param> private void btnOK_Click(object sender, RoutedEventArgs e) { var db = new SQLiteDatabase(MainWindow.CurrentDB); if (String.IsNullOrWhiteSpace(txtName.Text)) { txtName.Text = "League"; } MainWindow.Conferences.Single(conference => conference.ID == _curConf.ID).Name = txtName.Text; db.Update("Conferences", new Dictionary<string, string> { { "Name", txtName.Text } }, "ID = " + _curConf.ID); MainWindow.Divisions.RemoveAll(division => division.ConferenceID == _curConf.ID); db.Delete("Divisions", "Conference = " + _curConf.ID); var usedIDs = new List<int>(); db.GetDataTable("SELECT ID FROM Divisions") .Rows.Cast<DataRow>() .ToList() .ForEach(row => usedIDs.Add(ParseCell.GetInt32(row, "ID"))); var list = Tools.SplitLinesToList(txtDivisions.Text, false); foreach (var newDiv in list) { var newName = newDiv.Replace(':', '-'); var i = 0; while (usedIDs.Contains(i)) { i++; } MainWindow.Divisions.Add(new Division { ID = i, Name = newName, ConferenceID = _curConf.ID }); usedIDs.Add(i); } if (MainWindow.Divisions.Any(division => division.ConferenceID == _curConf.ID) == false) { var i = 0; while (usedIDs.Contains(i)) { i++; } MainWindow.Divisions.Add(new Division { ID = i, Name = txtName.Text, ConferenceID = _curConf.ID }); usedIDs.Add(i); } foreach (var div in MainWindow.Divisions.Where(division => division.ConferenceID == _curConf.ID)) { db.Insert( "Divisions", new Dictionary<string, string> { { "ID", div.ID.ToString() }, { "Name", div.Name }, { "Conference", div.ConferenceID.ToString() } }); } TeamStats.CheckForInvalidDivisions(); ListWindow.MustUpdate = true; Close(); }
/// <summary>Handles the Click event of the btnRemove control. Allows the user to remove an item.</summary> /// <param name="sender">The source of the event.</param> /// <param name="e"> /// The <see cref="RoutedEventArgs" /> instance containing the event data. /// </param> private void btnRemove_Click(object sender, RoutedEventArgs e) { if (lstData.SelectedIndex == -1) { return; } var conf = (Conference) lstData.SelectedItem; var r = MessageBox.Show( "Are you sure you want to delete the " + conf.Name + " conference?", "NBA Stats Tracker", MessageBoxButton.YesNo, MessageBoxImage.Question); if (r == MessageBoxResult.No) { return; } var db = new SQLiteDatabase(MainWindow.CurrentDB); MainWindow.Conferences.Remove(conf); db.Delete("Conferences", "ID = " + conf.ID); MainWindow.Divisions.RemoveAll(division => division.ConferenceID == conf.ID); db.Delete("Divisions", "Conference = " + conf.ID); if (MainWindow.Conferences.Count == 0) { MainWindow.Conferences.Add(new Conference { ID = 0, Name = "League" }); db.Insert("Conferences", new Dictionary<string, string> { { "ID", "0" }, { "Name", "League" } }); MainWindow.Divisions.Add(new Division { ID = 0, Name = "League", ConferenceID = 0 }); db.Insert("Divisions", new Dictionary<string, string> { { "ID", "0" }, { "Name", "League" }, { "Conference", "0" } }); } lstData.ItemsSource = null; lstData.ItemsSource = MainWindow.Conferences; TeamStats.CheckForInvalidDivisions(); }
/// <summary> /// Initializes a new instance of the <see cref="DualListWindow" /> class. Used to enable/disable players/teams for the season. /// </summary> /// <param name="currentDB">The current DB.</param> /// <param name="curSeason">The cur season.</param> /// <param name="maxSeason">The max season.</param> /// <param name="mode">The mode.</param> public DualListWindow(string currentDB, int curSeason, int maxSeason, Mode mode) : this() { _mode = mode; _currentDB = currentDB; _curSeason = curSeason; _maxSeason = maxSeason; txbDescription.Text = "Current Season: " + _curSeason + "/" + _maxSeason; var db = new SQLiteDatabase(_currentDB); var teamsT = "Teams"; _playersT = "Players"; if (_curSeason != _maxSeason) { var s = "S" + _curSeason; teamsT += s; _playersT += s; } if (mode == Mode.HiddenTeams) { var q = "select DisplayName, isHidden from " + teamsT + " ORDER BY DisplayName ASC"; var res = db.GetDataTable(q); foreach (DataRow r in res.Rows) { if (!ParseCell.GetBoolean(r, "isHidden")) { lstEnabled.Items.Add(ParseCell.GetString(r, "DisplayName")); } else { lstDisabled.Items.Add(ParseCell.GetString(r, "DisplayName")); } } btnLoadList.Visibility = Visibility.Hidden; } else if (mode == Mode.HiddenPlayers) { Title = "Enable/Disable Players for Season"; lblEnabled.Content = "Enabled Players"; lblDisabled.Content = "Disabled Players"; var q = "SELECT (LastName || ', ' || FirstName || ' (' || TeamFin || ')') AS Name, ID, isHidden FROM " + _playersT + " ORDER BY LastName"; var res = db.GetDataTable(q); foreach (DataRow r in res.Rows) { var s = ParseCell.GetString(r, "Name"); if (!ParseCell.GetBoolean(r, "isHidden")) { _shownPlayers.Add(new KeyValuePair<int, string>(ParseCell.GetInt32(r, "ID"), s)); } else { _hiddenPlayers.Add(new KeyValuePair<int, string>(ParseCell.GetInt32(r, "ID"), s)); } } _shownPlayers.RaiseListChangedEvents = true; lstEnabled.DisplayMemberPath = "Value"; lstEnabled.SelectedValuePath = "Key"; lstEnabled.ItemsSource = _shownPlayers; _hiddenPlayers.RaiseListChangedEvents = true; lstDisabled.DisplayMemberPath = "Value"; lstDisabled.SelectedValuePath = "Key"; lstDisabled.ItemsSource = _hiddenPlayers; btnLoadList.Visibility = Visibility.Hidden; } }
private void btnOK_Click(object sender, RoutedEventArgs e) { if (_mode == Mode.HiddenTeams) { var db = new SQLiteDatabase(_currentDB); var teamsT = "Teams"; var plTeamsT = "PlayoffTeams"; var oppT = "Opponents"; var plOppT = "PlayoffOpponents"; if (_curSeason != _maxSeason) { var s = "S" + _curSeason; teamsT += s; plTeamsT += s; oppT += s; plOppT += s; } foreach (string name in lstEnabled.Items) { var dict = new Dictionary<string, string> { { "isHidden", "False" } }; db.Update(teamsT, dict, "DisplayName LIKE \"" + name + "\""); db.Update(plTeamsT, dict, "DisplayName LIKE \"" + name + "\""); db.Update(oppT, dict, "DisplayName LIKE \"" + name + "\""); db.Update(plOppT, dict, "DisplayName LIKE \"" + name + "\""); } foreach (string name in lstDisabled.Items) { var q = "select * from GameResults where SeasonNum = " + _curSeason + " AND (Team1ID = " + getTeamIDFromDisplayName(name) + " OR Team2ID = " + getTeamIDFromDisplayName(name) + ")"; var res = db.GetDataTable(q); if (res.Rows.Count > 0) { var r = MessageBox.Show( name + " have box scores this season. Are you sure you want to disable this team?", "NBA Stats Tracker", MessageBoxButton.YesNo, MessageBoxImage.Question); if (r == MessageBoxResult.No) { continue; } } var dict = new Dictionary<string, string> { { "isHidden", "True" } }; db.Update(teamsT, dict, "DisplayName LIKE \"" + name + "\""); db.Update(plTeamsT, dict, "DisplayName LIKE \"" + name + "\""); db.Update(oppT, dict, "DisplayName LIKE \"" + name + "\""); db.Update(plOppT, dict, "DisplayName LIKE \"" + name + "\""); } MainWindow.AddInfo = "$$TEAMSENABLED"; Close(); } else if (_mode == Mode.HiddenPlayers) { var db = new SQLiteDatabase(_currentDB); var dataList = new List<Dictionary<string, string>>(); var whereList = new List<string>(); foreach (KeyValuePair<int, string> item in lstEnabled.Items) { var dict = new Dictionary<string, string> { { "isHidden", "False" } }; dataList.Add(dict); whereList.Add("ID = " + item.Key); } db.UpdateManyTransaction(_playersT, dataList, whereList); dataList = new List<Dictionary<string, string>>(); whereList = new List<string>(); foreach (KeyValuePair<int, string> item in lstDisabled.Items) { var q = "select * from PlayerResults INNER JOIN GameResults ON GameResults.GameID = PlayerResults.GameID where SeasonNum = " + _curSeason + " AND PlayerID = " + item.Key; var res = db.GetDataTable(q, true); if (res.Rows.Count > 0) { var r = MessageBox.Show( item.Value + " has box scores this season. Are you sure you want to disable them?", "NBA Stats Tracker", MessageBoxButton.YesNo, MessageBoxImage.Question); if (r == MessageBoxResult.No) { continue; } } var dict = new Dictionary<string, string> { { "isHidden", "True" }, { "isActive", "False" }, { "TeamFin", "" } }; dataList.Add(dict); whereList.Add("ID = " + item.Key); } db.UpdateManyTransaction(_playersT, dataList, whereList); MainWindow.AddInfo = "$$PLAYERSENABLED"; Close(); } else if (_mode == Mode.REDitor) { if (lstEnabled.Items.Count != 30) { MessageBox.Show( "You can't have less or more than 30 teams enabled. You currently have " + lstEnabled.Items.Count + "."); return; } //MainWindow.selectedTeams = new List<Dictionary<string, string>>(_activeTeams); MainWindow.SelectedTeams = new List<Dictionary<string, string>>(); foreach (string team in lstEnabled.Items) { var teamName = team.Split(new[] { " (ID: " }, StringSplitOptions.None)[0]; MainWindow.SelectedTeams.Add( _validTeams.Find( delegate(Dictionary<string, string> t) { if (t["Name"] == teamName) { return true; } return false; })); } MainWindow.SelectedTeamsChanged = _changed; DialogResult = true; Close(); } else if (_mode == Mode.TradePlayers) { foreach (var pair in _rosters) { var newTeam = pair.Key; foreach (var pID in pair.Value) { var oldTeam = MainWindow.PST[pID].TeamF; var oldTeamS = MainWindow.PST[pID].TeamS; if (newTeam != oldTeam) { if (oldTeamS == -1) { MainWindow.PST[pID].TeamS = MainWindow.PST[pID].TeamF; } MainWindow.PST[pID].TeamF = newTeam; MainWindow.PST[pID].IsSigned = newTeam != -1; } } } DialogResult = true; Close(); } }
/// <summary>Handles the Click event of the mnuFileNew control. Allows the user to create a new database.</summary> /// <param name="sender">The source of the event.</param> /// <param name="e"> /// The <see cref="RoutedEventArgs" /> instance containing the event data. /// </param> private async void mnuFileNew_Click(object sender, RoutedEventArgs e) { var sfd = new SaveFileDialog { Filter = "NST Database (*.tst)|*.tst", InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\NBA Stats Tracker\" }; sfd.ShowDialog(); if (sfd.FileName == "") { return; } try { File.Delete(sfd.FileName); } catch (IOException ex) { MessageBox.Show("Couldn't create the database.\n" + ex.Message); return; } DB = new SQLiteDatabase(sfd.FileName); SQLiteIO.PrepareNewDB(DB, 1, 1); TST = new Dictionary<int, TeamStats>(); TSTOpp = new Dictionary<int, TeamStats>(); PST = new Dictionary<int, PlayerStats>(); BSHist = new List<BoxScoreEntry>(); txtFile.Text = sfd.FileName; CurrentDB = txtFile.Text; populateSeasonCombo(); ChangeSeason(1); SQLiteIO.SetSetting("Game Length", 48); SQLiteIO.SetSetting("Season Length", 82); mnuTools.IsEnabled = true; grdAnalysis.IsEnabled = true; grdUpdate.IsEnabled = true; MWInstance.IsEnabled = false; await UpdateAllData(); StopProgressWatchTimer(); MWInstance.IsEnabled = true; }
/// <summary>Populates the season combo using a specified NST database file.</summary> /// <param name="file">The file from which to determine the available seasons.</param> private void populateSeasonCombo(string file) { DB = new SQLiteDatabase(file); generateSeasons(); }
/// <summary> /// Populates the season combo using a specified NST database file. /// </summary> /// <param name="file">The file from which to determine the available seasons.</param> public void PopulateSeasonCombo(string file) { DB = new SQLiteDatabase(file); GenerateSeasons(); }
/// <summary> /// Handles the Click event of the mnuFileNew control. /// Allows the user to create a new database. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e"> /// The <see cref="RoutedEventArgs" /> instance containing the event data. /// </param> private void mnuFileNew_Click(object sender, RoutedEventArgs e) { var sfd = new SaveFileDialog {Filter = "NST Database (*.tst)|*.tst", InitialDirectory = AppDocsPath}; sfd.ShowDialog(); if (sfd.FileName == "") { return; } try { File.Delete(sfd.FileName); } catch (IOException ex) { MessageBox.Show("Couldn't create the database.\n" + ex.Message); return; } DB = new SQLiteDatabase(sfd.FileName); SQLiteIO.PrepareNewDB(DB, 1, 1); TST = new Dictionary<int, TeamStats>(); TSTOpp = new Dictionary<int, TeamStats>(); PST = new Dictionary<int, PlayerStats>(); BSHist = new List<BoxScoreEntry>(); txtFile.Text = sfd.FileName; CurrentDB = txtFile.Text; PopulateSeasonCombo(); ChangeSeason(1); SQLiteIO.SetSetting("Game Length", 48); SQLiteIO.SetSetting("Season Length", 82); mnuTools.IsEnabled = true; grdAnalysis.IsEnabled = true; grdUpdate.IsEnabled = true; UpdateAllData(); }
/// <summary> /// Updates the box score data grid. /// </summary> /// <param name="teamID">Name of the team.</param> /// <param name="playersList">The players list.</param> /// <param name="pbsList">The player box score list.</param> /// <param name="playersT">The players' SQLite table name.</param> /// <param name="loading"> /// if set to <c>true</c>, it is assumed that a pre-existing box score is being loaded. /// </param> private static void updateBoxScoreDataGrid(int teamID, out ObservableCollection<KeyValuePair<int, string>> playersList, ref SortableBindingList<PlayerBoxScore> pbsList, string playersT, bool loading) { var db = new SQLiteDatabase(MainWindow.CurrentDB); string q = "select * from " + playersT + " where TeamFin = " + teamID + ""; q += " ORDER BY LastName ASC"; DataTable res = db.GetDataTable(q); playersList = new ObservableCollection<KeyValuePair<int, string>>(); if (!loading) { pbsList = new SortableBindingList<PlayerBoxScore>(); } foreach (DataRow r in res.Rows) { var ps = new PlayerStats(r, MainWindow.TST); playersList.Add(new KeyValuePair<int, string>(ps.ID, ps.LastName + ", " + ps.FirstName)); if (!loading) { var pbs = new PlayerBoxScore {PlayerID = ps.ID, TeamID = teamID}; pbsList.Add(pbs); } } for (int i = 0; i < pbsList.Count; i++) { PlayerBoxScore cur = pbsList[i]; string name = MainWindow.PST[cur.PlayerID].LastName + ", " + MainWindow.PST[cur.PlayerID].FirstName; var player = new KeyValuePair<int, string>(cur.PlayerID, name); cur.Name = name; if (!playersList.Contains(player)) { playersList.Add(player); } pbsList[i] = cur; } playersList = new ObservableCollection<KeyValuePair<int, string>>(playersList.OrderBy(item => item.Value)); }