public void EditSurvey(Survey survey) { if (Authentication.userName == USER_NAME && Authentication.password == PASSWORD) { DAL.PollDAL.EditSurvey(survey); } }
/// <summary> /// Deserializes survey from XML string into Survey object /// </summary> /// <param name="xmlString">XML string, which holds serialized Survey object</param> /// <returns>Deserialized Survey object</returns> public static Survey DeserializeSurvey(string xmlString) { Survey survey = new Survey(); try { XmlSerializer xmlSerializer = new XmlSerializer(typeof(Survey)); MemoryStream memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(xmlString)); XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.ASCII); survey = (Survey)xmlSerializer.Deserialize(memoryStream); foreach (Poll poll in survey.Polls) { foreach (Choice choice in poll.Choices) { choice.parent = poll; } } } catch (Exception) { return null; } return survey; }
public int CreateSurvey(Survey newSurvey) { if (Authentication.userName == USER_NAME && Authentication.password == PASSWORD) { return DAL.PollDAL.CreateSurvey(newSurvey); } else { return -1; } }
/// <summary> /// Gets Survey from database by Survey ID /// </summary> /// <param name="surveyID">Survey ID that tells which Survey to get</param> /// <returns></returns> public static Survey GetSurvey(int surveyID) { if (!isConnected) { Init(); } SQLiteCommand sqliteCommand = dbConnection.CreateCommand(); sqliteCommand.CommandText = "SELECT * FROM " + SURVEYS_TABLE + " WHERE id=:id"; sqliteCommand.Parameters.AddWithValue(":id", surveyID.ToString()); SQLiteDataReader sqliteSurvey = sqliteCommand.ExecuteReader(); Survey survey = new Survey(); if (!sqliteSurvey.HasRows) { return survey; } survey.Id = Convert.ToInt32(sqliteSurvey["id"]); survey.Name = sqliteSurvey["name"].ToString(); survey.TestMode = Convert.ToBoolean(sqliteSurvey["testmode"]); survey.MinScore = Convert.ToDouble(sqliteSurvey["minscore"]); survey.Polls = new List<Poll>(); sqliteSurvey.Close(); sqliteCommand.CommandText = "SELECT p.* FROM " + SURVEY_POLLS_TABLE + " pxp LEFT JOIN " + POLLS_TABLE + " p ON (pxp.poll_id=p.id) WHERE pxp.survey_id=:id"; SQLiteDataReader sqlPolls = sqliteCommand.ExecuteReader(); SQLiteCommand sqliteCommand2 = dbConnection.CreateCommand(); sqliteCommand2.CommandText = "SELECT c.* FROM " + POLL_CHOICES_TABLE + " pxc LEFT JOIN " + CHOICES_TABLE + " c ON (pxc.choice_id=c.id) WHERE pxc.poll_id=:id"; sqliteCommand2.Parameters.Add(new SQLiteParameter(":id")); while (sqlPolls.Read()) { Poll newPoll = new Poll(sqlPolls["name"].ToString()); newPoll.Id = Convert.ToInt32(sqlPolls["id"]); newPoll.Description = sqlPolls["description"].ToString(); newPoll.CorrectChoiceID = Convert.ToInt32(sqlPolls["correctchoice"]); newPoll.CustomChoiceEnabled = Convert.ToBoolean(sqlPolls["customenabled"]); sqliteCommand2.Parameters[":id"].Value = newPoll.Id; SQLiteDataReader sqlChoices = sqliteCommand2.ExecuteReader(); while (sqlChoices.Read()) { Choice newChoice = new Choice(sqlChoices["name"].ToString()); newChoice.Id = Convert.ToInt32(sqlChoices["id"]); newPoll.Choices.Add(newChoice); } sqlChoices.Close(); survey.Polls.Add(newPoll); } sqlPolls.Close(); return survey; }
/// <summary> /// Save changed survey to database /// </summary> /// <param name="survey">Survey object that is to be changed in database</param> public static void EditSurvey(Survey survey) { SQLiteCommand sqliteCommand = dbConnection.CreateCommand(); sqliteCommand.Parameters.AddWithValue(":survey_id", survey.Id); sqliteCommand.CommandText = "DELETE FROM " + SURVEY_POLLS_TABLE + " WHERE survey_id=:survey_id"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.Add(new SQLiteParameter(":id", survey.Id)); sqliteCommand.Parameters.Add(new SQLiteParameter(":name", survey.Name)); sqliteCommand.Parameters.Add(new SQLiteParameter(":testmode", survey.TestMode)); sqliteCommand.Parameters.Add(new SQLiteParameter(":minscore", survey.MinScore)); sqliteCommand.CommandText = "UPDATE " + SURVEYS_TABLE + " SET name=:name, testmode=:testmode, minscore=:minscore WHERE id=:id"; sqliteCommand.ExecuteNonQuery(); foreach (Poll curPoll in survey.Polls) { sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.Add(new SQLiteParameter(":name")); sqliteCommand.Parameters.Add(new SQLiteParameter(":id")); foreach (Choice curChoice in curPoll.Choices) { int oldId = curChoice.Id; sqliteCommand.Parameters[":name"].Value = curChoice.choice; sqliteCommand.Parameters[":id"].Value = curChoice.Id; if (curChoice.Id <= 0) { sqliteCommand.CommandText = "INSERT INTO " + CHOICES_TABLE + "(name) VALUES(:name)"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.CommandText = "SELECT last_insert_rowid()"; curChoice.Id = Convert.ToInt32(sqliteCommand.ExecuteScalar()); } else { sqliteCommand.CommandText = "UPDATE " + CHOICES_TABLE + " SET name=:name WHERE id=:id"; sqliteCommand.ExecuteNonQuery(); } if (oldId == curPoll.CorrectChoiceID) { curPoll.CorrectChoiceID = curChoice.Id; } } sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.AddWithValue(":id", curPoll.Id); sqliteCommand.Parameters.AddWithValue(":name", curPoll.Name); sqliteCommand.Parameters.AddWithValue(":description", curPoll.Description); sqliteCommand.Parameters.AddWithValue(":correctchoice", curPoll.CorrectChoiceID); sqliteCommand.Parameters.AddWithValue(":customenabled", curPoll.CustomChoiceEnabled); if (curPoll.Id <= 0) { sqliteCommand.CommandText = "INSERT INTO " + POLLS_TABLE + "(name, description, correctchoice, customenabled) VALUES(:name, :description, :correctchoice, :customenabled)"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.CommandText = "SELECT last_insert_rowid()"; curPoll.Id = Convert.ToInt32(sqliteCommand.ExecuteScalar()); } else { sqliteCommand.CommandText = "UPDATE " + POLLS_TABLE + " SET name=:name, description=:description, correctchoice=:correctchoice, customenabled=:customenabled WHERE id=:id"; sqliteCommand.ExecuteNonQuery(); } sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.AddWithValue(":poll_id", curPoll.Id); sqliteCommand.Parameters.Add(new SQLiteParameter(":choice_id")); sqliteCommand.CommandText = "DELETE FROM " + POLL_CHOICES_TABLE + " WHERE poll_id=:poll_id"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.CommandText = "INSERT INTO " + POLL_CHOICES_TABLE + "(poll_id, choice_id) VALUES(:poll_id, :choice_id)"; foreach (Choice curChoice in curPoll.Choices) { sqliteCommand.Parameters[":choice_id"].Value = curChoice.Id; sqliteCommand.ExecuteNonQuery(); } sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.AddWithValue(":survey_id", survey.Id); sqliteCommand.Parameters.AddWithValue(":poll_id", curPoll.Id); sqliteCommand.CommandText = "INSERT INTO " + SURVEY_POLLS_TABLE + "(survey_id, poll_id) VALUES(:survey_id, :poll_id)"; sqliteCommand.ExecuteNonQuery(); } }
/// <summary> /// Creates new Survey in database /// </summary> /// <param name="newSurvey">object of Survey that is to be created in database</param> /// <returns></returns> public static int CreateSurvey(Survey newSurvey) { SQLiteCommand sqliteCommand = dbConnection.CreateCommand(); sqliteCommand.Parameters.Add(new SQLiteParameter(":name", newSurvey.Name)); sqliteCommand.Parameters.Add(new SQLiteParameter(":testmode", newSurvey.TestMode)); sqliteCommand.Parameters.Add(new SQLiteParameter(":minscore", newSurvey.MinScore)); sqliteCommand.Parameters.Add( new SQLiteParameter( ":date", DateTime.Now.ToString() ) ); sqliteCommand.CommandText = "INSERT INTO " + SURVEYS_TABLE + "(name, testmode, minscore, date_created) VALUES(:name, :testmode, :minscore, :date)"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.CommandText = "SELECT last_insert_rowid()"; newSurvey.Id = Convert.ToInt32(sqliteCommand.ExecuteScalar()); foreach (Poll curPoll in newSurvey.Polls) { sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.Add(new SQLiteParameter(":name")); foreach (Choice curChoice in curPoll.Choices) { int oldId = curChoice.Id; sqliteCommand.Parameters[":name"].Value = curChoice.choice; sqliteCommand.CommandText = "INSERT INTO " + CHOICES_TABLE + "(name) VALUES(:name)"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.CommandText = "SELECT last_insert_rowid()"; curChoice.Id = Convert.ToInt32(sqliteCommand.ExecuteScalar()); if (oldId == curPoll.CorrectChoiceID) { curPoll.CorrectChoiceID = curChoice.Id; } } sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.AddWithValue(":name", curPoll.Name); sqliteCommand.Parameters.AddWithValue(":description", curPoll.Description); sqliteCommand.Parameters.AddWithValue(":correctchoice", curPoll.CorrectChoiceID); sqliteCommand.Parameters.AddWithValue(":customenabled", curPoll.CustomChoiceEnabled); sqliteCommand.CommandText = "INSERT INTO " + POLLS_TABLE + "(name, description, correctchoice, customenabled) VALUES(:name, :description, :correctchoice, :customenabled)"; sqliteCommand.ExecuteNonQuery(); sqliteCommand.CommandText = "SELECT last_insert_rowid()"; curPoll.Id = Convert.ToInt32(sqliteCommand.ExecuteScalar()); sqliteCommand.Parameters.Clear(); sqliteCommand.CommandText = "INSERT INTO " + POLL_CHOICES_TABLE + "(poll_id, choice_id) VALUES(:poll_id, :choice_id)"; sqliteCommand.Parameters.AddWithValue(":poll_id", curPoll.Id); sqliteCommand.Parameters.Add(new SQLiteParameter(":choice_id")); foreach (Choice curChoice in curPoll.Choices) { sqliteCommand.Parameters[":choice_id"].Value = curChoice.Id; sqliteCommand.ExecuteNonQuery(); } sqliteCommand.Parameters.Clear(); sqliteCommand.Parameters.AddWithValue(":survey_id", newSurvey.Id); sqliteCommand.Parameters.AddWithValue(":poll_id", curPoll.Id); sqliteCommand.CommandText = "INSERT INTO " + SURVEY_POLLS_TABLE + "(survey_id, poll_id) VALUES(:survey_id, :poll_id)"; sqliteCommand.ExecuteNonQuery(); } return Convert.ToInt32(newSurvey.Id); }
private void surveysListBox1_SelectedIndexChanged(object sender, EventArgs e) { survey = surveysList[surveysListBox1.SelectedIndex]; }
private void saveButton_Click(object sender, EventArgs e) { // Verification of filling of survey's fields foreach (Survey curSurvey in surveysList) { try { if (curSurvey.Polls.Count == 0) throw new Exception("Survey \"" + curSurvey.Name + "\" must have polls"); foreach (Poll curPoll in curSurvey.Polls) { if (curPoll.Choices.Count == 0) throw new Exception("Survey \"" + curSurvey.Name + "\" -> Poll \"" + curPoll.Name + "\": poll must have choices"); } } catch (Exception exception) { MessageBox.Show(exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } // Transform correct choice Indexes to IDs List<int> IDList = new List<int>(); foreach (Survey curSurvey in surveysList) { foreach (Poll curPoll in curSurvey.Polls) { try { IDList.Add(curPoll.Choices[curPoll.CorrectChoiceID].Id); } catch (Exception exception) { MessageBox.Show(curSurvey.Name + "." + curPoll.Name + ": CorrectChoice Index is out of range", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } } // Save all correct choice changes int index = 0; foreach (Survey curSurvey in surveysList) { foreach (Poll curPoll in curSurvey.Polls) { curPoll.CorrectChoiceID = IDList[index]; index++; } } history.Exclude(); // Save all new foreach (Survey curSurvey in surveysList) { if (curSurvey.Id < 0) { PollClientGUI.pollService.CreateSurvey(curSurvey); } } /* OLD <--- foreach (Survey curSurvey in surveysList) { if (curSurvey.Id < 0) { PollPacket pollPacket = new PollPacket(); pollPacket.request = new Request(); pollPacket.request.type = Request.CREATE_SURVEY; pollPacket.survey = curSurvey; PollClientGUI.client.Send(PollSerializator.SerializePacket(pollPacket)); } } */ // Save all edited foreach (int idEdited in history.edited) { Survey survey = new Survey(); // Find needed Survey in list foreach (Survey curSurvey in surveysList) { if (curSurvey.Id == idEdited) { survey = curSurvey; break; } } PollClientGUI.pollService.EditSurvey(survey); } /* OLD <--- foreach (int idEdited in history.edited) { PollPacket pollPacket = new PollPacket(); pollPacket.request = new Request(); pollPacket.request.id = idEdited.ToString(); // Find needed Survey in list foreach (Survey curSurvey in surveysList) { if (curSurvey.Id == idEdited) { pollPacket.survey = curSurvey; break; } } pollPacket.request.type = Request.EDIT_SURVEY; PollClientGUI.client.Send(PollSerializator.SerializePacket(pollPacket)); } */ // Remove all deleted foreach (int idDeleted in history.deleted) { PollClientGUI.pollService.RemoveSurvey(idDeleted); } /* OLD <--- foreach (int idDeleted in history.deleted) { PollPacket pollPacket = new PollPacket(); pollPacket.request = new Request(); pollPacket.request.id = idDeleted.ToString(); pollPacket.request.type = Request.REMOVE_SURVEY; PollClientGUI.client.Send(PollSerializator.SerializePacket(pollPacket)); } */ MessageBox.Show("Changes successfully sent to server", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); GetSurveys(); history.Clear(); }
/// <summary> /// Function creates new Survey /// </summary> /// <param name="sender">object sender</param> /// <param name="e">EventArgs e</param> private void createButton_Click( object sender, EventArgs e ) { Survey survey = new Survey(); int newId = idGenerator.id; survey.Name = "newSurvey" + Math.Abs(newId).ToString(); survey.Id = newId; surveysList.Add(survey); propertyGrid.SelectedObject = surveysList[surveysList.Count - 1]; RefreshEditorList(); surveysListBox.SelectedIndex = surveysList.Count - 1; }
/// <summary> /// Server sends list of available surveys. User picks one and client gets that survey from server. /// </summary> public static void GetSurvey() { PollPacket sendPacket = new PollPacket(); sendPacket.request = new Request(); sendPacket.request.type = Request.GET_LIST; PollPacket receivedPacket = new PollPacket(); receivedPacket = ReceivePollPacket(sendPacket); // Check if list is not empty if (receivedPacket.surveyList.items.Count == 0) { Console.WriteLine("Sorry, but data base is empty, no surveys..."); client.Disconnect(); Console.WriteLine("- Disconnected from server"); Console.WriteLine("Press any key to exit..."); Console.ReadKey(true); Environment.Exit(-1); } // Output list of surveys Console.WriteLine("List of surveys:"); int index = 0; foreach (Item curItem in receivedPacket.surveyList.items) { index++; Console.WriteLine(index + ". " + curItem.name); } while (true) { Console.WriteLine("Please select survey[1-{0}]:", receivedPacket.surveyList.items.Count); // Let user input survey id string userAnswer = Console.ReadLine(); try { index = Convert.ToInt32(userAnswer); if (index > 0 && index <= receivedPacket.surveyList.items.Count) { string surveyID = receivedPacket.surveyList.items[index - 1].id.ToString(); sendPacket.request.type = Request.GET_SURVEY; sendPacket.request.id = surveyID; break; } else { throw new Exception("Invalid survey id! Please, input correct id"); } } catch (Exception exception) { Console.WriteLine("! " + exception.Message); } } // Receive poll receivedPacket = ReceivePollPacket(sendPacket); survey = receivedPacket.survey; Console.WriteLine("<- Survey received"); }
/// <summary> /// Serializes survey from Survey object into XML string /// </summary> /// <param name="survey">Survey oject</param> /// <returns>XML string, which holds serialized Survey object</returns> public static String SerializeSurvey(Survey survey) { String XmlizedString = null; try { MemoryStream memoryStream = new MemoryStream(); XmlSerializer xs = new XmlSerializer(typeof(Survey)); XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.ASCII); xs.Serialize(xmlTextWriter, survey); memoryStream = (MemoryStream)xmlTextWriter.BaseStream; XmlizedString = Encoding.ASCII.GetString(memoryStream.ToArray()); } catch (Exception) { return null; } return XmlizedString; }
/// <summary> /// Adds or edits survey and saves it to server /// </summary> /// <param name="surveyID">id of session to edit</param> public static void EditSurvey( int surveyID ) { Survey survey; if ( surveyID == 0 ) { survey = new Survey(); } else { PollPacket pollPacket = new PollPacket(); pollPacket.request = new Request(); pollPacket.request.type = Request.GET_SURVEY; pollPacket.request.id = surveyID.ToString(); pollPacket = ReceivePollPacket( pollPacket ); survey = pollPacket.survey; } survey.Name = InputHelper.AskQuestion("Enter survey name:", survey.Name, null); survey.TestMode = InputHelper.ToBoolean(InputHelper.AskQuestion("Test mode[y/n]?", InputHelper.ToString(survey.TestMode), new string[] { STRING_YES, STRING_NO })); if (survey.TestMode == true) { while (true) { try { survey.MinScore = Convert.ToDouble(InputHelper.AskQuestion("Min score to pass test:", Convert.ToString(survey.MinScore, cultureInfo), null), cultureInfo); if (survey.MinScore > 1 || survey.MinScore < 0) throw new Exception("min score must be between 0 and 1"); break; } catch (Exception exception) { Console.WriteLine("Error: {0}", exception.Message); //Console.WriteLine("Please, input correct min score (example: 0.5)"); } } } while(true) { Console.WriteLine("Survey contains {0} polls.", survey.Polls.Count); if (survey.Polls.Count > 0) { Console.WriteLine( "Actions:" ); Console.WriteLine( "1. Add new poll" ); Console.WriteLine( "2. Edit poll" ); Console.WriteLine( "3. Remove poll" ); Console.WriteLine( "4. End" ); int userChoice = InputHelper.AskQuestion("Select action [1-4]:", 1, 4); if ( userChoice == 4 ) break; int index; switch (userChoice) { case 1: EditPoll( ref survey, -1 ); break; case 2: index = 0; Console.WriteLine("List of polls:"); foreach (Poll poll in survey.Polls) { index++; Console.WriteLine("{0}. {1}", index, poll.Name); } userChoice = InputHelper.AskQuestion(String.Format("Choose which one to edit [1-{0}]:", index), 1, index); EditPoll( ref survey, userChoice-1 ); break; case 3: index = 0; Console.WriteLine("List of polls:"); foreach (Poll poll in survey.Polls) { index++; Console.WriteLine("{0}. {1}", index, poll.Name); } survey.Polls.RemoveAt(InputHelper.AskQuestion(String.Format("Choose which one to delete [1-{0}]:", index), 1, index)-1); break; } } else { EditPoll( ref survey, -1 ); } } // Save survey to server if (InputHelper.AskQuestion("Do you want to save this survey to server [y/n]?", new string[] { STRING_YES, STRING_NO }) == STRING_YES) { PollPacket sendPacket = new PollPacket(); sendPacket.request = new Request(); if (surveyID == 0) { sendPacket.request.type = Request.CREATE_SURVEY; } else { sendPacket.request.type = Request.EDIT_SURVEY; } sendPacket.request.id = surveyID.ToString(); sendPacket.survey = survey; string sendString = PollSerializator.SerializePacket(sendPacket); client.Send(sendString); } }
/// <summary> /// Adds or edits a poll /// </summary> /// <param name="survey">Survey conected to poll</param> /// <param name="index">index of poll in survey poll list</param> public static void EditPoll( ref Survey survey, int index ) { Poll newPoll; if ( index == -1 ) { survey.Polls.Add( new Poll() ); index = survey.Polls.Count - 1; newPoll = survey.Polls[index]; newPoll.Id = 0; newPoll.CorrectChoiceID = 0; } else { newPoll = survey.Polls[index]; } newPoll.Name = InputHelper.AskQuestion( "Poll name:", newPoll.Name, null ); newPoll.Description = InputHelper.AskQuestion( "Poll description:", newPoll.Description, null ); while ( true ) { int choiceIndex; Console.WriteLine( "Poll contains {0} choices.", newPoll.Choices.Count ); if ( newPoll.Choices.Count >= (survey.TestMode ? 2 : 0) ) { Console.WriteLine( "Actions:" ); Console.WriteLine( "1. Add new choice" ); Console.WriteLine( "2. Edit choice" ); Console.WriteLine( "3. Remove choice" ); Console.WriteLine( "4. End" ); int userChoice = InputHelper.AskQuestion( "Select action [1-4]:", 1, 4 ); if (userChoice == 4) break; switch ( userChoice ) { case 1: choiceIndex = newPoll.Choices.Count; newPoll.Choices.Add( new Choice() ); newPoll.Choices[choiceIndex].Id = 0; newPoll.Choices[choiceIndex].choice = InputHelper.AskQuestion( "Choice name:", null ); newPoll.Choices[choiceIndex].parent = newPoll; Console.WriteLine( "Choice added!" ); break; case 2: choiceIndex = newPoll.GetChoiceId(); newPoll.Choices[choiceIndex-1].choice = InputHelper.AskQuestion( "Choice name:", newPoll.Choices[choiceIndex-1].choice, null ); Console.WriteLine( "Choice edited!" ); break; case 3: choiceIndex = newPoll.GetChoiceId(); newPoll.Choices.RemoveAt( choiceIndex-1 ); Console.WriteLine( "Choice deleted!" ); break; } } else { /* bool addNewChoice = InputHelper.ToBoolean( InputHelper.AskQuestion( "Add new choice[y/n]?", new string[] { STRING_YES, STRING_NO } ) ); if ( addNewChoice == false ) break;*/ choiceIndex = newPoll.Choices.Count; newPoll.Choices.Add( new Choice() ); newPoll.Choices[choiceIndex].Id = 0; newPoll.Choices[choiceIndex].choice = InputHelper.AskQuestion( "Choice name:", null ); newPoll.Choices[choiceIndex].parent = newPoll; Console.WriteLine( "Choice added!" ); } } if ( survey.TestMode == false ) { // Enable CustomChoice automaticly if user doesn't inputed any choice if ( newPoll.Choices.Count == 0 ) { newPoll.CustomChoiceEnabled = true; } else { newPoll.CustomChoiceEnabled = InputHelper.ToBoolean( InputHelper.AskQuestion( "Enable custom choice for this poll[y/n]?", InputHelper.ToString( newPoll.CustomChoiceEnabled ), new string[] { STRING_YES, STRING_NO } ) ); } } else { /* foreach ( Choice choice in newPoll.choices ) Console.WriteLine( "\t" + choice.id + ". " + choice.choice ); */ // Ask correct choice Console.WriteLine("Which one is correct?"); newPoll.CorrectChoiceID = newPoll.GetChoiceId(); } }