#!/usr/bin/python2

# Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
# 
# This file is part of MooseFS.
# 
# MooseFS is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 2 (only).
# 
# MooseFS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with MooseFS; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
# or visit http://www.gnu.org/licenses/gpl-2.0.html

PROTO_BASE = 0

#some constants from MFSCommunication.h
CLTOMA_CSERV_LIST = (PROTO_BASE+500)
MATOCL_CSERV_LIST = (PROTO_BASE+501)
CLTOCS_HDD_LIST_V1 = (PROTO_BASE+502)
CSTOCL_HDD_LIST_V1 = (PROTO_BASE+503)
CLTOMA_SESSION_LIST = (PROTO_BASE+508)
MATOCL_SESSION_LIST = (PROTO_BASE+509)
CLTOMA_INFO = (PROTO_BASE+510)
MATOCL_INFO = (PROTO_BASE+511)
CLTOMA_FSTEST_INFO = (PROTO_BASE+512)
MATOCL_FSTEST_INFO = (PROTO_BASE+513)
CLTOMA_CHUNKSTEST_INFO = (PROTO_BASE+514)
MATOCL_CHUNKSTEST_INFO = (PROTO_BASE+515)
CLTOMA_CHUNKS_MATRIX = (PROTO_BASE+516)
MATOCL_CHUNKS_MATRIX = (PROTO_BASE+517)
CLTOMA_QUOTA_INFO = (PROTO_BASE+518)
MATOCL_QUOTA_INFO = (PROTO_BASE+519)
CLTOMA_EXPORTS_INFO = (PROTO_BASE+520)
MATOCL_EXPORTS_INFO = (PROTO_BASE+521)
CLTOMA_MLOG_LIST = (PROTO_BASE+522)
MATOCL_MLOG_LIST = (PROTO_BASE+523)
CLTOMA_CSSERV_COMMAND = (PROTO_BASE+524)
MATOCL_CSSERV_COMMAND = (PROTO_BASE+525)
CLTOMA_SESSION_COMMAND = (PROTO_BASE+526)
MATOCL_SESSION_COMMAND = (PROTO_BASE+527)
CLTOMA_MEMORY_INFO = (PROTO_BASE+528)
MATOCL_MEMORY_INFO = (PROTO_BASE+529)
CLTOMA_MASS_RESOLVE_PATHS = (PROTO_BASE+536)
MATOCL_MASS_RESOLVE_PATHS = (PROTO_BASE+537)
CLTOMA_MISSING_CHUNKS = (PROTO_BASE+544)
MATOCL_MISSING_CHUNKS = (PROTO_BASE+545)

CLTOCS_HDD_LIST_V2 = (PROTO_BASE+600)
CSTOCL_HDD_LIST_V2 = (PROTO_BASE+601)

MFS_MESSAGE = 1

MFS_CSSERV_COMMAND_REMOVE = 0
MFS_CSSERV_COMMAND_BACKTOWORK = 1
MFS_CSSERV_COMMAND_MAINTENANCEON = 2
MFS_CSSERV_COMMAND_MAINTENANCEOFF = 3

MFS_SESSION_COMMAND_REMOVE = 0

STATUS_OK = 0
ERROR_NOTFOUND = 41
ERROR_ACTIVE = 42

STATE_DUMMY = 0
STATE_LEADER = 1
STATE_ELECT = 2
STATE_FOLLOWER = 3
STATE_USURPER = 4

UNRESOLVED = "(unresolved)"

import socket
import struct
import time
import sys
import traceback
import os
import subprocess

cgimode = 1 if 'GATEWAY_INTERFACE' in os.environ else 0

try:
	xrange
except NameError:
	xrange = range

#parse parameters and auxilinary functions
if cgimode:
	try:
		import urllib.parse as xurllib
	except ImportError:
		import urllib as xurllib
	import cgi
	import cgitb

	cgitb.enable()

	fields = cgi.FieldStorage()

	try:
		if "masterhost" in fields:
			masterhost = fields.getvalue("masterhost")
		else:
			masterhost = 'mfsmaster'
	except Exception:
		masterhost = 'mfsmaster'
	try:
		masterport = int(fields.getvalue("masterport"))
	except Exception:
		masterport = 9421
	try:
		mastercontrolport = int(fields.getvalue("mastercontrolport"))
	except Exception:
		try:
			mastercontrolport = int(fields.getvalue("masterport"))-2
		except Exception:
			mastercontrolport = 9419
	try:
		if "mastername" in fields:
			mastername = fields.getvalue("mastername")
		else:
			mastername = 'MooseFS'
	except Exception:
		mastername = 'MooseFS'

#	thsep = ''
#	html_thsep = ''

	def htmlentities(str):
		return str.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace("'",'&apos;').replace('"','&quot;')

	def urlescape(str):
		return xurllib.quote_plus(str)

	def resolve(strip):
		global UNRESOLVED
		try:
			return (socket.gethostbyaddr(strip))[0]
		except Exception:
			return UNRESOLVED

	def createlink(update):
		global fields,urlescape
		c = []
		for k in fields:
			if k not in update:
				c.append("%s=%s" % (k,urlescape(fields.getvalue(k))))
		for k,v in update.items():
			if v!="":
				c.append("%s=%s" % (k,urlescape(v)))
		return "mfs.cgi?%s" % ("&amp;".join(c))

	def createorderlink(prefix,columnid):
		global fields,createlink
		ordername = "%sorder" % prefix
		revname = "%srev" % prefix
		try:
			orderval = int(fields.getvalue(ordername))
		except Exception:
			orderval = 0
		try:
			revval = int(fields.getvalue(revname))
		except Exception:
			revval = 0
		return createlink({revname:"1"}) if orderval==columnid and revval==0 else createlink({ordername:str(columnid),revname:"0"})

	def createinputs(ignorefields):
		for k in fields:
			if k not in ignorefields:
				yield """<input type="hidden" name="%s" value="%s">""" % (k,htmlentities(fields.getvalue(k)))
		return

else: # CLI mode
	import getopt

	masterhost = 'mfsmaster'
	masterport = 9421
	mastercontrolport = 9419
	mastername = 'MooseFS'
	frameset = -1
	plaintextseparator = "\t"
	forceplaintext = 0
	colormode = 0
	donotresolve = 0
	sectionset = []
	sectionsubset = []
	clicommands = []

# order and data parameters
	IMorder = 0
	IMrev = 0
	MForder = 0
	MFrev = 0
	CSorder = 0
	CSrev = 0
	MBorder = 0
	MBrev = 0
	HDorder = 0
	HDrev = 0
	HDperiod = 0
	HDtime = 0
	HDaddrname = 1
	EXorder = 0
	EXrev = 0
	MSorder = 0
	MSrev = 0
	MOorder = 0
	MOrev = 0
	MOdata = 0
	QUorder = 0
	QUrev = 0
	INmatrix = 0

	lastsval = ''
	lastorder = None
	lastrev = 0
	lastmode = None
	try:
		opts,args = getopt.getopt(sys.argv[1:],"hH:P:S:C:f:ps:no:rm:28")
	except:
		opts = [('-h',None)]
	for opt,val in opts:
		if opt=='-h':
			print("usage:")
			print("\t%s [-hpn28] [-H master_host] [-P master_port] [-f 0..3] -S(IN|IM|LI|IG|MU|IC|IL|MF|CS|MB|HD|EX|MS|MO|QU) [-o order_id [-r]] [-m mode_id]" % sys.argv[0])
			print("\t%s [-hpn28] [-H master_host] [-P master_port] [-f 0..3] -C(RC/ip/port|BW/ip/port)" % sys.argv[0])
			print("\ncommon:\n")
			print("\t-h : print this message")
			print("\t-p : force plain text format on tty devices")
			print("\t-s separator : field separator to use in plain text format on tty devices (forces -p)")
			print("\t-2 : force 256-color terminal color codes")
			print("\t-8 : force 8-color terminal color codes")
			print("\t-H master_host : master address (default: mfsmaster)")
			print("\t-P master_port : master client port (default: 9421)")
			print("\t-n : do not resolve ip adresses (default when output device is not tty)")
			print("\t-f frame charset number : set frame charset to be displayed as table frames in ttymode")
			print("\t\t-f0 : use simple ascii frames '+','-','|' (default for non utf-8 encodings)")
			if sys.stdout.encoding=='UTF-8':
				if sys.version_info[0]<3:
					print("\t\t-f1 : use utf-8 frames: \xe2\x94\x8f\xe2\x94\xb3\xe2\x94\x93\xe2\x94\xa3\xe2\x95\x8b\xe2\x94\xab\xe2\x94\x97\xe2\x94\xbb\xe2\x94\x9b\xe2\x94\x81\xe2\x94\x83\xe2\x95\xb8\xe2\x95\xb9\xe2\x95\xba\xe2\x95\xbb")
					print("\t\t-f2 : use utf-8 frames: \xe2\x94\x8c\xe2\x94\xac\xe2\x94\x90\xe2\x94\x9c\xe2\x94\xbc\xe2\x94\xa4\xe2\x94\x94\xe2\x94\xb4\xe2\x94\x98\xe2\x94\x80\xe2\x94\x82\xe2\x95\xb4\xe2\x95\xb5\xe2\x95\xb6\xe2\x95\xb7")
					print("\t\t-f3 : use utf-8 frames: \xe2\x95\x94\xe2\x95\xa6\xe2\x95\x97\xe2\x95\xa0\xe2\x95\xac\xe2\x95\xa3\xe2\x95\x9a\xe2\x95\xa9\xe2\x95\x9d\xe2\x95\x90\xe2\x95\x91 (default for utf-8 encodings)")
				else:
					print("\t\t-f1 : use utf-8 frames: \u250f\u2533\u2513\u2523\u254b\u252b\u2517\u253b\u251b\u2501\u2503\u2578\u2579\u257a\u257b")
					print("\t\t-f2 : use utf-8 frames: \u250c\u252c\u2510\u251c\u253c\u2524\u2514\u2534\u2518\u2500\u2502\u2574\u2575\u2576\u2577")
					print("\t\t-f3 : use utf-8 frames: \u2554\u2566\u2557\u2560\u256c\u2563\u255a\u2569\u255d\u2550\u2551 (default for utf-8 encodings)")
			else:
				print("\t\t-f1 : use utf-8 frames (thick single)")
				print("\t\t-f2 : use utf-8 frames (thin single)")
				print("\t\t-f3 : use utf-8 frames (double - default for utf-8 encodings)")
			print("\nmonitoring:\n")
			print("\t-S data set : defines data set to be displayed")
			print("\t\t-SIN : show full master info")
			print("\t\t-SIM : show only masters states")
			print("\t\t-SLI : show only licence info")
			print("\t\t-SIG : show only general master (leader) info")
			print("\t\t-SMU : show only master memory usage")
			print("\t\t-SIC : show only chunks info (goal/copies matrices)")
			print("\t\t-SIL : show only loop info (with messages)")
			print("\t\t-SMF : show only missing chunks/files")
			print("\t\t-SCS : show connected chunk servers")
			print("\t\t-SMB : show connected metadata backup servers")
			print("\t\t-SHD : show hdd data")
			print("\t\t-SEX : show exports")
			print("\t\t-SMS : show active mounts")
			print("\t\t-SMO : show operation counters")
			print("\t\t-SQU : show quota info")
			print("\t-o order_id : sort data by column specified by 'order id' (depends on data set)")
			print("\t-r : reverse order")
			print("\t-m mode_id : show data specified by 'mode id' (depends on data set)")
			print("\ncommands:\n")
			print("\t-C command : perform particular command")
			print("\t\t-CRC/ip/port : remove given chunkserver from list of active chunkservers")
			print("\t\t-CBW/ip/port : send given chunkserver back to work (from grace state)")
			print("\t\t-CM1/ip/port : switch given chunkserver to maintenance mode")
			print("\t\t-CM0/ip/port : switch given chunkserver to standard mode (from maintenance mode)")
			print("\t\t-CRS/sessionid : remove given session")
			os._exit(0)
		elif opt=='-2':
			colormode = 2
		elif opt=='-8':
			colormode = 1
		elif opt=='-p':
			forceplaintext = 1
		elif opt=='-s':
			plaintextseparator = val
			forceplaintext = 1
		elif opt=='-n':
			donotresolve = 1
		elif opt=='-f':
			frameset = int(val)
		elif opt=='-H':
			masterhost = val
		elif opt=='-P':
			masterport = int(val)
		elif opt=='-S':
			lastsval = val
			if 'IN' in val:
				sectionset.append("IN")
				sectionsubset.append("IM")
				sectionsubset.append("LI")
				sectionsubset.append("IG")
				sectionsubset.append("MU")
				sectionsubset.append("IC")
				sectionsubset.append("IL")
				sectionsubset.append("MF")
				if lastmode!=None:
					INmatrix = lastmode
				if lastorder!=None:
					IMorder = lastorder
				if lastrev:
					IMrev = 1
			if 'IM' in val:
				sectionset.append("IN")
				sectionsubset.append("IM")
				if lastorder!=None:
					IMorder = lastorder
				if lastrev:
					IMrev = 1
			if 'LI' in val:
				sectionset.append("IN")
				sectionsubset.append("LI")
			if 'IG' in val:
				sectionset.append("IN")
				sectionsubset.append("IG")
			if 'MU' in val:
				sectionset.append("IN")
				sectionsubset.append("MU")
			if 'IC' in val:
				sectionset.append("IN")
				sectionsubset.append("IC")
				if lastmode!=None:
					INmatrix = lastmode
			if 'IL' in val:
				sectionset.append("IN")
				sectionsubset.append("IL")
			if 'MF' in val:
				sectionset.append("IN")
				sectionsubset.append("MF")
				if lastorder!=None:
					MForder = lastorder
				if lastrev:
					MFrev = 1
			if 'CS' in val:
				sectionset.append("CS")
				sectionsubset.append("CS")
				if lastorder!=None:
					CSorder = lastorder
				if lastrev:
					CSrev = 1
			if 'MB' in val:
				sectionset.append("CS")
				sectionsubset.append("MB")
				if lastorder!=None:
					MBorder = lastorder
				if lastrev:
					MBrev = 1
			if 'HD' in val:
				sectionset.append("HD")
				if lastorder!=None:
					HDorder = lastorder
				if lastrev:
					HDrev = 1
				if lastmode!=None:
					if lastmode>=0 and lastmode<6:
						HDperiod,HDtime = divmod(lastmode,2)
			if 'EX' in val:
				sectionset.append("EX")
				if lastorder!=None:
					EXorder = lastorder
				if lastrev:
					EXrev = 1
			if 'MS' in val:
				sectionset.append("MS")
				if lastorder!=None:
					MSorder = lastorder
				if lastrev:
					MSrev = 1
			if 'MO' in val:
				sectionset.append("MO")
				if lastorder!=None:
					MOorder = lastorder
				if lastrev:
					MOrev = 1
				if lastmode!=None:
					MOdata = lastmode
			if 'QU' in val:
				sectionset.append("QU")
				if lastorder!=None:
					QUorder = lastorder
				if lastrev:
					QUrev = 1
			lastorder = None
			lastrev = 0
			lastmode = None
		elif opt=='-o':
			if 'IM' in lastsval:
				IMorder = int(val)
			if 'MF' in lastsval:
				MForder = int(val)
			if 'CS' in lastsval:
				CSorder = int(val)
			if 'MB' in lastsval:
				MBorder = int(val)
			if 'HD' in lastsval:
				HDorder = int(val)
			if 'EX' in lastsval:
				EXorder = int(val)
			if 'MS' in lastsval:
				MSorder = int(val)
			if 'MO' in lastsval:
				MOorder = int(val)
			if 'QU' in lastsval:
				QUorder = int(val)
			if lastsval=='':
				lastorder = int(val)
		elif opt=='-r':
			if 'IM' in lastsval:
				IMrev = 1
			if 'MF' in lastsval:
				MFrev = 1
			if 'CS' in lastsval:
				CSrev = 1
			if 'MB' in lastsval:
				MBrev = 1
			if 'HD' in lastsval:
				HDrev = 1
			if 'EX' in lastsval:
				EXrev = 1
			if 'MS' in lastsval:
				MSrev = 1
			if 'MO' in lastsval:
				MOrev = 1
			if 'QU' in lastsval:
				QUrev = 1
			if lastsval=='':
				lastrev = 1
		elif opt=='-m':
			if 'HD' in lastsval:
				d = int(val)
				if d>=0 and d<6:
					HDperiod,HDtime = divmod(d,2)
			if 'MO' in lastsval:
				MOdata = int(val)
			if 'IN' in lastsval or 'IC' in lastsval:
				INmatrix = int(val)
			if lastsval=='':
				lastmode = int(val)
		elif opt=='-C':
			clicommands.append(val)

	if sectionset==[] and clicommands==[]:
		print("Specify data to be shown (option -S) or command (option -C). Use '-h' for help.")
		os._exit(0)

	ttymode = 1 if forceplaintext==0 and os.isatty(1) else 0
	if ttymode:
		try:
			import curses
			curses.setupterm()
			if curses.tigetnum("colors")>=256:
				colors256 = 1
			else:
				colors256 = 0
		except Exception:
			colors256 = 1 if 'TERM' in os.environ and '256color' in os.environ['TERM'] else 0
		# colors: 0 - white,1 - red,2 - orange,3 - yellow,4 - green,5 - cyan,6 - blue,7 - violet,8 - gray
		CSI="\x1B["
		if colors256:
			ttyreset=CSI+"0m"
			colorcode=[CSI+"38;5;196m",CSI+"38;5;208m",CSI+"38;5;226m",CSI+"38;5;34m",CSI+"38;5;30m",CSI+"38;5;19m",CSI+"38;5;55m",CSI+"38;5;244m"]
		else:
			ttysetred=CSI+"31m"
			ttysetyellow=CSI+"33m"
			ttysetgreen=CSI+"32m"
			ttysetcyan=CSI+"36m"
			ttysetblue=CSI+"34m"
			ttysetmagenta=CSI+"35m"
			ttyreset=CSI+"0m"
			# no orange - use red, no gray - use white
			colorcode=[ttysetred,ttysetred,ttysetyellow,ttysetgreen,ttysetcyan,ttysetblue,ttysetmagenta,""]
	else:
		colorcode=["","","","","","","",""]

	if ttymode and sys.stdout.encoding=='UTF-8':
		if frameset>=0 and frameset<=3:
			tabbleframes=frameset
		else:
			tabbleframes=0
	else:
		tabbleframes=0

	# frames:
	#  +-----+-----+-----+-----+
	#  |     |     |     |     |
	#  |     |     |     |  |  |
	#  |  +- | -+- | -+  |  +- |
	#  |  |  |  |  |  |  |  |  |
	#  |     |     |     |     |
	#  +-----+-----+-----+-----+
	#  |     |     |     |     |
	#  |  |  |  |  |  |  |  |  |
	#  | -+- | -+  |  +- | -+- |
	#  |  |  |  |  |     |     |
	#  |     |     |     |     |
	#  +-----+-----+-----+-----+
	#  |     |     |     |     |
	#  |  |  |     |  |  |     |
	#  | -+  | -+- |  +  | -+  |
	#  |     |     |  |  |     |
	#  |     |     |     |     |
	#  +-----+-----+-----+-----+
	#  |     |     |     |     |
	#  |  |  |     |     |     |
	#  |  +  |  +- |  +  |  +  |
	#  |     |     |  |  |     |
	#  |     |     |     |     |
	#  +-----+-----+-----+-----+
	#  

	class Tabble:
		def __init__(self,title,ccnt,defattr=""):
			if tabbleframes==1:
				if sys.version_info[0]<3:
					self.frames = ['\xe2\x94\x8f', '\xe2\x94\xb3', '\xe2\x94\x93', '\xe2\x94\xa3', '\xe2\x95\x8b', '\xe2\x94\xab', '\xe2\x94\x97', '\xe2\x94\xbb', '\xe2\x94\x9b', '\xe2\x94\x81', '\xe2\x94\x83', '\xe2\x95\xb8', '\xe2\x95\xb9', '\xe2\x95\xba', '\xe2\x95\xbb', ' ']
				else:
					self.frames = ['\u250f', '\u2533', '\u2513', '\u2523', '\u254b', '\u252b', '\u2517', '\u253b', '\u251b', '\u2501', '\u2503', '\u2578', '\u2579', '\u257a', '\u257b', ' ']
			elif tabbleframes==2:
				if sys.version_info[0]<3:
					self.frames = ['\xe2\x94\x8c', '\xe2\x94\xac', '\xe2\x94\x90', '\xe2\x94\x9c', '\xe2\x94\xbc', '\xe2\x94\xa4', '\xe2\x94\x94', '\xe2\x94\xb4', '\xe2\x94\x98', '\xe2\x94\x80', '\xe2\x94\x82', '\xe2\x95\xb4', '\xe2\x95\xb5', '\xe2\x95\xb6', '\xe2\x95\xb7', ' ']
				else:
					self.frames = ['\u250c', '\u252c', '\u2510', '\u251c', '\u253c', '\u2524', '\u2514', '\u2534', '\u2518', '\u2500', '\u2502', '\u2574', '\u2575', '\u2576', '\u2577', ' ']
			elif tabbleframes==3:
				if sys.version_info[0]<3:
					self.frames = ['\xe2\x95\x94', '\xe2\x95\xa6', '\xe2\x95\x97', '\xe2\x95\xa0', '\xe2\x95\xac', '\xe2\x95\xa3', '\xe2\x95\x9a', '\xe2\x95\xa9', '\xe2\x95\x9d', '\xe2\x95\x90', '\xe2\x95\x91', ' ', '\xe2\x95\x91', ' ', '\xe2\x95\x91', ' ']
				else:
					self.frames = ['\u2554', '\u2566', '\u2557', '\u2560', '\u256c', '\u2563', '\u255a', '\u2569', '\u255d', '\u2550', '\u2551', ' ', '\u2551', ' ', '\u2551', ' ']
			else:
				self.frames = ['+','+','+','+','+','+','+','+','+','-','|',' ','|',' ','|',' ']
			self.title = title
			self.ccnt = ccnt
			self.head = []
			self.body = []
			self.defattrs = []
			self.cwidth = []
			for i in range(ccnt):
				self.defattrs.append(defattr)
				self.cwidth.append(0)
		def combineattr(self,attr,defattr):
			attrcolor = ""
			for c in ("0","1","2","3","4","5","6","7","8"):
				if c in defattr:
					attrcolor = c
			for c in ("0","1","2","3","4","5","6","7","8"):
				if c in attr:
					attrcolor = c
			attrjust = ""
			for c in ("l","L","r","R","c","C"):
				if c in defattr:
					attrjust = c
			for c in ("l","L","r","R","c","C"):
				if c in attr:
					attrjust = c
			return attrcolor+attrjust
		def header(self,*rowdata):
			ccnt = 0
			for celldata in rowdata:
				if type(celldata)==tuple:
					if len(celldata)==3:
						ccnt+=celldata[2]
					else:
						if celldata[0]!=None:
							cstr = str(celldata[0])
							if len(cstr) > self.cwidth[ccnt]:
								self.cwidth[ccnt] = len(cstr)
						ccnt+=1
				else:
					if celldata!=None:
						cstr = str(celldata)
						if len(cstr) > self.cwidth[ccnt]:
							self.cwidth[ccnt] = len(cstr)
					ccnt+=1
			if ccnt != self.ccnt:
				raise IndexError
			self.head.append(rowdata)
		def defattr(self,*rowdata):
			if len(rowdata) != self.ccnt:
				raise IndexError
			self.defattrs = rowdata
		def append(self,*rowdata):
			ccnt = 0
			rdata = []
			for celldata in rowdata:
				if type(celldata)==tuple:
					if celldata[0]!=None:
						cstr = str(celldata[0])
					else:
						cstr = ""
					if len(celldata)==3:
						rdata.append((cstr,self.combineattr(celldata[1],self.defattrs[ccnt]),celldata[2]))
						ccnt+=celldata[2]
					else:
						if len(cstr) > self.cwidth[ccnt]:
							self.cwidth[ccnt] = len(cstr)
						if len(celldata)==2:
							rdata.append((cstr,self.combineattr(celldata[1],self.defattrs[ccnt])))
						else:
							rdata.append((cstr,self.defattrs[ccnt]))
						ccnt+=1
				else:
					if celldata!=None:
						cstr = str(celldata)
						if len(cstr) > self.cwidth[ccnt]:
							self.cwidth[ccnt] = len(cstr)
						rdata.append((cstr,self.defattrs[ccnt]))
					else:
						rdata.append(celldata)
					ccnt+=1
			if ccnt != self.ccnt:
				raise IndexError
			self.body.append(rdata)
		def attrdata(self,cstr,cattr,cwidth):
			retstr = ""
			if "1" in cattr:
				retstr += colorcode[0]
				needreset = 1
			elif "2" in cattr:
				retstr += colorcode[1]
				needreset = 1
			elif "3" in cattr:
				retstr += colorcode[2]
				needreset = 1
			elif "4" in cattr:
				retstr += colorcode[3]
				needreset = 1
			elif "5" in cattr:
				retstr += colorcode[4]
				needreset = 1
			elif "6" in cattr:
				retstr += colorcode[5]
				needreset = 1
			elif "7" in cattr:
				retstr += colorcode[6]
				needreset = 1
			elif "8" in cattr:
				retstr += colorcode[7]
				needreset = 1
			else:
				needreset = 0
			if cstr=="--":
				retstr += " "+"-"*cwidth+" "
			elif cstr=="---":
				retstr += "-"*(cwidth+2)
			elif "L" in cattr or "l" in cattr:
				retstr += " "+cstr.ljust(cwidth)+" "
			elif "R" in cattr or "r" in cattr:
				retstr += " "+cstr.rjust(cwidth)+" "
			else:
				retstr += " "+cstr.center(cwidth)+" "
			if needreset:
				retstr += ttyreset
			return retstr
		def lines(self):
			outstrtab = []
			if ttymode:
				tabdata = []
				# upper frame
				tabdata.append((("---","",self.ccnt),))
				# title
				tabdata.append(((self.title,"",self.ccnt),))
				# header
				if len(self.head)>0:
					tabdata.append((("---","",self.ccnt),))
					tabdata.extend(self.head)
				# head and data separator
				tabdata.append((("---","",self.ccnt),))
				# data
				if len(self.body)==0:
					tabdata.append((("no data","",self.ccnt),))
				else:
					tabdata.extend(self.body)
				# bottom frame
				tabdata.append((("---","",self.ccnt),))
				# check col-spaned headers and adjust column widths if necessary
				for rowdata in tabdata:
					ccnt = 0
					for celldata in rowdata:
						if type(celldata)==tuple and len(celldata)==3 and celldata[0]!=None:
							cstr = str(celldata[0])
							clen = len(cstr)
							cwidth = sum(self.cwidth[ccnt:ccnt+celldata[2]])+3*(celldata[2]-1)
							if clen > cwidth:
								add = clen - cwidth
								adddm = divmod(add,celldata[2])
								cadd = adddm[0]
								if adddm[1]>0:
									cadd+=1
								for i in range(celldata[2]):
									self.cwidth[ccnt+i] += cadd
							ccnt += celldata[2]
						else:
							ccnt += 1
				separators = []
				# before tab - no separators
				seplist = []
				for i in range(self.ccnt+1):
					seplist.append(0)
				separators.append(seplist)
				for rowdata in tabdata:
					seplist = [1]
					for celldata in rowdata:
						if type(celldata)==tuple and len(celldata)==3:
							for i in range(celldata[2]-1):
								seplist.append(1 if celldata[0]=='---' else 0)
						seplist.append(1)
					separators.append(seplist)
				# after tab - no separators
				seplist = []
				for i in range(self.ccnt+1):
					seplist.append(0)
				separators.append(seplist)
				# add upper and lower separators:
				updownsep = [[a*2 + b for (a,b) in zip(x,y)] for (x,y) in zip(separators[2:],separators[:-2])]
				# create tabble
				for (rowdata,sepdata) in zip(tabdata,updownsep):
	#				print rowdata,sepdata
					ccnt = 0
					line = ""
					nsep = 0 #self.frames[10]
					for celldata in rowdata:
						cpos = ccnt
						cattr = ""
						if type(celldata)==tuple:
							if celldata[1]!=None:
								cattr = celldata[1]
							if len(celldata)==3:
								cwidth = sum(self.cwidth[ccnt:ccnt+celldata[2]])+3*(celldata[2]-1)
								ccnt+=celldata[2]
							else:
								cwidth = self.cwidth[ccnt]
								ccnt+=1
							cstr = celldata[0]
						else:
							cstr = celldata
							cwidth = self.cwidth[ccnt]
							ccnt+=1
						if cstr==None:
							cstr = ""
						if type(cstr)!=str:
							cstr = str(cstr)
						if cstr=="---":
							if nsep==0:
								line += self.frames[(13,6,0,3)[sepdata[cpos]]]
								#line += self.frames[(15,6,0,3)[sepdata[cpos]]]
							else:
								line += self.frames[(9,7,1,4)[sepdata[cpos]]]
							nsep = 1 #self.frames[4]
							for ci in range(cpos,ccnt-1):
								line += self.frames[9]*(self.cwidth[ci]+2)
								line += self.frames[(9,7,1,4)[sepdata[ci+1]]]
							line += self.frames[9]*(self.cwidth[ccnt-1]+2)
						else:
							if nsep==0:
								line += self.frames[(15,12,14,10)[sepdata[cpos]]]
								#line += self.frames[(15,10,10,10)[sepdata[cpos]]]
							else:
								line += self.frames[(11,8,2,5)[sepdata[cpos]]]
								#line += self.frames[(15,8,2,5)[sepdata[cpos]]]
							nsep = 0
							line += self.attrdata(cstr,cattr,cwidth)
					if nsep==0:
						line += self.frames[(15,12,14,10)[sepdata[ccnt]]]
						#line += self.frames[(15,10,10,10)[sepdata[ccnt]]]
					else:
						line += self.frames[(11,8,2,5)[sepdata[ccnt]]]
						#line += self.frames[(15,8,2,5)[sepdata[ccnt]]]
					outstrtab.append(line)
			else:
				for rowdata in self.body:
					row = []
					for celldata in rowdata:
						if type(celldata)==tuple:
							cstr = str(celldata[0])
						elif celldata!=None:
							cstr = str(celldata)
						else:
							cstr = ""
						row.append(cstr)
					outstrtab.append("%s:%s%s" % (self.title,plaintextseparator,plaintextseparator.join(row)))
			return outstrtab
		def __str__(self):
			return "\n".join(self.lines())

	#x = Tabble("Test title",4)
	#x.header("column1","column2","column3","column4")
	#x.append("t1","t2","very long entry","test")
	#x.append(("r","r3"),("l","l2"),"also long entry","test")
	#print x
	#
	#x = Tabble("Very long tabble title",2)
	#x.defattr("l","r")
	#x.append("key","value")
	#x.append("other key",123)
	#y = []
	#y.append(("first","1"))
	#y.append(("second","4"))
	#x.append(*y)
	#print x
	#
	#x = Tabble("Tabble with complicated header",15,"r")
	#x.header(("","",4),("I/O stats last min","",8),("","",3))
	#x.header(("info","",4),("---","",8),("space","",3))
	#x.header(("","",4),("transfer","",2),("max time","",3),("# of ops","",3),("","",3))
	#x.header(("---","",15))
	#x.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync","used","total","used %")
	#x.append("192.168.1.102:9422:/mnt/hd4/",66908,"no errors","ok","19 MiB/s","27 MiB/s","263625 us","43116 us","262545 us",3837,3295,401,"1.0 TiB","1.3 TiB","76.41%")
	#x.append("192.168.1.102:9422:/mnt/hd5/",67469,"no errors","ok","25 MiB/s","29 MiB/s","340303 us","89168 us","223610 us",2487,2593,366,"1.0 TiB","1.3 TiB","75.93%")
	#x.append("192.168.1.111:9422:/mnt/hd5/",109345,("2012-10-12 07:27","2"),("damaged","1"),"-","-","-","-","-","-","-","-","1.2 TiB","1.3 TiB","87.18%")
	#x.append("192.168.1.211:9422:/mnt/hd5/",49128,"no errors",("marked for removal","4"),"-","-","-","-","-","-","-","-","501 GiB","1.3 TiB","36.46%")
	##x.append("192.168.1.111:9422:/mnt/hd5/",109345,("2012-10-12 07:27","2"),("damaged","1"),("","-",8),"1.2 TiB","1.3 TiB","87.18%")
	##x.append("192.168.1.211:9422:/mnt/hd5/",49128,"no errors",("marked for removal","4"),("","-",8),"501 GiB","1.3 TiB","36.46%")
	#x.append("192.168.1.229:9422:/mnt/hd10/","67969","no errors","ok","17 MiB/s","11 MiB/s","417292 us","76333 us","1171903 us","2299","2730","149","1.0 TiB","1.3 TiB","76.61%")
	#print x
	#
	#x = Tabble("Colors",1,"r")
	#x.append(("white","0"))
	#x.append(("red","1"))
	#x.append(("orange","2"))
	#x.append(("yellow","3"))
	#x.append(("green","4"))
	#x.append(("cyan","5"))
	#x.append(("blue","6"))
	#x.append(("magenta","7"))
	#x.append(("gray","8"))
	#print x
	#
	#x = Tabble("Adjustments",1)
	#x.append(("left","l"))
	#x.append(("right","r"))
	#x.append(("center","c"))
	#print x
	#
	#x = Tabble("Special entries",3)
	#x.defattr("l","r","r")
	#x.header("entry","effect","extra column")
	#x.append("-- ","--","")
	#x.append("--- ","---","")
	#x.append("('--','',2)",('--','',2))
	#x.append("('','',2)",('','',2))
	#x.append("('---','',2)",('---','',2))
	#x.append("('red','1')",('red','1'),'')
	#x.append("('orange','2')",('orange','2'),'')
	#x.append("('yellow','3')",('yellow','3'),'')
	#x.append("('green','4')",('green','4'),'')
	#x.append("('cyan','5')",('cyan','5'),'')
	#x.append("('blue','6')",('blue','6'),'')
	#x.append("('magenta','7')",('magenta','7'),'')
	#x.append("('gray','8')",('gray','8'),'')
	#x.append(('---','',3))
	#x.append("('left','l',2)",('left','l',2))
	#x.append("('right','r',2)",('right','r',2))
	#x.append("('center','c',2)",('center','c',2))
	#print x

	def resolve(strip):
		if donotresolve:
			return strip
		try:
			return (socket.gethostbyaddr(strip))[0]
		except Exception:
			return strip






