#ifndef DOCKBAR_H_
#define DOCKBAR_H_

#include "basebar.h"
//      local macros
//
// configurable constants

#define XXX_NEW         0       // 1=turn on work-in-progress
#define XXX_BROWSEROWNED    0   // 1:browser deskbar is owned (proto)
#define XXX_CHEEDESK    0       // 1:chee's desktop (vs. _fDesktop)
#define XXX_BTMFLOAT    0       // 0=allow dragging from non-desk-btm->float
#define XXX_HIDE        1       // 1=turn on autohide (work-in-progress)
#define XXX_HIDEALL     1       // 1=enable autohide in browsers (non-topmost)


#define XXX_CANCEL      0       // 1=use experimental CANCEL code
#define XXX_NEWSLIDE    0       // 1=use new SlideWindow code

#ifndef UNREFERENCED_PARM
#define UNREFERENCED_PARM(p)    (p)      // ARGUSED
#endif

//***   _PM, _PX -- lazy shorthands
// DESCRIPTION
//      _PM     check for p==NULL before doing p->m
//      _PX     check for p==NULL before doing EXPR(p)
//
#define _PM(p, m)       ((p) ? (p)->m : (-1))
#define _PX(p, x)       ((p) ? (x) : (-1))

#define BITS_SET(v, m)  (((v) & (m)) == (m))

//***   IN, OUT, INOUT --
//
#define IN
#define OUT
#define INOUT

#ifndef NOCDESKBAR
#include "dhuihand.h"

//========================================================================
// class CDeskBar (CDeskBar* pwbar)
// NOTES
//  we don't use CObjectWithSite because we want _ptbSite not _punkSite.
//========================================================================
class CDockingBar : public CBaseBar
                ,public IDockingWindow
                ,public IObjectWithSite     // n.b. *not* CObjectWithSite
                ,public IPersistStreamInit
                ,public IPersistPropertyBag
                ,public CDocHostUIHandler
{
public:
    // *** IUnknown -- disambiguate ***
    virtual STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
    virtual STDMETHODIMP_(ULONG) AddRef(void)
        { return CBaseBar::AddRef(); }
    virtual STDMETHODIMP_(ULONG) Release(void)
        { return CBaseBar::Release(); }

    // *** IOleWindow -- disambiguate ***
    virtual STDMETHODIMP GetWindow(HWND * lphwnd)
        { return CBaseBar::GetWindow(lphwnd); }
    virtual STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode)
        { return CBaseBar::ContextSensitiveHelp(fEnterMode); }

    // *** IOleCommandTarget methods ***
    virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup,
        DWORD nCmdID, DWORD nCmdexecopt,
        VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);

    // *** IDockingWindow methods ***
    virtual STDMETHODIMP ShowDW(BOOL fShow);
    virtual STDMETHODIMP CloseDW(DWORD dwReserved) { return CBaseBar::CloseDW(dwReserved); }
    virtual STDMETHODIMP ResizeBorderDW(LPCRECT prcBorder,
        IUnknown* punkToolbarSite, BOOL fReserved);

    // *** IObjectWithSite methods ***
    virtual STDMETHODIMP SetSite(IUnknown* punkSite);
    // NOTE: I sure hope E_NOTIMPL is ok?
    virtual STDMETHODIMP GetSite(REFIID riid, void** ppvSite) { ASSERT(0); *ppvSite = NULL; return E_NOTIMPL; };

    // *** IServiceProvider methods ***
    virtual STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, LPVOID* ppvObj);

    // *** IPersistStreamInit ***
    //virtual STDMETHODIMP GetClassID(CLSID *pClassID);
    virtual STDMETHODIMP IsDirty(void);
    virtual STDMETHODIMP Load(IStream *pStm);
    virtual STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty);
    virtual STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize);
    virtual STDMETHODIMP InitNew(void);

    // *** IPersistPropertyBag ***
    virtual STDMETHODIMP Load(IPropertyBag *pPropBag,
                                           IErrorLog *pErrorLog);
    virtual STDMETHODIMP Save(IPropertyBag *pPropBag,
                        BOOL fClearDirty, BOOL fSaveAllProperties);

    // *** IInputObjectSite methods ***
    virtual STDMETHODIMP OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus);
    
    // *** IDocHostUIHandler methods ***
    virtual STDMETHODIMP ShowContextMenu(DWORD dwID,
        POINT* ppt, IUnknown* cmdtReserved, IDispatch* pdispReserved);

