source: ntrip/branches/BNC_2.12/src/reqcdlg.cpp@ 9336

Last change on this file since 9336 was 8632, checked in by stuerze, 6 years ago

some updates to support RINEX Version 3.04

File size: 21.1 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: reqcDlg
30 *
31 * Purpose: Displays the teqc-like editing options
32 *
33 * Author: L. Mervart
34 *
35 * Created: 28-Mar-2012
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <iostream>
42
43#include "reqcdlg.h"
44#include "bncsettings.h"
45
46using namespace std;
47
48
49// Constructor
50////////////////////////////////////////////////////////////////////////////
51reqcDlg::reqcDlg(QWidget* parent) : QDialog(parent) {
52
53 setWindowTitle(tr("RINEX Editing Options"));
54
55 int ww = QFontMetrics(font()).width('w');
56
57 const QString timeFmtString = "yyyy-MM-dd hh:mm:ss";
58
59 _reqcRnxVersion = new QComboBox(this);
60 _reqcSampling = new QComboBox(this);
61 _reqcStartDateTime = new QDateTimeEdit(this);
62 _reqcStartDateTime->setDisplayFormat(timeFmtString);
63 _reqcEndDateTime = new QDateTimeEdit(this);
64 _reqcEndDateTime->setDisplayFormat(timeFmtString);
65 _reqcRunBy = new QLineEdit(this);
66 _reqcUseObsTypes = new QLineEdit(this);
67 _reqcComment = new QLineEdit(this);
68 _reqcOldMarkerName = new QLineEdit(this);
69 _reqcNewMarkerName = new QLineEdit(this);
70 _reqcOldAntennaName = new QLineEdit(this);
71 _reqcNewAntennaName = new QLineEdit(this);
72 _reqcOldAntennaNumber = new QLineEdit(this);
73 _reqcNewAntennaNumber = new QLineEdit(this);
74 _reqcOldAntennadN = new QLineEdit(this);
75 _reqcNewAntennadN = new QLineEdit(this);
76 _reqcOldAntennadE = new QLineEdit(this);
77 _reqcNewAntennadE = new QLineEdit(this);
78 _reqcOldAntennadU = new QLineEdit(this);
79 _reqcNewAntennadU = new QLineEdit(this);
80 _reqcOldReceiverName = new QLineEdit(this);
81 _reqcNewReceiverName = new QLineEdit(this);
82 _reqcOldReceiverNumber = new QLineEdit(this);
83 _reqcNewReceiverNumber = new QLineEdit(this);
84
85 _reqcRnxVersion->setEditable(false);
86 _reqcRnxVersion->addItems(QString("2,3").split(","));
87 _reqcRnxVersion->setMaximumWidth(7*ww);
88
89 _reqcSampling->setEditable(false);
90 _reqcSampling->addItems(QString("0.1 sec,1 sec,5 sec,10 sec,15 sec,30 sec,60 sec").split(","));
91 bncSettings settings;
92 int ll = _reqcSampling->findText(settings.value("reqcSampling").toString());
93 if (ll != -1) {
94 _reqcSampling->setCurrentIndex(ll);
95 }
96
97 // Read Options
98 // ------------
99 int kk = _reqcRnxVersion->findText(settings.value("reqcRnxVersion").toString());
100 if (kk != -1) {
101 _reqcRnxVersion->setCurrentIndex(kk);
102 }
103 _reqcSampling->findText(settings.value("reqcSampling").toString());
104 if (settings.value("reqcStartDateTime").toString().isEmpty()) {
105 _reqcStartDateTime->setDateTime(QDateTime::fromString("1967-11-02T00:00:00", Qt::ISODate));
106 }
107 else {
108 _reqcStartDateTime->setDateTime(settings.value("reqcStartDateTime").toDateTime());
109 }
110 if (settings.value("reqcEndDateTime").toString().isEmpty()) {
111 _reqcEndDateTime->setDateTime(QDateTime::fromString("2099-01-01T00:00:00", Qt::ISODate));
112 }
113 else {
114 _reqcEndDateTime->setDateTime(settings.value("reqcEndDateTime").toDateTime());
115 }
116 _reqcRunBy->setText(settings.value("reqcRunBy").toString());
117 _reqcUseObsTypes->setText(settings.value("reqcUseObsTypes").toString());
118 _reqcComment->setText(settings.value("reqcComment").toString());
119 _reqcOldMarkerName->setText(settings.value("reqcOldMarkerName").toString());
120 _reqcNewMarkerName->setText(settings.value("reqcNewMarkerName").toString());
121 _reqcOldAntennaName->setText(settings.value("reqcOldAntennaName").toString());
122 _reqcNewAntennaName->setText(settings.value("reqcNewAntennaName").toString());
123 _reqcOldAntennaNumber->setText(settings.value("reqcOldAntennaNumber").toString());
124 _reqcNewAntennaNumber->setText(settings.value("reqcNewAntennaNumber").toString());
125 _reqcOldAntennadN->setText(settings.value("reqcOldAntennadN").toString());
126 _reqcNewAntennadN->setText(settings.value("reqcNewAntennadN").toString());
127 _reqcOldAntennadE->setText(settings.value("reqcOldAntennadE").toString());
128 _reqcNewAntennadE->setText(settings.value("reqcNewAntennadE").toString());
129 _reqcOldAntennadU->setText(settings.value("reqcOldAntennadU").toString());
130 _reqcNewAntennadU->setText(settings.value("reqcNewAntennadU").toString());
131 _reqcOldReceiverName->setText(settings.value("reqcOldReceiverName").toString());
132 _reqcNewReceiverName->setText(settings.value("reqcNewReceiverName").toString());
133 _reqcOldReceiverNumber->setText(settings.value("reqcOldReceiverNumber").toString());
134 _reqcNewReceiverNumber->setText(settings.value("reqcNewReceiverNumber").toString());
135
136
137 QString hlp = settings.value("reqcV2Priority").toString();
138 if (hlp.isEmpty()) {
139 hlp = "G:12&PWCSLX G:5&IQX R:12&PC R:3&IQX R:46&ABX E:16&BCXZ E:578&IQX J:1&SLXCZ J:26&SLX J:5&IQX C:267&IQX C:128&DPX C:7&DPZ I:ABCX S:1&C S:5&IQX";
140 }
141 _reqcV2Priority = new QLineEdit(hlp);
142
143 // Dialog Layout
144 // -------------
145 QGridLayout* grid = new QGridLayout;
146
147 int ir = 0;
148 grid->addWidget(new QLabel("RINEX Version"), ir, 1);
149 grid->addWidget(_reqcRnxVersion, ir, 2);
150 grid->addWidget(new QLabel("Sampling"), ir, 3, Qt::AlignRight);
151 grid->addWidget(_reqcSampling, ir, 4);
152 ++ir;
153 grid->addWidget(new QLabel("Version 2 signal priority"), ir, 1);
154 grid->addWidget(_reqcV2Priority, ir, 2, 1, 4);
155 ++ir;
156 grid->addWidget(new QLabel("Start"), ir, 1);
157 grid->addWidget(_reqcStartDateTime, ir, 2);
158 grid->addWidget(new QLabel("End"), ir, 3, Qt::AlignRight);
159 grid->addWidget(_reqcEndDateTime, ir, 4);
160 ++ir;
161 grid->addWidget(new QLabel("Run By"), ir, 0);
162 grid->addWidget(_reqcRunBy, ir, 1);
163 ++ir;
164 grid->addWidget(new QLabel("Use Obs. Types"), ir, 0);
165 grid->addWidget(_reqcUseObsTypes, ir, 1, 1, 4);
166 ++ir;
167 grid->addWidget(new QLabel("Comment(s)"), ir, 0);
168 grid->addWidget(_reqcComment, ir, 1, 1, 4);
169 ++ir;
170 grid->addWidget(new QLabel("Old"), ir, 1, 1, 2, Qt::AlignCenter);
171 grid->addWidget(new QLabel("New"), ir, 3, 1, 2, Qt::AlignCenter);
172 ++ir;
173 grid->addWidget(new QLabel("Marker Name"), ir, 0);
174 grid->addWidget(_reqcOldMarkerName, ir, 1, 1, 2);
175 grid->addWidget(_reqcNewMarkerName, ir, 3, 1, 2);
176 ++ir;
177 grid->addWidget(new QLabel("Antenna Name"), ir, 0);
178 grid->addWidget(_reqcOldAntennaName, ir, 1, 1, 2);
179 grid->addWidget(_reqcNewAntennaName, ir, 3, 1, 2);
180 ++ir;
181 grid->addWidget(new QLabel("Antenna Number"), ir, 0);
182 grid->addWidget(_reqcOldAntennaNumber, ir, 1, 1, 2);
183 grid->addWidget(_reqcNewAntennaNumber, ir, 3, 1, 2);
184 ++ir;
185 grid->addWidget(new QLabel("Antenna ecc. dN"), ir, 0);
186 grid->addWidget(_reqcOldAntennadN, ir, 1, 1, 2);
187 grid->addWidget(_reqcNewAntennadN, ir, 3, 1, 2);
188 ++ir;
189 grid->addWidget(new QLabel("Antenna ecc. dE"), ir, 0);
190 grid->addWidget(_reqcOldAntennadE, ir, 1, 1, 2);
191 grid->addWidget(_reqcNewAntennadE, ir, 3, 1, 2);
192 ++ir;
193 grid->addWidget(new QLabel("Antenna ecc. dU"), ir, 0);
194 grid->addWidget(_reqcOldAntennadU, ir, 1, 1, 2);
195 grid->addWidget(_reqcNewAntennadU, ir, 3, 1, 2);
196 ++ir;
197 grid->addWidget(new QLabel("Receiver Name"), ir, 0);
198 grid->addWidget(_reqcOldReceiverName, ir, 1, 1, 2);
199 grid->addWidget(_reqcNewReceiverName, ir, 3, 1, 2);
200 ++ir;
201 grid->addWidget(new QLabel("Receiver Number"), ir, 0);
202 grid->addWidget(_reqcOldReceiverNumber, ir, 1, 1, 2);
203 grid->addWidget(_reqcNewReceiverNumber, ir, 3, 1, 2);
204
205
206 slotReqcTextChanged();
207 connect(_reqcRnxVersion, SIGNAL(currentIndexChanged(const QString &)),
208 this, SLOT(slotReqcTextChanged()));
209
210 _buttonWhatsThis = new QPushButton(tr("Help=Shift+F1"), this);
211 connect(_buttonWhatsThis, SIGNAL(clicked()), this, SLOT(slotWhatsThis()));
212
213 _buttonOK = new QPushButton(tr("OK / Save"), this);
214 connect(_buttonOK, SIGNAL(clicked()), this, SLOT(slotOK()));
215
216 _buttonCancel = new QPushButton(tr("Cancel"), this);
217 connect(_buttonCancel, SIGNAL(clicked()), this, SLOT(close()));
218
219 QHBoxLayout* buttonLayout = new QHBoxLayout;
220 buttonLayout->addWidget(_buttonWhatsThis);
221 buttonLayout->addStretch(1);
222 buttonLayout->addWidget(_buttonOK);
223 buttonLayout->addWidget(_buttonCancel);
224
225 QVBoxLayout* mainLayout = new QVBoxLayout(this);
226 mainLayout->addLayout(grid);
227 mainLayout->addLayout(buttonLayout);
228
229 // WhatsThis, RINEX Editing & QC
230 // -----------------------------
231 _reqcRnxVersion->setWhatsThis(tr("<p>Select version number of emerging new RINEX file.</p><p>Note the following:</p><p>When converting <u>RINEX Version 2 to Version 3 </u>Observation files, the tracking mode or channel information (signal attribute, see RINEX Version 3 documentation) in the (last out of the three characters) observation code is left blank if unknown.</p><p>When converting <u>RINEX Version 3 to Version 2</u>, the mapping of observations follows a 'Signal priority list' with signal attributes as defined in RINEX Version 3.</p>"));
232 _reqcSampling->setWhatsThis(tr("<p>Select sampling rate of emerging new RINEX Observation file.</p>"));
233 _reqcV2Priority->setWhatsThis(tr("<p>Specify a priority list of characters defining signal attributes as defined in RINEX Version 3. Priorities will be used to map observations with RINEX Version 3 attributes from incoming streams to Version 2. The underscore character '_' stands for undefined attributes. A question mark '?' can be used as wildcard which represents any one character.</p><p>Signal priorities can be specified as equal for all systems, as system specific or as system and freq. specific. For example: </li><ul><li>'CWPX_?' (General signal priorities valid for all GNSS) </li><li>'C:IQX I:ABCX' (System specific signal priorities for BDS and IRNSS) </li><li>'G:12&PWCSLXYN G:5&IQX R:12&PC R:3&IQX' (System and frequency specific signal priorities) </li></ul>Default is the following priority list 'G:12&PWCSLX G:5&IQX R:12&PC R:3&IQX R:46&ABX E:16&BCXZ E:578&IQX J:1&SLXCZ J:26&SLX J:5&IQX C:267&IQX C:128&DPX C:7&DPZ I:ABCX S:1&C S:5&IQX'.</p>"));
234 _reqcStartDateTime->setWhatsThis(tr("<p>Specify begin of emerging new RINEX Observation file.</p>"));
235 _reqcEndDateTime->setWhatsThis(tr("<p>Specify end of emerging new RINEX Observation file.</p>"));
236 _reqcRunBy->setWhatsThis(tr("<p>Specify a 'RUN BY' string to be included in the emerging new RINEX file header.</p><p>Default is an empty option field, meaning the operator's user ID is used as 'RUN BY' string.</p>"));
237 _reqcComment->setWhatsThis(tr("<p>Specifying a comment line text to be added to the emerging new RINEX file header is an option. Any introduction of newline specification '\\n' in this enforces the beginning of a further comment line. Comment line(s) will be added to the header after the 'PGM / RUN BY / DATE' record.</p><p>Default is an empty option field meaning that no additional comment line is added to the RINEX header.</p>"));
238 _reqcUseObsTypes->setWhatsThis(tr("<p>This option lets you limit the RINEX output to specific observation types. Examples:</p><p><ul><li>G:C1C G:L1C R:C1C R:C1P S:C1C C:C1I C:L1I E:C1X E:L1X<br>(Valid for output of RINEX Version 3; output contains GPS C1C and L1C, GLONASS C1C and C1P, SBAS C1C, BeiDou C1C, C1I andL1I, Galileo C1X and L1X.)</li><li>C1 L2 L5<br>(Valid for output of RINEX Version 2 with mapping of Version 3 signals to Version 2 according to 'Version 2 Signal Priority'; output contains C1, L2 and L5 observations from any GNSS system.)</li></ul></p><p>Default is an empty option field, meaning that the RINEX output file contains all observations made available through RINEX input file.</p>"));
239 _reqcOldMarkerName->setWhatsThis(tr("<p>Enter old Marker Name in RINEX Observation file.</p><p>Default is an empty option field.</p>"));
240 _reqcNewMarkerName->setWhatsThis(tr("<p>Enter new Marker Name in RINEX Observation file.</p><p>If option 'Old Marker Name' is either left blank or its content is specified as given in the RINEX input file, then the marker name in the RINEX output file will be specified by 'New Marker Name'</p><p>Default is an empty option field, meaning that the content of the Marker Name data field in the RINEX file will not be changed.</p>"));
241 _reqcOldAntennaName->setWhatsThis(tr("<p>Enter old Antenna Name in RINEX Observation file.</p><p>Default is an empty option field.</p>"));
242 _reqcNewAntennaName->setWhatsThis(tr("<p>Enter new Antenna Name in RINEX Observation file.</p><p>If option 'Old Antenna Name' is either left blank or its content is specified as given in the RINEX input file, then the antenna name in the RINEX output file will be specified by 'New Antenna Name'</p><p>Default is an empty option field, meaning that the content of the Antenna Name data field in the RINEX file will not be changed.</p>"));
243 _reqcOldAntennaNumber->setWhatsThis(tr("<p>Enter old Antenna Number in RINEX Observation file.</p><p>Default is an empty option field.</p>"));
244 _reqcNewAntennaNumber->setWhatsThis(tr("<p>Enter new Antenna Number in RINEX Observation file.</p><p>If option 'Old Antenna Number' is either left blank or its content is specified as given in the RINEX input file, then the antenna number in the RINEX output file will be specified by 'New Antenna Number'</p><p>Default is an empty option field, meaning that the content of the Antenna Number data field in the RINEX file will not be changed.</p>"));
245 _reqcOldAntennadN->setWhatsThis(tr("<p>Enter old North Antenna Eccentricity in RINEX Observation file.</p><p>Default is an empty option field.</p>"));
246 _reqcNewAntennadN->setWhatsThis(tr("<p>Enter new North Antenna Eccentricity in RINEX Observation file.</p><p>If option 'Old Antenna North Eccentricity' is either left blank or its content is specified as given in the RINEX input file, then the north antenna eccentricity in the RINEX output file will be specified by 'New North Antenna Eccentricity'</p><p>Default is an empty option field, meaning that the content of the North Antenna Eccentricity data field in the RINEX file will not be changed.</p>"));
247 _reqcOldAntennadE->setWhatsThis(tr("<p>Enter old East Antenna Eccentricity in RINEX Observation file.</p><p>Default is an empty option field.</p>"));
248 _reqcNewAntennadE->setWhatsThis(tr("<p>Enter new East Antenna Eccentricity in RINEX Observation file.</p><p>If option 'Old Antenna East Eccentricity' is either left blank or its content is specified as given in the RINEX input file, then the east antenna eccentricity in the RINEX output file will be specified by 'New East Antenna Eccentricity'</p><p>Default is an empty option field, meaning that the content of the East Antenna Eccentricity data field in the RINEX file will not be changed.</p>"));
249 _reqcOldAntennadU->setWhatsThis(tr("<p>Enter old Up Antenna Eccentricity in RINEX Observation file.</p><p>Default is an empty option field.</p>"));
250 _reqcNewAntennadU->setWhatsThis(tr("<p>Enter new Up Antenna Eccentricity in RINEX Observation file.</p><p>If option 'Old Antenna Up Eccentricity' is either left blank or its content is specified as given in the RINEX input file, then the up antenna eccentricity in the RINEX output file will be specified by 'New Up Antenna Eccentricity'</p><p>Default is an empty option field, meaning that the content of the Up Antenna Eccentricity data field in the RINEX file will not be changed.</p>"));
251 _reqcOldReceiverName->setWhatsThis(tr("<p>Enter old Receiver Name in RINEX Observation file.<p>Default is an empty option field.</p></p>"));
252 _reqcNewReceiverName->setWhatsThis(tr("<p>Enter new Receiver Name in RINEX Observation file.</p><p>If option 'Old Receiver Name' is either left blank or its content is specified as given in the RINEX input file, then the receiver name in the RINEX output file will be specified by 'New Receiver Name'</p><p>Default is an empty option field, meaning that the content of the Receiver Name data field in the RINEX file will not be changed.</p>"));
253 _reqcOldReceiverNumber->setWhatsThis(tr("<p>Enter old Receiver Number in RINEX Observation file.<p>Default is an empty option field.</p></p>"));
254 _reqcNewReceiverNumber->setWhatsThis(tr("<p>Enter new Receiver Number in RINEX Observation file.</p><p>If option 'Old Receiver Number' is either left blank or its content is specified as given in the RINEX input file, then the receiver number in the RINEX output file will be specified by 'New Receiver Number'</p><p>Default is an empty option field, meaning that the content of the Receiver Number data field in the RINEX file will not be changed.</p>"));
255}
256
257// Destructor
258////////////////////////////////////////////////////////////////////////////
259reqcDlg::~reqcDlg() {
260 delete _buttonOK;
261 delete _buttonCancel;
262 delete _buttonWhatsThis;
263}
264
265// Accept the Options
266////////////////////////////////////////////////////////////////////////////
267void reqcDlg::slotOK() {
268 saveOptions();
269 done(0);
270}
271
272// Whats This Help
273////////////////////////////////////////////////////////////////////////////
274void reqcDlg::slotWhatsThis() {
275 QWhatsThis::enterWhatsThisMode();
276}
277
278// Close Dialog gracefully
279////////////////////////////////////////////////////////////////////////////
280void reqcDlg::closeEvent(QCloseEvent* event) {
281
282 int iRet = QMessageBox::question(this, "Close", "Save Options?",
283 QMessageBox::Yes, QMessageBox::No,
284 QMessageBox::Cancel);
285
286 if (iRet == QMessageBox::Cancel) {
287 event->ignore();
288 return;
289 }
290 else if (iRet == QMessageBox::Yes) {
291 saveOptions();
292 }
293
294 QDialog::closeEvent(event);
295}
296
297// Save Selected Options
298////////////////////////////////////////////////////////////////////////////
299void reqcDlg::saveOptions() {
300
301 bncSettings settings;
302
303 settings.setValue("reqcRnxVersion" , _reqcRnxVersion->currentText());
304 settings.setValue("reqcSampling" , _reqcSampling->currentText());
305 settings.setValue("reqcV2Priority" , _reqcV2Priority->text());
306 settings.setValue("reqcStartDateTime" , _reqcStartDateTime->dateTime().toString(Qt::ISODate));
307 settings.setValue("reqcEndDateTime" , _reqcEndDateTime->dateTime().toString(Qt::ISODate));
308 settings.setValue("reqcRunBy" , _reqcRunBy->text());
309 settings.setValue("reqcUseObsTypes" , _reqcUseObsTypes->text());
310 settings.setValue("reqcComment" , _reqcComment->text());
311 settings.setValue("reqcOldMarkerName" , _reqcOldMarkerName->text());
312 settings.setValue("reqcNewMarkerName" , _reqcNewMarkerName->text());
313 settings.setValue("reqcOldAntennaName" , _reqcOldAntennaName->text());
314 settings.setValue("reqcNewAntennaName" , _reqcNewAntennaName->text());
315 settings.setValue("reqcOldAntennaNumber" , _reqcOldAntennaNumber->text());
316 settings.setValue("reqcNewAntennaNumber" , _reqcNewAntennaNumber->text());
317 settings.setValue("reqcOldAntennadN" , _reqcOldAntennadN->text());
318 settings.setValue("reqcNewAntennadN" , _reqcNewAntennadN->text());
319 settings.setValue("reqcOldAntennadE" , _reqcOldAntennadE->text());
320 settings.setValue("reqcNewAntennadE" , _reqcNewAntennadE->text());
321 settings.setValue("reqcOldAntennadU" , _reqcOldAntennadU->text());
322 settings.setValue("reqcNewAntennadU" , _reqcNewAntennadU->text());
323 settings.setValue("reqcNewAntennaNumber" , _reqcNewAntennaNumber->text());
324 settings.setValue("reqcOldReceiverName" , _reqcOldReceiverName->text());
325 settings.setValue("reqcNewReceiverName" , _reqcNewReceiverName->text());
326 settings.setValue("reqcOldReceiverNumber", _reqcOldReceiverNumber->text());
327 settings.setValue("reqcNewReceiverNumber", _reqcNewReceiverNumber->text());
328}
329
330// Reqc Text Changed
331////////////////////////////////////////////////////////////////////////////
332void reqcDlg::slotReqcTextChanged(){
333
334 const static QPalette paletteWhite(QColor(255, 255, 255));
335 const static QPalette paletteGray(QColor(230, 230, 230));
336
337 if (sender() == 0 || sender() == _reqcRnxVersion) {
338 if (_reqcRnxVersion->currentText() == "2") {
339 _reqcV2Priority->setPalette(paletteWhite);
340 _reqcV2Priority->setEnabled(true);
341 }
342 else {
343 _reqcV2Priority->setPalette(paletteGray);
344 _reqcV2Priority->setEnabled(false);
345 }
346 }
347}
348
Note: See TracBrowser for help on using the repository browser.