# common auxilinary functions

def getmasteraddresses():
	m = []
	try:
		for i in socket.getaddrinfo(masterhost,masterport,socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP):
			if i[0]==socket.AF_INET and i[1]==socket.SOCK_STREAM and i[2]==socket.SOL_TCP:
				m.append(i[4])
	except Exception:
		pass
	return m

#def mysend(socket,msg):
#	totalsent = 0
#	while totalsent < len(msg):
#		sent = socket.send(msg[totalsent:])
#		if sent == 0:
#			raise RuntimeError("socket connection broken")
#		totalsent = totalsent + sent

#def myrecv(socket,leng):
#	if sys.version_info[0]<3:
#		msg = ''
#	else:
#		msg = bytes(0)
#	while len(msg) < leng:
#		chunk = socket.recv(leng-len(msg))
#		if len(chunk) == 0:
#			raise RuntimeError("socket connection broken")
#		msg = msg + chunk
#	return msg

def state_name(stateid):
	if stateid==STATE_DUMMY:
		return "DUMMY"
	elif stateid==STATE_USURPER:
		return "USURPER"
	elif stateid==STATE_FOLLOWER:
		return "FOLLOWER"
	elif stateid==STATE_ELECT:
		return "ELECT"
	elif stateid==STATE_LEADER:
		return "LEADER"
	else:
		return "???"

def state_color(stateid,sync):
	if stateid==STATE_DUMMY:
		return 8
	elif stateid==STATE_FOLLOWER or stateid==STATE_USURPER:
		if sync:
			return 5
		else:
			return 6
	elif stateid==STATE_ELECT:
		return 3
	elif stateid==STATE_LEADER:
		return 4
	else:
		return 1

def decimal_number(number,sep=' '):
	parts = []
	while number>=1000:
		number,rest = divmod(number,1000)
		parts.append("%03u" % rest)
	parts.append(str(number))
	parts.reverse()
	return sep.join(parts)

def humanize_number(number,sep='',suff='B'):
	number*=100
	scale=0
	while number>=99950:
		number = number//1024
		scale+=1
	if number<995 and scale>0:
		b = (number+5)//10
		nstr = "%u.%u" % divmod(b,10)
	else:
		b = (number+50)//100
		nstr = "%u" % b
	if scale>0:
		return "%s%s%si%s" % (nstr,sep,"-KMGTPEZY"[scale],suff)
	else:
		return "%s%s%s" % (nstr,sep,suff)

def timeduration_to_shortstr(timeduration):
	for l,s in ((86400,'d'),(3600,'h'),(60,'m'),(0,'s')):
		if timeduration>=l:
			if l>0:
				n = float(timeduration)/float(l)
			else:
				n = float(timeduration)
			rn = round(n,1)
			if n==round(n,0):
				return "%.0f%s" % (n,s)
			else:
				return "%s%.1f%s" % (("~" if n!=rn else ""),rn,s)
	return "???"

def timeduration_to_fullstr(timeduration):
	if timeduration>=86400:
		days,dayseconds = divmod(timeduration,86400)
		daysstr = "%u day%s, " % (days,("s" if days!=1 else ""))
	else:
		dayseconds = timeduration
		daysstr = ""
	hours,hourseconds = divmod(dayseconds,3600)
	minutes,seconds = divmod(hourseconds,60)
	if seconds==round(seconds,0):
		return "%u second%s (%s%u:%02u:%02u)" % (timeduration,("" if timeduration==1 else "s"),daysstr,hours,minutes,seconds)
	else:
		seconds,fracsec = divmod(seconds,1)
		return "%.3f seconds (%s%u:%02u:%02u.%03u)" % (timeduration,daysstr,hours,minutes,seconds,round(1000*fracsec,0))

def print_exception():
	exc_type, exc_value, exc_traceback = sys.exc_info()
	global cgimode,ttymode
	try:
		if cgimode:
			print("""<table class="FR" cellspacing="0">""")
			print("""<tr><td align="left"><pre>""")
			print(traceback.format_exc().strip())
			print("""</pre></td></tr>""")
			print("""</table>""")
		elif ttymode:
			tab = Tabble("Exception Traceback",4)
			tab.header("file","line","in","text")
			tab.defattr("l","r","l","l")
			for d in traceback.extract_tb(exc_traceback):
				tab.append(d[0],d[1],d[2],repr(d[3]))
			tab.append(("---","",4))
			tab.append(("Error","c",4))
			tab.append(("---","",4))
			for d in traceback.format_exception_only(exc_type, exc_value):
				tab.append((repr(d.strip()),"",4))
			print("%s%s%s" % (colorcode[1],tab,ttyreset))
		else:
			print("""---------------------------------------------------------------- error -----------------------------------------------------------------""")
			print(traceback.format_exc().strip())
			print("""----------------------------------------------------------------------------------------------------------------------------------------""")
	except:
		print(traceback.format_exc().strip())

def version_convert(version):
	if version>=(2,0,0):
		return ((version[0],version[1],version[2]//2),version[2]&1)
	elif version>=(1,7,0):
		return (version,1)
	elif version>(0,0,0):
		return (version,0)
	else:
		return (version,-1)

def version_str_and_sort(version):
	version,pro = version_convert(version)
	strver = "%u.%u.%u" % version
	sortver = "%05u_%03u_%03u" % version
	if pro==1:
		strver += " PRO"
		sortver += "_2"
	elif pro==0:
		sortver += "_1"
	else:
		sortver += "_0"
	return (strver,sortver)

class MFSConn:
	def __init__(self,host,port):
		self.host = host
		self.port = port
		self.socket = None
		self.connect()
	def __del__(self):
		try:
			if self.socket:
				self.socket.close()
#				print "connection closed with: %s:%u" % (self.host,self.port)
			self.socket = None
		except AttributeError:
			pass
	def connect(self):
		cnt = 0
		while self.socket == None and cnt<3:
			self.socket = socket.socket()
			self.socket.settimeout(1)
			try:
				self.socket.connect((self.host,self.port))
			except Exception:
				self.socket.close()
				self.socket = None
				cnt += 1
		if self.socket==None:
			self.socket = socket.socket()
			self.socket.settimeout(1)
			self.socket.connect((self.host,self.port))
#		else:
#			print "connected to: %s:%u" % (self.host,self.port)
	def close(self):
		if self.socket:
			self.socket.close()
			self.socket = None
	def mysend(self,msg):
		if self.socket == None:
			self.connect()
		totalsent = 0
		while totalsent < len(msg):
			sent = self.socket.send(msg[totalsent:])
			if sent == 0:
				raise RuntimeError("socket connection broken")
			totalsent = totalsent + sent
	def myrecv(self,leng):
		if sys.version_info[0]<3:
			msg = ''
		else:
			msg = bytes(0)
		while len(msg) < leng:
			chunk = self.socket.recv(leng-len(msg))
			if len(chunk) == 0:
				raise RuntimeError("socket connection broken")
			msg = msg + chunk
		return msg
	def command(self,cmdout,cmdin,dataout=None):
		if dataout:
			l = len(dataout)
			msg = struct.pack(">LL",cmdout,l) + dataout
		else:
			msg = struct.pack(">LL",cmdout,0)
		cmdok = 0
		errcnt = 0
		while cmdok==0:
			try:
				self.mysend(msg)
				header = self.myrecv(8)
				cmd,length = struct.unpack(">LL",header)
				if cmd==cmdin:
					datain = self.myrecv(length)
					cmdok = 1
				else:
					raise RuntimeError("MFS communication error - bad answer")
			except Exception:
				if errcnt<3:
					self.close()
					self.connect()
					errcnt+=1
				else:
					raise RuntimeError("MFS communication error")
		return datain,length

class Master(MFSConn):
	def __init__(self,host,port):
		MFSConn.__init__(self,host,port)
		self.version = (0,0,0)
		self.pro = -1
	def set_version(self,version):
		self.version,self.pro = version_convert(version)
	def version_at_least(self,v1,v2,v3):
		return (self.version>=(v1,v2,v3))
	def version_less_than(self,v1,v2,v3):
		return (self.version<(v1,v2,v3))
	def version_is(self,v1,v2,v3):
		return (self.version==(v1,v2,v3))
	def version_unknown(self):
		return (self.version==(0,0,0))
	def is_pro(self):
		return self.pro
	def sort_ver(self):
		sortver = "%05u_%03u_%03u" % self.version
		if self.pro==1:
			sortver += "_2"
		elif self.pro==0:
			sortver += "_1"
		else:
			sortver += "_0"
		return sortver


def resolve_inodes_paths(leaderconn,inodes):
	inodepaths = {}
	if len(inodes)>0:
		data,length = leaderconn.command(CLTOMA_MASS_RESOLVE_PATHS,MATOCL_MASS_RESOLVE_PATHS,struct.pack(">"+len(inodes)*"L",*inodes))
		pos = 0
		while pos+8<=length:
			inode,psize = struct.unpack(">LL",data[pos:pos+8])
			pos+=8
			if psize == 0:
				if inode not in inodepaths:
					inodepaths[inode] = []
				inodepaths[inode].append("./META")
			elif pos + psize <= length:
				while psize>=4:
					pleng = struct.unpack(">L",data[pos:pos+4])[0]
					pos+=4
					psize-=4
					path = data[pos:pos+pleng]
					pos+=pleng
					psize-=pleng
					if sys.version_info[0]>=3:
						try:
							path = path.decode('ascii')
						except UnicodeDecodeError:
							pass
					if inode not in inodepaths:
						inodepaths[inode] = []
					inodepaths[inode].append(path)
				if psize!=0:
					raise RuntimeError("MFS packet malformed")
		if pos!=length:
			raise RuntimeError("MFS packet malformed")
	return inodepaths


# find leader
leaderispro = 0
leaderfound = 0
followerfound = 0
electfound = 0
leaderconn = None
leaderinfo = None
masterlist = getmasteraddresses()
masterlistver = []
masterlistinfo = []

for mhost,mport in masterlist:
	conn = None
	version = (0,0,0)
	statestr = "???"
	statecolor = 1
	memusage = 0
	syscpu = 0
	usercpu = 0
	lastsuccessfulstore = 0
	lastsaveseconds = 0
	lastsavestatus = 0
	metaversion = 0
	try:
		conn = Master(mhost,mport)
		try:
			data,length = conn.command(CLTOMA_INFO,MATOCL_INFO)
			if length==52:
				version = (1,4,0)
				conn.set_version(version)
				if leaderfound==0:
					leaderconn = conn
					leaderinfo = data
					leaderfound = 1
				statestr = "OLD MASTER (LEADER ONLY)"
				statecolor = 0
			elif length==60:
				version = (1,5,0)
				conn.set_version(version)
				if leaderfound==0:
					leaderconn = conn
					leaderinfo = data
					leaderfound = 1
				statestr = "OLD MASTER (LEADER ONLY)"
				statecolor = 0
			elif length==68 or length==76 or length==101:
				version = struct.unpack(">HBB",data[:4])
				conn.set_version(version)
				if leaderfound==0:
					leaderconn = conn
					leaderinfo = data
					leaderfound = 1
				if length==76:
					memusage = struct.unpack(">Q",data[4:12])[0]
				if length==101:
					memusage,syscpu,usercpu = struct.unpack(">QQQ",data[4:28])
					syscpu/=10000000.0
					usercpu/=10000000.0
					lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">LLB",data[92:101])
				if version<(1,7,0):
					statestr = "OLD MASTER (LEADER ONLY)"
					statecolor = 0
				else:
					statestr = "UPGRADE THIS UNIT !!!"
					statecolor = 2
			elif length==121:
				version = struct.unpack(">HBB",data[:4])
				conn.set_version(version)
				memusage,syscpu,usercpu = struct.unpack(">QQQ",data[4:28])
				syscpu/=10000000.0
				usercpu/=10000000.0
				lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">LLB",data[92:101])
				if conn.version_at_least(2,0,14):
					lastsaveseconds = lastsaveseconds / 1000.0
				workingstate,nextstate,stablestate,sync,leaderip,changetime,metaversion = struct.unpack(">BBBBLLQ",data[101:121])
				if workingstate==0xFF and nextstate==0xFF and stablestate==0xFF and sync==0xFF:
					if leaderfound==0:
						leaderconn = conn
						leaderinfo = data
						leaderfound = 1
					statestr = "-"
					statecolor = 0
				elif stablestate==0 or workingstate!=nextstate:
					statestr = "transition %s -> %s" % (state_name(workingstate),state_name(nextstate))
					statecolor = 8
				else:
					statestr = state_name(workingstate)
					statecolor = state_color(workingstate,sync)
					if workingstate==STATE_FOLLOWER or workingstate==STATE_USURPER:
						if sync==0:
							statestr += " (DESYNC)"
						followerfound = 1
					if workingstate==STATE_ELECT:
						electfound = 1
					if workingstate==STATE_LEADER and leaderfound==0:
						leaderispro = 1
						leaderconn = conn
						leaderinfo = data
						leaderfound = 1
		except Exception:
			statestr = "BUSY"
			statecolor = 7
	except Exception:
		statestr = "DEAD"
	try:
		iptab = tuple(map(int,mhost.split('.')))
		strip = "%u.%u.%u.%u" % iptab
		sortip = "%03u_%03u_%03u_%03u" % iptab
	except Exception:
		strip = mhost
		sortip = mhost
	strver,sortver = version_str_and_sort(version)
	if conn and conn!=leaderconn:
		del conn
	masterlistver.append((mhost,mport,version))
	masterlistinfo.append((sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus))

if leaderfound and leaderconn.version_less_than(1,6,10):
	if cgimode:
		print("Content-Type: text/html; charset=UTF-8")
		print("")
		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
		print("""<head>""")
		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
		print("""</head>""")
		print("""<body>""")
		if leaderconn.version_unknown():
			print("""<h1 align="center">Can't detect MFS master version</h1>""")
		else:
			print("""<h1 align="center">MFS master version not supported (pre 1.6.10)</h1>""")
		print("""</body>""")
		print("""</html>""")
	else:
		if leaderconn.version_unknown():
			print("""Can't detect MFS master version""")
		else:
			print("""MFS master version not supported (pre 1.6.10)""")
	sys.exit(1)




# commands
if cgimode:
	# commands in CGI mode
	cmd_success = -1
	if "CSremove" in fields:
		cmd_success = 0
		tracedata = ""
		if leaderfound:
			try:
				serverdata = fields.getvalue("CSremove").split(":")
				if len(serverdata)==2:
					csip = list(map(int,serverdata[0].split(".")))
					csport = int(serverdata[1])
					if len(csip)==4:
						if leaderconn.version_less_than(1,6,28):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBH",csip[0],csip[1],csip[2],csip[3],csport))
							if length==0:
								cmd_success = 1
								status = 0
						else:
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_REMOVE,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
			except Exception:
				tracedata = traceback.format_exc()
		url = createlink({"CSremove":""})
	elif "CSbacktowork" in fields:
		cmd_success = 0
		tracedata = ""
		if leaderfound:
			try:
				serverdata = fields.getvalue("CSbacktowork").split(":")
				if len(serverdata)==2:
					csip = list(map(int,serverdata[0].split(".")))
					csport = int(serverdata[1])
					if len(csip)==4:
						if leaderconn.version_at_least(1,6,28):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_BACKTOWORK,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
			except Exception:
				tracedata = traceback.format_exc()
		url = createlink({"CSbacktowork":""})
	elif "CSmaintenanceon" in fields:
		cmd_success = 0
		tracedata = ""
		if leaderfound:
			try:
				serverdata = fields.getvalue("CSmaintenanceon").split(":")
				if len(serverdata)==2:
					csip = list(map(int,serverdata[0].split(".")))
					csport = int(serverdata[1])
					if len(csip)==4:
						if leaderconn.version_at_least(2,0,11):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEON,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
			except Exception:
				tracedata = traceback.format_exc()
		url = createlink({"CSmaintenanceon":""})
	elif "CSmaintenanceoff" in fields:
		cmd_success = 0
		tracedata = ""
		if leaderfound:
			try:
				serverdata = fields.getvalue("CSmaintenanceoff").split(":")
				if len(serverdata)==2:
					csip = list(map(int,serverdata[0].split(".")))
					csport = int(serverdata[1])
					if len(csip)==4:
						if leaderconn.version_at_least(2,0,11):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEOFF,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
			except Exception:
				tracedata = traceback.format_exc()
		url = createlink({"CSmaintenanceoff":""})
	elif "MSremove" in fields:
		cmd_success = 0
		tracedata = ""
		if leaderfound:
			try:
				sessionid = int(fields.getvalue("MSremove"))
				data,length = leaderconn.command(CLTOMA_SESSION_COMMAND,MATOCL_SESSION_COMMAND,struct.pack(">BL",MFS_SESSION_COMMAND_REMOVE,sessionid))
				if length==1:
					status = (struct.unpack(">B",data))[0]
					cmd_success = 1
			except Exception:
				tracedata = traceback.format_exc()
		url = createlink({"MSremove":""})
	if cmd_success==1:
		print("Status: 302 Found")
		print("Location: %s" % url.replace("&amp;","&"))
		print("Content-Type: text/html; charset=UTF-8")
		print("")
		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
		print("""<head>""")
		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
		print("""<meta http-equiv="Refresh" content="0; url=%s" />""" % url)
		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
		print("""</head>""")
		print("""<body>""")
		print("""<h1 align="center"><a href="%s">If you see this then it means that redirection didn't work, so click here</a></h1>""" % url)
		print("""</body>""")
		print("""</html>""")
		sys.exit(0)
	elif cmd_success==0:
		print("Content-Type: text/html; charset=UTF-8")
		print("")
		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
		print("""<head>""")
		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
		print("""<meta http-equiv="Refresh" content="5; url=%s" />""" % url)
		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
		print("""</head>""")
		print("""<body>""")
		print("""<h3 align="center">Can't perform command - wait 5 seconds for refresh</h3>""")
		if tracedata:
			print("""<hr />""")
			print("""<pre>%s</pre>""" % tracedata)
		print("""</body>""")
		print("""</html>""")
		sys.exit(0)
else:
	if leaderfound:
		for cmd in clicommands:
			cmddata = cmd.split('/')
			if cmddata[0]=='RC':
				cmd_success = 0
				try:
					csip = list(map(int,cmddata[1].split(".")))
					csport = int(cmddata[2])
					if len(csip)==4:
						if leaderconn.version_less_than(1,6,28):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBH",csip[0],csip[1],csip[2],csip[3],csport))
							if length==0:
								cmd_success = 1
								status = 0
						else:
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_REMOVE,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
					if cmd_success:
						if status==STATUS_OK:
							print("Chunkserver %s/%s has been removed" % (cmddata[1],cmddata[2]))
						elif status==ERROR_NOTFOUND:
							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
						elif status==ERROR_ACTIVE:
							print("Chunkserver %s/%s can't be removed because is still active" (cmddata[1],cmddata[2]))
						else:
							print("Can't remove chunkserver %s/%s (status:%u)" % (cmddata[1],cmddata[2],status))
					else:
						print("Can't remove chunkserver %s/%s" % (cmddata[1],cmddata[2]))
				except Exception:
					print_exception()
			if cmddata[0]=='BW':
				cmd_success = 0
				try:
					csip = list(map(int,cmddata[1].split(".")))
					csport = int(cmddata[2])
					if len(csip)==4:
						if leaderconn.version_at_least(1,6,28):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_BACKTOWORK,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
					if cmd_success:
						if status==STATUS_OK:
							print("Chunkserver %s/%s has back to work" % (cmddata[1],cmddata[2]))
						elif status==ERROR_NOTFOUND:
							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
						else:
							print("Can't turn chunkserver %s/%s back to work (status:%u)" % (cmddata[1],cmddata[2],status))
					else:
						print("Can't turn chunkserver %s/%s back to work" % (cmddata[1],cmddata[2]))
				except Exception:
					print_exception()
			if cmddata[0]=='M1':
				cmd_success = 0
				try:
					csip = list(map(int,cmddata[1].split(".")))
					csport = int(cmddata[2])
					if len(csip)==4:
						if leaderconn.version_at_least(2,0,11):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEON,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
					if cmd_success:
						if status==STATUS_OK:
							print("Chunkserver %s/%s has been switched to maintenance mode" % (cmddata[1],cmddata[2]))
						elif status==ERROR_NOTFOUND:
							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
						else:
							print("Can't switch chunkserver %s/%s to maintenance mode (status:%u)" % (cmddata[1],cmddata[2],status))
					else:
						print("Can't switch chunkserver %s/%s to maintenance mode" % (cmddata[1],cmddata[2]))
				except Exception:
					print_exception()
			if cmddata[0]=='M0':
				cmd_success = 0
				try:
					csip = list(map(int,cmddata[1].split(".")))
					csport = int(cmddata[2])
					if len(csip)==4:
						if leaderconn.version_at_least(2,0,11):
							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEOFF,csip[0],csip[1],csip[2],csip[3],csport))
							if length==1:
								status = (struct.unpack(">B",data))[0]
								cmd_success = 1
					if cmd_success:
						if status==STATUS_OK:
							print("Chunkserver %s/%s has been switched to standard mode" % (cmddata[1],cmddata[2]))
						elif status==ERROR_NOTFOUND:
							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
						else:
							print("Can't switch chunkserver %s/%s to standard mode (status:%u)" % (cmddata[1],cmddata[2],status))
					else:
						print("Can't switch chunkserver %s/%s to standard mode" % (cmddata[1],cmddata[2]))
				except Exception:
					print_exception()
			if cmddata[0]=='RS':
				cmd_success = 0
				try:
					sessionid = int(cmddata[1])
					data,length = leaderconn.command(CLTOMA_SESSION_COMMAND,MATOCL_SESSION_COMMAND,struct.pack(">BL",MFS_SESSION_COMMAND_REMOVE,sessionid))
					if length==1:
						status = (struct.unpack(">B",data))[0]
						cmd_success = 1
					if cmd_success:
						if status==STATUS_OK:
							print("Session %u has been removed" % (sessionid))
						elif status==ERROR_NOTFOUND:
							print("Session %u hasn't been found" % (sessionid))
						elif status==ERROR_ACTIVE:
							print("Session %u can't be removed because is still active" % (sessionid))
						else:
							print("Can't remove session %u (status:%u)" % (sessionid,status))
					else:
						print("Can't remove session %u" % (sessionid))
				except Exception:
					print_exception()
	elif len(clicommands)>0:
		print("Can't perform any operation because there is no leading master")

if cgimode:
	if "sections" in fields:
		sectionstr = fields.getvalue("sections")
		sectionset = set(sectionstr.split("|"))
	else:
		sectionset = set(("IN",))
	if "subsections" in fields:
		subsectionstr = fields.getvalue("subsections")
		sectionsubset = set(subsectionstr.split("|"))
	else:
		sectionsubset = ["IM","LI","IG","MU","IC","IL","MF","CS","MB"] # used only in climode - in cgimode turn on all subsections

	if leaderfound:
		if leaderconn.version_less_than(1,7,0):
			sectiondef={
				"IN":"Info",
				"CS":"Servers",
				"HD":"Disks",
				"EX":"Exports",
				"MS":"Mounts",
				"MO":"Operations",
				"MC":"Master Charts",
				"CC":"Server Charts"
			}
			sectionorder=["IN","CS","HD","EX","MS","MO","MC","CC"];
		else:
			sectiondef={
				"IN":"Info",
				"CS":"Servers",
				"HD":"Disks",
				"EX":"Exports",
				"MS":"Mounts",
				"MO":"Operations",
				"QU":"Quotas",
				"MC":"Master Charts",
				"CC":"Server Charts"
			}
			sectionorder=["IN","CS","HD","EX","MS","MO","QU","MC","CC"];
	else:
		sectiondef = {
			"IN":"Info"
		}
		sectionorder=["IN"];

	print("Content-Type: text/html; charset=UTF-8")
	print("")
	# print """<!-- Put IE into quirks mode -->
	print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
	print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
	print("""<head>""")
	print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
	print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
	print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
	print("""<script src="acidtab.js" type="text/javascript"></script>""")
	print("""</head>""")
	print("""<body>""")

	#MENUBAR
	print("""<div id="header">""")
	print("""<table class="HDR" cellpadding="0" cellspacing="0" border="0">""")
	print("""<tr>""")
	print("""<td class="LOGO"><a href="http://www.moosefs.org"><img src="/logomini.png" alt="logo" style="border:0;width:123px;height:47px" /></a></td>""")
	print("""<td class="MENU"><table class="MENU" cellspacing="0">""")
	print("""<tr>""")
	last="U"
	for k in sectionorder:
		if k==sectionorder[-1]:
			last = "L%s" % last
		if k in sectionset:
			if len(sectionset)<=1:
				print("""<td class="%sS">%s &#8722;</td>""" % (last,sectiondef[k]))
			else:
				print("""<td class="%sS"><a href="%s">%s</a> <a href="%s">&#8722;</a></td>""" % (last,createlink({"sections":k}),sectiondef[k],createlink({"sections":"|".join(sectionset-set([k]))})))
			last="S"
		else:
			print("""<td class="%sU"><a href="%s">%s</a> <a href="%s">+</a></td>""" % (last,createlink({"sections":k}),sectiondef[k],createlink({"sections":"|".join(sectionset|set([k]))})))
			last="U"
	print("""</tr>""")
	print("""</table></td>""")
	print("""<td class="FILLER" style="white-space:nowrap;">""")
	#print("""<a href="http://jigsaw.w3.org/css-validator/check/referer"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" /></a>""")
	#print("""<a href="http://validator.w3.org/check?uri=referer"><img style="border:0;width:88px;height:31px" src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Strict" /></a>""")
	print("""</td>""")
	print("""</tr>""")
	print("""</table>""")
	print("""</div>""")

	#print """<div id="footer">
	#Moose File System by Jakub Kruszona-Zawadzki
	#</div>
	#"""

	print("""<div id="container">""")

needseparator = 0