protected:
    // Constructor & Destructor
    CDockingBar();
    virtual ~CDockingBar();
    
    void _Initialize();         // 2nd-phase ctor
    virtual void _SetModeSide(UINT eMode, UINT uSide, HMONITOR hMon, BOOL fNoMerge);
    virtual void _OnPostedPosRectChange();
    virtual void _GetChildPos(LPRECT prc);
    virtual void _GetStyleForMode(UINT eMode, LONG* plStyle, LONG* plExStyle, HWND* phwndParent);
    
    friend HRESULT CDeskBar_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);
    friend HRESULT CDeskBar_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);
    friend HRESULT BrowserBar_Create(IUnknown** ppunk, IUnknown** ppbs);

    // Private members
    HMENU _GetContextMenu();

    virtual LRESULT _OnCommand(UINT msg, WPARAM wparam, LPARAM lparam);
    void _ChangeTopMost(UINT eModeNew);
    void _ChangeWindowStateAndParent(UINT eModeNew);
    void _ChangeZorder();
    void _ResetZorder();
    virtual void _OnRaise(UINT flags);
#if XXX_BTMFLOAT && 0
    void _MayReWindow(BOOL fToFloat);
#endif
    
    virtual void _NotifyModeChange(DWORD dwMode);
    void _GetBorderRect(HMONITOR hMon, RECT* prc);
    HRESULT _NegotiateBorderRect(RECT* prcOut, RECT* prcReq, BOOL fCommit);
    virtual void _OnSize(void);
    void _InitPos4(BOOL fCtor);
    void _ProtoRect(RECT* prcOut, UINT eModeNew, UINT uSideNew, HMONITOR hMonNew, POINT* ptXY);
    void _NegotiateRect(UINT eModeNew, UINT uSideNew, HMONITOR hMonNew, RECT* rcReq, BOOL fCommit);
    void _MoveSizeHelper(UINT eModeNew, UINT eSideNew, HMONITOR hMonNew,
        POINT* ptTrans, RECT* rcFeed, BOOL fCommit, BOOL fMove);
    void _SetVRect(RECT* rcNew);
    void _Recalc(void);

    LRESULT _CalcHitTest(WPARAM wParam, LPARAM lParam);

    void _DragEnter(UINT uMsg, int xCursor, int yCursor, RECT* rcFeed);
    void _DragTrack(UINT uMsg, int xCursor, int yCursor, RECT* rcFeed, int eState);
    void _DragLeave(int x, int y, BOOL fCommit);
    void _ExecDrag(int eDragging);

    void _TrackSliding(int x, int y, RECT* rcFeed,
        BOOL fCommit, BOOL fMove);
    UINT _CalcDragPlace(POINT& pt, HMONITOR * hMon);
    void _SmoothDragPlace(UINT eModeNew, UINT eSideNew, HMONITOR hMonNew, INOUT POINT* pt, RECT* rcFeed);
    void _RemoveToolbar(DWORD dwFlags);

    HRESULT _TrackPopupMenu(const POINT* ppt);
    HMONITOR _SetNewMonitor(HMONITOR hMonNew);

    void _HideRegister(BOOL fToHide);
    void _DoHide(UINT uOpMask);
    virtual void _HandleWindowPosChanging(LPWINDOWPOS pwp);
    virtual void _GrowShrinkBar(DWORD dwDirection);

#if 0
    void _DoManHide(UINT uOpMask);
