text:
/////////////////////////////////////////////////////////////////////////////
// Name:        src/html/helpwnd.cpp
// Purpose:     wxHtmlHelpWindow
// Notes:       Based on htmlhelp.cpp, implementing a monolithic
//              HTML Help controller class,  by Vaclav Slavik
// Author:      Harm van der Heijden and Vaclav Slavik
// RCS-ID:      $Id$
// Copyright:   (c) Harm van der Heijden and Vaclav Slavik
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx.h"

#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#if wxUSE_WXHTML_HELP

#ifndef WX_PRECOMP
    #include "wx/object.h"
    #include "wx/dynarray.h"
    #include "wx/intl.h"
    #include "wx/log.h"
    #if wxUSE_STREAMS
        #include "wx/stream.h"
    #endif

    #include "wx/sizer.h"

    #include "wx/bmpbuttn.h"
    #include "wx/statbox.h"
    #include "wx/radiobox.h"
    #include "wx/menu.h"
    #include "wx/settings.h"
    #include "wx/msgdlg.h"
    #include "wx/textctrl.h"
    #include "wx/toolbar.h"
    #include "wx/choicdlg.h"
    #include "wx/filedlg.h"
#endif // WX_PRECOMP

#include "wx/html/helpfrm.h"
#include "wx/html/helpdlg.h"
#include "wx/html/helpctrl.h"
#include "wx/notebook.h"
#include "wx/imaglist.h"
#include "wx/treectrl.h"
#include "wx/tokenzr.h"
#include "wx/wfstream.h"
#include "wx/html/htmlwin.h"
#include "wx/busyinfo.h"
#include "wx/progdlg.h"
#include "wx/fontenum.h"
#include "wx/artprov.h"
#include "wx/spinctrl.h"

// what is considered "small index"?
#define INDEX_IS_SMALL 100

/* Motif defines this as a macro */
#ifdef Below
#undef Below
#endif

//--------------------------------------------------------------------------
// wxHtmlHelpTreeItemData (private)
//--------------------------------------------------------------------------

class wxHtmlHelpTreeItemData : public wxTreeItemData
{
    public:
#if defined(__VISAGECPP__)
//  VA needs a default ctor for some reason....
        wxHtmlHelpTreeItemData() : wxTreeItemData()
            { m_Id = 0; }
#endif
        wxHtmlHelpTreeItemData(int id) : wxTreeItemData()
            { m_Id = id;}

        int m_Id;
};

//--------------------------------------------------------------------------
// wxHtmlHelpHashData (private)
//--------------------------------------------------------------------------

class wxHtmlHelpHashData : public wxObject
{
    public:
        wxHtmlHelpHashData(int index, wxTreeItemId id) : wxObject()
            { m_Index = index; m_Id = id;}
        virtual ~wxHtmlHelpHashData() {}

        int m_Index;
        wxTreeItemId m_Id;
};

//--------------------------------------------------------------------------
// wxHtmlHelpHtmlWindow (private)
//--------------------------------------------------------------------------

class wxHtmlHelpHtmlWindow : public wxHtmlWindow
{
public:
    wxHtmlHelpHtmlWindow(wxHtmlHelpWindow *win, wxWindow *parent, wxWindowID id = wxID_ANY,
                         const wxPoint& pos = wxDefaultPosition, const wxSize& sz = wxDefaultSize, long style = wxHW_DEFAULT_STYLE)
        : wxHtmlWindow(parent, id, pos, sz, style), m_Window(win)
    {
        SetStandardFonts();
    }

    void OnLink(wxHtmlLinkEvent& ev)
    {
        const wxMouseEvent *e = ev.GetLinkInfo().GetEvent();
        if (e == NULL || e->LeftUp())
            m_Window->NotifyPageChanged();

        // skip the event so that normal processing (i.e. following the link)
        // is done:
        ev.Skip();
    }

    // Returns full location with anchor (helper)
    static wxString GetOpenedPageWithAnchor(wxHtmlWindow *win)
    {
        if(!win)
            return wxEmptyString;

        wxString an = win->GetOpenedAnchor();
        wxString pg = win->GetOpenedPage();
        if(!an.empty())
        {
            pg << wxT("#") << an;
        }
        return pg;
    }

private:
    wxHtmlHelpWindow *m_Window;

    wxDECLARE_NO_COPY_CLASS(wxHtmlHelpHtmlWindow);
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(wxHtmlHelpHtmlWindow, wxHtmlWindow)
    EVT_HTML_LINK_CLICKED(wxID_ANY, wxHtmlHelpHtmlWindow::OnLink)
END_EVENT_TABLE()

//---------------------------------------------------------------------------
// wxHtmlHelpWindow::m_mergedIndex
//---------------------------------------------------------------------------

WX_DEFINE_ARRAY_PTR(const wxHtmlHelpDataItem*, wxHtmlHelpDataItemPtrArray);

struct wxHtmlHelpMergedIndexItem
{
    wxHtmlHelpMergedIndexItem *parent;
    wxString                   name;
    wxHtmlHelpDataItemPtrArray items;
};

WX_DECLARE_OBJARRAY(wxHtmlHelpMergedIndexItem, wxHtmlHelpMergedIndex);
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxHtmlHelpMergedIndex)

void wxHtmlHelpWindow::UpdateMergedIndex()
{
    delete m_mergedIndex;
    m_mergedIndex = new wxHtmlHelpMergedIndex;
    wxHtmlHelpMergedIndex& merged = *m_mergedIndex;

    const wxHtmlHelpDataItems& items = m_Data->GetIndexArray();
    size_t len = items.size();

    wxHtmlHelpMergedIndexItem *history[128] = {NULL};

    for (size_t i = 0; i < len; i++)
    {
        const wxHtmlHelpDataItem& item = items[i];
        wxASSERT_MSG( item.level < 128, wxT("nested index entries too deep") );

        if (history[item.level] &&
            history[item.level]->items[0]->name == item.name)
        {
            // same index entry as previous one, update list of items
            history[item.level]->items.Add(&item);
        }
        else
        {
            // new index entry
            wxHtmlHelpMergedIndexItem *mi = new wxHtmlHelpMergedIndexItem();
            mi->name = item.GetIndentedName();
            mi->items.Add(&item);
            mi->parent = (item.level == 0) ? NULL : history[item.level - 1];
            history[item.level] = mi;
            merged.Add(mi);
        }
    }
}

//---------------------------------------------------------------------------
// wxHtmlHelpWindow
//---------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS(wxHtmlHelpWindow, wxWindow)

BEGIN_EVENT_TABLE(wxHtmlHelpWindow, wxWindow)
    EVT_TOOL_RANGE(wxID_HTML_PANEL, wxID_HTML_OPTIONS, wxHtmlHelpWindow::OnToolbar)
    EVT_BUTTON(wxID_HTML_BOOKMARKSREMOVE, wxHtmlHelpWindow::OnToolbar)
    EVT_BUTTON(wxID_HTML_BOOKMARKSADD, wxHtmlHelpWindow::OnToolbar)
    EVT_TREE_SEL_CHANGED(wxID_HTML_TREECTRL, wxHtmlHelpWindow::OnContentsSel)
    EVT_LISTBOX(wxID_HTML_INDEXLIST, wxHtmlHelpWindow::OnIndexSel)
    EVT_LISTBOX(wxID_HTML_SEARCHLIST, wxHtmlHelpWindow::OnSearchSel)
    EVT_BUTTON(wxID_HTML_SEARCHBUTTON, wxHtmlHelpWindow::OnSearch)
    EVT_TEXT_ENTER(wxID_HTML_SEARCHTEXT, wxHtmlHelpWindow::OnSearch)
    EVT_BUTTON(wxID_HTML_INDEXBUTTON, wxHtmlHelpWindow::OnIndexFind)
    EVT_TEXT_ENTER(wxID_HTML_INDEXTEXT, wxHtmlHelpWindow::OnIndexFind)
    EVT_BUTTON(wxID_HTML_INDEXBUTTONALL, wxHtmlHelpWindow::OnIndexAll)
    EVT_COMBOBOX(wxID_HTML_BOOKMARKSLIST, wxHtmlHelpWindow::OnBookmarksSel)
    EVT_SIZE(wxHtmlHelpWindow::OnSize)
END_EVENT_TABLE()

wxHtmlHelpWindow::wxHtmlHelpWindow(wxWindow* parent, wxWindowID id,
                                    const wxPoint& pos,
                                    const wxSize& size,
                                    int style, int helpStyle, wxHtmlHelpData* data)
{
    Init(data);
    Create(parent, id, pos, size, style, helpStyle);
}

void wxHtmlHelpWindow::Init(wxHtmlHelpData* data)
{
    if (data)
    {
        m_Data = data;
        m_DataCreated = false;
    }
    else
    {
        m_Data = new wxHtmlHelpData();
        m_DataCreated = true;
    }

    m_ContentsPage = 0;
    m_IndexPage = 0;
    m_SearchPage = 0;

    m_ContentsBox = NULL;
    m_IndexList = NULL;
    m_IndexButton = NULL;
    m_IndexButtonAll = NULL;
    m_IndexText = NULL;
    m_SearchList = NULL;
    m_SearchButton = NULL;
    m_SearchText = NULL;
    m_SearchChoice = NULL;
    m_IndexCountInfo = NULL;
    m_Splitter = NULL;
    m_NavigPan = NULL;
    m_NavigNotebook = NULL;
    m_HtmlWin = NULL;
    m_Bookmarks = NULL;
    m_SearchCaseSensitive = NULL;
    m_SearchWholeWords = NULL;

    m_mergedIndex = NULL;

#if wxUSE_CONFIG
    m_Config = NULL;
    m_ConfigRoot = wxEmptyString;
#endif // wxUSE_CONFIG

    m_Cfg.x = m_Cfg.y = wxDefaultCoord;
    m_Cfg.w = 700;
    m_Cfg.h = 480;
    m_Cfg.sashpos = 240;
    m_Cfg.navig_on = true;

    m_NormalFonts = m_FixedFonts = NULL;
    m_NormalFace = m_FixedFace = wxEmptyString;
#ifdef __WXMSW__
    m_FontSize = 10;
#else
    m_FontSize = 14;
#endif

#if wxUSE_PRINTING_ARCHITECTURE
    m_Printer = NULL;
#endif

    m_PagesHash = NULL;
    m_UpdateContents = true;
    m_toolBar = NULL;
    m_helpController = NULL;
}

// Create: builds the GUI components.
// with the style flag it's possible to toggle the toolbar, contents, index and search
// controls.
// m_HtmlWin will *always* be created, but it's important to realize that
// m_ContentsBox, m_IndexList, m_SearchList, m_SearchButton, m_SearchText and
// m_SearchButton may be NULL.
// moreover, if no contents, index or searchpage is needed, m_Splitter and
// m_NavigPan will be NULL too (with m_HtmlWin directly connected to the frame)

bool wxHtmlHelpWindow::Create(wxWindow* parent, wxWindowID id,
                             const wxPoint& pos, const wxSize& size,
                             int style, int helpStyle)
{
    m_hfStyle = helpStyle;

#if wxUSE_CONFIG
    // Do the config in two steps. We read the HtmlWindow customization after we
    // create the window.
    if (m_Config)
        ReadCustomization(m_Config, m_ConfigRoot);
#endif // wxUSE_CONFIG

    wxWindow::Create(parent, id, pos, size, style, wxT("wxHtmlHelp"));

    SetHelpText(_("Displays help as you browse the books on the left."));

    GetPosition(&m_Cfg.x, &m_Cfg.y);

    int notebook_page = 0;

    // The sizer for the whole top-level window.
    wxSizer *topWindowSizer = new wxBoxSizer(wxVERTICAL);
    SetSizer(topWindowSizer);
    SetAutoLayout(true);

#if wxUSE_TOOLBAR
    // toolbar?
    if (helpStyle & (wxHF_TOOLBAR | wxHF_FLAT_TOOLBAR))
    {
        wxToolBar *toolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                                           wxNO_BORDER | wxTB_HORIZONTAL |
                                           wxTB_DOCKABLE | wxTB_NODIVIDER |
                                           (helpStyle & wxHF_FLAT_TOOLBAR ? wxTB_FLAT : 0));
        toolBar->SetMargins( 2, 2 );
        toolBar->SetToolBitmapSize( wxSize(22,22) );
        AddToolbarButtons(toolBar, helpStyle);
        toolBar->Realize();
        topWindowSizer->Add(toolBar, 0, wxEXPAND);
        m_toolBar = toolBar;
    }