if leaderfound==0:
	if cgimode:
		out = []
		out.append("""<table class="FR" cellspacing="0">""")
		if len(masterlist)==0:
			out.append("""	<tr>""")
			out.append("""		<td align="center">""")
			out.append("""			<span class="ERROR">Can't find masters (resolve given name) !!!</span><br />""")
			out.append("""			<form method="GET">""")
			out.append("""				Input your DNS master name: <input type="text" name="masterhost" value="%s" size="100">""" % (masterhost))
			for i in createinputs(["masterhost"]):
				out.append("""				%s""" % (i))
			out.append("""				<input type="submit" value="Try it !!!">""")
			out.append("""			</form>""")
			out.append("""		</td>""")
			out.append("""	</tr>""")
		elif electfound:
			out.append("""	<tr>""")
			out.append("""		<td align="center">""")
			out.append("""			<span class="ERROR">Leader master server not found, but there is an elect, so make sure that all chnunkservers are running - elect should became a leader soon</span><br />""")
			out.append("""		</td>""")
			out.append("""	</tr>""")
		elif followerfound:
			out.append("""	<tr><td align="center"><span class="ERROR">Leader master server not found !!!</span><br /><button type="button" onclick="document.location.href='%s'">click here to try to resolve this problem</button></td></tr>""" % createlink({"MAsupervisor":"true"}))
		else:
			out.append("""	<tr>""")
			out.append("""		<td align="center">""")
			out.append("""			<span class="ERROR">Can't find working masters !!!</span><br />""")
			out.append("""			<form method="GET">""")
			out.append("""				Input your DNS master name: <input type="text" name="masterhost" value="%s" size="100"><br />""" % (masterhost))
			out.append("""				Input your master-client port number: <input type="text" name="masterport" value="%u" size="5"><br />""" % (masterport))
			out.append("""				Input your master-control port number: <input type="text" name="mastercontrolport" value="%u" size="5"><br />""" % (mastercontrolport))
			for i in createinputs(["masterhost","masterport","mastercontrolport"]):
				out.append("""				%s""" % (i))
			out.append("""				<input type="submit" value="Try it !!!">""")
			out.append("""			</form>""")
			out.append("""		</td>""")
			out.append("""	</tr>""")
		out.append("""</table>""")
		print("\n".join(out))
	else:
		if len(masterlist)==0:
			print("""Can't find masters (resolve '%s') !!!""" % (masterhost))
		elif electfound:
			print("Leader master server not found, but there is an elect, so make sure that all chnunkservers are running - elect should became a leader soon")
		elif followerfound:
			print("Leader master server not found !!! - maybe you should run 'mfssupervisor -f -x -h %s -p %u'" % (masterhost,mastercontrolport))
		else:
			print("Working master servers not found !!! - maybe you are using wrong port number or wrong dns name")
	needseparator=1
	sectionset = set(("IN",))
	sectionsubset = ["IM"] # used only in climode - in cgimode turn on all subsections

# parse cgi parameters
if cgimode:
	try:
		INmatrix = int(fields.getvalue("INmatrix"))
	except Exception:
		INmatrix = 0
	try:
		IMorder = int(fields.getvalue("IMorder"))
	except Exception:
		IMorder = 0
	try:
		IMrev = int(fields.getvalue("IMrev"))
	except Exception:
		IMrev = 0
	try:
		MForder = int(fields.getvalue("MForder"))
	except Exception:
		MForder = 0
	try:
		MFrev = int(fields.getvalue("MFrev"))
	except Exception:
		MFrev = 0
	try:
		MFlimit = int(fields.getvalue("MFlimit"))
	except Exception:
		MFlimit = 100
	try:
		CSorder = int(fields.getvalue("CSorder"))
	except Exception:
		CSorder = 0
	try:
		CSrev = int(fields.getvalue("CSrev"))
	except Exception:
		CSrev = 0
	try:
		MBorder = int(fields.getvalue("MBorder"))
	except Exception:
		MBorder = 0
	try:
		MBrev = int(fields.getvalue("MBrev"))
	except Exception:
		MBrev = 0
	try:
		HDorder = int(fields.getvalue("HDorder"))
	except Exception:
		HDorder = 0
	try:
		HDrev = int(fields.getvalue("HDrev"))
	except Exception:
		HDrev = 0
	try:
		HDperiod = int(fields.getvalue("HDperiod"))
	except Exception:
		HDperiod = 0
	try:
		HDtime = int(fields.getvalue("HDtime"))
	except Exception:
		HDtime = 0
	try:
		HDaddrname = int(fields.getvalue("HDaddrname"))
	except Exception:
		HDaddrname = 0
	try:
		EXorder = int(fields.getvalue("EXorder"))
	except Exception:
		EXorder = 0
	try:
		EXrev = int(fields.getvalue("EXrev"))
	except Exception:
		EXrev = 0
	try:
		MSorder = int(fields.getvalue("MSorder"))
	except Exception:
		MSorder = 0
	try:
		MSrev = int(fields.getvalue("MSrev"))
	except Exception:
		MSrev = 0
	try:
		MOorder = int(fields.getvalue("MOorder"))
	except Exception:
		MOorder = 0
	try:
		MOrev = int(fields.getvalue("MOrev"))
	except Exception:
		MOrev = 0
	try:
		MOdata = int(fields.getvalue("MOdata"))
	except Exception:
		MOdata = 0
	try:
		QUorder = int(fields.getvalue("QUorder"))
	except Exception:
		QUorder = 0
	try:
		QUrev = int(fields.getvalue("QUrev"))
	except Exception:
		QUrev = 0
	try:
		if "MCdata" in fields:
			MCdata = fields.getvalue("MCdata")
		else:
			MCdata = ""
	except Exception:
		MCdata = ""
	try:
		if "CCdata" in fields:
			CCdata = fields.getvalue("CCdata")
		else:
			CCdata = ""
	except Exception:
		CCdata = ""
else:
	# fix order id's
	if CSorder>=2:
		CSorder+=1
	if leaderfound and leaderconn.version_less_than(1,7,25) and CSorder>=4:
		CSorder+=1
	if leaderfound and leaderconn.version_less_than(1,6,28) and CSorder>=5:
		CSorder+=1
	if CSorder>=6 and CSorder<=9:
		CSorder+=4
	elif CSorder>=10 and CSorder<=13:
		CSorder+=10

	if MBorder>=2:
		MBorder+=1

	if HDorder>=13 and HDorder<=15:
		HDorder+=7

	if leaderfound and leaderconn.version_less_than(1,7,0) and EXorder>=10:
		EXorder+=1

	if MSorder>=3:
		MSorder+=1
	if leaderfound and leaderconn.version_less_than(1,7,0) and MSorder>=10:
		MSorder+=1
	if MSorder==0:
		MSorder=2

	if MOorder==2:
		MOorder = 3
	elif MOorder>=3 and MOorder<=18:
		MOorder += 97
	elif MOorder==19:
		MOorder = 150
	elif MOorder!=1:
		MOorder = 0

	if QUorder>=2 and QUorder<=6:
		QUorder += 8
	elif QUorder>=7 and QUorder<=10:
		QUorder += 14
	elif QUorder>=11 and QUorder<=22:
		QUorder = (lambda x: x[0]+x[1]*10)(divmod(QUorder-11,3))+31
	elif QUorder<1 or QUorder>22:
		QUorder = 0


