* src/web/ejabberd_web_admin.erl: Images now specified via CSS,

design slightly updated, added last activity statistics (thanks to
Sergei Golovan)

SVN Revision: 344
This commit is contained in:
Alexey Shchepin 2005-05-08 23:39:46 +00:00
parent 4eca697b2d
commit 4f7359298e
2 changed files with 333 additions and 260 deletions

View File

@ -1,3 +1,9 @@
2005-05-09 Alexey Shchepin <alexey@sevcom.net>
* src/web/ejabberd_web_admin.erl: Images now specified via CSS,
design slightly updated, added last activity statistics (thanks to
Sergei Golovan)
2005-05-07 Alexey Shchepin <alexey@sevcom.net> 2005-05-07 Alexey Shchepin <alexey@sevcom.net>
* src/stringprep/stringprep_drv.c: Added check for bidi * src/stringprep/stringprep_drv.c: Added check for bidi

View File

@ -64,154 +64,117 @@ make_xhtml(Els, Lang) ->
{"type", "text/css"}, {"type", "text/css"},
{"rel", "stylesheet"}], []}]}, {"rel", "stylesheet"}], []}]},
?XE("body", ?XE("body",
[?XAE("table", [?XAE("div",
[{"id", "main"}], [{"id", "container"}],
[?XE("tbody", [?XAE("div",
[?XAE("tr", [{"id", "header"}],
[{"id", "top"}], [?XE("h1",
[?XE("td", [?ACT("/admin/", "ejabberd administration")]
[?XE("table", )]),
[?XE("tbody", ?XAE("div",
[?XE("tr", [{"id", "navigation"}],
[?XE("td", [?XE("ul",
[?XAE("a", [{"href", "/admin/"}], [?LI([?ACT("/admin/acls/", "Access Control Lists")]),
[?XA("img", [{"src", "/admin/logo.png"}, ?LI([?ACT("/admin/access/", "Access Rules")]),
{"width", "343"}, ?LI([?ACT("/admin/users/", "Users")]),
{"height", "55"}, ?LI([?ACT("/admin/online-users/", "Online Users")]),
{"alt", "ejabberd"}, ?LI([?ACT("/admin/last-activity/", "Last Activity")]),
{"border", "0"}])])]), ?LI([?ACT("/admin/nodes/", "Nodes")]),
?XAE("td", [{"width", "100%"}, ?LI([?ACT("/admin/stats/", "Statistics")])
{"background", "/admin/logo-fill.png"}], ] ++
[?XAE("a", [{"href", "/admin/"}], case lists:member(mod_shared_roster,
[?XA("img", [{"src", "/admin/1x1tr.gif"}, gen_mod:loaded_modules()) of
{"width", "100%"}, true ->
{"height", "55"}, [?LI([?ACT("/admin/shared-roster/", "Shared Roster")])];
{"alt", ""}, false ->
{"border", "0"}])])] []
)])]) end
])])]), )]),
?XAE("tr", ?XAE("div",
[{"id", "middle"}], [{"id", "content"}],
[?XE("td", Els),
[?XAE("table", ?XAE("div",
[{"id", "middle-table"}], [{"id", "clearcopyright"}],
[?XE("tbody", [{xmlcdata, ""}])]),
[?XE("tr", ?XAE("div",
[?XAE("td", [{"id", "copyrightouter"}],
[{"id", "middle-td1"}], [?XAE("div",
[?XAE("ul", [{"id", "copyright"}],
[{"id", "navlist"}], [?XCT("p",
[?LI([?ACT("/admin/acls/", "Access Control Lists")]), "ejabberd (c) 2002-2005 Alexey Shchepin, 2004-2005 Process One")
?LI([?ACT("/admin/access/", "Access Rules")]), ])])])
?LI([?ACT("/admin/users/", "Users")]),
?LI([?ACT("/admin/online-users/", "Online Users")]),
?LI([?ACT("/admin/nodes/", "Nodes")]),
?LI([?ACT("/admin/stats/", "Statistics")])
] ++
case lists:member(mod_shared_roster,
gen_mod:loaded_modules()) of
true ->
[?LI([?ACT("/admin/shared-roster/", "Shared Roster")])];
false ->
[]
end
)]),
?XAE("td",
[{"id", "middle-td2"}],
[?XAE("div", [{"id", "content"}], Els)])])])
])])]),
?XAE("tr",
[{"id", "bottom"}],
[?XE("td",
[?XE("table",
[?XE("tbody",
[?XE("tr",
[?XCT("td",
"ejabberd (c) 2002-2005 Alexey Shchepin, 2004-2005 Process One")
])])
])])])])])])
]}}. ]}}.
css() -> " css() -> "
body { html,body {
background: white;
margin: 0;
padding: 0;
height: 100%;
}
#container {
padding: 0;
margin: 0;
min-height: 100%;
height: 100%;
margin-bottom: -30px;
}
html>body #container {
height: auto;
}
#header h1 {
width: 100%;
height: 55px;
padding: 0;
margin: 0;
background: transparent url(\"/admin/logo-fill.png\");
}
#header h1 a {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 55px;
padding: 0;
margin: 0;
background: transparent url(\"/admin/logo.png\") no-repeat;
display: block;
text-indent: -700em;
}
#clearcopyright {
display: block;
width: 100%;
height: 30px;
}
#copyrightouter {
display: table;
width: 100%;
height: 30px;
}
#copyright {
display: table-cell;
vertical-align: bottom;
width: 100%;
height: 30px;
}
#copyright p {
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
margin-top: 0; margin-top: 5px;
margin-bottom: 0; margin-bottom: 0;
} padding-left: 0;
padding-right: 0;
#main { padding-top: 1px;
border: none; padding-bottom: 1px;
border-spacing: 0;
border-collapse: collapse;
background-color: #fe8a00;
width: 100%; width: 100%;
height: 100%;
padding: 0;
}
#main > tbody > tr > td {
padding: 0;
}
#top > td > table {
border: none;
border-spacing: 0;
border-collapse: collapse;
background-color: #fe8a00;
width: 100%;
padding-top: 2px;
}
#top table {
border: none;
border-spacing: 0;
border-collapse: collapse;
background-color: #fe8a00;
width: 100%;
padding-top: 2px;
}
#top td {
padding: 0;
}
#top img {
margin-bottom: 0px;
}
#middle {
height: 100%;
}
#middle-table {
border: none;
border-spacing: 0;
border-collapse: collapse;
width: 100%;
height: 100%;
empty-cells: show;
}
#middle-td1, #middle-td2 {
padding: 0;
background-color: #ffffff;
vertical-align: top;
}
#middle-td2 {
width: 100%;
}
#bottom table {
border: none;
border-spacing: 0;
border-collapse: collapse;
width: 100%;
}
#bottom table td {
padding: 0;
color: #ffffff; color: #ffffff;
background-color: #fe8a00; background-color: #fe8a00;
font-family: Verdana, Arial, Helvetica, sans-serif; font-family: Verdana, Arial, Helvetica, sans-serif;
@ -220,86 +183,76 @@ body {
text-align: center; text-align: center;
} }
/*td{ #navigation ul {
font-size: 3pt; position: absolute;
} top: 55px;
td.a{ left: 0;
color: #fc8800; padding: 0 1px 1px;
background-color: #fe8a00; margin: 0;
} font-family: Verdana, Arial, Helvetica, sans-serif;
td.b{ font-size: 7.5pt;
color: #333333; font-weight: bold;
background-color: #000000; background: #d47911;
} width: 13em;
td.c{ }
color: #743300;
background-color: #723100;
}
td.d{
color: #fdc58a;
background-color: #ffc78c;
}
td.e{
color: #fde1c7;
background-color: #ffe3c9;
}
td.f{
color: #fdfdfd;
background-color: #ffffff;
}*/
td.copy{
color: #ffffff;
background-color: #fe8a00;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 7pt;
font-weight: bold;
text-align: center;
}
#navlist #navigation ul li {
{ list-style: none;
padding: 0 1px 1px; margin: 0;
margin-left: 0; text-align: left;
font: bold 10px Verdana, sans-serif; display: inline;
background: #d47911; }
width: 13em;
}
#navlist li #navigation ul li a {
{ margin: 0;
list-style: none; display: block;
margin: 0; padding: 0.25em 0.5em 0.25em 0.75em;
text-align: left; border-left: 1em solid #ffc78c;
display: inline; border-top: 1px solid gray;
} background: #ffe3c9;
text-decoration: none;
}
#navlist li a #navigation ul li a:link {
{ color: #844;
display: block; }
padding: 0.25em 0.5em 0.25em 0.75em;
border-left: 1em solid #ffc78c;
border-top: 1px solid gray;
background: #ffe3c9;
text-decoration: none;
}
#navlist li a:link { color: #844; } #navigation ul li a:visited {
#navlist li a:visited { color: #766; } color: #766;
}
#navlist li a:hover #navigation ul li a:hover {
{ border-color: #fc8800;
border-color: #fc8800; color: #FFF;
color: #FFF; background: #332;
background: #332; }
}
#lastactivity li {
font-weight: bold;
border: 1px solid #d6760e;
background-color: #fff2e8;
padding: 2px;
margin-bottom: -1px;
}
td.copy {
color: #ffffff;
background-color: #fe8a00;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 7pt;
font-weight: bold;
text-align: center;
}
input { input {
border: 1px solid #d6760e; font-family: Verdana, Arial, Helvetica, sans-serif;
color: #723202; font-size: 10pt;
background-color: #fff2e8; border: 1px solid #d6760e;
vertical-align: middle; color: #723202;
margin-bottom: 0px; background-color: #fff2e8;
padding: 0.1em; vertical-align: middle;
margin-bottom: 0px;
padding: 0.1em;
} }
input[type=submit] { input[type=submit] {
@ -312,24 +265,24 @@ input[type=submit] {
} }
textarea { textarea {
border: 1px solid #d6760e; font-family: Verdana, Arial, Helvetica, sans-serif;
color: #723202; font-size: 10pt;
background-color: #fff2e8; border: 1px solid #d6760e;
vertical-align: middle; color: #723202;
margin-top: 7px; background-color: #fff2e8;
/*margin-left: 7px; vertical-align: middle;
margin-right: 7px;*/ margin-top: 7px;
margin-bottom: 5px; margin-bottom: 5px;
padding: 0.1em; padding: 0.1em;
} }
select { select {
border: 1px solid #d6760e; border: 1px solid #d6760e;
color: #723202; color: #723202;
background-color: #fff2e8; background-color: #fff2e8;
vertical-align: middle; vertical-align: middle;
margin-bottom: 0px; margin-bottom: 0px;
padding: 0.1em; padding: 0.1em;
} }
thead { thead {
@ -412,7 +365,6 @@ h1 {
font-size: 14pt; font-size: 14pt;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
padding-left: 5px;
padding-top: 2px; padding-top: 2px;
padding-bottom: 2px; padding-bottom: 2px;
margin-top: 0px; margin-top: 0px;
@ -425,7 +377,6 @@ h2 {
font-size: 12pt; font-size: 12pt;
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
padding-left: 5px;
padding-top: 2px; padding-top: 2px;
padding-bottom: 2px; padding-bottom: 2px;
margin-top: 0px; margin-top: 0px;
@ -438,7 +389,6 @@ h3 {
font-size: 10pt; font-size: 10pt;
font-weight: bold; font-weight: bold;
text-align: left; text-align: left;
padding-left: 5px;
padding-top: 20px; padding-top: 20px;
padding-bottom: 2px; padding-bottom: 2px;
margin-top: 0px; margin-top: 0px;
@ -446,21 +396,21 @@ h3 {
} }
#content a:link { #content a:link {
color: #444466; color: #990000;
font-family: Verdana, Arial, Helvetica, sans-serif; font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10pt; font-size: 10pt;
font-weight: bold; font-weight: bold;
text-decoration: underlined; text-decoration: underlined;
} }
#content a:visited { #content a:visited {
color: #444466; color: #990000;
font-family: Verdana, Arial, Helvetica, sans-serif; font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10pt; font-size: 10pt;
font-weight: bold; font-weight: bold;
text-decoration: underlined; text-decoration: underlined;
} }
#content a:hover { #content a:hover {
color: #222266; color: #cc6600;
font-family: Verdana, Arial, Helvetica, sans-serif; font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 10pt; font-size: 10pt;
font-weight: bold; font-weight: bold;
@ -468,7 +418,7 @@ h3 {
} }
#content li { #content ul li {
list-style-type: dot; list-style-type: dot;
font-size: 10pt; font-size: 10pt;
/*font-size: 7pt;*/ /*font-size: 7pt;*/
@ -479,9 +429,11 @@ h3 {
font-size: 10pt; font-size: 10pt;
} }
div#content { #content {
margin-left: 10px; font-family: Verdana, Arial, Helvetica, sans-serif;
margin-top: 5px; font-size: 10pt;
padding-left: 13em;
padding-top: 5px;
} }
*.alignright { *.alignright {
@ -492,15 +444,27 @@ div#content {
logo() -> logo() ->
jlib:decode_base64( jlib:decode_base64(
"iVBORw0KGgoAAAANSUhEUgAAAVcAAAA3CAMAAACPbPnEAAAAYFBMVEX///8CAgJyMgL+vm7Wdg7+igL+/v7+slb+qkb+4sr+ojP+nir+lhr+1qb+khL+wnb+wn7+zpb+jgb+yoz+xo7+tmL+pj7+mib+jg7+5sb+rlL+rkr+mh7+tl7+2q7+umpJ0uikAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfUBAUJBhWzc9qJAAABQ0lEQVR42u2bXU/CQBBFUUZFURAU5Ev4//+S3Ow+tFl3s6adtE3Oebghzc4DJ/Nw04WZgQczexJkz4lXvOKVxKuXV6APTCFXAq94xSte8ermFYbrA6+ilemZRxGz+fxBxMydL0/Vz5anvkUrPfb1IPCKV7ziFa9uXsG/DzyLPz7ndjS3tc3tSbcwPdl9tmYq3dHmk9x3r8mtiM11KfCKV7ziFa9uXmEc7wf+u6+5TtlXf62fKu9rl3wX9ibsLPCKV7ziFa9uXmF87wf67aBT6a+hp4bOehFxU0/CbgKveMUrXvHq5hXG+vuBcpss75zH/VZ5X7vcb4W7q5A/wvbCXoTNhX0JvOIVr3jFq5tX4P8Fw2V6g7UQ9itsLeKmfgi84hWveMWrm1egDwyX6Q3WTtinsI2wq7CjwCte8YpXvLp5BQ/utIiGbwh9RAEAAAAASUVORK5CYII="). "iVBORw0KGgoAAAANSUhEUgAAAVcAAAA3CAMAAACPbPnEAAAAYFBMVEX///8C"
"AgJyMgL+vm7Wdg7+igL+/v7+slb+qkb+4sr+ojP+nir+lhr+1qb+khL+wnb+"
"wn7+zpb+jgb+yoz+xo7+tmL+pj7+mib+jg7+5sb+rlL+rkr+mh7+tl7+2q7+"
"umpJ0uikAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA"
"AAsSAdLdfvwAAAAHdElNRQfUBAUJBhWzc9qJAAABQ0lEQVR42u2bXU/CQBBF"
"UUZFURAU5Ev4//+S3Ow+tFl3s6adtE3Oebghzc4DJ/Nw04WZgQczexJkz4lX"
"vOKVxKuXV6APTCFXAq94xSte8ermFYbrA6+ilemZRxGz+fxBxMydL0/Vz5an"
"vkUrPfb1IPCKV7ziFa9uXsG/DzyLPz7ndjS3tc3tSbcwPdl9tmYq3dHmk9x3"
"r8mtiM11KfCKV7ziFa9uXmEc7wf+u6+5TtlXf62fKu9rl3wX9ibsLPCKV7zi"
"Fa9uXmF87wf67aBT6a+hp4bOehFxU0/CbgKveMUrXvHq5hXG+vuBcpss75zH"
"/VZ5X7vcb4W7q5A/wvbCXoTNhX0JvOIVr3jFq5tX4P8Fw2V6g7UQ9itsLeKm"
"fgi84hWveMWrm1egDwyX6Q3WTtinsI2wq7CjwCte8YpXvLp5BQ/utIiGbwh9"
"RAEAAAAASUVORK5CYII=").
logo_fill() -> logo_fill() ->
jlib:decode_base64( jlib:decode_base64(
"iVBORw0KGgoAAAANSUhEUgAAAAYAAAA3BAMAAADdxCZzAAAAIVBMVEX////Wdg7+igL+khL+jg7+nir+rkr+umr+yoz+1qb+5sYp3v/aAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfUBAYHDzOol2bZAAAASElEQVR42mMQFBRkUFJSxMAgcWNjQwwMEndxccTAIPHQ0EAMDBJPS0vEwCDx8vJCDAwS7+hoxMAg8ZkzJ2JgkPiqVQsxMFAcABvNNugXg2QkAAAAAElFTkSuQmCC"). "iVBORw0KGgoAAAANSUhEUgAAAAYAAAA3BAMAAADdxCZzAAAAHlBMVEXWdg7+"
"igL+jg7+khL+nir+rkr+umr+yoz+1qb+5sbOf9L8AAAACXBIWXMAAA9hAAAP"
empty() -> "YQGoP6dpAAAAQUlEQVQI12XDSxHAIBAFQT6BJEcsYAELWMACFtYCFnAL7zxd"
jlib:decode_base64( "1c5dvhSU2BpKqBXl6R0ljYGS50R5zVC+tVD+vfE6YyUexE9x7g4AAAAASUVO"
"R0lGODlhAQABAIAAAP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgABACwAAAAAAQABAAACAkwBADs="). "RK5CYII=").
process_admin(#request{us = US, process_admin(#request{us = US,
path = [], path = [],
@ -508,19 +472,20 @@ process_admin(#request{us = US,
lang = Lang} = Request) -> lang = Lang} = Request) ->
make_xhtml([?XCT("h1", "ejabberd administration"), make_xhtml([?XCT("h1", "ejabberd administration"),
?XE("ul", ?XE("ul",
[?LI([?ACT("acls/", "Access Control Lists"), ?C(" "), [?LI([?ACT("/admin/acls/", "Access Control Lists"), ?C(" "),
?ACT("acls-raw/", "(raw)")]), ?ACT("/admin/acls-raw/", "(raw)")]),
?LI([?ACT("access/", "Access Rules"), ?C(" "), ?LI([?ACT("/admin/access/", "Access Rules"), ?C(" "),
?ACT("access-raw/", "(raw)")]), ?ACT("/admin/access-raw/", "(raw)")]),
?LI([?ACT("users/", "Users")]), ?LI([?ACT("/admin/users/", "Users")]),
?LI([?ACT("online-users/", "Online Users")]), ?LI([?ACT("/admin/online-users/", "Online Users")]),
?LI([?ACT("nodes/", "Nodes")]), ?LI([?ACT("/admin/last-activity/", "Last Activity")]),
?LI([?ACT("stats/", "Statistics")]) ?LI([?ACT("/admin/nodes/", "Nodes")]),
?LI([?ACT("/admin/stats/", "Statistics")])
] ++ ] ++
case lists:member(mod_shared_roster, case lists:member(mod_shared_roster,
gen_mod:loaded_modules()) of gen_mod:loaded_modules()) of
true -> true ->
[?LI([?ACT("shared-roster/", "Shared Roster")])]; [?LI([?ACT("/admin/shared-roster/", "Shared Roster")])];
false -> false ->
[] []
end end
@ -545,12 +510,6 @@ process_admin(#request{us = US,
lang = Lang} = Request) -> lang = Lang} = Request) ->
{200, [{"Content-Type", "image/png"}], logo_fill()}; {200, [{"Content-Type", "image/png"}], logo_fill()};
process_admin(#request{us = US,
path = ["1x1tr.gif"],
q = Query,
lang = Lang} = Request) ->
{200, [{"Content-Type", "image/gif"}], empty()};
process_admin(#request{us = US, process_admin(#request{us = US,
path = ["acls-raw"], path = ["acls-raw"],
q = Query, q = Query,
@ -798,6 +757,46 @@ process_admin(#request{us = US,
Res = list_online_users(Lang), Res = list_online_users(Lang),
make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang); make_xhtml([?XCT("h1", "ejabberd users")] ++ Res, Lang);
process_admin(#request{method = Method,
us = US,
path = ["last-activity"],
q = Query,
lang = Lang} = Request) ->
?INFO_MSG("query: ~p", [Query]),
Month = case lists:keysearch("period", 1, Query) of
{value, {_, Val}} ->
Val;
_ ->
"month"
end,
Res = case lists:keysearch("ordinary", 1, Query) of
{value, {_, _}} ->
list_last_activity(Lang, false, Month);
_ ->
list_last_activity(Lang, true, Month)
end,
make_xhtml([?XCT("h1", "Users last activity")] ++
[?XAE("form", [{"method", "post"}],
[?CT("Period: "),
?XAE("select", [{"name", "period"}],
lists:map(
fun({O, V}) ->
Sel = if
O == Month -> [{"selected", "selected"}];
true -> []
end,
?XAC("option",
Sel ++ [{"value", O}], V)
end, [{"month", ?T("Last month")},
{"year", ?T("Last year")},
{"all", ?T("All activity")}])),
?C(" "),
?INPUTT("submit", "ordinary", "Show Ordinary Table"),
?C(" "),
?INPUTT("submit", "integral", "Show Integral Table")
])] ++
Res, Lang);
process_admin(#request{us = US, process_admin(#request{us = US,
path = ["stats"], path = ["stats"],
q = Query, q = Query,
@ -1557,6 +1556,74 @@ user_roster_item_parse_query(User, Server, Items, Query) ->
nothing. nothing.
list_last_activity(_Lang, Integral, Period) ->
{MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp = MegaSecs * 1000000 + Secs,
case Period of
"all" ->
TS = 0,
Days = infinity;
"year" ->
TS = TimeStamp - 366 * 86400,
Days = 366;
_ ->
TS = TimeStamp - 31 * 86400,
Days = 31
end,
case catch mnesia:dirty_select(
last_activity, [{{last_activity, '_', '$1', '_'},
[{'>', '$1', TS}],
[{'trunc', {'/',
{'-', TimeStamp, '$1'},
86400}}]}]) of
{'EXIT', _Reason} ->
[];
Vals ->
Hist = histogram(Vals, Integral),
Left = case Days of
infinity ->
0;
_ ->
Days - length(Hist)
end,
Tail = case Integral andalso Hist /= [] of
true ->
lists:duplicate(Left, lists:last(Hist));
_ ->
lists:duplicate(Left, 0)
end,
Max = lists:max(Hist),
[?XAE("ol",
[{"id", "lastactivity"}, {"start", "0"}],
[?XAE("li",
[{"style", "width:" ++ integer_to_list(
trunc(90 * V / Max)) ++ "%;"}],
[{xmlcdata, integer_to_list(V)}])
|| V <- Hist ++ Tail])]
end.
histogram(Values, Integral) ->
histogram(lists:sort(Values), Integral, 0, 0, []).
histogram([H | T], Integral, Current, Count, Hist) when Current == H ->
histogram(T, Integral, Current, Count + 1, Hist);
histogram([H | _] = Values, Integral, Current, Count, Hist) when Current < H ->
if
Integral ->
histogram(Values, Integral, Current + 1, Count, [Count | Hist]);
true ->
histogram(Values, Integral, Current + 1, 0, [Count | Hist])
end;
histogram([], _Integral, _Current, Count, Hist) ->
if
Count > 0 ->
lists:reverse([Count | Hist]);
true ->
lists:reverse(Hist)
end.
get_nodes(Lang) -> get_nodes(Lang) ->
RunningNodes = mnesia:system_info(running_db_nodes), RunningNodes = mnesia:system_info(running_db_nodes),