/// <summary> /// Lädt alle Messpunkte eines Raums /// </summary> /// <returns></returns> public List <Messpunkt> LoadMesspunkte(Raum raum) { bool wasOpen = connection.State == System.Data.ConnectionState.Open; if (!wasOpen) { connection.Open(); } List <Messpunkt> retval = new List <Messpunkt>(); raum.Messpunkte.Clear(); using (MySqlCommand cmd = new MySqlCommand(SqlConstants.SQL_LoadMesspunkte, connection)) { using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { Messpunkt mp = new Messpunkt(); mp.FromReader(reader); if (mp.RaumID == raum.RaumID) { //mp.Raum = raum; raum.Messpunkte.Add(mp); retval.Add(mp); } } } } if (!wasOpen) { connection.Clone(); } return(retval); }
/// <summary> /// Lädt die Messwerte eines Messpunkts /// </summary> /// <returns></returns> public List <MessWert> LoadMesswerte(Messpunkt messpunkt) { bool wasOpen = connection.State == System.Data.ConnectionState.Open; if (!wasOpen) { connection.Open(); } List <MessWert> retval = new List <MessWert>(); messpunkt.Werte.Clear(); using (MySqlCommand cmd = new MySqlCommand(SqlConstants.SQL_LoadMesswerte, connection)) { using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { MessWert mw = new MessWert(); mw.FromReader(reader); if (mw.MesspunktID == messpunkt.MesspunktID) { //mw.Messpunkt = messpunkt; messpunkt.Werte.Add(mw); retval.Add(mw); } } } } if (!wasOpen) { connection.Clone(); } return(retval); }
public void PTIns() { m_ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptPointOptions prPtOpt = new PromptPointOptions("Bitte Position wählen:"); bool bBeenden = false; while (!bBeenden) { PromptPointResult prPtRes = m_ed.GetPoint("Position wählen:"); if (prPtRes.Status == PromptStatus.OK) { PromptStringOptions prStringOpt = new PromptStringOptions("Nr: " + PNrZähler); prStringOpt.AllowSpaces = false; PromptResult prRes = m_ed.GetString(prStringOpt); if (prRes.Status == PromptStatus.OK) { if (prRes.StringResult != "") { PNrZähler = prRes.StringResult; PNrZähler = objUtil.incString(PNrZähler); } } Messpunkt objMP = new Messpunkt(PNrZähler, prPtRes.Value.X, prPtRes.Value.Y, null, null, 0); objMP.draw("MP", "MP-P"); } else { bBeenden = true; } } }
private void bt_OK_Click(object sender, EventArgs e) { Messpunkt[] vMP = m_objBlöcke.getMP; for (int i = 0; i < m_objBlöcke.count; i++) { Messpunkt objMP = vMP[i]; objMP.Prefix = tb_Prefix.Text; } }
//Messpunkte einfügen private void InsertMP() { bool bHeader = false; bool bErrorIO = false; int firstRow = 0; //erste einzulesende Zeile string[] arZeile = _Text.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); List <Messpunkt> lsMP = new List <Messpunkt>(); //Header? if (bHeader) { firstRow = 1; } for (int i = firstRow; i < arZeile.Length; i++) { try { string Zeile = arZeile[i]; string[] arElement = Zeile.Split(new char[] { ';' }, StringSplitOptions.None); string PNum = arElement[0]; double X = Convert.ToDouble(arElement[1].Replace(',', '.'), CultureInfo.InvariantCulture); double Y = Convert.ToDouble(arElement[2].Replace(',', '.'), CultureInfo.InvariantCulture); //Höhe string HöheText = String.Empty;; double?Z = null; bool import3d = Convert.ToBoolean(_config.GetAppSettingString("3dImport")); try { HöheText = @arElement[3].Replace(',', '.'); HöheText = HöheText.Replace("\r", ""); if (HöheText != String.Empty) { Z = Convert.ToDouble(HöheText, CultureInfo.InvariantCulture); } } catch { } Messpunkt MP = null; if (import3d) { if (Z.HasValue) { Point3d pos = new Point3d(X, Y, Z.Value); MP = new Messpunkt(PNum, pos, HöheText); } else { Point2d pos = new Point2d(X, Y); MP = new Messpunkt(PNum, pos); } } else { Point2d pos = new Point2d(X, Y); if (Z.HasValue) { MP = new Messpunkt(PNum, pos, HöheText); } else { MP = new Messpunkt(PNum, pos); } } lsMP.Add(MP); } catch { if (i == 0) { bHeader = true; } else { _lsErrorLine.Add(i); bErrorIO = true; } } } try { if (!bErrorIO) { int Anzahl = lsMP.Count; if (ProcessingStarted != null) { string process = "Punkte importieren"; LongProcessStartedEventArgs e = new LongProcessStartedEventArgs( process, lsMP.Count, true); ProcessingStarted(this, e); } for (int i = 0; i < lsMP.Count; i++) { Messpunkt MP = lsMP[i]; if (ProcessingProgressed != null) { string progMsg = string.Format( "{0} out of {1}. {2} remaining...\n" + "Processing entity: {3}", i, lsMP.Count, lsMP.Count - i, MP.PNum); LongProcessingProgressEventArgs e1 = new LongProcessingProgressEventArgs(progMsg); ProcessingProgressed(this, e1); //Since this processing is cancellable, we //test if user clicked the "Stop" button in the //progressing dialog box if (e1.Cancel) { Anzahl = i; break; } } MP.Draw(_block, _basislayer); } ProcessingEnded?.Invoke(this, EventArgs.Empty); MessageBox.Show(Anzahl.ToString() + " Messpunkte eingefügt!"); } else { dlgPtImport diaPtImport = new dlgPtImport() { Text = _Text }; diaPtImport.ShowDialog(); } } finally { //Make sure the CloseProgressUIRequested event always fires, so //that the progress dialog box gets closed because of this event CloseProgressUIRequested?.Invoke(this, EventArgs.Empty); } }
public void run() { OpenFileDialog ddOpenFile = new OpenFileDialog(); ddOpenFile.Title = "Vermessungspunkte importieren"; ddOpenFile.Filter = "Punktwolke|*.csv|Punktwolke|*.dat"; ddOpenFile.DefaultExt = m_Settings.Extention; Editor m_ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; DialogResult diagRes = DialogResult.None; if (!m_Settings.openExportFile) { diagRes = ddOpenFile.ShowDialog(); } else { ddOpenFile.FileName = m_Settings.ExportFile; diagRes = DialogResult.OK; } if (diagRes == DialogResult.OK) { bool fileOK = true; m_Filename = ddOpenFile.FileName; try { StreamReader sr = new StreamReader(m_Filename, Encoding.Default); m_Text = sr.ReadToEnd(); sr.Close(); } catch { fileOK = false; } if (fileOK) { m_Extention = m_Filename.Substring(m_Filename.LastIndexOf('.') + 1).ToLower(); string[] arZeile; string PNum; double Rechtswert = new double(); double Hochwert = new double(); double Höhe = new double(); double?Höhenwert = new Double(); myRegistry.regIO objRegIO = new myRegistry.regIO(); string Basislayer = (string)objRegIO.readValue("blocks", "Basislayer"); //Basislayer ggf. anlegen myAutoCAD.myLayer objLayer = myAutoCAD.myLayer.Instance; objLayer.checkLayer(Basislayer, true); int Zähler = 0; int iZeile = 1; switch (m_Extention) { case "dat": bool bDatFehler = false; m_arText = m_Text.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); //Zeilen von MP in Array einfügen foreach (string Zeile in m_arText) { arZeile = Zeile.Split(new char[] { (char)32 }, StringSplitOptions.RemoveEmptyEntries); m_arPunkte.Add(arZeile); if (arZeile.Length < 3) { bDatFehler = true; break; } iZeile++; } if (!bDatFehler) { foreach (string[] Zeile in m_arPunkte) { bool bFehler = false; PNum = Zeile[0]; if (m_Util.convertToDouble(Zeile[1], ref Rechtswert, null) != Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { bFehler = true; } if (m_Util.convertToDouble(Zeile[2], ref Hochwert, null) != Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { bFehler = true; } Autodesk.AutoCAD.Runtime.ErrorStatus eSHöhe = m_Util.convertToDouble(Zeile[3], ref Höhe, null); if (!(eSHöhe == Autodesk.AutoCAD.Runtime.ErrorStatus.OK || eSHöhe == Autodesk.AutoCAD.Runtime.ErrorStatus.NullExtents)) { bFehler = true; } //Nachkommastellen Höhe myAutoCAD.myUtilities objUtil = new myAutoCAD.myUtilities(); int Precision = objUtil.Precision(Zeile[3]); double CASHöhe = Höhe; Höhe = Math.Round(Höhe, Convert.ToInt32(m_objRegIO.readValue("blocks", "Kommastellen"))); //Att3 (Datum) string Att3 = String.Empty; try { if (Zeile[4] != "" && Zeile[4] != "\r") { Att3 = Zeile[4]; } } catch { } //Att4 (Code) string Att4 = String.Empty; try { if (Zeile[5] != "" && Zeile[5] != "\r") { Att4 = Zeile[5]; } } catch { } //Att5 (Hersteller) string Att5 = String.Empty; try { if (Zeile[6] != "" && Zeile[6] != "\r") { Att5 = Zeile[6]; } } catch { } if (!bFehler) { //Höhe if (eSHöhe == Autodesk.AutoCAD.Runtime.ErrorStatus.NullExtents) { Höhenwert = null; } else { Höhenwert = Höhe; } myAutoCAD.Messpunkt objMP = new Messpunkt(PNum, Rechtswert, Hochwert, Höhenwert, CASHöhe, Precision); if (Att3 != String.Empty) { objMP.Att3_Wert = Att3; } if (Att4 != String.Empty) { objMP.Att4_Wert = Att4; } if (Att5 != String.Empty) { objMP.Att5_Wert = Att5; } if (objMP.draw("MP", Basislayer) == Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { Zähler += 1; } else { break; } } } } else { MessageBox.Show("Fehler in dat File! (Zeile: " + iZeile.ToString()); } break; case "csv": m_arText = m_Text.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); //Zeilen von MP in Array einfügen foreach (string Zeile in m_arText) { arZeile = Zeile.Split(new char[] { ';' }, StringSplitOptions.None); m_arPunkte.Add(arZeile); } foreach (string[] Zeile in m_arPunkte) { bool bFehler = false; Rechtswert = new Double(); Hochwert = new Double(); Höhe = new Double(); string Blockname = String.Empty; PNum = Zeile[0]; if (m_Util.convertToDouble(Zeile[1], ref Rechtswert, null) != Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { bFehler = true; } if (m_Util.convertToDouble(Zeile[2], ref Hochwert, null) != Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { bFehler = true; } Autodesk.AutoCAD.Runtime.ErrorStatus eSHöhe = m_Util.convertToDouble(Zeile[3], ref Höhe, null); if (!(eSHöhe == Autodesk.AutoCAD.Runtime.ErrorStatus.OK || eSHöhe == Autodesk.AutoCAD.Runtime.ErrorStatus.NullExtents)) { bFehler = true; } //Nachkommastellen Höhe myAutoCAD.myUtilities objUtil = new myAutoCAD.myUtilities(); int Precision = objUtil.Precision(Zeile[3]); double CASHöhe = Höhe; Höhe = Math.Round(Höhe, Convert.ToInt32(m_objRegIO.readValue("blocks", "Kommastellen"))); //Blockname try { if (Zeile[4] != "" && Zeile[4] != "\r") { Blockname = Zeile[4]; } } catch { } //Att3 (Datum) string Att3 = String.Empty; try { if (Zeile[4] != "" && Zeile[4] != "\r") { Att3 = Zeile[4]; } } catch { } //Att4 (Code) string Att4 = String.Empty; try { if (Zeile[5] != "" && Zeile[5] != "\r") { Att4 = Zeile[5]; } } catch { } //Att5 (Hersteller) string Att5 = String.Empty; try { if (Zeile[6] != "" && Zeile[6] != "\r") { Att5 = Zeile[6]; } } catch { } //Att6 string Att6 = String.Empty; try { if (Zeile[7] != "" && Zeile[7] != "\r") { Att6 = Zeile[7]; } } catch { } //Att7 string Att7 = String.Empty; try { if (Zeile[8] != "" && Zeile[8] != "\r") { Att7 = Zeile[8]; } } catch { } //Att8 string Att8 = String.Empty; try { if (Zeile[9] != "" && Zeile[9] != "\r") { Att8 = Zeile[9]; } } catch { } //Att9 string Att9 = String.Empty; try { if (Zeile[10] != "" && Zeile[10] != "\r") { Att9 = Zeile[10]; } } catch { } //Att10 string Att10 = String.Empty; try { if (Zeile[11] != "" && Zeile[11] != "\r") { Att10 = Zeile[11]; } } catch { } if (!bFehler) { //Höhe if (eSHöhe == Autodesk.AutoCAD.Runtime.ErrorStatus.NullExtents) { Höhenwert = null; } else { Höhenwert = Höhe; } myAutoCAD.Messpunkt objMP = new Messpunkt(PNum, Rechtswert, Hochwert, Höhenwert, CASHöhe, Precision, Blockname); if (Att3 != String.Empty) { objMP.Att3_Wert = Att3; } if (Att4 != String.Empty) { objMP.Att4_Wert = Att4; } if (Att5 != String.Empty) { objMP.Att5_Wert = Att5; } if (Att6 != String.Empty) { objMP.Att6_Wert = Att6; } if (Att7 != String.Empty) { objMP.Att7_Wert = Att7; } if (Att8 != String.Empty) { objMP.Att8_Wert = Att8; } if (Att9 != String.Empty) { objMP.Att9_Wert = Att9; } if (Att10 != String.Empty) { objMP.Att10_Wert = Att10; } if (objMP.draw("MP", Basislayer) == Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { Zähler += 1; } else { break; } } } break; } MessageBox.Show(Zähler.ToString() + " Punkte importiert!"); m_ed.Regen(); //Object acadObject = Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication; //acadObject.GetType().InvokeMember("ZoomExtents", BindingFlags.InvokeMethod, null, acadObject, null); } else { MessageBox.Show(m_Filename + " kann nicht geöffnet werden!"); } } }
public MesspunktTreeViewItem(Messpunkt mp) : base(mp) { }
public void convertTo3d() { Database db = HostApplicationServices.WorkingDatabase; Autodesk.AutoCAD.DatabaseServices.TransactionManager myTm = db.TransactionManager; Transaction myT = db.TransactionManager.StartTransaction(); //alle Blöcke wählen myAutoCAD.Blöcke.Instance.init(); myAutoCAD.Blöcke.Instance.selectAll(); Messpunkt[] vMP = Blöcke.Instance.getMP; //Linien using (DocumentLock dl = Application.DocumentManager.MdiActiveDocument.LockDocument()) { foreach (KeyValuePair <ObjectId, Line> valPair in m_LineCollection) { ObjectId id = valPair.Key; Line objLine = valPair.Value; Messpunkt MP = new Messpunkt(); Point2d startPt = new Point2d(objLine.StartPoint.X, objLine.StartPoint.Y); Point2d endPt = new Point2d(objLine.EndPoint.X, objLine.EndPoint.Y); Line line = (Line)myT.GetObject(id, OpenMode.ForWrite); if (Blöcke.Instance.findPos(ref MP, startPt, 0.001) == ErrorStatus.OK) { line.StartPoint = MP.Position; } else { m_lsMP_Error.Add(new Messpunkt("", startPt.X, startPt.Y, null, null, 0)); } if (Blöcke.Instance.findPos(ref MP, endPt, 0.001) == ErrorStatus.OK) { line.EndPoint = MP.Position; } else { m_lsMP_Error.Add(new Messpunkt("", endPt.X, endPt.Y, null, null, 0)); } } } //Polylinien using (DocumentLock dl = Application.DocumentManager.MdiActiveDocument.LockDocument()) { foreach (KeyValuePair <ObjectId, Polyline> valPair in m_PolylineCollection) { ObjectId id = valPair.Key; Polyline objPL = valPair.Value; List <Point3d> lsPt3d = new List <Point3d>(); //Vertices iterieren for (int i = 0; i < objPL.NumberOfVertices; i++) { Point2d pt = objPL.GetPoint2dAt(i); Messpunkt MP = new Messpunkt(); if (Blöcke.Instance.findPos(ref MP, pt, 0.001) == ErrorStatus.OK) { lsPt3d.Add(MP.Position); } else { Point3d pt3d = new Point3d(pt.X, pt.Y, 0); MP.Position = pt3d; m_lsMP_Error.Add(MP); lsPt3d.Add(pt3d); } } //3dPolylinie erstellen //Punktliste erzeugen Point3d[] vPT3d = new Point3d[lsPt3d.Count]; for (int i = 0; i < lsPt3d.Count; i++) { vPT3d[i] = lsPt3d[i]; } //3d Polylinie erzeugen Point3dCollection pt3dCol = new Point3dCollection(vPT3d); Polyline3d objPL3d = new Polyline3d(Poly3dType.SimplePoly, pt3dCol, objPL.Closed); objPL3d.Layer = objPL.Layer; //2d Polylinie löschen Polyline pl = (Polyline)myT.GetObject(id, OpenMode.ForWrite); pl.Erase(true); //Polylinie in DB einfügen try { BlockTable bt = (BlockTable)myT.GetObject(db.BlockTableId, OpenMode.ForRead, false); BlockTableRecord btr = (BlockTableRecord)myT.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false); ObjectId idPL3d = btr.AppendEntity(objPL3d); myT.AddNewlyCreatedDBObject(objPL3d, true); objPL3d.Draw(); } catch { } } } //Polyline2d using (DocumentLock dl = Application.DocumentManager.MdiActiveDocument.LockDocument()) { foreach (KeyValuePair <ObjectId, Polyline2d> valPair in m_Polyline2dCollection) { ObjectId id = valPair.Key; Polyline2d objPL2d = valPair.Value; List <Point3d> lsPt3d = new List <Point3d>(); //Vertices iterieren foreach (ObjectId idVertex in objPL2d) { Vertex2d vertex2d = (Vertex2d)myT.GetObject(idVertex, OpenMode.ForRead); Point2d pt = new Point2d(vertex2d.Position.X, vertex2d.Position.Y); Messpunkt MP = new Messpunkt(); if (Blöcke.Instance.findPos(ref MP, pt, 0.001) == ErrorStatus.OK) { lsPt3d.Add(MP.Position); } else { Point3d pt3d = new Point3d(pt.X, pt.Y, 0); MP.Position = pt3d; m_lsMP_Error.Add(MP); lsPt3d.Add(pt3d); } } //3dPolylinie erstellen //Punktliste erzeugen Point3d[] vPT3d = new Point3d[lsPt3d.Count]; for (int i = 0; i < lsPt3d.Count; i++) { vPT3d[i] = lsPt3d[i]; } //3d Polylinie erzeugen Point3dCollection pt3dCol = new Point3dCollection(vPT3d); Polyline3d objPL3d = new Polyline3d(Poly3dType.SimplePoly, pt3dCol, objPL2d.Closed); objPL3d.Layer = objPL2d.Layer; //2d Polylinie löschen Polyline2d pl2d = (Polyline2d)myT.GetObject(id, OpenMode.ForWrite); pl2d.Erase(true); //Polylinie in DB einfügen try { BlockTable bt = (BlockTable)myT.GetObject(db.BlockTableId, OpenMode.ForRead, false); BlockTableRecord btr = (BlockTableRecord)myT.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite, false); ObjectId idPL3d = btr.AppendEntity(objPL3d); myT.AddNewlyCreatedDBObject(objPL3d, true); objPL3d.Draw(); } catch { } } } //Fehler anzeigen if (m_lsMP_Error.Count > 0) { foreach (Messpunkt MP in m_lsMP_Error) { MP.mark(0.2); } System.Windows.Forms.MessageBox.Show(m_lsMP_Error.Count.ToString() + " Fehler gefunden!"); } else { System.Windows.Forms.MessageBox.Show("3d Konvertierung fehlerfrei durchgeführt!"); } myT.Commit(); }
private void bt_OpenPTFile_Click(object sender, EventArgs e) { OpenFileDialog ddOpenFile = new OpenFileDialog(); ddOpenFile.Title = "Vermessungspunkte importieren"; ddOpenFile.Filter = "Punktwolke|*.csv"; ddOpenFile.DefaultExt = "csv"; string[] arText; //Array mit Zeilen List <string[]> arPunkte = new List <string[]>(); arPunkte.Clear(); m_lsMP.Clear(); tB_nPTÜbereinstimmung.Text = ""; m_lsMPÜbereinstimmung.Clear(); Editor m_ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor; if (ddOpenFile.ShowDialog() == DialogResult.OK) { m_Filename = ddOpenFile.FileName; StreamReader sr = new StreamReader(m_Filename, Encoding.Default); m_Text = sr.ReadToEnd(); sr.Close(); m_Extention = m_Filename.Substring(m_Filename.LastIndexOf('.') + 1).ToLower(); string[] arZeile; int iZeile = 1; switch (m_Extention) { case "csv": arText = m_Text.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); //Zeilen von MP in Array einfügen foreach (string Zeile in arText) { arZeile = Zeile.Split(new char[] { ';' }, StringSplitOptions.None); arPunkte.Add(arZeile); } foreach (string[] Zeile in arPunkte) { string PNum; double Rechtswert = new double(); double Hochwert = new double(); double Höhe = new double(); double?Höhenwert = null; bool bFehler = false; Autodesk.AutoCAD.Runtime.ErrorStatus es; PNum = Zeile[0]; if (m_Util.convertToDouble(Zeile[1], ref Rechtswert, iZeile) != Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { bFehler = true; } if (m_Util.convertToDouble(Zeile[2], ref Hochwert, iZeile) != Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { bFehler = true; } es = m_Util.convertToDouble(Zeile[3], ref Höhe, iZeile); if (es == Autodesk.AutoCAD.Runtime.ErrorStatus.OK) { Höhenwert = Höhe; } if (es != Autodesk.AutoCAD.Runtime.ErrorStatus.OK || es != Autodesk.AutoCAD.Runtime.ErrorStatus.NullPtr) { bFehler = false; } //Nachkommastellen Höhe myAutoCAD.myUtilities objUtil = new myAutoCAD.myUtilities(); int Precision = objUtil.Precision(Zeile[3]); if (!bFehler) { myAutoCAD.Messpunkt objMP = new Messpunkt(PNum, Rechtswert, Hochwert, Höhenwert, Höhenwert, Precision); objMP.Att4_Wert = myUtilities.Global.Owner; m_lsMP.Add(objMP); } iZeile++; } //Bestimmen der Punkte mit Übereinstimmung Punktdatenfile mit Zeichnung foreach (Messpunkt MP in m_lsMP) { Messpunkt objMP = new Messpunkt(); if (m_Blöcke.findPos(ref objMP, new Autodesk.AutoCAD.Geometry.Point2d(MP.Position.X, MP.Position.Y), 0.01) == ErrorStatus.OK) { m_lsMPÜbereinstimmung.Add(objMP); } } //Ausgabe Dialogbox tB_PTFilename.Text = m_Filename; tb_nPunkteFile.Text = m_lsMP.Count.ToString(); tB_nPTÜbereinstimmung.Text = m_lsMPÜbereinstimmung.Count.ToString(); if (m_lsMPÜbereinstimmung.Count > 0) { bt_markieren.Enabled = true; bt_löschen.Enabled = true; } break; } } }