#endif //wxUSE_TOOLBAR

    wxSizer *navigSizer = NULL;

#ifdef __WXMSW__
    wxBorder htmlWindowBorder = GetDefaultBorder();
    if (htmlWindowBorder == wxBORDER_SUNKEN)
        htmlWindowBorder = wxBORDER_SIMPLE;
#else
    wxBorder htmlWindowBorder = wxBORDER_SIMPLE;
#endif

    if (helpStyle & (wxHF_CONTENTS | wxHF_INDEX | wxHF_SEARCH))
    {
        // traditional help controller; splitter window with html page on the
        // right and a notebook containing various pages on the left
        long splitterStyle = wxSP_3D;
        // Drawing moving sash can cause problems on wxMac
#ifdef __WXMAC__
        splitterStyle |= wxSP_LIVE_UPDATE;
#endif
        m_Splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, splitterStyle);

        topWindowSizer->Add(m_Splitter, 1, wxEXPAND);

        m_HtmlWin = new wxHtmlHelpHtmlWindow(this, m_Splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_DEFAULT_STYLE|htmlWindowBorder);
        m_NavigPan = new wxPanel(m_Splitter, wxID_ANY);
        m_NavigNotebook = new wxNotebook(m_NavigPan, wxID_HTML_NOTEBOOK,
                                         wxDefaultPosition, wxDefaultSize);
#ifdef __WXMAC__
        m_NavigNotebook->SetWindowVariant(wxWINDOW_VARIANT_SMALL);
#endif

        navigSizer = new wxBoxSizer(wxVERTICAL);
        navigSizer->Add(m_NavigNotebook, 1, wxEXPAND);

        m_NavigPan->SetSizer(navigSizer);
    }
    else
    {
        // only html window, no notebook with index,contents etc
        m_HtmlWin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_DEFAULT_STYLE|htmlWindowBorder);
        topWindowSizer->Add(m_HtmlWin, 1, wxEXPAND);
    }

#if wxUSE_CONFIG
    if ( m_Config )
        m_HtmlWin->ReadCustomization(m_Config, m_ConfigRoot);
#endif // wxUSE_CONFIG

    // contents tree panel?
    if ( helpStyle & wxHF_CONTENTS )
    {
        wxWindow *dummy = new wxPanel(m_NavigNotebook, wxID_HTML_INDEXPAGE);
#ifdef __WXMAC__
        dummy->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
#endif
        wxSizer *topsizer = new wxBoxSizer(wxVERTICAL);

        topsizer->Add(0, 10);

        dummy->SetSizer(topsizer);

        if ( helpStyle & wxHF_BOOKMARKS )
        {
            m_Bookmarks = new wxComboBox(dummy, wxID_HTML_BOOKMARKSLIST,
                                         wxEmptyString,
                                         wxDefaultPosition, wxDefaultSize,
                                         0, NULL, wxCB_READONLY | wxCB_SORT);
            m_Bookmarks->Append(_("(bookmarks)"));
            for (unsigned i = 0; i < m_BookmarksNames.GetCount(); i++)
                m_Bookmarks->Append(m_BookmarksNames[i]);
            m_Bookmarks->SetSelection(0);

            wxBitmapButton *bmpbt1, *bmpbt2;
            bmpbt1 = new wxBitmapButton(dummy, wxID_HTML_BOOKMARKSADD,
                                 wxArtProvider::GetBitmap(wxART_ADD_BOOKMARK,
                                                          wxART_BUTTON));
            bmpbt2 = new wxBitmapButton(dummy, wxID_HTML_BOOKMARKSREMOVE,
                                 wxArtProvider::GetBitmap(wxART_DEL_BOOKMARK,
                                                          wxART_BUTTON));
#if wxUSE_TOOLTIPS
            bmpbt1->SetToolTip(_("Add current page to bookmarks"));
            bmpbt2->SetToolTip(_("Remove current page from bookmarks"));
#endif // wxUSE_TOOLTIPS

            wxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);

            sizer->Add(m_Bookmarks, 1, wxALIGN_CENTRE_VERTICAL | wxRIGHT, 5);
            sizer->Add(bmpbt1, 0, wxALIGN_CENTRE_VERTICAL | wxRIGHT, 2);
            sizer->Add(bmpbt2, 0, wxALIGN_CENTRE_VERTICAL, 0);

            topsizer->Add(sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 10);
        }

        m_ContentsBox = new wxTreeCtrl(dummy, wxID_HTML_TREECTRL,
                                       wxDefaultPosition, wxDefaultSize,
#if defined(__WXGTK20__) || defined(__WXMAC__)
                                       wxSUNKEN_BORDER |
                                       wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT |
                                       wxTR_NO_LINES
#else
                                       wxSUNKEN_BORDER |
                                       wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT |
                                       wxTR_LINES_AT_ROOT
#endif
                                       );

        wxImageList *ContentsImageList = new wxImageList(16, 16);
        ContentsImageList->Add(wxArtProvider::GetIcon(wxART_HELP_BOOK,
                                                      wxART_HELP_BROWSER,
                                                      wxSize(16, 16)));
        ContentsImageList->Add(wxArtProvider::GetIcon(wxART_HELP_FOLDER,
                                                      wxART_HELP_BROWSER,
                                                      wxSize(16, 16)));
        ContentsImageList->Add(wxArtProvider::GetIcon(wxART_HELP_PAGE,
                                                      wxART_HELP_BROWSER,
                                                      wxSize(16, 16)));

        m_ContentsBox->AssignImageList(ContentsImageList);

        topsizer->Add(m_ContentsBox, 1,
                      wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT,
                      2);

        m_NavigNotebook->AddPage(dummy, _("Contents"));
        m_ContentsPage = notebook_page++;
    }

    // index listbox panel?
    if ( helpStyle & wxHF_INDEX )
    {
        wxWindow *dummy = new wxPanel(m_NavigNotebook, wxID_HTML_INDEXPAGE);
#ifdef __WXMAC__
        dummy->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
#endif
        wxSizer *topsizer = new wxBoxSizer(wxVERTICAL);

        dummy->SetSizer(topsizer);

        m_IndexText = new wxTextCtrl(dummy, wxID_HTML_INDEXTEXT, wxEmptyString,
                                     wxDefaultPosition, wxDefaultSize,
                                     wxTE_PROCESS_ENTER);
        m_IndexButton = new wxButton(dummy, wxID_HTML_INDEXBUTTON, _("Find"));
        m_IndexButtonAll = new wxButton(dummy, wxID_HTML_INDEXBUTTONALL,
                                        _("Show all"));
        m_IndexCountInfo = new wxStaticText(dummy, wxID_HTML_COUNTINFO,
                                            wxEmptyString, wxDefaultPosition,
                                            wxDefaultSize,
                                            wxALIGN_RIGHT | wxST_NO_AUTORESIZE);
        m_IndexList = new wxListBox(dummy, wxID_HTML_INDEXLIST,
                                    wxDefaultPosition, wxDefaultSize,
                                    0, NULL, wxLB_SINGLE);

#if wxUSE_TOOLTIPS
        m_IndexButton->SetToolTip(_("Display all index items that contain given substring. Search is case insensitive."));
        m_IndexButtonAll->SetToolTip(_("Show all items in index"));
#endif //wxUSE_TOOLTIPS

        topsizer->Add(m_IndexText, 0, wxEXPAND | wxALL, 10);
        wxSizer *btsizer = new wxBoxSizer(wxHORIZONTAL);
        btsizer->Add(m_IndexButton, 0, wxRIGHT, 2);
        btsizer->Add(m_IndexButtonAll);
        topsizer->Add(btsizer, 0,
                      wxALIGN_RIGHT | wxLEFT | wxRIGHT | wxBOTTOM, 10);
        topsizer->Add(m_IndexCountInfo, 0, wxEXPAND | wxLEFT | wxRIGHT, 2);
        topsizer->Add(m_IndexList, 1, wxEXPAND | wxALL, 2);

        m_NavigNotebook->AddPage(dummy, _("Index"));
        m_IndexPage = notebook_page++;
    }

    // search list panel?
    if ( helpStyle & wxHF_SEARCH )
    {
        wxWindow *dummy = new wxPanel(m_NavigNotebook, wxID_HTML_INDEXPAGE);
#ifdef __WXMAC__
        dummy->SetWindowVariant(wxWINDOW_VARIANT_NORMAL);
#endif
        wxSizer *sizer = new wxBoxSizer(wxVERTICAL);

        dummy->SetSizer(sizer);

        m_SearchText = new wxTextCtrl(dummy, wxID_HTML_SEARCHTEXT,
                                      wxEmptyString,
                                      wxDefaultPosition, wxDefaultSize,
                                      wxTE_PROCESS_ENTER);
        m_SearchChoice = new wxChoice(dummy, wxID_HTML_SEARCHCHOICE,
                                      wxDefaultPosition, wxSize(125,wxDefaultCoord));
        m_SearchCaseSensitive = new wxCheckBox(dummy, wxID_ANY, _("Case sensitive"));
        m_SearchWholeWords = new wxCheckBox(dummy, wxID_ANY, _("Whole words only"));
        m_SearchButton = new wxButton(dummy, wxID_HTML_SEARCHBUTTON, _("Search"));
#if wxUSE_TOOLTIPS
        m_SearchButton->SetToolTip(_("Search contents of help book(s) for all occurrences of the text you typed above"));
#endif //wxUSE_TOOLTIPS
        m_SearchList = new wxListBox(dummy, wxID_HTML_SEARCHLIST,
                                     wxDefaultPosition, wxDefaultSize,
                                     0, NULL, wxLB_SINGLE);

        sizer->Add(m_SearchText, 0, wxEXPAND | wxALL, 10);
        sizer->Add(m_SearchChoice, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10);
        sizer->Add(m_SearchCaseSensitive, 0, wxLEFT | wxRIGHT, 10);
        sizer->Add(m_SearchWholeWords, 0, wxLEFT | wxRIGHT, 10);
        sizer->Add(m_SearchButton, 0, wxALL | wxALIGN_RIGHT, 8);
        sizer->Add(m_SearchList, 1, wxALL | wxEXPAND, 2);

        m_NavigNotebook->AddPage(dummy, _("Search"));
        m_SearchPage = notebook_page;
    }

    m_HtmlWin->Show();

    RefreshLists();

    if ( navigSizer )
    {
        navigSizer->SetSizeHints(m_NavigPan);
        m_NavigPan->Layout();
    }

    // showtime
    if ( m_NavigPan && m_Splitter )
    {
        // The panel will have its own min size which the splitter
        // should respect
        //if (m_NavigPan)
        //    m_Splitter->SetMinimumPaneSize(m_NavigPan->GetBestSize().x);
        //else
        m_Splitter->SetMinimumPaneSize(20);

        if ( m_Cfg.navig_on )
        {
            m_NavigPan->Show();
            m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
        }
        else
        {
            m_NavigPan->Show(false);
            m_Splitter->Initialize(m_HtmlWin);
        }
    }

    // Reduce flicker by updating the splitter pane sizes before the
    // frame is shown
    wxSizeEvent sizeEvent(GetSize(), GetId());
    GetEventHandler()->ProcessEvent(sizeEvent);

    if (m_Splitter)
        m_Splitter->UpdateSize();

    return true;
}

wxHtmlHelpWindow::~wxHtmlHelpWindow()
{
    if ( m_helpController )
        m_helpController->SetHelpWindow(NULL);

    delete m_mergedIndex;

    // PopEventHandler(); // wxhtmlhelpcontroller (not any more!)
    if (m_DataCreated)
        delete m_Data;
    if (m_NormalFonts) delete m_NormalFonts;
    if (m_FixedFonts) delete m_FixedFonts;
    if (m_PagesHash)
    {
        WX_CLEAR_HASH_TABLE(*m_PagesHash);
        delete m_PagesHash;
    }
#if wxUSE_PRINTING_ARCHITECTURE
    if (m_Printer) delete m_Printer;
#endif
}

void wxHtmlHelpWindow::SetController(wxHtmlHelpController* controller)
{
    if (m_DataCreated)
        delete m_Data;
    m_helpController = controller;
    m_Data = controller->GetHelpData();
    m_DataCreated = false;
}