if "IN" in sectionset:
	if cgimode and MFS_MESSAGE:
		if needseparator:
			print("""<br/>""")
		else:
			needseparator=1
		out = []
		out.append("""<table class="FR" cellspacing="0">""")
		out.append("""<tr><th>Notice</th></tr>""")
		out.append("""<tr><td>You are currently using GPL version of MooseFS. If you want to find out what great features are available in MooseFS Pro go to <a href="http://moosefs.com/products.html">http://moosefs.com/products.html</a></td></tr>""")
		out.append("""</table>""")
		print("\n".join(out))

	if "IM" in sectionsubset and len(masterlistinfo)>0:
		try:
			if needseparator:
				if cgimode:
					print("""<br/>""")
				else:
					print("")
			else:
				needseparator=1
			if cgimode:
				out = []
				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmasters" cellspacing="0">""")
				out.append("""	<tr><th colspan="10">Metadata Servers (masters)</th></tr>""")
				out.append("""	<tr>""")
				out.append("""		<th class="acid_tab_enumerate">#</th>""")
				out.append("""		<th>ip</th>""")
				out.append("""		<th>version</th>""")
				out.append("""		<th>state</th>""")
				out.append("""		<th>metadata version</th>""")
				out.append("""		<th>RAM used</th>""")
				out.append("""		<th>CPU used</th>""")
				out.append("""		<th>last successful metadata save</th>""")
				out.append("""		<th>last metadata save duration</th>""")
				out.append("""		<th>last metadata save status</th>""")
				out.append("""	</tr>""")
			elif ttymode:
				tab = Tabble("Metadata Servers",9,"r")
				tab.header("ip","version","state","metadata version","RAM used","CPU used","last meta save","last save duration","last save status")
			else:
				tab = Tabble("metadata servers",9)
			masterstab = []
			for sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus in masterlistinfo:
				if IMorder==1:
					sf = sortip
				elif IMorder==2:
					sf = sortver
				elif IMorder==3:
					sf = statecolor
				elif IMorder==4:
					sf = metaversion
				elif IMorder==5:
					sf = memusage
				elif IMorder==6:
					sf = syscpu+usercpu
				elif IMorder==7:
					sf = lastsuccessfulstore
				elif IMorder==8:
					sf = lastsaveseconds
				elif IMorder==9:
					sf = lastsavestatus
				else:
					sf = 0
				masterstab.append((sf,sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus))

			masterstab.sort()
			if IMrev:
				masterstab.reverse()

			for sf,sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus in masterstab:
				if cgimode:
					if leaderconn!=None and leaderconn.is_pro() and not strver.endswith(" PRO"):
						verclass = "BADVERSION"
					elif leaderconn!=None and leaderconn.sort_ver() > sortver:
						verclass = "LOWERVERSION"
					elif leaderconn!=None and leaderconn.sort_ver() < sortver:
						verclass = "HIGHERVERSION"
					else:
						verclass = "OKVERSION"
					out.append("""	<tr>""")
					out.append("""		<td align="right"></td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,strip,sortver,verclass,strver))
					out.append("""		<td align="center"><span class="STATECOLOR%u">%s</span></td>""" % (statecolor,statestr))
					out.append("""		<td align="right">%s</td>""" % (decimal_number(metaversion)))
					if memusage>0:
						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
					else:
						out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS or can't be obtained from server">not available</td>""")
					if syscpu>0 or usercpu>0:
						out.append("""		<td align="center"><a style="cursor:default" title="all:%.7f%% sys:%.7f%% user:%.7f%%">all:%.2f%%&nbsp;sys:%.2f%%&nbsp;user:%.2f%%</a></td>""" % (syscpu+usercpu,syscpu,usercpu,syscpu+usercpu,syscpu,usercpu))
					else:
						out.append("""		<td align="center"><a style="cursor:default" title="obtaining cpu usage is not supported by your OS or can't be obtained from server">not available</td>""")
					if lastsuccessfulstore>0:
						out.append("""		<td align="center">%s</td>""" % time.asctime(time.localtime(lastsuccessfulstore)))
						out.append("""		<td align="center"><a style="cursor:default" title="%s">%s</a></td>""" % (timeduration_to_fullstr(lastsaveseconds),timeduration_to_shortstr(lastsaveseconds)))
					else:
						out.append("""		<td align="center">-</td><td align="center">-</td>""")
					if lastsuccessfulstore>0 or lastsavestatus>0:
						out.append("""		<td align="center"><span class="%s">%s</span></td>""" % ("SUCCESS" if lastsavestatus==0 or lastsavestatus==1 else "WARNING" if lastsavestatus==2 else "ERROR","Saved in background" if lastsavestatus==0 else "Downloaded from other master" if lastsavestatus==1 else "Saved in foreground" if lastsavestatus==2 else "Unknown status: %u" % lastsavestatus))
					else:
						out.append("""		<td align="center">-</td>""")
					out.append("""	</tr>""")
				else:
					clist = [strip,strver,(statestr,"c%u" % statecolor),decimal_number(metaversion)]
					if memusage>0:
						if ttymode:
							clist.append(humanize_number(memusage," "))
						else:
							clist.append(memusage)
					else:
						clist.append("not available")
					if syscpu>0 or usercpu>0:
						if ttymode:
							clist.append("all:%.2f%% sys:%.2f%% user:%.2f%%" % (syscpu+usercpu,syscpu,usercpu))
						else:
							clist.append("all:%.7f%% sys:%.7f%% user:%.7f%%" % (syscpu+usercpu,syscpu,usercpu))
					else:
						clist.append("not available")
					if lastsuccessfulstore>0:
						if ttymode:
							clist.append(time.asctime(time.localtime(lastsuccessfulstore)))
							clist.append(timeduration_to_shortstr(lastsaveseconds))
						else:
							clist.append(lastsuccessfulstore)
							clist.append("%.3f" % lastsaveseconds)
					else:
						clist.append("-")
						clist.append("-")
					if lastsuccessfulstore>0 or lastsavestatus>0:
						clist.append(("Saved in background","4") if lastsavestatus==0 else ("Downloaded from other master","4") if lastsavestatus==1 else ("Saved in foreground","2") if lastsavestatus==2 else ("Unknown status: %u" % lastsavestatus,"1"))
					else:
						clist.append("-")
					tab.append(*clist)

			if len(masterstab)==0:
				if cgimode:
					out.append("""	<tr><td colspan="10">Servers not found !!! - check your DNS</td></tr>""")
				else:
					tab.append(("""Servers not found !!! - check your DNS""","c",9))

			if cgimode:
				out.append("""</table>""")
			if cgimode:
				print("\n".join(out))
			else:
				print(tab)
		except Exception:
			print_exception()


	if "IG" in sectionsubset:
		try:
			if needseparator:
				if cgimode:
					print("""<br/>""")
				else:
					print("")
			else:
				needseparator=1
			length = len(leaderinfo)
			if length==68:
				v1,v2,v3,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies = struct.unpack(">HBBQQQLQLLLLLLL",leaderinfo)
				strver,sortver = version_str_and_sort((v1,v2,v3))
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="13">Info</th></tr>""")
					out.append("""	<tr>""")
					out.append("""		<th>version</th>""")
					out.append("""		<th>total space</th>""")
					out.append("""		<th>avail space</th>""")
					out.append("""		<th>trash space</th>""")
					out.append("""		<th>trash files</th>""")
					out.append("""		<th>sustained space</th>""")
					out.append("""		<th>sustained files</th>""")
					out.append("""		<th>all fs objects</th>""")
					out.append("""		<th>directories</th>""")
					out.append("""		<th>files</th>""")
					out.append("""		<th>chunks</th>""")
					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<td align="center">%s</td>""" % strver)
					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
					out.append("""		<td align="right">%u</td>""" % trfiles)
					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
					out.append("""		<td align="right">%u</td>""" % refiles)
					out.append("""		<td align="right">%u</td>""" % nodes)
					out.append("""		<td align="right">%u</td>""" % dirs)
					out.append("""		<td align="right">%u</td>""" % files)
					out.append("""		<td align="right">%u</td>""" % chunks)
					out.append("""		<td align="right">%u</td>""" % allcopies)
					out.append("""		<td align="right">%u</td>""" % tdcopies)
					out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				else:
					if ttymode:
						tab = Tabble("Master Info",2)
					else:
						tab = Tabble("master info",2)
					tab.defattr("l","r")
					tab.append("master version",strver)
					if ttymode:
						tab.append("total space",humanize_number(total," "))
						tab.append("avail space",humanize_number(avail," "))
						tab.append("trash space",humanize_number(trspace," "))
					else:
						tab.append("total space",total)
						tab.append("avail space",avail)
						tab.append("trash space",trspace)
					tab.append("trash files",trfiles)
					if ttymode:
						tab.append("sustained space",humanize_number(respace," "))
					else:
						tab.append("sustained space",respace)
					tab.append("sustained files",refiles)
					tab.append("all fs objects",nodes)
					tab.append("directories",dirs)
					tab.append("files",files)
					tab.append("chunks",chunks)
					tab.append("all chunk copies",allcopies)
					tab.append("regular chunk copies",tdcopies)
					print(tab)
			elif length==76:
				v1,v2,v3,memusage,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies = struct.unpack(">HBBQQQQLQLLLLLLL",leaderinfo)
				strver,sortver = version_str_and_sort((v1,v2,v3))
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="14">Info</th></tr>""")
					out.append("""	<tr>""")
					out.append("""		<th>version</th>""")
					out.append("""		<th>RAM used</th>""")
					out.append("""		<th>total space</th>""")
					out.append("""		<th>avail space</th>""")
					out.append("""		<th>trash space</th>""")
					out.append("""		<th>trash files</th>""")
					out.append("""		<th>sustained space</th>""")
					out.append("""		<th>sustained files</th>""")
					out.append("""		<th>all fs objects</th>""")
					out.append("""		<th>directories</th>""")
					out.append("""		<th>files</th>""")
					out.append("""		<th>chunks</th>""")
					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<td align="center">%s</td>""" % strver)
					if memusage>0:
						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
					else:
						out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS">not available</td>""")
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
					out.append("""		<td align="center">%u</td>""" % trfiles)
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
					out.append("""		<td align="center">%u</td>""" % refiles)
					out.append("""		<td align="center">%u</td>""" % nodes)
					out.append("""		<td align="center">%u</td>""" % dirs)
					out.append("""		<td align="center">%u</td>""" % files)
					out.append("""		<td align="center">%u</td>""" % chunks)
					out.append("""		<td align="center">%u</td>""" % allcopies)
					out.append("""		<td align="center">%u</td>""" % tdcopies)
					out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				else:
					if ttymode:
						tab = Tabble("Master Info",2)
					else:
						tab = Tabble("master info",2)
					tab.defattr("l","r")
					tab.append("master version",strver)
					if memusage>0:
						if ttymode:
							tab.append("RAM used",humanize_number(memusage," "))
						else:
							tab.append("RAM used",memusage)
					else:
						tab.append("RAM used","not available")
					if ttymode:
						tab.append("total space",humanize_number(total," "))
						tab.append("avail space",humanize_number(avail," "))
						tab.append("trash space",humanize_number(trspace," "))
					else:
						tab.append("total space",total)
						tab.append("avail space",avail)
						tab.append("trash space",trspace)
					tab.append("trash files",trfiles)
					if ttymode:
						tab.append("sustained space",humanize_number(respace," "))
					else:
						tab.append("sustained space",respace)
					tab.append("sustained files",refiles)
					tab.append("all fs objects",nodes)
					tab.append("directories",dirs)
					tab.append("files",files)
					tab.append("chunks",chunks)
					tab.append("all chunk copies",allcopies)
					tab.append("regular chunk copies",tdcopies)
					print(tab)
			elif length==101 or length==121:
				v1,v2,v3,memusage,syscpu,usercpu,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies,lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">HBBQQQQQQLQLLLLLLLLLB",leaderinfo[:101])
				strver,sortver = version_str_and_sort((v1,v2,v3))
				syscpu/=10000000.0
				usercpu/=10000000.0
				if leaderconn.version_at_least(2,0,14):
					lastsaveseconds = lastsaveseconds / 1000.0
				if cgimode:
					out = []
					if length==101:
						out.append("""<table class="FR" cellspacing="0">""")
						out.append("""	<tr><th colspan="6">General Info</th></tr>""")
						out.append("""	<tr>""")
						out.append("""		<th>version</th>""")
						out.append("""		<th>RAM used</th>""")
						out.append("""		<th>CPU used</th>""")
						out.append("""		<th>last successful metadata save</th>""")
						out.append("""		<th>last metadata save duration</th>""")
						out.append("""		<th>last metadata save status</th>""")
						out.append("""	</tr>""")
						out.append("""	<tr>""")
						out.append("""		<td align="center">%s</td>""" % strver)
						if memusage>0:
							out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
						else:
							out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS">not available</td>""")
						if syscpu>0 or usercpu>0:
							out.append("""		<td align="center"><a style="cursor:default" title="all:%.7f%% sys:%.7f%% user:%.7f">all:%.2f%%&nbsp;sys:%.2f%%&nbsp;user:%.2f%%</a></td>""" % (syscpu+usercpu,syscpu,usercpu,syscpu+usercpu,syscpu,usercpu))
						else:
							out.append("""		<td align="center"><a style="cursor:default" title="obtaining cpu usage is not supported by your OS">not available</td>""")
						if lastsuccessfulstore>0:
							out.append("""		<td align="center">%s</td>""" % time.asctime(time.localtime(lastsuccessfulstore)))
							out.append("""		<td align="center"><a style="cursor:default" title="%s">%s</a></td>""" % (timeduration_to_fullstr(lastsaveseconds),timeduration_to_shortstr(lastsaveseconds)))
						else:
							out.append("""		<td align="center">-</td><td align="center">-</td>""")
						if lastsuccessfulstore>0 or lastsavestatus>0:
							out.append("""		<td align="center"><span class="%s">%s</span></td>""" % ("SUCCESS" if lastsavestatus==0 else "ERROR","OK" if lastsavestatus==0 else "ERROR (%u)" % lastsavestatus))
						else:
							out.append("""		<td align="center">-</td>""")
						out.append("""	</tr>""")
						out.append("""</table>""")
						out.append("""<br/>""")
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="12">Metadata Info</th></tr>""")
					out.append("""	<tr>""")
					out.append("""		<th>total space</th>""")
					out.append("""		<th>avail space</th>""")
					out.append("""		<th>trash space</th>""")
					out.append("""		<th>trash files</th>""")
					out.append("""		<th>sustained space</th>""")
					out.append("""		<th>sustained files</th>""")
					out.append("""		<th>all fs objects</th>""")
					out.append("""		<th>directories</th>""")
					out.append("""		<th>files</th>""")
					out.append("""		<th>chunks</th>""")
					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
					out.append("""		<td align="center">%u</td>""" % trfiles)
					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
					out.append("""		<td align="center">%u</td>""" % refiles)
					out.append("""		<td align="center">%u</td>""" % nodes)
					out.append("""		<td align="center">%u</td>""" % dirs)
					out.append("""		<td align="center">%u</td>""" % files)
					out.append("""		<td align="center">%u</td>""" % chunks)
					out.append("""		<td align="center">%u</td>""" % allcopies)
					out.append("""		<td align="center">%u</td>""" % tdcopies)
					out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				else:
					if ttymode:
						tab = Tabble("Master Info",2)
					else:
						tab = Tabble("master info",2)
					tab.defattr("l","r")
					tab.append("master version",strver)
					if memusage>0:
						if ttymode:
							tab.append("RAM used",humanize_number(memusage," "))
						else:
							tab.append("RAM used",memusage)
					else:
						tab.append("RAM used","not available")
					if syscpu>0 or usercpu>0:
						if ttymode:
							tab.append("CPU used","%.2f%%" % (syscpu+usercpu))
							tab.append("CPU used (system)","%.2f%%" % (syscpu))
							tab.append("CPU used (user)","%.2f%%" % (usercpu))
						else:
							tab.append("CPU used (system)","%.9f" % (syscpu/100.0))
							tab.append("CPU used (user)","%.9f" % (usercpu/100.0))
					else:
						tab.append("CPU used","not available")
					if ttymode:
						tab.append("total space",humanize_number(total," "))
						tab.append("avail space",humanize_number(avail," "))
						tab.append("trash space",humanize_number(trspace," "))
					else:
						tab.append("total space",total)
						tab.append("avail space",avail)
						tab.append("trash space",trspace)
					tab.append("trash files",trfiles)
					if ttymode:
						tab.append("sustained space",humanize_number(respace," "))
					else:
						tab.append("sustained space",respace)
					tab.append("sustained files",refiles)
					tab.append("all fs objects",nodes)
					tab.append("directories",dirs)
					tab.append("files",files)
					tab.append("chunks",chunks)
					tab.append("all chunk copies",allcopies)
					tab.append("regular chunk copies",tdcopies)
					if lastsuccessfulstore>0:
						if ttymode:
							tab.append("last successful store",time.asctime(time.localtime(lastsuccessfulstore)))
							tab.append("last save duration",timeduration_to_shortstr(lastsaveseconds))
						else:
							tab.append("last successful store",lastsuccessfulstore)
							tab.append("last save duration","%.3f" % lastsaveseconds)
					else:
						tab.append("last successful store","-")
						tab.append("last save duration","-")
					if lastsuccessfulstore>0 or lastsavestatus>0:
						tab.append("last save status",("Saved in background","4") if lastsavestatus==0 else ("Downloaded from another master","4") if lastsavestatus==1 else ("Saved in foreground","2") if lastsavestatus==2 else ("Unknown status: %u" % lastsavestatus,"1"))
					else:
						tab.append("last save status","-")
					print(tab)
			else:
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><td align="left">unrecognized answer from MFSmaster</td></tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				else:
					print("unrecognized answer from MFSmaster")
		except Exception:
			print_exception()

	if "MU" in sectionsubset and leaderconn.version_at_least(1,7,16):
		if needseparator:
			if cgimode:
				print("""<br/>""")
			else:
				print("")
		else:
			needseparator=1
		try:
			data,length = leaderconn.command(CLTOMA_MEMORY_INFO,MATOCL_MEMORY_INFO)
			if length>=176 and length%16==0:
				memusage = struct.unpack(">QQQQQQQQQQQQQQQQQQQQQQ",data[:176])
				memlabels = ["chunk hash","chunks","cs lists","edge hash","edges","node hash","nodes","deleted nodes","chunk tabs","symlinks","quota"]
				abrlabels = ["c.h.","c.","c.l.","e.h.","e.","n.h.","n.","d.n.","c.t.","s.","q."]
				totalused = 0
				totalallocated = 0
				for i in xrange(11):
					totalused += memusage[1+i*2]
					totalallocated += memusage[i*2]
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="%d">Memory usage detailed info</th></tr>""" % (len(memlabels)+2))
					out.append("""	<tr><th></th>""")
					for i in xrange(11):
						out.append("""		<th>%s</th>""" % memlabels[i])
					out.append("""	<th>total</th></tr>""")
					out.append("""	<tr><th align="center">used</th>""")
					for i in xrange(11):
						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage[1+i*2]),humanize_number(memusage[1+i*2],"&nbsp;")))
					out.append("""	<td align="center"><a style="cursor:default" title="%s B">%s</a></td></tr>""" % (decimal_number(totalused),humanize_number(totalused,"&nbsp;")))
					out.append("""	<tr><th align="center">allocated</th>""")
					for i in xrange(11):
						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage[i*2]),humanize_number(memusage[i*2],"&nbsp;")))
					out.append("""	<td align="center"><a style="cursor:default" title="%s B">%s</a></td></tr>""" % (decimal_number(totalallocated),humanize_number(totalallocated,"&nbsp;")))
					out.append("""	<tr><th align="center">utilization</th>""")
					for i in xrange(11):
						if memusage[i*2]:
							percent = "%.2f %%" % (100.0 * memusage[1+i*2] / memusage[i*2])
						else:
							percent = "-"
						out.append("""		<td align="center">%s</td>""" % percent)
					if totalallocated:
						percent = "%.2f %%" % (100.0 * totalused / totalallocated)
					else:
						percent = "-"
					out.append("""	<td align="center">%s</td></tr>""" % percent)
					if totalallocated>0:
						out.append("""	<tr><th align="center">distribution</th>""")
						for i in xrange(11):
							tpercent = "%.2f %%" % (100.0 * memusage[i*2] / totalallocated)
							out.append("""		<td align="center">%s</td>""" % tpercent)
						out.append("""	<td>-</td></tr>""")
						out.append("""  <tr><th align="center">distribution bar</th>""")
						out.append("""		<td colspan="%d" class="NOPADDING">""" % (len(memlabels)+1))
						out.append("""			<table width="100%" cellspacing="0" style="border:0px;" id="bar"><tr>""")
						memdistribution = []
						other = 0.0
						for i,(label,abr) in enumerate(zip(memlabels,abrlabels)):
							tpercent = (100.0 * memusage[i*2] / totalallocated)
							if tpercent>1.0:
								memdistribution.append((tpercent,label,abr))
							else:
								other+=tpercent
						memdistribution.sort()
						memdistribution.reverse()
						if other>0:
							memdistribution.append((other,None,None))
						cl = "FIRST"
						labels = []
						tooltips = []
						for i,(percent,label,abr) in enumerate(memdistribution):
							if label:
								if percent>10.0:
									out.append("""				<td style="width:%.2f%%;" class="MEMDIST%d MEMDIST%s" align="center"><a style="cursor:default;" title="%s (%.2f %%)">%s</a></td>""" % (percent,i,cl,label,percent,label))
								elif percent>3.0:
									out.append("""				<td style="width:%.2f%%;" class="MEMDIST%d MEMDIST%s" align="center"><a style="cursor:default;" title="%s (%.2f %%)">%s</a></td>""" % (percent,i,cl,label,percent,abr))
								else:
									out.append("""				<td style="width:%.2f%%;" class="MEMDIST%d MEMDIST%s" align="center"><a style="cursor:default;" title="%s (%.2f %%)">%s</a></td>""" % (percent,i,cl,label,percent,"#"))
								labels.append(label)
								tooltips.append("%s (%.2f %%)" % (label,percent))
							else:
								out.append("""				<td style="width:%.2f%%;" class="MEMDISTOTHER MEMDIST%s"></td>""" % (percent,cl))
								labels.append("others")
								tooltips.append("other memory segments (%.2f %%)" % (percent))
							cl = "MID"
						out.append("""			</tr></table>""")
						out.append("""<script type="text/javascript">""")
						out.append("""<!--//--><![CDATA[//><!--""")
						out.append("""	var bar_labels = [%s];""" % ",".join(map(repr,labels)))
						out.append("""	var bar_tooltips = [%s];""" % ",".join(map(repr,tooltips)))
						out.append("""//--><!]]>""")
						out.append("""</script>""")
						out.append("""<script type="text/javascript">
<!--//--><![CDATA[//><!--
	function bar_refresh() {
		var b = document.getElementById("bar");
		var i,j,x;
		if (b) {
			var x = b.getElementsByTagName("td");
			for (i=0 ; i<x.length ; i++) {
				x[i].innerHTML = "";
			}
			for (i=0 ; i<x.length ; i++) {
				var width = x[i].clientWidth;
				var label = bar_labels[i];
				var tooltip = bar_tooltips[i];
				x[i].innerHTML = "<a title='" + tooltip + "'>" + label + "</a>";
				if (width<x[i].clientWidth) {
					x[i].innerHTML = "<a title='" + tooltip + "'>&#8230;</a>";
					if (width<x[i].clientWidth) {
						x[i].innerHTML = "<a title='" + tooltip + "'>&#8226;</a>";
						if (width<x[i].clientWidth) {
							x[i].innerHTML = "<a title='" + tooltip + "'>.</a>";
							if (width<x[i].clientWidth) {
								x[i].innerHTML = "";
							}
						}
					} else {
						for (j=1 ; j<bar_labels[i].length-1 ; j++) {
							x[i].innerHTML = "<a title='" + tooltip + "'>"+label.substring(0,j) + "&#8230;</a>";
							if (width<x[i].clientWidth) {
								break;
							}
						}
						x[i].innerHTML = "<a title='" + tooltip + "'>" + label.substring(0,j-1) + "&#8230;</a>";
					}
				}
			}
		}
	}

	function bar_add_event(obj,type,fn) {
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
		} else if (obj.attachEvent) {
			obj.attachEvent('on'+type, fn);
		}
	}

	bar_add_event(window,"load",bar_refresh);
	bar_add_event(window,"resize",bar_refresh);
//--><!]]>
</script>""")
						out.append("""		</td>""")
						out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				else:
					if ttymode:
						tab = Tabble("Memory Usage Detailed Info",5)
						tab.defattr("l","r","r","r","r")
						tab.header("object name","memory used","memory allocated","utilization percent","percent of total allocated memory")
					else:
						tab = Tabble("memory usage detailed info",3)
						tab.defattr("l","r","r")
						tab.header("object name","memory used","memory allocated")
					for i in xrange(11):
						if ttymode:
							if memusage[i*2]>0:
								upercent = "%.2f %%" % (100.0 * memusage[1+i*2] / memusage[i*2])
							else:
								upercent = "-"
							if totalallocated:
								tpercent = "%.2f %%" % (100.0 * memusage[i*2] / totalallocated)
							else:
								tpercent = "-"
							tab.append(memlabels[i],humanize_number(memusage[1+i*2]," "),humanize_number(memusage[i*2]," "),upercent,tpercent)
						else:
							tab.append(memlabels[i],memusage[1+i*2],memusage[i*2])
					if ttymode:
						tab.append(("---","",5))
						percent = 100.0 * totalused / totalallocated
						tab.append("total",humanize_number(totalused," "),humanize_number(totalallocated," "),"%.2f %%" % percent,"-")
					print(tab)
		except Exception:
			print_exception()

	if "IC" in sectionsubset:
		if needseparator:
			if cgimode:
				print("""<br/>""")
			else:
				print("")
		else:
			needseparator=1
		try:
			if leaderconn.version_less_than(1,7,0):
				data,length = leaderconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX,struct.pack(">B",0))
				if length==484:
					matrix = []
					matrix.append([])
					for i in range(11):
						matrix[0].append(list(struct.unpack(">LLLLLLLLLLL",data[i*44:i*44+44])))
					data,length = leaderconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX,struct.pack(">B",1))
					if length==484:
						matrix.append([])
						for i in range(11):
							matrix[1].append(list(struct.unpack(">LLLLLLLLLLL",data[i*44:i*44+44])))
				progressstatus = 0
			else:
				data,length = leaderconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX)
				if length==969:
					progressstatus = struct.unpack(">B",data[0:1])[0]
					matrix = ([],[])
					for x in range(2):
						for i in range(11):
							matrix[x].append(list(struct.unpack(">LLLLLLLLLLL",data[1+x*484+i*44:45+x*484+i*44])))
			progressstr = "disconnections" if (progressstatus==1) else "connections" if (progressstatus==2) else "connections and disconnections"
			if len(matrix)==2:
				if cgimode:
					out = []
					out.append("""<table class="acid_tab acid_tab_storageid_mfsmatrix" cellspacing="0" id="mfsmatrix">""")
					out.append("""	<tr><th colspan="13">""")
					out.append("""		<span class="matrix_vis0">All chunks state matrix (counts 'regular' hdd space and 'marked for removal' hdd space : <a href="javascript:acid_tab.switchdisplay('mfsmatrix','matrix_vis',1)" class="VISIBLELINK">switch to 'regular'</a>)</span>""")
					out.append("""		<span class="matrix_vis1">Regular chunks state matrix (counts only 'regular' hdd space : <a href="javascript:acid_tab.switchdisplay('mfsmatrix','matrix_vis',0)" class="VISIBLELINK">switch to 'all'</a>)</span>""")
					out.append("""	</th></tr>""")
					if progressstatus>0:
						out.append("""<tr><th colspan="13"><span class="ERROR">Warning: counters may not be valid - %s in progress</span></th></tr>""" % progressstr)
					out.append("""	<tr>""")
					out.append("""		<th rowspan="2" class="PERC4 acid_tab_skip">goal</th>""")
					out.append("""		<th colspan="12" class="PERC96 acid_tab_skip">valid copies</th>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<th class="PERC8 acid_tab_skip">0</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">1</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">2</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">3</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">4</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">5</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">6</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">7</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">8</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">9</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">10+</th>""")
					out.append("""		<th class="PERC8 acid_tab_skip">all</th>""")
					out.append("""	</tr>""")
				elif ttymode:
					if INmatrix==0:
						tab = Tabble("All chunks state matrix",13,"r")
					else:
						tab = Tabble("Regular chunks state matrix",13,"r")
					if progressstatus>0:
						tab.header(("Warning: counters may not be valid - %s in progress" % progressstr,"1c",13))
						tab.header(("---","",13))
					tab.header("",("valid copies","",12))
					tab.header("goal",("---","",12))
					tab.header("","    0    ","    1    ","    2    ","    3    ","    4    ","    5    ","    6    ","    7    ","    8    ","    9    ","   10+   ","   all   ")
				else:
					out = []
					if INmatrix==0:
						mtypeprefix=("all chunks matrix:%s" % plaintextseparator)
					else:
						mtypeprefix=("regular chunks matrix:%s" % plaintextseparator)
				classsum = []
				classsum.append(7*[0])
				classsum.append(7*[0])
				sumlist = []
				sumlist.append(11*[0])
				sumlist.append(11*[0])
				for goal in range(11):
					if cgimode:
						out.append("""	<tr>""")
						if goal==10:
							out.append("""		<th align="center" class="acid_tab_skip">10+</th>""")
						else:
							out.append("""		<th align="center" class="acid_tab_skip">%u</th>""" % goal)
					else:
						if goal==10:
							clist = ["10+"]
						else:
							clist = [goal]
					for vc in range(11):
						if goal==0:
							if vc==0:
								cl = "DELETEREADY"
								clidx = 6
							else:
								cl = "DELETEPENDING"
								clidx = 5
						elif vc==0:
							cl = "MISSING"
							clidx = 0
						elif vc>goal:
							cl = "OVERGOAL"
							clidx = 4
						elif vc<goal:
							if vc==1:
								cl = "ENDANGERED"
								clidx = 1
							else:
								cl = "UNDERGOAL"
								clidx = 2
						else:
							cl = "NORMAL"
							clidx = 3
						classsum[0][clidx]+=matrix[0][goal][vc]
						classsum[1][clidx]+=matrix[1][goal][vc]
						if cgimode:
							out.append("""		<td align="right" class="acid_tab_skip">""")
							if matrix[0][goal][vc]>0:
								out.append("""			<span class="%s matrix_vis0">%u</span>""" % (cl,matrix[0][goal][vc]))
							if matrix[1][goal][vc]>0:
								out.append("""			<span class="%s matrix_vis1">%u</span>""" % (cl,matrix[1][goal][vc]))
							out.append("""		</td>""")
						elif ttymode:
							if matrix[INmatrix][goal][vc]>0:
								clist.append((matrix[INmatrix][goal][vc],"1234678"[clidx]))
							else:
								clist.append("-")
						else:
							if matrix[INmatrix][goal][vc]>0:
								out.append("""%sgoal/copies/chunks:%s%u%s%u%s%u""" % (mtypeprefix,plaintextseparator,goal,plaintextseparator,vc,plaintextseparator,matrix[INmatrix][goal][vc]))
					if cgimode:
						if goal==0:
							out.append("""		<td align="right" class="acid_tab_skip">""")
							out.append("""			<span class="IGNORE matrix_vis0">%u</span>""" % sum(matrix[0][goal]))
							out.append("""			<span class="IGNORE matrix_vis1">%u</span>""" % sum(matrix[1][goal]))
							out.append("""		</td>""")
						else:
							out.append("""		<td align="right" class="acid_tab_skip">""")
							out.append("""			<span class="matrix_vis0">%u</span>""" % sum(matrix[0][goal]))
							out.append("""			<span class="matrix_vis1">%u</span>""" % sum(matrix[1][goal]))
							out.append("""		</td>""")
						out.append("""	</tr>""")
					elif ttymode:
						clist.append(sum(matrix[INmatrix][goal]))
						tab.append(*clist)
					if goal>0:
						sumlist[0] = [ a + b for (a,b) in zip(sumlist[0],matrix[0][goal])]
						sumlist[1] = [ a + b for (a,b) in zip(sumlist[1],matrix[1][goal])]
				if cgimode:
					out.append("""	<tr>""")
					out.append("""		<th align="center" class="acid_tab_skip">all 1+</th>""")
					for vc in range(11):
						out.append("""		<td align="right" class="acid_tab_skip"><span class="matrix_vis0">%u</span><span class="matrix_vis1">%u</span></td>""" % (sumlist[0][vc],sumlist[1][vc]))
					out.append("""		<td align="right" class="acid_tab_skip"><span class="matrix_vis0">%u</span><span class="matrix_vis1">%u</span></td>""" % (sum(sumlist[0]),sum(sumlist[1])))
					out.append("""	</tr>""")
					out.append("""	<tr><th align="center" class="acid_tab_skip">colors</th><td colspan="12" class="acid_tab_skip">""")
					out.append("""		<span class="matrix_vis0">"""+(" / ".join(["""<span class="%sBOX"></span>&nbsp;-&nbsp;%s (<span class="%s">%u</span>)""" % (cl,desc,cl,classsum[0][clidx]) for clidx,cl,desc in [(0,"MISSING","missing"),(1,"ENDANGERED","endangered"),(2,"UNDERGOAL","undergoal"),(3,"NORMAL","stable"),(4,"OVERGOAL","overgoal"),(5,"DELETEPENDING","pending&nbsp;deletion"),(6,"DELETEREADY","ready&nbsp;to&nbsp;be&nbsp;removed")]]))+"</span>")
					out.append("""		<span class="matrix_vis1">"""+(" / ".join(["""<span class="%sBOX"></span>&nbsp;-&nbsp;%s (<span class="%s">%u</span>)""" % (cl,desc,cl,classsum[1][clidx]) for clidx,cl,desc in [(0,"MISSING","missing"),(1,"ENDANGERED","endangered"),(2,"UNDERGOAL","undergoal"),(3,"NORMAL","stable"),(4,"OVERGOAL","overgoal"),(5,"DELETEPENDING","pending&nbsp;deletion"),(6,"DELETEREADY","ready&nbsp;to&nbsp;be&nbsp;removed")]]))+"</span>")
					out.append("""	</td></tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				elif ttymode:
					clist = ["all 1+"]
					for vc in range(11):
						clist.append(sumlist[INmatrix][vc])
					clist.append(sum(sumlist[INmatrix]))
					tab.append(*clist)
					tab.append(("---","",13))
					#tab.append(("missing: %s%u%s / endangered: %s%u%s / undergoal: %s%u%s / stable: %s%u%s / overgoal: %s%u%s / pending deletion: %s%u%s / to be removed: %s%u%s" % (colorcode[0],classsum[0],ttyreset,colorcode[1],classsum[1],ttyreset,colorcode[2],classsum[2],ttyreset,colorcode[3],classsum[3],ttyreset,colorcode[5],classsum[4],ttyreset,colorcode[6],classsum[5],ttyreset,colorcode[7],classsum[6],ttyreset),"c",13))
					tab.append(("missing: %u / endangered: %u / undergoal: %u / stable: %u / overgoal: %u / pending deletion: %u / to be removed: %u" % (classsum[INmatrix][0],classsum[INmatrix][1],classsum[INmatrix][2],classsum[INmatrix][3],classsum[INmatrix][4],classsum[INmatrix][5],classsum[INmatrix][6]),"c",13))
#							out.append("chunkclass missing: %s%u%s" % (colorcode[0],classsum[0],ttyreset))
#							out.append("chunkclass endangered: %s%u%s" % (colorcode[1],classsum[1],ttyreset))
#							out.append("chunkclass undergoal: %s%u%s" % (colorcode[2],classsum[2],ttyreset))
#							out.append("chunkclass stable: %s%u%s" % (colorcode[3],classsum[3],ttyreset))
#							out.append("chunkclass overgoal: %s%u%s" % (colorcode[4],classsum[4],ttyreset))
#							out.append("chunkclass pending deletion: %s%u%s" % (colorcode[5],classsum[5],ttyreset))
#							out.append("chunkclass to be removed: %s%u%s" % (colorcode[6],classsum[6],ttyreset))
					print(tab)
				else:
					out.append("%schunkclass missing:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][0]))
					out.append("%schunkclass endangered:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][1]))
					out.append("%schunkclass undergoal:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][2]))
					out.append("%schunkclass stable:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][3]))
					out.append("%schunkclass overgoal:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][4]))
					out.append("%schunkclass pending deletion:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][5]))
					out.append("%schunkclass to be removed:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][6]))
					print("\n".join(out))
		except Exception:
			print_exception()

	if "IL" in sectionsubset:
		try:
			if needseparator:
				if cgimode:
					print("""<br/>""")
				else:
					print("")
			else:
				needseparator=1
			data,length = leaderconn.command(CLTOMA_CHUNKSTEST_INFO,MATOCL_CHUNKSTEST_INFO)
			if length==52:
				loopstart,loopend,del_invalid,ndel_invalid,del_unused,ndel_unused,del_dclean,ndel_dclean,del_ogoal,ndel_ogoal,rep_ugoal,nrep_ugoal,rebalnce = struct.unpack(">LLLLLLLLLLLLL",data)
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="8">Chunk operations info</th></tr>""")
					out.append("""	<tr>""")
					out.append("""		<th colspan="2">loop time</th>""")
					out.append("""		<th colspan="4">deletions</th>""")
					out.append("""		<th colspan="2">replications</th>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<th>start</th>""")
					out.append("""		<th>end</th>""")
					out.append("""		<th>invalid</th>""")
					out.append("""		<th>unused</th>""")
					out.append("""		<th>disk clean</th>""")
					out.append("""		<th>over goal</th>""")
					out.append("""		<th>under goal</th>""")
					out.append("""		<th>rebalance</th>""")
					out.append("""	</tr>""")
					if loopstart>0:
						out.append("""	<tr>""")
						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
						out.append("""		<td align="right">%u</td>""" % rebalnce)
						out.append("""	</tr>""")
					else:
						out.append("""	<tr>""")
						out.append("""		<td colspan="8" align="center">no data</td>""")
						out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				elif ttymode:
					tab = Tabble("Chunk operations info",8,"r")
					tab.header(("loop time","",2),("deletions","",4),("replications","",2))
					tab.header(("---","",8))
					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","rebalance")
					if loopstart>0:
						tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),"%u/%u" % (del_invalid,del_invalid+ndel_invalid),"%u/%u" % (del_unused,del_unused+ndel_unused),"%u/%u" % (del_dclean,del_dclean+ndel_dclean),"%u/%u" % (del_ogoal,del_ogoal+ndel_ogoal),"%u/%u" % (rep_ugoal,rep_ugoal+nrep_ugoal),rebalnce)
					else:
						tab.append(("no data","c",8))
					print(tab)
				else:
					out = []
					if loopstart>0:
						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
					else:
						out.append("""chunk loop%sno data""" % plaintextseparator)
					print("\n".join(out))
			elif length==60:
				loopstart,loopend,del_invalid,ndel_invalid,del_unused,ndel_unused,del_dclean,ndel_dclean,del_ogoal,ndel_ogoal,rep_ugoal,nrep_ugoal,rebalnce,locked_unused,locked_used = struct.unpack(">LLLLLLLLLLLLLLL",data)
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="10">Chunk operations info</th></tr>""")
					out.append("""	<tr>""")
					out.append("""		<th colspan="2">loop time</th>""")
					out.append("""		<th colspan="4">deletions</th>""")
					out.append("""		<th colspan="2">replications</th>""")
					out.append("""		<th colspan="2">locked</th>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<th>start</th>""")
					out.append("""		<th>end</th>""")
					out.append("""		<th>invalid</th>""")
					out.append("""		<th>unused</th>""")
					out.append("""		<th>disk clean</th>""")
					out.append("""		<th>over goal</th>""")
					out.append("""		<th>under goal</th>""")
					out.append("""		<th>rebalance</th>""")
					out.append("""		<th>unused</th>""")
					out.append("""		<th>used</th>""")
					out.append("""	</tr>""")
					if loopstart>0:
						out.append("""	<tr>""")
						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
						out.append("""		<td align="right">%u</td>""" % rebalnce)
						out.append("""		<td align="right">%u</td>""" % locked_unused)
						out.append("""		<td align="right">%u</td>""" % locked_used)
						out.append("""	</tr>""")
					else:
						out.append("""	<tr>""")
						out.append("""		<td colspan="10" align="center">no data</td>""")
						out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				elif ttymode:
					tab = Tabble("Chunk operations info",10,"r")
					tab.header(("loop time","",2),("deletions","",4),("replications","",2),("locked","",2))
					tab.header(("---","",10))
					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","rebalance","unused","used")
					if loopstart>0:
						tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),"%u/%u" % (del_invalid,del_invalid+ndel_invalid),"%u/%u" % (del_unused,del_unused+ndel_unused),"%u/%u" % (del_dclean,del_dclean+ndel_dclean),"%u/%u" % (del_ogoal,del_ogoal+ndel_ogoal),"%u/%u" % (rep_ugoal,rep_ugoal+nrep_ugoal),rebalnce,locked_unused,locked_used)
					else:
						tab.append(("no data","c",10))
					print(tab)
				else:
					out = []
					if loopstart>0:
						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
						out.append("""chunk loop%slocked%sunused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_unused))
						out.append("""chunk loop%slocked%sused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_used))
					else:
						out.append("""chunk loop%sno data""" % plaintextseparator)
					print("\n".join(out))
		except Exception:
			print_exception()

		try:
			if needseparator:
				if cgimode:
					print("""<br/>""")
				else:
					print("")
			else:
				needseparator=1
			if (leaderconn.version_at_least(2,0,66) and leaderconn.version_less_than(3,0,0)) or leaderconn.version_at_least(3,0,19):
				data,length = leaderconn.command(CLTOMA_FSTEST_INFO,MATOCL_FSTEST_INFO,struct.pack(">B",0))
				pver = 1
			else:
				data,length = leaderconn.command(CLTOMA_FSTEST_INFO,MATOCL_FSTEST_INFO)
				pver = 0
			if length>=(36 + pver*8):
				if pver==1:
					loopstart,loopend,files,ugfiles,mfiles,mtfiles,msfiles,chunks,ugchunks,mchunks,msgbuffleng = struct.unpack(">LLLLLLLLLLL",data[:44])
					datastr = data[44:].decode('ascii')
				else:
					loopstart,loopend,files,ugfiles,mfiles,chunks,ugchunks,mchunks,msgbuffleng = struct.unpack(">LLLLLLLLL",data[:36])
					datastr = data[36:].decode('ascii')
				if cgimode:
					out = []
					out.append("""<table class="FR" cellspacing="0">""")
					out.append("""	<tr><th colspan="%u">Filesystem check info</th></tr>""" % (8 if pver==0 else 10))
					out.append("""	<tr>""")
					out.append("""		<th>check loop start time</th>""")
					out.append("""		<th>check loop end time</th>""")
					out.append("""		<th>files</th>""")
					out.append("""		<th>under-goal files</th>""")
					out.append("""		<th>missing files</th>""")
					if pver==1:
						out.append("""		<th>missing trash files</th>""")
						out.append("""		<th>missing sustained files</th>""")
					out.append("""		<th>chunks</th>""")
					out.append("""		<th>under-goal chunks</th>""")
					out.append("""		<th>missing chunks</th>""")
					out.append("""	</tr>""")
					if loopstart>0:
						out.append("""	<tr>""")
						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
						out.append("""		<td align="right">%u</td>""" % files)
						out.append("""		<td align="right">%u</td>""" % ugfiles)
						out.append("""		<td align="right">%u</td>""" % mfiles)
						if pver==1:
							out.append("""		<td align="right">%u</td>""" % mtfiles)
							out.append("""		<td align="right">%u</td>""" % msfiles)
						out.append("""		<td align="right">%u</td>""" % chunks)
						out.append("""		<td align="right">%u</td>""" % ugchunks)
						out.append("""		<td align="right">%u</td>""" % mchunks)
						out.append("""	</tr>""")
						if msgbuffleng>0:
							if msgbuffleng==100000:
								out.append("""	<tr><th colspan="8">Important messages (first 100k):</th></tr>""")
							else:
								out.append("""	<tr><th colspan="8">Important messages:</th></tr>""")
							out.append("""	<tr>""")
							out.append("""		<td colspan="8" align="left"><pre>%s</pre></td>""" % (datastr.replace("&","&amp;").replace(">","&gt;").replace("<","&lt;")))
							out.append("""	</tr>""")
					else:
						out.append("""	<tr>""")
						out.append("""		<td colspan="%u" align="center">no data</td>""" % (8 if pver==0 else 10))
						out.append("""	</tr>""")
					out.append("""</table>""")
					print("\n".join(out))
				elif ttymode:
					if pver==1:
						tab = Tabble("Filesystem check info",10,"r")
						tabwidth = 10
						tab.header("check loop start time","check loop end time","files","under-goal files","missing files","missing trash files","missing sustained files","chunks","under-goal chunks","missing chunks")
					else:
						tab = Tabble("Filesystem check info",8,"r")
						tabwidth = 8
						tab.header("check loop start time","check loop end time","files","under-goal files","missing files","chunks","under-goal chunks","missing chunks")
					if loopstart>0:
						if pver==1:
							tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),files,ugfiles,mfiles,mtfiles,msfiles,chunks,ugchunks,mchunks)
						else:
							tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),files,ugfiles,mfiles,chunks,ugchunks,mchunks)
						if msgbuffleng>0:
							tab.append(("---","",tabwidth))
							if msgbuffleng==100000:
								tab.append(("Important messages (first 100k):","c",tabwidth))
							else:
								tab.append(("Important messages:","c",tabwidth))
							tab.append(("---","",tabwidth))
							for line in datastr.strip().split("\n"):
								tab.append((line.strip(),"l",tabwidth))
					else:
						tab.append(("no data","c",tabwidth))
					print(tab)
				else:
					out = []
					if loopstart>0:
						out.append("""check loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
						out.append("""check loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
						out.append("""check loop%sfiles:%s%u""" % (plaintextseparator,plaintextseparator,files))
						out.append("""check loop%sunder-goal files:%s%u""" % (plaintextseparator,plaintextseparator,ugfiles))
						out.append("""check loop%smissing files:%s%u""" % (plaintextseparator,plaintextseparator,mfiles))
						if pver==1:
							out.append("""check loop%smissing trash files:%s%u""" % (plaintextseparator,plaintextseparator,mtfiles))
							out.append("""check loop%smissing sustained files:%s%u""" % (plaintextseparator,plaintextseparator,msfiles))
						out.append("""check loop%schunks:%s%u""" % (plaintextseparator,plaintextseparator,chunks))
						out.append("""check loop%sunder-goal chunks:%s%u""" % (plaintextseparator,plaintextseparator,ugchunks))
						out.append("""check loop%smissing chunks:%s%u""" % (plaintextseparator,plaintextseparator,mchunks))
						if msgbuffleng>0:
							for line in datastr.strip().split("\n"):
								out.append("check loop%simportant messages:%s%s" % (plaintextseparator,plaintextseparator,line.strip()))
					else:
						out.append("""check loop: no data""")
					print("\n".join(out))
		except Exception:
			print_exception()

	if "MF" in sectionsubset and ((leaderconn.version_at_least(2,0,66) and leaderconn.version_less_than(3,0,0)) or leaderconn.version_at_least(3,0,19)):
		try:
			if needseparator:
				if cgimode:
					print("""<br/>""")
				else:
					print("")
			else:
				needseparator=1
			inodes = set()
			missingchunks = []
			if ((leaderconn.version_at_least(2,0,71) and leaderconn.version_less_than(3,0,0)) or leaderconn.version_at_least(3,0,25)):
				data,length = leaderconn.command(CLTOMA_MISSING_CHUNKS,MATOCL_MISSING_CHUNKS,struct.pack(">B",1))
				if length%17==0:
					n = length//17
					for x in xrange(n):
						chunkid,inode,indx,mtype = struct.unpack(">QLLB",data[x*17:x*17+17])
						inodes.add(inode)
						missingchunks.append((chunkid,inode,indx,mtype))
				mode = 1
			else:
				data,length = leaderconn.command(CLTOMA_MISSING_CHUNKS,MATOCL_MISSING_CHUNKS)
				if length%16==0:
					n = length//16
					for x in xrange(n):
						chunkid,inode,indx = struct.unpack(">QLL",data[x*16:x*16+16])
						inodes.add(inode)
						missingchunks.append((chunkid,inode,indx,None))
				mode = 0
			inodepaths = resolve_inodes_paths(leaderconn,inodes)
			mcdata = []
			mccnt = 0
			for chunkid,inode,indx,mtype in missingchunks:
				if inode in inodepaths:
					paths = inodepaths[inode]
					mccnt += len(paths)
				else:
					paths = []
					mccnt += 1
				sf = paths
				if MForder==1:
					sf = paths
				elif MForder==2:
					sf = inode
				elif MForder==3:
					sf = indx
				elif MForder==4:
					sf = chunkid
				elif MForder==5:
					sf = mtype
				mcdata.append((sf,paths,inode,indx,chunkid,mtype))
			mcdata.sort()
			if MFrev:
				mcdata.reverse()
			if cgimode:
				out = []
				if mccnt>0:
					out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_missingfiles" cellspacing="0">""")
					if MFlimit>0 and mccnt>MFlimit:
						out.append("""	<tr><th colspan="%u">Missing files (gathered by previous file-loop) - %u/%u entries - <a href="%s" class="VISIBLELINK">show more</a> - <a href="%s" class="VISIBLELINK">show all</a></th></tr>""" % ((6 if mode==1 else 5),MFlimit,mccnt,createlink({"MFlimit":"%u" % (MFlimit + 100)}),createlink({"MFlimit":"0"})))
					else:
						out.append("""	<tr><th colspan="%u">Missing files (gathered by previous file-loop)</th></tr>""" % (6 if mode==1 else 5))
					out.append("""	<tr>""")
					out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
					out.append("""		<th rowspan="2">paths</th>""")
					out.append("""		<th rowspan="2">inode</th>""")
					out.append("""		<th rowspan="2">index</th>""")
					out.append("""		<th rowspan="2">chunk&nbsp;id</th>""")
					if mode==1:
						out.append("""		<th rowspan="2">type&nbsp;of&nbsp;missing&nbsp;chunk</th>""")
					out.append("""	</tr>""")
				else:
					needseparator=0
			elif ttymode:
				if mode==1:
					tab = Tabble("Missing Files/Chunks (gathered by previous file-loop)",5)
					tab.header("path","inode","index","chunk id","type of missing chunk")
					tab.defattr("l","r","r","r","r")
				else:
					tab = Tabble("Missing Files/Chunks (gathered by previous file-loop)",4)
					tab.header("path","inode","index","chunk id")
					tab.defattr("l","r","r","r")
			else:
				tab = Tabble("missing files",(5 if mode==1 else 4))
			missingcount = 0
			for sf,paths,inode,indx,chunkid,mtype in mcdata:
				if mtype==0:
					mtypestr = "NO COPY"
				elif mtype==1:
					mtypestr = "INVALID COPIES"
				elif mtype==2:
					mtypestr = "WRONG VERSIONS"
				else:
					mtypestr = "OTHER"
				if cgimode:
					if mccnt>0:
						if len(paths)==0:
							if missingcount<MFlimit or MFlimit==0:
								out.append("""	<tr>""")
								out.append("""		<td align="right"></td>""")
								out.append("""		<td align="left"> * unknown path * (deleted file)</td>""")
								out.append("""		<td align="right">%u</td>""" % inode)
								out.append("""		<td align="right">%u</td>""" % indx)
								out.append("""		<td align="right">%016X</td>""" % chunkid)
								if mode==1:
									out.append("""		<td align="right">%s</td>""" % mtypestr)
								out.append("""	</tr>""")
							missingcount += 1
						else:
							for path in paths:
								if missingcount<MFlimit or MFlimit==0:
									out.append("""	<tr>""")
									out.append("""		<td align="right"></td>""")
									out.append("""		<td align="left">%s</td>""" % path)
									out.append("""		<td align="right">%u</td>""" % inode)
									out.append("""		<td align="right">%u</td>""" % indx)
									out.append("""		<td align="right">%016X</td>""" % chunkid)
									if mode==1:
										out.append("""		<td align="right">%s</td>""" % mtypestr)
									out.append("""	</tr>""")
								missingcount += 1
				else:
					if len(paths)==0:
						dline = [" * unknown path * (deleted file)",inode,indx,chunkid]
						if mode==1:
							dline.append(mtypestr)
						tab.append(*dline)
					else:
						for path in paths:
							dline = [path,inode,indx,chunkid]
							if mode==1:
								dline.append(mtypestr)
							tab.append(*dline)
			if cgimode:
				if mccnt>0:
					out.append("""</table>""")
				print("\n".join(out))
			else:
				print(tab)
		except Exception:
			print_exception()

if "CS" in sectionset:
	if "CS" in sectionsubset:
		if needseparator:
			if cgimode:
				print("""<br/>""")
			else:
				print("")
		else:
			needseparator=1

		try:
			if cgimode:
				out = []
				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfscs" cellspacing="0">""")
				if leaderconn.version_at_least(2,0,11):
					out.append("""	<tr><th colspan="17">Chunk Servers</th></tr>""")
				elif leaderconn.version_at_least(1,7,25):
					out.append("""	<tr><th colspan="16">Chunk Servers</th></tr>""")
				elif leaderconn.version_at_least(1,6,28):
					out.append("""	<tr><th colspan="15">Chunk Servers</th></tr>""")
				else:
					out.append("""	<tr><th colspan="14">Chunk Servers</th></tr>""")
				out.append("""	<tr>""")
				out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
				out.append("""		<th rowspan="2">host</th>""")
				out.append("""		<th rowspan="2">ip</th>""")
				out.append("""		<th rowspan="2">port</th>""")
				if leaderconn.version_at_least(1,7,25):
					out.append("""		<th rowspan="2">id</th>""")
				out.append("""		<th rowspan="2">version</th>""")
				if leaderconn.version_at_least(1,6,28):
					out.append("""		<th rowspan="2">load</th>""")
				if leaderconn.version_at_least(2,0,11):
					out.append("""		<th rowspan="2">maintenance</th>""")
				out.append("""		<th colspan="4">'regular' hdd space</th>""")
				out.append("""		<th colspan="4">'marked for removal' hdd space</th>""")
				out.append("""	</tr>""")
				out.append("""	<tr>""")
				out.append("""		<th>chunks</th>""")
				out.append("""		<th>used</th>""")
				out.append("""		<th>total</th>""")
				out.append("""		<th class="PROGBAR">% used</th>""")
				out.append("""		<th>chunks</th>""")
				out.append("""		<th>used</th>""")
				out.append("""		<th>total</th>""")
				out.append("""		<th class="PROGBAR">% used</th>""")
				out.append("""	</tr>""")
			elif ttymode:
				if leaderconn.version_at_least(2,0,11):
					tab = Tabble("Chunk Servers",14,"r")
					tab.header("","","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
					tab.header("ip/host","port","id","version","load","maintenance",("---","",8))
					tab.header("","","","","","","chunks","used","total","% used","chunks","used","total","% used")
				elif leaderconn.version_at_least(1,7,25):
					tab = Tabble("Chunk Servers",13,"r")
					tab.header("","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
					tab.header("ip/host","port","id","version","load",("---","",8))
					tab.header("","","","","","chunks","used","total","% used","chunks","used","total","% used")
				elif leaderconn.version_at_least(1,6,28):
					tab = Tabble("Chunk Servers",12,"r")
					tab.header("","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
					tab.header("ip/host","port","version","load",("---","",8))
					tab.header("","","","","chunks","used","total","% used","chunks","used","total","% used")
				else:
					tab = Tabble("Chunk Servers",11,"r")
					tab.header("","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
					tab.header("ip/host","port","version",("---","",8))
					tab.header("","","","chunks","used","total","% used","chunks","used","total","% used")
			else:
				if leaderconn.version_at_least(2,0,11):
					tab = Tabble("chunk servers",12)
				elif leaderconn.version_at_least(1,7,25):
					tab = Tabble("chunk servers",11)
				elif leaderconn.version_at_least(1,6,28):
					tab = Tabble("chunk servers",10)
				else:
					tab = Tabble("chunk servers",9)
			data,length = leaderconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
			if leaderconn.version_at_least(1,7,25) and (length%64)==0:
				n = length//64
				servers = []
				dservers = []
				usedsum = 0
				totalsum = 0
				for i in range(n):
					d = data[i*64:(i+1)*64]
					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port,csid,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime = struct.unpack(">BBBBBBBBHHQQLQQLLLL",d)
					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
					strver,sortver = version_str_and_sort((v1,v2,v3))
					host = resolve(strip)
					if total>0:
						usedsum+=used
						totalsum+=total
					if CSorder==1:
						sf = host
					elif CSorder==2 or CSorder==0:
						sf = sortip
					elif CSorder==3:
						sf = port
					elif CSorder==4:
						sf = csid
					elif CSorder==5:
						sf = sortver
					elif CSorder==6:
						sf = (gracetime,load)
					elif CSorder==10:
						sf = chunks
					elif CSorder==11:
						sf = used
					elif CSorder==12:
						sf = total
					elif CSorder==13:
						if total>0:
							sf = (1.0*used)/total
						else:
							sf = 0
					elif CSorder==20:
						sf = tdchunks
					elif CSorder==21:
						sf = tdused
					elif CSorder==22:
						sf = tdtotal
					elif CSorder==23:
						if tdtotal>0:
							sf = (1.0*tdused)/tdtotal
						else:
							sf = 0
					else:
						sf = 0
					if (flags&1)==0:
						servers.append((sf,host,sortip,strip,port,csid,sortver,strver,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime))
					else:
						dservers.append((sf,host,sortip,strip,port,csid,flags))
				servers.sort()
				dservers.sort()
				if CSrev:
					servers.reverse()
					dservers.reverse()
				if totalsum>0:
					avgpercent = (usedsum*100.0)/totalsum
				else:
					avgpercent = 0
				for sf,host,sortip,strip,port,csid,sortver,strver,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime in servers:
					if cgimode:
						if leaderconn.is_pro() and not strver.endswith(" PRO"):
							verclass = "BADVERSION"
						elif leaderconn.sort_ver() > sortver:
							verclass = "LOWERVERSION"
						elif leaderconn.sort_ver() < sortver:
							verclass = "HIGHERVERSION"
						else:
							verclass = "OKVERSION"
						if leaderconn.version_at_least(2,0,11):
							if (flags&2)==0:
								mm = "switch on"
								mmurl = createlink({"CSmaintenanceon":("%s:%u" % (strip,port))})
								cl = None
							else:
								mm = "switch off"
								mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
								cl = "MAINTAINREADY"
						else:
							cl = None
						out.append("""	<tr>""")
						out.append("""		<td align="right"></td>""")
						if cl:
							out.append("""		<td align="left"><span class="%s">%s</span></td>""" % (cl,host))
							out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,cl,strip))
							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,port))
							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,csid))
						else:
							out.append("""		<td align="left">%s</td>""" % (host))
							out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortip,strip))
							out.append("""		<td align="center">%u</td>""" % (port))
							out.append("""		<td align="center">%u</td>""" % (csid))
						out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortver,verclass,strver))
						if gracetime>0:
							out.append("""		<td align="right"><a style="cursor:default" title="back after %u seconds" href="%s"><span class="GRACETIME">[%u]</span></a></td>""" % (gracetime,createlink({"CSbacktowork":("%s:%u" % (strip,port))}),load))
						else:
							out.append("""		<td align="right">%u</td>""" % (load))
						if leaderconn.version_at_least(2,0,11):
							out.append("""		<td align="center"><a href="%s">%s</a></td>""" % (mmurl,mm))
						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (chunks,used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
						if (total>0):
							usedpercent = (used*100.0)/total
							if usedpercent<avgpercent:
								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
							else:
								diffstr = "+%.4f" % (usedpercent-avgpercent)
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (tdchunks,tdused,decimal_number(tdused),humanize_number(tdused,"&nbsp;"),tdtotal,decimal_number(tdtotal),humanize_number(tdtotal,"&nbsp;")))
						if (tdtotal>0):
							usedpercent = (tdused*100.0)/tdtotal
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGVALUE">%.2f</div></div></td>""" % (usedpercent,100.0-usedpercent,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
						out.append("""	</tr>""")
					elif ttymode:
						if total>0:
							regperc = "%.2f%%" % ((used*100.0)/total)
						else:
							regperc = "-"
						if tdtotal>0:
							tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
						else:
							tdperc = "-"
						if leaderconn.version_at_least(2,0,11):
							if (flags&2)==0:
								mm = "off"
							else:
								mm = "on"
							tab.append(host,port,csid,strver,load,mm,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
						else:
							tab.append(host,port,csid,strver,load,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
					else:
						if leaderconn.version_at_least(2,0,11):
							if (flags&2)==0:
								mm = "standard_mode"
							else:
								mm = "maintenance_mode"
							tab.append(host,port,csid,strver,load,mm,chunks,used,total,tdchunks,tdused,tdtotal)
						else:
							tab.append(host,port,csid,strver,load,chunks,used,total,tdchunks,tdused,tdtotal)
				if len(dservers)>0:
					if cgimode:
						out.append("""</table>""")
						out.append("""<br/>""")
						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
						if leaderconn.version_at_least(2,0,11):
							out.append("""	<tr><th colspan="7">Disconnected Chunk Servers</th></tr>""")
						else:
							out.append("""	<tr><th colspan="6">Disconnected Chunk Servers</th></tr>""")
						out.append("""	<tr>""")
						out.append("""		<th class="acid_tab_enumerate">#</th>""")
						out.append("""		<th>host</th>""")
						out.append("""		<th>ip</th>""")
						out.append("""		<th>port</th>""")
						out.append("""		<th>id</th>""")
						if leaderconn.version_at_least(2,0,11):
							out.append("""		<th>maintenance</th>""")
						out.append("""		<th class="acid_tab_skip">remove</th>""")
						out.append("""	</tr>""")
					elif ttymode:
						if leaderconn.version_at_least(2,0,11):
							tab.append(("---","",14))
							tab.append(("disconnected servers","1c",14))
							tab.append(("---","",14))
							tab.append(("ip/host","c"),("port","c"),("csid","r"),("maintenance","c"),("change maintenance command","c",5),("remove command","c",5))
							tab.append(("---","",14))
						else:
							tab.append(("---","",13))
							tab.append(("disconnected servers","1c",13))
							tab.append(("---","",13))
							tab.append(("ip/host","c"),("port","c"),("csid","r"),("remove command","c",10))
							tab.append(("---","",13))
					else:
						print(tab)
						print("")
						if leaderconn.version_at_least(2,0,11):
							tab = Tabble("Disconnected chunk servers",4)
						else:
							tab = Tabble("Disconnected chunk servers",3)
				for sf,host,sortip,strip,port,csid,flags in dservers:
					if cgimode:
						out.append("""	<tr>""")
						if leaderconn.version_at_least(2,0,11):
							if (flags&2)==0:
								mm = "switch on"
								mmurl = createlink({"CSmaintenanceon":("%s:%u" % (strip,port))})
								cl = "DISCONNECTED"
							else:
								mm = "switch off"
								mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
								cl = "MAINTAINED"
							out.append("""		<td align="right"></td><td align="left"><span class="%s">%s</span></td>""" % (cl,host))
							out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,cl,strip))
							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,port))
							out.append("""		<td align="right"><span class="%s">%u</span></td>""" % (cl,csid))
							out.append("""		<td align="center"><span class="%s"><a href="%s">%s</a></span></td>""" % (cl,mmurl,mm))
							out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % (createlink({"CSremove":("%s:%u" % (strip,port))})))
						else:
							out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td><td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td><td align="center"><span class="DISCONNECTED">%u</span></td><td align="right"><span class="DISCONNECTED">%u</span></td><td align="center"><a href="%s">click to remove</a></td>""" % (host,sortip,strip,port,csid,createlink({"CSremove":("%s:%u" % (strip,port))})))
						out.append("""	</tr>""")
					elif ttymode:
						if leaderconn.version_at_least(2,0,11):
							if (flags&2)==0:
								mm = "off"
								mmcmd = "%s -H %s -P %u -CM1/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
							else:
								mm = "on"
								mmcmd = "%s -H %s -P %u -CM0/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
							tab.append(host,port,csid,mm,(mmcmd,"l",5),("%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",5))
						else:
							tab.append(host,port,csid,("%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",10))
					else:
						if leaderconn.version_at_least(2,0,11):
							if (flags&2)==0:
								mm = "standard_mode"
							else:
								mm = "maintenance_mode"
							tab.append(host,port,csid,mm)
						else:
							tab.append(host,port,csid)
			if leaderconn.version_at_least(1,6,28) and leaderconn.version_less_than(1,7,25) and (length%62)==0:
				n = length//62
				servers = []
				dservers = []
				usedsum = 0
				totalsum = 0
				for i in range(n):
					d = data[i*62:(i+1)*62]
					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime = struct.unpack(">BBBBBBBBHQQLQQLLLL",d)
					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
					strver,sortver = version_str_and_sort((v1,v2,v3))
					host = resolve(strip)
					if total>0:
						usedsum+=used
						totalsum+=total
					if CSorder==1:
						sf = host
					elif CSorder==2 or CSorder==0:
						sf = sortip
					elif CSorder==3:
						sf = port
					elif CSorder==5:
						sf = sortver
					elif CSorder==6:
						sf = (gracetime,load)
					elif CSorder==10:
						sf = chunks
					elif CSorder==11:
						sf = used
					elif CSorder==12:
						sf = total
					elif CSorder==13:
						if total>0:
							sf = (1.0*used)/total
						else:
							sf = 0
					elif CSorder==20:
						sf = tdchunks
					elif CSorder==21:
						sf = tdused
					elif CSorder==22:
						sf = tdtotal
					elif CSorder==23:
						if tdtotal>0:
							sf = (1.0*tdused)/tdtotal
						else:
							sf = 0
					else:
						sf = 0
					if disconnected==0:
						servers.append((sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime))
					else:
						dservers.append((sf,host,sortip,strip,port))
				servers.sort()
				dservers.sort()
				if CSrev:
					servers.reverse()
					dservers.reverse()
				if totalsum>0:
					avgpercent = (usedsum*100.0)/totalsum
				else:
					avgpercent = 0
				for sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime in servers:
					if cgimode:
						if leaderconn.is_pro() and not strver.endswith(" PRO"):
							verclass = "BADVERSION"
						elif leaderconn.sort_ver() > sortver:
							verclass = "LOWERVERSION"
						elif leaderconn.sort_ver() < sortver:
							verclass = "HIGHERVERSION"
						else:
							verclass = "OKVERSION"
						out.append("""	<tr>""")
						out.append("""		<td align="right"></td><td align="left">%s</td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center">%u</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (host,sortip,strip,port,sortver,verclass,strver))
						if gracetime>0:
							out.append("""		<td align="right"><a style="cursor:default" title="back after %u seconds"><span class="GRACETIME">[%u]</span></a></td>""" % (gracetime,load))
						else:
							out.append("""		<td align="right">%u</td>""" % (load))
						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (chunks,used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
						if (total>0):
							usedpercent = (used*100.0)/total
							if usedpercent<avgpercent:
								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
							else:
								diffstr = "+%.4f" % (usedpercent-avgpercent)
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (tdchunks,tdused,decimal_number(tdused),humanize_number(tdused,"&nbsp;"),tdtotal,decimal_number(tdtotal),humanize_number(tdtotal,"&nbsp;")))
						if (tdtotal>0):
							usedpercent = (tdused*100.0)/tdtotal
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGVALUE">%.2f</div></div></td>""" % (usedpercent,100.0-usedpercent,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
						out.append("""	</tr>""")
					elif ttymode:
						if total>0:
							regperc = "%.2f%%" % ((used*100.0)/total)
						else:
							regperc = "-"
						if tdtotal>0:
							tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
						else:
							tdperc = "-"
						tab.append(host,port,strver,load,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
					else:
						tab.append(host,port,strver,load,chunks,used,total,tdchunks,tdused,tdtotal)
				if len(dservers)>0:
					if cgimode:
						out.append("""</table>""")
						out.append("""<br/>""")
						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
						out.append("""	<tr><th colspan="5">Disconnected Chunk Servers</th></tr>""")
						out.append("""	<tr>""")
						out.append("""		<th class="acid_tab_enumerate">#</th>""")
						out.append("""		<th>host</th>""")
						out.append("""		<th>ip</th>""")
						out.append("""		<th>port</th>""")
						out.append("""		<th class="acid_tab_skip">cmd</th>""")
						out.append("""	</tr>""")
					elif ttymode:
						tab.append(("---","",12))
						tab.append(("disconnected servers","1c",12))
						tab.append(("---","",12))
						tab.append(("ip/host","c"),("port","c"),("remove command","c",10))
						tab.append(("---","",12))
					else:
						print(tab)
						print("")
						tab = Tabble("Disconnected chunk servers",2)
				for sf,host,sortip,strip,port in dservers:
					if cgimode:
						out.append("""	<tr>""")
						out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td><td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td><td align="center"><span class="DISCONNECTED">%u</span></td><td align="center"><a href="%s">click to remove</a></td>""" % (host,sortip,strip,port,createlink({"CSremove":("%s:%u" % (strip,port))})))
						out.append("""	</tr>""")
					elif ttymode:
						tab.append(host,port,("%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",10))
					else:
						tab.append(host,port)
			if leaderconn.version_less_than(1,6,28) and (length%54)==0:
				n = length//54
				servers = []
				dservers = []
				usedsum = 0
				totalsum = 0
				for i in range(n):
					d = data[i*54:(i+1)*54]
					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port,used,total,chunks,tdused,tdtotal,tdchunks,errcnt = struct.unpack(">BBBBBBBBHQQLQQLL",d)
					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
					strver,sortver = version_str_and_sort((v1,v2,v3))
					host = resolve(strip)
					if total>0:
						usedsum+=used
						totalsum+=total
					sf = sortip
					if CSorder==1:
						sf = host
					elif CSorder==2:
						sf = sortip
					elif CSorder==3:
						sf = port
					elif CSorder==5:
						sf = sortver
					elif CSorder==10:
						sf = chunks
					elif CSorder==11:
						sf = used
					elif CSorder==12:
						sf = total
					elif CSorder==13:
						if total>0:
							sf = (1.0*used)/total
						else:
							sf = 0
					elif CSorder==20:
						sf = tdchunks
					elif CSorder==21:
						sf = tdused
					elif CSorder==22:
						sf = tdtotal
					elif CSorder==23:
						if tdtotal>0:
							sf = (1.0*tdused)/tdtotal
						else:
							sf = 0
					if disconnected==0:
						servers.append((sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt))
					else:
						dservers.append((sf,host,sortip,strip,port))
				servers.sort()
				dservers.sort()
				if CSrev:
					servers.reverse()
					dservers.reverse()
				if totalsum>0:
					avgpercent = (usedsum*100.0)/totalsum
				else:
					avgpercent = 0
				i = 1
				for sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt in servers:
					if cgimode:
						if leaderconn.is_pro() and not strver.endswith(" PRO"):
							verclass = "BADVERSION"
						elif leaderconn.sort_ver() > sortver:
							verclass = "LOWERVERSION"
						elif leaderconn.sort_ver() < sortver:
							verclass = "HIGHERVERSION"
						else:
							verclass = "OKVERSION"
						out.append("""	<tr>""")
						out.append("""		<td align="right"></td><td align="left">%s</td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center">%u</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (host,sortip,strip,port,sortver,verclass,strver))
						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (chunks,used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
						if (total>0):
							usedpercent = (used*100.0)/total
							if usedpercent<avgpercent:
								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
							else:
								diffstr = "+%.4f" % (usedpercent-avgpercent)
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (tdchunks,tdused,decimal_number(tdused),humanize_number(tdused,"&nbsp;"),tdtotal,decimal_number(tdtotal),humanize_number(tdtotal,"&nbsp;")))
						if (tdtotal>0):
							usedpercent = (tdused*100.0)/tdtotal
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGVALUE">%.2f</div></div></td>""" % (usedpercent,100.0-usedpercent,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
						out.append("""	</tr>""")
						i+=1
					elif ttymode:
						if total>0:
							regperc = "%.2f%%" % ((used*100.0)/total)
						else:
							regperc = "-"
						if tdtotal>0:
							tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
						else:
							tdperc = "-"
						tab.append(host,port,strver,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
					else:
						tab.append(host,port,strver,chunks,used,total,tdchunks,tdused,tdtotal)
				if len(dservers)>0:
					if cgimode:
						out.append("""</table>""")
						out.append("""<br/>""")
						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
						out.append("""	<tr><th colspan="5">Disconnected Chunk Servers</th></tr>""")
						out.append("""	<tr>""")
						out.append("""		<th class="acid_tab_enumerate">#</th>""")
						out.append("""		<th>host</th>""")
						out.append("""		<th>ip</th>""")
						out.append("""		<th>port</th>""")
						out.append("""		<th class="acid_tab_skip">cmd</th>""")
						out.append("""	</tr>""")
					elif ttymode:
						tab.append(("---","",11))
						tab.append(("disconnected servers","1c",11))
						tab.append(("---","",11))
						tab.append(("ip/host","c"),("port","c"),("remove command","c",9))
						tab.append(("---","",11))
					else:
						print(tab)
						print("")
						tab = Tabble("Disconnected chunk servers",2)
				for sf,host,sortip,strip,port in dservers:
					if cgimode:
						out.append("""	<tr>""")
						out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td><td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td><td align="center"><span class="DISCONNECTED">%u</span></td><td align="center"><a href="%s">click to remove</a></td>""" % (host,sortip,strip,port,createlink({"CSremove":("%s:%u" % (strip,port))})))
						out.append("""	</tr>""")
						i+=1
					elif ttymode:
						tab.append(host,port,("%s -H %s -P %u -CCR/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",9))
					else:
						tab.append(host,port)
			if cgimode:
				out.append("""</table>""")
				print("\n".join(out))
			else:
				print(tab)
		except Exception:
			print_exception()

	if "MB" in sectionsubset:
		if needseparator:
			if cgimode:
				print("""<br/>""")
			else:
				print("")
		else:
			needseparator=1

		try:
			if cgimode:
				out = []
				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmbl" cellspacing="0">""")
				out.append("""	<tr><th colspan="4">Metadata Backup Loggers</th></tr>""")
				out.append("""	<tr>""")
				out.append("""		<th class="acid_tab_enumerate">#</th>""")
				out.append("""		<th>host</th>""")
				out.append("""		<th>ip</th>""")
				out.append("""		<th>version</th>""")
				out.append("""	</tr>""")
			elif ttymode:
				tab = Tabble("Metadata Backup Loggers",2,"r")
				tab.header("ip/host","version")
			else:
				tab = Tabble("metadata backup loggers",2)
			data,length = leaderconn.command(CLTOMA_MLOG_LIST,MATOCL_MLOG_LIST)
			if (length%8)==0:
				n = length//8
				servers = []
				for i in range(n):
					d = data[i*8:(i+1)*8]
					v1,v2,v3,ip1,ip2,ip3,ip4 = struct.unpack(">HBBBBBB",d)
					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
					host = resolve(strip)
					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
					strver,sortver = version_str_and_sort((v1,v2,v3))
					sf = (ip1,ip2,ip3,ip4)
					if MBorder==1:
						sf = host
					elif MBorder==2:
						sf = sortip
					elif MBorder==3:
						sf = sortver
					servers.append((sf,host,sortip,strip,sortver,strver))
				servers.sort()
				if MBrev:
					servers.reverse()
				for sf,host,sortip,strip,sortver,strver in servers:
					if cgimode:
						if leaderconn.is_pro() and not strver.endswith(" PRO"):
							verclass = "BADVERSION"
						elif leaderconn.sort_ver() > sortver:
							verclass = "LOWERVERSION"
						elif leaderconn.sort_ver() < sortver:
							verclass = "HIGHERVERSION"
						else:
							verclass = "OKVERSION"
						out.append("""	<tr>""")
						out.append("""		<td align="right"></td><td align="left">%s</td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (host,sortip,strip,sortver,verclass,strver))
						out.append("""	</tr>""")
					else:
						tab.append(host,strver)
			if cgimode:
				out.append("""</table>""")
				print("\n".join(out))
			else:
				print(tab)
		except Exception:
			print_exception()

if "HD" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	try:
		# get cs list
		hostlist = []
		data,length = leaderconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
		if leaderconn.version_at_least(1,7,25) and (length%64)==0:
			n = length//64
			servers = []
			for i in range(n):
				d = data[i*64:(i+1)*64]
				flags,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
				if (flags&1)==0:
					hostlist.append((v1,v2,v3,ip1,ip2,ip3,ip4,port))
		elif leaderconn.version_at_least(1,6,28) and leaderconn.version_less_than(1,7,25) and (length%62)==0:
			n = length//62
			servers = []
			for i in range(n):
				d = data[i*62:(i+1)*62]
				disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
				if disconnected==0:
					hostlist.append((v1,v2,v3,ip1,ip2,ip3,ip4,port))
		elif leaderconn.version_less_than(1,6,28) and (length%54)==0:
			n = length//54
			servers = []
			for i in range(n):
				d = data[i*54:(i+1)*54]
				disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
				if disconnected==0:
					hostlist.append((v1,v2,v3,ip1,ip2,ip3,ip4,port))

		# get hdd lists one by one
		hdd = []
		shdd = []
		for v1,v2,v3,ip1,ip2,ip3,ip4,port in hostlist:
			hostip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
			hostkey = "%s:%u" % (hostip,port)
			hoststr = resolve(hostip)
			if port>0:
				if (v1,v2,v3)<=(1,6,8):
					conn = MFSConn(hostip,port)
					data,length = conn.command(CLTOCS_HDD_LIST_V1,CSTOCL_HDD_LIST_V1)
					while length>0:
						if sys.version_info[0]<3:
							plen = ord(data[0])
							hddpath = data[1:plen+1]
						else:
							plen = data[0]
							hddpath = data[1:plen+1]
							try:
								hddpath = hddpath.decode('ascii')
							except UnicodeDecodeError:
								pass
						hostpath = "%s:%u:%s" % (hoststr,port,hddpath)
						ippath = "%s:%u:%s" % (hostip,port,hddpath)
						sortippath = "%03u_%03u_%03u_%03u:%05u:%s" % (ip1,ip2,ip3,ip4,port,hddpath)
						flags,errchunkid,errtime,used,total,chunkscnt = struct.unpack(">BQLQQL",data[plen+1:plen+34])
						length -= plen+34
						data = data[plen+34:]
						sf = (ip1,ip2,ip3,ip4,port,data[1:plen+1])
						if HDorder==1:
							sf = (ip1,ip2,ip3,ip4,port,data[1:plen+1])
						elif HDorder==2:
							sf = chunkscnt
						elif HDorder==3:
							sf = errtime
						elif HDorder==4:
							sf = -flags
						elif HDorder==20:
							sf = used
						elif HDorder==21:
							sf = total
						elif HDorder==22:
							if total>0:
								sf = (1.0*used)/total
							else:
								sf = 0
						hdd.append((sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]))
				else:
					conn = MFSConn(hostip,port)
					data,length = conn.command(CLTOCS_HDD_LIST_V2,CSTOCL_HDD_LIST_V2)
					while length>0:
						entrysize = struct.unpack(">H",data[:2])[0]
						entry = data[2:2+entrysize]
						data = data[2+entrysize:]
						length -= 2+entrysize;
						if sys.version_info[0]<3:
							plen = ord(entry[0])
							hddpath = entry[1:plen+1]
						else:
							plen = entry[0]
							hddpath = entry[1:plen+1]
							try:
								hddpath = hddpath.decode('ascii')
							except UnicodeDecodeError:
								pass
						hostpath = "%s:%u:%s" % (hoststr,port,hddpath)
						ippath = "%s:%u:%s" % (hostip,port,hddpath)
						sortippath = "%03u.%03u.%03u.%03u:%05u:%s" % (ip1,ip2,ip3,ip4,port,hddpath)
						flags,errchunkid,errtime,used,total,chunkscnt = struct.unpack(">BQLQQL",entry[plen+1:plen+34])
						rbytes = [0,0,0]
						wbytes = [0,0,0]
						usecreadsum = [0,0,0]
						usecwritesum = [0,0,0]
						usecfsyncsum = [0,0,0]
						rops = [0,0,0]
						wops = [0,0,0]
						fsyncops = [0,0,0]
						usecreadmax = [0,0,0]
						usecwritemax = [0,0,0]
						usecfsyncmax = [0,0,0]
						if entrysize==plen+34+144:
							rbytes[0],wbytes[0],usecreadsum[0],usecwritesum[0],rops[0],wops[0],usecreadmax[0],usecwritemax[0] = struct.unpack(">QQQQLLLL",entry[plen+34:plen+34+48])
							rbytes[1],wbytes[1],usecreadsum[1],usecwritesum[1],rops[1],wops[1],usecreadmax[1],usecwritemax[1] = struct.unpack(">QQQQLLLL",entry[plen+34+48:plen+34+96])
							rbytes[2],wbytes[2],usecreadsum[2],usecwritesum[2],rops[2],wops[2],usecreadmax[2],usecwritemax[2] = struct.unpack(">QQQQLLLL",entry[plen+34+96:plen+34+144])
#								if HDperiod==0:
#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34:plen+34+48])
#								elif HDperiod==1:
#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34+48:plen+34+96])
#								elif HDperiod==2:
#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34+96:plen+34+144])
						elif entrysize==plen+34+192:
							rbytes[0],wbytes[0],usecreadsum[0],usecwritesum[0],usecfsyncsum[0],rops[0],wops[0],fsyncops[0],usecreadmax[0],usecwritemax[0],usecfsyncmax[0] = struct.unpack(">QQQQQLLLLLL",entry[plen+34:plen+34+64])
							rbytes[1],wbytes[1],usecreadsum[1],usecwritesum[1],usecfsyncsum[1],rops[1],wops[1],fsyncops[1],usecreadmax[1],usecwritemax[1],usecfsyncmax[1] = struct.unpack(">QQQQQLLLLLL",entry[plen+34+64:plen+34+128])
							rbytes[2],wbytes[2],usecreadsum[2],usecwritesum[2],usecfsyncsum[2],rops[2],wops[2],fsyncops[2],usecreadmax[2],usecwritemax[2],usecfsyncmax[2] = struct.unpack(">QQQQQLLLLLL",entry[plen+34+128:plen+34+192])
#								if HDperiod==0:
#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34:plen+34+64])
#								elif HDperiod==1:
#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34+64:plen+34+128])
#								elif HDperiod==2:
#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34+128:plen+34+192])
						rbw = [0,0,0]
						wbw = [0,0,0]
						usecreadavg = [0,0,0]
						usecwriteavg = [0,0,0]
						usecfsyncavg = [0,0,0]
						for i in range(3):
							if usecreadsum[i]>0:
								rbw[i] = rbytes[i]*1000000//usecreadsum[i]
							if usecwritesum[i]+usecfsyncsum[i]>0:
								wbw[i] = wbytes[i]*1000000//(usecwritesum[i]+usecfsyncsum[i])
							if rops[i]>0:
								usecreadavg[i] = usecreadsum[i]//rops[i]
							if wops[i]>0:
								usecwriteavg[i] = usecwritesum[i]//wops[i]
							if fsyncops[i]>0:
								usecfsyncavg[i] = usecfsyncsum[i]//fsyncops[i]
						sf = sortippath
						if HDorder==1:
							sf = sortippath
						elif HDorder==2:
							sf = chunkscnt
						elif HDorder==3:
							sf = errtime
						elif HDorder==4:
							sf = -flags
						elif HDorder==5:
							sf = rbw[HDperiod]
						elif HDorder==6:
							sf = wbw[HDperiod]
						elif HDorder==7:
							if HDtime==1:
								sf = usecreadavg[HDperiod]
							else:
								sf = usecreadmax[HDperiod]
						elif HDorder==8:
							if HDtime==1:
								sf = usecwriteavg[HDperiod]
							else:
								sf = usecwritemax[HDperiod]
						elif HDorder==9:
							if HDtime==1:
								sf = usecfsyncavg[HDperiod]
							else:
								sf = usecfsyncmax[HDperiod]
						elif HDorder==10:
							sf = rops[HDperiod]
						elif HDorder==11:
							sf = wops[HDperiod]
						elif HDorder==12:
							sf = fsyncops[HDperiod]
						elif HDorder==20:
							if flags&4==0:
								sf = used
							else:
								sf = 0
						elif HDorder==21:
							if flags&4==0:
								sf = total
							else:
								sf = 0
						elif HDorder==22:
							if flags&4==0 and total>0:
								sf = (1.0*used)/total
							else:
								sf = 0
						if flags&4 and not cgimode and ttymode:
							shdd.append((sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes))
						else:
							hdd.append((sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes))

		if len(hdd)>0 or len(shdd)>0:
			if cgimode:
				out = []
				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfshdd" cellspacing="0" id="mfshdd">""")
				out.append("""	<tr><th colspan="16">Disks</th></tr>""")
				out.append("""	<tr>""")
				out.append("""		<th rowspan="3" class="acid_tab_enumerate">#</th>""")
				out.append("""		<th colspan="4" rowspan="2">""")
				out.append("""			<span class="hddaddrname_vis0">info (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddaddrname_vis',1)" class="VISIBLELINK">switch IP to name</a>)</span>""")
				out.append("""			<span class="hddaddrname_vis1">info (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddaddrname_vis',0)" class="VISIBLELINK">switch name to IP</a>)</span>""")
				out.append("""		</th>""")
				out.append("""		<th colspan="8">""")
				out.append("""			<span class="hddperiod_vis0">I/O stats last min (switch to <a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',1)" class="VISIBLELINK">hour</a>,<a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',2)" class="VISIBLELINK">day</a>)</span>""")
				out.append("""			<span class="hddperiod_vis1">I/O stats last hour (switch to <a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',0)" class="VISIBLELINK">min</a>,<a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',2)" class="VISIBLELINK">day</a>)</span>""")
				out.append("""			<span class="hddperiod_vis2">I/O stats last day (switch to <a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',0)" class="VISIBLELINK">min</a>,<a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',1)" class="VISIBLELINK">hour</a>)</span>""")
				out.append("""		</th>""")
#				if HDperiod==2:
#					out.append("""		<th colspan="8">I/O stats last day (switch to <a href="%s" class="VISIBLELINK">min</a>,<a href="%s" class="VISIBLELINK">hour</a>)</th>""" % (createlink({"HDperiod":"0"}),createlink({"HDperiod":"1"})))
#				elif HDperiod==1:
#					out.append("""		<th colspan="8">I/O stats last hour (switch to <a href="%s" class="VISIBLELINK">min</a>,<a href="%s" class="VISIBLELINK">day</a>)</th>""" % (createlink({"HDperiod":"0"}),createlink({"HDperiod":"2"})))
#				else:
#					out.append("""		<th colspan="8">I/O stats last min (switch to <a href="%s" class="VISIBLELINK">hour</a>,<a href="%s" class="VISIBLELINK">day</a>)</th>""" % (createlink({"HDperiod":"1"}),createlink({"HDperiod":"2"})))
				out.append("""		<th colspan="3" rowspan="2">space</th>""")
				out.append("""	</tr>""")
				out.append("""	<tr>""")
				out.append("""		<th colspan="2"><a style="cursor:default" title="average data transfer speed">transfer</a></th>""")
				out.append("""		<th colspan="3">""")
				out.append("""			<span class="hddtime_vis0"><a style="cursor:default" title="max time of read or write one chunk block (up to 64kB)">max time</a> (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddtime_vis',1)" class="VISIBLELINK">switch to avg</a>)</span>""")
				out.append("""			<span class="hddtime_vis1"><a style="cursor:default" title="average time of read or write chunk block (up to 64kB)">avg time</a> (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddtime_vis',0)" class="VISIBLELINK">switch to max</a>)</span>""")
				out.append("""		</th>""")
#				if HDtime==1:
#					out.append("""		<th colspan="3"><a style="cursor:default" title="average time of read or write chunk block (up to 64kB)">avg time</a> (<a href="%s" class="VISIBLELINK">switch to max</a>)</th>""" % (createlink({"HDtime":"0"})))
#				else:
#					out.append("""		<th colspan="3"><a style="cursor:default" title="max time of read or write one chunk block (up to 64kB)">max time</a> (<a href="%s" class="VISIBLELINK">switch to avg</a>)</th>""" % (createlink({"HDtime":"1"})))
				out.append("""		<th colspan="3"><a style="cursor:default" title="number of chunk block operations / chunk fsyncs"># of ops</a></th>""")
				out.append("""	</tr>""")
				out.append("""	<tr>""")
				out.append("""		<th class="acid_tab_level_1"><span class="hddaddrname_vis0">IP</span><span class="hddaddrname_vis1">name</span> path</th>""")
				out.append("""		<th>chunks</th>""")
				out.append("""		<th>last error</th>""")
				out.append("""		<th>status</th>""")
				out.append("""		<th class="acid_tab_level_1">read</th>""")
				out.append("""		<th class="acid_tab_level_1">write</th>""")
				out.append("""		<th class="acid_tab_level_2">read</th>""")
				out.append("""		<th class="acid_tab_level_2">write</th>""")
				out.append("""		<th class="acid_tab_level_2">fsync</th>""")
				out.append("""		<th class="acid_tab_level_1">read</th>""")
				out.append("""		<th class="acid_tab_level_1">write</th>""")
				out.append("""		<th class="acid_tab_level_1">fsync</th>""")
				out.append("""		<th>used</th>""")
				out.append("""		<th>total</th>""")
				out.append("""		<th class="SMPROGBAR">% used</th>""")
				#out.append("""		<th><a href="%s">chunks</a></th>""" % (createorderlink("HD",2)))
				#out.append("""		<th><a href="%s">last error</a></th>""" % (createorderlink("HD",3)))
				#out.append("""		<th><a href="%s">status</a></th>""" % (createorderlink("HD",4)))
				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",5)))
				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",6)))
				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",7)))
				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",8)))
				#out.append("""		<th><a href="%s">fsync</a></th>""" % (createorderlink("HD",9)))
				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",10)))
				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",11)))
				#out.append("""		<th><a href="%s">fsync</a></th>""" % (createorderlink("HD",12)))
				#out.append("""		<th><a href="%s">used</a></th>""" % (createorderlink("HD",20)))
				#out.append("""		<th><a href="%s">total</a></th>""" % (createorderlink("HD",21)))
				#out.append("""		<th class="SMPROGBAR"><a href="%s">used (%%)</a></th>""" % (createorderlink("HD",22)))
				out.append("""	</tr>""")
			elif ttymode:
				tab = Tabble("Disks",15,"r")
				tab.header(("","",4),("I/O stats last %s" % ("day" if HDperiod==2 else "hour" if HDperiod==1 else "min"),"",8),("","",3))
				tab.header(("info","",4),("---","",8),("space","",3))
				tab.header(("","",4),("transfer","",2),("%s time" % ("avg" if HDtime==1 else "max"),"",3),("# of ops","",3),("","",3))
				tab.header(("---","",15))
				if len(hdd)>0 or len(shdd)==0:
					tab.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync","used","total","used %")
					lscanning = 0
				else:
					tab.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync",("progress","c",3))
					lscanning = 1
			else:
				tab = Tabble("disks",14)
			hdd.sort()
			shdd.sort()
			if HDrev:
				hdd.reverse()
				shdd.reverse()
			usedsum = {}
			totalsum = {}
			hostavg = {}
			for sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes in hdd+shdd:
				if hostkey not in usedsum:
					usedsum[hostkey]=0
					totalsum[hostkey]=0
					hostavg[hostkey]=0
				if flags&4==0 and total>0:
					usedsum[hostkey]+=used
					totalsum[hostkey]+=total
					if totalsum[hostkey]>0:
						hostavg[hostkey] = (usedsum[hostkey] * 100.0) / totalsum[hostkey]
			for sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes in hdd+shdd:
				if flags==1:
					status = 'marked for removal'
				elif flags==2:
					status = 'damaged'
				elif flags==3:
					status = 'damaged, marked for removal'
				elif flags==4 or flags==6:
					status = 'scanning'
				elif flags==5 or flags==7:
					status = 'marked for removal, scanning'
				else:
					status = 'ok'
				if errtime==0 and errchunkid==0:
					lerror = 'no errors'
				else:
					if cgimode:
						errtimetuple = time.localtime(errtime)
						lerror = '<a style="cursor:default" title="%s on chunk: %u">%s</a>' % (time.strftime("%Y-%m-%d %H:%M:%S",errtimetuple),errchunkid,time.strftime("%Y-%m-%d %H:%M",errtimetuple))
					elif ttymode:
						errtimetuple = time.localtime(errtime)
						lerror = time.strftime("%Y-%m-%d %H:%M",errtimetuple)
					else:
						lerror = errtime
				if cgimode:
					out.append("""	<tr>""")
					out.append("""		<td align="right"></td>""")
					out.append("""		<td align="left"><span class="hddaddrname_vis0"><span class="sortkey">%s </span>%s</span><span class="hddaddrname_vis1">%s</span></td>""" % (sortippath,ippath,hostpath))
					out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span>%s</td><td align="right">%s</td>""" % (chunkscnt,errtime,lerror,status))
					validdata = [1,1,1]
					for i in range(3):
						if rbw[i]==0 and wbw[i]==0 and usecreadmax[i]==0 and usecwritemax[i]==0 and usecfsyncmax[i]==0 and rops[i]==0 and wops[i]==0:
							validdata[i] = 0
					# rbw
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							out.append("""				<span class="sortkey">%u </span><a style="cursor:default" title="%s B/s">%s/s</a>""" % (rbw[i],decimal_number(rbw[i]),humanize_number(rbw[i],"&nbsp;")))
						else:
							out.append("""				<span class="sortkey">-1 </span>-""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# wbw
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							out.append("""				<span class="sortkey">%u </span><a style="cursor:default" title="%s B/s">%s/s</a>""" % (wbw[i],decimal_number(wbw[i]),humanize_number(wbw[i],"&nbsp;")))
						else:
							out.append("""				<span class="sortkey">-1 </span>-""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# readtime
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecreadmax[i])
							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecreadavg[i])
						else:
							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# writetime
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecwritemax[i])
							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecwriteavg[i])
						else:
							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# fsynctime
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecfsyncmax[i])
							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecfsyncavg[i])
						else:
							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# rops
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							if rops[i]>0:
								bsize = rbytes[i]/rops[i]
							else:
								bsize = 0
							out.append("""				<a style="cursor:default" title="average block size: %u B">%u</a>""" % (bsize,rops[i]))
						else:
							out.append("""				<span class="sortkey">-1 </span>-""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# wops
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							if wops[i]>0:
								bsize = wbytes[i]/wops[i]
							else:
								bsize = 0
							out.append("""				<a style="cursor:default" title="average block size: %u B">%u</a>""" % (bsize,wops[i]))
						else:
							out.append("""				<span class="sortkey">-1 </span>-""")
						out.append("""			</span>""")
					out.append("""		</td>""")
					# fsyncops
					out.append("""		<td align="right">""")
					for i in range(3):
						out.append("""			<span class="hddperiod_vis%u">""" % i)
						if validdata[i]:
							out.append("""				%u""" % (fsyncops[i]))
						else:
							out.append("""				<span class="sortkey">-1 </span>-""")
						out.append("""			</span>""")
					out.append("""		</td>""")
#					if rbw==0 and wbw==0 and rtime==0 and wtime==0 and rops==0 and wops==0:
#						out.append("""		<td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td>""")
#					else:
#						if rops>0:
#							rbsize = rbytes/rops
#						else:
#							rbsize = 0
#						if wops>0:
#							wbsize = wbytes/wops
#						else:
#							wbsize = 0
#						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B/s">%s/s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s/s</a></td>""" % (rbw,decimal_number(rbw),humanize_number(rbw,"&nbsp;"),wbw,decimal_number(wbw),humanize_number(wbw,"&nbsp;")))
#						out.append("""		<td align="right">%u us</td><td align="right">%u us</td><td align="right">%u us</td><td align="right"><a style="cursor:default" title="average block size: %u B">%u</a></td><td align="right"><a style="cursor:default" title="average block size: %u B">%u</a></td><td align="right">%u</td>""" % (rtime,wtime,fsynctime,rbsize,rops,wbsize,wops,fsyncops))
					if flags&4:
						out.append("""		<td colspan="3" align="right"><span class="sortkey">0 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.0f%%;"></div><div class="PROGVALUE">%.0f%% scanned</div></div></td>""" % (100.0-used,used))
					else:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
						if total>0:
							usedpercent = (used*100.0)/total
							avgpercent = hostavg[hostkey]
							if usedpercent<avgpercent:
								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
							else:
								diffstr = "+%.4f" % (usedpercent-avgpercent)
							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:100px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
						else:
							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:100px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
					out.append("""	</tr>""")
				elif ttymode:
					rtime = usecreadmax[HDperiod] if HDtime==0 else usecreadavg[HDperiod]
					wtime = usecwritemax[HDperiod] if HDtime==0 else usecwriteavg[HDperiod]
					fsynctime = usecfsyncmax[HDperiod] if HDtime==0 else usecfsyncavg[HDperiod]
					ldata = [ippath,chunkscnt,lerror,status]
					if rbw[HDperiod]==0 and wbw[HDperiod]==0 and usecreadmax[HDperiod]==0 and usecwritemax[HDperiod]==0 and usecfsyncmax[HDperiod]==0 and rops[HDperiod]==0 and wops[HDperiod]==0:
						ldata.extend(("-","-","-","-","-","-","-","-"))
					else:
						ldata.extend(("%s/s" % humanize_number(rbw[HDperiod]," "),"%s/s" % humanize_number(wbw[HDperiod]," "),"%u us" % rtime,"%u us" % wtime,"%u us" % fsynctime,rops[HDperiod],wops[HDperiod],fsyncops[HDperiod]))
					if flags&4:
						if lscanning==0:
							lscanning=1
							tab.append(("---","",15))
							tab.append("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync",("progress","c",3))
							tab.append(("---","",15))
						ldata.append(("%.0f%%" % used,"r",3))
					else:
						if total>0:
							perc = "%.2f%%" % ((used*100.0)/total)
						else:
							perc = "-"
						ldata.extend((humanize_number(used," "),humanize_number(total," "),perc))
					tab.append(*ldata)
				else:
					rtime = usecreadmax[HDperiod] if HDtime==0 else usecreadavg[HDperiod]
					wtime = usecwritemax[HDperiod] if HDtime==0 else usecwriteavg[HDperiod]
					fsynctime = usecfsyncmax[HDperiod] if HDtime==0 else usecfsyncavg[HDperiod]
					ldata = [ippath,chunkscnt,lerror,status]
					if rbw[HDperiod]==0 and wbw[HDperiod]==0 and usecreadmax[HDperiod]==0 and usecwritemax[HDperiod]==0 and usecfsyncmax[HDperiod]==0 and rops[HDperiod]==0 and wops[HDperiod]==0:
						ldata.extend(("-","-","-","-","-","-","-","-"))
					else:
						ldata.extend((rbw[HDperiod],wbw[HDperiod],rtime,wtime,fsynctime,rops[HDperiod],wops[HDperiod],fsyncops[HDperiod]))
					if flags&4:
						ldata.extend(("progress:",used))
					else:
						ldata.extend((used,total))
					tab.append(*ldata)
			if cgimode:
				out.append("""</table>""")
				print("\n".join(out))
			else:
				print(tab)
	except Exception:
		print_exception()

if "EX" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	try:
		if cgimode:
			out = []
			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsexports" cellspacing="0">""")
			out.append("""	<tr><th colspan="%u">Exports</th></tr>""" % (19 if leaderconn.version_at_least(1,7,0) else 18 if leaderconn.version_at_least(1,6,26) else 14))
			out.append("""	<tr>""")
			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
			out.append("""		<th colspan="2">ip&nbsp;range</th>""")
#			out.append("""		<th rowspan="2"><a href="%s">path</a></th>""" % (createorderlink("EX",3)))
#			out.append("""		<th rowspan="2"><a href="%s">minversion</a></th>""" % (createorderlink("EX",4)))
#			out.append("""		<th rowspan="2"><a href="%s">alldirs</a></th>""" % (createorderlink("EX",5)))
#			out.append("""		<th rowspan="2"><a href="%s">password</a></th>""" % (createorderlink("EX",6)))
#			out.append("""		<th rowspan="2"><a href="%s">ro/rw</a></th>""" % (createorderlink("EX",7)))
#			out.append("""		<th rowspan="2"><a href="%s">restricted&nbsp;ip</a></th>""" % (createorderlink("EX",8)))
#			out.append("""		<th rowspan="2"><a href="%s">ignore&nbsp;gid</a></th>""" % (createorderlink("EX",9)))
			out.append("""		<th rowspan="2">path</th>""")
			out.append("""		<th rowspan="2">minversion</th>""")
			out.append("""		<th rowspan="2">alldirs</th>""")
			out.append("""		<th rowspan="2">password</th>""")
			out.append("""		<th rowspan="2">ro/rw</th>""")
			out.append("""		<th rowspan="2">restricted&nbsp;ip</th>""")
			out.append("""		<th rowspan="2">ignore&nbsp;gid</th>""")
			if leaderconn.version_at_least(1,7,0):
#				out.append("""		<th rowspan="2"><a href="%s">can&nbsp;change&nbsp;quota</a></th>""" % (createorderlink("EX",10)))
				out.append("""		<th rowspan="2">admin</th>""")
			out.append("""		<th colspan="2">map&nbsp;root</th>""")
			out.append("""		<th colspan="2">map&nbsp;users</th>""")
			if leaderconn.version_at_least(1,6,26):
				out.append("""		<th colspan="2">goal&nbsp;limit</th>""")
				out.append("""		<th colspan="2">trashtime&nbsp;limit</th>""")
			out.append("""	</tr>""")
			out.append("""	<tr>""")
#			out.append("""		<th><a href="%s">from</a></th>""" % (createorderlink("EX",1)))
#			out.append("""		<th><a href="%s">to</a></th>""" % (createorderlink("EX",2)))
#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("EX",11)))
#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("EX",12)))
#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("EX",13)))
#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("EX",14)))
			out.append("""		<th>from</th>""")
			out.append("""		<th>to</th>""")
			out.append("""		<th>uid</th>""")
			out.append("""		<th>gid</th>""")
			out.append("""		<th>uid</th>""")
			out.append("""		<th>gid</th>""")
			if leaderconn.version_at_least(1,6,26):
#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("EX",15)))
#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("EX",16)))
#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("EX",17)))
#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("EX",18)))
				out.append("""		<th>min</th>""")
				out.append("""		<th>max</th>""")
				out.append("""		<th>min</th>""")
				out.append("""		<th>max</th>""")
			out.append("""	</tr>""")
		elif ttymode:
			tab = Tabble("Exports",(18 if leaderconn.version_at_least(1,7,0) else 17 if leaderconn.version_at_least(1,6,26) else 13))
			dline = ["r","r","l","c","c","c","c","c","c"]
			if leaderconn.version_at_least(1,7,0):
				dline.append("c")
			dline.extend(("r","r","r","r"))
			if leaderconn.version_at_least(1,6,26):
				dline.extend(("r","r","r","r"))
			tab.defattr(*dline)
			dline = [("ip range","",2),"","","","","","",""]
			if leaderconn.version_at_least(1,7,0):
				dline.append("")
			dline.extend((("map root","",2),("map users","",2)))
			if leaderconn.version_at_least(1,6,26):
				dline.extend((("goal limit","",2),("trashtime limit","",2)))
			tab.header(*dline)
			dline = [("---","",2),"path","minversion","alldirs","password","ro/rw","restrict ip","ignore gid"]
			if leaderconn.version_at_least(1,7,0):
				dline.append("admin")
			if leaderconn.version_at_least(1,6,26):
				dline.append(("---","",8))
			else:
				dline.append(("---","",4))
			tab.header(*dline)
			dline = ["from","to","","","","","","",""]
			if leaderconn.version_at_least(1,7,0):
				dline.append("")
			dline.extend(("uid","gid","uid","gid"))
			if leaderconn.version_at_least(1,6,26):
				dline.extend(("min","max","min","max"))
			tab.header(*dline)
		else:
			tab = Tabble("exports",(18 if leaderconn.version_at_least(1,7,0) else 17 if leaderconn.version_at_least(1,6,26) else 13))
		if leaderconn.version_at_least(1,6,26):
			data,length = leaderconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO,struct.pack(">B",1))
		else:
			data,length = leaderconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO)
		servers = []
		pos = 0
		while pos<length:
			fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4,pleng = struct.unpack(">BBBBBBBBL",data[pos:pos+12])
			ipfrom = "%d.%d.%d.%d" % (fip1,fip2,fip3,fip4)
			ipto = "%d.%d.%d.%d" % (tip1,tip2,tip3,tip4)
			sortipfrom = "%03d.%03d.%03d.%03d" % (fip1,fip2,fip3,fip4)
			sortipto = "%03d.%03d.%03d.%03d" % (tip1,tip2,tip3,tip4)
			pos+=12
			path = data[pos:pos+pleng]
			if sys.version_info[0]>=3:
				try:
					path = path.decode('ascii')
				except UnicodeDecodeError:
					pass
			pos+=pleng
			if leaderconn.version_at_least(1,6,26):
				v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">HBBBBLLLLBBLL",data[pos:pos+32])
				pos+=32
				if mingoal<=1 and maxgoal>=9:
					mingoal = None
					maxgoal = None
				if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
					mintrashtime = None
					maxtrashtime = None
			else:
				v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">HBBBBLLLL",data[pos:pos+22])
				mingoal = None;
				maxgoal = None;
				mintrashtime = None;
				maxtrashtime = None;
				pos+=22
			strver,sortver = version_str_and_sort((v1,v2,v3))
			if path=='.':
				meta=1
			else:
				meta=0
			sf = (fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4)
			if EXorder==1:
				sf = sortipfrom
			elif EXorder==2:
				sf = sortipto
			elif EXorder==3:
				sf = path
			elif EXorder==4:
				sf = sortver
			elif EXorder==5:
				if meta:
					sf = None
				else:
					sf = exportflags&1
			elif EXorder==6:
				sf = exportflags&2
			elif EXorder==7:
				sf = sesflags&1
			elif EXorder==8:
				sf = 2-(sesflags&2)
			elif EXorder==9:
				if meta:
					sf = None
				else:
					sf = sesflags&4
			elif EXorder==10:
				if meta:
					sf = None
				else:
					sf = sesflags&8
			elif EXorder==11:
				if meta:
					sf = None
				else:
					sf = rootuid
			elif EXorder==12:
				if meta:
					sf = None
				else:
					sf = rootgid
			elif EXorder==13:
				if meta or (sesflags&16)==0:
					sf = None
				else:
					sf = mapalluid
			elif EXorder==14:
				if meta or (sesflags&16)==0:
					sf = None
				else:
					sf = mapalguid
			elif EXorder==15:
				sf = mingoal
			elif EXorder==16:
				sf = maxgoal
			elif EXorder==17:
				sf = mintrashtime
			elif EXorder==18:
				sf = maxtrashtime
			servers.append((sf,sortipfrom,ipfrom,sortipto,ipto,path,meta,sortver,strver,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime))
		servers.sort()
		if EXrev:
			servers.reverse()
		for sf,sortipfrom,ipfrom,sortipto,ipto,path,meta,sortver,strver,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime in servers:
			if cgimode:
				out.append("""	<tr>""")
				out.append("""		<td align="right"></td>""")
				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipfrom,ipfrom))
				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipto,ipto))
				out.append("""		<td align="left">%s</td>""" % (".&nbsp;(META)" if meta else path))
				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortver,strver))
				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if exportflags&1 else "no"))
				out.append("""		<td align="center">%s</td>""" % ("yes" if exportflags&2 else "no"))
				out.append("""		<td align="center">%s</td>""" % ("ro" if sesflags&1 else "rw"))
				out.append("""		<td align="center">%s</td>""" % ("no" if sesflags&2 else "yes"))
				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&4 else "no"))
				if leaderconn.version_at_least(1,7,0):
					out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&8 else "no"))
				if meta:
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
				else:
					out.append("""		<td align="right">%u</td>""" % rootuid)
					out.append("""		<td align="right">%u</td>""" % rootgid)
				if meta or (sesflags&16)==0:
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
				else:
					out.append("""		<td align="right">%u</td>""" % mapalluid)
					out.append("""		<td align="right">%u</td>""" % mapallgid)
				if leaderconn.version_at_least(1,6,26):
					if mingoal!=None and maxgoal!=None:
						out.append("""		<td align="right">%u</td>""" % mingoal)
						out.append("""		<td align="right">%u</td>""" % maxgoal)
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if mintrashtime!=None and maxtrashtime!=None:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (mintrashtime,timeduration_to_fullstr(mintrashtime),timeduration_to_shortstr(mintrashtime)))
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (maxtrashtime,timeduration_to_fullstr(maxtrashtime),timeduration_to_shortstr(maxtrashtime)))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
				out.append("""	</tr>""")
			elif ttymode:
				dline = [ipfrom,ipto,". (META)" if meta else path,strver,"-" if meta else "yes" if exportflags&1 else "no","yes" if exportflags&2 else "no","ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"]
				if leaderconn.version_at_least(1,7,0):
					dline.append("-" if meta else "yes" if sesflags&8 else "no")
				if meta:
					dline.extend(("-","-"))
				else:
					dline.extend((rootuid,rootgid))
				if meta or (sesflags&16)==0:
					dline.extend(("-","-"))
				else:
					dline.extend((mapalluid,mapallgid))
				if leaderconn.version_at_least(1,6,26):
					if mingoal!=None and maxgoal!=None:
						dline.extend((mingoal,maxgoal))
					else:
						dline.extend(("-","-"))
					if mintrashtime!=None and maxtrashtime!=None:
						dline.extend((timeduration_to_shortstr(mintrashtime),timeduration_to_shortstr(maxtrashtime)))
					else:
						dline.extend(("-","-"))
				tab.append(*dline)
			else:
				dline = [ipfrom,ipto,". (META)" if meta else path,strver,"-" if meta else "yes" if exportflags&1 else "no","yes" if exportflags&2 else "no","ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"]
				if leaderconn.version_at_least(1,7,0):
					dline.append("-" if meta else "yes" if sesflags&8 else "no")
				if meta:
					dline.extend(("-","-"))
				else:
					dline.extend((rootuid,rootgid))
				if meta or (sesflags&16)==0:
					dline.extend(("-","-"))
				else:
					dline.extend((mapalluid,mapallgid))
				if leaderconn.version_at_least(1,6,26):
					if mingoal!=None and maxgoal!=None:
						dline.extend((mingoal,maxgoal))
					else:
						dline.extend(("-","-"))
					if mintrashtime!=None and maxtrashtime!=None:
						dline.extend((mintrashtime,maxtrashtime))
					else:
						dline.extend(("-","-"))
				tab.append(*dline)
		if cgimode:
			out.append("""</table>""")
			print("\n".join(out))
		else:
			print(tab)
	except Exception:
		print_exception()

