-rw-r--r-- | korganizer/koprefs.cpp | 2 | ||||
-rw-r--r-- | korganizer/koprefs.h | 3 | ||||
-rw-r--r-- | korganizer/mainwindow.cpp | 321 | ||||
-rw-r--r-- | korganizer/mainwindow.h | 70 |
4 files changed, 2 insertions, 394 deletions
diff --git a/korganizer/koprefs.cpp b/korganizer/koprefs.cpp index 84e3d00..1210094 100644 --- a/korganizer/koprefs.cpp +++ b/korganizer/koprefs.cpp | |||
@@ -192,8 +192,6 @@ KOPrefs::KOPrefs() : | |||
192 | // addItemBool("WriteBackExistingOnly",&mWriteBackExistingOnly,false); | 192 | // addItemBool("WriteBackExistingOnly",&mWriteBackExistingOnly,false); |
193 | // addItemBool("AskForPreferences",&mAskForPreferences,true); | 193 | // addItemBool("AskForPreferences",&mAskForPreferences,true); |
194 | // addItemBool("ShowSyncSummary",&mShowSyncSummary,true); | 194 | // addItemBool("ShowSyncSummary",&mShowSyncSummary,true); |
195 | addItemString("PassiveSyncPort",&mPassiveSyncPort,"9197" ); | ||
196 | addItemString("PassiveSyncPw",&mPassiveSyncPw,"abc" ); | ||
197 | addItemString("ActiveSyncPort",&mActiveSyncPort,"9197" ); | 195 | addItemString("ActiveSyncPort",&mActiveSyncPort,"9197" ); |
198 | addItemString("ActiveSyncIP",&mActiveSyncIP,"192.168.0.40" ); | 196 | addItemString("ActiveSyncIP",&mActiveSyncIP,"192.168.0.40" ); |
199 | addItemBool("ShowSyncEvents",&mShowSyncEvents,false); | 197 | addItemBool("ShowSyncEvents",&mShowSyncEvents,false); |
diff --git a/korganizer/koprefs.h b/korganizer/koprefs.h index d9ac851..ff09e19 100644 --- a/korganizer/koprefs.h +++ b/korganizer/koprefs.h | |||
@@ -278,8 +278,7 @@ class KOPrefs : public KPimPrefs | |||
278 | int mAlarmSuspendCount; | 278 | int mAlarmSuspendCount; |
279 | int mAlarmBeepInterval; | 279 | int mAlarmBeepInterval; |
280 | 280 | ||
281 | QString mPassiveSyncPort; | 281 | |
282 | QString mPassiveSyncPw; | ||
283 | QString mActiveSyncPort; | 282 | QString mActiveSyncPort; |
284 | QString mActiveSyncIP; | 283 | QString mActiveSyncIP; |
285 | 284 | ||
diff --git a/korganizer/mainwindow.cpp b/korganizer/mainwindow.cpp index 9104347..e3324ee 100644 --- a/korganizer/mainwindow.cpp +++ b/korganizer/mainwindow.cpp | |||
@@ -130,7 +130,6 @@ MainWindow::MainWindow( QWidget *parent, const char *name, QString msg) : | |||
130 | #ifdef DESKTOP_VERSION | 130 | #ifdef DESKTOP_VERSION |
131 | setFont( QFont("Arial"), 14 ); | 131 | setFont( QFont("Arial"), 14 ); |
132 | #endif | 132 | #endif |
133 | mSyncActionDialog = 0; | ||
134 | mServerSocket = 0; | 133 | mServerSocket = 0; |
135 | mClosed = false; | 134 | mClosed = false; |
136 | //QString confFile = KStandardDirs::appDir() + "config/korganizerrc"; | 135 | //QString confFile = KStandardDirs::appDir() + "config/korganizerrc"; |
@@ -2347,323 +2346,3 @@ void MainWindow::printCal() | |||
2347 | mView->print();//mCp->showDialog(); | 2346 | mView->print();//mCp->showDialog(); |
2348 | } | 2347 | } |
2349 | 2348 | ||
2350 | |||
2351 | |||
2352 | KServerSocket:: KServerSocket ( QString pw, Q_UINT16 port, int backlog, QObject * parent, const char * name ) : QServerSocket( port, backlog, parent, name ) | ||
2353 | { | ||
2354 | mPassWord = pw; | ||
2355 | mSocket = 0; | ||
2356 | mSyncActionDialog = 0; | ||
2357 | blockRC = false; | ||
2358 | }; | ||
2359 | |||
2360 | void KServerSocket::newConnection ( int socket ) | ||
2361 | { | ||
2362 | // qDebug("KServerSocket:New connection %d ", socket); | ||
2363 | if ( mSocket ) { | ||
2364 | qDebug("KServerSocket::newConnection Socket deleted! "); | ||
2365 | delete mSocket; | ||
2366 | mSocket = 0; | ||
2367 | } | ||
2368 | mSocket = new QSocket( this ); | ||
2369 | connect( mSocket , SIGNAL(readyRead()), this, SLOT(readClient()) ); | ||
2370 | connect( mSocket , SIGNAL(delayedCloseFinished()), this, SLOT(discardClient()) ); | ||
2371 | mSocket->setSocket( socket ); | ||
2372 | } | ||
2373 | |||
2374 | void KServerSocket::discardClient() | ||
2375 | { | ||
2376 | //qDebug(" KServerSocket::discardClient()"); | ||
2377 | if ( mSocket ) { | ||
2378 | delete mSocket; | ||
2379 | mSocket = 0; | ||
2380 | } | ||
2381 | //emit endConnect(); | ||
2382 | } | ||
2383 | void KServerSocket::readClient() | ||
2384 | { | ||
2385 | if ( blockRC ) | ||
2386 | return; | ||
2387 | if ( mSocket == 0 ) { | ||
2388 | qDebug("ERROR::KServerSocket::readClient(): mSocket == 0 "); | ||
2389 | return; | ||
2390 | } | ||
2391 | qDebug("KServerSocket readClient()"); | ||
2392 | if ( mSocket->canReadLine() ) { | ||
2393 | QString line = mSocket->readLine(); | ||
2394 | qDebug("KServerSocket readline: %s ", line.latin1()); | ||
2395 | QStringList tokens = QStringList::split( QRegExp("[ \r\n][ \r\n]*"), line ); | ||
2396 | if ( tokens[0] == "GET" ) { | ||
2397 | if ( tokens[1] == mPassWord ) | ||
2398 | //emit sendFile( mSocket ); | ||
2399 | send_file(); | ||
2400 | else { | ||
2401 | KMessageBox::information( 0, i18n("ERROR:\nGot send file request\nwith invalid password")); | ||
2402 | qDebug("password %s, invalid password %s ",mPassWord.latin1(), tokens[1].latin1() ); | ||
2403 | } | ||
2404 | } | ||
2405 | if ( tokens[0] == "PUT" ) { | ||
2406 | if ( tokens[1] == mPassWord ) { | ||
2407 | //emit getFile( mSocket ); | ||
2408 | blockRC = true; | ||
2409 | get_file(); | ||
2410 | } | ||
2411 | else { | ||
2412 | KMessageBox::information( 0, i18n("ERROR:\nGot receive file request\nwith invalid password")); | ||
2413 | qDebug("password %s, invalid password %s ",mPassWord.latin1(), tokens[1].latin1() ); | ||
2414 | } | ||
2415 | } | ||
2416 | if ( tokens[0] == "STOP" ) { | ||
2417 | //emit endConnect(); | ||
2418 | end_connect(); | ||
2419 | } | ||
2420 | } | ||
2421 | } | ||
2422 | void KServerSocket::end_connect() | ||
2423 | { | ||
2424 | delete mSyncActionDialog; | ||
2425 | mSyncActionDialog = 0; | ||
2426 | } | ||
2427 | void KServerSocket::send_file() | ||
2428 | { | ||
2429 | //qDebug("MainWindow::sendFile(QSocket* s) "); | ||
2430 | if ( mSyncActionDialog ) | ||
2431 | delete mSyncActionDialog; | ||
2432 | mSyncActionDialog = new QDialog ( 0, "input-dialog", true ); | ||
2433 | mSyncActionDialog->setCaption(i18n("Received sync request")); | ||
2434 | QLabel* label = new QLabel( i18n("Synchronizing from remote ...\n\nDo not use this application!\n\nIf syncing fails\nyou can close this dialog."), mSyncActionDialog ); | ||
2435 | QVBoxLayout* lay = new QVBoxLayout( mSyncActionDialog ); | ||
2436 | lay->addWidget( label); | ||
2437 | lay->setMargin(7); | ||
2438 | lay->setSpacing(7); | ||
2439 | mSyncActionDialog->setFixedSize( 230, 120); | ||
2440 | mSyncActionDialog->show(); | ||
2441 | qDebug("KSS::saving ... "); | ||
2442 | emit saveFile(); | ||
2443 | qApp->processEvents(); | ||
2444 | QString fileName = mFileName; | ||
2445 | QFile file( fileName ); | ||
2446 | if (!file.open( IO_ReadOnly ) ) { | ||
2447 | delete mSyncActionDialog; | ||
2448 | mSyncActionDialog = 0; | ||
2449 | qDebug("KSS::error open file "); | ||
2450 | mSocket->close(); | ||
2451 | if ( mSocket->state() == QSocket::Idle ) | ||
2452 | QTimer::singleShot( 10, this , SLOT ( discardClient())); | ||
2453 | return ; | ||
2454 | |||
2455 | } | ||
2456 | mSyncActionDialog->setCaption( i18n("Sending file...") ); | ||
2457 | QTextStream ts( &file ); | ||
2458 | ts.setCodec( QTextCodec::codecForName("utf8") ); | ||
2459 | QTextStream os( mSocket ); | ||
2460 | os.setCodec( QTextCodec::codecForName("utf8") ); | ||
2461 | //os.setEncoding( QTextStream::UnicodeUTF8 ); | ||
2462 | while ( ! ts.atEnd() ) { | ||
2463 | os << ts.readLine() << "\n"; | ||
2464 | } | ||
2465 | //os << ts.read(); | ||
2466 | file.close(); | ||
2467 | mSyncActionDialog->setCaption( i18n("Waiting for synced file...") ); | ||
2468 | mSocket->close(); | ||
2469 | if ( mSocket->state() == QSocket::Idle ) | ||
2470 | QTimer::singleShot( 10, this , SLOT ( discardClient())); | ||
2471 | } | ||
2472 | void KServerSocket::get_file() | ||
2473 | { | ||
2474 | mSyncActionDialog->setCaption( i18n("Receiving synced file...") ); | ||
2475 | |||
2476 | piTime.start(); | ||
2477 | piFileString = ""; | ||
2478 | QTimer::singleShot( 1, this , SLOT (readBackFileFromSocket( ) )); | ||
2479 | } | ||
2480 | |||
2481 | |||
2482 | void KServerSocket::readBackFileFromSocket() | ||
2483 | { | ||
2484 | //qDebug("readBackFileFromSocket() %d ", piTime.elapsed ()); | ||
2485 | while ( mSocket->canReadLine () ) { | ||
2486 | piTime.restart(); | ||
2487 | QString line = mSocket->readLine (); | ||
2488 | piFileString += line; | ||
2489 | //qDebug("readline: %s ", line.latin1()); | ||
2490 | mSyncActionDialog->setCaption( i18n("Received %1 bytes").arg( piFileString.length() ) ); | ||
2491 | |||
2492 | } | ||
2493 | if ( piTime.elapsed () < 3000 ) { | ||
2494 | // wait for more | ||
2495 | //qDebug("waitformore "); | ||
2496 | QTimer::singleShot( 100, this , SLOT (readBackFileFromSocket( ) )); | ||
2497 | return; | ||
2498 | } | ||
2499 | QString fileName = mFileName; | ||
2500 | QFile file ( fileName ); | ||
2501 | if (!file.open( IO_WriteOnly ) ) { | ||
2502 | delete mSyncActionDialog; | ||
2503 | mSyncActionDialog = 0; | ||
2504 | qDebug("error open cal file "); | ||
2505 | piFileString = ""; | ||
2506 | emit file_received( false ); | ||
2507 | blockRC = false; | ||
2508 | return ; | ||
2509 | |||
2510 | } | ||
2511 | |||
2512 | // mView->setLoadedFileVersion(QDateTime::currentDateTime().addSecs( -1)); | ||
2513 | QTextStream ts ( &file ); | ||
2514 | ts.setCodec( QTextCodec::codecForName("utf8") ); | ||
2515 | mSyncActionDialog->setCaption( i18n("Writing file to disk...") ); | ||
2516 | ts << piFileString; | ||
2517 | mSocket->close(); | ||
2518 | if ( mSocket->state() == QSocket::Idle ) | ||
2519 | QTimer::singleShot( 10, this , SLOT ( discardClient())); | ||
2520 | file.close(); | ||
2521 | delete mSyncActionDialog; | ||
2522 | mSyncActionDialog = 0; | ||
2523 | piFileString = ""; | ||
2524 | blockRC = false; | ||
2525 | emit file_received( true ); | ||
2526 | |||
2527 | } | ||
2528 | |||
2529 | KCommandSocket::KCommandSocket ( QString password, Q_UINT16 port, QString host, QObject * parent, const char * name ): QObject( parent, name ) | ||
2530 | { | ||
2531 | mPassWord = password; | ||
2532 | mSocket = 0; | ||
2533 | mPort = port; | ||
2534 | mHost = host; | ||
2535 | |||
2536 | mRetVal = quiet; | ||
2537 | mTimerSocket = new QTimer ( this ); | ||
2538 | connect( mTimerSocket, SIGNAL ( timeout () ), this, SLOT ( deleteSocket() ) ); | ||
2539 | } | ||
2540 | void KCommandSocket::readFile( QString fn ) | ||
2541 | { | ||
2542 | if ( !mSocket ) { | ||
2543 | mSocket = new QSocket( this ); | ||
2544 | connect( mSocket, SIGNAL(readyRead()), this, SLOT(startReadFileFromSocket()) ); | ||
2545 | connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) ); | ||
2546 | } | ||
2547 | mFileString = ""; | ||
2548 | mFileName = fn; | ||
2549 | mFirst = true; | ||
2550 | mSocket->connectToHost( mHost, mPort ); | ||
2551 | QTextStream os( mSocket ); | ||
2552 | os.setEncoding( QTextStream::UnicodeUTF8 ); | ||
2553 | os << "GET " << mPassWord << "\r\n"; | ||
2554 | mTimerSocket->start( 10000 ); | ||
2555 | } | ||
2556 | |||
2557 | void KCommandSocket::writeFile( QString fileName ) | ||
2558 | { | ||
2559 | if ( !mSocket ) { | ||
2560 | mSocket = new QSocket( this ); | ||
2561 | connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) ); | ||
2562 | connect( mSocket, SIGNAL(connected ()), this, SLOT(writeFileToSocket()) ); | ||
2563 | } | ||
2564 | mFileName = fileName ; | ||
2565 | mSocket->connectToHost( mHost, mPort ); | ||
2566 | } | ||
2567 | void KCommandSocket::writeFileToSocket() | ||
2568 | { | ||
2569 | QFile file2( mFileName ); | ||
2570 | if (!file2.open( IO_ReadOnly ) ) { | ||
2571 | mRetVal= errorW; | ||
2572 | mSocket->close(); | ||
2573 | if ( mSocket->state() == QSocket::Idle ) | ||
2574 | QTimer::singleShot( 10, this , SLOT ( deleteSocket())); | ||
2575 | return ; | ||
2576 | } | ||
2577 | QTextStream ts2( &file2 ); | ||
2578 | ts2.setCodec( QTextCodec::codecForName("utf8") ); | ||
2579 | QTextStream os2( mSocket ); | ||
2580 | os2.setCodec( QTextCodec::codecForName("utf8") ); | ||
2581 | os2 << "PUT " << mPassWord << "\r\n";; | ||
2582 | while ( ! ts2.atEnd() ) { | ||
2583 | os2 << ts2.readLine() << "\n"; | ||
2584 | } | ||
2585 | mRetVal= successW; | ||
2586 | file2.close(); | ||
2587 | mSocket->close(); | ||
2588 | if ( mSocket->state() == QSocket::Idle ) | ||
2589 | QTimer::singleShot( 10, this , SLOT ( deleteSocket())); | ||
2590 | } | ||
2591 | void KCommandSocket::sendStop() | ||
2592 | { | ||
2593 | if ( !mSocket ) { | ||
2594 | mSocket = new QSocket( this ); | ||
2595 | connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) ); | ||
2596 | } | ||
2597 | mSocket->connectToHost( mHost, mPort ); | ||
2598 | QTextStream os2( mSocket ); | ||
2599 | os2.setCodec( QTextCodec::codecForName("utf8") ); | ||
2600 | os2 << "STOP\r\n"; | ||
2601 | mSocket->close(); | ||
2602 | if ( mSocket->state() == QSocket::Idle ) | ||
2603 | QTimer::singleShot( 10, this , SLOT ( deleteSocket())); | ||
2604 | } | ||
2605 | |||
2606 | void KCommandSocket::startReadFileFromSocket() | ||
2607 | { | ||
2608 | if ( ! mFirst ) | ||
2609 | return; | ||
2610 | mFirst = false; | ||
2611 | mTimerSocket->stop(); | ||
2612 | mFileString = ""; | ||
2613 | mTime.start(); | ||
2614 | QTimer::singleShot( 1, this , SLOT (readFileFromSocket( ) )); | ||
2615 | |||
2616 | } | ||
2617 | void KCommandSocket::readFileFromSocket() | ||
2618 | { | ||
2619 | //qDebug("readBackFileFromSocket() %d ", mTime.elapsed ()); | ||
2620 | while ( mSocket->canReadLine () ) { | ||
2621 | mTime.restart(); | ||
2622 | QString line = mSocket->readLine (); | ||
2623 | mFileString += line; | ||
2624 | //qDebug("readline: %s ", line.latin1()); | ||
2625 | } | ||
2626 | if ( mTime.elapsed () < 3000 ) { | ||
2627 | // wait for more | ||
2628 | //qDebug("waitformore "); | ||
2629 | QTimer::singleShot( 100, this , SLOT (readFileFromSocket( ) )); | ||
2630 | return; | ||
2631 | } | ||
2632 | QString fileName = mFileName; | ||
2633 | QFile file ( fileName ); | ||
2634 | if (!file.open( IO_WriteOnly ) ) { | ||
2635 | mFileString = ""; | ||
2636 | mRetVal = errorR; | ||
2637 | qDebug("Error open temp calender file for writing: %s",fileName.latin1() ); | ||
2638 | deleteSocket(); | ||
2639 | return ; | ||
2640 | |||
2641 | } | ||
2642 | // mView->setLoadedFileVersion(QDateTime::currentDateTime().addSecs( -1)); | ||
2643 | QTextStream ts ( &file ); | ||
2644 | ts.setCodec( QTextCodec::codecForName("utf8") ); | ||
2645 | ts << mFileString; | ||
2646 | file.close(); | ||
2647 | mFileString = ""; | ||
2648 | mRetVal = successR; | ||
2649 | mSocket->close(); | ||
2650 | // if state is not idle, deleteSocket(); is called via | ||
2651 | // connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) ); | ||
2652 | if ( mSocket->state() == QSocket::Idle ) | ||
2653 | deleteSocket(); | ||
2654 | } | ||
2655 | |||
2656 | void KCommandSocket::deleteSocket() | ||
2657 | { | ||
2658 | if ( mTimerSocket->isActive () ) { | ||
2659 | mTimerSocket->stop(); | ||
2660 | KMessageBox::information( 0, i18n("ERROR:\nConnection to remote host timed out!\nDid you forgot to enable\nsyncing on remote host? ")); | ||
2661 | mRetVal = errorR; | ||
2662 | } | ||
2663 | //qDebug("KCommandSocket::deleteSocket() %d", mRetVal ); | ||
2664 | if ( mSocket) | ||
2665 | delete mSocket; | ||
2666 | mSocket = 0; | ||
2667 | emit commandFinished( this, mRetVal ); | ||
2668 | } | ||
2669 | |||
diff --git a/korganizer/mainwindow.h b/korganizer/mainwindow.h index 4f89e03..0da0be0 100644 --- a/korganizer/mainwindow.h +++ b/korganizer/mainwindow.h | |||
@@ -5,12 +5,12 @@ | |||
5 | #include <qtimer.h> | 5 | #include <qtimer.h> |
6 | #include <qdict.h> | 6 | #include <qdict.h> |
7 | #include <qfile.h> | 7 | #include <qfile.h> |
8 | #include <qsocket.h> | ||
9 | #include <qtextstream.h> | 8 | #include <qtextstream.h> |
10 | #include <qregexp.h> | 9 | #include <qregexp.h> |
11 | 10 | ||
12 | #include <libkcal/incidence.h> | 11 | #include <libkcal/incidence.h> |
13 | #include "simplealarmclient.h" | 12 | #include "simplealarmclient.h" |
13 | #include <ksyncmanager.h> | ||
14 | 14 | ||
15 | class QAction; | 15 | class QAction; |
16 | class CalendarView; | 16 | class CalendarView; |
@@ -21,74 +21,7 @@ class KSyncProfile; | |||
21 | #define QPEMenuBar QMenuBar | 21 | #define QPEMenuBar QMenuBar |
22 | #endif | 22 | #endif |
23 | class QPEToolBar; | 23 | class QPEToolBar; |
24 | #include <qserversocket.h> | ||
25 | #include <qsocket.h> | ||
26 | #include <qnetworkprotocol.h> | ||
27 | 24 | ||
28 | class KServerSocket : public QServerSocket | ||
29 | { | ||
30 | Q_OBJECT | ||
31 | |||
32 | public: | ||
33 | KServerSocket ( QString password, Q_UINT16 port, int backlog = 0, QObject * parent=0, const char * name=0 ); | ||
34 | |||
35 | void newConnection ( int socket ) ; | ||
36 | void setFileName( QString fn ) {mFileName = fn;}; | ||
37 | |||
38 | signals: | ||
39 | //void sendFile(QSocket*); | ||
40 | //void getFile(QSocket*); | ||
41 | void file_received( bool ); | ||
42 | //void file_sent(); | ||
43 | void saveFile(); | ||
44 | void endConnect(); | ||
45 | private slots: | ||
46 | void discardClient(); | ||
47 | void readClient(); | ||
48 | void readBackFileFromSocket(); | ||
49 | private : | ||
50 | bool blockRC; | ||
51 | void send_file(); | ||
52 | void get_file(); | ||
53 | void end_connect(); | ||
54 | QDialog* mSyncActionDialog; | ||
55 | QSocket* mSocket; | ||
56 | QString mPassWord; | ||
57 | QString mFileName; | ||
58 | QTime piTime; | ||
59 | QString piFileString; | ||
60 | }; | ||
61 | |||
62 | class KCommandSocket : public QObject | ||
63 | { | ||
64 | Q_OBJECT | ||
65 | public: | ||
66 | enum state { successR, errorR, successW, errorW, quiet }; | ||
67 | KCommandSocket ( QString password, Q_UINT16 port, QString host, QObject * parent=0, const char * name=0 ); | ||
68 | void readFile( QString ); | ||
69 | void writeFile( QString ); | ||
70 | void sendStop(); | ||
71 | |||
72 | |||
73 | signals: | ||
74 | void commandFinished( KCommandSocket*, int ); | ||
75 | private slots: | ||
76 | void startReadFileFromSocket(); | ||
77 | void readFileFromSocket(); | ||
78 | void deleteSocket(); | ||
79 | void writeFileToSocket(); | ||
80 | private : | ||
81 | QSocket* mSocket; | ||
82 | QString mPassWord; | ||
83 | Q_UINT16 mPort; | ||
84 | QString mHost; | ||
85 | QString mFileName; | ||
86 | QTimer* mTimerSocket; | ||
87 | int mRetVal; | ||
88 | QTime mTime; | ||
89 | QString mFileString; | ||
90 | bool mFirst; | ||
91 | }; | ||
92 | 25 | ||
93 | namespace KCal { | 26 | namespace KCal { |
94 | class CalendarLocal; | 27 | class CalendarLocal; |
@@ -209,7 +142,6 @@ class MainWindow : public QMainWindow | |||
209 | bool mBlockSaveFlag; | 142 | bool mBlockSaveFlag; |
210 | bool mCalendarModifiedFlag; | 143 | bool mCalendarModifiedFlag; |
211 | QPixmap loadPixmap( QString ); | 144 | QPixmap loadPixmap( QString ); |
212 | QDialog * mSyncActionDialog; | ||
213 | }; | 145 | }; |
214 | 146 | ||
215 | 147 | ||