<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15372] CalendarServer/trunk/calendarserver/tools/dashboard.py</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15372">15372</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-12-08 13:44:13 -0800 (Tue, 08 Dec 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Support quick ways to view groups of panels,.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkcalendarservertoolsdashboardpy">CalendarServer/trunk/calendarserver/tools/dashboard.py</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkcalendarservertoolsdashboardpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/tools/dashboard.py (15371 => 15372)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/tools/dashboard.py        2015-12-05 16:56:31 UTC (rev 15371)
+++ CalendarServer/trunk/calendarserver/tools/dashboard.py        2015-12-08 21:44:13 UTC (rev 15372)
</span><span class="lines">@@ -19,8 +19,7 @@
</span><span class="cx"> server as exposed by the L{DashboardProtocol} stats socket.
</span><span class="cx"> """
</span><span class="cx">
</span><del>-from getopt import getopt, GetoptError
-
</del><ins>+import argparse
</ins><span class="cx"> import curses.panel
</span><span class="cx"> import errno
</span><span class="cx"> import fcntl
</span><span class="lines">@@ -58,45 +57,26 @@
</span><span class="cx"> sys.exit(0)
</span><span class="cx">
</span><span class="cx">
</span><del>-BOX_WIDTH = 52
</del><span class="cx">
</span><del>-
</del><span class="cx"> def main():
</span><del>- try:
- (optargs, _ignore_args) = getopt(
- sys.argv[1:], "hs:t", [
- "help",
- ],
- )
- except GetoptError, e:
- usage(e)
</del><ins>+ parser = argparse.ArgumentParser(description="Dashboard service for CalendarServer.")
+ parser.add_argument("-t", action="store_false", help="text output, not curses")
+ parser.add_argument("-s", default="localhost:8100", help="server host (and optional port), or unix socket path prefixed by 'unix:'")
+ args = parser.parse_args()
</ins><span class="cx">
</span><span class="cx"> #
</span><span class="cx"> # Get configuration
</span><span class="cx"> #
</span><del>- useCurses = True
- server = ("localhost", 8100)
-
- for opt, arg in optargs:
- if opt in ("-h", "--help"):
- usage()
-
- elif opt in ("-t"):
- useCurses = False
-
- elif opt in ("-s"):
- if not arg.startswith("unix:"):
- server = arg.split(":")
- if len(server) == 1:
- server.append(8100)
- else:
- server[1] = int(server[1])
- server = tuple(server)
- else:
- server = arg
-
</del><ins>+ useCurses = args.t
+ if not args.s.startswith("unix:"):
+ server = args.s.split(":")
+ if len(server) == 1:
+ server.append(8100)
</ins><span class="cx"> else:
</span><del>- raise NotImplementedError(opt)
</del><ins>+ server[1] = int(server[1])
+ server = tuple(server)
+ else:
+ server = args.s
</ins><span class="cx">
</span><span class="cx"> if useCurses:
</span><span class="cx"> def _wrapped(stdscrn):
</span><span class="lines">@@ -142,6 +122,10 @@
</span><span class="cx">
</span><span class="cx"> screen = None
</span><span class="cx"> registered_windows = {}
</span><ins>+ registered_window_sets = {
+ "H": ("HTTP Panels", [],),
+ "J": ("Jobs Panels", [],),
+ }
</ins><span class="cx"> registered_order = []
</span><span class="cx">
</span><span class="cx"> def __init__(self, server, screen, usesCurses):
</span><span class="lines">@@ -166,6 +150,17 @@
</span><span class="cx"> cls.registered_order.append(keypress)
</span><span class="cx">
</span><span class="cx">
</span><ins>+ @classmethod
+ def registerWindowSet(cls, wtype, keypress):
+ """
+ Register a set of window types along with a key press action. This allows the
+ controller to select the appropriate set of windows when its key is pressed,
+ and also provides help information to the L{HelpWindow} for each
+ available window set type.
+ """
+ cls.registered_window_sets[keypress][1].append(wtype)
+
+
</ins><span class="cx"> def run(self):
</span><span class="cx"> """
</span><span class="cx"> Create the initial window and run the L{scheduler}.
</span><span class="lines">@@ -182,7 +177,7 @@
</span><span class="cx"> """
</span><span class="cx">
</span><span class="cx"> # Toggle a specific window on or off
</span><del>- if wtype is not None:
</del><ins>+ if isinstance(wtype, type):
</ins><span class="cx"> if wtype not in [type(w) for w in self.windows]:
</span><span class="cx"> self.windows.append(wtype(self.usesCurses, self.client).makeWindow())
</span><span class="cx"> self.windows[-1].activate()
</span><span class="lines">@@ -203,7 +198,11 @@
</span><span class="cx"> window.deactivate()
</span><span class="cx"> self.windows = []
</span><span class="cx"> top = 0
</span><del>- ordered_windows = [self.registered_windows[i] for i in self.registered_order]
</del><ins>+ if wtype is None:
+ # All windows in registered order
+ ordered_windows = [self.registered_windows[i] for i in self.registered_order]
+ else:
+ ordered_windows = list(wtype)
</ins><span class="cx"> for wtype in filter(lambda x: x.all, ordered_windows):
</span><span class="cx"> new_win = wtype(self.usesCurses, self.client).makeWindow(top=top)
</span><span class="cx"> logging.debug('created %r at panel level %r' % (new_win, new_win.z_order))
</span><span class="lines">@@ -292,6 +291,8 @@
</span><span class="cx"> self.displayWindow(self.registered_windows["h"])
</span><span class="cx"> elif c in self.registered_windows:
</span><span class="cx"> self.displayWindow(self.registered_windows[c])
</span><ins>+ elif c in self.registered_window_sets:
+ self.displayWindow(self.registered_window_sets[c][1])
</ins><span class="cx">
</span><span class="cx"> if not initialUpdate:
</span><span class="cx"> self.sched.enter(self.seconds, 0, self.updateDisplay, ())
</span><span class="lines">@@ -390,6 +391,10 @@
</span><span class="cx"> all = True
</span><span class="cx"> clientItem = None
</span><span class="cx">
</span><ins>+ windowTitle = ""
+ formatWidth = 0
+ additionalRows = 0
+
</ins><span class="cx"> def __init__(self, usesCurses, client):
</span><span class="cx"> self.usesCurses = usesCurses
</span><span class="cx"> self.client = client
</span><span class="lines">@@ -399,11 +404,25 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def makeWindow(self, top=0, left=0):
</span><ins>+ self.updateRowCount()
+ self._createWindow(
+ self.windowTitle,
+ self.rowCount + self.additionalRows,
+ self.formatWidth,
+ begin_y=top, begin_x=left
+ )
+ return self
+
+
+ def updateRowCount(self):
+ """
+ Update L{self.rowCount} based on the current data
+ """
</ins><span class="cx"> raise NotImplementedError()
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> def _createWindow(
</span><del>- self, title, nlines, ncols=BOX_WIDTH, begin_y=0, begin_x=0
</del><ins>+ self, title, nlines, ncols, begin_y=0, begin_x=0
</ins><span class="cx"> ):
</span><span class="cx"> """
</span><span class="cx"> Initialize a curses window based on the sizes required.
</span><span class="lines">@@ -482,7 +501,6 @@
</span><span class="cx"> help = "dashboard help"
</span><span class="cx"> all = False
</span><span class="cx"> helpItems = (
</span><del>- "",
</del><span class="cx"> "a - all windows",
</span><span class="cx"> "n - no windows",
</span><span class="cx"> " - (space) pause dashboard polling",
</span><span class="lines">@@ -491,19 +509,20 @@
</span><span class="cx"> "q - exit the dashboard",
</span><span class="cx"> )
</span><span class="cx">
</span><ins>+ windowTitle = "Help"
+ formatWidth = 48
+ additionalRows = 3
+
</ins><span class="cx"> def makeWindow(self, top=0, left=0):
</span><span class="cx"> term_w, _ignore_term_h = terminal_size()
</span><del>- help_x_offset = term_w - BOX_WIDTH + 4
- self._createWindow(
- "Help",
- len(self.helpItems) + len(Dashboard.registered_windows) + 2,
- ncols=BOX_WIDTH - 4,
- begin_y=0,
- begin_x=help_x_offset,
- )
- return self
</del><ins>+ help_x_offset = term_w - self.formatWidth
+ return super(HelpWindow, self).makeWindow(0, help_x_offset)
</ins><span class="cx">
</span><span class="cx">
</span><ins>+ def updateRowCount(self):
+ self.rowCount = len(self.helpItems) + len(filter(lambda x: len(x[1]) != 0, Dashboard.registered_window_sets.values())) + len(Dashboard.registered_windows)
+
+
</ins><span class="cx"> def requiresUpdate(self):
</span><span class="cx"> return False
</span><span class="cx">
</span><span class="lines">@@ -526,6 +545,13 @@
</span><span class="cx"> Dashboard.registered_windows.items(), key=lambda x: x[0]
</span><span class="cx"> ):
</span><span class="cx"> items.append("{} - {}".format(keypress, wtype.help))
</span><ins>+
+ items.append("")
+ for key, value in Dashboard.registered_window_sets.items():
+ description, panels = value
+ if panels:
+ items.append("{} - {}".format(key, description))
+
</ins><span class="cx"> items.extend(self.helpItems)
</span><span class="cx"> for item in items:
</span><span class="cx"> if self.usesCurses:
</span><span class="lines">@@ -549,15 +575,15 @@
</span><span class="cx">
</span><span class="cx"> help = "server jobs"
</span><span class="cx"> clientItem = "jobs"
</span><del>- FORMAT_WIDTH = 98
</del><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
- nlines = defaultIfNone(self.readItem("jobcount"), 0)
- self.rowCount = nlines
- self._createWindow("Jobs", self.rowCount + 6, ncols=self.FORMAT_WIDTH, begin_y=top, begin_x=left)
- return self
</del><ins>+ windowTitle = "Jobs"
+ formatWidth = 98
+ additionalRows = 6
</ins><span class="cx">
</span><ins>+ def updateRowCount(self):
+ self.rowCount = defaultIfNone(self.readItem("jobcount"), 0)
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> def update(self):
</span><span class="cx"> records = defaultIfNone(self.clientData(), {})
</span><span class="cx"> if len(records) != self.rowCount:
</span><span class="lines">@@ -640,7 +666,7 @@
</span><span class="cx"> safeDivision(total_time, total_completed, 1000.0)
</span><span class="cx"> )
</span><span class="cx"> if self.usesCurses:
</span><del>- self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
</del><ins>+ self.window.hline(y, x, "-", self.formatWidth - 2)
</ins><span class="cx"> y += 1
</span><span class="cx"> self.window.addstr(y, x, s)
</span><span class="cx"> else:
</span><span class="lines">@@ -662,18 +688,15 @@
</span><span class="cx">
</span><span class="cx"> help = "server child job assignments"
</span><span class="cx"> clientItem = "job_assignments"
</span><del>- FORMAT_WIDTH = 40
</del><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
- slots = defaultIfNone(self.readItem(self.clientItem), {"workers": ()})["workers"]
- self.rowCount = len(slots)
- self._createWindow(
- "Job Assignments", self.rowCount + 5, self.FORMAT_WIDTH,
- begin_y=top, begin_x=left
- )
- return self
</del><ins>+ windowTitle = "Job Assignments"
+ formatWidth = 40
+ additionalRows = 5
</ins><span class="cx">
</span><ins>+ def updateRowCount(self):
+ self.rowCount = len(defaultIfNone(self.readItem(self.clientItem), {"workers": ()})["workers"])
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> def update(self):
</span><span class="cx"> data = defaultIfNone(self.clientData(), {"workers": {}, "level": 0})
</span><span class="cx"> records = data["workers"]
</span><span class="lines">@@ -736,7 +759,7 @@
</span><span class="cx"> total_completed,
</span><span class="cx"> )
</span><span class="cx"> if self.usesCurses:
</span><del>- self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
</del><ins>+ self.window.hline(y, x, "-", self.formatWidth - 2)
</ins><span class="cx"> y += 1
</span><span class="cx"> self.window.addstr(y, x, s)
</span><span class="cx"> else:
</span><span class="lines">@@ -758,18 +781,15 @@
</span><span class="cx">
</span><span class="cx"> help = "server child slots"
</span><span class="cx"> clientItem = "slots"
</span><del>- FORMAT_WIDTH = 72
</del><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
- slots = defaultIfNone(self.readItem(self.clientItem), {"slots": ()})["slots"]
- self.rowCount = len(slots)
- self._createWindow(
- "HTTP Slots", self.rowCount + 5, self.FORMAT_WIDTH,
- begin_y=top, begin_x=left
- )
- return self
</del><ins>+ windowTitle = "HTTP Slots"
+ formatWidth = 72
+ additionalRows = 5
</ins><span class="cx">
</span><ins>+ def updateRowCount(self):
+ self.rowCount = len(defaultIfNone(self.readItem(self.clientItem), {"slots": ()})["slots"])
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> def update(self):
</span><span class="cx"> data = defaultIfNone(self.clientData(), {"slots": {}, "overloaded": False})
</span><span class="cx"> records = data["slots"]
</span><span class="lines">@@ -840,7 +860,7 @@
</span><span class="cx"> sum([record["total"] for record in records]),
</span><span class="cx"> )
</span><span class="cx"> if self.usesCurses:
</span><del>- self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
</del><ins>+ self.window.hline(y, x, "-", self.formatWidth - 2)
</ins><span class="cx"> y += 1
</span><span class="cx"> self.window.addstr(y, x, s)
</span><span class="cx"> x += len(s) + 4
</span><span class="lines">@@ -871,13 +891,14 @@
</span><span class="cx"> help = "system details"
</span><span class="cx"> clientItem = "stats_system"
</span><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
- slots = defaultIfNone(self.readItem(self.clientItem), (1, 2, 3, 4,))
- self.rowCount = len(slots)
- self._createWindow("System", self.rowCount + 3, begin_y=top, begin_x=left)
- return self
</del><ins>+ windowTitle = "System"
+ formatWidth = 52
+ additionalRows = 3
</ins><span class="cx">
</span><ins>+ def updateRowCount(self):
+ self.rowCount = len(defaultIfNone(self.readItem(self.clientItem), (1, 2, 3, 4,)))
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> def update(self):
</span><span class="cx"> records = defaultIfNone(self.clientData(), {
</span><span class="cx"> "cpu use": 0.0,
</span><span class="lines">@@ -952,13 +973,15 @@
</span><span class="cx">
</span><span class="cx"> help = "server request stats"
</span><span class="cx"> clientItem = "stats"
</span><del>- FORMAT_WIDTH = 84
</del><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
- self._createWindow("Request Statistics", 8, self.FORMAT_WIDTH, begin_y=top, begin_x=left)
- return self
</del><ins>+ windowTitle = "Request Statistics"
+ formatWidth = 84
+ additionalRows = 4
</ins><span class="cx">
</span><ins>+ def updateRowCount(self):
+ self.rowCount = 4
</ins><span class="cx">
</span><ins>+
</ins><span class="cx"> def update(self):
</span><span class="cx"> records = defaultIfNone(self.clientData(), {})
</span><span class="cx"> self.iter += 1
</span><span class="lines">@@ -1031,18 +1054,19 @@
</span><span class="cx">
</span><span class="cx"> help = "server methods"
</span><span class="cx"> clientItem = "stats"
</span><del>- FORMAT_WIDTH = 116
</del><span class="cx"> stats_keys = ("current", "1m", "5m", "1h",)
</span><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
</del><ins>+ windowTitle = "Methods"
+ formatWidth = 116
+ additionalRows = 7
+
+ def updateRowCount(self):
</ins><span class="cx"> stats = defaultIfNone(self.clientData(), {})
</span><span class="cx"> methods = set()
</span><span class="cx"> for key in self.stats_keys:
</span><span class="cx"> methods.update(stats.get(key, {}).get("method", {}).keys())
</span><span class="cx"> nlines = len(methods)
</span><span class="cx"> self.rowCount = nlines
</span><del>- self._createWindow("Methods", self.rowCount + 7, ncols=self.FORMAT_WIDTH, begin_y=top, begin_x=left)
- return self
</del><span class="cx">
</span><span class="cx">
</span><span class="cx"> def update(self):
</span><span class="lines">@@ -1128,7 +1152,7 @@
</span><span class="cx"> *items
</span><span class="cx"> )
</span><span class="cx"> if self.usesCurses:
</span><del>- self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
</del><ins>+ self.window.hline(y, x, "-", self.formatWidth - 2)
</ins><span class="cx"> y += 1
</span><span class="cx"> self.window.addstr(y, x, s1)
</span><span class="cx"> y += 1
</span><span class="lines">@@ -1153,17 +1177,13 @@
</span><span class="cx">
</span><span class="cx"> help = "directory service stats"
</span><span class="cx"> clientItem = "directory"
</span><del>- FORMAT_WIDTH = 89
</del><span class="cx">
</span><ins>+ windowTitle = "Directory Service"
+ formatWidth = 89
+ additionalRows = 8
</ins><span class="cx">
</span><del>- def makeWindow(self, top=0, left=0):
- nlines = len(defaultIfNone(self.readItem("directory"), {}))
- self.rowCount = nlines
- self._createWindow(
- "Directory Service", self.rowCount + 8, ncols=self.FORMAT_WIDTH,
- begin_y=top, begin_x=left
- )
- return self
</del><ins>+ def updateRowCount(self):
+ self.rowCount = len(defaultIfNone(self.readItem("directory"), {}))
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx"> def update(self):
</span><span class="lines">@@ -1250,7 +1270,7 @@
</span><span class="cx"> "",
</span><span class="cx"> )
</span><span class="cx"> if self.usesCurses:
</span><del>- self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
</del><ins>+ self.window.hline(y, x, "-", self.formatWidth - 2)
</ins><span class="cx"> y += 1
</span><span class="cx"> self.window.addstr(y, x, s)
</span><span class="cx"> self.window.addstr(y + 1, x, s_cached)
</span><span class="lines">@@ -1269,13 +1289,21 @@
</span><span class="cx">
</span><span class="cx"> Dashboard.registerWindow(HelpWindow, "h")
</span><span class="cx"> Dashboard.registerWindow(SystemWindow, "s")
</span><del>-Dashboard.registerWindow(AssignmentsWindow, "w")
</del><span class="cx"> Dashboard.registerWindow(RequestStatsWindow, "r")
</span><ins>+Dashboard.registerWindow(HTTPSlotsWindow, "c")
</ins><span class="cx"> Dashboard.registerWindow(MethodsWindow, "m")
</span><ins>+Dashboard.registerWindow(AssignmentsWindow, "w")
</ins><span class="cx"> Dashboard.registerWindow(JobsWindow, "j")
</span><del>-Dashboard.registerWindow(HTTPSlotsWindow, "c")
</del><span class="cx"> Dashboard.registerWindow(DirectoryStatsWindow, "d")
</span><span class="cx">
</span><ins>+Dashboard.registerWindowSet(SystemWindow, "H")
+Dashboard.registerWindowSet(RequestStatsWindow, "H")
+Dashboard.registerWindowSet(HTTPSlotsWindow, "H")
+Dashboard.registerWindowSet(MethodsWindow, "H")
</ins><span class="cx">
</span><ins>+Dashboard.registerWindowSet(SystemWindow, "J")
+Dashboard.registerWindowSet(AssignmentsWindow, "J")
+Dashboard.registerWindowSet(JobsWindow, "J")
+
</ins><span class="cx"> if __name__ == "__main__":
</span><span class="cx"> main()
</span></span></pre>
</div>
</div>
</body>
</html>