AirInv Logo  0.1.2
C++ Simulated Airline Inventory Management System library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AIRINV_Master_Service.cpp
Go to the documentation of this file.
1 // //////////////////////////////////////////////////////////////////////
2 // Import section
3 // //////////////////////////////////////////////////////////////////////
4 // STL
5 #include <cassert>
6 #include <cmath>
7 // Boost
8 #include <boost/make_shared.hpp>
9 // StdAir
10 #include <stdair/basic/BasChronometer.hpp>
11 #include <stdair/basic/EventType.hpp>
12 #include <stdair/bom/BomKeyManager.hpp>
13 #include <stdair/bom/EventQueue.hpp>
14 #include <stdair/bom/SnapshotStruct.hpp>
15 #include <stdair/bom/RMEventStruct.hpp>
16 #include <stdair/service/Logger.hpp>
17 #include <stdair/STDAIR_Service.hpp>
18 // AirInv
26 
27 namespace AIRINV {
28 
29  // ////////////////////////////////////////////////////////////////////
30  AIRINV_Master_Service::AIRINV_Master_Service()
31  : _airinvMasterServiceContext (NULL) {
32  assert (false);
33  }
34 
35  // ////////////////////////////////////////////////////////////////////
36  AIRINV_Master_Service::
37  AIRINV_Master_Service (const AIRINV_Master_Service& iService)
38  : _airinvMasterServiceContext (NULL) {
39  assert (false);
40  }
41 
42  // ////////////////////////////////////////////////////////////////////
43  AIRINV_Master_Service::
44  AIRINV_Master_Service (const stdair::BasLogParams& iLogParams,
45  const stdair::BasDBParams& iDBParams)
46  : _airinvMasterServiceContext (NULL) {
47 
48  // Initialise the STDAIR service handler
49  stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
50  initStdAirService (iLogParams, iDBParams);
51 
52  // Initialise the service context
53  initServiceContext();
54 
55  // Add the StdAir service context to the AIRINV service context
56  // \note RMOL owns the STDAIR service resources here.
57  const bool ownStdairService = true;
58  addStdAirService (lSTDAIR_Service_ptr, ownStdairService);
59 
60  // Initialise the (remaining of the) context
61  initSlaveAirinvService();
62  }
63 
64  // ////////////////////////////////////////////////////////////////////
65  AIRINV_Master_Service::
66  AIRINV_Master_Service (const stdair::BasLogParams& iLogParams)
67  : _airinvMasterServiceContext (NULL) {
68 
69  // Initialise the STDAIR service handler
70  stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
71  initStdAirService (iLogParams);
72 
73  // Initialise the service context
74  initServiceContext();
75 
76  // Add the StdAir service context to the AIRINV service context
77  // \note RMOL owns the STDAIR service resources here.
78  const bool ownStdairService = true;
79  addStdAirService (lSTDAIR_Service_ptr, ownStdairService);
80 
81  // Initialise the (remaining of the) context
82  initSlaveAirinvService();
83  }
84 
85  // ////////////////////////////////////////////////////////////////////
86  AIRINV_Master_Service::
87  AIRINV_Master_Service (stdair::STDAIR_ServicePtr_T ioSTDAIR_Service_ptr)
88  : _airinvMasterServiceContext (NULL) {
89 
90  // Initialise the service context
91  initServiceContext();
92 
93  // Store the STDAIR service object within the (AIRINV) service context
94  // \note AirInv does not own the STDAIR service resources here.
95  const bool doesNotOwnStdairService = false;
96  addStdAirService (ioSTDAIR_Service_ptr, doesNotOwnStdairService);
97 
98  // Initialise the (remaining of the) context
99  initSlaveAirinvService();
100  }
101 
102  // ////////////////////////////////////////////////////////////////////
104  // Delete/Clean all the objects from memory
105  finalise();
106  }
107 
108  // ////////////////////////////////////////////////////////////////////
109  void AIRINV_Master_Service::finalise() {
110  assert (_airinvMasterServiceContext != NULL);
111  // Reset the (Boost.)Smart pointer pointing on the STDAIR_Service object.
112  _airinvMasterServiceContext->reset();
113  }
114 
115  // ////////////////////////////////////////////////////////////////////
116  void AIRINV_Master_Service::initServiceContext() {
117  // Initialise the context
118  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
120  _airinvMasterServiceContext = &lAIRINV_Master_ServiceContext;
121  }
122 
123  // ////////////////////////////////////////////////////////////////////
124  void AIRINV_Master_Service::
125  addStdAirService (stdair::STDAIR_ServicePtr_T ioSTDAIR_Service_ptr,
126  const bool iOwnStdairService) {
127 
128  // Retrieve the AirInv Master service context
129  assert (_airinvMasterServiceContext != NULL);
130  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
131  *_airinvMasterServiceContext;
132 
133  // Store the STDAIR service object within the (AIRINV) service context
134  lAIRINV_Master_ServiceContext.setSTDAIR_Service (ioSTDAIR_Service_ptr,
135  iOwnStdairService);
136  }
137 
138  // ////////////////////////////////////////////////////////////////////
139  stdair::STDAIR_ServicePtr_T AIRINV_Master_Service::
140  initStdAirService (const stdair::BasLogParams& iLogParams,
141  const stdair::BasDBParams& iDBParams) {
142 
150  stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
151  boost::make_shared<stdair::STDAIR_Service> (iLogParams, iDBParams);
152 
153  return lSTDAIR_Service_ptr;
154  }
155 
156  // ////////////////////////////////////////////////////////////////////
157  stdair::STDAIR_ServicePtr_T AIRINV_Master_Service::
158  initStdAirService (const stdair::BasLogParams& iLogParams) {
159 
167  stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
168  boost::make_shared<stdair::STDAIR_Service> (iLogParams);
169 
170  return lSTDAIR_Service_ptr;
171  }
172 
173  // ////////////////////////////////////////////////////////////////////
174  void AIRINV_Master_Service::initSlaveAirinvService() {
175 
176  // Retrieve the AirInv Master service context
177  assert (_airinvMasterServiceContext != NULL);
178  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
179  *_airinvMasterServiceContext;
180 
181  // Retrieve the StdAir service
182  stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
183  lAIRINV_Master_ServiceContext.getSTDAIR_ServicePtr();
184  assert (lSTDAIR_Service_ptr != NULL);
185 
195  AIRINV_ServicePtr_T lAIRINV_Service_ptr =
196  boost::make_shared<AIRINV_Service> (lSTDAIR_Service_ptr);
197 
198  // Store the AIRINV service object within the AIRINV Master service context.
199  lAIRINV_Master_ServiceContext.setAIRINV_Service (lAIRINV_Service_ptr);
200  }
201 
202  // ////////////////////////////////////////////////////////////////////
204  parseAndLoad (const stdair::Filename_T& iInventoryInputFilename) {
205 
206  // Retrieve the AirInv Master service context
207  if (_airinvMasterServiceContext == NULL) {
208  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
209  "has not been initialised");
210  }
211  assert (_airinvMasterServiceContext != NULL);
212 
213  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
214  *_airinvMasterServiceContext;
215 
216  // Retrieve the slave AIRINV service object from the (AIRINV)
217  // service context
218  AIRINV_Service& lAIRINV_Service =
219  lAIRINV_Master_ServiceContext.getAIRINV_Service();
220 
221  // Delegate the file parsing and BOM building to the dedicated service
222  lAIRINV_Service.parseAndLoad (iInventoryInputFilename);
223  }
224 
225  // ////////////////////////////////////////////////////////////////////
227  parseAndLoad (const stdair::Filename_T& iScheduleInputFilename,
228  const stdair::Filename_T& iODInputFilename,
229  const AIRRAC::YieldFilePath& iYieldFilename) {
230 
231  // Retrieve the AirInv Master service context
232  if (_airinvMasterServiceContext == NULL) {
233  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
234  "has not been initialised");
235  }
236  assert (_airinvMasterServiceContext != NULL);
237 
238  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
239  *_airinvMasterServiceContext;
240 
241  // Retrieve the slave AirInv service object from the (AirInv)
242  // service context
243  AIRINV_Service& lAIRINV_Service =
244  lAIRINV_Master_ServiceContext.getAIRINV_Service();
245 
246  // Delegate the file parsing and BOM building to the dedicated service
247  lAIRINV_Service.parseAndLoad (iScheduleInputFilename, iODInputFilename,
248  iYieldFilename);
249  }
250 
251  // ////////////////////////////////////////////////////////////////////
253 
254  // Retrieve the AirInv Master service context
255  if (_airinvMasterServiceContext == NULL) {
256  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
257  "has not been initialised");
258  }
259  assert (_airinvMasterServiceContext != NULL);
260 
261  // Retrieve the AirInv service context and whether it owns the Stdair
262  // service
263  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
264  *_airinvMasterServiceContext;
265  const bool doesOwnStdairService =
266  lAIRINV_Master_ServiceContext.getOwnStdairServiceFlag();
267 
268  // Retrieve the StdAir service object from the (AirInv) service context
269  stdair::STDAIR_Service& lSTDAIR_Service =
270  lAIRINV_Master_ServiceContext.getSTDAIR_Service();
271 
276  if (doesOwnStdairService == true) {
277  //
278  lSTDAIR_Service.buildSampleBom();
279  }
280 
289  AIRINV_Service& lAIRINV_Service =
290  lAIRINV_Master_ServiceContext.getAIRINV_Service();
291  lAIRINV_Service.buildSampleBom();
292 
300  }
301 
302  // ////////////////////////////////////////////////////////////////////
303  std::string AIRINV_Master_Service::
304  jsonExport (const stdair::AirlineCode_T& iAirlineCode,
305  const stdair::FlightNumber_T& iFlightNumber,
306  const stdair::Date_T& iDepartureDate) const {
307 
308  // Retrieve the AirInv Master service context
309  if (_airinvMasterServiceContext == NULL) {
310  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
311  "has not been initialised");
312  }
313  assert (_airinvMasterServiceContext != NULL);
314 
315  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
316  *_airinvMasterServiceContext;
317 
318  // Retrieve the slave AirInv (slave) service object from
319  // the (AirInv master) service context
320  AIRINV_Service& lAIRINV_Service =
321  lAIRINV_Master_ServiceContext.getAIRINV_Service();
322 
323  // Delegate the BOM dump to the dedicated service
324  return lAIRINV_Service.jsonExport (iAirlineCode, iFlightNumber,
325  iDepartureDate);
326  }
327 
328  // ////////////////////////////////////////////////////////////////////
329  std::string AIRINV_Master_Service::
330  list (const stdair::AirlineCode_T& iAirlineCode,
331  const stdair::FlightNumber_T& iFlightNumber) const {
332  std::ostringstream oFlightListStr;
333 
334  // Retrieve the AirInv Master service context
335  if (_airinvMasterServiceContext == NULL) {
336  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
337  "has not been initialised");
338  }
339  assert (_airinvMasterServiceContext != NULL);
340 
341  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
342  *_airinvMasterServiceContext;
343 
344  // Retrieve the slave AirInv (slave) service object from
345  // the (AirInv master) service context
346  AIRINV_Service& lAIRINV_Service =
347  lAIRINV_Master_ServiceContext.getAIRINV_Service();
348 
349  // Delegate the BOM display to the dedicated service
350  return lAIRINV_Service.list (iAirlineCode, iFlightNumber);
351  }
352 
353  // ////////////////////////////////////////////////////////////////////
355  check (const stdair::AirlineCode_T& iAirlineCode,
356  const stdair::FlightNumber_T& iFlightNumber,
357  const stdair::Date_T& iDepartureDate) const {
358  std::ostringstream oFlightListStr;
359 
360  // Retrieve the AirInv Master service context
361  if (_airinvMasterServiceContext == NULL) {
362  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
363  "has not been initialised");
364  }
365  assert (_airinvMasterServiceContext != NULL);
366 
367  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
368  *_airinvMasterServiceContext;
369 
370  // Retrieve the slave AirInv (slave) service object from
371  // the (AirInv master) service context
372  AIRINV_Service& lAIRINV_Service =
373  lAIRINV_Master_ServiceContext.getAIRINV_Service();
374 
375  // Delegate the BOM display to the dedicated service
376  return lAIRINV_Service.check (iAirlineCode, iFlightNumber, iDepartureDate);
377  }
378 
379  // ////////////////////////////////////////////////////////////////////
380  std::string AIRINV_Master_Service::csvDisplay() const {
381 
382  // Retrieve the AirInv Master service context
383  if (_airinvMasterServiceContext == NULL) {
384  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
385  "has not been initialised");
386  }
387  assert (_airinvMasterServiceContext != NULL);
388 
389  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
390  *_airinvMasterServiceContext;
391 
392  // Retrieve the slave AIRINV service object from
393  // the (AIRINV) service context
394  AIRINV_Service& lAIRINV_Service =
395  lAIRINV_Master_ServiceContext.getAIRINV_Service();
396 
397  // Delegate the BOM display to the dedicated service
398  return lAIRINV_Service.csvDisplay();
399  }
400 
401  // ////////////////////////////////////////////////////////////////////
402  std::string AIRINV_Master_Service::
403  csvDisplay (const stdair::AirlineCode_T& iAirlineCode,
404  const stdair::FlightNumber_T& iFlightNumber,
405  const stdair::Date_T& iDepartureDate) const {
406 
407  // Retrieve the AirInv Master service context
408  if (_airinvMasterServiceContext == NULL) {
409  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
410  "has not been initialised");
411  }
412  assert (_airinvMasterServiceContext != NULL);
413 
414  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
415  *_airinvMasterServiceContext;
416 
417  // Retrieve the slave AIRINV service object from
418  // the (AIRINV) service context
419  AIRINV_Service& lAIRINV_Service =
420  lAIRINV_Master_ServiceContext.getAIRINV_Service();
421 
422  // Delegate the BOM display to the dedicated service
423  return lAIRINV_Service.csvDisplay (iAirlineCode, iFlightNumber,
424  iDepartureDate);
425  }
426 
427  // ////////////////////////////////////////////////////////////////////
429  initSnapshotAndRMEvents (const stdair::Date_T& iStartDate,
430  const stdair::Date_T& iEndDate) {
431 
432  // Retrieve the AirInv Master service context
433  if (_airinvMasterServiceContext == NULL) {
434  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
435  "has not been initialised");
436  }
437  assert (_airinvMasterServiceContext != NULL);
438 
439  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
440  *_airinvMasterServiceContext;
441 
442  // Retrieve the StdAir service context
443  stdair::STDAIR_ServicePtr_T lSTDAIR_Service_ptr =
444  lAIRINV_Master_ServiceContext.getSTDAIR_ServicePtr();
445  assert (lSTDAIR_Service_ptr != NULL);
446 
447  // Retrieve the event queue object instance
448  stdair::EventQueue& lQueue = lSTDAIR_Service_ptr->getEventQueue();
449 
450  // Initialise the snapshot events
451  InventoryManager::initSnapshotEvents (iStartDate, iEndDate, lQueue);
452 
453  // \todo Browse the list of inventories and itinialise the RM events of
454  // each inventory.
455 
456  // Retrieve the slave AIRINV service object from the (AIRINV)
457  // service context
458  AIRINV_Service& lAIRINV_Service =
459  lAIRINV_Master_ServiceContext.getAIRINV_Service();
460  lQueue.addStatus (stdair::EventType::RM, 0);
461  stdair::RMEventList_T lRMEventList =
462  lAIRINV_Service.initRMEvents (iStartDate, iEndDate);
463  InventoryManager::addRMEventsToEventQueue (lQueue, lRMEventList);
464  }
465 
466  // ////////////////////////////////////////////////////////////////////
468  calculateAvailability (stdair::TravelSolutionStruct& ioTravelSolution,
469  const stdair::PartnershipTechnique& iPartnershipTechnique) {
470 
471  // Retrieve the AirInv Master service context
472  if (_airinvMasterServiceContext == NULL) {
473  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
474  "has not been initialised");
475  }
476  assert (_airinvMasterServiceContext != NULL);
477 
478  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
479  *_airinvMasterServiceContext;
480 
481  // Retrieve the slave AIRINV service object from the (AIRINV)
482  // service context
483  AIRINV_Service& lAIRINV_Service =
484  lAIRINV_Master_ServiceContext.getAIRINV_Service();
485 
486  // Delegate the availability retrieval to the dedicated service
487  stdair::BasChronometer lAvlChronometer;
488  lAvlChronometer.start();
489 
490  lAIRINV_Service.calculateAvailability (ioTravelSolution, iPartnershipTechnique);
491 
492  // DEBUG
493  // const double lAvlMeasure = lAvlChronometer.elapsed();
494  // STDAIR_LOG_DEBUG ("Availability retrieval: " << lAvlMeasure << " - "
495  // << lAIRINV_Master_ServiceContext.display());
496  }
497 
498  // ////////////////////////////////////////////////////////////////////
499  bool AIRINV_Master_Service::sell (const std::string& iSegmentDateKey,
500  const stdair::ClassCode_T& iClassCode,
501  const stdair::PartySize_T& iPartySize) {
502 
503  // Retrieve the AirInv Master service context
504  if (_airinvMasterServiceContext == NULL) {
505  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
506  "has not been initialised");
507  }
508  assert (_airinvMasterServiceContext != NULL);
509 
510  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
511  *_airinvMasterServiceContext;
512 
513  // Retrieve the corresponding inventory key
514  // const stdair::InventoryKey& lInventoryKey =
515  // stdair::BomKeyManager::extractInventoryKey (iSegmentDateKey);
516 
517  // Retrieve the slave AirInv service object from the (AirInv Master)
518  // service context
519  AIRINV_Service& lAIRINV_Service =
520  lAIRINV_Master_ServiceContext.getAIRINV_Service();
521 
522  // Delegate the booking to the dedicated command
523  stdair::BasChronometer lSellChronometer;
524  lSellChronometer.start();
525 
526  // Delegate the BOM building to the dedicated service
527  const bool hasBeenSaleSuccessful =
528  lAIRINV_Service.sell (iSegmentDateKey, iClassCode, iPartySize);
529 
530  // const double lSellMeasure = lSellChronometer.elapsed();
531 
532  // DEBUG
533  // STDAIR_LOG_DEBUG ("Booking sell: " << lSellMeasure << " - "
534  // << lAIRINV_Master_ServiceContext.display());
535 
536  //
537  return hasBeenSaleSuccessful;
538  }
539 
540  // ////////////////////////////////////////////////////////////////////
541  bool AIRINV_Master_Service::cancel (const std::string& iSegmentDateKey,
542  const stdair::ClassCode_T& iClassCode,
543  const stdair::PartySize_T& iPartySize) {
544 
545  // Retrieve the AirInv Master service context
546  if (_airinvMasterServiceContext == NULL) {
547  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
548  "has not been initialised");
549  }
550  assert (_airinvMasterServiceContext != NULL);
551 
552  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
553  *_airinvMasterServiceContext;
554 
555  // Retrieve the corresponding inventory key
556  // const stdair::InventoryKey& lInventoryKey =
557  // stdair::BomKeyManager::extractInventoryKey (iSegmentDateKey);
558 
559  // Retrieve the slave AirInv service object from the (AirInv Master)
560  // service context
561  AIRINV_Service& lAIRINV_Service =
562  lAIRINV_Master_ServiceContext.getAIRINV_Service();
563 
564  // Delegate the booking to the dedicated command
565  stdair::BasChronometer lCancelChronometer;
566  lCancelChronometer.start();
567 
568  // Delegate the BOM building to the dedicated service
569  const bool hasBeenSaleSuccessful =
570  lAIRINV_Service.cancel (iSegmentDateKey, iClassCode, iPartySize);
571 
572  // const double lCancelMeasure = lCancelChronometer.elapsed();
573 
574  // DEBUG
575  // STDAIR_LOG_DEBUG ("Booking cancel: " << lCancelMeasure << " - "
576  // << lAIRINV_Master_ServiceContext.display());
577 
578  //
579  return hasBeenSaleSuccessful;
580  }
581 
582  // ////////////////////////////////////////////////////////////////////
584  takeSnapshots (const stdair::SnapshotStruct& iSnapshot) {
585 
586  // Retrieve the AirInv Master service context
587  if (_airinvMasterServiceContext == NULL) {
588  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
589  "has not been initialised");
590  }
591  assert (_airinvMasterServiceContext != NULL);
592 
593  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
594  *_airinvMasterServiceContext;
595 
596  // Retrieve the slave AIRINV service object from the (AIRINV)
597  // service context
598  AIRINV_Service& lAIRINV_Service =
599  lAIRINV_Master_ServiceContext.getAIRINV_Service();
600 
601  // Retrieve the snapshot time and the airline code.
602  const stdair::DateTime_T& lSnapshotTime = iSnapshot.getSnapshotTime();
603  const stdair::AirlineCode_T& lAirlineCode = iSnapshot.getAirlineCode();
604 
605  lAIRINV_Service.takeSnapshots (lAirlineCode, lSnapshotTime);
606  }
607 
608  // ////////////////////////////////////////////////////////////////////
610  optimise (const stdair::RMEventStruct& iRMEvent,
611  const stdair::ForecastingMethod& iForecastingMethod,
612  const stdair::PartnershipTechnique& iPartnershipTechnique) {
613 
614  // Retrieve the AirInv Master service context
615  if (_airinvMasterServiceContext == NULL) {
616  throw stdair::NonInitialisedServiceException ("The AirInvMaster service "
617  "has not been initialised");
618  }
619  assert (_airinvMasterServiceContext != NULL);
620 
621  AIRINV_Master_ServiceContext& lAIRINV_Master_ServiceContext =
622  *_airinvMasterServiceContext;
623 
624  // Retrieve the slave AIRINV service object from the (AIRINV)
625  // service context
626  AIRINV_Service& lAIRINV_Service =
627  lAIRINV_Master_ServiceContext.getAIRINV_Service();
628 
629  // Retrieve the snapshot time and the airline code.
630  const stdair::DateTime_T& lRMEventTime = iRMEvent.getRMEventTime();
631  const stdair::AirlineCode_T& lAirlineCode = iRMEvent.getAirlineCode();
632  const stdair::KeyDescription_T& lFDDescription =
633  iRMEvent.getFlightDateDescription();
634 
635  lAIRINV_Service.optimise (lAirlineCode, lFDDescription, lRMEventTime,
636  iForecastingMethod, iPartnershipTechnique);
637  }
638 }