if "MS" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	try:
		if cgimode:
			out = []
			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmounts" cellspacing="0">""")
			out.append("""	<tr><th colspan="%u">Active mounts (parameters)</th></tr>""" % (21 if leaderconn.version_at_least(1,7,8) else 19 if leaderconn.version_at_least(1,7,0) else 18 if leaderconn.version_at_least(1,6,26) else 14))
			out.append("""	<tr>""")
			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
#			out.append("""		<th rowspan="2"><a href="%s">session&nbsp;id</a></th>""" % (createorderlink("MS",1)))
#			out.append("""		<th rowspan="2"><a href="%s">host</a></th>""" % (createorderlink("MS",2)))
#			out.append("""		<th rowspan="2"><a href="%s">ip</a></th>""" % (createorderlink("MS",3)))
#			out.append("""		<th rowspan="2"><a href="%s">mount&nbsp;point</a></th>""" % (createorderlink("MS",4)))
#			out.append("""		<th rowspan="2"><a href="%s">version</a></th>""" % (createorderlink("MS",5)))
#			out.append("""		<th rowspan="2"><a href="%s">root&nbsp;dir</a></th>""" % (createorderlink("MS",6)))
#			out.append("""		<th rowspan="2"><a href="%s">ro/rw</a></th>""" % (createorderlink("MS",7)))
#			out.append("""		<th rowspan="2"><a href="%s">restricted&nbsp;ip</a></th>""" % (createorderlink("MS",8)))
#			out.append("""		<th rowspan="2"><a href="%s">ignore&nbsp;gid</a></th>""" % (createorderlink("MS",9)))
			out.append("""		<th rowspan="2">session&nbsp;id</th>""")
			out.append("""		<th rowspan="2">host</th>""")
			out.append("""		<th rowspan="2">ip</th>""")
			out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
			if leaderconn.version_at_least(1,7,8):
				out.append("""		<th rowspan="2">open files</th>""")
				out.append("""		<th rowspan="2"># of connections</th>""")
			out.append("""		<th rowspan="2">version</th>""")
			out.append("""		<th rowspan="2">root&nbsp;dir</th>""")
			out.append("""		<th rowspan="2">ro/rw</th>""")
			out.append("""		<th rowspan="2">restricted&nbsp;ip</th>""")
			out.append("""		<th rowspan="2">ignore&nbsp;gid</th>""")
			if leaderconn.version_at_least(1,7,0):