#if wxUSE_TOOLBAR
void wxHtmlHelpWindow::AddToolbarButtons(wxToolBar *toolBar, int style)
{
    wxBitmap wpanelBitmap =
        wxArtProvider::GetBitmap(wxART_HELP_SIDE_PANEL, wxART_TOOLBAR);
    wxBitmap wbackBitmap =
        wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR);
    wxBitmap wforwardBitmap =
        wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_TOOLBAR);
    wxBitmap wupnodeBitmap =
        wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_TOOLBAR);
    wxBitmap wupBitmap =
        wxArtProvider::GetBitmap(wxART_GO_UP, wxART_TOOLBAR);
    wxBitmap wdownBitmap =
        wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_TOOLBAR);
    wxBitmap wopenBitmap =
        wxArtProvider::GetBitmap(wxART_FILE_OPEN, wxART_TOOLBAR);
    wxBitmap wprintBitmap =
        wxArtProvider::GetBitmap(wxART_PRINT, wxART_TOOLBAR);
    wxBitmap woptionsBitmap =
        wxArtProvider::GetBitmap(wxART_HELP_SETTINGS, wxART_TOOLBAR);

    wxASSERT_MSG( (wpanelBitmap.Ok() && wbackBitmap.Ok() &&
                   wforwardBitmap.Ok() && wupnodeBitmap.Ok() &&
                   wupBitmap.Ok() && wdownBitmap.Ok() &&
                   wopenBitmap.Ok() && wprintBitmap.Ok() &&
                   woptionsBitmap.Ok()),
                  wxT("One or more HTML help frame toolbar bitmap could not be loaded.")) ;

    toolBar->AddTool(wxID_HTML_PANEL, wxEmptyString, wpanelBitmap, _("Show/hide navigation panel"));
    toolBar->AddSeparator();
    toolBar->AddTool(wxID_HTML_BACK, wxEmptyString, wbackBitmap, _("Go back"));
    toolBar->AddTool(wxID_HTML_FORWARD, wxEmptyString, wforwardBitmap, _("Go forward"));
    toolBar->AddSeparator();
    toolBar->AddTool(wxID_HTML_UPNODE, wxEmptyString, wupnodeBitmap, _("Go one level up in document hierarchy"));
    toolBar->AddTool(wxID_HTML_UP, wxEmptyString, wupBitmap, _("Previous page"));
    toolBar->AddTool(wxID_HTML_DOWN, wxEmptyString, wdownBitmap, _("Next page"));

    if ((style & wxHF_PRINT) || (style & wxHF_OPEN_FILES))
        toolBar->AddSeparator();

    if (style & wxHF_OPEN_FILES)
        toolBar->AddTool(wxID_HTML_OPENFILE, wxEmptyString, wopenBitmap, _("Open HTML document"));

#if wxUSE_PRINTING_ARCHITECTURE
    if (style & wxHF_PRINT)
        toolBar->AddTool(wxID_HTML_PRINT, wxEmptyString, wprintBitmap, _("Print this page"));
#endif

    toolBar->AddSeparator();
    toolBar->AddTool(wxID_HTML_OPTIONS, wxEmptyString, woptionsBitmap, _("Display options dialog"));

    // Allow application to add custom buttons
    wxHtmlHelpFrame* parentFrame = wxDynamicCast(GetParent(), wxHtmlHelpFrame);
    wxHtmlHelpDialog* parentDialog = wxDynamicCast(GetParent(), wxHtmlHelpDialog);
    if (parentFrame)
        parentFrame->AddToolbarButtons(toolBar, style);
    if (parentDialog)
        parentDialog->AddToolbarButtons(toolBar, style);
}
#endif //wxUSE_TOOLBAR

bool wxHtmlHelpWindow::Display(const wxString& x)
{
    wxString url = m_Data->FindPageByName(x);
    if (!url.empty())
    {
        m_HtmlWin->LoadPage(url);
        NotifyPageChanged();
        return true;
    }

    return false;
}

bool wxHtmlHelpWindow::Display(const int id)
{
    wxString url = m_Data->FindPageById(id);
    if (!url.empty())
    {
        m_HtmlWin->LoadPage(url);
        NotifyPageChanged();
        return true;
    }

    return false;
}

bool wxHtmlHelpWindow::DisplayContents()
{
    if (! m_ContentsBox)
        return false;

    if (!m_Splitter->IsSplit())
    {
        m_NavigPan->Show();
        m_HtmlWin->Show();
        m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
        m_Cfg.navig_on = true;
    }

    m_NavigNotebook->SetSelection(m_ContentsPage);

    if (m_Data->GetBookRecArray().GetCount() > 0)
    {
        wxHtmlBookRecord& book = m_Data->GetBookRecArray()[0];
        if (!book.GetStart().empty())
            m_HtmlWin->LoadPage(book.GetFullPath(book.GetStart()));
    }

    return true;
}

bool wxHtmlHelpWindow::DisplayIndex()
{
    if (! m_IndexList)
        return false;

    if (!m_Splitter->IsSplit())
    {
        m_NavigPan->Show();
        m_HtmlWin->Show();
        m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
    }

    m_NavigNotebook->SetSelection(m_IndexPage);

    if (m_Data->GetBookRecArray().GetCount() > 0)
    {
        wxHtmlBookRecord& book = m_Data->GetBookRecArray()[0];
        if (!book.GetStart().empty())
            m_HtmlWin->LoadPage(book.GetFullPath(book.GetStart()));
    }

    return true;
}

void wxHtmlHelpWindow::DisplayIndexItem(const wxHtmlHelpMergedIndexItem *it)
{
    if (it->items.size() == 1)
    {
        if (!it->items[0]->page.empty())
        {
            m_HtmlWin->LoadPage(it->items[0]->GetFullPath());
            NotifyPageChanged();
        }
    }
    else
    {
        wxBusyCursor busy_cursor;

        // more pages associated with this index item -- let the user choose
        // which one she/he wants from a list:
        wxArrayString arr;
        size_t len = it->items.size();
        for (size_t i = 0; i < len; i++)
        {
            wxString page = it->items[i]->page;
            // try to find page's title in contents:
            const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
            size_t clen = contents.size();
            for (size_t j = 0; j < clen; j++)
            {
                if (contents[j].page == page)
                {
                    page = contents[j].name;
                    break;
                }
            }
            arr.push_back(page);
        }

        wxSingleChoiceDialog dlg(this,
                                 _("Please choose the page to display:"),
                                 _("Help Topics"),
                                 arr, NULL, wxCHOICEDLG_STYLE & ~wxCENTRE);
        if (dlg.ShowModal() == wxID_OK)
        {
            m_HtmlWin->LoadPage(it->items[dlg.GetSelection()]->GetFullPath());
            NotifyPageChanged();
        }
    }
}

