    // @(#)root/gui:$Name:  $:$Id: TGTableLayout.cxx,v 1.7 2003/11/12 19:34:59 rdm Exp $
    // Author: Brett Viren   04/15/2001

    /*************************************************************************
     * Copyright (C) 2001, Brett Viren                                       *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/
    /**************************************************************************

        This source is based on Xclass95, a Win95-looking GUI toolkit.
        Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

        Xclass95 is free software; you can redistribute it and/or
        modify it under the terms of the GNU Library General Public
        License as published by the Free Software Foundation; either
        version 2 of the License, or (at your option) any later version.

    **************************************************************************/
    /**************************************************************************

        The Layout algorithm was largely translated from GTK's gtktable.c
        source.  That source is also distributed under LGPL.

    **************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TGTableLayout                                                        //
    //                                                                      //
    // A LayoutManager which places child frames in a table. This uses      //
    // TGTableLayoutHints (not TGLayoutHints). See TGTableLayoutHints       //
    // for how to use these. This manager works like TGMatrixLayout with    //
    // the addition that:                                                   //
    //  - Child frames can span more than one column/row.                   //
    //  - Child frames can resize with the frame.                           //
    //  - Column and row sizes are not fixed nor (optionally) homogeneous.  //
    //  - The number of columns and rows must be fully specified.           //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TGTableLayout.h"
    #include "TGFrame.h"
    #include "TList.h"
    #include "TMath.h"
    #include "Rtypes.h"
    #include "Riostream.h"

    ClassImp(TGTableLayout)
    ClassImp(TGTableLayoutHints)

    //______________________________________________________________________________
     TGTableLayout::TGTableLayout(TGCompositeFrame *main, UInt_t nrows, UInt_t ncols,
                                 Bool_t homogeneous, Int_t sep, Int_t hints)
    {
       // TGTableLayout constructor.
       // Note:
       // - Number of rows first, number of Columns second
       // - homogeneous == true means all table cells are the same size,
       //   set by the widest and the highest child frame.
       // - s gives the amount of separation in pixels between cells
       // - h are the hints, see TGTableLayoutHints.

       fMain    = main;
       fList    = fMain->GetList();
       fSep     = sep;
       fHints   = hints;
       fNrows   = nrows;
       fNcols   = ncols;
       fRow     = 0;
       fCol     = 0;
       fHomogeneous = homogeneous;
    }

    //______________________________________________________________________________
     TGTableLayout::~TGTableLayout()
    {
       // TGTableLayout constructor.

       if (fRow) delete [] fRow;
       if (fCol) delete [] fCol;
    }

    //______________________________________________________________________________
     void TGTableLayout::FindRowColSizes()
    {
       // Find the sizes of rows and columns needed to statisfy
       // children's layout policies.

       // This is equiv to GTK's requisition stage

       FindRowColSizesInit();
       FindRowColSizesSinglyAttached();
       FindRowColSizesHomogeneous();
       FindRowColSizesMultiplyAttached();
       FindRowColSizesHomogeneous();
    }

    //______________________________________________________________________________
     void TGTableLayout::FindRowColSizesInit()
    {
       // Initialize values needed to determine the size of rows and columns.

       if (fRow) delete [] fRow;
       if (fCol) delete [] fCol;
       fRow = new TableData[fNrows];
       fCol = new TableData[fNcols];

       // Find max of each row and column

       UInt_t i;
       for (i = 0; i < fNrows; ++i) fRow[i].fDefSize = 0;
       for (i = 0; i < fNcols; ++i) fCol[i].fDefSize = 0;
    }

    //______________________________________________________________________________
     void TGTableLayout::FindRowColSizesSinglyAttached()
    {
       // Determine the size of rows/cols needed for singly attached children.

       TIter next(fList);
       TGFrameElement *ptr;

       while ((ptr = (TGFrameElement *) next())) {
          TGTableLayoutHints *layout =
                dynamic_cast<TGTableLayoutHints*>(ptr->fLayout);
          if (!layout) {
             Error("FindRowColSizesSinglyAttached", "didn't get TGTableLayoutHints from %s, layout = 0x%lx",
                   ptr->fFrame->GetName(), ptr->fLayout);
             return;
          }
          UInt_t col = layout->GetAttachLeft();
          if (col == (layout->GetAttachRight() - 1))
             fCol[col].fDefSize = TMath::Max(fCol[col].fDefSize,
                                             ptr->fFrame->GetDefaultWidth() +
                                             layout->GetPadLeft() +
                                             layout->GetPadRight());

          UInt_t row = layout->GetAttachTop();
          if (row == (layout->GetAttachBottom() - 1))
             fRow[row].fDefSize = TMath::Max(fRow[row].fDefSize,
                                             ptr->fFrame->GetDefaultHeight() +
                                             layout->GetPadTop() +
                                             layout->GetPadBottom());
       }
    }

    //______________________________________________________________________________
     void TGTableLayout::FindRowColSizesHomogeneous()
    {
       // If the table is homogeneous make sure all col/rows are same
       // size as biggest col/row.

       if (!fHomogeneous) return;

       UInt_t max_width = 0, max_height = 0, col, row;

       // find max
       for (col = 0; col < fNcols; ++col)
          max_width = TMath::Max(max_width,fCol[col].fDefSize);

       for (row = 0; row < fNrows; ++row)
          max_height = TMath::Max(max_height,fRow[row].fDefSize);

       // set max
       for (col = 0; col < fNcols; ++col) fCol[col].fDefSize = max_width;
       for (row = 0; row < fNrows; ++row) fRow[row].fDefSize = max_height;
    }

    //______________________________________________________________________________
     void TGTableLayout::FindRowColSizesMultiplyAttached()
    {
       // Checks any children which span multiple col/rows.

       TIter next(fList);
       TGFrameElement *ptr;

       while ((ptr = (TGFrameElement *) next())) {
          TGTableLayoutHints *layout =
                dynamic_cast<TGTableLayoutHints*>(ptr->fLayout);
          if (!layout) {
             Error("FindRowColSizesMultiplyAttached", "didn't get TGTableLayoutHints");
             return;
          }
          UInt_t left   = layout->GetAttachLeft();
          UInt_t right  = layout->GetAttachRight();
          if (left != right-1) {  // child spans multi-columns
             UInt_t width = 0, col;
             for (col = left; col < right; ++col) width += fCol[col].fDefSize;

             // If more space needed, divide space evenly among the columns
             UInt_t child_width = ptr->fFrame->GetDefaultWidth() +
                                  layout->GetPadLeft() + layout->GetPadRight();

             if (width < child_width) {
                width = child_width - width;
                for (col = left; col < right; ++col) {
                   UInt_t extra = width / (right - col);
                   fCol[col].fDefSize += extra;
                   width -= extra;
                }
             }
          }
          UInt_t top    = layout->GetAttachTop();
          UInt_t bottom = layout->GetAttachBottom();
          if (top != bottom-1) {  // child spans multi-rows
             UInt_t height = 0, row;
             for (row = top; row < bottom; ++row) height += fRow[row].fDefSize;

             // If more space needed, divide space evenly among the rows
             UInt_t child_height = ptr->fFrame->GetDefaultHeight() +
                                   layout->GetPadTop() + layout->GetPadBottom();

             if (height < child_height) {
                height = child_height - height;
                for (row = top; row < bottom; ++row) {
                   UInt_t extra = height / (bottom - row);
                   fRow[row].fDefSize += extra;
                   height -= extra;
                }
             }
          }
       }
    }

    //______________________________________________________________________________
     void TGTableLayout::SetRowColResize(UInt_t real_size, UInt_t nthings,
                                        TableData *thing, Bool_t homogeneous)
    {
       // If main frame is bigger or smaller than all children,
       // expand/shrink to fill. This is symmetric under row<-->col
       // switching so it is abstracted out to a normal function to save typing.

       if (homogeneous) {
          UInt_t ind, nexpand = 0, cur_size = 0;

          for (ind = 0; ind < nthings; ++ind)
             cur_size += thing[ind].fDefSize;

          if (cur_size < real_size) {
             for (ind = 0; ind < nthings; ++ind)
                if (thing[ind].fExpand) { ++ nexpand; break; }
             if (nexpand > 0) {
                UInt_t size = real_size;
                for (ind = 0; ind < nthings; ++ ind) {
                   UInt_t extra = size / (nthings - ind);
                   thing[ind].fRealSize = TMath::Max(1U, extra);
                   size -= extra;
                }
             }
          }
       } else {
          UInt_t ind, nshrink=0, nexpand=0, size=0;
          for (ind = 0; ind < nthings; ++ind) {
             size += thing[ind].fDefSize;
             if (thing[ind].fExpand) ++ nexpand;
             if (thing[ind].fShrink) ++ nshrink;
          }

          // Did main frame expand?
          if ((size < real_size) && (nexpand >= 1)) {
             size = real_size - size;
             for (ind = 0; ind < nthings; ++ind) {
                if (thing[ind].fExpand) {
                   UInt_t extra = size / nexpand;
                   thing[ind].fRealSize += extra;
                   size -= extra;
                   --nexpand;
                }
             }
          }

          // Did main frame shrink?
          if (size > real_size) {
             UInt_t total_nshrink = nshrink;
             UInt_t extra = size - real_size;
             while (total_nshrink > 0 && extra > 0) {
                nshrink = total_nshrink;
                for (ind = 0; ind < nthings; ++ind)
                   if (thing[ind].fShrink) {
                      UInt_t size = thing[ind].fRealSize;
                      thing[ind].fRealSize = TMath::Max(1U,thing[ind].fRealSize - extra / nshrink);
                      extra -= size - thing[ind].fRealSize;
                      --nshrink;
                      if (thing[ind].fRealSize < 2) {
                         total_nshrink -= 1;
                         thing[ind].fShrink = kFALSE;
                      }
                   }
             }
          }
       } // not homogeneous
    }

    //______________________________________________________________________________
     void TGTableLayout::SetRowColSizes()
    {
       // This gets the new sizes needed to fit the table to the parent
       // frame. To be called after FindRowColSizes.

       SetRowColSizesInit();
       UInt_t border_width = fMain->GetBorderWidth();

       SetRowColResize(fMain->GetWidth() - (fNcols-1)*fSep - 2*border_width,
                       fNcols, fCol, fHomogeneous);
       SetRowColResize(fMain->GetHeight() - (fNrows-1)*fSep - 2*border_width,
                       fNrows, fRow, fHomogeneous);
    }

    //______________________________________________________________________________
     void TGTableLayout::SetRowColSizesInit()
    {
       // Initialize rows/cols. By default they do not expand and they
       // do shrink. What the children want determine what the rows/cols do.

       UInt_t col;
       for (col = 0; col < fNcols; ++col) {
          fCol[col].fRealSize = fCol[col].fDefSize;
          fCol[col].fNeedExpand = kFALSE;
          fCol[col].fNeedShrink = kTRUE;
          fCol[col].fExpand = kFALSE;
          fCol[col].fShrink = kTRUE;
          fCol[col].fEmpty = kTRUE;
       }
       UInt_t row;
       for (row = 0; row < fNrows; ++row) {
          fRow[row].fRealSize = fRow[row].fDefSize;
          fRow[row].fNeedExpand = kFALSE;
          fRow[row].fNeedShrink = kTRUE;
          fRow[row].fExpand = kFALSE;
          fRow[row].fShrink = kTRUE;
          fRow[row].fEmpty = kTRUE;
       }

       // Check single row/col children for expand/shrink-ability
       TIter next(fList);
       TGFrameElement *ptr;
       while ((ptr = (TGFrameElement*) next())) {
          TGTableLayoutHints *layout =
                dynamic_cast<TGTableLayoutHints*>(ptr->fLayout);
          if (!layout) {
             Error("SetRowColSizesInit", "didn't get TGTableLayoutHints");
             return;
          }
          ULong_t hints = layout->GetLayoutHints();

          // columns
          if (layout->GetAttachLeft() == layout->GetAttachRight()-1) {
             if (hints & kLHintsExpandX)
                fCol[layout->GetAttachLeft()].fExpand = kTRUE;
             if (!(hints & kLHintsShrinkX))
                fCol[layout->GetAttachLeft()].fShrink = kFALSE;
             fCol[layout->GetAttachLeft()].fEmpty = kFALSE;
          }
          // rows
          if (layout->GetAttachTop() == layout->GetAttachBottom()-1) {
             if (hints & kLHintsExpandY)
                fRow[layout->GetAttachTop()].fExpand = kTRUE;
             if (!(hints & kLHintsShrinkY))
                fRow[layout->GetAttachTop()].fShrink = kFALSE;
             fRow[layout->GetAttachTop()].fEmpty = kFALSE;
          }
       }

       // Do same for children of spanning multiple col/rows
       next.Reset();
       while ((ptr = (TGFrameElement*) next())) {
          TGTableLayoutHints *layout =
                dynamic_cast<TGTableLayoutHints*>(ptr->fLayout);
          if (!layout) {
             Error("SetRowColSizesInit", "didn't get TGTableLayoutHints");
             return;
          }
          ULong_t hints = layout->GetLayoutHints();

          // columns
          UInt_t left = layout->GetAttachLeft();
          UInt_t right = layout->GetAttachRight();
          if (left != right - 1) {
             for (col = left; col < right; ++col) fCol[col].fEmpty = kFALSE;
             Bool_t has_expand=kFALSE, has_shrink=kTRUE;
             if (hints & kLHintsExpandX) {
                for (col = left; col < right; ++col)
                   if (fCol[col].fExpand) { has_expand = kTRUE; break; }
                if (!has_expand)
                   for (col = left; col < right; ++col)
                      fCol[col].fNeedExpand = kTRUE;
             }
             if (!(hints & kLHintsShrinkX)) {
                for (col = left; col < right; ++col)
                   if (!fCol[col].fShrink) { has_shrink = kFALSE; break;}
                if (has_shrink)
                   for (col = left; col < right; ++col)
                      fCol[col].fNeedShrink = kFALSE;
             }
          }

          // rows
          UInt_t top = layout->GetAttachTop();
          UInt_t bottom = layout->GetAttachBottom();
          if (top != bottom - 1) {
             for (row = top; row < bottom; ++row) fRow[row].fEmpty = kFALSE;
             Bool_t has_expand=kFALSE, has_shrink=kTRUE;
             if (hints & kLHintsExpandY) {
                for (row = top; row < bottom; ++row)
                   if (fRow[row].fExpand) { has_expand = kTRUE; break; }
                if (!has_expand)
                   for (row = top; row < bottom; ++row)
                      fRow[row].fNeedExpand = kTRUE;
             }
             if (!(hints & kLHintsShrinkY)) {
                for (row = top; row < bottom; ++row)
                   if (!fRow[row].fShrink) { has_shrink = kFALSE; break;}
                if (has_shrink)
                   for (row = top; row < bottom; ++row)
                      fRow[row].fNeedShrink = kFALSE;
             }
          }
       }

       // Set expand/shrink flags
       for (col = 0; col < fNcols; ++col) {
          if (fCol[col].fEmpty) {
             fCol[col].fExpand = kFALSE;
             fCol[col].fShrink = kFALSE;
          } else {
             if (fCol[col].fNeedExpand) fCol[col].fExpand = kTRUE;
             if (!fCol[col].fNeedShrink) fCol[col].fShrink = kFALSE;
          }
       }
       for (row = 0; row < fNrows; ++row) {
          if (fRow[row].fEmpty) {
             fRow[row].fExpand = kFALSE;
             fRow[row].fShrink = kFALSE;
          } else {
             if (fRow[row].fNeedExpand) fRow[row].fExpand = kTRUE;
             if (!fRow[row].fNeedShrink) fRow[row].fShrink = kFALSE;
          }
       }
    }

    //______________________________________________________________________________
     void TGTableLayout::CheckSanity()
    {
       // Sanity check various values.

       TIter next(fList);
       TGFrameElement *ptr;
       UInt_t nerrors = 0;
       while ((ptr = (TGFrameElement*) next())) {
          TGTableLayoutHints *layout =
                dynamic_cast<TGTableLayoutHints*>(ptr->fLayout);
          if (!layout) {
             Error("CheckSanity", "didn't get TGTableLayoutHints");
             return;
          }

          UInt_t right  = layout->GetAttachRight();
          UInt_t left   = layout->GetAttachLeft();
          UInt_t top    = layout->GetAttachTop();
          UInt_t bottom = layout->GetAttachBottom();

          if (left == right) {
             ++nerrors;
             Error("CheckSanity", "AttachLeft == AttachRight");
          }
          if (left > right) {
             ++nerrors;
             Error("CheckSanity", "AttachLeft > AttachRight");
          }
          if (left > fNcols-1) {
             ++nerrors;
             Error("CheckSanity", "AttachLeft illegal value: %u", left);
          }
          if (right < 1 || right > fNcols) {
             ++nerrors;
             Error("CheckSanity", "AttachRight illegal value: %u", right);
          }

          if (top == bottom) {
             ++nerrors;
             Error("CheckSanity", "AttachTop == AttachBottom");
          }
          if (top > bottom) {
             ++nerrors;
             Error("CheckSanity", "AttachTop > AttachBottom");
          }
          if (top > fNrows-1) {
             ++nerrors;
             Error("CheckSanity", "AttachTop illegal value: %u", top);
          }
          if (bottom < 1 || bottom > fNrows) {
             ++nerrors;
             Error("CheckSanity", "AttachBottom illegal value: %u", bottom);
          }

       }
       if (nerrors) {
          Error("CheckSanity", "errors in %u x %u table", fNcols, fNrows);
       }
    }

    //______________________________________________________________________________
     void TGTableLayout::Layout()
    {
        // Make a table layout of all frames in the list.

       CheckSanity();

       FindRowColSizes();

       SetRowColSizes();

       // Do the layout
       TIter next(fList);
       TGFrameElement *ptr;
       UInt_t border_width = fMain->GetBorderWidth();
       while ((ptr = (TGFrameElement*) next())) {
          TGTableLayoutHints *layout = (TGTableLayoutHints*)ptr->fLayout;
          ULong_t hints = layout->GetLayoutHints();
          TGDimension size = ptr->fFrame->GetDefaultSize();

          UInt_t right  = layout->GetAttachRight();
          UInt_t left   = layout->GetAttachLeft();
          UInt_t top    = layout->GetAttachTop();
          UInt_t bottom = layout->GetAttachBottom();

          // Find location and size of cell in which to fit the child frame.
          UInt_t col, cell_x = border_width + left*fSep;
          for (col = 0; col < left; ++col) cell_x += fCol[col].fRealSize;

          UInt_t row, cell_y = border_width + top*fSep;
          for (row = 0; row < top; ++row) cell_y += fRow[row].fRealSize;

          UInt_t cell_width = (right-left-1)*fSep;
          for (col=left; col < right; ++col)
             cell_width += fCol[col].fRealSize;

          UInt_t cell_height = (bottom-top-1)*fSep;
          for (row=top; row < bottom; ++row)
             cell_height += fRow[row].fRealSize;

          UInt_t pad_left   = layout->GetPadLeft();
          UInt_t pad_right  = layout->GetPadRight();
          UInt_t pad_bottom = layout->GetPadBottom();
          UInt_t pad_top    = layout->GetPadTop();

          // find size of child frame
          UInt_t ww,hh;
          if (hints & kLHintsFillX)
             ww = cell_width  - pad_left - pad_right;
          else
             ww = size.fWidth;
          if (hints & kLHintsFillY)
             hh = cell_height - pad_top - pad_bottom;
          else
             hh = size.fHeight;

          // Find location of child frame
          UInt_t xx;
          if (hints & kLHintsFillX) // Fill beats right/center/left hints
             xx = cell_x + pad_left;
          else if (hints & kLHintsRight)
             xx = cell_x + cell_width - pad_right - ww;
          else if (hints & kLHintsCenterX)
             xx = cell_x + cell_width/2 - ww/2; // padding?
          else                    // defaults to kLHintsLeft
             xx = cell_x + pad_left;

          UInt_t yy;
          if (hints & kLHintsFillY) // Fill beats top/center/bottom hings
             yy = cell_y + pad_top;
          else if (hints & kLHintsBottom)
             yy = cell_y + cell_height - pad_bottom - hh;
          else if (hints & kLHintsCenterY)
             yy = cell_y + cell_height/2 - hh/2; // padding?
          else                    // defaults to kLHintsTop
             yy = cell_y + pad_top;

          ptr->fFrame->MoveResize(xx,yy,ww,hh);
          ptr->fFrame->Layout();

       }
    }

    //______________________________________________________________________________
     TGDimension TGTableLayout::GetDefaultSize() const
    {
       // Return default dimension of the table layout.

       Int_t border_width = fMain->GetBorderWidth();

       TGDimension size(2*border_width + (fNcols-1)*fSep,
                        2*border_width + (fNrows-1)*fSep);

       UInt_t col, row;
       if (fCol)
          for (col = 0; col < fNcols; ++col) size.fWidth += fCol[col].fDefSize;
       if (fRow)
          for (row = 0; row < fNrows; ++row) size.fHeight += fRow[row].fDefSize;

       return size;
    }

    // ________________________________________________________________________
    void TGTableLayoutHints::SavePrimitive(ofstream &out, Option_t *)
    {

       // Save table layout hints as a C++ statement(s) on output stream out.

       TString hints;
       UInt_t pad = GetPadLeft()+GetPadRight()+GetPadTop()+GetPadBottom();

       if (!GetLayoutHints()) return;

       if ((fLayoutHints == kLHintsNormal) && (pad == 0)) return;

       if (fLayoutHints & kLHintsLeft) {
          if (hints.Length() == 0) hints  = "kLHintsLeft";
          else                     hints += " | kLHintsLeft";
       }
       if (fLayoutHints & kLHintsCenterX) {
          if  (hints.Length() == 0) hints  = "kLHintsCenterX";
          else                     hints += " | kLHintsCenterX";
       }
       if (fLayoutHints & kLHintsRight) {
          if (hints.Length() == 0) hints  = "kLHintsRight";
          else                     hints += " | kLHintsRight";
       }
       if (fLayoutHints & kLHintsTop) {
          if (hints.Length() == 0) hints  = "kLHintsTop";
          else                     hints += " | kLHintsTop";
       }
       if (fLayoutHints & kLHintsCenterY) {
          if (hints.Length() == 0) hints  = "kLHintsCenterY";
          else                     hints += " | kLHintsCenterY";
       }
       if (fLayoutHints & kLHintsBottom) {
          if (hints.Length() == 0) hints  = "kLHintsBottom";
          else                     hints += " | kLHintsBottom";
       }
       if (fLayoutHints & kLHintsExpandX) {
          if (hints.Length() == 0) hints  = "kLHintsExpandX";
          else                     hints += " | kLHintsExpandX";
       }
       if (fLayoutHints & kLHintsExpandY) {
          if (hints.Length() == 0) hints  = "kLHintsExpandY";
          else                     hints += " | kLHintsExpandY";
       }
       if (fLayoutHints & kLHintsShrinkX) {
          if (hints.Length() == 0) hints  = "kLHintsShrinkX";
          else                     hints += " | kLHintsShrinkX";
       }
       if (fLayoutHints & kLHintsShrinkY) {
          if (hints.Length() == 0) hints  = "kLHintsShrinkY";
          else                     hints += " | kLHintsShrinkY";
       }
       if (fLayoutHints & kLHintsFillX) {
          if (hints.Length() == 0) hints  = "kLHintsFillX";
          else                     hints += " | kLHintsFillX";
       }
       if (fLayoutHints & kLHintsFillY) {
          if (hints.Length() == 0) hints  = "kLHintsFillY";
          else                     hints += " | kLHintsFillY";
       }
       out << ", new TGTableLayoutHints(" << GetAttachLeft() << "," << GetAttachRight()
           << "," << GetAttachTop()  << "," << GetAttachBottom()
           << "," << hints;

       if (pad) {
          out << "," << GetPadLeft() << "," << GetPadRight()
              << "," << GetPadTop()  << "," << GetPadBottom();
        }
        out << ")";
    }

    // __________________________________________________________________________
     void TGTableLayout::SavePrimitive(ofstream &out, Option_t *)
    {

       // Save table layout as a C++ statement(s) on output stream.

       out << " new TGTableLayout(" << fMain->GetName() << "," << fNrows << "," << fNcols;

       if (fSep) {
          if (fHomogeneous == kTRUE)
             out << ", kTRUE";
          else
             out << ", kFALSE";
       out << fSep;
       }
       out  << ")";
       // hints parameter is not used/saved currently

    }