#				out.append("""		<th rowspan="2"><a href="%s">can&nbsp;change&nbsp;quota</a></th>""" % (createorderlink("MS",10)))
				out.append("""		<th rowspan="2">admin</th>""")
			out.append("""		<th colspan="2">map&nbsp;root</th>""")
			out.append("""		<th colspan="2">map&nbsp;users</th>""")
			if leaderconn.version_at_least(1,6,26):
				out.append("""		<th colspan="2">goal&nbsp;limits</th>""")
				out.append("""		<th colspan="2">trashtime&nbsp;limits</th>""")
			out.append("""	</tr>""")
			out.append("""	<tr>""")
#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("MS",11)))
#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("MS",12)))
#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("MS",13)))
#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("MS",14)))
			out.append("""		<th>uid</th>""")
			out.append("""		<th>gid</th>""")
			out.append("""		<th>uid</th>""")
			out.append("""		<th>gid</th>""")
			if leaderconn.version_at_least(1,6,26):
#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("MS",15)))
#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("MS",16)))
#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("MS",17)))
#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("MS",18)))
				out.append("""		<th>min</th>""")
				out.append("""		<th>max</th>""")
				out.append("""		<th>min</th>""")
				out.append("""		<th>max</th>""")
			out.append("""	</tr>""")
		elif ttymode:
			tab = Tabble("Active mounts (parameters)",(19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12))
			dline = ["r","r","l"]
			if leaderconn.version_at_least(1,7,8):
				dline.extend(("r","r"))
			dline.extend(("r","l","c","c","c"))
			if leaderconn.version_at_least(1,7,0):
				dline.append("c")
			dline.extend(("r","r","r","r"))
			if leaderconn.version_at_least(1,6,26):
				dline.extend(("r","r","r","r"))
			tab.defattr(*dline)
			dline = ["","","","","","","",""]
			if leaderconn.version_at_least(1,7,0):
				if leaderconn.version_at_least(1,7,8):
					dline.extend(("",""))
				dline.append("")
			dline.extend((("map root","",2),("map users","",2)))
			if leaderconn.version_at_least(1,6,26):
				dline.extend((("goal limit","",2),("trashtime limit","",2)))
			tab.header(*dline)
			dline = ["session id","ip/host","mount point"]
			if leaderconn.version_at_least(1,7,8):
				dline.extend(("open files","# of connections"))
			dline.extend(("version","root dir","ro/rw","restrict ip","ignore gid"))
			if leaderconn.version_at_least(1,7,0):
				dline.append("admin")
			if leaderconn.version_at_least(1,6,26):
				dline.append(("---","",8))
			else:
				dline.append(("---","",4))
			tab.header(*dline)
			dline = ["","","","","","","",""]
			if leaderconn.version_at_least(1,7,0):
				if leaderconn.version_at_least(1,7,8):
					dline.extend(("",""))
				dline.append("")
			dline.extend(("uid","gid","uid","gid"))
			if leaderconn.version_at_least(1,6,26):
				dline.extend(("min","max","min","max"))
			tab.header(*dline)
		else:
			tab = Tabble("active mounts, parameters",(19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12))
		if leaderconn.version_at_least(1,7,8):
			data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",2))
		elif leaderconn.version_at_least(1,6,26):
			data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",1))
		else:
			data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST)
		servers = []
		dservers = []
		if leaderconn.version_less_than(1,6,21):
			statscnt = 16
			pos = 0
		elif leaderconn.version_is(1,6,21):
			statscnt = 21
			pos = 0
		else:
			statscnt = struct.unpack(">H",data[0:2])[0]
			pos = 2
		while pos<length:
			if leaderconn.version_at_least(1,7,8):
				sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,openfiles,nsocks,expire,ileng = struct.unpack(">LBBBBHBBLBLL",data[pos:pos+25])
				pos+=25
			else:
				sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,ileng = struct.unpack(">LBBBBHBBL",data[pos:pos+16])
				pos+=16
				openfiles = 0;
				nsocks = 1
				expire = 0
			ipnum = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
			sortipnum = "%03u.%03u.%03u.%03u" % (ip1,ip2,ip3,ip4)
			strver,sortver = version_str_and_sort((v1,v2,v3))
			info = data[pos:pos+ileng]
			pos+=ileng
			pleng = struct.unpack(">L",data[pos:pos+4])[0]
			pos+=4
			path = data[pos:pos+pleng]
			pos+=pleng
			if sys.version_info[0]>=3:
				try:
					info = info.decode('ascii')
				except UnicodeDecodeError:
					pass
				try:
					path = path.decode('ascii')
				except UnicodeDecodeError:
					pass
			if leaderconn.version_at_least(1,6,26):
				sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">BLLLLBBLL",data[pos:pos+27])
				pos+=27
				if mingoal<=1 and maxgoal>=9:
					mingoal = None
					maxgoal = None
				if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
					mintrashtime = None
					maxtrashtime = None
			else:
				sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">BLLLL",data[pos:pos+17])
				mingoal = None
				maxgoal = None
				mintrashtime = None
				maxtrashtime = None
				pos+=17
			pos+=8*statscnt		# skip stats
			if path=='.':
				meta=1
			else:
				meta=0
			host = resolve(ipnum)