bool wxHtmlHelpWindow::KeywordSearch(const wxString& keyword,
                                    wxHelpSearchMode mode)
{
    wxCHECK_MSG( !keyword.empty(), false, "must have a non empty keyword" );

    if (mode == wxHELP_SEARCH_ALL)
    {
        if ( !(m_SearchList &&
               m_SearchButton && m_SearchText && m_SearchChoice) )
            return false;
    }
    else if (mode == wxHELP_SEARCH_INDEX)
    {
        if ( !(m_IndexList &&
               m_IndexButton && m_IndexButtonAll && m_IndexText) )
            return false;
    }

    int foundcnt = 0;
    wxString foundstr;
    wxString book = wxEmptyString;

    if (!m_Splitter->IsSplit())
    {
        m_NavigPan->Show();
        m_HtmlWin->Show();
        m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
    }

    if (mode == wxHELP_SEARCH_ALL)
    {
        m_NavigNotebook->SetSelection(m_SearchPage);
        m_SearchList->Clear();
        m_SearchText->SetValue(keyword);
        m_SearchButton->Disable();

        if (m_SearchChoice->GetSelection() != 0)
            book = m_SearchChoice->GetStringSelection();

        wxHtmlSearchStatus status(m_Data, keyword,
                                  m_SearchCaseSensitive->GetValue(),
                                  m_SearchWholeWords->GetValue(),
                                  book);

#if wxUSE_PROGRESSDLG
        wxProgressDialog progress(_("Searching..."),
                                  _("No matching page found yet"),
                                  status.GetMaxIndex(), this,
                                  wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
#endif

        int curi;
        while (status.IsActive())
        {
            curi = status.GetCurIndex();
            if (curi % 32 == 0
#if wxUSE_PROGRESSDLG
                && !progress.Update(curi)
#endif
               )
                break;
            if (status.Search())
            {
                foundstr.Printf(_("Found %i matches"), ++foundcnt);
#if wxUSE_PROGRESSDLG
                progress.Update(status.GetCurIndex(), foundstr);
#endif
                m_SearchList->Append(status.GetName(), (void*)status.GetCurItem());
            }
        }

        m_SearchButton->Enable();
        m_SearchText->SetSelection(0, keyword.length());
        m_SearchText->SetFocus();
    }
    else if (mode == wxHELP_SEARCH_INDEX)
    {
        m_NavigNotebook->SetSelection(m_IndexPage);
        m_IndexList->Clear();
        m_IndexButton->Disable();
        m_IndexButtonAll->Disable();
        m_IndexText->SetValue(keyword);

        DoIndexFind();
        m_IndexButton->Enable();
        m_IndexButtonAll->Enable();
        foundcnt = m_IndexList->GetCount();
    }

    if (foundcnt)
    {
        switch ( mode )
        {
            default:
                wxFAIL_MSG( wxT("unknown help search mode") );
                // fall back

            case wxHELP_SEARCH_ALL:
            {
                wxHtmlHelpDataItem *it =
                    (wxHtmlHelpDataItem*) m_SearchList->GetClientData(0);
                if (it)
                {
                    m_HtmlWin->LoadPage(it->GetFullPath());
                    NotifyPageChanged();
                }
                break;
            }

            case wxHELP_SEARCH_INDEX:
            {
                wxHtmlHelpMergedIndexItem* it =
                    (wxHtmlHelpMergedIndexItem*) m_IndexList->GetClientData(0);
                if (it)
                    DisplayIndexItem(it);
                break;
            }
        }

    }

    return foundcnt > 0;
}

void wxHtmlHelpWindow::CreateContents()
{
    if (! m_ContentsBox)
        return ;

    if (m_PagesHash)
    {
        WX_CLEAR_HASH_TABLE(*m_PagesHash);
        delete m_PagesHash;
    }

    const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();

    size_t cnt = contents.size();

    m_PagesHash = new wxHashTable(wxKEY_STRING, 2 * cnt);

    const int MAX_ROOTS = 64;
    wxTreeItemId roots[MAX_ROOTS];
    // VS: this array holds information about whether we've set item icon at
    //     given level. This is necessary because m_Data has a flat structure
    //     and there's no way of recognizing if some item has subitems or not.
    //     We set the icon later: when we find an item with level=n, we know
    //     that the last item with level=n-1 was afolder with subitems, so we
    //     set its icon accordingly
    bool imaged[MAX_ROOTS];
    m_ContentsBox->DeleteAllItems();

    roots[0] = m_ContentsBox->AddRoot(_("(Help)"));
    imaged[0] = true;

    for (size_t i = 0; i < cnt; i++)
    {
        wxHtmlHelpDataItem *it = &contents[i];
        // Handle books:
        if (it->level == 0)
        {
            if (m_hfStyle & wxHF_MERGE_BOOKS)
                // VS: we don't want book nodes, books' content should
                //    appear under tree's root. This line will create a "fake"
                //    record about book node so that the rest of this look
                //    will believe there really _is_ a book node and will
                //    behave correctly.
                roots[1] = roots[0];
            else
            {
                roots[1] = m_ContentsBox->AppendItem(roots[0],
                                         it->name, IMG_Book, -1,
                                         new wxHtmlHelpTreeItemData(i));
                m_ContentsBox->SetItemBold(roots[1], true);
            }
            imaged[1] = true;
        }
        // ...and their contents:
        else
        {
            roots[it->level + 1] = m_ContentsBox->AppendItem(
                                     roots[it->level], it->name, IMG_Page,
                                     -1, new wxHtmlHelpTreeItemData(i));
            imaged[it->level + 1] = false;
        }

        m_PagesHash->Put(it->GetFullPath(),
                         new wxHtmlHelpHashData(i, roots[it->level + 1]));

        // Set the icon for the node one level up in the hierarchy,
        // unless already done (see comment above imaged[] declaration)
        if (!imaged[it->level])
        {
            int image = IMG_Folder;
            if (m_hfStyle & wxHF_ICONS_BOOK)
                image = IMG_Book;
            else if (m_hfStyle & wxHF_ICONS_BOOK_CHAPTER)
                image = (it->level == 1) ? IMG_Book : IMG_Folder;
            m_ContentsBox->SetItemImage(roots[it->level], image);
            m_ContentsBox->SetItemImage(roots[it->level], image,
                                        wxTreeItemIcon_Selected);
            imaged[it->level] = true;
        }
    }
}

void wxHtmlHelpWindow::CreateIndex()
{
    if (! m_IndexList)
        return ;

    m_IndexList->Clear();

    size_t cnt = m_mergedIndex->size();

    wxString cnttext;
    if (cnt > INDEX_IS_SMALL)
        cnttext.Printf(_("%i of %i"), 0, cnt);
    else
        cnttext.Printf(_("%i of %i"), cnt, cnt);
    m_IndexCountInfo->SetLabel(cnttext);
    if (cnt > INDEX_IS_SMALL)
        return;

    for (size_t i = 0; i < cnt; i++)
        m_IndexList->Append((*m_mergedIndex)[i].name,
                            (char*)(&(*m_mergedIndex)[i]));
}

void wxHtmlHelpWindow::CreateSearch()
{
    if (! (m_SearchList && m_SearchChoice))
        return ;
    m_SearchList->Clear();
    m_SearchChoice->Clear();
    m_SearchChoice->Append(_("Search in all books"));
    const wxHtmlBookRecArray& bookrec = m_Data->GetBookRecArray();
    int i, cnt = bookrec.GetCount();
    for (i = 0; i < cnt; i++)
        m_SearchChoice->Append(bookrec[i].GetTitle());
    m_SearchChoice->SetSelection(0);
}

void wxHtmlHelpWindow::RefreshLists()
{
    // Update m_mergedIndex:
    UpdateMergedIndex();
    // Update the controls
    CreateContents();
    CreateIndex();
    CreateSearch();
}

#if wxUSE_CONFIG
void wxHtmlHelpWindow::ReadCustomization(wxConfigBase *cfg, const wxString& path)
{
    wxString oldpath;
    wxString tmp;

    if (path != wxEmptyString)
    {
        oldpath = cfg->GetPath();
        cfg->SetPath(wxT("/") + path);
    }

    m_Cfg.navig_on = cfg->Read(wxT("hcNavigPanel"), m_Cfg.navig_on) != 0;
    m_Cfg.sashpos = cfg->Read(wxT("hcSashPos"), m_Cfg.sashpos);
    m_Cfg.x = cfg->Read(wxT("hcX"), m_Cfg.x);
    m_Cfg.y = cfg->Read(wxT("hcY"), m_Cfg.y);
    m_Cfg.w = cfg->Read(wxT("hcW"), m_Cfg.w);
    m_Cfg.h = cfg->Read(wxT("hcH"), m_Cfg.h);

    m_FixedFace = cfg->Read(wxT("hcFixedFace"), m_FixedFace);
    m_NormalFace = cfg->Read(wxT("hcNormalFace"), m_NormalFace);
    m_FontSize = cfg->Read(wxT("hcBaseFontSize"), m_FontSize);

    {
        int i;
        int cnt;
        wxString val, s;

        cnt = cfg->Read(wxT("hcBookmarksCnt"), 0L);
        if (cnt != 0)
        {
            m_BookmarksNames.Clear();
            m_BookmarksPages.Clear();
            if (m_Bookmarks)
            {
                m_Bookmarks->Clear();
                m_Bookmarks->Append(_("(bookmarks)"));
            }

            for (i = 0; i < cnt; i++)
            {
                val.Printf(wxT("hcBookmark_%i"), i);
                s = cfg->Read(val);
                m_BookmarksNames.Add(s);
                if (m_Bookmarks) m_Bookmarks->Append(s);
                val.Printf(wxT("hcBookmark_%i_url"), i);
                s = cfg->Read(val);
                m_BookmarksPages.Add(s);
            }
        }
    }

    if (m_HtmlWin)
        m_HtmlWin->ReadCustomization(cfg);

    if (path != wxEmptyString)
        cfg->SetPath(oldpath);
}

void wxHtmlHelpWindow::WriteCustomization(wxConfigBase *cfg, const wxString& path)
{
    wxString oldpath;
    wxString tmp;

    if (path != wxEmptyString)
    {
        oldpath = cfg->GetPath();
        cfg->SetPath(wxT("/") + path);
    }

    cfg->Write(wxT("hcNavigPanel"), m_Cfg.navig_on);
    cfg->Write(wxT("hcSashPos"), (long)m_Cfg.sashpos);

    //  Don't write if iconized as this would make the window
    //  disappear next time it is shown!
    cfg->Write(wxT("hcX"), (long)m_Cfg.x);
    cfg->Write(wxT("hcY"), (long)m_Cfg.y);
    cfg->Write(wxT("hcW"), (long)m_Cfg.w);
    cfg->Write(wxT("hcH"), (long)m_Cfg.h);

    cfg->Write(wxT("hcFixedFace"), m_FixedFace);
    cfg->Write(wxT("hcNormalFace"), m_NormalFace);
    cfg->Write(wxT("hcBaseFontSize"), (long)m_FontSize);

    if (m_Bookmarks)
    {
        int i;
        int cnt = m_BookmarksNames.GetCount();
        wxString val;

        cfg->Write(wxT("hcBookmarksCnt"), (long)cnt);
        for (i = 0; i < cnt; i++)
        {
            val.Printf(wxT("hcBookmark_%i"), i);
            cfg->Write(val, m_BookmarksNames[i]);
            val.Printf(wxT("hcBookmark_%i_url"), i);
            cfg->Write(val, m_BookmarksPages[i]);
        }
    }

    if (m_HtmlWin)
        m_HtmlWin->WriteCustomization(cfg);

    if (path != wxEmptyString)
        cfg->SetPath(oldpath);
}
#endif // wxUSE_CONFIG

static void SetFontsToHtmlWin(wxHtmlWindow *win, const wxString& scalf, const wxString& fixf, int size)
{
    int f_sizes[7];
    f_sizes[0] = int(size * 0.6);
    f_sizes[1] = int(size * 0.8);
    f_sizes[2] = size;
    f_sizes[3] = int(size * 1.2);
    f_sizes[4] = int(size * 1.4);
    f_sizes[5] = int(size * 1.6);
    f_sizes[6] = int(size * 1.8);

    win->SetFonts(scalf, fixf, f_sizes);
}

class wxHtmlHelpWindowOptionsDialog : public wxDialog
{
public:
    wxComboBox *NormalFont, *FixedFont;
    wxSpinCtrl *FontSize;
    wxHtmlWindow *TestWin;

    wxHtmlHelpWindowOptionsDialog(wxWindow *parent)
        : wxDialog(parent, wxID_ANY, wxString(_("Help Browser Options")))
    {
        wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
        wxFlexGridSizer *sizer = new wxFlexGridSizer(2, 3, 2, 5);

        sizer->Add(new wxStaticText(this, wxID_ANY, _("Normal font:")));
        sizer->Add(new wxStaticText(this, wxID_ANY, _("Fixed font:")));
        sizer->Add(new wxStaticText(this, wxID_ANY, _("Font size:")));

        sizer->Add(NormalFont = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                      wxSize(200, wxDefaultCoord),
                      0, NULL, wxCB_DROPDOWN | wxCB_READONLY));

        sizer->Add(FixedFont = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                      wxSize(200, wxDefaultCoord),
                      0, NULL, wxCB_DROPDOWN | wxCB_READONLY));

        sizer->Add(FontSize = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                      wxDefaultSize, wxSP_ARROW_KEYS, 2, 100, 2, wxT("wxSpinCtrl")));

        topsizer->Add(sizer, 0, wxLEFT|wxRIGHT|wxTOP, 10);

        topsizer->Add(new wxStaticText(this, wxID_ANY, _("Preview:")),
                        0, wxLEFT | wxTOP, 10);

        topsizer->AddSpacer(5);

        topsizer->Add(TestWin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxSize(20, 150),
                                                 wxHW_SCROLLBAR_AUTO|wxBORDER_THEME),
                        1, wxEXPAND | wxLEFT | wxRIGHT, 10);

        wxBoxSizer *sizer2 = new wxBoxSizer(wxHORIZONTAL);
        wxButton *ok;
        sizer2->Add(ok = new wxButton(this, wxID_OK), 0, wxALL, 10);
        ok->SetDefault();
        sizer2->Add(new wxButton(this, wxID_CANCEL), 0, wxALL, 10);
        topsizer->Add(sizer2, 0, wxALIGN_RIGHT);

        SetSizer(topsizer);
        topsizer->Fit(this);
        Centre(wxBOTH);
    }

    void UpdateTestWin()
    {
        wxBusyCursor bcur;
        SetFontsToHtmlWin(TestWin,
                          NormalFont->GetStringSelection(),
                          FixedFont->GetStringSelection(),
                          FontSize->GetValue());

        wxString content(_("font size"));

        content = wxT("<font size=-2>") + content + wxT(" -2</font><br>")
                  wxT("<font size=-1>") + content + wxT(" -1</font><br>")
                  wxT("<font size=+0>") + content + wxT(" +0</font><br>")
                  wxT("<font size=+1>") + content + wxT(" +1</font><br>")
                  wxT("<font size=+2>") + content + wxT(" +2</font><br>")
                  wxT("<font size=+3>") + content + wxT(" +3</font><br>")
                  wxT("<font size=+4>") + content + wxT(" +4</font><br>") ;

        content = wxString( wxT("<html><body><table><tr><td>") ) +
                  _("Normal face<br>and <u>underlined</u>. ") +
                  _("<i>Italic face.</i> ") +
                  _("<b>Bold face.</b> ") +
                  _("<b><i>Bold italic face.</i></b><br>") +
                  content +
                  wxString( wxT("</td><td><tt>") ) +
                  _("Fixed size face.<br> <b>bold</b> <i>italic</i> ") +
                  _("<b><i>bold italic <u>underlined</u></i></b><br>") +
                  content +
                  wxT("</tt></td></tr></table></body></html>");

        TestWin->SetPage( content );
    }

    void OnUpdate(wxCommandEvent& WXUNUSED(event))
    {
        UpdateTestWin();
    }
    void OnUpdateSpin(wxSpinEvent& WXUNUSED(event))
    {
        UpdateTestWin();
    }

    DECLARE_EVENT_TABLE()
    wxDECLARE_NO_COPY_CLASS(wxHtmlHelpWindowOptionsDialog);
};

BEGIN_EVENT_TABLE(wxHtmlHelpWindowOptionsDialog, wxDialog)
    EVT_COMBOBOX(wxID_ANY, wxHtmlHelpWindowOptionsDialog::OnUpdate)
    EVT_SPINCTRL(wxID_ANY, wxHtmlHelpWindowOptionsDialog::OnUpdateSpin)
END_EVENT_TABLE()