#endif
        // for _DoHide and _DoManHide
        enum aho {
            AHO_KILLDO  = 0x01,
            AHO_SETDO   = 0x02,
            AHO_KILLUN  = 0x04,
            AHO_SETUN   = 0x08,
            AHO_REG     = 0x10,
            AHO_UNREG   = 0x20,
            AHO_MOVEDO  = 0x40,
            AHO_MOVEUN  = 0x80
        };

        #define AHO_MNE         TEXT("ksKSrRmM")

    void _AppBarRegister(BOOL fRegister);
    void _AppBarOnSize();
    void _AppBarOnCommand(UINT idCmd);
    void _AppBarOnWM(UINT uMsg, WPARAM wParam, LPARAM lParam);
    void _AppBarOnPosChanged(PAPPBARDATA pabd);
    void _AppBarCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    int AppBarQueryPos(RECT* prcOut, UINT uEdge, HMONITOR hMon, const RECT* prcReq, PAPPBARDATA pabd, BOOL fCommit);
    void AppBarSetPos(UINT uEdge, const RECT* prcReq, PAPPBARDATA pabd);
    void AppBarSetPos0(UINT uEdge, const RECT* prcReq, PAPPBARDATA pabd);
    void AppBarQuerySetPos(RECT* prcOut, UINT uEdge, HMONITOR hMon, const RECT* prcReq, PAPPBARDATA pabd, BOOL fCommit);
    LRESULT _OnNCHitTest(WPARAM wParam, LPARAM lParam);

    void _AdjustToChildSize();

    // Window procedure
    virtual LRESULT v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    void _OnActivate(WPARAM wParam, LPARAM lParam);

    virtual BOOL _OnCloseBar(BOOL fConfirm);


#define RX_EDGE         0x01
#define RX_OPPOSE       0x02
#define RX_ADJACENT     0x04
#define RX_GETWH        0x08
#define RX_HIDE         0x10

    //
    // We need to do a get window in side this function so that we
    // can mirror the edges. I changed them to non-static. [samera]
    //
    int RectXform(RECT* prcOut, UINT uRxMask,
        const RECT* prcIn, RECT* prcBound, int iWH, UINT uSide, HMONITOR hMon);
    
    int RectGetWH(const RECT* prcReq, UINT uSide) {
        return RectXform(NULL, RX_GETWH, prcReq, NULL, -1, uSide, NULL);
    }

    void RectSetWH(RECT* prcReq, int iWH, UINT uSide) {
        RectXform(prcReq, RX_OPPOSE, prcReq, NULL, iWH, uSide, NULL);
        return;
    }

    // Member variables
    IDockingWindowSite*  _ptbSite;           // owner
    INT             _adEdge[4];             // edges' widths (or heights)
    RECT            _rcFloat;               // floating position
    HMONITOR        _hMon;                  // the monitor I am on
    POINT           _ptIdtUnHide;           // unhide hysteresis cursor pos

    // Variable initialized IPersistPropertyBag::Load
    // ...

    // Bit fields
    UINT            _uSide:3;               // edge we're on (ABE_*)
    // 3 states to initialization (4 w/ ctor)
    BITBOOL         _fInitSited:1;          // SetSite done
    UINT            _eInitLoaded:2;         // Load (or InitNew) done
    BITBOOL         _fInitShowed:1;         // Show done
#if ! XXX_CHEEDESK
    BITBOOL         _fDesktop:1;            // 1:hosted by desktop (vs. browser)
#endif
    UINT            _fDragging:2;           // we're dragging
    BITBOOL         _fWantHide:1;           // 1:autohide requested (in UI)
    BITBOOL         _fDeleteable:1;         // when we close we should signal our parent to delete our info
    BITBOOL         _fAppRegistered:1;      // Registered as an appbar

    // Member variables (drag&drop, sizing, ...)
    UINT            _uSidePending:3;        // ...
    BITBOOL         _fCanHide:1;            // 1:autohide granted (registered)
    BOOL            _fHiding:2;             // hide mode (HIDE_*)
    BITBOOL         _fIdtDoHide:1;          // 1:IDT_AUTOHIDE running
    BITBOOL         _fIdtUnHide:1;          // 1:IDT_AUTOUNHIDE running

    UINT            _eMode;               // mode we're in (WBM_*)
    UINT            _eModePending;        // pending drag state
    
    LPARAM          _xyPending;             // pending drag state
    RECT            _rcPending;             // ...
    HMONITOR        _hMonPending;           // pending monitor 
