diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/debugger/src/dbg_wx_mon_win.erl | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/debugger/src/dbg_wx_mon_win.erl')
-rw-r--r-- | lib/debugger/src/dbg_wx_mon_win.erl | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/lib/debugger/src/dbg_wx_mon_win.erl b/lib/debugger/src/dbg_wx_mon_win.erl new file mode 100644 index 0000000000..dfb327fa6a --- /dev/null +++ b/lib/debugger/src/dbg_wx_mon_win.erl @@ -0,0 +1,586 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(dbg_wx_mon_win). + +%% External exports +-export([init/0]). +-export([create_win/3, get_window/1, + show_option/3, + enable/2, is_enabled/1, select/2, + add_module/3, delete_module/2, + add_process/6, update_process/4, clear_processes/1, + add_break/3, update_break/2, delete_break/2, + clear_breaks/1, clear_breaks/2, + handle_event/2 + ]). + +-import(dbg_wx_win, [to_string/1, to_string/2]). + +-include_lib("wx/include/wx.hrl"). + +-define(default_rows,10). + +-record(moduleInfo, {module, menubtn}). +-record(procInfo, {pid, row}). +-record(breakInfo, {point, status, break}). +-record(break, {mb, smi, emi, dimi, demi}). %% BUGBUG defined in dbg_ui_win +-record(winInfo, {window, % gsobj() + grid, % gsobj() + row, % int() Last row in grid + + focus, % int() Selected row in grid + + modules=[], % [#moduleInfo{}] Known modules + processes=[], % [#procInfo{}] Known processes + breaks=[], % [#breakInfo{}] Known breakpoints + + listbox, % gsobj() Listinng known modules + + %% Auto attach buttons + fbutton, % gsobj() + bbutton, % gsobj() + ebutton, % gsobj() + selected=[], % ['First Call'|'On Break'|'On Exit'] + + slabel, % showing Stack Trace option + blabel % showing Back Trace Size + }). + +%%==================================================================== +%% External exports +%%==================================================================== + +init() -> + dbg_wx_win:init(). + +%%-------------------------------------------------------------------- +%% create_win(GS, Title, Menus) -> #winInfo{} +%% GS = gsobj() +%% Title = string() +%% Menus = [menu()] See dbg_ui_win.erl +%%-------------------------------------------------------------------- + +-define(GRID,1000). + +-define(PAD, 5). +-define(Wf, 150). +-define(Wg, 770). +-define(W, 800). +-define(H, 390). + +create_win(_Wx, Title, Menus) -> + wx:batch(fun() -> create_win_batch(Title, Menus) end). + +create_win_batch(Title, Menus) -> + Win = wxFrame:new(wx:null(), ?wxID_ANY, Title, + [{size, {?W,?H}}]), + wxFrame:connect(Win, close_window, [{skip, true}]), + MenuBar = wxMenuBar:new(), + dbg_wx_win:create_menus(MenuBar, Menus, Win, 1), + wxFrame:setMenuBar(Win, MenuBar), + + MainSz = wxBoxSizer:new(?wxHORIZONTAL), + LeftSz = wxBoxSizer:new(?wxVERTICAL), + + Panel = wxPanel:new(Win), + Hlb = 200, + Listbox = wxListBox:new(Panel, ?wxID_ANY, [{size,{?Wf,Hlb}}, + {style,?wxLB_SINGLE}]), + wxSizer:add(LeftSz,Listbox,[{border, 3}]), + wxListBox:connect(Listbox, command_listbox_doubleclicked), + wxListBox:connect(Listbox, right_down), + + SBox = wxStaticBox:new(Panel, ?wxID_ANY, "Auto Attach:"), + SBS = wxStaticBoxSizer:new(SBox, ?wxVERTICAL), + Fbtn = wxCheckBox:new(Panel, ?wxID_ANY, "First Call"), + wxSizer:add(SBS,Fbtn), + Bbtn = wxCheckBox:new(Panel, ?wxID_ANY, "On Break"), + wxSizer:add(SBS,Bbtn), + Ebtn = wxCheckBox:new(Panel, ?wxID_ANY, "On Exit"), + wxSizer:add(SBS,Ebtn), + wxFrame:connect(Panel, command_checkbox_clicked), + wxSizer:add(LeftSz,SBS, [{flag,?wxEXPAND}]), + + SLabel = wxStaticText:new(Panel, ?wxID_ANY, "Stack Trace:\n On (with tail)"), + wxSizer:add(LeftSz,SLabel), + BLabel = wxStaticText:new(Panel, ?wxID_ANY, "Back Trace Size:\n 50000"), + wxSizer:add(LeftSz,BLabel), + + %% Create list_crtl / grid + Grid = wxListCtrl:new(Panel, [{winid, ?GRID}, + {style, ?wxLC_REPORT bor ?wxLC_SINGLE_SEL + bor ?wxLC_HRULES }, + {size, {600, -1}}]), + LI = wxListItem:new(), + wxListItem:setText(LI, "Pid"), + wxListItem:setAlign(LI, ?wxLIST_FORMAT_CENTRE), + wxListCtrl:insertColumn(Grid, 0, LI), + wxListItem:setText(LI, "Initial Call"), + wxListItem:setAlign(LI, ?wxLIST_FORMAT_LEFT), + wxListCtrl:insertColumn(Grid, 1, LI), + wxListItem:setText(LI, "Name"), + wxListCtrl:insertColumn(Grid, 2, LI), + wxListItem:setAlign(LI, ?wxLIST_FORMAT_CENTRE), + wxListItem:setText(LI, "Status"), + wxListCtrl:insertColumn(Grid, 3, LI), + wxListItem:setText(LI, "Information"), + wxListItem:setAlign(LI, ?wxLIST_FORMAT_LEFT), + wxListCtrl:insertColumn(Grid, 4, LI), + wxListItem:destroy(LI), + + wxListCtrl:setColumnWidth(Grid, 0, 80), + wxListCtrl:setColumnWidth(Grid, 1, 150), + wxListCtrl:setColumnWidth(Grid, 2, 100), + wxListCtrl:setColumnWidth(Grid, 3, 70), + wxListCtrl:setColumnWidth(Grid, 4, 200), + wxListCtrl:connect(Grid, command_list_item_activated), + wxListCtrl:connect(Grid, command_list_item_selected), + wxListCtrl:connect(Grid, size, [{skip, true}]), + wxListCtrl:connect(Grid, key_up, [{id, ?GRID}, {skip,true}]), + + wxWindow:connect(Win, enter_window, [{skip,true}]), + wxWindow:setFocus(Grid), + + %% Put it in the window + wxSizer:add(MainSz, LeftSz, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}]), + wxSizer:add(MainSz, Grid, [{border, 3}, {flag,?wxALL bor ?wxEXPAND}, + {proportion, 1}]), + + wxWindow:setSizer(Panel,MainSz), + wxSizer:fit(MainSz, Win), + wxSizer:setSizeHints(MainSz,Win), + + IconFile = dbg_wx_win:find_icon("erlang_bug.png"), + Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]), + wxFrame:setIcon(Win, Icon), + wxIcon:destroy(Icon), + wxFrame:show(Win), + dbg_wx_winman:raise(Win), + #winInfo{window=Win, grid=Grid, row=0, focus=0, + listbox=Listbox, + fbutton=Fbtn, bbutton=Bbtn, ebutton=Ebtn, + slabel=SLabel, blabel=BLabel}. + +%%-------------------------------------------------------------------- +%% get_window(WinInfo) -> Window +%% WinInfo = #winInfo{} +%% Window = wxobj() +%%-------------------------------------------------------------------- +get_window(WinInfo) -> + WinInfo#winInfo.window. + +%%-------------------------------------------------------------------- +%% show_option(WinInfo, Option, Value) -> void() +%% WinInfo = #winInfo{} +%% Option = auto_attach | stack_trace | back_trace +%% Value = [Flag] % Option==auto_attach +%% Flag = init | break | exit +%% | true | all | no_tail | false % Option==stack_trace +%% | int() % Option==back_trace +%%-------------------------------------------------------------------- +show_option(WinInfo, Option, Value) -> + case Option of + auto_attach -> + wx:foreach(fun(Button) -> + wxCheckBox:setValue(Button, false) + end, + option_buttons(WinInfo, [init, break, exit])), + wx:foreach(fun(Button) -> + wxCheckBox:setValue(Button, true) + end, + option_buttons(WinInfo, Value)); + + stack_trace -> + Text = case Value of + all -> "Stack Trace:\n On (with tail)"; + true -> "Stack Trace:\n On (with tail)"; + no_tail -> "Stack Trace:\n On (no tail)"; + false -> "Stack Trace:\n Off" + end, + wxStaticText:setLabel(WinInfo#winInfo.slabel, Text); + + back_trace -> + Text = "Back Trace Size:\n " ++ integer_to_list(Value), + wxStaticText:setLabel(WinInfo#winInfo.blabel, Text) + end. + +option_buttons(WinInfo, [init|Flags]) -> + [WinInfo#winInfo.fbutton|option_buttons(WinInfo, Flags)]; +option_buttons(WinInfo, [break|Flags]) -> + [WinInfo#winInfo.bbutton|option_buttons(WinInfo, Flags)]; +option_buttons(WinInfo, [exit|Flags]) -> + [WinInfo#winInfo.ebutton|option_buttons(WinInfo, Flags)]; +option_buttons(_WinInfo, []) -> + []. + +%%-------------------------------------------------------------------- +%% enable([MenuItem], Bool) +%% is_enabled(MenuItem) -> Bool +%% MenuItem = atom() +%% Bool = boolean() +%%-------------------------------------------------------------------- +enable(MenuItems, Bool) -> + lists:foreach(fun(MenuItem) -> + MI = get(MenuItem), + wxMenuItem:enable(MI, [{enable, Bool}]) + end, + MenuItems). + +is_enabled(MenuItem) -> + MI = get(MenuItem), + wxMenuItem:isEnabled(MI). + +%%-------------------------------------------------------------------- +%% select(MenuItem, Bool) +%% MenuItem = atom() +%% Bool = boolean() +%%-------------------------------------------------------------------- +select(MenuItem, Bool) -> + MI = get(MenuItem), + wxMenuItem:check(MI, [{check, Bool}]). + +%%-------------------------------------------------------------------- +%% add_module(WinInfo, Name, Mod) -> WinInfo +%% WinInfo = #winInfo{} +%% Name = atom() +%% Mod = atom() +%%-------------------------------------------------------------------- +add_module(WinInfo, MenuName, Mod) -> + Win = WinInfo#winInfo.window, + Modules = WinInfo#winInfo.modules, + case lists:keysearch(Mod, #moduleInfo.module, Modules) of + {value, _ModInfo} -> WinInfo; + false -> + %% Create a menu for the module + Menu = get(MenuName), + Sub = wxMenu:new([]), + ViewItem = wxMenu:append(Sub, ?wxID_ANY, "View"), + ViewId = wxMenuItem:getId(ViewItem), + wxMenu:connect(Win, command_menu_selected, + [{id,ViewId}, {userData, {module,Mod,view}}]), + DelItem = wxMenu:append(Sub, ?wxID_ANY, "Delete"), + DelId = wxMenuItem:getId(DelItem), + wxMenu:connect(Win, command_menu_selected, + [{id,DelId}, {userData, {module,Mod,delete}}]), + MenuBtn = wxMenu:append(Menu, ?wxID_ANY, atom_to_list(Mod), Sub), + wxListBox:append(WinInfo#winInfo.listbox, atom_to_list(Mod)), + + ModInfo = #moduleInfo{module=Mod, menubtn={Menu,MenuBtn}}, + WinInfo#winInfo{modules=[ModInfo | Modules]} + end. + +%%-------------------------------------------------------------------- +%% delete_module(WinInfo, Mod) -> WinInfo +%% WinInfo = #winInfo{} +%% Mod = atom() +%%-------------------------------------------------------------------- +delete_module(WinInfo, Mod) -> + {value, ModInfo} = lists:keysearch(Mod, #moduleInfo.module, + WinInfo#winInfo.modules), + {Menu, MenuBtn} = ModInfo#moduleInfo.menubtn, + wxMenu:'Destroy'(Menu, MenuBtn), + ListBox = WinInfo#winInfo.listbox, + Id = wxListBox:findString(ListBox, atom_to_list(Mod)), + wxListBox:delete(ListBox,Id), + WinInfo#winInfo{modules=lists:keydelete(Mod, #moduleInfo.module, + WinInfo#winInfo.modules)}. + +%%-------------------------------------------------------------------- +%% add_process(WinInfo, Pid, Name, Function, Status, Info) -> WinInfo +%% WinInfo = #winInfo{} +%% Pid = pid() +%% Name = undefined | atom() +%% Function = {Mod, Func, Args} +%% Status = idle | running | break | exit +%% Info = {} | term() +%%-------------------------------------------------------------------- +add_process(WinInfo, Pid, Name, {Mod,Func,Args}, Status, Info) -> + Grid = WinInfo#winInfo.grid, + Row = (WinInfo#winInfo.row), + + Name2 = case Name of undefined -> ""; _ -> to_string(Name) end, + FuncS = to_string("~w:~w/~w", [Mod, Func, length(Args)]), + Info2 = case Info of {} -> ""; _ -> to_string(Info) end, + Pid2 = to_string("~p",[Pid]), + + Add = fun() -> + _Dbg = wxListCtrl:insertItem(Grid, Row,""), + %%wxListCtrl:setItemData(Grid,Temp,Row), + if (Row rem 2) =:= 0 -> + wxListCtrl:setItemBackgroundColour(Grid, Row, {240,240,255}); + true -> ignore + end, + + wxListCtrl:setItem(Grid, Row, 0, Pid2), + wxListCtrl:setItem(Grid, Row, 1, FuncS), + wxListCtrl:setItem(Grid, Row, 2, Name2), + wxListCtrl:setItem(Grid, Row, 3, to_string(Status)), + wxListCtrl:setItem(Grid, Row, 4, Info2), + ok + end, + wx:batch(Add), + + ProcInfo = #procInfo{pid=Pid, row=Row}, + WinInfo#winInfo{processes=[ProcInfo|WinInfo#winInfo.processes], + row=Row+1}. + +%%-------------------------------------------------------------------- +%% update_process(WinInfo, Pid, Status, Info) +%% WinInfo = #winInfo{} +%% Pid = pid() +%% Status = idle | running | break | exit +%% Info = {} | term() +%%-------------------------------------------------------------------- +update_process(WinInfo, Pid, Status, Info) -> + {value, ProcInfo} = lists:keysearch(Pid, #procInfo.pid, + WinInfo#winInfo.processes), + + Grid = WinInfo#winInfo.grid, + Row = ProcInfo#procInfo.row, + Info2 = case Info of {} -> ""; _ -> Info end, + wxListCtrl:setItem(Grid, Row, 3, to_string(Status)), + wxListCtrl:setItem(Grid, Row, 4, to_string(Info2)). + +%%-------------------------------------------------------------------- +%% clear_processes(WinInfo) -> WinInfo +%% WinInfo = #winInfo{} +%%-------------------------------------------------------------------- +clear_processes(WinInfo) -> + Grid = WinInfo#winInfo.grid, + Max = WinInfo#winInfo.row, + wx:batch(fun() -> clear_processes(Grid, Max-1) end), + WinInfo#winInfo{row=0, focus=0, processes=[]}. + +clear_processes(Grid, Row) when Row >= 0 -> + Item = wxListItem:new(), + wxListItem:setId(Item,Row), + wxListItem:setColumn(Item, 3), + case wxListCtrl:getItem(Grid, Item) of + true -> + case wxListItem:getText(Item) of + "exit" -> + wxListItem:setColumn(Item, 0), + wxListCtrl:getItem(Grid, Item), + Pid = list_to_pid(wxListItem:getText(Item)), + dbg_wx_winman:clear_process(dbg_wx_trace:title(Pid)); + _ -> + ok + end; + false -> + ignore + end, + wxListItem:destroy(Item), + wxListCtrl:deleteItem(Grid, Row), + clear_processes(Grid, Row-1); +clear_processes(_Grid, _Row) -> + done. + +%%-------------------------------------------------------------------- +%% add_break(WinInfo, Name, {Point, Options}) -> WinInfo +%% WinInfo = #winInfo{} +%% Name = atom() +%% Point = {Mod, Line} +%% Options = [Status, Action, Mods, Cond] +%% Status = active | inactive +%% Action = enable | disable | delete +%% Mods = null (not used) +%% Cond = null | {Mod, Func} +%%-------------------------------------------------------------------- +add_break(WinInfo, Menu, {Point, Options}) -> + Break = dbg_wx_win:add_break(WinInfo#winInfo.window, Menu, Point), + dbg_wx_win:update_break(Break, Options), + BreakInfo = #breakInfo{point=Point, break=Break}, + WinInfo#winInfo{breaks=[BreakInfo|WinInfo#winInfo.breaks]}. + +%%-------------------------------------------------------------------- +%% update_break(WinInfo, {Point, Options}) +%% WinInfo = #winInfo{} +%% Point = {Mod, Line} +%% Options = [Status, Action, Mods, Cond] +%% Status = active | inactive +%% Action = enable | disable | delete +%% Mods = null (not used) +%% Cond = null | {Mod, Func} +%%-------------------------------------------------------------------- +update_break(WinInfo, {Point, Options}) -> + {value, BreakInfo} = lists:keysearch(Point, #breakInfo.point, + WinInfo#winInfo.breaks), + dbg_wx_win:update_break(BreakInfo#breakInfo.break, Options). + +%%-------------------------------------------------------------------- +%% delete_break(WinInfo, Point) -> WinInfo +%% WinInfo = #winInfo{} +%% Point = {Mod, Line} +%%-------------------------------------------------------------------- +delete_break(WinInfo, Point) -> + {value, BreakInfo} = lists:keysearch(Point, #breakInfo.point, + WinInfo#winInfo.breaks), + dbg_wx_win:delete_break(BreakInfo#breakInfo.break), + WinInfo#winInfo{breaks=lists:keydelete(Point, #breakInfo.point, + WinInfo#winInfo.breaks)}. + +%%-------------------------------------------------------------------- +%% clear_breaks(WinInfo) -> WinInfo +%% clear_breaks(WinInfo, Mod) -> WinInfo +%% WinInfo = #winInfo{} +%%-------------------------------------------------------------------- +clear_breaks(WinInfo) -> + lists:foreach(fun(BreakInfo) -> + dbg_wx_win:delete_break(BreakInfo#breakInfo.break) + end, + WinInfo#winInfo.breaks), + WinInfo#winInfo{breaks=[]}. +clear_breaks(WinInfo, Mod) -> + Fun = + fun(BreakInfo) -> + case BreakInfo#breakInfo.point of + {Mod, _Line} -> + dbg_wx_win:delete_break(BreakInfo#breakInfo.break), + false; + _ -> true + end + end, + Breaks = lists:filter(Fun, WinInfo#winInfo.breaks), + WinInfo#winInfo{breaks=Breaks}. + +%%-------------------------------------------------------------------- +%% handle_event(WxEvent, WinInfo) -> Command +%% WxEvent = #wx{} +%% WinInfo = #winInfo{} +%% Command = ignore +%% | stopped +%% | {coords, {X,Y}} +%% +%% | {shortcut, Key} +%% | MenuItem | {Menu, [MenuItem]} +%% MenuItem = Menu = atom() +%% | {break, Point, What} +%% What = delete | {status, Status} | {trigger, Trigger} +%% | {module, Mod, What} +%% What = view | delete +%% +%% | {focus, Pid, WinInfo} +%% | default +%%-------------------------------------------------------------------- +%% Window events +handle_event(#wx{event=#wxSize{size={W,_}}}, #winInfo{grid=Grid}) -> + wx:batch(fun() -> + Tot = wx:foldl(fun(C,Sum) -> + Sum + wxListCtrl:getColumnWidth(Grid, C) + end, 0, [0,1,2,3]), + wxListCtrl:setColumnWidth(Grid, 4, W-Tot-4) + end), + ignore; +handle_event(_Ev=#wx{event=#wxClose{}}, _WinInfo) -> +%% io:format("~p Received ~p close ~p~n", [?MODULE, self(), _Ev]), + stopped; + +%% Menus and keyboard shortcuts +handle_event(#wx{userData={dbg_ui_winman, Win}, + event=#wxCommand{type=command_menu_selected}}, _Wi) -> + dbg_wx_winman:raise(Win), + ignore; +handle_event(_Ev = #wx{event=#wxKey{keyCode=Key, controlDown=true}}, _WinInfo) -> + if + Key/=?WXK_UP, Key/=?WXK_DOWN, Key /=? WXK_RETURN -> + try + {shortcut, list_to_atom([Key+($a-$A)])} + catch _:_ -> ignore + end; + true -> + ignore + end; + +handle_event(#wx{userData={break, Point, status}, + event=#wxCommand{type=command_menu_selected}}, + WinInfo) -> + {value, BreakInfo} = lists:keysearch(Point, #breakInfo.point, + WinInfo#winInfo.breaks), + %% This is a temporary hack !! + #breakInfo{break=#break{smi=Smi}} = BreakInfo, + + case wxMenuItem:getText(Smi) of + "Enable" -> {break, Point, {status, active}}; + "Disable" -> {break, Point, {status, inactive}} + end; + +%% Listbox +handle_event(#wx{event=#wxCommand{type=command_listbox_doubleclicked, cmdString=ModS}}, + _WinInfo) -> + {module, list_to_atom(ModS), view}; +handle_event(#wx{obj=ListBox, event=#wxMouse{type=right_down, x=X,y=Y}}, + #winInfo{listbox=ListBox}) -> + case wxListBox:hitTest(ListBox, {X,Y}) of + ?wxNOT_FOUND -> ignore; + Row -> + ModS = wxListBox:getString(ListBox,Row), + io:format("Re-loading/interpreting: ~s~n", [ModS]), + int:i(list_to_atom(ModS)), + ignore + end; + +%% Auto attach buttons +handle_event(#wx{event=#wxCommand{type=command_checkbox_clicked}}, + WinInfo) -> + Check = fun(Button, NamesAcc) -> + case wxCheckBox:isChecked(Button) of + true -> + Name = wxCheckBox:getLabel(Button), + [list_to_atom(Name)|NamesAcc]; + false -> + NamesAcc + end + end, + Names = wx:foldl(Check, [], + [WinInfo#winInfo.ebutton, + WinInfo#winInfo.bbutton, + WinInfo#winInfo.fbutton]), + {'Auto Attach', Names}; + +%% Process grid +handle_event(#wx{event=#wxList{type=command_list_item_selected, + itemIndex=Row}}, WinInfo) -> + #winInfo{processes=Pids} = WinInfo, + {value, #procInfo{pid=Pid}} = + lists:keysearch(Row, #procInfo.row, Pids), + {focus, Pid, WinInfo#winInfo{focus=Row}}; +handle_event(#wx{event=#wxList{type=command_list_item_activated}}, + _WinInfo) -> + default; +handle_event(#wx{event=#wxMouse{type=enter_window}}, #winInfo{grid=Grid}) -> + %% Keyboard focus + wxWindow:setFocus(Grid), + ignore; + +%% Menu Events +handle_event(#wx{userData=Data, + event=_Cmd=#wxCommand{type=command_menu_selected}}, + _WinInfo) -> + Data; +handle_event(_Event, _WinInfo) -> +%% io:format("Ev: ~p~n",[_Event]), + ignore. + +%%==================================================================== +%% Internal functions +%%==================================================================== + + |