void wxHtmlHelpWindow::OptionsDialog()
{
    wxHtmlHelpWindowOptionsDialog dlg(this);
    unsigned i;

    if (m_NormalFonts == NULL)
    {
        m_NormalFonts = new wxArrayString(wxFontEnumerator::GetFacenames());
        m_NormalFonts->Sort(); // ascending sort
    }
    if (m_FixedFonts == NULL)
    {
        m_FixedFonts = new wxArrayString(
                    wxFontEnumerator::GetFacenames(wxFONTENCODING_SYSTEM,
                    true /*enum fixed width only*/));
        m_FixedFonts->Sort(); // ascending sort
    }

    // VS: We want to show the font that is actually used by wxHtmlWindow.
    //     If customization dialog wasn't used yet, facenames are empty and
    //     wxHtmlWindow uses default fonts -- let's find out what they
    //     are so that we can pass them to the dialog:
    if (m_NormalFace.empty())
    {
        wxFont fnt(m_FontSize, wxSWISS, wxNORMAL, wxNORMAL, false);
        m_NormalFace = fnt.GetFaceName();
    }
    if (m_FixedFace.empty())
    {
        wxFont fnt(m_FontSize, wxMODERN, wxNORMAL, wxNORMAL, false);
        m_FixedFace = fnt.GetFaceName();
    }

    for (i = 0; i < m_NormalFonts->GetCount(); i++)
        dlg.NormalFont->Append((*m_NormalFonts)[i]);
    for (i = 0; i < m_FixedFonts->GetCount(); i++)
        dlg.FixedFont->Append((*m_FixedFonts)[i]);
    if (!m_NormalFace.empty())
        dlg.NormalFont->SetStringSelection(m_NormalFace);
    else
        dlg.NormalFont->SetSelection(0);
    if (!m_FixedFace.empty())
        dlg.FixedFont->SetStringSelection(m_FixedFace);
    else
        dlg.FixedFont->SetSelection(0);
    dlg.FontSize->SetValue(m_FontSize);
    dlg.UpdateTestWin();

    if (dlg.ShowModal() == wxID_OK)
    {
        m_NormalFace = dlg.NormalFont->GetStringSelection();
        m_FixedFace = dlg.FixedFont->GetStringSelection();
        m_FontSize = dlg.FontSize->GetValue();
        SetFontsToHtmlWin(m_HtmlWin, m_NormalFace, m_FixedFace, m_FontSize);
    }
}

void wxHtmlHelpWindow::NotifyPageChanged()
{
    if (m_UpdateContents && m_PagesHash)
    {
        wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
        wxHtmlHelpHashData *ha = NULL;
        if (!page.empty())
            ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);

        if (ha)
        {
            bool olduc = m_UpdateContents;
            m_UpdateContents = false;
            m_ContentsBox->SelectItem(ha->m_Id);
            m_ContentsBox->EnsureVisible(ha->m_Id);
            m_UpdateContents = olduc;
        }
    }
}

/*
EVENT HANDLING :
*/

void wxHtmlHelpWindow::OnToolbar(wxCommandEvent& event)
{
    switch (event.GetId())
    {
        case wxID_HTML_BACK :
            m_HtmlWin->HistoryBack();
            NotifyPageChanged();
            break;

        case wxID_HTML_FORWARD :
            m_HtmlWin->HistoryForward();
            NotifyPageChanged();
            break;

        case wxID_HTML_UP :
            if (m_PagesHash)
            {
                wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
                wxHtmlHelpHashData *ha = NULL;
                if (!page.empty())
                    ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
                if (ha && ha->m_Index > 0)
                {
                    const wxHtmlHelpDataItem& it = m_Data->GetContentsArray()[ha->m_Index - 1];
                    if (!it.page.empty())
                    {
                        m_HtmlWin->LoadPage(it.GetFullPath());
                        NotifyPageChanged();
                    }
                }
            }
            break;

        case wxID_HTML_UPNODE :
            if (m_PagesHash)
            {
                wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
                wxHtmlHelpHashData *ha = NULL;
                if (!page.empty())
                    ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);
                if (ha && ha->m_Index > 0)
                {
                    int level =
                        m_Data->GetContentsArray()[ha->m_Index].level - 1;
                    int ind = ha->m_Index - 1;

                    const wxHtmlHelpDataItem *it =
                        &m_Data->GetContentsArray()[ind];
                    while (ind >= 0 && it->level != level)
                    {
                        ind--;
                        it = &m_Data->GetContentsArray()[ind];
                    }
                    if (ind >= 0)
                    {
                        if (!it->page.empty())
                        {
                            m_HtmlWin->LoadPage(it->GetFullPath());
                            NotifyPageChanged();
                        }
                    }
                }
            }
            break;

        case wxID_HTML_DOWN :
            if (m_PagesHash)
            {
                wxString page = wxHtmlHelpHtmlWindow::GetOpenedPageWithAnchor(m_HtmlWin);
                wxHtmlHelpHashData *ha = NULL;
                if (!page.empty())
                    ha = (wxHtmlHelpHashData*) m_PagesHash->Get(page);

                const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
                if (ha && ha->m_Index < (int)contents.size() - 1)
                {
                    size_t idx = ha->m_Index + 1;

                    while (contents[idx].GetFullPath() == page) idx++;

                    if (!contents[idx].page.empty())
                    {
                        m_HtmlWin->LoadPage(contents[idx].GetFullPath());
                        NotifyPageChanged();
                    }
                }
            }
            break;

        case wxID_HTML_PANEL :
            {
                if (! (m_Splitter && m_NavigPan))
                    return ;
                if (m_Splitter->IsSplit())
                {
                    m_Cfg.sashpos = m_Splitter->GetSashPosition();
                    m_Splitter->Unsplit(m_NavigPan);
                    m_Cfg.navig_on = false;
                }
                else
                {
                    m_NavigPan->Show();
                    m_HtmlWin->Show();
                    m_Splitter->SplitVertically(m_NavigPan, m_HtmlWin, m_Cfg.sashpos);
                    m_Cfg.navig_on = true;
                }
            }
            break;

        case wxID_HTML_OPTIONS :
            OptionsDialog();
            break;

        case wxID_HTML_BOOKMARKSADD :
            {
                wxString item;
                wxString url;

                item = m_HtmlWin->GetOpenedPageTitle();
                url = m_HtmlWin->GetOpenedPage();
                if (item == wxEmptyString)
                    item = url.AfterLast(wxT('/'));
                if (m_BookmarksPages.Index(url) == wxNOT_FOUND)
                {
                    m_Bookmarks->Append(item);
                    m_BookmarksNames.Add(item);
                    m_BookmarksPages.Add(url);
                }
            }
            break;

        case wxID_HTML_BOOKMARKSREMOVE :
            {
                wxString item;
                int pos;

                item = m_Bookmarks->GetStringSelection();
                pos = m_BookmarksNames.Index(item);
                if (pos != wxNOT_FOUND)
                {
                    m_BookmarksNames.RemoveAt(pos);
                    m_BookmarksPages.RemoveAt(pos);
                    pos = m_Bookmarks->GetSelection();
                    wxASSERT_MSG( pos != wxNOT_FOUND , wxT("Unknown bookmark position") ) ;
                    m_Bookmarks->Delete((unsigned int)pos);
                }
            }
            break;

#if wxUSE_PRINTING_ARCHITECTURE
        case wxID_HTML_PRINT :
            {
                if (m_Printer == NULL)
                    m_Printer = new wxHtmlEasyPrinting(_("Help Printing"), this);
                if (!m_HtmlWin->GetOpenedPage())
                {
                    wxLogWarning(_("Cannot print empty page."));
                }
                else
                {
                    m_Printer->PrintFile(m_HtmlWin->GetOpenedPage());
                }
            }
            break;
#endif

        case wxID_HTML_OPENFILE :
            {
                wxString filemask = wxString(
                    _("HTML files (*.html;*.htm)|*.html;*.htm|")) +
                    _("Help books (*.htb)|*.htb|Help books (*.zip)|*.zip|") +
                    _("HTML Help Project (*.hhp)|*.hhp|") +
#if wxUSE_LIBMSPACK
                    _("Compressed HTML Help file (*.chm)|*.chm|") +
#endif
                    _("All files (*.*)|*");
                wxString s = wxFileSelector(_("Open HTML document"),
                                            wxEmptyString,
                                            wxEmptyString,
                                            wxEmptyString,
                                            filemask,
                                            wxFD_OPEN | wxFD_FILE_MUST_EXIST,
                                            this);
                if (!s.empty())
                {
                    wxString ext = s.Right(4).Lower();
                    if (ext == wxT(".zip") || ext == wxT(".htb") ||
#if wxUSE_LIBMSPACK
                        ext == wxT(".chm") ||
#endif
                        ext == wxT(".hhp"))
                    {
                        wxBusyCursor bcur;
                        m_Data->AddBook(s);
                        RefreshLists();
                    }
                    else
                        m_HtmlWin->LoadPage(s);
                }
            }
            break;
    }
}

void wxHtmlHelpWindow::OnContentsSel(wxTreeEvent& event)
{
    wxHtmlHelpTreeItemData *pg;

    pg = (wxHtmlHelpTreeItemData*) m_ContentsBox->GetItemData(event.GetItem());

    if (pg && m_UpdateContents)
    {
        const wxHtmlHelpDataItems& contents = m_Data->GetContentsArray();
        m_UpdateContents = false;
        if (!contents[pg->m_Id].page.empty())
            m_HtmlWin->LoadPage(contents[pg->m_Id].GetFullPath());
        m_UpdateContents = true;
    }
}

void wxHtmlHelpWindow::OnIndexSel(wxCommandEvent& WXUNUSED(event))
{
    wxHtmlHelpMergedIndexItem *it = (wxHtmlHelpMergedIndexItem*)
        m_IndexList->GetClientData(m_IndexList->GetSelection());
    if (it)
        DisplayIndexItem(it);
}

void wxHtmlHelpWindow::OnIndexFind(wxCommandEvent& WXUNUSED(event))
{
    DoIndexFind();
}

void wxHtmlHelpWindow::DoIndexFind()
{
    wxString sr = m_IndexText->GetLineText(0);
    sr.MakeLower();
    if (sr == wxEmptyString)
    {
        DoIndexAll();
    }
    else
    {
        wxBusyCursor bcur;

        m_IndexList->Clear();
        const wxHtmlHelpMergedIndex& index = *m_mergedIndex;
        size_t cnt = index.size();

        int displ = 0;
        for (size_t i = 0; i < cnt; i++)
        {
            if (index[i].name.Lower().find(sr) != wxString::npos)
            {
                int pos = m_IndexList->Append(index[i].name,
                                              (char*)(&index[i]));

                if (displ++ == 0)
                {
                    // don't automatically show topic selector if this
                    // item points to multiple pages:
                    if (index[i].items.size() == 1)
                    {
                        m_IndexList->SetSelection(0);
                        DisplayIndexItem(&index[i]);
                    }
                }

                // if this is nested item of the index, show its parent(s)
                // as well, otherwise it would not be clear what entry is
                // shown:
                wxHtmlHelpMergedIndexItem *parent = index[i].parent;
                while (parent)
                {
                    if (pos == 0 ||
                        (index.Index(*(wxHtmlHelpMergedIndexItem*)m_IndexList->GetClientData(pos-1))) < index.Index(*parent))
                    {
                        m_IndexList->Insert(parent->name,
                                            pos, (char*)parent);
                        parent = parent->parent;
                    }
                    else break;
                }

                // finally, it the item we just added is itself a parent for
                // other items, show them as well, because they are refinements
                // of the displayed index entry (i.e. it is implicitly contained
                // in them: "foo" with parent "bar" reads as "bar, foo"):
                int level = index[i].items[0]->level;
                i++;
                while (i < cnt && index[i].items[0]->level > level)
                {
                    m_IndexList->Append(index[i].name, (char*)(&index[i]));
                    i++;
                }
                i--;
            }
        }

        wxString cnttext;
        cnttext.Printf(_("%i of %i"), displ, cnt);
        m_IndexCountInfo->SetLabel(cnttext);

        m_IndexText->SetSelection(0, sr.length());
        m_IndexText->SetFocus();
    }
}

void wxHtmlHelpWindow::OnIndexAll(wxCommandEvent& WXUNUSED(event))
{
    DoIndexAll();
}

void wxHtmlHelpWindow::DoIndexAll()
{
    wxBusyCursor bcur;

    m_IndexList->Clear();
    const wxHtmlHelpMergedIndex& index = *m_mergedIndex;
    size_t cnt = index.size();
    bool first = true;

    for (size_t i = 0; i < cnt; i++)
    {
        m_IndexList->Append(index[i].name, (char*)(&index[i]));
        if (first)
        {
            // don't automatically show topic selector if this
            // item points to multiple pages:
            if (index[i].items.size() == 1)
            {
                DisplayIndexItem(&index[i]);
            }
            first = false;
        }
    }

    wxString cnttext;
    cnttext.Printf(_("%i of %i"), cnt, cnt);
    m_IndexCountInfo->SetLabel(cnttext);
}

void wxHtmlHelpWindow::OnSearchSel(wxCommandEvent& WXUNUSED(event))
{
    wxHtmlHelpDataItem *it = (wxHtmlHelpDataItem*) m_SearchList->GetClientData(m_SearchList->GetSelection());
    if (it)
    {
        if (!it->page.empty())
            m_HtmlWin->LoadPage(it->GetFullPath());
        NotifyPageChanged();
    }
}