#ifdef DEBUG
    // temporary until we make browser tell us about activation
    BOOL            _fActive:1;             // 1:window is active
#endif

    
    // MOVE TO CBROWSERBAR    
    BITBOOL _fTheater :1;
    BITBOOL _fNoAutoHide :1;
    int _iTheaterWidth;
    // END MOVE TO CBROWSERBAR
};

#define WBM_IS_TOPMOST() (_eMode & WBM_TOPMOST)

#endif //NOCDESKBAR

//***   CASSERT -- compile-time assert
// DESCRIPTION
//      Like Assert, but checked at compile-time, and generates no code
//      Note that the expr must of course be constant...
#ifndef UNIX
#define CASSERT(e)      extern int dummy_array[(e)]
#else
#define CASSERT(e)      
#endif

//***   ABE_* -- helpers, etc. for ABE_*'s
//

//***   ABE_X* -- extended ABE_*'s
// DESCRIPTION
//      ABE_NIL: distinguished value (unused?).
//
//      ABE_XFLOATING: normally we carry around a (mode,side) pair.  this
//      works fine but is a pain in the (rare) case that we want to return
//      a pair.  so we have a 'special' side which means we're really
//      floating.  (alternatives considered included combining the two via
//      bit magic, or passing by reference.  none stood out as a great
//      sol'n, and we only use it one place.  a hack?  perhaps...)
#define ABE_NIL         ((UINT) 0x07)   // nil (-1 as a 3-bit field) (ugh!)
#define ABE_XFLOATING   ((UINT) 4)      // floating (undocked)
CASSERT((ABE_LEFT|ABE_RIGHT|ABE_TOP|ABE_BOTTOM) == 3);  // 0..3

#define ISABE_DOCK(abe) ((UINT)(abe) <= 3)

#define ABE_TO_IDM(abe) (IDM_AB_LEFT + (abe))
#define IDM_TO_ABE(abe) ((abe) - IDM_AB_LEFT)
CASSERT(IDM_AB_BOTTOM - IDM_AB_LEFT == 3);      // make sure LEFT is 0th

//***   ABE_HORIZ -- is ABE_* horizontal?
// #define ABE_HORIZ(e) ((e) == ABE_TOP || (e) == ABE_BOTTOM)
#define ABE_HORIZ(e)    ((e) & 1)
CASSERT(ABE_HORIZ(ABE_TOP) && ABE_HORIZ(ABE_BOTTOM));
CASSERT(! ABE_HORIZ(ABE_LEFT) && ! ABE_HORIZ(ABE_RIGHT));


#define APPBAR_CALLBACK (WM_USER + 73)  // REARCHITECT: bad bad bad, I don't know why this is bad but it's previous tagname was unacceptable, perhaps someone should look at this someday - justmann


//***   WS_*, etc. -- window bits, etc. for various modes
// NOTES
//      REVIW Don't use SM_CAPTION because it doesn't work properly yet.
//      WS_XTOPMOST w/ an 'X' to avoid collision w/ WS_TOPMOST...

#define WS_NIL          (WS_POPUP|WS_CLIPCHILDREN|WS_CLIPSIBLINGS)
#define WS_EX_NIL       (WS_EX_TOOLWINDOW /*|WS_EX_WINDOWEDGE*/)
#define PARENT_NIL      (HWND_DESKTOP)

#define WS_XTOPMOST     (WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_CLIPSIBLINGS)
#define WS_EX_XTOPMOST  (WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE)
#define PARENT_XTOPMOST (HWND_DESKTOP)

#define WS_BTMMOST      (WS_POPUP|WS_THICKFRAME|WS_CLIPCHILDREN|WS_CLIPSIBLINGS)
#define WS_EX_BTMMOST   (WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE)
#define PARENT_BTMMOST() HWND_DESKTOP