#				if path=="":
#					path="(empty)"
			sf = sortipnum
			if MSorder==1:
				sf = sessionid
			elif MSorder==2:
				sf = host
			elif MSorder==3:
				sf = sortipnum
			elif MSorder==4:
				sf = info
			elif MSorder==5:
				sf = openfiles
			elif MSorder==6:
				if nsocks>0:
					sf = nsocks
				else:
					sf = expire
			elif MSorder==7:
				sf = sortver
			elif MSorder==8:
				sf = path
			elif MSorder==9:
				sf = sesflags&1
			elif MSorder==10:
				sf = 2-(sesflags&2)
			elif MSorder==11:
				if meta:
					sf = None
				else:
					sf = sesflags&4
			elif MSorder==12:
				if meta:
					sf = None
				else:
					sf = sesflags&8
			elif MSorder==13:
				if meta:
					sf = None
				else:
					sf = rootuid
			elif MSorder==14:
				if meta:
					sf = None
				else:
					sf = rootgid
			elif MSorder==15:
				if meta or (sesflags&16)==0:
					sf = None
				else:
					sf = mapalluid
			elif MSorder==16:
				if meta or (sesflags&16)==0:
					sf = None
				else:
					sf = mapallgid
			elif MSorder==17:
				sf = mingoal
			elif MSorder==18:
				sf = maxgoal
			elif MSorder==19:
				sf = mintrashtime
			elif MSorder==20:
				sf = maxtrashtime
			if nsocks>0:
				servers.append((sf,sessionid,host,sortipnum,ipnum,info,openfiles,nsocks,sortver,strver,meta,path,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime))
			else:
				dservers.append((sf,sessionid,host,sortipnum,ipnum,info,openfiles,expire))
		servers.sort()
		dservers.sort()
		if MSrev:
			servers.reverse()
			dservers.reverse()
		for sf,sessionid,host,sortipnum,ipnum,info,openfiles,nsocks,sortver,strver,meta,path,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime in servers:
			if cgimode:
				if leaderconn.is_pro() and not strver.endswith(" PRO"):
					verclass = "BADVERSION"
				elif leaderconn.sort_ver() > sortver:
					verclass = "LOWERVERSION"
				elif leaderconn.sort_ver() < sortver:
					verclass = "HIGHERVERSION"
				else:
					verclass = "OKVERSION"
				out.append("""	<tr>""")
				out.append("""		<td align="right"></td>""")
				out.append("""		<td align="center">%u</td>""" % sessionid)
				out.append("""		<td align="left">%s</td>""" % host)
				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
				out.append("""		<td align="left">%s</td>""" % info)
				if leaderconn.version_at_least(1,7,8):
					out.append("""		<td align="center">%u</td>""" % openfiles)
					out.append("""		<td align="center">%u</td>""" % nsocks)
				out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortver,verclass,strver))
				out.append("""		<td align="left">%s</td>""" % (".&nbsp;(META)" if meta else path))
				out.append("""		<td align="center">%s</td>""" % ("ro" if sesflags&1 else "rw"))
				out.append("""		<td align="center">%s</td>""" % ("no" if sesflags&2 else "yes"))
				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&4 else "no"))
				if leaderconn.version_at_least(1,7,0):
					out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&8 else "no"))
				if meta:
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
				else:
					out.append("""		<td align="right">%u</td>""" % rootuid)
					out.append("""		<td align="right">%u</td>""" % rootgid)
				if meta or (sesflags&16)==0:
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
				else:
					out.append("""		<td align="right">%u</td>""" % mapalluid)
					out.append("""		<td align="right">%u</td>""" % mapallgid)
				if leaderconn.version_at_least(1,6,26):
					if mingoal!=None and maxgoal!=None:
						out.append("""		<td align="right">%u</td>""" % mingoal)
						out.append("""		<td align="right">%u</td>""" % maxgoal)
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if mintrashtime!=None and maxtrashtime!=None:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (mintrashtime,timeduration_to_fullstr(mintrashtime),timeduration_to_shortstr(mintrashtime)))
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (maxtrashtime,timeduration_to_fullstr(maxtrashtime),timeduration_to_shortstr(maxtrashtime)))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
				out.append("""	</tr>""")
			elif ttymode:
				dline = [sessionid,host,info]
				if leaderconn.version_at_least(1,7,8):
					dline.extend((openfiles,nsocks))
				dline.extend((strver,".&nbsp;(META)" if meta else path,"ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"))
				if leaderconn.version_at_least(1,7,0):
					dline.append("-" if meta else "yes" if sesflags&8 else "no")
				if meta:
					dline.extend(("-","-"))
				else:
					dline.extend((rootuid,rootgid))
				if meta or (sesflags&16)==0:
					dline.extend(("-","-"))
				else:
					dline.extend((mapalluid,mapallgid))
				if leaderconn.version_at_least(1,6,26):
					if mingoal!=None and maxgoal!=None:
						dline.extend((mingoal,maxgoal))
					else:
						dline.extend(("-","-"))
					if mintrashtime!=None and maxtrashtime!=None:
						dline.extend((timeduration_to_shortstr(mintrashtime),timeduration_to_shortstr(maxtrashtime)))
					else:
						dline.extend(("-","-"))
				tab.append(*dline)
			else:
				dline = [sessionid,host,info]
				if leaderconn.version_at_least(1,7,8):
					dline.extend((openfiles,nsocks))
				dline.extend((strver,".&nbsp;(META)" if meta else path,"ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"))
				if leaderconn.version_at_least(1,7,0):
					dline.append("-" if meta else "yes" if sesflags&8 else "no")
				if meta:
					dline.extend(("-","-"))
				else:
					dline.extend((rootuid,rootgid))
				if meta or (sesflags&16)==0:
					dline.extend(("-","-"))
				else:
					dline.extend((mapalluid,mapallgid))
				if leaderconn.version_at_least(1,6,26):
					if mingoal!=None and maxgoal!=None:
						dline.extend((mingoal,maxgoal))
					else:
						dline.extend(("-","-"))
					if mintrashtime!=None and maxtrashtime!=None:
						dline.extend((mintrashtime,maxtrashtime))
					else:
						dline.extend(("-","-"))
				tab.append(*dline)
		if len(dservers)>0 and leaderconn.version_at_least(1,7,8):
			if cgimode:
				out.append("""</table>""")
				out.append("""<br/>""")
				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmounts" cellspacing="0">""")
				out.append("""	<tr><th colspan="8">Inactive mounts (parameters)</th></tr>""")
				out.append("""	<tr>""")
				out.append("""		<th class="acid_tab_enumerate">#</th>""")
				out.append("""		<th>session&nbsp;id</th>""")
				out.append("""		<th>host</th>""")
				out.append("""		<th>ip</th>""")
				out.append("""		<th>mount&nbsp;point</th>""")
				out.append("""		<th>open files</th>""")
				out.append("""		<th>expires</th>""")
				out.append("""		<th>cmd</th>""")
				out.append("""	</tr>""")
			elif ttymode:
				tabcols = (19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12)
				tab.append(("---","",tabcols))
				tab.append(("Inactive mounts (parameters)","1c",tabcols))
				tab.append(("---","",tabcols))
				dline = [("session id","c"),("ip/host","c"),("mount point","c"),("open files","c"),("expires","c"),("command to remove","c",tabcols-5)]
				tab.append(*dline)
				tab.append(("---","",tabcols))
			else:
				print(tab)
				print("")
				tab = Tabble("inactive mounts, parameters",5)
		for sf,sessionid,host,sortipnum,ipnum,info,openfiles,expire in dservers:
			if cgimode:
				out.append("""	<tr>""")
				out.append("""		<td align="right"></td>""")
				out.append("""		<td align="center">%u</td>""" % sessionid)
				out.append("""		<td align="left">%s</td>""" % host)
				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
				out.append("""		<td align="left">%s</td>""" % info)
				out.append("""		<td align="center">%u</td>""" % openfiles)
				out.append("""		<td align="center">%u</td>""" % expire)
				out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % createlink({"MSremove":("%u" % (sessionid))}))
				out.append("""	</tr>""")
			elif ttymode:
				tabcols = (19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12)
				dline = [sessionid,host,info,openfiles,expire,("%s -H %s -P %u -CRS/%u" % (sys.argv[0],masterhost,masterport,sessionid),"l",tabcols-5)]
				tab.append(*dline)
			else:
				dline = [sessionid,host,info,openfiles,expire]
				tab.append(*dline)
		if cgimode:
			out.append("""</table>""")
			print("\n".join(out))
		else:
			print(tab)
	except Exception:
		print_exception()

if "MO" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	try:
		if cgimode:
			out = []
			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsops" cellspacing="0" id="mfsops">""")
#			out.append("""<table class="FR" cellspacing="0">""")
			out.append("""	<tr><th colspan="21">Active mounts (operations)</th></tr>""")
			out.append("""	<tr>""")
			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
#			out.append("""		<th rowspan="2"><a href="%s">host</a></th>""" % (createorderlink("MO",1)))
#			out.append("""		<th rowspan="2"><a href="%s">ip</a></th>""" % (createorderlink("MO",2)))
#			out.append("""		<th rowspan="2"><a href="%s">mount&nbsp;point</a></th>""" % (createorderlink("MO",3)))
			out.append("""		<th rowspan="2">host</th>""")
			out.append("""		<th rowspan="2">ip</th>""")
			out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
			out.append("""		<th colspan="17">""")
			out.append("""			<span class="opshour_vis0">operations last hour (<a href="javascript:acid_tab.switchdisplay('mfsops','opshour_vis',1)" class="VISIBLELINK">switch to current</a>)</span>""")
			out.append("""			<span class="opshour_vis1">operations current hour (<a href="javascript:acid_tab.switchdisplay('mfsops','opshour_vis',0)" class="VISIBLELINK">switch to last</a>)</span>""")
			out.append("""		</th>""")
			out.append("""	</tr>""")
			out.append("""	<tr>""")
#			out.append("""		<th><a href="%s">statfs</a></th>""" % (createorderlink("MO",100)))
#			out.append("""		<th><a href="%s">getattr</a></th>""" % (createorderlink("MO",101)))
#			out.append("""		<th><a href="%s">setattr</a></th>""" % (createorderlink("MO",102)))
#			out.append("""		<th><a href="%s">lookup</a></th>""" % (createorderlink("MO",103)))
#			out.append("""		<th><a href="%s">mkdir</a></th>""" % (createorderlink("MO",104)))
#			out.append("""		<th><a href="%s">rmdir</a></th>""" % (createorderlink("MO",105)))
#			out.append("""		<th><a href="%s">symlink</a></th>""" % (createorderlink("MO",106)))
#			out.append("""		<th><a href="%s">readlink</a></th>""" % (createorderlink("MO",107)))
#			out.append("""		<th><a href="%s">mknod</a></th>""" % (createorderlink("MO",108)))
#			out.append("""		<th><a href="%s">unlink</a></th>""" % (createorderlink("MO",109)))
#			out.append("""		<th><a href="%s">rename</a></th>""" % (createorderlink("MO",110)))
#			out.append("""		<th><a href="%s">link</a></th>""" % (createorderlink("MO",111)))
#			out.append("""		<th><a href="%s">readdir</a></th>""" % (createorderlink("MO",112)))
#			out.append("""		<th><a href="%s">open</a></th>""" % (createorderlink("MO",113)))
#			out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("MO",114)))
#			out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("MO",115)))
#			out.append("""		<th><a href="%s">total</a></th>""" % (createorderlink("MO",150)))
			out.append("""		<th class="acid_tab_level_1">statfs</th>""")
			out.append("""		<th class="acid_tab_level_1">getattr</th>""")
			out.append("""		<th class="acid_tab_level_1">setattr</th>""")
			out.append("""		<th class="acid_tab_level_1">lookup</th>""")
			out.append("""		<th class="acid_tab_level_1">mkdir</th>""")
			out.append("""		<th class="acid_tab_level_1">rmdir</th>""")
			out.append("""		<th class="acid_tab_level_1">symlink</th>""")
			out.append("""		<th class="acid_tab_level_1">readlink</th>""")
			out.append("""		<th class="acid_tab_level_1">mknod</th>""")
			out.append("""		<th class="acid_tab_level_1">unlink</th>""")
			out.append("""		<th class="acid_tab_level_1">rename</th>""")
			out.append("""		<th class="acid_tab_level_1">link</th>""")
			out.append("""		<th class="acid_tab_level_1">readdir</th>""")
			out.append("""		<th class="acid_tab_level_1">open</th>""")
			out.append("""		<th class="acid_tab_level_1">read</th>""")
			out.append("""		<th class="acid_tab_level_1">write</th>""")
			out.append("""		<th class="acid_tab_level_1">total</th>""")
			out.append("""	</tr>""")
		elif ttymode:
			tab = Tabble("Active mounts (operations)",19)
			tab.header("","",("operations %s hour" % ("last" if MOdata==0 else "current"),"",17))
			tab.header("host/ip","mount point",("---","",17))
			tab.header("","","statfs","getattr","setattr","lookup","mkdir","rmdir","symlink","readlink","mknod","unlink","rename","link","readdir","open","read","write","total")
			tab.defattr("r","l","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r")
		else:
			tab = Tabble("active mounts, operations",19)
		data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST)
		servers = []
		if leaderconn.version_less_than(1,6,21):
			statscnt = 16
			pos = 0
		elif leaderconn.version_is(1,6,21):
			statscnt = 21
			pos = 0
		else:
			statscnt = struct.unpack(">H",data[0:2])[0]
			pos = 2
		while pos<length:
			sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,ileng = struct.unpack(">LBBBBHBBL",data[pos:pos+16])
			sortipnum = "%03u.%03u.%03u.%03u" % (ip1,ip2,ip3,ip4)
			ipnum = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
#				sortver = "$05u.%03u.%03u" % (v1,v2,v3)
#				strver = "%u.%u.%u" % (v1,v2,v3)
			pos+=16
			info = data[pos:pos+ileng]
			pos+=ileng
			pleng = struct.unpack(">L",data[pos:pos+4])[0]
			pos+=4
			path = data[pos:pos+pleng]
			pos+=pleng
			if sys.version_info[0]>=3:
				try:
					info = info.decode('ascii')
				except UnicodeDecodeError:
					pass
				try:
					path = path.decode('ascii')
				except UnicodeDecodeError:
					pass
			# sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">BLLLL",data[pos:pos+17])
			pos+=17
			if statscnt<16:
				stats_c = struct.unpack(">"+"L"*statscnt,data[pos:pos+4*statscnt])+(0,)*(16-statscnt)
				pos+=statscnt*4
				stats_l = struct.unpack(">"+"L"*statscnt,data[pos:pos+4*statscnt])+(0,)*(16-statscnt)
				pos+=statscnt*4
			else:
				stats_c = struct.unpack(">LLLLLLLLLLLLLLLL",data[pos:pos+64])
				pos+=statscnt*4
				stats_l = struct.unpack(">LLLLLLLLLLLLLLLL",data[pos:pos+64])
				pos+=statscnt*4
			host = resolve(ipnum)
			sf = sortipnum
			if MOorder==1:
				sf = host
			elif MOorder==2:
				sf = sortipnum
			elif MOorder==3:
				sf = info
			elif MOorder>=100 and MOorder<=115:
				if MOdata==0:
					sf = stats_l[MOorder-100]
				else:
					sf = stats_c[MOorder-100]
				if cgimode:
					sf = -sf
			elif MOorder==150:
				if MOdata==0:
					sf = sum(stats_l)
				else:
					sf = sum(stats_c)
				if cgimode:
					sf = -sf
			if path!='.':
				servers.append((sf,host,ipnum,info,stats_c,stats_l))
		servers.sort()
		if MOrev:
			servers.reverse()
		for sf,host,ipnum,info,stats_c,stats_l in servers:
			if cgimode:
				out.append("""	<tr>""")
				out.append("""		<td align="right"></td>""")
				out.append("""		<td align="left">%s</td>""" % host)
				out.append("""		<td align="center"><span class="sortkey">%s</span>%s</td>""" % (sortipnum,ipnum))
				out.append("""		<td align="left">%s</td>""" % info)
				for st in range(16):
					out.append("""		<td align="right">""")
					out.append("""			<span class="opshour_vis0"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (stats_c[st],stats_l[st],stats_l[st]))
					out.append("""			<span class="opshour_vis1"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (stats_c[st],stats_l[st],stats_c[st]))
					out.append("""		</td>""")
				out.append("""		<td align="right">""")
				out.append("""			<span class="opshour_vis0"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (sum(stats_c),sum(stats_l),sum(stats_l)))
				out.append("""			<span class="opshour_vis1"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (sum(stats_c),sum(stats_l),sum(stats_c)))
				out.append("""		</td>""")
#					if MOdata==0:
#						for st in xrange(16):
#							out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (stats_c[st],stats_l[st],stats_l[st]))
#						out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (sum(stats_c),sum(stats_l),sum(stats_l)))
#					else:
#						for st in xrange(16):
#							out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (stats_c[st],stats_l[st],stats_c[st]))
#						out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (sum(stats_c),sum(stats_l),sum(stats_c)))
				out.append("""	</tr>""")
			else:
				ldata = [host,info]
				if MOdata==0:
					ldata.extend(stats_l)
					ldata.append(sum(stats_l))
				else:
					ldata.extend(stats_c)
					ldata.append(sum(stats_c))
				tab.append(*ldata)
		if cgimode:
			out.append("""</table>""")
			print("\n".join(out))
		else:
			print(tab)
	except Exception:
		print_exception()

if "QU" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	try:
		if cgimode:
			out = []
			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsquota" cellspacing="0">""")
			out.append("""	<tr><th colspan="23">Active quotas</th></tr>""")
			out.append("""	<tr>""")
			out.append("""		<th rowspan="3" class="acid_tab_enumerate">#</th>""")
#			out.append("""		<th rowspan="2"><a href="%s">path</a></th>""" % (createorderlink("QU",11)))
#			out.append("""		<th rowspan="2"><a href="%s">exceeded</a></th>""" % (createorderlink("QU",2)))
			out.append("""		<th rowspan="3">path</th>""")
			out.append("""	<th colspan="5">soft&nbsp;quota</th>""")
			out.append("""	<th colspan="4">hard&nbsp;quota</th>""")
			out.append("""	<th colspan="12">current&nbsp;values</th>""")
			out.append("""	</tr>""")
			out.append("""	<tr>""")
#			out.append("""		<th><a href="%s">time&nbsp;to&nbsp;expire</a></th>""" % (createorderlink("QU",10)))
#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",11)))
#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",12)))
#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",13)))
#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",14)))
#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",21)))
#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",22)))
#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",23)))
#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",24)))
#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",31)))
#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",32)))
#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",33)))
#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",34)))
#			out.append("""		<th>exceeded</th>""")
			out.append("""		<th rowspan="2">time&nbsp;to&nbsp;expire</th>""")
			out.append("""		<th rowspan="2">inodes</th>""")
			out.append("""		<th rowspan="2">length</th>""")
			out.append("""		<th rowspan="2">size</th>""")
			out.append("""		<th rowspan="2">real&nbsp;size</th>""")
			out.append("""		<th rowspan="2">inodes</th>""")
			out.append("""		<th rowspan="2">length</th>""")
			out.append("""		<th rowspan="2">size</th>""")
			out.append("""		<th rowspan="2">real&nbsp;size</th>""")
			out.append("""		<th colspan="3">inodes</th>""")
			out.append("""		<th colspan="3">length</th>""")
			out.append("""		<th colspan="3">size</th>""")
			out.append("""		<th colspan="3">real&nbsp;size</th>""")
			out.append("""	</tr>""")
			out.append("""	<tr>""")
			out.append("""		<th>value</th>""")
			out.append("""		<th>% soft</th>""")
			out.append("""		<th>% hard</th>""")
			out.append("""		<th>value</th>""")
			out.append("""		<th>% soft</th>""")
			out.append("""		<th>% hard</th>""")
			out.append("""		<th>value</th>""")
			out.append("""		<th>% soft</th>""")
			out.append("""		<th>% hard</th>""")
			out.append("""		<th>value</th>""")
			out.append("""		<th>% soft</th>""")
			out.append("""		<th>% hard</th>""")
			out.append("""	</tr>""")
		elif ttymode:
#			tab = Tabble("Active quotas",14)
#			tab.header("",("soft quota","",5),("hard quota","",4),("current values","",4))
#			tab.header("path",("---","",13))
#			tab.header("","time to expire","inodes","length","size","real size","inodes","length","size","real size","inodes","length","size","real size")
#			tab.defattr("l","r","r","r","r","r","r","r","r","r","r","r","r","r")
			tab = Tabble("Active quotas",22)
			tab.header("",("soft quota","",5),("hard quota","",4),("current values","",12))
			tab.header("",("---","",21))
			tab.header("path","","","","","","","","","",("inodes","",3),("length","",3),("size","",3),("real size","",3))
			tab.header("","time to expire","inodes","length","size","real size","inodes","length","size","real size",("---","",12))
			tab.header("","","","","","","","","","","value","% soft","% hard","value","% soft","% hard","value","% soft","% hard","value","% soft","% hard")
			tab.defattr("l","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r")
		else:
			tab = Tabble("active quotas",14)
		data,length = leaderconn.command(CLTOMA_QUOTA_INFO,MATOCL_QUOTA_INFO)
		if length>=4 and leaderconn.version_at_least(1,7,0):
			quotas = []
			maxperc = 0.0
			pos = 0
			while pos<length:
				inode,pleng = struct.unpack(">LL",data[pos:pos+8])
				pos+=8
				path = data[pos:pos+pleng]
				if sys.version_info[0]>=3:
					try:
						path = path.decode('ascii')
					except UnicodeDecodeError:
						pass
				pos+=pleng
				exceeded,qflags,timetoblock = struct.unpack(">BBL",data[pos:pos+6])
				pos+=6;
				sinodes,slength,ssize,srealsize = struct.unpack(">LQQQ",data[pos:pos+28])
				pos+=28
				hinodes,hlength,hsize,hrealsize = struct.unpack(">LQQQ",data[pos:pos+28])
				pos+=28
				cinodes,clength,csize,crealsize = struct.unpack(">LQQQ",data[pos:pos+28])
				pos+=28
				if (qflags&1) and sinodes>0:
					perc = 100.0*cinodes/sinodes
					if perc>maxperc:
						maxperc = perc
				if (qflags&2) and slength>0:
					perc = 100.0*clength/slength
					if perc>maxperc:
						maxperc = perc
				if (qflags&4) and ssize>0:
					perc = 100.0*csize/ssize
					if perc>maxperc:
						maxperc = perc
				if (qflags&8) and srealsize>0:
					perc = 100.0*crealsize/srealsize
					if perc>maxperc:
						maxperc = perc
				if (qflags&16) and hinodes>0:
					perc = 100.0*cinodes/hinodes
					if perc>maxperc:
						maxperc = perc
				if (qflags&32) and hlength>0:
					perc = 100.0*clength/hlength
					if perc>maxperc:
						maxperc = perc
				if (qflags&64) and hsize>0:
					perc = 100.0*csize/hsize
					if perc>maxperc:
						maxperc = perc
				if (qflags&128) and hrealsize>0:
					perc = 100.0*crealsize/hrealsize
					if perc>maxperc:
						maxperc = perc
				sf = path
				if QUorder==1:
					sf = path
				elif QUorder==2:
					sf = exceeded
				elif QUorder==10:
					sf = timetoblock
				elif QUorder==11:
					sf = sinodes
				elif QUorder==12:
					sf = slength
				elif QUorder==13:
					sf = ssize
				elif QUorder==14:
					sf = srealsize
				elif QUorder==21:
					sf = hinodes
				elif QUorder==22:
					sf = hlength
				elif QUorder==23:
					sf = hsize
				elif QUorder==24:
					sf = hrealsize
				elif QUorder==31:
					sf = cinodes
				elif QUorder==32:
					sf = clength
				elif QUorder==33:
					sf = csize
				elif QUorder==34:
					sf = crealsize
				elif QUorder==41:
					sf = (-1,0) if (qflags&1)==0 else (1,0) if sinodes==0 else (0,1.0*cinodes/sinodes)
				elif QUorder==42:
					sf = (-1,0) if (qflags&2)==0 else (1,0) if slength==0 else (0,1.0*clength/slength)
				elif QUorder==43:
					sf = (-1,0) if (qflags&4)==0 else (1,0) if ssize==0 else (0,1.0*csize/ssize)
				elif QUorder==44:
					sf = (-1,0) if (qflags&8)==0 else (1,0) if srealsize==0 else (0,1.0*crealsize/srealsize)
				elif QUorder==51:
					sf = (-1,0) if (qflags&16)==0 else (1,0) if hinodes==0 else (0,1.0*cinodes/hinodes)
				elif QUorder==52:
					sf = (-1,0) if (qflags&32)==0 else (1,0) if hlength==0 else (0,1.0*clength/hlength)
				elif QUorder==53:
					sf = (-1,0) if (qflags&64)==0 else (1,0) if hsize==0 else (0,1.0*csize/hsize)
				elif QUorder==54:
					sf = (-1,0) if (qflags&128)==0 else (1,0) if hrealsize==0 else (0,1.0*crealsize/hrealsize)
				quotas.append((sf,path,exceeded,qflags,timetoblock,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize,cinodes,clength,csize,crealsize))
			quotas.sort()
			if QUrev:
				quotas.reverse()
			maxperc += 0.01
			for sf,path,exceeded,qflags,timetoblock,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize,cinodes,clength,csize,crealsize in quotas:
				if cgimode:
					out.append("""	<tr>""")
					out.append("""		<td align="right"></td>""")
					out.append("""		<td align="left">%s</td>""" % path)
	#				out.append("""		<td align="center">%s</td>""" % ("yes" if exceeded else "no"))
					if timetoblock<0xFFFFFFFF:
						if timetoblock>0:
	#						days,rest = divmod(timetoblock,86400)
	#						hours,rest = divmod(rest,3600)
	#						min,sec = divmod(rest,60)
	#						if days>0:
	#							tbstr = "%ud,&nbsp;%uh&nbsp;%um&nbsp;%us" % (days,hours,min,sec)
	#						elif hours>0:
	#							tbstr = "%uh&nbsp;%um&nbsp;%us" % (hours,min,sec)
	#						elif min>0:
	#							tbstr = "%um&nbsp;%us" % (min,sec)
	#						else:
	#							tbstr = "%us" % sec
							out.append("""		<td align="center"><span class="SEXCEEDED"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></span></td>""" % (timetoblock,timeduration_to_fullstr(timetoblock),timeduration_to_shortstr(timetoblock)))
						else:
							out.append("""		<td align="center"><span class="EXCEEDED"><span class="sortkey">0 </span>expired</span></td>""")
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&1:
						out.append("""		<td align="right"><span>%u</span></td>""" % (sinodes))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&2:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (slength,decimal_number(slength),humanize_number(slength,"&nbsp;")))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&4:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (ssize,decimal_number(ssize),humanize_number(ssize,"&nbsp;")))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&8:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (srealsize,decimal_number(srealsize),humanize_number(srealsize,"&nbsp;")))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&16:
						out.append("""		<td align="right"><span>%u</span></td>""" % (hinodes))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&32:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (hlength,decimal_number(hlength),humanize_number(hlength,"&nbsp;")))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&64:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (hsize,decimal_number(hsize),humanize_number(hsize,"&nbsp;")))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&128:
						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (hrealsize,decimal_number(hrealsize),humanize_number(hrealsize,"&nbsp;")))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="right">%u</td>""" % cinodes)
					if qflags&1:
						if sinodes>0:
							if sinodes>=cinodes:
								cl="NOTEXCEEDED"
							elif timetoblock>0:
								cl="SEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*cinodes)/sinodes))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&16:
						if hinodes>0:
							if hinodes>cinodes:
								cl="NOTEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*cinodes)/hinodes))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (clength,decimal_number(clength),humanize_number(clength,"&nbsp;")))
					if qflags&2:
						if slength>0:
							if slength>=clength:
								cl="NOTEXCEEDED"
							elif timetoblock>0:
								cl="SEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*clength)/slength))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&32:
						if hlength>0:
							if hlength>clength:
								cl="NOTEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*clength)/hlength))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (csize,decimal_number(csize),humanize_number(csize,"&nbsp;")))
					if qflags&4:
						if ssize>0:
							if ssize>=csize:
								cl="NOTEXCEEDED"
							elif timetoblock>0:
								cl="SEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*csize)/ssize))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&64:
						if hsize>0:
							if hsize>csize:
								cl="NOTEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*csize)/hsize))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (crealsize,decimal_number(crealsize),humanize_number(crealsize,"&nbsp;")))
					if qflags&8:
						if srealsize>0:
							if srealsize>=crealsize:
								cl="NOTEXCEEDED"
							elif timetoblock>0:
								cl="SEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*crealsize)/srealsize))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					if qflags&128:
						if hrealsize>0:
							if hrealsize>crealsize:
								cl="NOTEXCEEDED"
							else:
								cl="EXCEEDED"
							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*crealsize)/hrealsize))
						else:
							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
					else:
						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
					out.append("""	</tr>""")
				elif ttymode:
					dline = [path] #,"yes" if exceeded else "no"]
					if timetoblock<0xFFFFFFFF:
						if timetoblock>0:
							dline.append((timeduration_to_shortstr(timetoblock),"2"))
						else:
							dline.append(("expired","1"))
					else:
						dline.append("-")
					if qflags&1:
						dline.append(sinodes)
					else:
						dline.append("-")
					if qflags&2:
						dline.append(humanize_number(slength," "))
					else:
						dline.append("-")
					if qflags&4:
						dline.append(humanize_number(ssize," "))
					else:
						dline.append("-")
					if qflags&8:
						dline.append(humanize_number(srealsize," "))
					else:
						dline.append("-")
					if qflags&16:
						dline.append(hinodes)
					else:
						dline.append("-")
					if qflags&32:
						dline.append(humanize_number(hlength," "))
					else:
						dline.append("-")
					if qflags&64:
						dline.append(humanize_number(hsize," "))
					else:
						dline.append("-")
					if qflags&128:
						dline.append(humanize_number(hrealsize," "))
					else:
						dline.append("-")
					dline.append(cinodes)
					if qflags&1:
						if sinodes>0:
							dline.append(("%.2f" % ((100.0*cinodes)/sinodes),"4" if sinodes>=cinodes else "2" if timetoblock>0 else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					if qflags&16:
						if hinodes>0:
							dline.append(("%.2f" % ((100.0*cinodes)/hinodes),"4" if hinodes>cinodes else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					dline.append(humanize_number(clength," "))
					if qflags&2:
						if slength>0:
							dline.append(("%.2f" % ((100.0*clength)/slength),"4" if slength>=clength else "2" if timetoblock>0 else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					if qflags&32:
						if hlength>0:
							dline.append(("%.2f" % ((100.0*clength)/hlength),"4" if hlength>clength else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					dline.append(humanize_number(csize," "))
					if qflags&4:
						if ssize>0:
							dline.append(("%.2f" % ((100.0*csize)/ssize),"4" if ssize>=csize else "2" if timetoblock>0 else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					if qflags&64:
						if hsize>0:
							dline.append(("%.2f" % ((100.0*csize)/hsize),"4" if hsize>csize else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					dline.append(humanize_number(crealsize," "))
					if qflags&8:
						if srealsize>0:
							dline.append(("%.2f" % ((100.0*crealsize)/srealsize),"4" if srealsize>=crealsize else "2" if timetoblock>0 else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					if qflags&128:
						if hrealsize>0:
							dline.append(("%.2f" % ((100.0*crealsize)/hrealsize),"4" if hrealsize>crealsize else "1"))
						else:
							dline.append(("inf","1"))
					else:
						dline.append("-")
					tab.append(*dline)
				else:
					dline = [path,"yes" if exceeded else "no"]
					if timetoblock<0xFFFFFFFF:
						if timetoblock>0:
							dline.append(timetoblock)
						else:
							dline.append("expired")
					else:
						dline.append("-")
					dline.append(sinodes if qflags&1 else "-")
					dline.append(slength if qflags&2 else "-")
					dline.append(ssize if qflags&4 else "-")
					dline.append(srealsize if qflags&8 else "-")
					dline.append(hinodes if qflags&16 else "-")
					dline.append(hlength if qflags&32 else "-")
					dline.append(hsize if qflags&64 else "-")
					dline.append(hrealsize if qflags&128 else "-")
					dline.extend((cinodes,clength,csize,crealsize))
					tab.append(*dline)
		if cgimode:
			out.append("""</table>""")
			print("\n".join(out))
		else:
			print(tab)
	except Exception:
		print_exception()

if "MC" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	out = []

	try:
		if cgimode:
			charts = (
				(100,'cpu','cpu usage (percent)'),
				(101,'memory','memory usage (if available - rss + virt)'),
				(2,'dels','chunk deletions (per minute)'),
				(3,'repl','chunk replications (per minute)'),
				(4,'stafs','statfs operations (per minute)'),
				(5,'getattr','getattr operations (per minute)'),
				(6,'setattr','setattr operations (per minute)'),
				(7,'lookup','lookup operations (per minute)'),
				(8,'mkdir','mkdir operations (per minute)'),
				(9,'rmdir','rmdir operations (per minute)'),
				(10,'symlink','symlink operations (per minute)'),
				(11,'readlink','readlink operations (per minute)'),
				(12,'mknod','mknod operations (per minute)'),
				(13,'unlink','unlink operations (per minute)'),
				(14,'rename','rename operations (per minute)'),
				(15,'link','link operations (per minute)'),
				(16,'readdir','readdir operations (per minute)'),
				(17,'open','open operations (per minute)'),
				(18,'read','read operations (per minute)'),
				(19,'write','write operations (per minute)'),
				(21,'prcvd','packets received (per second)'),
				(22,'psent','packets sent (per second)'),
				(23,'brcvd','bits received (per second)'),
				(24,'bsent','bits sent (per second)')
			)

			if MCdata=="" and leaderfound:
				MCdata="%s:%u:%u" % (leaderconn.host,leaderconn.port,1 if leaderconn.version_at_least(2,0,0) else 0)
			servers = []
			mixedservers = 0
			if len(masterlistver)>0:
				masterlistver.sort()
				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Select: <select name="server" size="1" onchange="document.location.href='%s&amp;MCdata='+this.options[this.selectedIndex].value">""" % createlink({"MCdata":""}))
				entrystr = []
				entrydesc = {}
				for id,oname,desc in charts:
					name = oname.replace(":","")
					entrystr.append(name)
					entrydesc[name] = desc
				for strip,port,version in masterlistver:
					nc = 1 if version>=(2,0,0) else 0
					if mixedservers==0:
						mixedservers = nc+1
					if mixedservers!=nc+1:
						mixedservers = 3
					name = "%s:%u" % (strip,port)
					namearg = "%s:%u" % (name,nc)
					hostx = resolve(strip)
					if hostx==UNRESOLVED:
						host = ""
					else:
						host = " / "+hostx
					entrystr.append(namearg)
					entrydesc[namearg] = "Server: %s%s%s" % (name,host," *" if strip==leaderconn.host else "")
					servers.append((strip,port,"ma_"+name.replace(".","_").replace(":","_"),entrydesc[namearg],nc))
				if MCdata not in entrystr:
					out.append("""<option value="" selected="selected"> data type or server</option>""")
				for estr in entrystr:
					if estr==MCdata:
						out.append("""<option value="%s" selected="selected">%s</option>""" % (estr,entrydesc[estr]))
					else:
						out.append("""<option value="%s">%s</option>""" % (estr,entrydesc[estr]))
				out.append("""</select></th></tr></table></form><br/>""")

			mchtmp = MCdata.split(":")
			if len(mchtmp)==2:
				mchtmp = (mchtmp[0],mchtmp[1],0)
			if len(mchtmp)==3:
				mahost = mchtmp[0]
				maport = mchtmp[1]
				manc = int(mchtmp[2])

				out.append("""<script type="text/javascript">""")
				out.append("""<!--//--><![CDATA[//><!--""")
				out.append("""	var ma_vids = [%s];""" % ",".join(map(repr,[ x[0] for x in charts ])))
				out.append("""	var ma_inames = [%s];""" % ",".join(map(repr,[ x[1] for x in charts ])))
				out.append("""	var ma_idesc = [%s];""" % ",".join(map(repr,[ x[2] for x in charts ])))
				out.append("""	var ma_host = "%s";""" % mahost)
				out.append("""	var ma_port = "%s";""" % maport)
				out.append("""	var ma_nc = %u;""" % manc)
				out.append("""//--><!]]>""")
				out.append("""</script>""")
				out.append("""<script type="text/javascript">
<!--//--><![CDATA[//><!--
	var i,j;
	var ma_chartid = [0,0];
	var ma_range_up=0;
	var ma_range_down=0;
	var ma_zoomed = [];
	var ma_resizeto;
	function ma_refresh() {
		var i;
		var minutes = Math.floor((new Date()).getTime()/60000);
		for (i=0 ; i<ma_inames.length ; i++) {
			var name = ma_inames[i];
			var vid = ma_vids[i];
			var id = vid*10+ma_range_up;
			var element = document.getElementById(name);
			if (element) {
				var url;
				if (ma_nc) {
					var width = element.scrollWidth;
					var height = element.scrollHeight;
					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
				} else {
					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;antycache="+minutes;
				}
				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
					element.ma_url = url;
					element.style.backgroundImage = "url('"+url+"')";
				}
			}
		}
		for (i=0 ; i<2 ; i++) {
			var vid = ma_vids[ma_chartid[i]];
			var id = vid*10+ma_range_down;
			var iname = "ma_chart"+i;
			var element = document.getElementById(iname);
			if (element) {
				var url;
				if (ma_nc) {
					var width = element.scrollWidth;
					var height = element.scrollHeight;
					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
				} else {
					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;antycache="+minutes;
				}
				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
					element.ma_url = url;
					element.style.backgroundImage = "url('"+url+"')";
				}
			}
		}
	}
	function ma_change_up(num) {
		ma_range_up = num;
		ma_refresh();
	}
	function ma_change_down(num) {
		ma_range_down = num;
		ma_refresh();
	}
	function ma_zoom(element) {
		var name = element.id;
		if (typeof(ma_zoomed[name])=="undefined") {
			ma_zoomed[name]=0;
		}
		if (ma_zoomed[name]==0) {
			ma_zoomed[name]=1;
			element.style.height = '220px';
		} else if (ma_zoomed[name]==1) {
			ma_zoomed[name]=2;
			element.style.height = '420px';
		} else if (ma_zoomed[name]==2) {
			ma_zoomed[name]=3;
			element.style.height = '820px';
		} else {
			ma_zoomed[name]=0;
			element.style.height = '120px';
		}
		ma_refresh();
	}
	function ma_resized() {
		clearTimeout(ma_resizeto);
		ma_resizeto = setTimeout(ma_refresh,250);
	}
	function ma_change_type(id,no) {
		var o;
		o = document.getElementById("ma_cell_"+id+"_"+ma_chartid[id]);
		o.className="REL";
		ma_chartid[id]=no;
		o = document.getElementById("ma_cell_"+id+"_"+ma_chartid[id]);
		o.className="PR";
		o = document.getElementById("ma_desc"+id);
		o.innerHTML = ma_idesc[no];
		ma_refresh();
	}
	function ma_add_event(obj,type,fn) {
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
		} else if (obj.attachEvent) {
			obj.attachEvent('on'+type, fn);
		}
	}
	ma_add_event(window,"load",ma_refresh);
	ma_add_event(window,"resize",ma_resized);
//--><!]]>
</script>""")
				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
				out.append("""	<tr>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(0);">short range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(1);">medium range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(2);">long range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(3);">very long range</a></th>""")
				out.append("""	</tr>""")
				for id,name,desc in charts:
					divclass = "CHARTDYNAMIC" if manc else "CHARTSTATIC"
					divclick = 'onclick="ma_zoom(this)"' if manc else ""
					out.append("""	<tr class="C2">""")
					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
					out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
					out.append("""				<span class="CAPTION">%s</span>""" % desc)
					out.append("""			</div>""")
					out.append("""		</td>""")
					out.append("""	</tr>""")
				out.append("""</table>""")
				out.append("""<br/>""")

				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
				out.append("""	<tr>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(0);">short range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(1);">medium range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(2);">long range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(3);">very long range</a></th>""")
				out.append("""	</tr>""")
				for i in range(2):
					divclass = "CHARTDYNAMIC" if manc else "CHARTSTATIC"
					divclick = 'onclick="ma_zoom(this)"' if manc else ""
					out.append("""	<tr class="C2">""")
					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
					out.append("""			<div class="%s" id="ma_chart%u" %s>""" % (divclass,i,divclick))
					out.append("""				<span class="CAPTION" id="ma_desc%u">%s</span>""" % (i,charts[0][2]))
					out.append("""			</div>""")
					out.append("""		</td>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<td colspan="4">""")
					out.append("""			<table class="BOTMENU" cellspacing="0">""")
					out.append("""				<tr>""")
					no=0
					cl="PR"
					for id,name,desc in charts:
						out.append("""					<td align="center" id="ma_cell_%u_%u" class="%s"><a href="javascript:ma_change_type(%u,%u);" title="%s">%s</a></td>""" % (i,no,cl,i,no,desc,name))
						cl="REL"
						no+=1
					out.append("""				</tr>""")
					out.append("""			</table>""")
					out.append("""		</td>""")
					out.append("""	</tr>""")
				out.append("""</table>""")
			elif len(mchtmp)==1 and len(MCdata)>0:
				chid = 0
				for id,name,desc in charts:
					if name==MCdata:
						chid = id
				if chid==0:
					try:
						chid = int(MCdata)
					except Exception:
						pass
				if chid>0 and chid<1000:
					out.append("""<script type="text/javascript">""")
					out.append("""<!--//--><![CDATA[//><!--""")
					out.append("""	var ma_vhosts = [%s];""" % ",".join(map(repr,[ x[0] for x in servers ])))
					out.append("""	var ma_vports = [%s];""" % ",".join(map(repr,[ x[1] for x in servers ])))
					out.append("""	var ma_inames = [%s];""" % ",".join(map(repr,[ x[2] for x in servers ])))
					out.append("""	var ma_nc = [%s];""" % ",".join(map(repr,[ x[4] for x in servers ])))
					out.append("""	var ma_chid = %u;""" % chid);
					out.append("""//--><!]]>""")
					out.append("""</script>""")
					out.append("""<script type="text/javascript">
<!--//--><![CDATA[//><!--
	var i,j;
	var ma_range=0;
	var ma_zoomed = [];
	var ma_resizeto;
	function ma_refresh() {
		var i;
		var minutes = Math.floor((new Date()).getTime()/60000);
		for (i=0 ; i<ma_inames.length ; i++) {
			var name = ma_inames[i];
			var vhost = ma_vhosts[i];
			var vport = ma_vports[i];
			var manc = ma_nc[i];
			var id = ma_chid*10+ma_range;
			var element = document.getElementById(name);
			if (element) {
				var url;
				if (manc) {
					var width = element.scrollWidth;
					var height = element.scrollHeight;
					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
				} else {
					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;antycache="+minutes;
				}
				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
					element.ma_url = url;
					element.style.backgroundImage = "url('"+url+"')";
				}
			}
		}
	}
	function ma_change(num) {
		ma_range = num;
		ma_refresh();
	}
	function ma_zoom(element) {
		var name = element.id;
		if (typeof(ma_zoomed[name])=="undefined") {
			ma_zoomed[name]=0;
		}
		if (ma_zoomed[name]==0) {
			ma_zoomed[name]=1;
			element.style.height = '220px';
		} else if (ma_zoomed[name]==1) {
			ma_zoomed[name]=2;
			element.style.height = '420px';
		} else if (ma_zoomed[name]==2) {
			ma_zoomed[name]=3;
			element.style.height = '820px';
		} else {
			ma_zoomed[name]=0;
			element.style.height = '120px';
		}
		ma_refresh();
	}
	function ma_resized() {
		clearTimeout(ma_resizeto);
		ma_resizeto = setTimeout(ma_refresh,250);
	}
	function ma_add_event(obj,type,fn) {
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
		} else if (obj.attachEvent) {
			obj.attachEvent('on'+type, fn);
		}
	}
	ma_add_event(window,"load",ma_refresh);
	ma_add_event(window,"resize",ma_resized);
//--><!]]>
</script>""")
					out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
					out.append("""	<tr>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(0);">short range</a></th>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(1);">medium range</a></th>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(2);">long range</a></th>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(3);">very long range</a></th>""")
					out.append("""	</tr>""")
					for mahost,maport,name,desc,manc in servers:
						divclass = "CHARTDYNAMIC" if manc else "CHARTSTATICMIXED" if mixedservers==3 else "CHARTSTATIC"
						divclick = 'onclick="ma_zoom(this)"' if manc else ""
						out.append("""	<tr class="C2">""")
						out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
						out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
						out.append("""				<span class="CAPTION">%s</span>""" % desc)
						out.append("""			</div>""")
						out.append("""		</td>""")
						out.append("""	</tr>""")
					out.append("""</table>""")
		else:
			out.append("""master charts are unavailable in CLI mode""")
		print("\n".join(out))
	except Exception:
		print_exception()

if "CC" in sectionset:
	if needseparator:
		if cgimode:
			print("""<br/>""")
		else:
			print("")
	else:
		needseparator=1

	out = []

	try:
		if cgimode:
			# get cs list
			hostlist = []
			data,length = leaderconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
			if leaderconn.version_at_least(1,7,25) and (length%64)==0:
				n = length//64
				servers = []
				for i in range(n):
					d = data[i*64:(i+1)*64]
					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
					if (flags&1)==0:
						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
			elif leaderconn.version_at_least(1,6,28) and leaderconn.version_less_than(1,7,25) and (length%62)==0:
				n = length//62
				servers = []
				for i in range(n):
					d = data[i*62:(i+1)*62]
					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
					if disconnected==0:
						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
			elif leaderconn.version_less_than(1,6,28) and (length%54)==0:
				n = length//54
				servers = []
				for i in range(n):
					d = data[i*54:(i+1)*54]
					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
					if disconnected==0:
						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
			charts = (
				(100,'cpu','cpu usage (percent)'),
				(107,'memory','memory usage (if available - rss + virt)'),
				(101,'datain','traffic from clients and other chunkservers (bits/s - main server + replicator)'),
				(102,'dataout','traffic to clients and other chunkservers (bits/s - main server + replicator)'),
				(103,'bytesr','bytes read - data/other (bytes/s)'),
				(104,'bytesw','bytes written - data/other (bytes/s)'),
				(2,'masterin','traffic from master (bits/s)'),
				(3,'masterout','traffic to master (bits/s)'),
				(105,'hddopr','number of low-level read operations per minute'),
				(106,'hddopw','number of low-level write operations per minute'),
				(16,'hlopr','number of high-level read operations per minute'),
				(17,'hlopw','number of high-level write operations per minute'),
				(18,'rtime','time of data read operations'),
				(19,'wtime','time of data write operations'),
				(20,'repl','number of chunk replications per minute'),
				(21,'create','number of chunk creations per minute'),
				(22,'delete','number of chunk deletions per minute'),
				(28,'load','load - max operations in queue'),
			)

			servers = []
			mixedservers = 0
			if len(hostlist)>0:
				hostlist.sort()
				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Select: <select name="server" size="1" onchange="document.location.href='%s&amp;CCdata='+this.options[this.selectedIndex].value">""" % createlink({"CCdata":""}))
				entrystr = []
				entrydesc = {}
				for id,oname,desc in charts:
					name = oname.replace(":","")
					entrystr.append(name)
					entrydesc[name] = desc
				for ip,port,version in hostlist:
					nc = 1 if version>=(2,0,0) else 0
					if mixedservers==0:
						mixedservers = nc+1
					if mixedservers!=nc+1:
						mixedservers = 3
					strip = "%u.%u.%u.%u" % ip
					name = "%s:%u" % (strip,port)
					namearg = "%s:%u" % (name,nc)
					hostx = resolve(strip)
					if hostx==UNRESOLVED:
						host = ""
					else:
						host = " / "+hostx
					entrystr.append(namearg)
					entrydesc[namearg] = "Server: %s%s" % (name,host)
					servers.append((strip,port,"cs_"+name.replace(".","_").replace(":","_"),entrydesc[namearg],nc))
				if CCdata not in entrystr:
					out.append("""<option value="" selected="selected"> data type or server</option>""")
				for estr in entrystr:
					if estr==CCdata:
						out.append("""<option value="%s" selected="selected">%s</option>""" % (estr,entrydesc[estr]))
					else:
						out.append("""<option value="%s">%s</option>""" % (estr,entrydesc[estr]))
				out.append("""</select></th></tr></table></form><br/>""")

			cchtmp = CCdata.split(":")
			if len(cchtmp)==2:
				cchtmp = (cchtmp[0],cchtmp[1],0)
			if len(cchtmp)==3:
				cshost = cchtmp[0]
				csport = cchtmp[1]
				csnc = int(cchtmp[2])

				out.append("""<script type="text/javascript">""")
				out.append("""<!--//--><![CDATA[//><!--""")
				out.append("""	var cs_vids = [%s];""" % ",".join(map(repr,[ x[0] for x in charts ])))
				out.append("""	var cs_inames = [%s];""" % ",".join(map(repr,[ x[1] for x in charts ])))
				out.append("""	var cs_idesc = [%s];""" % ",".join(map(repr,[ x[2] for x in charts ])))
				out.append("""	var cs_host = "%s";""" % cshost)
				out.append("""	var cs_port = "%s";""" % csport)
				out.append("""	var cs_nc = %u;""" % csnc)
				out.append("""//--><!]]>""")
				out.append("""</script>""")
				out.append("""<script type="text/javascript">
<!--//--><![CDATA[//><!--
	var i,j;
	var cs_chartid = [0,0];
	var cs_range_up=0;
	var cs_range_down=0;
	var cs_zoomed = [];
	var cs_resizeto;
	function cs_refresh() {
		var i;
		var minutes = Math.floor((new Date()).getTime()/60000);
		for (i=0 ; i<cs_inames.length ; i++) {
			var name = cs_inames[i];
			var vid = cs_vids[i];
			var id = vid*10+cs_range_up;
			var element = document.getElementById(name);
			if (element) {
				var url;
				if (cs_nc) {
					var width = element.scrollWidth;
					var height = element.scrollHeight;
					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
				} else {
					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;antycache="+minutes;
				}
				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
					element.cs_url = url;
					element.style.backgroundImage = "url('"+url+"')";
				}
			}
		}
		for (i=0 ; i<2 ; i++) {
			var vid = cs_vids[cs_chartid[i]];
			var id = vid*10+cs_range_down;
			var iname = "cs_chart"+i;
			var element = document.getElementById(iname);
			if (element) {
				var url;
				if (cs_nc) {
					var width = element.scrollWidth;
					var height = element.scrollHeight;
					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
				} else {
					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;antycache="+minutes;
				}
				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
					element.cs_url = url;
					element.style.backgroundImage = "url('"+url+"')";
				}
			}
		}
	}
	function cs_change_up(num) {
		cs_range_up = num;
		cs_refresh();
	}
	function cs_change_down(num) {
		cs_range_down = num;
		cs_refresh();
	}
	function cs_zoom(element) {
		var name = element.id;
		if (typeof(cs_zoomed[name])=="undefined") {
			cs_zoomed[name]=0;
		}
		if (cs_zoomed[name]==0) {
			cs_zoomed[name]=1;
			element.style.height = '220px';
		} else if (cs_zoomed[name]==1) {
			cs_zoomed[name]=2;
			element.style.height = '420px';
		} else if (cs_zoomed[name]==2) {
			cs_zoomed[name]=3;
			element.style.height = '820px';
		} else {
			cs_zoomed[name]=0;
			element.style.height = '120px';
		}
		cs_refresh()
	}
	function cs_resized() {
		clearTimeout(cs_resizeto);
		cs_resizeto = setTimeout(cs_refresh,250);
	}
	function cs_change_type(id,no) {
		var o;
		o = document.getElementById("cs_cell_"+id+"_"+cs_chartid[id]);
		o.className="REL";
		cs_chartid[id]=no;
		o = document.getElementById("cs_cell_"+id+"_"+cs_chartid[id]);
		o.className="PR";
		o = document.getElementById("cs_desc"+id);
		o.innerHTML = cs_idesc[no];
		cs_refresh();
	}
	function cs_add_event(obj,type,fn) {
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
		} else if (obj.attachEvent) {
			obj.attachEvent('on'+type, fn);
		}
	}
	cs_add_event(window,"load",cs_refresh);
	cs_add_event(window,"resize",cs_resized);
//--><!]]>
</script>""")
				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
				out.append("""	<tr>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(0);">short range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(1);">medium range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(2);">long range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(3);">very long range</a></th>""")
				out.append("""	</tr>""")
				for id,name,desc in charts:
					divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATIC"
					divclick = 'onclick="cs_zoom(this)"' if csnc else ""
					out.append("""	<tr class="C2">""")
					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
					out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
					out.append("""				<span class="CAPTION">%s</span>""" % desc)
					out.append("""			</div>""")
					out.append("""		</td>""")
					out.append("""	</tr>""")
				out.append("""</table>""")
				out.append("""<br/>""")

				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
				out.append("""	<tr>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(0);">short range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(1);">medium range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(2);">long range</a></th>""")
				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(3);">very long range</a></th>""")
				out.append("""	</tr>""")
				for i in range(2):
					divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATIC"
					divclick = 'onclick="cs_zoom(this)"' if csnc else ""
					out.append("""	<tr class="C2">""")
					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
					out.append("""			<div class="%s" id="cs_chart%u" %s>""" % (divclass,i,divclick))
					out.append("""				<span class="CAPTION" id="cs_desc%u">%s</span>""" % (i,charts[0][2]))
					out.append("""			</div>""")
					out.append("""		</td>""")
					out.append("""	</tr>""")
					out.append("""	<tr>""")
					out.append("""		<td colspan="4">""")
					out.append("""			<table class="BOTMENU" cellspacing="0">""")
					out.append("""				<tr>""")
					no=0
					cl="PR"
					for id,name,desc in charts:
						out.append("""					<td align="center" id="cs_cell_%u_%u" class="%s"><a href="javascript:cs_change_type(%u,%u);" title="%s">%s</a></td>""" % (i,no,cl,i,no,desc,name))
						cl="REL"
						no+=1
					out.append("""				</tr>""")
					out.append("""			</table>""")
					out.append("""		</td>""")
					out.append("""	</tr>""")
				out.append("""</table>""")
			elif len(cchtmp)==1 and len(CCdata)>0:
				chid = 0
				for id,name,desc in charts:
					if name==CCdata:
						chid = id
				if chid==0:
					try:
						chid = int(CCdata)
					except Exception:
						pass
				if chid>0 and chid<1000:
					out.append("""<script type="text/javascript">""")
					out.append("""<!--//--><![CDATA[//><!--""")
					out.append("""	var i,j;""")
					out.append("""	var cs_range=0;""")
					out.append("""	var cs_vhosts = [%s];""" % ",".join(map(repr,[ x[0] for x in servers ])))
					out.append("""	var cs_vports = [%s];""" % ",".join(map(repr,[ x[1] for x in servers ])))
					out.append("""	var cs_inames = [%s];""" % ",".join(map(repr,[ x[2] for x in servers ])))
					out.append("""	var cs_nc = [%s];""" % ",".join(map(repr,[ x[4] for x in servers ])))
					out.append("""	var cs_chid = %u;""" % chid)
					out.append("""//--><!]]>""")
					out.append("""</script>""")
					out.append("""<script type="text/javascript">
<!--//--><![CDATA[//><!--
	var i,j;
	var cs_range=0;
	var cs_zoomed = [];
	var cs_resizeto;
	function cs_refresh() {
		var i;
		var minutes = Math.floor((new Date()).getTime()/60000);
		for (i=0 ; i<cs_inames.length ; i++) {
			var name = cs_inames[i];
			var vhost = cs_vhosts[i];
			var vport = cs_vports[i];
			var csnc = cs_nc[i];
			var id = cs_chid*10+cs_range;
			var element = document.getElementById(name);
			if (element) {
				var url;
				if (csnc) {
					var width = element.scrollWidth;
					var height = element.scrollHeight;
					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
				} else {
					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;antycache="+minutes;
				}
				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
					element.cs_url = url;
					element.style.backgroundImage = "url('"+url+"')";
				}
			}
		}
	}
	function cs_change(num) {
		cs_range = num;
		cs_refresh();
	}
	function cs_zoom(element) {
		var name = element.id;
		if (typeof(cs_zoomed[name])=="undefined") {
			cs_zoomed[name]=0;
		}
		if (cs_zoomed[name]==0) {
			cs_zoomed[name]=1;
			element.style.height = '220px';
		} else if (cs_zoomed[name]==1) {
			cs_zoomed[name]=2;
			element.style.height = '420px';
		} else if (cs_zoomed[name]==2) {
			cs_zoomed[name]=3;
			element.style.height = '820px';
		} else {
			cs_zoomed[name]=0;
			element.style.height = '120px';
		}
		cs_refresh();
	}
	function cs_resized() {
		clearTimeout(cs_resizeto);
		cs_resizeto = setTimeout(cs_refresh,250);
	}
	function cs_add_event(obj,type,fn) {
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
		} else if (obj.attachEvent) {
			obj.attachEvent('on'+type, fn);
		}
	}
	cs_add_event(window,"load",cs_refresh);
	cs_add_event(window,"resize",cs_resized);
//--><!]]>
</script>""")
					out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
					out.append("""	<tr>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(0);">short range</a></th>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(1);">medium range</a></th>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(2);">long range</a></th>""")
					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(3);">very long range</a></th>""")
					out.append("""	</tr>""")
					for cshost,csport,name,desc,csnc in servers:
						divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATICMIXED" if mixedservers==3 else "CHARTSTATIC"
						divclick = 'onclick="cs_zoom(this)"' if csnc else ""
						out.append("""	<tr class="C2">""")
						out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
						out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
						out.append("""				<span class="CAPTION">%s</span>""" % desc)
						out.append("""			</div>""")
						out.append("""		</td>""")
						out.append("""	</tr>""")
					out.append("""</table>""")
		else:
			out.append("""chunk server charts are unavailable in CLI mode""")
		print("\n".join(out))
	except Exception:
		print_exception()

if cgimode:
	print("""</div> <!-- end of container -->""")

	print("""</body>""")
	print("""</html>""")