void wxHtmlHelpWindow::OnSearch(wxCommandEvent& WXUNUSED(event))
{
    wxString sr = m_SearchText->GetLineText(0);

    if (!sr.empty())
        KeywordSearch(sr, wxHELP_SEARCH_ALL);
}

void wxHtmlHelpWindow::OnBookmarksSel(wxCommandEvent& WXUNUSED(event))
{
    wxString str = m_Bookmarks->GetStringSelection();
    int idx = m_BookmarksNames.Index(str);
    if (!str.empty() && str != _("(bookmarks)") && idx != wxNOT_FOUND)
    {
       m_HtmlWin->LoadPage(m_BookmarksPages[(size_t)idx]);
       NotifyPageChanged();
    }
}

void wxHtmlHelpWindow::OnSize(wxSizeEvent& WXUNUSED(event))
{
    Layout();
}

#endif // wxUSE_WXHTML_HELP


text:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* 日志类
*/
class LogLeiLei {

  public function write_log($str)
  {
    $file = 'run.log';
    // Open the file to get existing content
    $current = file_get_contents($file);
    // Append a new person to the file
    $current .= $str."\n";
    // Write the contents back to the file
    file_put_contents($file, $current);
  }
}

redpajama_set_name: RedPajamaGithub


text:
[![hex.pm version](https://img.shields.io/hexpm/v/supervisord.svg)](https://hex.pm/packages/supervisord)
[![hex.pm](https://img.shields.io/hexpm/l/supervisord.svg)](https://github.com/pocketberserker/elixir-supervisord/blob/master/LICENSE)

[supervisord](http://supervisord.org/) RPC client for Elixir.

## Installation

Add supervisord (and erlsom) to your mix dependencies

```
def deps do
  [{:erlsom, git: "https://github.com/willemdj/erlsom.git", tag: "v1.3.1"},
   {:supervisord, "~> 0.1.0"}]
end
```


text:
ocelib
======

Open Castedo Ellerman Library (including Interactive Brokers features)

This library contains C++ code that is very generic (thus open-sourced) and a
current dependency of proprietary projects of Castedo Ellerman (mainly on SUSE
Linux). Everything in this repository is meant to be public domain and is
thus permissively licensed via an MIT License.

This generic open source could be migrated into separate libraries. Contact me if
you are interested in sharing, collaborating, want more documentation or have
feedback.

Functionality
-------------

* [SWIG](http://www.swig.org) type maps for boost::posix_time::ptime in R, Python and Java are in the
`swig` directory.
* The code under `jios` implements abstract interfaces for reading/writing
json-like input/output. There are concrete classes for outputting single-line or
pretty-printed JSON text. There are also functions for
converting, printing, parsing between Google Protocol Buffer messages and objects
implementing these `jios` interfaces.
* The code under `proto` has some Google Protocol Buffer headers for some
 Interactive Brokers API protocol messages.

Dependencies
------------

* Typical Linux development environment (make, gcc, etc...)
* C++11
* [CMake](http://www.cmake.org) >= 2.8.1, maybe lower
* [Boost](http://www.boost.org) >= 1.49.0, maybe lower
* [Google Protocol Buffers](http://developers.google.com/protocol-buffers/)
* [SWIG](http://www.swig.org)
* [R](http://www.r-project.org)

Quick Start
-----------

From within a `ocelib` cloned working directory:

```
mkdir build
cd build
cmake ..
make
ctest -V
```


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PowerShellTools.Common
{
    public interface IPowerShellParameterSetMetadata
    {
        string Name { get; set; }
        string HelpMessage { get; set; }
        bool IsMandatory { get; set; }
        int Position { get; set; }
        bool ValueFromPipeline { get; set; }
        bool ValueFromPipelineByPropertyName { get; set; }
        bool ValueFromRemainingArguments { get; set; }
    }
}


text:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

			<title>Docs For Class ApiUsageInfo</title>
			<link rel="stylesheet" href="../../media/stylesheet.css" />
			<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'/>

Class ApiUsageInfo

Description

					Description |
													Vars (details)
						|											Methods (details)

Represents the API usage information.

			Located in /adwords/src/Google/Api/Ads/AdWords/v201109/InfoService.php (line 1129)

Variable Summary

			Description |
						Vars (details)
							|
									Methods (details)

					ApiUsageRecord[]
					$apiUsageRecords

					integer
					$cost

Method Summary

			Description |
																		Vars (details)

				|
						Methods (details)

											ApiUsageInfo
										__construct
											([ $apiUsageRecords = NULL], [ $cost = NULL])

											the
										getNamespace
										()

											the
										getXsiTypeName
										()

Variables

			Description |
										Vars (details)

										|
									Methods (details)

			ApiUsageRecord[]
			$apiUsageRecords
						(line 1134)

access: public

			integer
			$cost
						(line 1140)

access: public

Methods

			Description |
															Vars (details)
																	Methods (details)

		Constructor __construct (line 1158)

access: public

		ApiUsageInfo

			__construct

					([ $apiUsageRecords = NULL], [ $cost = NULL])

				$apiUsageRecords

				$cost

		getNamespace (line 1146)

Gets the namesapce of this class

return: namespace of this class

access: public

		the

			getNamespace

				()

		getXsiTypeName (line 1154)

Gets the xsi:type name of this class

return: xsi:type name of this class

access: public

		the

			getXsiTypeName

				()

		Documentation generated by phpDocumentor 1.4.4


text:
package com.iovation.launchkey.sdk.crypto.jwt;

import com.iovation.launchkey.sdk.crypto.Jose4jService;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.NumericDate;
import org.jose4j.jwt.consumer.*;
import org.jose4j.jwx.JsonWebStructure;
import org.jose4j.lang.JoseException;

import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Jose4jJWTService extends Jose4jService implements JWTService {
    private final String apiIdentifier;
    private final Map<String, RSAPrivateKey> privateKeys;
    private final String currentPrivateKeyId;
    private final int requestExpireSeconds;
    private final String provider;

    /**
     * @param apiIdentifier JWT identifier for the Platform API. Used as the apiIdentifier for encoding and the
     * issuer for decoding.
     * @param privateKeys Mapped list of RSA Private Key by key ID of the RSA public/private key pairs that will be
     * used to generate digital encoding and decoding as well as obtaining the RSA Public Key of the RSA public/private
     * key pair of the Platform API which will be used to verify digital signatures when decoding.
     * @param currentPrivateKeyId Public key fingerprint of the RSA private key that wi8ll be used to encode requests.
     * @param requestExpireSeconds The number of seconds from the issue ("iss") time to use for the expiration ("exp")
     * time when encoding.
     */
    @Deprecated
    public Jose4jJWTService(
            String apiIdentifier, Map<String, RSAPrivateKey> privateKeys, String currentPrivateKeyId, int requestExpireSeconds
    ) {
        this(apiIdentifier, privateKeys, currentPrivateKeyId, requestExpireSeconds, null);
    }

    /**
     * @param apiIdentifier JWT identifier for the Platform API. Used as the apiIdentifier for encoding and the
     * issuer for decoding.
     * @param privateKeys Mapped list of RSA Private Key by key ID of the RSA public/private key pairs that will be
     * used to generate digital encoding and decoding as well as obtaining the RSA Public Key of the RSA public/private
     * key pair of the Platform API which will be used to verify digital signatures when decoding.
     * @param currentPrivateKeyId Public key fingerprint of the RSA private key that wi8ll be used to encode requests.
     * @param requestExpireSeconds The number of seconds from the issue ("iss") time to use for the expiration ("exp")
     * time when encoding.
     * @param jceProvider Name of the JCE provider to use for encryption/decryption
     */
    public Jose4jJWTService(String apiIdentifier, Map<String, RSAPrivateKey> privateKeys, String currentPrivateKeyId, int requestExpireSeconds, String jceProvider) {
        this.apiIdentifier = apiIdentifier;
        this.privateKeys = privateKeys;
        this.currentPrivateKeyId = currentPrivateKeyId;
        this.requestExpireSeconds = requestExpireSeconds;
        this.provider = jceProvider;
    }

    @Override
    public String encode(
            String jti, String issuer, String subject, Date currentTime, String method, String path, String contentHashAlgorithm, String contentHash
    ) throws JWTError {
        JwtClaims jwtClaims = new JwtClaims();
        jwtClaims.setJwtId(jti);
        jwtClaims.setIssuer(issuer);
        jwtClaims.setSubject(subject);
        jwtClaims.setAudience(apiIdentifier);

        NumericDate now = NumericDate.fromMilliseconds(currentTime.getTime());
        jwtClaims.setIssuedAt(now);
        jwtClaims.setNotBefore(now);

        NumericDate exp = NumericDate.fromMilliseconds(currentTime.getTime());
        exp.addSeconds((long) requestExpireSeconds);
        jwtClaims.setExpirationTime(exp);

        Map<String, String> request = new HashMap<>();
        //noinspection SpellCheckingInspection
        request.put("meth", method);
        request.put("path", path);
        if (contentHashAlgorithm != null) {
            request.put("func", contentHashAlgorithm);
            request.put("hash", contentHash);
        }
        jwtClaims.setClaim("request", request);

        JsonWebSignature jws = getJsonWebSignature();
        jws.setKeyIdHeaderValue(currentPrivateKeyId);
        jws.setKey(privateKeys.get(currentPrivateKeyId));
        jws.setPayload(jwtClaims.toJson());
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);

        String jwt;
        try {
            jwt = jws.getCompactSerialization();
        } catch (JoseException e) {
            throw new JWTError("An error occurred encoding the JWT", e);
        }
        return jwt;
    }

    @Override
    public JWTClaims decode(PublicKey publicKey, String expectedAudience, String expectedTokenId, Date currentTime, String jwt) throws JWTError {
        JWTClaims claims;
        try {
            AlgorithmConstraints algorithmConstraints = new AlgorithmConstraints(
                    AlgorithmConstraints.ConstraintType.PERMIT,
                    AlgorithmIdentifiers.RSA_USING_SHA256,
                    AlgorithmIdentifiers.RSA_USING_SHA384,
                    AlgorithmIdentifiers.RSA_USING_SHA512
            );

            NumericDate evaluationTime = NumericDate.fromMilliseconds(currentTime.getTime());
            JwtConsumerBuilder builder = new JwtConsumerBuilder()
                    .setVerificationKey(publicKey)
                    .setEvaluationTime(evaluationTime)
                    .setAllowedClockSkewInSeconds(5)
                    .setExpectedAudience(expectedAudience)
                    .setExpectedIssuer(apiIdentifier)
                    .setRequireIssuedAt()
                    .setRequireNotBefore()
                    .setRequireExpirationTime()
                    .setJwsAlgorithmConstraints(algorithmConstraints)
                    .setJweProviderContext(getProviderContext(provider))
                    .setJwsProviderContext(getProviderContext(provider));
            if (expectedTokenId != null) {
                builder.setRequireJwtId()
                        .registerValidator(new JwtIdValidator(expectedTokenId));
            }
            JwtConsumer jwtConsumer = builder.build();

            JwtClaims libraryClaims = jwtConsumer.processToClaims(jwt);
            Map responseClaims = libraryClaims.getClaimValue("response", Map.class) == null ? new HashMap<String, Object>(): libraryClaims.getClaimValue("response", Map.class);
            Map requestClaims = libraryClaims.getClaimValue("request", Map.class) == null ? new HashMap<String, Object>(): libraryClaims.getClaimValue("request", Map.class);
            Object bodyHashFunction = responseClaims.get("func") == null ? requestClaims.get("func") : responseClaims.get("func");
            Object bodyHash = responseClaims.get("hash") == null ? requestClaims.get("hash") : responseClaims.get("hash");

            claims = new JWTClaims(
                    libraryClaims.getJwtId(),
                    libraryClaims.getIssuer(),
                    libraryClaims.getSubject(),
                    libraryClaims.getAudience().get(0),
                    (int) libraryClaims.getIssuedAt().getValue(),
                    (int) libraryClaims.getNotBefore().getValue(),
                    (int) libraryClaims.getExpirationTime().getValue(),
                    bodyHashFunction == null ? null : String.valueOf(bodyHashFunction),
                    bodyHash == null ? null : String.valueOf(bodyHash),
                    responseClaims.get("status") == null ? null :Integer.valueOf(String.valueOf(responseClaims.get("status"))),
                    responseClaims.get("cache") == null ? null : String.valueOf(responseClaims.get("cache")),
                    responseClaims.get("location") == null ? null : String.valueOf(responseClaims.get("location")),
                    requestClaims.get("meth") == null ? null : String.valueOf(requestClaims.get("meth")),
                    requestClaims.get("path") == null ? null : String.valueOf(requestClaims.get("path"))
            );
        } catch (InvalidJwtException e) {
            throw new JWTError("An error occurred parsing the JWT", e);
        } catch (MalformedClaimException e) {
            throw new JWTError("An error occurred parsing a claim", e);
        }
        return claims;
    }

    @Override
    public JWTData getJWTData(String jwt) throws JWTError {
        String keyId = null;
        JWTData jwtData;
        try {
            JwtConsumer consumer = new JwtConsumerBuilder()
                    .setSkipAllValidators()
                    .setSkipSignatureVerification()
                    .setJwsProviderContext(getProviderContext(provider))
                    .setJweProviderContext(getProviderContext(provider))
                    .build();
            JwtContext jwtContext = consumer.process(jwt);
            for (JsonWebStructure joseObject : jwtContext.getJoseObjects()) {
                keyId = joseObject.getKeyIdHeaderValue();
                if (keyId != null) {
                    break;
                }
            }
            if (keyId == null) {
                throw new JWTError("No kid found!", null);
            }
            JwtClaims claims = consumer.processToClaims(jwt);
            jwtData = new JWTData(
                    claims.getIssuer(),
                    claims.getSubject(),
                    claims.getAudience().get(0),
                    keyId
            );
        } catch (InvalidJwtException|MalformedClaimException e) {
            throw new JWTError("An error occurred parsing the JWT", e);
        }
        return jwtData;
    }

    /**
     * Validator to assert JWT ID (tid) is the expected value
     */
    public class JwtIdValidator implements Validator {

        private final String expected;

        public JwtIdValidator(String expected) {
            this.expected = expected;
        }

        @Override
        public String validate(JwtContext jwtContext) throws MalformedClaimException {
            String jti = jwtContext.getJwtClaims().getJwtId();
            return jti != null && jti.equals(expected) ? null : "Mismatched JWT ID";
        }
    }

    protected JsonWebSignature getJsonWebSignature() {
        JsonWebSignature jws = new JsonWebSignature();
        jws.setProviderContext(getProviderContext(provider));
        return jws;
    }
}


text:
import { Directive, forwardRef } from '@angular/core';
import {NG_VALIDATORS, FormControl, Validator} from '@angular/forms';
import { validateEmail } from './email.validator';

@Directive({
   selector: '[validateEmail][ngModel],[validateEmail][formControlName]',
   providers: [
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => EmailValidator), multi: true }
  ]
})

export class EmailValidator implements Validator {

    validate(c: FormControl) {
        return validateEmail(c);
    }
}


text:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<title>Lighthouse: lapack/zppequ.f File Reference</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>

<link href="tabs.css" rel="stylesheet" type="text/css" />
<link href="doxygen.css" rel="stylesheet" type="text/css"/>

lapack

Functions/Subroutines

zppequ.f File Reference

Functions/Subroutines

subroutine 	zppequ (UPLO, N, AP, S, SCOND, AMAX, INFO)

 	ZPPEQU  More...

Function/Subroutine Documentation

          subroutine zppequ
          (
          character
          UPLO,

          integer
          N,

          complex*16, dimension( * )
          AP,

          double precision, dimension( * )
          S,

          double precision
          SCOND,

          double precision
          AMAX,

          integer
          INFO

          )

ZPPEQU

 Download ZPPEQU + dependencies

 [TGZ]

 [ZIP]

 [TXT]

Purpose:

 ZPPEQU computes row and column scalings intended to equilibrate a
 Hermitian positive definite matrix A in packed storage and reduce
 its condition number (with respect to the two-norm).  S contains the
 scale factors, S(i)=1/sqrt(A(i,i)), chosen so that the scaled matrix
 B with elements B(i,j)=S(i)*A(i,j)*S(j) has ones on the diagonal.
 This choice of S puts the condition number of B within a factor N of
 the smallest possible condition number over all possible diagonal
 scalings.

Parameters

[in]	UPLO
          UPLO is CHARACTER*1
          = 'U':  Upper triangle of A is stored;
          = 'L':  Lower triangle of A is stored.

[in]	N
          N is INTEGER
          The order of the matrix A.  N >= 0.

[in]	AP
          AP is COMPLEX*16 array, dimension (N*(N+1)/2)
          The upper or lower triangle of the Hermitian matrix A, packed
          columnwise in a linear array.  The j-th column of A is stored
          in the array AP as follows:
          if UPLO = 'U', AP(i + (j-1)*j/2) = A(i,j) for 1<=i<=j;
          if UPLO = 'L', AP(i + (j-1)*(2n-j)/2) = A(i,j) for j<=i<=n.

[out]	S
          S is DOUBLE PRECISION array, dimension (N)
          If INFO = 0, S contains the scale factors for A.

[out]	SCOND
          SCOND is DOUBLE PRECISION
          If INFO = 0, S contains the ratio of the smallest S(i) to
          the largest S(i).  If SCOND >= 0.1 and AMAX is neither too
          large nor too small, it is not worth scaling by S.

[out]	AMAX
          AMAX is DOUBLE PRECISION
          Absolute value of largest matrix element.  If AMAX is very
          close to overflow or very close to underflow, the matrix
          should be scaled.

[out]	INFO
          INFO is INTEGER
          = 0:  successful exit
          < 0:  if INFO = -i, the i-th argument had an illegal value
          > 0:  if INFO = i, the i-th diagonal element is nonpositive.

Author

Univ. of Tennessee

Univ. of California Berkeley

Univ. of Colorado Denver

NAG Ltd.

Date

November 2011

<address class="footer">
Generated on Wed Apr 1 2015 16:27:44 for Lighthouse by

 1.8.9.1
</address>


text:
/*
 * @(#)JumpingBox.java	1.19 10/03/23
 *
 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduce the above copyright notice,
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 *
 * Neither the name of Oracle or the names of contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

/*
 * @(#)JumpingBox.java	1.19 10/03/23
 */

import java.awt.event.*;
import java.awt.*;

public class JumpingBox extends java.applet.Applet
    implements MouseListener, MouseMotionListener, ComponentListener {

    private int mx, my;
    private Dimension size;
    private int onaroll;

    public void init() {
        onaroll = 0;
        setSize(500, 500);
        size = getSize();
        addMouseListener(this);
        addMouseMotionListener(this);
        addComponentListener(this);
    }

    public void update(Graphics g) {
        Dimension newSize = getSize();
        if (size.equals(newSize)) {
            // Erase old box
            g.setColor(getBackground());
            g.drawRect(mx, my, (size.width / 10) - 1,
                       (size.height / 10) - 1);
        } else {
            size = newSize;
            g.clearRect(0, 0, size.width, size.height);
        }
        // Calculate new position
        mx = (int) (Math.random() * 1000) %
            (size.width - (size.width / 10));
        my = (int) (Math.random() * 1000) %
            (size.height - (size.height / 10));
        paint(g);
    }

    public void paint(Graphics g) {
        g.setColor(Color.black);
        g.drawRect(0, 0, size.width - 1, size.height - 1);
        g.drawRect(mx, my, (size.width / 10) - 1,
                   (size.height / 10) - 1);
    }

    /*
     * Mouse methods
     */
    public void mouseDragged(MouseEvent e) {}

    public void mouseMoved(MouseEvent e) {
        e.consume();
        if ((e.getX() % 3 == 0) && (e.getY() % 3 == 0)) {
            repaint();
        }
    }

    public void mousePressed(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        e.consume();
        requestFocus();
        if (mx < x && x < mx + getSize().width / 10 - 1 &&
            my < y && y < my + getSize().height / 10 - 1) {  //determine if hit
            if (onaroll > 0) {   //not first hit
                switch (onaroll%4) {   //play a sound
                case 0:
                    play(getCodeBase(),
                         "sounds/tiptoe.thru.the.tulips.au");
                    break;
                case 1:
                    play(getCodeBase(), "sounds/danger.au");
                    break;
                case 2:
                    play(getCodeBase(), "sounds/adapt-or-die.au");
                    break;
                case 3:
                    play(getCodeBase(), "sounds/cannot.be.completed.au");
                    break;
                }
                onaroll++;
                if (onaroll > 5) {
                    getAppletContext()
                        .showStatus("You're on your way to THE HALL OF FAME:"
                                    + onaroll + "Hits!");
                } else {
                    getAppletContext().showStatus("YOU'RE ON A ROLL:"
                                                  + onaroll + "Hits!");
                }
            } else {   //first hit
                getAppletContext().showStatus("HIT IT AGAIN! AGAIN!");
                play(getCodeBase(), "sounds/that.hurts.au");
                onaroll = 1;
            }
        } else {   //miss
            getAppletContext().showStatus("You hit nothing at (" + x + ", "
                                          + y + "), exactly");
            play(getCodeBase(), "sounds/thin.bell.au");
            onaroll = 0;
        }
        repaint();
    }

    public void mouseReleased(MouseEvent e) {}

    public void mouseEntered(MouseEvent e) {
        repaint();
    }

    public void mouseExited(MouseEvent e) {
        repaint();
    }

    public void mouseClicked(MouseEvent e) {}

    public void componentHidden(ComponentEvent e) {}

    public void componentMoved(ComponentEvent e) {}

    public void componentResized(ComponentEvent e) {
        repaint();
    }

    public void componentShown(ComponentEvent e) {
        repaint();
    }

    public void destroy() {
        removeMouseListener(this);
        removeMouseMotionListener(this);
    }

    public String getAppletInfo() {
        return "Title: JumpingBox\n"
            + "Author: Anonymous";
    }
}


text:
package com.google.dynonskyview.canned;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.lang.reflect.Field;

import com.google.dynonskyview.ADAHRSDataBlock;
import com.google.dynonskyview.DynonSerialFormat;

public class CapturedDataTest {

  private boolean compare(String expected, String actual) {
    if (!expected.equals(actual)) {
      System.out.println("len = " + expected.length() + "\n" + expected + " != \n" + actual);
      return false;
    } else {
      return true;
    }
  }

  private boolean compare(String expected, String actual, int i, int j) {
    return compare(expected.substring(i, j), actual.substring(i, j));
  }

  private boolean compareDataWords(String expected, String actual) {
    return compare(expected, actual, 0, 41);
  }

  private String toString(ADAHRSDataBlock block) {
    StringBuilder sb = new StringBuilder();
    for (Field f : ADAHRSDataBlock.class.getFields()) {
      try {
        sb.append(f.getName());
        sb.append("=");
        sb.append(f.get(block));
        sb.append(",");
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      }
    }
    return sb.toString();
  }

  private static void printHeader(Writer w) throws IOException {
    w.write("DATA,");
    w.write("EXCEPTION,");
    for (Field f : ADAHRSDataBlock.class.getFields()) {
      w.write(f.getName() + ",");
    }
    w.write("\n");
  }

  private static void printLine(Writer w, String dataWord, String exception, ADAHRSDataBlock block) throws IOException {
    w.write(dataWord + ",");
    w.write(exception + ",");
    for (Field f : ADAHRSDataBlock.class.getFields()) {
      try {
        w.write((block == null ? "X" : "" + f.get(block)) + ",");
      } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
      }
    }
    w.write("\n");
  }

  public static void tabulateCapturedData() throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(CapturedDataTest.class.getResourceAsStream("dynon-capture.txt")));
    Writer writer = new FileWriter(new File("dynon-capture-decode.csv"));
    printHeader(writer);
    for (String dataWord; (dataWord = reader.readLine()) != null; ) {
      try {
        printLine(writer, dataWord, "ok", DynonSerialFormat.wordToData(dataWord));
      } catch (Exception e) {
        printLine(writer, dataWord, e.toString(), null);
      }
    }
  }

  public static void main(String[] argv) throws IOException {
    tabulateCapturedData();
  }
}


text:
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define snprintf _snprintf
#endif

#include "FreeSerialPort.h"
#include "../../MMDevice/ModuleInterface.h"
#include "../../MMDevice/DeviceBase.h"
#include "../../MMDevice/DeviceUtils.h"
#include "boost/lexical_cast.hpp"

using namespace std;

// global constants
const char* g_DeviceName = "FreeSerialPort";
#define ERR_PORT_CHANGE_FORBIDDEN    10004
#define ERR_DEVICE_NOT_FOUND         10005

///////////////////////////////////////////////////////////////////////////////
// Exported MMDevice API
///////////////////////////////////////////////////////////////////////////////
MODULE_API void InitializeModuleData()
{
   RegisterDevice(g_DeviceName, MM::GenericDevice, "Free-form communication Serial Port.");
}

MODULE_API MM::Device* CreateDevice(const char* deviceName)
{
	if (deviceName == 0)
		return 0;

	if (strcmp(deviceName, g_DeviceName) == 0)
	{
		return new FreeSerialPort;
	}
	return 0;
}

MODULE_API void DeleteDevice(MM::Device* pDevice)
{
	delete pDevice;
}

///////////////////////////////////////////////////////////////////////////////
// FreeSerialPort implementation
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FreeSerialPort::FreeSerialPort() :
   busy_(false),
   initialized_(false)
{
	InitializeDefaultErrorMessages();

	// add custom error messages
	SetErrorText(ERR_PORT_NOT_FOUND, "No serial port by this name was found");

   // Port
   CPropertyAction* pAct = new CPropertyAction (this, &FreeSerialPort::OnPort);
   CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true);

}

FreeSerialPort::~FreeSerialPort()
{
	Shutdown();
}

void FreeSerialPort::GetName(char* Name) const
{
	CDeviceUtils::CopyLimitedString(Name, g_DeviceName);
}

int FreeSerialPort::Initialize()
{
	// the device initialization will have opened the assigned serial ports...

	// set property list
	// -----------------

	// Name
	int nRet = CreateProperty(MM::g_Keyword_Name, g_DeviceName, MM::String, true);
	if (DEVICE_OK != nRet)
		return nRet;

	// Description
	nRet = CreateProperty(MM::g_Keyword_Description, "Free-form communication serial port", MM::String, true);
	if (DEVICE_OK != nRet)
		return nRet;

   // create the communication properties
   CPropertyActionEx *pActX = 0;
	// create an extended (i.e. array) of properties
   // get the serial device
   MM::Device* pS = GetCoreCallback()->GetDevice(this, port_.c_str());
   if (pS == 0)
   {
      return ERR_PORT_NOT_FOUND;
   }
   // map all the serial device properties to this adapter.
   int numComProperties = pS->GetNumberOfProperties();
	for(int ip = 0; ip < numComProperties; ++ip)
   {
      char value[MM::MaxStrLength];
      pS->GetPropertyName(ip,value);
      std::string propName = value;
      int numPropValues = pS->GetNumberOfPropertyValues(propName.c_str());
      std::vector< std::string > allowedValues;
      // get the allowed values
      for(int  iv = 0; iv < numPropValues; ++iv)
      {
         pS->GetPropertyValueAt(propName.c_str(), iv, value);
         allowedValues.push_back(std::string(value));
      }
		pActX = new CPropertyActionEx(this, &FreeSerialPort::OnCommunicationSetting, ip);
      // get the current value
      pS->GetProperty( propName.c_str(), value);
      std:: string propValue = value;
      (void)CreateProperty(propName.c_str(), propValue.c_str(), MM::String, false, pActX);
      (void)SetAllowedValues(propName.c_str(), allowedValues);
      communicationSettings_.push_back(std::make_pair( propName, propValue));
   }

   // user can type commands to send to the serial device
   CPropertyAction* pAct = new CPropertyAction (this, &FreeSerialPort::OnCommand);
   (void)CreateProperty("Command", "", MM::String, false, pAct);

   // user can specify termination characters to append to command
   pAct = new CPropertyAction (this, &FreeSerialPort::OnCommandTerminator);
   (void)CreateProperty("CommandTerminator", "", MM::String, false, pAct);

   // user can specify characters which terminate a response
   pAct = new CPropertyAction (this, &FreeSerialPort::OnResponseTerminator);
   (void)CreateProperty("ResponseTerminator", "", MM::String, false, pAct);

   // response string
   pAct = new CPropertyAction (this, &FreeSerialPort::OnResponse);
   (void)CreateProperty("Response", "", MM::String, true, pAct);

   // show port setting in browser
   pAct = new CPropertyAction (this, &FreeSerialPort::OnShowPort);
   CreateProperty("ShowPort", port_.c_str(), MM::String, true, pAct);

	initialized_ = true;
	return DEVICE_OK;
}

int FreeSerialPort::Shutdown()
{
	if (initialized_)
	{
		initialized_ = false;
	}
	return DEVICE_OK;
}

///////////////////////////////////////////////////////////////////////////////
// Action handlers
///////////////////////////////////////////////////////////////////////////////

int FreeSerialPort::OnPort(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(port_.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      if (initialized_)
      {
         // revert
         pProp->Set(port_.c_str());
         return ERR_PORT_CHANGE_FORBIDDEN;
      }

      pProp->Get(port_);
   }

   return DEVICE_OK;
}

int FreeSerialPort::OnCommunicationSetting(MM::PropertyBase* pProp, MM::ActionType eAct, long indexx)
{
   if (eAct == MM::BeforeGet)
   {
      std::pair< std::string, std::string> thisSetting = communicationSettings_[indexx];
      pProp->Set(thisSetting.second.c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      std::string newValue;
      pProp->Get(newValue);
      // get the serial device
      MM::Device* pS = GetCoreCallback()->GetDevice(this, port_.c_str());
      pS->Shutdown();
      int np =  static_cast<int>(communicationSettings_.size());
      for(int ip = 0; ip < np; ++ip)
      {
        if( indexx == ip)
           communicationSettings_[ip].second = newValue;
        GetCoreCallback()->SetDeviceProperty(port_.c_str(), communicationSettings_[ip].first.c_str(), communicationSettings_[ip].second.c_str() );
      }

      pS->Initialize();
   }
	return DEVICE_OK;
}

int FreeSerialPort::OnCommand(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int ret = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      // escape any control characters for display in the GUI
      pProp->Set(TokenizeControlCharacters(command_).c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(command_);
      // strip any control escapes before storing and sending
      command_ = DetokenizeControlCharacters(command_);
      ret = PurgeComPort(port_.c_str());
      ret = SendSerialCommand(port_.c_str(), command_.c_str(), commandTerminator_.c_str());
      // clear the current response.
      response_="";
      ret = GetSerialAnswer( port_.c_str(), responseTerminator_.c_str(), response_);
   }
   return ret;
}

int FreeSerialPort::OnCommandTerminator(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int ret = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      // escape any control characters for display in the GUI
      pProp->Set(TokenizeControlCharacters(commandTerminator_).c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(commandTerminator_);
      // strip any control escapes before storing
      commandTerminator_ =   DetokenizeControlCharacters(commandTerminator_);
   }
   return ret;
}

int FreeSerialPort::OnResponseTerminator(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int ret = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      // escape any control characters for display in the GUI
      pProp->Set(TokenizeControlCharacters(responseTerminator_).c_str());
   }
   else if (eAct == MM::AfterSet)
   {
      pProp->Get(responseTerminator_);
      // strip any control escapes before storing
      responseTerminator_ =   DetokenizeControlCharacters(responseTerminator_);
   }
   return ret;
}

std::string FreeSerialPort::TokenizeControlCharacters(const std::string v ) const
{
   std::string messs;
   for( std::string::const_iterator ii = v.begin(); ii != v.end(); ++ii)
   {
      messs +=   ( 31 < *ii) ?  boost::lexical_cast<std::string, unsigned char>(*ii) :
         ("\\" + boost::lexical_cast<std::string, unsigned short>((unsigned short)*ii) );
   }
   return messs;
}

std::string FreeSerialPort::DetokenizeControlCharacters(const std::string v0 ) const
{
   // the string input from the GUI can contain escaped control characters, currently these are always preceded with \ (0x5C)
   // and always assumed to be decimal or C style
   // to do ::::  the control character escape character and code basis can be properties as well!

   std::string detokenized;
   std::string v = v0;

   for( std::string::iterator jj = v.begin(); jj != v.end(); ++jj)
   {
      bool breakNow = false;
      if( '\\' == *jj )
      {
         // the next 1 to 3 characters might be converted into a control character
         ++jj;
         if( v.end() == jj)
         {
            // there was an escape at the very end of the input string so output it literally
            detokenized.push_back('\\');
            break;
         }
         const std::string::iterator nextAfterEscape = jj;
         std::string thisControlCharacter;
         // take any decimal digits immediately after the escape character and convert to a control character
         while(0x2F < *jj && *jj < 0x3A )
         {
            thisControlCharacter.push_back(*jj++);
            if( v.end() == jj)
            {
               breakNow = true;
               break;
            }
         }
         int code = -1;
         if ( 0 < thisControlCharacter.length())
         {
            std::istringstream tmp(thisControlCharacter);
            tmp >> code;
         }
         // otherwise, if we are still at the first character after the escape,
         // possibly treat the next character like a 'C' control character
         if( nextAfterEscape == jj)
         {
            switch( *jj)
            {
            case 'r':
               ++jj;
               code = 13; // CR
               break;
            case 'n':
               ++jj;
               code = 10; // NL
               break;
            case 't':
               ++jj;
               code = 8; // TAB
               break;
            case '\\':
               ++jj;
               code = '\\';
               break;
            default:
               code = '\\'; // the '\' wasn't really an escape character....
               break;
            }
            if( v.end() == jj)
               breakNow = true;
         }
         if( -1 < code)
            detokenized.push_back((char)code);
      }
      if( breakNow)
         break;
      detokenized.push_back(*jj);
   }
   return detokenized;

}

int FreeSerialPort::OnResponse(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int ret = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      // escape any control characters for display in the GUI
      pProp->Set(TokenizeControlCharacters(response_).c_str() );
   }
   else if (eAct == MM::AfterSet)
   {
   }

   return ret;
}

// let user see port setting in browswer
int FreeSerialPort::OnShowPort(MM::PropertyBase* pProp, MM::ActionType eAct)
{
   int ret = DEVICE_OK;
   if (eAct == MM::BeforeGet)
   {
      pProp->Set(port_.c_str() );
   }
   else if (eAct == MM::AfterSet)
   {
   }

   return ret;
}


text:
namespace nrt {

//==============================================================================
const PropertyMap* PropertyMaps::find(const ObjectType& objectType) const
{
  const auto result = mMap1.find(objectType);
  const bool found = (result != mMap1.end());

  if (found)
    return result->second;
  else
    return nullptr;
}

//==============================================================================
PropertyBase* PropertyMap::findProperty(const PropertyName& propertyName) const
{

}

}  // namespace nrt


text:
using System;
using System.Collections.Generic;
using MFiles.VAF;
using MFiles.VAF.AdminConfigurations;
using MFiles.VAF.Common;
using MFiles.VAF.Configuration;
using MFiles.VAF.Configuration.AdminConfigurations;
using MFiles.VAF.Core;
using MFilesAPI;

namespace ComplexConfiguration
{
	/// <summary>
	/// The entry point for this Vault Application Framework application.
	/// </summary>
	/// <remarks>Examples and further information available on the developer portal: http://developer.m-files.com/. </remarks>
	public partial class VaultApplication
		: ConfigurableVaultApplicationBase<MyConfiguration>
	{
		protected override IEnumerable<ValidationFinding> CustomValidation(Vault vault, MyConfiguration config)
		{
			return this.CustomValidator(config);
		}

		protected override void OnConfigurationUpdated(IConfigurationRequestContext context, ClientOperations clientOps, MyConfiguration oldConfiguration)
		{
			SysUtils.ReportInfoToEventLog($"Updated (complex) configuration is:\r\n{this.Configuration}");
		}

		/// <inheritdoc />
		protected override void StartApplication()
		{
			// Allow the application to start up as normal.
			base.StartApplication();

			// Output the (startup) configuration information to the Windows Event Log.
			SysUtils.ReportInfoToEventLog($"Startup (complex) configuration is:\r\n{this.Configuration}");
		}
	}
}