#if 0
// 970208 keep this around for 1 week in case the autosize bug isn't fixed
#define WS_BTMMOST      WS_BBTMMOST
#define WS_EX_BTMMOST   WS_EX_BBTMMOST
#define PARENT_BTMMOST() PARENT_BBTMMOST()
#endif

#define WS_BFLOATING     ((/*WS_POPUP*/WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME |WS_THICKFRAME|WS_CLIPCHILDREN|WS_CLIPSIBLINGS) & ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX))
#define WS_EX_BFLOATING  (/*WS_EX_PALETTEWINDOW | */ WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE)


#define WS_FLOATING     ((/*WS_POPUP*/WS_TILEDWINDOW|WS_THICKFRAME|WS_CLIPCHILDREN|WS_CLIPSIBLINGS) & ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX))
#define WS_EX_FLOATING  (WS_EX_PALETTEWINDOW | WS_EX_WINDOWEDGE)
#define PARENT_FLOATING (HWND_DESKTOP)

#if XXX_BROWSEROWNED
#define WS_BBTMMOST     WS_FLOATING
#define WS_EX_BBTMMOST  (WS_EX_FLOATING|WS_EX_TOOLWINDOW)
#define PARENT_BBTMMOST PARENT_FLOATING
#else
// non-topmost
#define WS_BBTMMOST     (WS_CHILD/*|WS_BORDER|WS_THICKFRAME*/|WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
#define WS_EX_BBTMMOST  (WS_EX_CLIENTEDGE /*|WS_EX_WINDOWEDGE*/)
#define PARENT_BBTMMOST() (_hwndSite)
#endif

#define ISWSX_EDGELESS(ws, wsx) \
    (!(((ws)&WS_THICKFRAME) || ((wsx)&WS_EX_WINDOWEDGE)))

#define ISWBM_EDGELESS(eMode) \
    ((eMode==WBM_BBOTTOMMOST && ISWSX_EDGELESS(WS_BBTMMOST, WS_EX_BBTMMOST)) \
    || (eMode==WBM_BOTTOMMOST && ISWSX_EDGELESS(WS_BTMMOST, WS_EX_BTMMOST)))

#define XY_NIL          ((LPARAM) (-1))

// drag state
#define DRAG_NIL        0       // nil
#define DRAG_MOVE       1       // moving
#define DRAG_SIZE       2       // sizing

extern void DBC_ExecDrag(IUnknown *pDbc, int eDragging);

#define WBMF_BROWSER    (0x0001000)        // hosted by browser (vs. by desktop)
#define WBM_BBOTTOMMOST (WBMF_BROWSER|WBM_BOTTOMMOST)
//#define WBM_BTOPMOST    (WBMF_BROWSER|WBM_TOPMOST)
#define WBM_BFLOATING   (WBMF_BROWSER|WBM_FLOATING)
#define WBM_BNIL        *** error! ***


//***   ISWBM_* -- check mode
#define ISWBM_FLOAT(eMode) \
                           (eMode & WBM_FLOATING)

#define ISWBM_BOTTOM(eMode) \
    ((eMode) == WBM_BOTTOMMOST || (eMode) == WBM_BBOTTOMMOST)

#if XXX_CHEEDESK
#define ISWBM_DESKTOP()     (!(_eMode & WBMF_BROWSER))
#else
#define ISWBM_DESKTOP()     (_fDesktop)
#endif

#if XXX_BROWSEROWNED
#define ISWBM_OWNED(eMode) ((!ISWBM_DESKTOP()) && \
    ((eMode) == WBM_BFLOATING || (eMode) == WBM_BBOTTOMMOST))
#else
#define ISWBM_OWNED(eMode) ((eMode) == WBM_BFLOATING)
#endif

#if XXX_HIDE
#if XXX_HIDEALL
#define ISWBM_HIDEABLE(eMode)   (((eMode) & ~WBMF_BROWSER) != WBM_FLOATING)
#else
#define ISWBM_HIDEABLE(eMode)   ((eMode) == WBM_TOPMOST)
#endif
#endif

