File indexing completed on 2025-01-19 13:27:30
0001 /* 0002 This file is part of the KDE project 0003 Copyright (C) 2002 Fred Malabre <fmalabre@yahoo.com> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KSpreadLeader.h" 0022 0023 using namespace KSpread; 0024 0025 Leader::Leader(KoFilterChain *filterChain) 0026 { 0027 m_worker = nullptr; 0028 m_filterChain = filterChain; 0029 } 0030 0031 0032 Leader::Leader(KoFilterChain *filterChain, KSpreadBaseWorker *newWorker) 0033 { 0034 m_worker = newWorker; 0035 m_filterChain = filterChain; 0036 } 0037 0038 0039 Leader::~Leader() 0040 { 0041 } 0042 0043 0044 KSpreadBaseWorker *Leader::getWorker() const 0045 { 0046 return m_worker; 0047 } 0048 0049 0050 void Leader::setWorker(KSpreadBaseWorker *newWorker) 0051 { 0052 m_worker = newWorker; 0053 } 0054 0055 0056 KoFilter::ConversionStatus Leader::convert() 0057 { 0058 KoFilter::ConversionStatus status; 0059 0060 // Validate the filter chain and the worker 0061 if (!m_filterChain) { 0062 kWarning(30508) << "koFilterChain is NULL!"; 0063 return KoFilter::StupidError; 0064 } 0065 if (!m_worker) { 0066 kWarning(30508) << "the KSpreadWorker is NULL!"; 0067 return KoFilter::StupidError; 0068 } 0069 0070 // Gather data about the filter itself 0071 KSpreadFilterProperty docProperty; 0072 docProperty["outputfile"] = m_filterChain->outputFile(); 0073 status = m_worker->startDocument(docProperty); 0074 if (status != KoFilter::OK) 0075 return status; 0076 0077 // Get the document in memory 0078 KSpreadDoc *document = (KSpreadDoc *) m_filterChain->inputDocument(); 0079 if (!document) { 0080 kWarning(30508) << "the KSpreadDoc is NULL!"; 0081 return KoFilter::StupidError; 0082 } 0083 if (!::qt_cast<const KSpread::Doc *>(document)) { 0084 kWarning(30508) << "the document is not a KSpreadDoc!"; 0085 return KoFilter::StupidError; 0086 } 0087 if (document->mimeType() != "application/x-kspread") { 0088 kWarning(30508) << "the mime type document is not application/x-kspread!"; 0089 return KoFilter::StupidError; 0090 } 0091 KoDocumentInfo *info = document->documentInfo(); 0092 if (!info) { 0093 kWarning(30508) << "the KoDocumentInfo is NULL!"; 0094 return KoFilter::StupidError; 0095 } 0096 0097 // Gather data about the document info 0098 status = doInfo(info); 0099 if (status != KoFilter::OK) 0100 return status; 0101 0102 // Gather data about the spread book 0103 status = doSpreadBook(document); 0104 if (status != KoFilter::OK) 0105 return status; 0106 0107 // Gather data about the spread sheet 0108 KSpreadSheet *spreadSheet = document->map()->firstTable(); 0109 while (spreadSheet != 0) { 0110 status = doSpreadSheet(spreadSheet); 0111 if (status != KoFilter::OK) 0112 return status; 0113 0114 // Gather data about the cell 0115 for (int row = 1; row <= m_maxCellRow; ++row) { 0116 for (int column = 1; column <= m_maxCellColumn; ++column) { 0117 Cell spreadCell(spreadSheet, column, row); 0118 status = doSpreadCell(spreadCell, column, row); 0119 if (status != KoFilter::OK) 0120 return status; 0121 } 0122 } 0123 0124 spreadSheet = document->map()->nextTable(); 0125 } 0126 0127 return status; 0128 } 0129 0130 0131 KoFilter::ConversionStatus Leader::doInfo(KoDocumentInfo *info) 0132 { 0133 KoFilter::ConversionStatus status; 0134 0135 #if 0 // this was never used, it's been removed now 0136 // Gather data about the document log 0137 KSpreadFilterProperty docInfoLogProperty; 0138 KoDocumentInfoLog *infoLog = (KoDocumentInfoLog *) info->page("log"); 0139 docInfoLogProperty["oldlog"] = infoLog->oldLog(); 0140 docInfoLogProperty["newlog"] = infoLog->newLog(); 0141 status = m_worker->startInfoLog(docInfoLogProperty); 0142 if (status != KoFilter::OK) 0143 return status; 0144 #endif 0145 0146 // Gather data about the document author 0147 KSpreadFilterProperty docInfoAuthorProperty; 0148 KoDocumentInfoAuthor *infoAuthor = (KoDocumentInfoAuthor *) info->page("author"); 0149 docInfoAuthorProperty["fullname"] = infoAuthor->fullName(); 0150 docInfoAuthorProperty["initial"] = infoAuthor->initial(); 0151 docInfoAuthorProperty["title"] = infoAuthor->title(); 0152 docInfoAuthorProperty["company"] = infoAuthor->company(); 0153 docInfoAuthorProperty["email"] = infoAuthor->email(); 0154 docInfoAuthorProperty["telephone"] = infoAuthor->telephone(); 0155 docInfoAuthorProperty["fax"] = infoAuthor->fax(); 0156 docInfoAuthorProperty["country"] = infoAuthor->country(); 0157 docInfoAuthorProperty["postalcode"] = infoAuthor->postalCode(); 0158 docInfoAuthorProperty["city"] = infoAuthor->city(); 0159 docInfoAuthorProperty["street"] = infoAuthor->street(); 0160 status = m_worker->startInfoAuthor(docInfoAuthorProperty); 0161 if (status != KoFilter::OK) 0162 return status; 0163 0164 // Gather data about the document about 0165 KSpreadFilterProperty docInfoAboutProperty; 0166 KoDocumentInfoAbout *infoAbout = (KoDocumentInfoAbout *) info->page("about"); 0167 docInfoAboutProperty["title"] = infoAbout->title(); 0168 docInfoAboutProperty["author"] = infoAbout->abstract(); 0169 status = m_worker->startInfoAbout(docInfoAboutProperty); 0170 return status; 0171 } 0172 0173 0174 KoFilter::ConversionStatus Leader::doSpreadBook(KSpreadDoc *document) 0175 { 0176 KSpreadFilterProperty docSpreadBookProperty; 0177 docSpreadBookProperty["spreadsheetcount"] = QString::number(document->map()->count()); 0178 docSpreadBookProperty["decimalsymbol"] = document->locale()->decimalSymbol(); 0179 docSpreadBookProperty["thousandsseparator"] = document->locale()->thousandsSeparator(); 0180 docSpreadBookProperty["currencysymbol"] = document->locale()->currencySymbol(); 0181 docSpreadBookProperty["monetarydecimalsymbol"] = document->locale()->monetaryDecimalSymbol(); 0182 docSpreadBookProperty["monetarythousandsseparator"] = document->locale()->monetaryThousandsSeparator(); 0183 docSpreadBookProperty["positivesign"] = document->locale()->positiveSign(); 0184 docSpreadBookProperty["negativesign"] = document->locale()->negativeSign(); 0185 docSpreadBookProperty["fracdigits"] = QString::number(document->locale()->fracDigits()); 0186 docSpreadBookProperty["positiveprefixcurrencysymbol"] = (document->locale()->positivePrefixCurrencySymbol() == 0 ? "false" : "true"); 0187 docSpreadBookProperty["negativeprefixcurrencysymbol"] = (document->locale()->negativePrefixCurrencySymbol() == 0 ? "false" : "true"); 0188 docSpreadBookProperty["use12clock"] = (document->locale()->use12Clock() == 0 ? "false" : "true"); 0189 docSpreadBookProperty["weekstartsmonday"] = (document->locale()->weekStartsMonday() == 0 ? "false" : "true"); 0190 docSpreadBookProperty["weekstartday"] = QString::number(document->locale()->weekStartDay()); 0191 docSpreadBookProperty["language"] = document->locale()->language(); 0192 docSpreadBookProperty["country"] = document->locale()->country(); 0193 docSpreadBookProperty["encoding"] = document->locale()->encoding(); 0194 docSpreadBookProperty["dateformat"] = document->locale()->dateFormat(); 0195 docSpreadBookProperty["dateformatshort"] = document->locale()->dateFormatShort(); 0196 docSpreadBookProperty["timeformat"] = document->locale()->timeFormat(); 0197 docSpreadBookProperty["defaultlanguage"] = KLocale::defaultLanguage(); 0198 docSpreadBookProperty["defaultcountry"] = KLocale::defaultCountry(); 0199 docSpreadBookProperty["defaultgridpencolorname"] = document->defaultGridPen().color().name(); 0200 docSpreadBookProperty["defaultgridpencolorred"] = QString::number(document->defaultGridPen().color().Qt::red()); 0201 docSpreadBookProperty["defaultgridpencolorgreen"] = QString::number(document->defaultGridPen().color().Qt::green()); 0202 docSpreadBookProperty["defaultgridpencolorblue"] = QString::number(document->defaultGridPen().color().Qt::blue()); 0203 docSpreadBookProperty["defaultgridpenwidth"] = QString::number(document->defaultGridPen().width()); 0204 docSpreadBookProperty["showverticalscrollbar"] = (document->getShowVerticalScrollBar() == 0 ? "false" : "true"); 0205 docSpreadBookProperty["showhorizontalscrollbar"] = (document->getShowHorizontalScrollBar() == 0 ? "false" : "true"); 0206 docSpreadBookProperty["showcolheader"] = (document->getShowColHeader() == 0 ? "false" : "true"); 0207 docSpreadBookProperty["showrowheader"] = (document->getShowRowHeader() == 0 ? "false" : "true"); 0208 docSpreadBookProperty["indentvalue"] = QString::number(document->getIndentValue()); 0209 docSpreadBookProperty["movetovalue"] = QString::number(document->getMoveToValue()); 0210 docSpreadBookProperty["showmessageerror"] = (document->getShowMessageError() == 0 ? "false" : "true"); 0211 docSpreadBookProperty["showtabbar"] = (document->getShowTabBar() == 0 ? "false" : "true"); 0212 docSpreadBookProperty["pagebordercolorname"] = document->pageBorderColor().name(); 0213 docSpreadBookProperty["pagebordercolorred"] = QString::number(document->pageBorderColor().Qt::red()); 0214 docSpreadBookProperty["pagebordercolorgreen"] = QString::number(document->pageBorderColor().Qt::green()); 0215 docSpreadBookProperty["pagebordercolorblue"] = QString::number(document->pageBorderColor().Qt::blue()); 0216 docSpreadBookProperty["showcommentindicator"] = (document->getShowCommentIndicator() == 0 ? "false" : "true"); 0217 docSpreadBookProperty["showformulabar"] = (document->getShowFormulaBar() == 0 ? "false" : "true"); 0218 docSpreadBookProperty["dontcheckupperword"] = (document->dontCheckUpperWord() == 0 ? "false" : "true"); 0219 docSpreadBookProperty["dontchecktitlecase"] = (document->dontCheckTitleCase() == 0 ? "false" : "true"); 0220 docSpreadBookProperty["showstatusbar"] = (document->getShowStatusBar() == 0 ? "false" : "true"); 0221 docSpreadBookProperty["unitname"] = document->getUnitName(); 0222 docSpreadBookProperty["syntaxversion"] = QString::number(document->syntaxVersion()); 0223 return m_worker->startSpreadBook(docSpreadBookProperty); 0224 } 0225 0226 0227 KoFilter::ConversionStatus Leader::doSpreadSheet(KSpreadSheet *spreadSheet) 0228 { 0229 KSpreadFilterProperty docSpreadSheetProperty; 0230 docSpreadSheetProperty["name"] = spreadSheet->tableName(); 0231 docSpreadSheetProperty["sizemaxx"] = QString::number(spreadSheet->sizeMaxX()); 0232 docSpreadSheetProperty["sizemaxy"] = QString::number(spreadSheet->sizeMaxY()); 0233 docSpreadSheetProperty["showgrid"] = (spreadSheet->getShowGrid() == 0 ? "false" : "true"); 0234 docSpreadSheetProperty["showformula"] = (spreadSheet->getShowFormula() == 0 ? "false" : "true"); 0235 docSpreadSheetProperty["showformulaindicator"] = (spreadSheet->getShowFormulaIndicator() == 0 ? "false" : "true"); 0236 docSpreadSheetProperty["lcmode"] = (spreadSheet->getLcMode() == 0 ? "false" : "true"); 0237 docSpreadSheetProperty["autocalc"] = (spreadSheet->isAutomaticCalculationEnabled() == 0 ? "false" : "true"); 0238 docSpreadSheetProperty["showcolumnnumber"] = (spreadSheet->getShowColumnNumber() == 0 ? "false" : "true"); 0239 docSpreadSheetProperty["hidezero"] = (spreadSheet->getHideZero() == 0 ? "false" : "true"); 0240 docSpreadSheetProperty["firstletterupper"] = (spreadSheet->getFirstLetterUpper() == 0 ? "false" : "true"); 0241 docSpreadSheetProperty["ishidden"] = (spreadSheet->isHidden() == 0 ? "false" : "true"); 0242 docSpreadSheetProperty["showpageborders"] = (spreadSheet->isShowPageOutline() == 0 ? "false" : "true"); 0243 docSpreadSheetProperty["printablewidth"] = QString::number(spreadSheet->printableWidth()); 0244 docSpreadSheetProperty["printableheight"] = QString::number(spreadSheet->printableHeight()); 0245 docSpreadSheetProperty["paperwidth"] = QString::number(spreadSheet->paperWidth()); 0246 docSpreadSheetProperty["paperheight"] = QString::number(spreadSheet->paperHeight()); 0247 docSpreadSheetProperty["leftborder"] = QString::number(spreadSheet->leftBorder()); 0248 docSpreadSheetProperty["rightborder"] = QString::number(spreadSheet->rightBorder()); 0249 docSpreadSheetProperty["topborder"] = QString::number(spreadSheet->topBorder()); 0250 docSpreadSheetProperty["bottomborder"] = QString::number(spreadSheet->bottomBorder()); 0251 docSpreadSheetProperty["headleft"] = spreadSheet->headLeft(); 0252 docSpreadSheetProperty["headmid"] = spreadSheet->headMid(); 0253 docSpreadSheetProperty["headright"] = spreadSheet->headRight(); 0254 docSpreadSheetProperty["footleft"] = spreadSheet->footLeft(); 0255 docSpreadSheetProperty["footmid"] = spreadSheet->footMid(); 0256 docSpreadSheetProperty["footright"] = spreadSheet->footRight(); 0257 docSpreadSheetProperty["orientation"] = spreadSheet->orientationString(); 0258 docSpreadSheetProperty["paperformat"] = spreadSheet->paperFormatString(); 0259 docSpreadSheetProperty["printgrid"] = (spreadSheet->getPrintGrid() == 0 ? "false" : "true"); 0260 docSpreadSheetProperty["printcomment"] = (spreadSheet->getPrintCommentIndicator() == 0 ? "false" : "true"); 0261 docSpreadSheetProperty["printformula"] = (spreadSheet->getPrintFormulaIndicator() == 0 ? "false" : "true"); 0262 updateMaxCells(spreadSheet); 0263 docSpreadSheetProperty["maxcellrow"] = QString::number(m_maxCellRow); 0264 docSpreadSheetProperty["maxcellcolumn"] = QString::number(m_maxCellColumn); 0265 return m_worker->startSpreadSheet(docSpreadSheetProperty); 0266 } 0267 0268 0269 KoFilter::ConversionStatus Leader::doSpreadCell(const Cell& spreadCell, int column, int row) 0270 { 0271 KSpreadFilterProperty docSpreadCellProperty; 0272 docSpreadCellProperty["column"] = QString::number(column); 0273 docSpreadCellProperty["row"] = QString::number(row); 0274 docSpreadCellProperty["width"] = QString::number(spreadCell->width()); 0275 docSpreadCellProperty["height"] = QString::number(spreadCell->height()); 0276 docSpreadCellProperty["empty"] = (spreadCell->isEmpty() == 0 ? "false" : "true"); 0277 if (!spreadCell->isEmpty()) { 0278 docSpreadCellProperty["text"] = spreadCell->userInput(); 0279 docSpreadCellProperty["strouttext"] = spreadCell->displayText(); 0280 docSpreadCellProperty["action"] = spreadCell->action(); 0281 docSpreadCellProperty["date"] = (spreadCell->isDate() == 0 ? "false" : "true"); 0282 docSpreadCellProperty["time"] = (spreadCell->isTime() == 0 ? "false" : "true"); 0283 docSpreadCellProperty["textwidth"] = QString::number(spreadCell->textWidth()); 0284 docSpreadCellProperty["textheight"] = QString::number(spreadCell->textHeight()); 0285 docSpreadCellProperty["forceextracells"] = (spreadCell->isForceExtraCells() == 0 ? "false" : "true"); 0286 docSpreadCellProperty["mergedxcells"] = QString::number(spreadCell->mergedXCells()); 0287 docSpreadCellProperty["mergedycells"] = QString::number(spreadCell->mergedYCells()); 0288 docSpreadCellProperty["extraxcells"] = QString::number(spreadCell->extraXCells()); 0289 docSpreadCellProperty["extraycells"] = QString::number(spreadCell->extraYCells()); 0290 docSpreadCellProperty["extrawidth"] = QString::number(spreadCell->extraWidth()); 0291 docSpreadCellProperty["extraheight"] = QString::number(spreadCell->extraHeight()); 0292 docSpreadCellProperty["formula"] = (spreadCell->isFormula() == 0 ? "false" : "true"); 0293 docSpreadCellProperty["haserror"] = (spreadCell->hasError() == 0 ? "false" : "true"); 0294 docSpreadCellProperty["alignx"] = QString::number(spreadCell->effectiveAlignX()); 0295 docSpreadCellProperty["name"] = spreadCell->name(); 0296 docSpreadCellProperty["fullname"] = spreadCell->fullName(); 0297 docSpreadCellProperty["content"] = QString::number(spreadCell->content()); 0298 docSpreadCellProperty["style"] = QString::number(spreadCell->style()); 0299 docSpreadCellProperty["valuedate"] = spreadCell->valueDate().toString(); 0300 docSpreadCellProperty["valuetime"] = spreadCell->valueTime().toString(); 0301 docSpreadCellProperty["leftborderwidth"] = QString::number(spreadCell->leftBorderPen(column, row).width()); 0302 docSpreadCellProperty["leftbordercolorname"] = spreadCell->leftBorderPen(column, row).color().name(); 0303 docSpreadCellProperty["leftbordercolorred"] = QString::number(spreadCell->leftBorderPen(column, row).color().Qt::red()); 0304 docSpreadCellProperty["leftbordercolorgreen"] = QString::number(spreadCell->leftBorderPen(column, row).color().Qt::green()); 0305 docSpreadCellProperty["leftbordercolorblue"] = QString::number(spreadCell->leftBorderPen(column, row).color().Qt::blue()); 0306 docSpreadCellProperty["topborderwidth"] = QString::number(spreadCell->topBorderPen(column, row).width()); 0307 docSpreadCellProperty["topbordercolorname"] = spreadCell->topBorderPen(column, row).color().name(); 0308 docSpreadCellProperty["topbordercolorred"] = QString::number(spreadCell->topBorderPen(column, row).color().Qt::red()); 0309 docSpreadCellProperty["topbordercolorgreen"] = QString::number(spreadCell->topBorderPen(column, row).color().Qt::green()); 0310 docSpreadCellProperty["topbordercolorblue"] = QString::number(spreadCell->topBorderPen(column, row).color().Qt::blue()); 0311 docSpreadCellProperty["rightborderwidth"] = QString::number(spreadCell->rightBorderPen(column, row).width()); 0312 docSpreadCellProperty["rightbordercolorname"] = spreadCell->rightBorderPen(column, row).color().name(); 0313 docSpreadCellProperty["rightbordercolorred"] = QString::number(spreadCell->rightBorderPen(column, row).color().Qt::red()); 0314 docSpreadCellProperty["rightbordercolorgreen"] = QString::number(spreadCell->rightBorderPen(column, row).color().Qt::green()); 0315 docSpreadCellProperty["rightbordercolorblue"] = QString::number(spreadCell->rightBorderPen(column, row).color().Qt::blue()); 0316 docSpreadCellProperty["bottomborderwidth"] = QString::number(spreadCell->bottomBorderPen(column, row).width()); 0317 docSpreadCellProperty["bottombordercolorname"] = spreadCell->bottomBorderPen(column, row).color().name(); 0318 docSpreadCellProperty["bottombordercolorred"] = QString::number(spreadCell->bottomBorderPen(column, row).color().Qt::red()); 0319 docSpreadCellProperty["bottombordercolorgreen"] = QString::number(spreadCell->bottomBorderPen(column, row).color().Qt::green()); 0320 docSpreadCellProperty["bottombordercolorblue"] = QString::number(spreadCell->bottomBorderPen(column, row).color().Qt::blue()); 0321 docSpreadCellProperty["bgcolorname"] = spreadCell->bgColor(column, row).name(); 0322 docSpreadCellProperty["bgcolorred"] = QString::number(spreadCell->bgColor(column, row).Qt::red()); 0323 docSpreadCellProperty["bgcolorgreen"] = QString::number(spreadCell->bgColor(column, row).Qt::green()); 0324 docSpreadCellProperty["bgcolorblue"] = QString::number(spreadCell->bgColor(column, row).Qt::blue()); 0325 docSpreadCellProperty["bgbrushstyle"] = QString::number(spreadCell->backGroundBrush(column, row).style()); 0326 docSpreadCellProperty["valueempty"] = (spreadCell->value().isEmpty() == 0 ? "false" : "true"); 0327 docSpreadCellProperty["valueboolean"] = (spreadCell->value().isBoolean() == 0 ? "false" : "true"); 0328 docSpreadCellProperty["valueinteger"] = (spreadCell->value().isInteger() == 0 ? "false" : "true"); 0329 docSpreadCellProperty["valuefloat"] = (spreadCell->value().isFloat() == 0 ? "false" : "true"); 0330 docSpreadCellProperty["valuenumber"] = (spreadCell->value().isNumber() == 0 ? "false" : "true"); 0331 docSpreadCellProperty["valuestring"] = (spreadCell->value().isString() == 0 ? "false" : "true"); 0332 docSpreadCellProperty["valueerror"] = (spreadCell->value().isError() == 0 ? "false" : "true"); 0333 docSpreadCellProperty["valueasboolean"] = (spreadCell->value().asBoolean() == 0 ? "false" : "true"); 0334 docSpreadCellProperty["valueasinteger"] = QString::number(spreadCell->value().asInteger()); 0335 docSpreadCellProperty["valueasfloat"] = QString::number(spreadCell->value().asFloat()); 0336 docSpreadCellProperty["valueasstring"] = spreadCell->value().asString(); 0337 docSpreadCellProperty["valueasdatetime"] = spreadCell->value().asDateTime().toString(); 0338 docSpreadCellProperty["valueaserror"] = spreadCell->value().errorMessage(); 0339 } 0340 return m_worker->startSpreadCell(docSpreadCellProperty); 0341 } 0342 0343 0344 void Leader::updateMaxCells(KSpreadSheet *spreadSheet) 0345 { 0346 m_maxCellColumn = 0; 0347 m_maxCellRow = 0; 0348 0349 int maxColumn = spreadSheet->maxColumn(); 0350 int maxRow = spreadSheet->maxRow(); 0351 0352 // Go through all the SpreadSheet to find out the minimum rectangle of cells 0353 // Maybe we should have something which does that in the KSpreadSheet class, 0354 // it would be easy to keep track of this each time a new Cellis instanciated. 0355 for (int row = 1; row < maxRow; ++row) { 0356 bool usedColumn = false; 0357 for (int column = 1; column < maxColumn; ++column) { 0358 Cell cell(spreadSheet, column, row); 0359 if (!cell.isDefault() && !cell.isEmpty()) { 0360 if (column > m_maxCellColumn) { 0361 m_maxCellColumn = column; 0362 } 0363 usedColumn = true; 0364 } 0365 } 0366 if (usedColumn) { 0367 m_maxCellRow = row; 0368 } 0369 } 0370 }