#define CHKWBM_CHANGE(eModeNew, eModeCur) \
    (((eModeNew) & WBMF_BROWSER) == ((eModeCur) & WBMF_BROWSER) \
        || (eModeNew) == WBM_NIL || (eModeCur) == WBM_NIL) 


//***   timer stuff
#define IDT_POPUI       10
#define IDT_AUTOHIDE    11
#define IDT_AUTOUNHIDE  12

#define DLY_AUTOHIDE    500
#define DLY_AUTOUNHIDE  50

//***   hide state (_fHiding)
#define HIDE_FALSE      0       // must be FALSE
#define HIDE_AUTO       1       // currently hidden (due to autohide)
#define HIDE_MANUAL     2       // currently hidden (due to manual hide)

CASSERT(! HIDE_FALSE);


#if 0
//***   MKMS, MSTO* -- make/crack combined mode+side
//
#define MSTOMODE(ms)    (((UINT) (ms)) >> 8)
#define MSTOSIDE(ms)    (((UINT) (ms)) & 0x7)
#define MKMS(m, s)      ((((UINT) (m)) << 8) | (UINT) (s))
#endif

#if WEBBAR_APP
HMENU LoadMenuPopup(UINT id);
extern HINSTANCE        g_hinst;
#define HINST_THISDLL   g_hinst
#endif

// REARCHITECT we can replace these once the portability layer is up and running.
#define Command_GetNotifyCode(wp,lp)    HIWORD(wp)
#define Command_GetHwndCtl(lp)          ((HWND)lp)
#define Command_GetID(wp)               LOWORD(wp)


CASSERT((ABE_LEFT|ABE_RIGHT|ABE_TOP|ABE_BOTTOM) == 3);  // must fit in _uSide:2

//***   MoveRect -- move left-top corner of rect to (x,y)
//
#define MoveRect(prc, x, y) \
    OffsetRect((prc), (x) - (prc)->left, (y) - (prc)->top)

#define AB_THEIGHT(rc)  (RECTHEIGHT(rc) * 10 / 100)     // 10%
#define AB_BHEIGHT(rc)  (RECTHEIGHT(rc) * 10 / 100)     // 10%
#define AB_LWIDTH(rc)   (40)                            // fixed width 40
#define AB_RWIDTH(rc)   ( RECTWIDTH(rc) * 35 / 100)     // 30%

void SlideWindow(HWND hwnd, RECT *prc, HMONITOR hMonClip, BOOL fShow);


class PropDataSet {
public:
    BOOL _fSet;
    DWORD _dwData;
};

class CDockingBarPropertyBag :
      public IPropertyBag
    , public IDockingBarPropertyBagInit
{
public:
    // *** IUnknown ***
    virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
    virtual STDMETHODIMP_(ULONG) AddRef(void) ;
    virtual STDMETHODIMP_(ULONG) Release(void);

    // *** IPropertyBag ***
    virtual HRESULT STDMETHODCALLTYPE Read( 
                                           /* [in] */ LPCOLESTR pszPropName,
                                           /* [out][in] */ VARIANT *pVar,
                                           /* [in] */ IErrorLog *pErrorLog);

    virtual HRESULT STDMETHODCALLTYPE Write( 
                                            /* [in] */ LPCOLESTR pszPropName,
                                            /* [in] */ VARIANT *pVar) {return E_NOTIMPL;};

    // *** IDockingBarPropertyBagInit
    virtual STDMETHODIMP SetDataDWORD(ENUMPROPDATA e, DWORD dwData) { _props[e]._fSet = TRUE; _props[e]._dwData = dwData; return S_OK; }
    
protected:
    CDockingBarPropertyBag() { _cRef = 1; };
    friend HRESULT CDockingBarPropertyBag_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi);

    UINT _cRef;
    
    PropDataSet _props[PROPDATA_COUNT];
    
}; 

#endif