Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/README.md
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/README.md	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/README.md	(working copy)
@@ -0,0 +1,34 @@
+## AMP Reports
+
+### This set of files is used to generate AMP reports through Composer.
+
+#### ToDo
+
+1. Make it fully customizable and directly usable from 'cm' project
+2. Apply PEP 8 Style Guide for Python
+
+
+### Composer reporting directories information
+
+#### Composer ui & reporting directories location on device:
+- /usr/local/share/composer/
+
+#### Composer database (sqlite3) file location on device
+- /var/opt/composer/ui/conf/
+
+
+#### The "composer.db" has the following database tables
+
+1. alert
+2. alert_info
+3. data_source
+4. host
+5. login_log
+6. monitor
+7. notification_channel
+8. report
+9. report_log
+10. setting
+11. sqlite_sequence
+12. user
+
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/composer.db
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/composer.db
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/composer.db	(revision 2475)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/composer.db	(working copy)

Property changes on: src/webui/webui/htdocs/new/src/cm/report/composer.db
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/charts/logo/default.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = image/png
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/charts/logo/default.png
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/charts/logo/default.png	(revision 2475)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/charts/logo/default.png	(working copy)

Property changes on: src/webui/webui/htdocs/new/src/cm/report/reporting/charts/logo/default.png
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+image/png
\ No newline at end of property
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/__init__.py	(added)
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/__init__.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/__init__.py	(revision 0)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/custom_charts.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/custom_charts.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/custom_charts.py	(working copy)
@@ -0,0 +1,555 @@
+#coding=utf-8
+from pyecharts.chart import Chart
+
+
+class Scatter(Chart):
+    """
+    <<< 散点图 >>>
+    直角坐标系上的散点图可以用来展现数据的 x，y 之间的关系，如果数据项有多个维度，
+    可以用颜色来表现，利用 geo 组件。
+    """
+
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Scatter, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+        return self
+
+    def __add(self,
+              name,
+              x_axis,
+              y_axis,
+              extra_data=None,
+              extra_name=None,
+              symbol_size=10,
+              **kwargs):
+        """
+        :param name:
+            系列名称，用于 tooltip 的显示，legend 的图例筛选。
+        :param x_axis:
+            x 坐标轴数据。
+        :param y_axis:
+            y 坐标轴数据。
+        :param extra_data:
+            第三维度数据，x 轴为第一个维度，y 轴为第二个维度。（可在 visualmap 中
+            将视图元素映射到第三维度）。
+        :param extra_name:
+            额外的数据项的名称，可以为每个数据点指定一个名称。
+        :param symbol_size:
+            标记图形大小，默认为 10。
+        :param kwargs:
+        """
+        assert len(x_axis) == len(y_axis)
+        kwargs.update(type="scatter", x_axis=x_axis)
+        chart = self._get_all_options(**kwargs)
+
+        xaxis, yaxis = chart["xy_axis"]
+        # show split line, because by default split line is hidden for xaxis
+        xaxis[0]["splitLine"]["show"] = True
+        self._option.update(xAxis=xaxis, yAxis=yaxis)
+        self._option.get("legend")[0].get("data").append(name)
+
+        zip_lst = [x_axis, y_axis]
+        for e in (extra_data, extra_name):
+            if e:
+                # 确保提供的额外的数据或名称长度相同
+                assert len(e) == len(x_axis)
+                zip_lst.append(e)
+        _data = [list(z) for z in zip(*zip_lst)]
+
+        self._option.get("series").append({
+            "type":
+            "scatter",
+            "name":
+            name,
+            "symbol":
+            chart["symbol"],
+            "symbolSize":
+            symbol_size,
+            "data":
+            _data,
+            "label":
+            chart["label"],
+            "markPoint":
+            chart["mark_point"],
+            "markLine":
+            chart["mark_line"],
+            "seriesId":
+            self._option.get("series_id"),
+            "itemStyle": {
+                'color': '#ffffff',
+                'borderColor': '#C66F69',
+                'borderWidth': 1.3,
+                'opacity': 1
+            }
+        })
+        self._config_components(**kwargs)
+
+
+class Pie(Chart):
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Pie, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+
+    def __add(self,
+              name,
+              attr,
+              value,
+              radius=None,
+              center=None,
+              rosetype=None,
+              **kwargs):
+        kwargs.update(type="pie")
+        chart = self._get_all_options(**kwargs)
+        assert len(attr) == len(value)
+        _data = []
+        for data in zip(attr, value):
+            _name, _value = data
+            _data.append({"name": _name, "value": _value})
+
+        _rmin, _rmax = "0%", "75%"
+        if radius:
+            if len(radius) == 2:
+                _rmin, _rmax = ["{}%".format(r) for r in radius]
+
+        _cmin, _cmax = "50%", "50%"
+        if center:
+            if len(center) == 2:
+                _cmin, _cmax = ["{}%".format(c) for c in center]
+
+        if rosetype:
+            if rosetype not in ("radius", "area"):
+                rosetype = "radius"
+
+        for a in attr:
+            self._option.get("legend")[0].get("data").append({
+                "name": a,
+                "icon": "circle"
+            })
+
+        # _dlst = self._option.get("legend")[0].get("data")
+        # _dset = list(set(_dlst))
+        # _dset.sort(key=_dlst.index)
+        # self._option.get("legend")[0].update(data=list(_dset))
+        # self._option.get("legend")[0].get("data").append({"icon": "circle"})
+
+        self._option.get("series").append({
+            "type":
+            "pie",
+            "name":
+            name,
+            "data":
+            _data,
+            "radius": [_rmin, _rmax],
+            "center": [_cmin, _cmax],
+            "roseType":
+            rosetype,
+            "label":
+            chart["label"],
+            "seriesId":
+            self._option.get("series_id"),
+        })
+        self._config_components(**kwargs)
+
+
+class Line(Chart):
+    """
+    <<< 折线/面积图 >>>
+
+    折线图是用折线将各个数据点标志连接起来的图表，用于展现数据的变化趋势。
+    """
+
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Line, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+
+    def __add(self,
+              name,
+              x_axis,
+              y_axis,
+              is_symbol_show=True,
+              symbol_size=4,
+              is_smooth=False,
+              is_stack=False,
+              is_step=False,
+              is_fill=False,
+              **kwargs):
+        """
+
+        :param name:
+            系列名称，用于 tooltip 的显示，legend 的图例筛选。
+        :param x_axis:
+            x 坐标轴数据。
+        :param y_axis:
+            y 坐标轴数据。
+        :param is_symbol_show:
+            是否显示标记图形，默认为 True。
+        :param is_smooth:
+            是否平滑曲线显示，默认为 False。
+        :param is_stack:
+            数据堆叠，同个类目轴上系列配置相同的 stack 值可以堆叠放置。默认为 False。
+        :param is_step:
+            是否是阶梯线图。可以设置为 True 显示成阶梯线图。默认为 False。
+            也支持设置成'start', 'middle', 'end'分别配置在当前点，当前点与下个
+            点的中间下个点拐弯。
+        :param is_fill:
+            是否填充曲线所绘制面积，默认为 False。
+        :param kwargs:
+        """
+        assert len(x_axis) == len(y_axis)
+        kwargs.update(x_axis=x_axis, type="line", flag=True)
+        chart = self._get_all_options(**kwargs)
+
+        xaxis, yaxis = chart["xy_axis"]
+        if is_stack:
+            is_stack = "stack_" + str(self._option["series_id"])
+        else:
+            is_stack = ""
+        self._option.update(xAxis=xaxis, yAxis=yaxis)
+        self._option.get("legend")[0].get("data").append(name)
+        self._option.get("yAxis")[0]["splitLine"] = {
+            "lineStyle": {
+                "color": ["#eee"],
+                "width": 0.2
+            }
+        }
+
+        _data = [list(z) for z in zip(x_axis, y_axis)]
+
+        self._option.get("series").append({
+            "type":
+            "line",
+            "name":
+            name,
+            "symbol":
+            chart["symbol"],
+            "symbolSize":
+            symbol_size,
+            "smooth":
+            is_smooth,
+            "step":
+            is_step,
+            "stack":
+            is_stack,
+            "showSymbol":
+            is_symbol_show,
+            "data":
+            _data,
+            "label":
+            chart["label"],
+            "lineStyle":
+            chart["line_style"],
+            "areaStyle":
+            chart["area_style"],
+            "markPoint":
+            chart["mark_point"],
+            "markLine":
+            chart["mark_line"],
+            "seriesId":
+            self._option.get("series_id"),
+        })
+        self._config_components(**kwargs)
+
+
+class Line_shadow(Chart):
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Line_shadow, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+
+    def __add(self,
+              name,
+              x_axis,
+              y_axis,
+              is_symbol_show=True,
+              symbol_size=4,
+              is_smooth=False,
+              is_stack=False,
+              is_step=False,
+              is_fill=False,
+              shadowColor="#000",
+              shadowBlur=10,
+              shadowOffsetY=2,
+              mypieces=None,
+              **kwargs):
+        assert len(x_axis) == len(y_axis)
+        kwargs.update(x_axis=x_axis, type="line", flag=True)
+        chart = self._get_all_options(**kwargs)
+
+        xaxis, yaxis = chart["xy_axis"]
+        if is_stack:
+            is_stack = "stack_" + str(self._option["series_id"])
+        else:
+            is_stack = ""
+        self._option.update(xAxis=xaxis, yAxis=yaxis)
+        self._option.get("legend")[0].get("data").append(name)
+        self._option.get("yAxis")[0]["splitLine"] = {
+            "lineStyle": {
+                "color": ["#eee"],
+                "width": 0.2
+            }
+        }
+
+        chart["line_style"]["normal"]["shadowColor"] = shadowColor
+        chart["line_style"]["normal"]["shadowBlur"] = shadowBlur
+        chart["line_style"]["normal"]["shadowOffsetY"] = shadowOffsetY
+        if mypieces is not None:
+            self._option.update(visualMap=mypieces)
+
+        _data = [list(z) for z in zip(x_axis, y_axis)]
+
+        self._option.get("series").append({
+            "type":
+            "line",
+            "name":
+            name,
+            "symbol":
+            chart["symbol"],
+            "symbolSize":
+            symbol_size,
+            "smooth":
+            is_smooth,
+            "step":
+            is_step,
+            "stack":
+            is_stack,
+            "showSymbol":
+            is_symbol_show,
+            "data":
+            _data,
+            "label":
+            chart["label"],
+            "areaStyle":
+            chart["area_style"],
+            "markPoint":
+            chart["mark_point"],
+            "markLine":
+            chart["mark_line"],
+            "seriesId":
+            self._option.get("series_id"),
+            # "lineStyle":{
+            #     "normal":{
+            #         "width":1,
+            #         "shadowColor": shadowColor,
+            #         "shadowBlur":shadowBlur,
+            #         "shadowOffsetY":shadowOffsetY
+            #     }
+            # },
+            "lineStyle":
+            chart["line_style"],
+        })
+        self._config_components(**kwargs)
+
+
+class Bar(Chart):
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Bar, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+
+    def __add(self,
+              name,
+              x_axis,
+              y_axis,
+              is_stack=False,
+              bar_gap=0.5,
+              bar_category_gap="20%",
+              **kwargs):
+        assert len(x_axis) == len(y_axis)
+        kwargs.update(x_axis=x_axis)
+        chart = self._get_all_options(**kwargs)
+
+        if is_stack:
+            is_stack = "stack_" + str(self._option["series_id"])
+        else:
+            is_stack = ""
+        xaxis, yaxis = chart["xy_axis"]
+        self._option.update(xAxis=xaxis, yAxis=yaxis)
+        self._option.get("legend")[0].get("data").append(name)
+        self._option.get("yAxis")[0]["splitLine"] = {
+            "lineStyle": {
+                "color": ["#eee"],
+                "width": 0.2
+            }
+        }
+
+        self._option.get("series").append({
+            "type":
+            "bar",
+            "name":
+            name,
+            "data":
+            y_axis,
+            "barWidth":
+            "40%",
+            "stack":
+            is_stack,
+            "barGap":
+            bar_gap,
+            "barCategoryGap":
+            bar_category_gap,
+            "label":
+            chart["label"],
+            "markPoint":
+            chart["mark_point"],
+            "markLine":
+            chart["mark_line"],
+            "color": [
+                "#37A2DA", "#edafda", "#93b7e3", "#a5e7f0", "#cbb0e3",
+                "#516b91", "#59c4e6"
+            ],
+            "seriesId":
+            self._option.get("series_id"),
+        })
+        self._config_components(**kwargs)
+
+
+class Tree_customize(Chart):
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Tree_customize, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+
+    def __add(self,
+              name,
+              x_axis,
+              y_axis,
+              is_symbol_show=True,
+              symbol_size=4,
+              is_smooth=False,
+              is_stack=False,
+              is_step=False,
+              is_fill=False,
+              tree_data={},
+              fontSize=12,
+              **kwargs):
+        assert len(x_axis) == len(y_axis)
+        kwargs.update(x_axis=x_axis, type="tree", flag=True)
+        chart = self._get_all_options(**kwargs)
+
+        xaxis, yaxis = chart["xy_axis"]
+        if is_stack:
+            is_stack = "stack_" + str(self._option["series_id"])
+        else:
+            is_stack = ""
+        self._option.update(xAxis=xaxis, yAxis=yaxis)
+        self._option.get("legend")[0].get("data").append(name)
+
+        self._option.get("series").append({
+            "type": 'tree',
+            "data": [tree_data],
+            "symbolSize": 7,
+            "top": "10%",
+            "bottom": "10%",
+            "left": "50%",
+            # "right": "20%",
+            "label": {
+                "normal": {
+                    "position": [-30, 5],
+                    "verticalAlign": 'middle',
+                    "align": 'center',
+                    "fontSize": fontSize
+                }
+            },
+            "leaves": {
+                "label": {
+                    "normal": {
+                        "position": 'right',
+                        "verticalAlign": 'middle',
+                        "align": 'left'
+                    }
+                }
+            },
+            "expandAndCollapse": True,
+            "animationDuration": 550,
+            "animationDurationUpdate": 750
+        })
+        self._config_components(**kwargs)
+
+
+class Area_diff(Chart):
+    def __init__(self, title="", subtitle="", **kwargs):
+        super(Area_diff, self).__init__(title, subtitle, **kwargs)
+
+    def add(self, *args, **kwargs):
+        self.__add(*args, **kwargs)
+
+    def __add(self,
+              name,
+              x_axis,
+              y_axis,
+              is_symbol_show=True,
+              symbol_size=4,
+              is_smooth=False,
+              is_stack=False,
+              is_step=False,
+              is_fill=False,
+              pieces=[],
+              **kwargs):
+        assert len(x_axis) == len(y_axis)
+        kwargs.update(x_axis=x_axis, type="line", flag=True)
+        chart = self._get_all_options(**kwargs)
+
+        xaxis, yaxis = chart["xy_axis"]
+        if is_stack:
+            is_stack = "stack_" + str(self._option["series_id"])
+        else:
+            is_stack = ""
+        self._option.update(xAxis=xaxis, yAxis=yaxis)
+        self._option.get("legend")[0].get("data").append(name)
+        self._option.get("yAxis")[0]["splitLine"] = {
+            "lineStyle": {
+                "color": ["#eee"],
+                "width": 0.2
+            }
+        }
+
+        self._option.get("series").append({
+            "type":
+            "line",
+            "name":
+            name,
+            "symbol":
+            chart["symbol"],
+            "symbolSize":
+            symbol_size,
+            "smooth":
+            is_smooth,
+            "step":
+            is_step,
+            "stack":
+            is_stack,
+            "showSymbol":
+            is_symbol_show,
+            "data":
+            y_axis,
+            "label":
+            chart["label"],
+            "lineStyle":
+            chart["line_style"],
+            "areaStyle":
+            chart["area_style"],
+            "markPoint":
+            chart["mark_point"],
+            "markLine":
+            chart["mark_line"],
+            "seriesId":
+            self._option.get("series_id"),
+        })
+
+        visual_map = {
+            "show": False,
+            "dimension": 0,
+            "pieces": pieces,
+        }
+
+        self._option.update(visualMap=visual_map)
+        self._config_components(**kwargs)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/gen_chart.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/gen_chart.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/gen_chart.py	(working copy)
@@ -0,0 +1,281 @@
+import pyecharts as pes
+import os
+import json
+from session import tsdbQuery
+from wand.image import Image
+from pyecharts.engine import create_default_environment
+from .custom_charts import Bar, Pie, Line
+from pyecharts import configure
+from module.parse_time import parseWeekDay
+
+
+def get_chart_size(chartspath):
+    with Image(filename=chartspath) as img:
+        return img.size
+
+
+class ChartsComponent(object):
+    def __init__(self, chartspath=""):
+        self.chartspath = chartspath
+        self.env = create_default_environment("png")
+        configure(global_theme='light')
+
+    def grid(self, charts, chartspath, grid_width, grid_height):
+        # return
+        grid = pes.Grid()
+        grid.add(charts, grid_width=grid_width, grid_height=grid_height)
+        # grid.render(path=chartspath)
+        self.env.render_chart_to_file(grid, path=chartspath)
+        with Image(filename=chartspath) as img:
+            img.trim()
+            img.save(filename=chartspath)
+
+    def LineGraphWidget(self, config, name, title="", width=660, height=180):
+        chartPath = os.path.join(self.chartspath, name + ".png")
+        res = tsdbQuery(json.dumps(config['args']['datasource']))
+
+        line = Line("",
+                    title_color='#727581',
+                    title_pos='center',
+                    title_text_size=12,
+                    width=width,
+                    height=height)
+
+        refids = ['A']
+        if 'refids' in config['args']['option']['chart'].keys():
+            refids = config['args']['option']['chart']['refids']
+
+        k_lst = []
+        i = 0
+        for id in refids:
+            for index, series in enumerate(config['args']['option']['series']):
+                v_lst = []
+                if res[id]['series']:
+                    ss = res[id]['series'][i]['points']
+                    for s in ss:
+                        if i == 0:
+                            k_lst.append(s[0])
+                        v_lst.append(s[1])
+
+                if len(k_lst) == 0:
+                    line = pes.Line("No Data",
+                                    width=width,
+                                    height=height,
+                                    title_pos='center',
+                                    title_top='30%',
+                                    title_text_size=26,
+                                    title_color='#727581')
+                line.add(series['name'], k_lst, v_lst, **series['config'])
+                i += 1
+
+        # self.env.render_chart_to_file(line, path=chartPath)
+        self.grid(line, chartPath, width, height)
+        return res
+
+    def PieGraphWidget(self, config, name, title="", width=400, height=250):
+        chartPath = os.path.join(self.chartspath, name + ".png")
+        res = tsdbQuery(json.dumps(config['args']['datasource']))
+
+        pie = Pie("", width=width, height=height)
+
+        k_lst, v_lst = [], []
+
+        if 'error' not in res['A'].keys():
+
+            if res['A']['tables'] is None:
+                if 'legends' in config['args']['option']['chart'].keys():
+                    k_lst = config['args']['option']['chart']['legends']
+                    series = res['A']['series']
+                    for ss in series:
+                        v_lst.append(ss['points'][0][1])
+            else:
+                rows = res['A']['tables'][0]['rows']
+
+                if 'legends' in config['args']['option']['chart'].keys():
+                    k_lst = config['args']['option']['chart']['legends']
+                    for i in range(len(rows[0])):
+                        if not rows[0][i]:
+                            rows[0][i] = 0
+                    v_lst = rows[0]
+
+                elif 'legends2' in config['args']['option']['chart'].keys():
+                    k_lst = config['args']['option']['chart']['legends2']
+                    for legend in k_lst:
+                        flag = False
+                        for row in rows:
+                            if row[0] == legend:
+                                flag = True
+                                v_lst.append(row[1])
+
+                        if not flag:
+                            v_lst.append(0)
+
+                else:
+                    rows1 = []
+                    rows2 = []
+                    if 'top' in config['args']['option']['chart'].keys():
+                        top = config['args']['option']['chart']['top']
+
+                        if top > 0:
+                            rows = sorted(rows,
+                                          key=lambda student: student[1],
+                                          reverse=True)
+                        else:
+                            rows = sorted(rows, key=lambda student: student[1])
+
+                        if abs(top) >= len(rows):
+                            rows1 = rows
+                        else:
+                            if top > 0:
+                                rows1 = rows[0:top]
+                                rows2 = rows[top:]
+                            else:
+                                rows1 = rows[top:]
+                                rows2 = rows[0:len(rows) + top]
+                    else:
+                        rows1 = rows
+
+                    for row in rows1:
+                        k_lst.append(row[0])
+                        if row[1] is None:
+                            v_lst.append(0)
+                        else:
+                            v_lst.append(row[1])
+
+                    if len(rows2) > 0:
+                        sum = 0
+                        for row in rows2:
+                            sum += row[1]
+                        k_lst.append('other')
+                        v_lst.append(sum)
+
+            series = config['args']['option']['series'][0]
+            pie.add(series['name'], k_lst, v_lst, **series['config'])
+
+        self.grid(pie, chartPath, width, height)
+        return (k_lst, v_lst)
+
+    def MapGraphWidget(self, config, name, title="", width=500, height=250):
+        chartPath = os.path.join(self.chartspath, name + ".png")
+        res = tsdbQuery(json.dumps(config['args']['datasource']))
+
+        map = pes.Map("", width=width, height=height)
+
+        if 'error' not in res['A'].keys():
+            rows = res['A']['tables'][0]['rows']
+            k_lst, v_lst = [], []
+
+            series = config['args']['option']['series'][0]
+            for s in rows:
+                k_lst.append(s[0])
+                v_lst.append(s[1])
+
+            if len(v_lst) == 0:
+                series["config"]["visual_range"] = [0, 200]
+            else:
+                series["config"]["visual_range"] = [min(v_lst), max(v_lst)]
+            map.add(series['name'], k_lst, v_lst, **series['config'])
+
+        self.grid(map, chartPath, width, height)
+        return res
+
+    def BarGraphWidget(self, config, name, title="", width=560, height=180):
+        chartPath = os.path.join(self.chartspath, name + ".png")
+        res = tsdbQuery(json.dumps(config['args']['datasource']))
+
+        bar = Bar(title,
+                  title_color='#727581',
+                  title_pos='30%',
+                  title_text_size=12,
+                  width=width,
+                  height=height)
+
+        if 'error' not in res['A'].keys():
+            rows = res['A']['tables'][0]['rows']
+            k_lst, v_lst = [], []
+
+            if 'legends' in config['args']['option']['chart'].keys():
+                k_lst = config['args']['option']['chart']['legends']
+                v_lst = rows[0]
+                for index, series in enumerate(
+                        config['args']['option']['series']):
+                    bar.add(series['name'], k_lst, v_lst, **series['config'])
+                    v_lst = []
+
+            elif 'legends2' in config['args']['option']['chart'].keys():
+                k_lst = config['args']['option']['chart']['legends2']
+                for legend in k_lst:
+                    flag = False
+                    for row in rows:
+                        if row[0] == legend:
+                            flag = True
+                            v_lst.append(row[1])
+
+                    if not flag:
+                        v_lst.append(0)
+
+                for index, series in enumerate(
+                        config['args']['option']['series']):
+                    bar.add(series['name'], k_lst, v_lst, **series['config'])
+                    v_lst = []
+
+            else:
+                for index, series in enumerate(
+                        config['args']['option']['series']):
+                    for row in rows:
+                        if index == 0:
+                            k_lst.append(row[0])
+                        v_lst.append(row[index + 1])
+
+                    if len(k_lst) == 0:
+                        bar = Bar("No Data",
+                                  width=width,
+                                  height=height,
+                                  title_pos='35%',
+                                  title_top='30%',
+                                  title_text_size=24,
+                                  title_color='#727581')
+
+                    bar.add(series['name'], k_lst, v_lst, **series['config'])
+                    v_lst = []
+
+        self.grid(bar, chartPath, width, height)
+        return res
+
+    def WeekBarGraphWidget(self, config, name, title="", width=560,
+                           height=180):
+        chartPath = os.path.join(self.chartspath, name + ".png")
+        res = tsdbQuery(json.dumps(config['args']['datasource']))
+
+        bar = Bar(title,
+                  title_color='#727581',
+                  title_pos='center',
+                  title_text_size=12,
+                  width=width,
+                  height=height)
+
+        if 'error' not in res['A'].keys():
+            rows = res['A']['tables'][0]['rows']
+            k_lst, v_lst = [], []
+
+            for index, series in enumerate(config['args']['option']['series']):
+                rows.sort(key=lambda x: x[0])
+                for row in rows:
+                    if index == 0:
+                        k_lst.append(parseWeekDay(row[0]))
+                    v_lst.append(row[index + 1])
+
+                if len(k_lst) == 0:
+                    bar = Bar("No Data",
+                              width=width,
+                              height=height,
+                              title_pos='35%',
+                              title_top='30%',
+                              title_text_size=24,
+                              title_color='#727581')
+
+                bar.add(series['name'], k_lst, v_lst, **series['config'])
+                v_lst = []
+
+        self.grid(bar, chartPath, width, height)
+        return res
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/gen_pdf.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/gen_pdf.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/gen_pdf.py	(working copy)
@@ -0,0 +1,976 @@
+# -*- coding: UTF-8 -*-
+import pylatex as plx
+from pylatex.utils import bold, NoEscape
+from datetime import datetime as dt
+import subprocess
+import os
+from session import getChartsPath, getCompanyName
+# import sys
+# reload(sys)
+# sys.setdefaultencoding('utf-8')
+
+
+class GeneratePDF(object):
+    def __init__(self, options):
+        geometry_options = [
+            NoEscape("papersize={%s, %s}" %
+                     (options["paperwidth"], options["paperheight"]))
+        ]
+        for key in options:
+            if key != "paperwidth" and key != "paperheight":
+                if key != options[key]:
+                    geometry_options.append("%s=%s" % (key, options[key]))
+                else:
+                    geometry_options.append("%s" % key)
+
+        self.doc = plx.Document(documentclass='ctexart',
+                                geometry_options=geometry_options,
+                                fontenc=None)
+        self.options = options
+
+    def create_doc(self, *args, **kargs):
+        for i in range(len(args)):
+            self.doc.preamble.append(NoEscape(r"\usepackage{%s}" % args[i]))
+        for key in kargs:
+            self.doc.preamble.append(NoEscape(r"\%s{%s}" % (key, kargs[key])))
+
+    def header_footer(self,
+                      note=None,
+                      product_name=None,
+                      report_class=None,
+                      report_cls=None,
+                      benchmark=None,
+                      report_type=None):
+
+        header_page = plx.PageStyle("header")
+        # Header image
+        with header_page.create(plx.Head("L")) as header_left:
+            with header_left.create(
+                    plx.MiniPage(width=NoEscape(r"0.49\textwidth"),
+                                 pos='c')) as logo_wrapper:
+                logo_file = os.path.join(getChartsPath(), 'logo/logo.png')
+                logo_wrapper.append(plx.HorizontalSpace("8mm"))
+                logo_wrapper.append(
+                    plx.StandAloneGraphic(image_options="height=30",
+                                          filename=logo_file))
+
+        # Add document title
+        with header_page.create(plx.Head("R")) as right_header:
+            with right_header.create(
+                    plx.MiniPage(width=NoEscape(r"0.49\textwidth"),
+                                 pos='c',
+                                 align='r')) as title_wrapper:
+                title_wrapper.append(
+                    plx.MediumText(
+                        NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" %
+                                 (product_name))))
+                title_wrapper.append(plx.HorizontalSpace("8mm"))
+                title_wrapper.append(plx.LineBreak())
+                if report_type != "":
+                    title_wrapper.append(
+                        plx.MediumText(
+                            NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" %
+                                     (report_type))))
+                    title_wrapper.append(plx.HorizontalSpace("8mm"))
+                    title_wrapper.append(plx.LineBreak())
+                title_wrapper.append(
+                    NoEscape(
+                        r"\textcolor[RGB]{114,117,129}{Generated Date: %s\hspace{1.5mm}}"
+                        % dt.now().strftime("%Y/%m/%d")))
+                title_wrapper.append(plx.HorizontalSpace("8mm"))
+
+        # with header_page.create(plx.Head("C")) as header:
+        #     with header.create(plx.Tabular("p{2.2cm} X[r]")) as header_table:
+        #         logo_wrapper = plx.MiniPage(width=NoEscape(r'0.17\textwidth'),
+        #                                     align='l')
+
+        #         logo_path = os.path.join(getChartsPath(), 'logo/logo.png')
+        #         if not os.path.exists(logo_path):
+        #             logo_path = os.path.join(getChartsPath(), 'logo/default.png')
+
+        #         logo = plx.StandAloneGraphic(image_options="height=25", filename=logo_path)
+        #         logo_wrapper.append(plx.HorizontalSpace("3mm"))
+        #         logo_wrapper.append(logo)
+
+        #         title_wrapper = plx.MiniPage(width=NoEscape(r'0.8\textwidth'), align='r')
+        #         title = plx.MediumText(
+        #             bold(
+        #                 NoEscape(r"\textcolor[RGB]{74,74,74}{%s\newblock\newblock \
+        #                                                 %s}" % (product_name, report_type))))
+        #         title_wrapper.append(title)
+        #         title_wrapper.append(plx.HorizontalSpace('1mm'))
+
+        #         note_wrapper = plx.MiniPage(width=NoEscape(r'0.8\textwidth'),
+        #                                     pos='htbp!',
+        #                                     align='r')
+        #         note = NoEscape(
+        #             r"\textcolor[RGB]{155,163,175}{Generated Date: %s\hspace{1.5mm}}"
+        #             % dt.now().strftime("%Y/%m/%d"))
+        #         note_wrapper.append(note)
+
+        #         header_table.add_row([
+        #             plx.MultiRow(2, data=logo_wrapper),
+        #             plx.MultiRow(1, data=title_wrapper)
+        #         ])
+        #         header_table.add_row(["", plx.MultiRow(1, data=note_wrapper)])
+
+        with header_page.create(plx.Foot("C")) as footer:
+            with footer.create(plx.Tabular("p{2.2cm} X[r]")) as footer_table:
+                branch_address = plx.MiniPage(width=NoEscape(r"0.8\textwidth"),
+                                              pos='t')
+                branch_address.append(
+                    NoEscape(r'\textcolor[RGB]{74,74,74}{ %s }' %
+                             (getCompanyName())))
+
+                document_details = plx.MiniPage(
+                    width=NoEscape(r"0.8\textwidth"), pos='t', align='r')
+                document_details.append(
+                    NoEscape(r'\textcolor[RGB]{74,74,74}{ \thepage\ }'))
+
+                footer_table.add_row([branch_address, document_details])
+
+        self.doc.preamble.append(header_page)
+        self.doc.change_document_style("header")
+
+    def navigation(self, nav, star_num):
+        with self.doc.create(plx.Tabu("p{1mm} x[l] p{1mm}")) as three:
+            content = plx.Tabu("X", row_height=3.0)
+            row = [plx.HugeText(plx.TextColor("white", "SLP: "))]
+            tabu = "X[c]"
+            for i in range(len(nav)):
+                star = ""
+                minipage = plx.MiniPage(width=NoEscape(r'0.3\textwidth'),
+                                        pos='c')
+                name = plx.MediumText(
+                    plx.TextColor("white", NoEscape(r"%s\newline" % nav[i])))
+                for j in range(star_num[i]):
+                    star = star + r"\faCheck\hspace{2mm}"
+                name.append(
+                    plx.SmallText(
+                        NoEscape(r"\textcolor{white}{%s\newline}" % star)))
+                minipage.append(name)
+                tabu = tabu + " X[l]"
+                row.append(minipage)
+
+            grade = plx.Tabu(tabu)
+            grade.add_row(row)
+            content.add_row([grade], color="gray!120")
+            three.add_row(["", content, ""])
+
+        self.doc.append(plx.LineBreak())
+        self.doc.append(plx.LineBreak())
+        self.doc.append(plx.LineBreak())
+
+    def landscape_navigation(self, nav):
+        with self.doc.create(plx.Tabu("p{1mm} p{19.5cm} p{1mm}")) as three:
+            content = plx.Tabu("X", row_height=2.0)
+            row = NoEscape(r"\textcolor[RGB]{74,74,74}{%s\newline}" % nav)
+            content.append(
+                NoEscape(r"\arrayrulecolor{gray!40}\bottomrule[2pt]"))
+            content.add_row([row], color="gray!10")  # 这句是关键
+            content.append(NoEscape(r"\arrayrulecolor{gray!40}\toprule[2pt]"))
+            three.add_row(["", content, ""])
+        self.doc.append(plx.LineBreak())
+
+    def landscape_navigations(self, navs):
+        with self.doc.create(plx.Tabu("p{1mm} p{19.5cm} p{1mm}")) as three:
+            content = plx.Tabu("X", row_height=2.0)
+            row = NoEscape()
+            for nav in navs:
+                row += NoEscape(r"\textcolor[RGB]{74,74,74}{%s\newline}" % nav)
+            content.append(
+                NoEscape(r"\arrayrulecolor{gray!40}\bottomrule[2pt]"))
+            content.add_row([row], color="gray!10")  # 这句是关键
+            content.append(NoEscape(r"\arrayrulecolor{gray!40}\toprule[2pt]"))
+            three.add_row(["", content, ""])
+        self.doc.append(plx.LineBreak())
+
+    def topic(self, topic_name, topic_star_num, space_mm):
+        with self.doc.create(plx.Center()) as centered:
+            with centered.create(plx.Tabu("p{1mm} X[l] p{1mm}",
+                                          row_height=1.5)) as team:
+                title = plx.LargeText(
+                    NoEscape(r"\textcolor[RGB]{114,117,129}{%s}" % topic_name))
+                if topic_star_num > 0:
+                    star = ""
+                    for i in range(topic_star_num):
+                        star = star + r"\faStar\hspace{2mm}"
+                    title.append(
+                        plx.SmallText(
+                            NoEscape(r"\textcolor[RGB]{114,117,130}{%s}" %
+                                     star)))
+                team.add_row(["", title, ""])
+
+            with centered.create(
+                    plx.Tabu("p{1mm} X[c] p{1mm}", row_height=0.12)) as three:
+                content = plx.Tabu("X", row_height=0.12)
+                content.add_row([""], color="gray!120")
+                three.add_row(["", content, ""])
+
+            # with centered.create(plx.MiniPage(width="555")) as report:
+            #     with report.create(plx.Tabu("X[c]", row_height=0.1)) as line:
+            #         line.append(
+            #             NoEscape(
+            #                 r"\arrayrulecolor{gray!120}\tabucline[2pt]{-}"))
+            #         line.append(plx.VerticalSpace("%smm" % space_mm))
+            #         line.add_empty_row()
+            #         line.append(plx.LineBreak())
+
+        self.doc.append(NoEscape(r"\newline"))
+
+    def topic2(self, topic_name, is_line=True):
+
+        with self.doc.create(plx.Center()) as centered:
+            with centered.create(plx.Tabu("p{1mm} X[l] p{1mm}",
+                                          row_height=0.5)) as team:
+                title = NoEscape(r"\textcolor[RGB]{155,163,175}{%s}" %
+                                 topic_name)
+                team.add_row(["", title, ""])
+            if is_line:
+                with centered.create(
+                        plx.Tabu("p{1mm} X[c] p{1mm}",
+                                 row_height=0.12)) as three:
+                    content = plx.Tabu("X", row_height=0.12)
+                    content.add_row([""], color="gray!50")
+                    three.add_row(["", content, ""])
+
+        #     with centered.create(plx.MiniPage(width="555")) as report:
+        #         with report.create(plx.Tabu("X[c]", row_height=0.1)) as line:
+        #             line.append(
+        #                 NoEscape(
+        #                     r"\arrayrulecolor{gray!40}\tabucline[2pt]{-}"))
+        #             line.append(plx.VerticalSpace("1mm"))
+
+    def landscape_topic(self, topic_name, space_mm):
+        with self.doc.create(plx.Tabu("p{1mm} X[l] p{1mm}",
+                                      row_height=1.5)) as tp:
+            title = plx.LargeText(
+                bold(NoEscape(r"\textcolor[RGB]{114,117,129}{%s}" %
+                              topic_name)))
+            tp.add_row(["", title, ""])
+            tp.append(plx.VerticalSpace("%smm" % space_mm))
+
+        self.doc.append(NoEscape(r"\newline"))
+
+    def annotation(self, annotation_name, space_mm):
+        tp = plx.Tabu("X[l]", row_height=0.8)
+        for i, an in enumerate(annotation_name):
+            if i == 0:
+                title = plx.SmallText(
+                    NoEscape(r"\textcolor[RGB]{114,117,129}{%s}" % an))
+            else:
+                title = plx.SmallText(
+                    NoEscape(
+                        r"\textcolor[RGB]{114,117,129}{\newblock\newblock\newblock \
+                                                \newblock\newblock\newblock\newblock\newblock\newblock \
+                                                \newblock\newblock\newblock %s}"
+                        % an))
+            tp.add_row([title])
+        return tp
+
+    def table_report_boxplot(self,
+                             table_report_name,
+                             spec,
+                             tb,
+                             row,
+                             change_color=False,
+                             newline=False,
+                             newempty=True):
+        table_spec = "p{1mm} "
+        topic = [""]
+        content = [""]
+        if change_color:
+            color = "74,74,74"
+        else:
+            color = "155,163,175"
+        for i in range(len(table_report_name)):
+            table_spec += "p{%smm} " % spec[i]
+            topic.append(
+                NoEscape(r"\textcolor[RGB]{%s}{%s}" %
+                         (color, table_report_name[i])))
+            content.append(plx.MultiRow(row[i], data=tb[i]))
+        table_spec += "p{1mm}"
+        topic.append("")
+        content.append("")
+        with self.doc.create(plx.Tabu(table_spec, row_height=0.8)) as table:
+            if topic[1] != "":
+                table.add_row(topic)
+            if newline:
+                table.add_empty_row()
+            table.add_row(content)
+            if newempty:
+                table.add_empty_row()
+        self.doc.append(plx.LineBreak())
+
+    def table_report(self,
+                     table_report_name,
+                     spec,
+                     tb,
+                     change_color=False,
+                     newline=False,
+                     newempty=True):
+        table_spec = "p{1mm} "
+        topic = [""]
+        content = [""]
+        if change_color:
+            color = "74,74,74"
+        else:
+            color = "155,163,175"
+        for i in range(len(table_report_name)):
+            table_spec += "p{%smm} " % spec[i]
+            topic.append(
+                NoEscape(r"\textcolor[RGB]{%s}{%s}" %
+                         (color, table_report_name[i])))
+            content.append(tb[i])
+        table_spec += "p{1mm}"
+        topic.append("")
+        content.append("")
+        with self.doc.create(plx.Tabu(table_spec, row_height=0.8)) as table:
+            if topic[1] != "":
+                table.add_row(topic)
+            if newline:
+                table.add_empty_row()
+            table.add_row(content)
+            if newempty:
+                table.add_empty_row()
+        self.doc.append(plx.LineBreak())
+
+    def team_desc(self, tm_desc):
+        table_spec = "p{3mm} X[l] X[r] p{15mm} X[l] X[r] p{3mm}"
+        # with self.doc.create(plx.MiniPage(width="550")) as table_line:
+        # with self.doc.create(plx.Center()) as centered:
+        with self.doc.create(plx.Tabu(table_spec, row_height=1.0)) as table:
+            for i in range(len(tm_desc)):
+                a = NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" % tm_desc[i][0])
+                b = NoEscape(r"\textcolor[RGB]{155,163,175}{%s}" %
+                             tm_desc[i][1])
+                c = NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" % tm_desc[i][2])
+                d = NoEscape(r"\textcolor[RGB]{155,163,175}{%s}" %
+                             tm_desc[i][3])
+                table.add_row(["", a, b, "", c, d, ""])
+                if i < len(tm_desc) - 1:
+                    table.append(
+                        NoEscape(
+                            r"\arrayrulecolor{gray!25}\cmidrule[1pt]{2-3}\cmidrule[1pt]{5-6}"
+                        ))
+            table.append(
+                NoEscape(r"\arrayrulecolor{gray!60}\cmidrule[2pt]{2-6}"))
+
+    def one_row_desc(self, tm_desc):
+        table_spec = "p{3mm} p{5cm} X[l] p{3mm}"
+        # with self.doc.create(plx.MiniPage(width="550")) as table_line:
+        with self.doc.create(plx.Center()) as centered:
+
+            with centered.create(plx.Tabu(table_spec,
+                                          row_height=1.0)) as table:
+                table.append(
+                    NoEscape(r"\arrayrulecolor{gray!60}\cmidrule[2pt]{2-3}"))
+
+                for i in range(len(tm_desc)):
+                    a = NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" %
+                                 tm_desc[i][0])
+                    b = NoEscape(r"\textcolor[RGB]{155,163,175}{%s}" %
+                                 tm_desc[i][1])
+                    table.add_row(["", a, b, ""])
+                    if i < len(tm_desc) - 1:
+                        table.append(
+                            NoEscape(
+                                r"\arrayrulecolor{gray!25}\cmidrule[1pt]{2-3}")
+                        )
+
+                table.append(
+                    NoEscape(r"\arrayrulecolor{gray!60}\cmidrule[2pt]{2-3}"))
+
+        #     with centered.create(plx.MiniPage(width="555")) as table_line:
+        #         with table_line.create(plx.Tabu("X", row_height=0.1)) as tl:
+        #             tl.append(
+        #                 NoEscape(
+        #                     r"\arrayrulecolor{gray!60}\tabucline[2pt]{-}"))
+        #             tl.add_empty_row()
+        self.doc.append(NoEscape(r"\newline"))
+
+    def table_one_two_row(self, chart_content, report_content, table_content,
+                          spec):
+        with self.doc.create(plx.MiniPage(width="555",
+                                          fontsize="small")) as table_line:
+            with table_line.create(
+                    plx.Tabu("p{1mm} p{%scm} p{%scm} p{1mm}" %
+                             (spec[0], spec[1]),
+                             row_height=0.5)) as table:
+                # table.add_row(["", "", plx.MultiRow(1, data=NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" % report_content[0])), ""])
+                # table.add_empty_row()
+                # table.add_row(["", "", plx.MultiRow(1, data=NoEscape(r"\textcolor[RGB]{74,74,74}{%s}" % report_content[1])), ""])
+                # table.add_empty_row()
+                table.add_row([
+                    "",
+                    plx.MultiRow(4, data=chart_content),
+                    plx.MultiRow(1, data=table_content), ""
+                ])
+                table.add_empty_row()
+        self.doc.append(plx.VerticalSpace("4.5cm"))
+        self.doc.append(plx.LineBreak())
+
+    def table_more_two_row(self, chart_content, report_content, spec):
+        table_line = plx.MiniPage(width="555", fontsize="footnotesize")
+        # with self.doc.create(plx.MiniPage(width="555", fontsize="small")) as table_line:
+        with table_line.create(
+                plx.Tabu("p{1mm} p{%scm} p{%scm} p{1mm}" % (spec[0], spec[1]),
+                         row_height=1.2)) as table:
+            table.append(NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+            for i in range(len(report_content)):
+                for j in range(len(report_content[i])):
+                    if i == 0 and j == 0:
+                        table.add_row(
+                            ["",
+                             plx.MultiRow(10, data=chart_content), "", ""])
+                        table.add_row([
+                            "", "",
+                            plx.MultiRow(1,
+                                         data=NoEscape(
+                                             r"\textcolor[RGB]{74,74,74}{%s}" %
+                                             report_content[i][j])), ""
+                        ])
+                        table.add_empty_row()
+                        table.add_empty_row()
+                        table.add_empty_row()
+                        table.add_empty_row()
+                        table.add_empty_row()
+                    elif i == 1 and j == 2:
+                        table.add_row([
+                            "", "",
+                            plx.MultiRow(1,
+                                         data=NoEscape(
+                                             r"\textcolor[RGB]{74,74,74}{%s}" %
+                                             report_content[i][j])), ""
+                        ])
+                        table.add_empty_row()
+                        table.add_empty_row()
+                        table.add_empty_row()
+                    elif i == 2 and j == 2:
+                        table.add_row([
+                            "", "",
+                            plx.MultiRow(1,
+                                         data=NoEscape(
+                                             r"\textcolor[RGB]{74,74,74}{%s}" %
+                                             report_content[i][j])), ""
+                        ])
+                    else:
+                        table.add_row([
+                            "", "",
+                            plx.MultiRow(1,
+                                         data=NoEscape(
+                                             r"\textcolor[RGB]{74,74,74}{%s}" %
+                                             report_content[i][j])), ""
+                        ])
+                        table.add_empty_row()
+        return table_line
+        # self.doc.append(plx.LineBreak())
+        # self.doc.append(plx.VerticalSpace("1cm"))
+
+    def table_one_column(self,
+                         width,
+                         table_content,
+                         table_style="common",
+                         fontsize="normalsize",
+                         fontsize2="normalsize",
+                         isline=True,
+                         is_bold=False,
+                         table_spec=None,
+                         row_height=1.0):
+        table = plx.MiniPage(width=width, fontsize=fontsize)
+        with table.create(plx.Tabu("X", row_height=1.3)) as tb:
+            if isline:
+                if is_bold:
+                    tb.append(
+                        NoEscape(
+                            r"\arrayrulecolor{gray!120}\bottomrule[15pt]"))
+                else:
+                    tb.append(
+                        NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+            if table_style == "common":
+                for i in range(len(table_content)):
+                    if table_spec is None:
+                        content = plx.Tabu(len(table_content[i]) * "X[l] ",
+                                           row_height=row_height)
+                    else:
+                        t_spec = ""
+                        for t in range(len(table_spec)):
+                            t_spec += "p{%scm} " % table_spec[t]
+                        content = plx.Tabu(t_spec, row_height=1.0)
+                    each_row = []
+                    for j in range(len(table_content[i])):
+                        if i == 0:
+                            text = plx.MiniPage(
+                                fontsize=fontsize,
+                                data=NoEscape(
+                                    r"\textcolor[RGB]{74,74,74}{%s}" %
+                                    table_content[i][j]))
+                        else:
+                            text = plx.MiniPage(
+                                fontsize=fontsize2,
+                                data=NoEscape(
+                                    r"\textcolor[RGB]{155,163,175}{%s}" %
+                                    table_content[i][j]))
+                        each_row.append(text)
+                    content.add_row(each_row)
+                    if i % 2 == 0:
+                        color = "white"
+                    else:
+                        color = "gray!15"
+                    tb.add_row([content], color=color)
+                    if i < len(table_content) - 1:
+                        tb.add_hline(color="gray!30")
+            elif table_style == "skill":
+                for i in range(len(table_content)):
+                    if table_spec is None:
+                        content = plx.Tabu(len(table_content[i]) * "X[l] ",
+                                           row_height=row_height)
+                    else:
+                        t_spec = ""
+                        for t in range(len(table_spec)):
+                            t_spec += "p{%smm} " % table_spec[t]
+                        content = plx.Tabu(t_spec, row_height=1.0)
+                    each_row = []
+                    for j in range(len(table_content[i])):
+                        if i == 0 or j == 0:
+                            text = plx.MiniPage(
+                                fontsize=fontsize,
+                                data=NoEscape(
+                                    r"\textcolor[RGB]{74,74,74}{%s}" %
+                                    table_content[i][j]))
+                        else:
+                            text = plx.MiniPage(
+                                fontsize=fontsize,
+                                data=NoEscape(
+                                    r"\textcolor[RGB]{155,163,175}{%s}" %
+                                    table_content[i][j]))
+                        each_row.append(text)
+                    content.add_row(each_row)
+                    if i == 0 or i % 2 == 1:
+                        color = "white"
+                    else:
+                        color = "gray!15"
+                    tb.add_row([content], color=color)
+                    if i < len(table_content) - 1:
+                        tb.add_hline(color="gray!30")
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\toprule[2pt]"))
+        return table
+
+    def long_table(self,
+                   table_content,
+                   fontsize="normalsize",
+                   fontsize2="normalsize",
+                   fontcolor="74,74,74",
+                   fontcolor2="155,163,175",
+                   isline=True,
+                   is_bold=False,
+                   table_spec=None,
+                   row_height=1.0):
+        with self.doc.create(plx.Center()) as centered:
+            with centered.create(plx.LongTabu("X", to="7.65in")) as tb:
+                if isline:
+                    if is_bold:
+                        tb.append(
+                            NoEscape(
+                                r"\arrayrulecolor{gray!120}\bottomrule[15pt]"))
+                    else:
+                        tb.append(
+                            NoEscape(
+                                r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+                for i in range(len(table_content)):
+                    if table_spec is None:
+                        content = plx.Tabu(len(table_content[i]) * "X[l] ",
+                                           row_height=row_height)
+                    else:
+                        t_spec = ""
+                        for t in range(len(table_spec)):
+                            t_spec += "p{%scm} " % table_spec[t]
+                        content = plx.Tabu(t_spec, row_height=row_height)
+                    each_row = []
+                    for j in range(len(table_content[i])):
+                        if i == 0:
+                            if table_spec is not None:
+                                text = plx.MiniPage(
+                                    width=str(table_spec[j]) + 'cm',
+                                    fontsize=fontsize,
+                                    data=NoEscape(
+                                        r"\textcolor[RGB]{%s}{%s}" %
+                                        (fontcolor, table_content[i][j])))
+                            else:
+                                text = plx.MiniPage(
+                                    fontsize=fontsize,
+                                    data=NoEscape(
+                                        r"\textcolor[RGB]{%s}{%s}" %
+                                        (fontcolor, table_content[i][j])))
+                        else:
+                            cell = r""
+                            if isinstance(table_content[i][j], list):
+                                k = 0
+                                for row in table_content[i][j]:
+                                    if k == 0:
+                                        cell += r"\textcolor[RGB]{%s}{%s}" % (
+                                            fontcolor2, row)
+                                    else:
+                                        cell += r"\\\textcolor[RGB]{%s}{%s}" % (
+                                            fontcolor2, row)
+                                    k += 1
+                            else:
+                                cell = r"\textcolor[RGB]{%s}{%s}" % (
+                                    fontcolor2, table_content[i][j])
+
+                            if table_spec is not None:
+                                text = plx.MiniPage(width=str(table_spec[j]) +
+                                                    'cm',
+                                                    fontsize=fontsize2,
+                                                    data=NoEscape(cell))
+                            else:
+                                text = plx.MiniPage(fontsize=fontsize2,
+                                                    data=NoEscape(cell))
+                        each_row.append(text)
+                    content.add_row(each_row)
+                    if i % 2 == 0:
+                        color = "white"
+                    else:
+                        color = "gray!15"
+                    if i == 0:
+                        tb.add_row([content], color=color)
+                        tb.add_hline(color="gray!30")
+                        # tb.add_empty_row()
+                        tb.end_table_header()
+                    else:
+                        tb.add_row([content], color=color)
+                    if i < len(table_content) - 1:
+                        tb.add_hline(color="gray!30")
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\toprule[2pt]"))
+
+    def table_long_column(self, width, table_content):
+        table = plx.MiniPage(width=width)
+        with table.create(plx.Tabu("X", row_height=1.3)) as tb:
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+            for i in range(len(table_content)):
+                table_spec = "p{50mm} p{60mm} " + (len(table_content[i]) -
+                                                   2) * "X[l] "
+                content = plx.Tabu(table_spec, row_height=1.0)
+                each_row = []
+                for j in range(len(table_content[i])):
+                    if i == 0:
+                        color = "74,74,74"
+                    else:
+                        color = "155,163,175"
+                    if j == 0 or j == 1:
+                        text = plx.MiniPage(
+                            width=NoEscape(r"1.0\textwidth"),
+                            data=NoEscape(r"\textcolor[RGB]{%s}{%s}" %
+                                          (color, table_content[i][j])))
+                    else:
+                        text = plx.MiniPage(
+                            width=NoEscape(r"0.2\textwidth"),
+                            data=NoEscape(r"\textcolor[RGB]{%s}{%s}" %
+                                          (color, table_content[i][j])))
+                    each_row.append(text)
+                content.add_row(each_row)
+                if i % 2 == 0:
+                    color = "white"
+                else:
+                    color = "gray!15"
+                tb.add_row([content], color=color)
+                if i < len(table_content) - 1:
+                    tb.add_hline(color="gray!30")
+        return table
+
+    def charts_one_column(self,
+                          chartpath,
+                          width,
+                          chartwidth,
+                          chartheight,
+                          isline=True,
+                          mini_w=None,
+                          isempty=False):
+        chart = plx.MiniPage(width=width, align='c')
+
+        with chart.create(plx.Tabu("X[c]", row_height=0.5)) as ct:
+            if isline:
+                ct.append(
+                    NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+                ct.add_empty_row()
+            if mini_w is not None:
+                chart_mini = plx.MiniPage(width=mini_w)
+                chart_mini.append(
+                    plx.StandAloneGraphic(chartpath,
+                                          image_options="width=%s, height=%s" %
+                                          (chartwidth, chartheight)))
+                ct.add_row([chart_mini])
+            else:
+                ct.add_row([
+                    plx.StandAloneGraphic(chartpath,
+                                          image_options="width=%s, height=%s" %
+                                          (chartwidth, chartheight))
+                ])
+            if isempty:
+                ct.add_empty_row()
+            # for i in range(empty):
+            #     ct.add_empty_row()
+            # ct.add_empty_row()
+        return chart
+
+    def charts_boxplot(self, chartpath, width, chartwidth, chartheight):
+        chart = plx.MiniPage(width=width, align='c')
+        boxplot = plx.StandAloneGraphic(chartpath,
+                                        image_options="width=%s, height=%s" %
+                                        (chartwidth, chartheight))
+        chart.append(boxplot)
+        return chart
+
+    def table_multi_column(self, width, table_content, table_spec):
+        table = plx.MiniPage(width=width, pos='c', content_pos='c', align='c')
+        tabu = ""
+        content = []
+        for i in range(len(table_content)):
+            if i == len(table_content) - 1:
+                center = "c"
+            else:
+                center = "c|"
+            tabu += center
+
+            if i % 2 == 0:
+                content.append(
+                    plx.MultiColumn(
+                        1,
+                        align=center,
+                        color="gray!15",
+                        data=plx.MiniPage(
+                            width=table_spec[0],
+                            align="c",
+                            data=NoEscape(r"\textcolor[RGB]{128,128,128}{%s}" %
+                                          table_content[i]))))
+            else:
+                content.append(
+                    plx.MultiColumn(
+                        1,
+                        align=center,
+                        color="white",
+                        data=plx.MiniPage(
+                            width=table_spec[1],
+                            align="c",
+                            data=NoEscape(r"\textcolor[RGB]{128,128,128}{%s}" %
+                                          table_content[i]))))
+
+        with table.create(plx.Tabu(tabu, row_height=1.2)) as tb:
+            tb.append(NoEscape(r"\arrayrulecolor{gray!70}\bottomrule[2pt]"))
+            tb.add_row(content)
+            tb.append(NoEscape(r"\arrayrulecolor{gray!70}\toprule[2pt]"))
+        return table
+
+    def table_multi_column_second(self, width, table_content, table_spec):
+        table = plx.MiniPage(width=width)
+        tabu = ""
+        for i in range(len(table_content[1])):
+            tabu += "X[l] "
+        with table.create(plx.Tabu(tabu, row_height=1.2)) as tb:
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+            for i in range(len(table_content)):
+                content = []
+                for j in range(len(table_content[i])):
+                    if j == 0 or j == len(table_content[i]) - 1:
+                        left = "l"
+                    else:
+                        left = "|l|"
+
+                    if i == 0:
+                        if j == 0:
+                            content.append(
+                                plx.MultiColumn(1,
+                                                align=left,
+                                                data=table_content[i][j]))
+                        else:
+                            content.append(
+                                plx.MultiColumn(
+                                    2,
+                                    align=left,
+                                    data=plx.MiniPage(
+                                        width=106,
+                                        align="l",
+                                        data=NoEscape(
+                                            r"\textcolor[RGB]{70,74,91}{%s}" %
+                                            table_content[i][j]))))
+                    else:
+                        if j % 2 == 1:
+                            color = "gray!15"
+                        else:
+                            color = "white"
+                        if i == 1 or j == 0:
+                            textcolor = "70,74,91"
+                        else:
+                            textcolor = "155,163,175"
+                        if j == 0:
+                            content.append(
+                                plx.MultiColumn(
+                                    1,
+                                    align=left,
+                                    color=color,
+                                    data=plx.MiniPage(
+                                        width=53,
+                                        align="l",
+                                        data=NoEscape(
+                                            r"\textcolor[RGB]{%s}{%s}" %
+                                            (textcolor,
+                                             table_content[i][j])))))
+                        else:
+                            content.append(
+                                plx.MultiColumn(
+                                    1,
+                                    align=left,
+                                    color=color,
+                                    data=plx.MiniPage(
+                                        width=48.5,
+                                        align="l",
+                                        data=NoEscape(
+                                            r"\textcolor[RGB]{%s}{%s}" %
+                                            (textcolor,
+                                             table_content[i][j])))))
+                tb.add_row(content)
+                if i != len(table_content) - 1:
+                    tb.append(
+                        NoEscape(
+                            r"\arrayrulecolor{gray!50}\tabucline[1pt]{-}"))
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\toprule[2pt]"))
+        return table
+
+    def table_multi_column_secondEX(self,
+                                    width,
+                                    table_content,
+                                    table_spec,
+                                    fontsize="normalsize",
+                                    fontsize2="normalsize"):
+        table = plx.MiniPage(width=width, fontsize=fontsize)
+        tabu = ""
+        for i in range(len(table_content[1])):
+            tabu += "X[l] "
+
+        with table.create(plx.Tabu(tabu, row_height=1.0)) as tb:
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+            for i in range(len(table_content)):
+                content = []
+                for j in range(len(table_content[i])):
+                    if j == 0 or j == len(table_content[i]) - 1:
+                        left = "l"
+                    else:
+                        left = "|l|"
+
+                    if i == 0:
+                        if j == 0:
+                            content.append(
+                                plx.MultiColumn(1,
+                                                align=left,
+                                                data=table_content[i][j]))
+                        else:
+                            content.append(
+                                plx.MultiColumn(
+                                    2,
+                                    align=left,
+                                    data=plx.MiniPage(
+                                        width=178,
+                                        align="l",
+                                        fontsize=fontsize,
+                                        data=NoEscape(
+                                            r"\textcolor[RGB]{70,74,91}{%s}" %
+                                            table_content[i][j]))))
+                    else:
+                        if j % 2 == 1:
+                            color = "gray!15"
+                        else:
+                            color = "white"
+                        if i == 1 or j == 0:
+                            textcolor = "70,74,91"
+                        else:
+                            textcolor = "155,163,175"
+                        if j == 0:
+                            content.append(
+                                plx.MultiColumn(
+                                    1,
+                                    align=left,
+                                    color=color,
+                                    data=plx.MiniPage(
+                                        width=146,
+                                        align="l",
+                                        fontsize=fontsize,
+                                        data=NoEscape(
+                                            r"\textcolor[RGB]{%s}{%s}" %
+                                            (textcolor,
+                                             table_content[i][j])))))
+                        else:
+                            content.append(
+                                plx.MultiColumn(
+                                    1,
+                                    align=left,
+                                    color=color,
+                                    data=plx.MiniPage(
+                                        width=87,
+                                        align="l",
+                                        fontsize=fontsize2,
+                                        data=NoEscape(
+                                            r"\textcolor[RGB]{%s}{%s}" %
+                                            (textcolor,
+                                             table_content[i][j])))))
+                tb.add_row(content)
+                if i != len(table_content) - 1:
+                    tb.append(
+                        NoEscape(
+                            r"\arrayrulecolor{gray!50}\tabucline[1pt]{-}"))
+            tb.append(NoEscape(r"\arrayrulecolor{gray!50}\toprule[2pt]"))
+        return table
+
+    def description(self, width, desc_content):
+        table = plx.MiniPage(width=width, align="l")
+        with table.create(plx.Tabu("X[l]", row_height=0.01)) as desc:
+            desc.append(NoEscape(r"\arrayrulecolor{gray!50}\bottomrule[2pt]"))
+            # desc.add_empty_row()
+            # desc.add_row([""])
+            # desc.add_row(["asdfasdfsdaasdfadsf"])
+            # desc.add_row(["asdfasdfsdaasdfadsf"])
+        for i in range(len(desc_content)):
+            table.append(plx.LineBreak())
+            table.append(plx.SmallText(NoEscape(r"%s" % desc_content[i])))
+        return table
+
+    def newpage(self):
+        self.doc.append(plx.NewPage())
+
+    def newline(self):
+        self.doc.append(plx.LineBreak())
+
+    def new_line(self):
+        self.doc.append(NoEscape(r"\newline"))
+
+    def newspace(self):
+        self.doc.append(plx.VerticalSpace("2mm"))
+
+    def split_line(self):
+        with self.doc.create(plx.Center()) as centered:
+            with centered.create(plx.Tabu("p{1mm} X[c] p{1mm}",
+                                          row_height=0.1)) as three:
+                content = plx.Tabu("X", row_height=1.0)
+                content.add_row([""], color="gray!120")
+                three.add_row(["", content, ""])
+
+    def generate_pdf(self, filepath, filename):
+        if not os.path.exists(filepath):
+            os.makedirs(filepath)
+
+        self.doc.generate_tex(os.path.join(filepath, filename))
+        subprocess.call([
+            "/usr/share/TinTex/bin/x86_64-linux/xelatex",
+            "-interaction=nonstopmode", "-output-directory=" + filepath,
+            os.path.join(filepath, filename) + ".tex"
+        ])
+        # subprocess.call([
+        #     "/usr/share/TinTex/bin/x86_64-linux/xelatex",
+        #     "-interaction=nonstopmode", "-output-directory=" + filepath,
+        #     os.path.join(filepath, filename) + ".tex"
+        # ])
+
+
+# GPDF = GeneratePDF()
+# GPDF.change_setting()
+# GPDF.create_doc("pdf_tex/test/", "test", "fontawesome", "booktabs", "xcolor", setCJKmainfont=".PingFang SC Regular")
+# GPDF.generate_pdf("pdf_tex/test/", "test",)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/parse_time.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/parse_time.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/parse_time.py	(working copy)
@@ -0,0 +1,56 @@
+import time
+from datetime import datetime
+
+
+def parseDuration(duration):
+    duringStamp = int(duration[:-1])
+    if duration[-1] == "s":
+        duringStamp = duringStamp
+    elif duration[-1] == "m":
+        duringStamp = duringStamp * 60
+    elif duration[-1] == "h":
+        duringStamp = duringStamp * 60 * 60
+    elif duration[-1] == "d":
+        duringStamp = duringStamp * 60 * 60 * 24
+    elif duration[-1] == "w":
+        duringStamp = duringStamp * 60 * 60 * 24 * 7
+    elif duration[-1] == "M":
+        duringStamp = duringStamp * 60 * 60 * 24 * 30
+    elif duration[-1] == "y":
+        duringStamp = duringStamp * 60 * 60 * 24 * 365
+    return duringStamp
+
+
+def parseTimeCondition(condition, format_str="%Y/%m/%d %H:%M:%S"):
+
+    if "now" in condition:
+        if condition == "now":
+            return time.strftime(format_str, time.localtime())
+        else:
+            duration = condition.replace(' ', '').replace('now-', '')
+            return time.strftime(
+                format_str,
+                time.localtime(time.time() - parseDuration(duration)))
+    else:
+        date = datetime.fromtimestamp(int(condition) / 1000)
+        return date.strftime(format_str)
+
+
+def calTimeDiff(from_str, to_str):
+    ft = time.strptime(from_str, "%Y/%m/%d %H:%M:%S")
+    tt = time.strptime(to_str, "%Y/%m/%d %H:%M:%S")
+
+    return int(time.mktime(tt) - time.mktime(ft))
+
+
+def parseWeekDay(num):
+    num2week = {
+        '0': "Sunday",
+        '1': "Monday",
+        '2': "Tuesday",
+        '3': "Wednesday",
+        '4': "Thursday",
+        '5': "Friday",
+        '6': "Saturday",
+    }
+    return num2week[num]
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/session.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/session.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/module/session.py	(working copy)
@@ -0,0 +1,298 @@
+# import requests
+import socket
+import json
+import commands
+import ConfigParser
+import httplib
+import time
+import hashlib
+import os
+
+COMPOSER_KEY = ''
+COMPOSER_SECRET = ''
+COMPOSER_RESTAPI_PORT = 3000
+
+REPORT_PATH = ''
+CHARTS_PATH = ''
+
+DEVICE_NAME = 'Composer'
+
+headers = {'Content-Type': 'application/json; charset=utf-8'}
+
+
+def setHomePath(homePath):
+
+    global REPORT_PATH
+    global CHARTS_PATH
+
+    global COMPOSER_KEY
+    global COMPOSER_SECRET
+    global DEVICE_NAME
+    global Company_NAME
+
+    config = ConfigParser.ConfigParser()
+    config.readfp(open(homePath + '/ui/conf/app.ini'))
+    COMPOSER_KEY = config.get("default", "api.key")
+    COMPOSER_SECRET = config.get("default", "api.secret")
+    DEVICE_NAME = config.get("default", "app.name")
+    Company_NAME = config.get("default", "company.name")
+
+    REPORT_PATH = homePath + '/reporting/data'
+    CHARTS_PATH = homePath + '/reporting/charts'
+
+    if not os.path.exists(REPORT_PATH):
+        os.makedirs(REPORT_PATH)
+    if not os.path.exists(CHARTS_PATH):
+        os.makedirs(CHARTS_PATH)
+
+
+def getReportPath():
+    return REPORT_PATH
+
+
+def getDeviceName():
+    return DEVICE_NAME
+
+
+def getCompanyName():
+    if (Company_NAME == ""):
+        return "ARRAY NETWORKS, INC."
+    else:
+        return Company_NAME
+
+
+def getChartsPath():
+    return CHARTS_PATH
+
+
+def composer_proxy(methdod, url, data):
+
+    timestamp = str(int(time.time()))
+    m = hashlib.md5()
+    m.update(COMPOSER_KEY + str(timestamp) + url + COMPOSER_SECRET)
+
+    if '?' in url:
+        url += "&time=" + timestamp + "&sign=" + m.hexdigest()
+    else:
+        url += "?time=" + timestamp + "&sign=" + m.hexdigest()
+
+    httpClient = None
+
+    try:
+        httpClient = httplib.HTTPConnection('localhost',
+                                            str(COMPOSER_RESTAPI_PORT),
+                                            True,
+                                            timeout=30)
+        httpClient.request(methdod, url, data, headers)
+        response = httpClient.getresponse()
+        resp = response.read()
+    except Exception, e:
+        raise e
+    finally:
+        if httpClient:
+            httpClient.close()
+
+    return json.loads(resp)
+
+
+def fetchReporting(id):
+    return composer_proxy('GET', '/v1/report/' + id, '')
+
+
+def tsdbQuery(data):
+    res = composer_proxy('POST', '/v1/tsdb/query', data)
+
+    if res['code'] != 0:
+        return {}
+    else:
+        return res['data']['results']
+
+
+def escapeshellarg(cmd_str):
+    ret = '"'
+    esacpe_chars = [
+        '#', '&', ';', '`', '|', '*', '?', '~', '<', '>', '^', '(', ')', '[',
+        ']', '{', '}', '$', '\\', ',', '"'
+    ]
+    for each in cmd_str:
+        if each in esacpe_chars:
+            ret += '\\'
+        ret += each
+    ret += '"'
+    return ret
+
+
+def cmd_direct(cmd):
+    cmd = cmd.strip()
+    f_eop = chr(252)
+    cmd = escapeshellarg(cmd)
+    cmd = '/ca/bin/backend -u ' + 'array' + ' -c ' + cmd
+    cmd = cmd.encode('utf-8') + f_eop
+    (status, output) = commands.getstatusoutput(cmd)
+    if status != 0:
+        return ''
+    else:
+        return output.strip(f_eop)
+
+
+def fetchHostName():
+    output = cmd_direct('show version')
+    if output != '':
+        hostname = output.split("\n")[3].split(":")[1]
+    else:
+        hostname = socket.gethostname()
+    return hostname
+
+
+def fetchServiceAddress(service_name):
+    # return " 183.63.1.102 80\n"
+    output = cmd_direct("show security service address \"%s\"" %
+                        (service_name))
+    if output != '':
+        return output.replace("security service address ",
+                              "").replace(service_name,
+                                          "").replace('\n', ", ")
+    else:
+        return ''
+
+
+def fetchAMPDeviceBuildInfo(device_ip):
+    import psycopg2
+    result = {
+        "current_version": "",
+        "new_version": "",
+    }
+
+    try:
+        # result["current_version"] = "Rel.APV.1.3.0.9"
+        # result["new_version"] = "Rel.APV.1.3.0.9"
+        # return result
+        conn = psycopg2.connect(database="cm",
+                                user="postgres",
+                                password="",
+                                host="127.0.0.1",
+                                port="5432")
+
+        cur = conn.cursor()
+        cur.execute("SELECT name FROM device WHERE ip_address = '%s'" %
+                    device_ip)
+        rows = cur.fetchall()
+        device_name = ''
+        for row in rows:
+            device_name = row[0]
+
+        cur.execute(
+            "SELECT current_version, new_version FROM device_build_up_info WHERE device_name = '%s'"
+            % device_name)
+        rows = cur.fetchall()
+        for row in rows:
+            result["current_version"] = row[0]
+            result["new_version"] = row[1]
+        conn.close()
+    except Exception as re:
+        print(re)
+
+    return result
+
+
+def fetchAMPServiceCertInfo(device_ip, service_name):
+    import psycopg2
+    result = {
+        "expiration": 100,
+    }
+    try:
+        conn = psycopg2.connect(database="cm",
+                                user="postgres",
+                                password="",
+                                host="127.0.0.1",
+                                port="5432")
+
+        cur = conn.cursor()
+        cur.execute("SELECT name FROM device WHERE ip_address = '%s'" %
+                    device_ip)
+        rows = cur.fetchall()
+        device_name = ''
+        for row in rows:
+            device_name = row[0]
+
+        cur.execute(
+            "SELECT expiration FROM adc_vs_ssl_info WHERE vs_name = '%s' AND device_name = '%s'"
+            % (service_name, device_name))
+        rows = cur.fetchall()
+        for row in rows:
+            result["expiration"] = row[0]
+        conn.close()
+    except Exception as re:
+        print(re)
+    return result
+
+
+def fetchServicePCIDSS(service_name):
+    output = cmd_direct("show security service pci %s" % service_name)
+    if output != '':
+        return json.loads(output)
+    return {
+        "PCI_DSS": {},
+        "result": "Error: security service %s fetch error." % service_name
+    }
+    return {
+        "PCI_DSS": {
+            "name":
+            "service_waf",
+            "PCI_DSS_1": [],
+            "PCI_DSS_2": [{
+                "item": "2.3",
+                "match": 0
+            }],
+            "PCI_DSS_3": [{
+                "item": "3.3",
+                "match": 2
+            }],
+            "PCI_DSS_4": [{
+                "item": "4.1",
+                "match": 0
+            }],
+            "PCI_DSS_5": [],
+            "PCI_DSS_6": [{
+                "item": "6.1",
+                "match": 1
+            }, {
+                "item": "6.5.1",
+                "match": 1
+            }, {
+                "item": "6.5.2",
+                "match": 1
+            }, {
+                "item": "6.5.4",
+                "match": 0
+            }, {
+                "item": "6.5.5",
+                "match": 2
+            }, {
+                "item": "6.5.7",
+                "match": 1
+            }, {
+                "item": "6.5.8",
+                "match": 1
+            }, {
+                "item": "6.5.9",
+                "match": 1
+            }, {
+                "item": "6.6",
+                "match": 2
+            }],
+            "PCI_DSS_7": [{
+                "item": "7.1",
+                "match": 1
+            }],
+            "PCI_DSS_8": [],
+            "PCI_DSS_9": [],
+            "PCI_DSS_10": [],
+            "PCI_DSS_11": [{
+                "item": "11.4",
+                "match": 1
+            }],
+            "PCI_DSS_12": []
+        },
+        "result": "Success."
+    }
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/report.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/report.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/report.py	(working copy)
@@ -0,0 +1,36 @@
+# -*- coding: UTF-8 -*-
+import sys
+# import os
+# from module.gen_pdf import GeneratePDF
+# from module.gen_chart import ChartsComponent
+from module.session import fetchReporting
+from module.session import setHomePath
+# from template.setting import router
+from template.default import default
+from template.setting import router
+
+if __name__ == "__main__":
+
+    args = sys.argv[1:]
+    if len(args) != 3:
+        raise Exception("Invalid reporting args")
+
+    homePath = args[0]
+    reportingID = args[1]
+    folderID = args[2]
+
+    setHomePath(homePath)
+
+    rep = fetchReporting(reportingID)
+
+    if rep['code'] != 0:
+        raise Exception(rep['message'])
+
+    pdfname = rep['data']['name']
+    args = rep['data']['args']
+    # created = rep['data']['created']
+
+    if 'monitor_id' in args.keys():
+        router[args['monitor_id']](folderID, pdfname, args)
+    else:
+        default(folderID, pdfname, args)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/__init__.py	(added)
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/__init__.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/__init__.py	(revision 0)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/amp_device.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/amp_device.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/amp_device.py	(working copy)
@@ -0,0 +1,551 @@
+# -*- coding: UTF-8 -*-
+import os
+import json
+from module.gen_pdf import GeneratePDF
+from module.gen_chart import ChartsComponent, get_chart_size
+from module.parse_time import parseTimeCondition, calTimeDiff
+from module.session import getReportPath, fetchAMPDeviceBuildInfo
+from utils import format_str, LineConfig
+from default import sampling_data
+
+
+def buildDeviceBasicWidgets(device_type, device_ip, from_str, to_str, rounded):
+    device_type = device_type.lower()
+    widgets = [{
+        "name": "network_throughput",
+        "icon": "line-chart",
+        "verbose_name": 'Network Throughput (Kbps)',
+        "cls": "LineGraphWidget",
+        "args": {
+            "params": {
+                "flush": "10s"
+            },
+            "option": {
+                "chart": {
+                    "grid_top": 30,
+                    "grid_bottom": 40
+                },
+                "series": [{
+                    "name": "Sent",
+                    "config": LineConfig
+                }, {
+                    "name": "Received",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                from_str,
+                "to":
+                to_str,
+                "queries": [{
+                    "datasourceId":
+                    1,
+                    "select": [[{
+                        "type": "field",
+                        "params": ["total_out"]
+                    }, {
+                        "type": "first"
+                    }, {
+                        "type": "derivative",
+                        "params": ["1s"]
+                    }, {
+                        "type": "math",
+                        "params": ["/128"]
+                    }],
+                               [{
+                                   "type": "field",
+                                   "params": ["total_in"]
+                               }, {
+                                   "type": "first"
+                               }, {
+                                   "type": "derivative",
+                                   "params": ["1s"]
+                               }, {
+                                   "type": "math",
+                                   "params": ["/128"]
+                               }]],
+                    "measurement":
+                    "snmp_system",
+                    "tags": [{
+                        "key": "agent_host",
+                        "value": device_ip,
+                        "operator": "="
+                    }],
+                    "groupBy": [{
+                        "type": "time",
+                        "params": [rounded]
+                    }, {
+                        "type": "fill",
+                        "params": ["null"]
+                    }],
+                    "resultFormat":
+                    "time_series"
+                }]
+            }
+        }
+    }, {
+        "name": "cpu_usage",
+        "icon": "line-chart",
+        "verbose_name": 'CPU Usage (%)',
+        "cls": "LineGraphWidget",
+        "args": {
+            "params": {
+                "flush": "10s"
+            },
+            "option": {
+                "chart": {
+                    "grid_top": 30,
+                    "grid_bottom": 40
+                },
+                "series": [{
+                    "name": "cpu_usage",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                from_str,
+                "to":
+                to_str,
+                "queries": [{
+                    "datasourceId":
+                    1,
+                    "select": [[{
+                        "type": "field",
+                        "params": ["cpu_usage"]
+                    }, {
+                        "type": "mean"
+                    }]],
+                    "measurement":
+                    "snmp_system",
+                    "tags": [{
+                        "key": "agent_host",
+                        "value": device_ip,
+                        "operator": "="
+                    }],
+                    "groupBy": [{
+                        "type": "time",
+                        "params": [rounded]
+                    }, {
+                        "type": "fill",
+                        "params": ["null"]
+                    }],
+                    "resultFormat":
+                    "time_series"
+                }]
+            }
+        }
+    }, {
+        "name": "net_memory_usage",
+        "icon": "line-chart",
+        "verbose_name": 'Network Memory Usage (%)',
+        "cls": "LineGraphWidget",
+        "args": {
+            "params": {
+                "flush": "10s"
+            },
+            "option": {
+                "chart": {
+                    "grid_top": 30,
+                    "grid_bottom": 40
+                },
+                "series": [{
+                    "name": "memory_usage",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                from_str,
+                "to":
+                to_str,
+                "queries": [{
+                    "datasourceId":
+                    1,
+                    "select": [[{
+                        "type": "field",
+                        "params": ["net_mem_usage"]
+                    }, {
+                        "type": "mean"
+                    }]],
+                    "measurement":
+                    "snmp_system",
+                    "tags": [{
+                        "key": "agent_host",
+                        "value": device_ip,
+                        "operator": "="
+                    }],
+                    "groupBy": [{
+                        "type": "time",
+                        "params": [rounded]
+                    }, {
+                        "type": "fill",
+                        "params": ["null"]
+                    }],
+                    "resultFormat":
+                    "time_series"
+                }]
+            }
+        }
+    }]
+    if device_type in ["apv", "vapv", "vnsae", "nsae", "vnetopti", "netopti"]:
+        widgets += [{
+            "name": "system_memory_usage",
+            "icon": "line-chart",
+            "verbose_name": 'System Memory Usage (%)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "memory_usage",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["mem_usage"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "snmp_system",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "disk_usage",
+            "icon": "line-chart",
+            "verbose_name": 'Disk Usage (%)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "disk_usage",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["used"]
+                        }, {
+                            "type": "mean"
+                        }, {
+                            "type": "math",
+                            "params": ["*100/mean(size)"]
+                        }]],
+                        "measurement":
+                        "snmp_storage",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }]
+    elif device_type in ["ag", "vxag", "vnetgate", "netgate"]:
+        widgets += [{
+            "name": "active_sessions",
+            "icon": "line-chart",
+            "verbose_name": 'Active Session',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "active_sessions",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["ActiveSessions"]
+                        }, {
+                            "type": "sum"
+                        }]],
+                        "measurement":
+                        "virtualSiteStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }]
+    return widgets
+
+
+def roundInterval(interval):
+    if interval <= 12.5:
+        return "10s"  # 10s
+    # 17.5s
+    if interval <= 17.5:
+        return "15s"  # 15s
+    # 25s
+    if interval <= 25:
+        return "20s"  # 20s
+    # 45s
+    if interval <= 45:
+        return "30s"  # 30s
+    # 1.5m
+    if interval <= 90:
+        return "1m"  # 1m
+    # 3.5m
+    if interval <= 210:
+        return "2m"  # 2m
+    # 7.5m
+    if interval <= 450:
+        return "5m"  # 5m
+    # 12.5m
+    if interval <= 750:
+        return "10m"  # 10m
+    # 12.5m
+    if interval <= 1050:
+        return "15m"  # 15m
+    # 25m
+    if interval <= 1500:
+        return "20m"  # 20m
+    # 45m
+    if interval <= 2700:
+        return "30m"  # 30m
+    # 1.5h
+    if interval <= 5400:
+        return "1h"  # 1h
+    # 2.5h
+    if interval <= 9000:
+        return "2h"  # 2h
+    # 4.5h
+    if interval <= 16200:
+        return "3h"  # 3h
+    # 9h
+    if interval <= 32400:
+        return "6h"  # 6h
+    # 24h
+    if interval <= 86400:
+        return "12h"  # 12h
+    # 48h
+    if interval <= 172800:
+        return "24h"  # 24h
+    # 1w
+    if interval <= 604800:
+        return "24h"  # 24h
+    # 3w
+    if interval <= 1814400:
+        return "1w"  # 1w
+    # 2y
+    if interval < 3628800:
+        return "30d"  # 30d
+    return "1y"  # 1y
+
+
+def amp_device(folderID, pdfname, args):
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    from_str = parseTimeCondition(args['from'])
+    to_str = parseTimeCondition(args['to'])
+    time_diff = calTimeDiff(from_str, to_str)
+
+    interval = time_diff / 30
+    rounded = roundInterval(interval)
+
+    cc = ChartsComponent(chartspath=pdfpath)
+
+    dataMap = {}
+
+    widgets = buildDeviceBasicWidgets(args['subject']['type'],
+                                      args['subject']['ip'], args['from'],
+                                      args['to'], rounded)
+    for j in range(len(widgets)):
+        # print(json.dumps(widget))
+        data = getattr(cc, widgets[j]['cls'])(widgets[j], str(j))
+        dataMap[str(j)] = sampling_data(widgets[j], data)
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": "0.3in",
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans Semibold",
+        setCJKmainfont="Open Sans",
+    )
+    doc.header_footer(product_name="Device Running Status Report",
+                      report_type="")
+    doc.newline()
+    doc.split_line()
+
+    doc.topic("Information", 0, 1)
+
+    versionInfo = fetchAMPDeviceBuildInfo(args['subject']['ip'])
+
+    desc = [
+        [
+            "Device Name",
+            format_str(args['subject']['name']), "Device IP",
+            format_str(args['subject']['ip'])
+        ],
+        [
+            "Device Type",
+            format_str(args['subject']['type']), "Connection",
+            json.dumps(args['subject']['connection'])
+        ], ["From", from_str, "To", to_str],
+        [
+            "Create Time",
+            parseTimeCondition("now"), "Report Type", "Device Running Status"
+        ],
+        [
+            "Current Version",
+            format_str(versionInfo["current_version"]),
+            "Suggest upgrading to version",
+            format_str(
+                versionInfo["current_version"] == versionInfo["new_version"]
+                and " " or versionInfo["new_version"])
+        ]
+    ]
+    doc.team_desc(desc)
+    doc.newline()
+
+    doc.topic("1. Basic Monitoring", 0, 1)
+    doc.newline()
+
+    for j in range(len(widgets)):
+        chartPath = os.path.join(pdfpath, str(j) + ".png")
+        h, w = get_chart_size(chartPath)
+        topic = "%s. %s" % (j + 1, format_str(widgets[j]['verbose_name']))
+
+        table_data = dataMap[str(j)]
+
+        if widgets[j]['cls'] == "PieGraphWidget":
+            doc.topic2(topic)
+            chart_pfal = doc.charts_one_column(chartPath,
+                                               240,
+                                               240,
+                                               int(240 * w / h),
+                                               isline=False)
+
+            table_cta_profit_source = doc.table_one_column(
+                280,
+                table_data,
+                fontsize="small",
+                fontsize2="footnotesize",
+                row_height=0.9)
+
+            report_cta_profit_source = []
+            doc.table_one_two_row(chart_pfal, report_cta_profit_source,
+                                  table_cta_profit_source, [9, 8])
+        else:
+            # doc.topic2(topic)
+            chart_pfal = doc.charts_one_column(chartPath, 550, 500,
+                                               int(500 * w / h))
+            doc.table_report([topic], [98], [chart_pfal])
+
+            print(table_data)
+            # table_data = [['Time', 'cpu\\_usage'], ["1", "2"]]
+            if table_data is not None:
+                doc.long_table(table_data,
+                               fontsize="small",
+                               fontsize2="footnotesize",
+                               isline=False,
+                               row_height=0.8)
+        doc.newline()
+
+    pdfname += "_" + parseTimeCondition(
+        args['from'], format_str="%Y%m%d%H%M%S") + "_" + parseTimeCondition(
+            args['to'], format_str="%Y%m%d%H%M%S")
+
+    doc.generate_pdf(pdfpath, pdfname)
\ No newline at end of file
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/amp_service.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/amp_service.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/amp_service.py	(working copy)
@@ -0,0 +1,1438 @@
+# -*- coding: UTF-8 -*-
+import os
+from module.gen_pdf import GeneratePDF
+from module.gen_chart import ChartsComponent, get_chart_size
+from module.parse_time import parseTimeCondition, calTimeDiff
+from module.session import getReportPath, fetchAMPServiceCertInfo
+from utils import format_str, LineConfig, PieConfig
+from default import sampling_data
+from amp_device import roundInterval
+
+
+def buildServiceBasicWidgets(service_name, service_type, device_ip, from_str,
+                             to_str, rounded):
+    widgets = []
+    if "SLB_vs" in service_type:
+        widgets += [{
+            "name": "vsConnPerSec",
+            "icon": "line-chart",
+            "verbose_name": 'Connections Per Second',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "vsConnPerSec",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["ConnPerSec"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "virtualStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "ServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "vsCurrEstab",
+            "icon": "line-chart",
+            "verbose_name": 'Connections Established',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "vsCurrEstab",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["CurrEstab"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "virtualStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "ServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "network_throughtput",
+            "icon": "line-chart",
+            "verbose_name": 'Network Throughput (Kbps)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["OutBytePerSec"]
+                        }, {
+                            "type": "mean"
+                        }, {
+                            "type": "math",
+                            "params": ["/128"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["InBytePerSec"]
+                                   }, {
+                                       "type": "mean"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["/128"]
+                                   }]],
+                        "measurement":
+                        "virtualStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "ServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }]
+    elif "SLB_rs" in service_type:
+        widgets += [{
+            "name": "rsCntOfReq",
+            "icon": "line-chart",
+            "verbose_name": 'Number of outstanding requests',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "rsCntOfReq",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["rsCntOfReq"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "rsConnCnt",
+            "icon": "line-chart",
+            "verbose_name": 'Number of open connections',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "rsConnCnt",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["rsConnCnt"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "rsTotalHits",
+            "icon": "line-chart",
+            "verbose_name": 'The total number of requests',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "rsTotalHits",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["rsTotalHits"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "bandwidth",
+            "icon": "line-chart",
+            "verbose_name": 'The Bandwidth (KB/second)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "realOutBandwidth",
+                        "config": LineConfig
+                    }, {
+                        "name": "realInBandwidth",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["realOutBandwidth"]
+                        }, {
+                            "type": "mean"
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["realInBandwidth"]
+                                   }, {
+                                       "type": "mean"
+                                   }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "rsConnPerSec",
+            "icon": "line-chart",
+            "verbose_name": 'Number of Connection per second',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "rsConnPerSec",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["rsConnPerSec"]
+                        }, {
+                            "type": "mean"
+                        }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "network_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'Network Throughput (Kbps)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Receive",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["rsOutBytePerSec"]
+                        }, {
+                            "type": "mean"
+                        }, {
+                            "type": "math",
+                            "params": ["/128"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["rsInBytePerSec"]
+                                   }, {
+                                       "type": "mean"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["/128"]
+                                   }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "network_throughput_packet",
+            "icon": "line-chart",
+            "verbose_name": 'Network Throughput (packet/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": "5%",
+                        "grid_left": 20,
+                        "grid_right": "5%"
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Receive",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    "now-10m",
+                    "to":
+                    "now",
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["rsOutBytePerSec"]
+                        }, {
+                            "type": "mean"
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["rsInPacketPerSec"]
+                                   }, {
+                                       "type": "mean"
+                                   }]],
+                        "measurement":
+                        "realStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "realServerId",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": ["$interval"]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }]
+    elif "SSLVPN" in service_type:
+        widgets += [{
+            "name": "login_status",
+            "icon": "pie-chart",
+            "verbose_name": 'Login Status',
+            "cls": "PieGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "legends": [
+                            "SuccessLogin", "FailureLogin", "ErrorLogin",
+                            "LockedLogin", "RejectedLogin"
+                        ]
+                    },
+                    "series": [{
+                        "name": "login_status",
+                        "config": PieConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["SuccessLogin"]
+                        }, {
+                            "type": "max"
+                        }, {
+                            "type": "math",
+                            "params": ["- min(SuccessLogin)"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["FailureLogin"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(FailureLogin)"]
+                                   }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["ErrorLogin"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(ErrorLogin)"]
+                                   }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["LockedLogin"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(LockedLogin)"]
+                                   }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["RejectedLogin"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(RejectedLogin)"]
+                                   }]],
+                        "measurement":
+                        "virtualSiteStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "client_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'Client Throughput (bit/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["ClientBytesOut"]
+                        }, {
+                            "type": "first"
+                        }, {
+                            "type": "derivative",
+                            "params": ["1s"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["ClientBytesIn"]
+                                   }, {
+                                       "type": "first"
+                                   }, {
+                                       "type": "derivative",
+                                       "params": ["1s"]
+                                   }]],
+                        "measurement":
+                        "virtualSiteStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "server_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'Server Throughput (bit/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["ServerBytesOut"]
+                        }, {
+                            "type": "first"
+                        }, {
+                            "type": "derivative",
+                            "params": ["1s"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["ServerBytesIn"]
+                                   }, {
+                                       "type": "first"
+                                   }, {
+                                       "type": "derivative",
+                                       "params": ["1s"]
+                                   }]],
+                        "measurement":
+                        "virtualSiteStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "l3_tunnels_status",
+            "icon": "pie-chart",
+            "verbose_name": 'L3 Tunnels Status',
+            "cls": "PieGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "legends": [
+                            "TunnelsOpen", "TunnelsEst", "TunnelsRejected",
+                            "TunnelsTerminated"
+                        ]
+                    },
+                    "series": [{
+                        "name": "vpn_tunnels_status",
+                        "config": PieConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["TunnelsOpen"]
+                        }, {
+                            "type": "max"
+                        }, {
+                            "type": "math",
+                            "params": ["- min(TunnelsOpen)"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["TunnelsEst"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(TunnelsEst)"]
+                                   }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["TunnelsRejected"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(TunnelsRejected)"]
+                                   }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["TunnelsTerminated"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(TunnelsTerminated)"]
+                                   }]],
+                        "measurement":
+                        "vpnStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "l3_vpn_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'L3 VPN Throughput (bit/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["BytesOut"]
+                        }, {
+                            "type": "first"
+                        }, {
+                            "type": "derivative",
+                            "params": ["1s"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["BytesIn"]
+                                   }, {
+                                       "type": "first"
+                                   }, {
+                                       "type": "derivative",
+                                       "params": ["1s"]
+                                   }]],
+                        "measurement":
+                        "vpnStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "l3_client_app_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'L3 Client APP Throughput (bit/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["clientAppBytesOut"]
+                        }, {
+                            "type": "first"
+                        }, {
+                            "type": "derivative",
+                            "params": ["1s"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["clientAppBytesIn"]
+                                   }, {
+                                       "type": "first"
+                                   }, {
+                                       "type": "derivative",
+                                       "params": ["1s"]
+                                   }]],
+                        "measurement":
+                        "vpnStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "l7_request_status",
+            "icon": "pie-chart",
+            "verbose_name": 'L7 Requests Status',
+            "cls": "PieGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "legends": ["AuthorizedReq", "UnauthorizedReq"]
+                    },
+                    "series": [{
+                        "name": "vpn_tunnels_status",
+                        "config": PieConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["AuthorizedReq"]
+                        }, {
+                            "type": "max"
+                        }, {
+                            "type": "math",
+                            "params": ["- min(AuthorizedReq)"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["UnauthorizedReq"]
+                                   }, {
+                                       "type": "max"
+                                   }, {
+                                       "type": "math",
+                                       "params": ["- min(UnauthorizedReq)"]
+                                   }]],
+                        "measurement":
+                        "webStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "l7_client_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'L7 Client Throughput (bit/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["ClientBytesOut"]
+                        }, {
+                            "type": "first"
+                        }, {
+                            "type": "derivative",
+                            "params": ["1s"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["ClientBytesIn"]
+                                   }, {
+                                       "type": "first"
+                                   }, {
+                                       "type": "derivative",
+                                       "params": ["1s"]
+                                   }]],
+                        "measurement":
+                        "webStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }, {
+            "name": "l7_server_throughput",
+            "icon": "line-chart",
+            "verbose_name": 'L7 Server Throughput (bit/s)',
+            "cls": "LineGraphWidget",
+            "args": {
+                "params": {
+                    "flush": "10s"
+                },
+                "option": {
+                    "chart": {
+                        "grid_top": 30,
+                        "grid_bottom": 40
+                    },
+                    "series": [{
+                        "name": "Sent",
+                        "config": LineConfig
+                    }, {
+                        "name": "Received",
+                        "config": LineConfig
+                    }]
+                },
+                "datasource": {
+                    "from":
+                    from_str,
+                    "to":
+                    to_str,
+                    "queries": [{
+                        "datasourceId":
+                        1,
+                        "select": [[{
+                            "type": "field",
+                            "params": ["ServerBytesOut"]
+                        }, {
+                            "type": "first"
+                        }, {
+                            "type": "derivative",
+                            "params": ["1s"]
+                        }],
+                                   [{
+                                       "type": "field",
+                                       "params": ["ServerBytesIn"]
+                                   }, {
+                                       "type": "first"
+                                   }, {
+                                       "type": "derivative",
+                                       "params": ["1s"]
+                                   }]],
+                        "measurement":
+                        "webStats",
+                        "tags": [{
+                            "key": "agent_host",
+                            "value": device_ip,
+                            "operator": "="
+                        }, {
+                            "key": "Id",
+                            "value": service_name,
+                            "operator": "="
+                        }],
+                        "groupBy": [{
+                            "type": "time",
+                            "params": [rounded]
+                        }, {
+                            "type": "fill",
+                            "params": ["null"]
+                        }],
+                        "resultFormat":
+                        "time_series"
+                    }]
+                }
+            }
+        }]
+    return widgets
+
+
+def amp_service(folderID, pdfname, args):
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    from_str = parseTimeCondition(args['from'])
+    to_str = parseTimeCondition(args['to'])
+    time_diff = calTimeDiff(from_str, to_str)
+
+    interval = time_diff / 30
+    rounded = roundInterval(interval)
+
+    cc = ChartsComponent(chartspath=pdfpath)
+
+    dataMap = {}
+
+    widgets = buildServiceBasicWidgets(args['subject']['name'],
+                                       args['subject']['origin_type'],
+                                       args['device_ip'], args['from'],
+                                       args['to'], rounded)
+    for j in range(len(widgets)):
+        # print(json.dumps(widget))
+        data = getattr(cc, widgets[j]['cls'])(widgets[j], str(j))
+        dataMap[str(j)] = sampling_data(widgets[j], data)
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": "0.3in",
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans Semibold",
+        setCJKmainfont="Open Sans",
+    )
+    doc.header_footer(product_name="Service Running Status Report",
+                      report_type="")
+    doc.newline()
+    doc.split_line()
+
+    doc.topic("Information", 0, 1)
+
+    certInfo = fetchAMPServiceCertInfo(args['device_ip'],
+                                       args['subject']['name'])
+
+    if args['subject']['origin_type'] != "SLB_rs":
+        desc = [[
+            "Service Name",
+            format_str(args['subject']['name']), "Service Type",
+            format_str(args['subject']['origin_type'])
+        ], ["From", from_str, "To", to_str],
+                [
+                    "Create Time",
+                    parseTimeCondition("now"), "Report Type",
+                    "Service Running Status"
+                ],
+                [
+                    "Certificate Expiration",
+                    format_str(certInfo["expiration"] > 4 and "Not Yet Due"
+                               or certInfo["expiration"] + " Days"), "", ""
+                ]]
+    else:
+        desc = [[
+            "Service Name",
+            format_str(args['subject']['name']), "Service Type",
+            format_str("Real Service")
+        ], ["From", from_str, "To", to_str],
+                [
+                    "Create Time",
+                    parseTimeCondition("now"), "Report Type",
+                    "Service Running Status"
+                ]]
+
+    doc.team_desc(desc)
+    doc.newline()
+
+    doc.topic("1. Basic Monitoring", 0, 1)
+    doc.newline()
+
+    for j in range(len(widgets)):
+        chartPath = os.path.join(pdfpath, str(j) + ".png")
+        h, w = get_chart_size(chartPath)
+        topic = "%s. %s" % (j + 1, format_str(widgets[j]['verbose_name']))
+
+        table_data = dataMap[str(j)]
+
+        if widgets[j]['cls'] == "PieGraphWidget":
+            doc.topic2(topic)
+            chart_pfal = doc.charts_one_column(chartPath,
+                                               240,
+                                               240,
+                                               int(240 * w / h),
+                                               isline=False)
+
+            table_cta_profit_source = doc.table_one_column(
+                280,
+                table_data,
+                fontsize="small",
+                fontsize2="footnotesize",
+                row_height=0.9)
+
+            report_cta_profit_source = []
+            doc.table_one_two_row(chart_pfal, report_cta_profit_source,
+                                  table_cta_profit_source, [9, 8])
+        else:
+            # doc.topic2(topic)
+            chart_pfal = doc.charts_one_column(chartPath, 550, 500,
+                                               int(500 * w / h))
+            doc.table_report([topic], [98], [chart_pfal])
+
+            # table_data = [['Time', 'cpu\\_usage'], ["1", "2"]]
+            if table_data is not None:
+                doc.long_table(table_data,
+                               fontsize="small",
+                               fontsize2="footnotesize",
+                               isline=False,
+                               row_height=0.8)
+        doc.newline()
+
+    pdfname += "_" + parseTimeCondition(
+        args['from'], format_str="%Y%m%d%H%M%S") + "_" + parseTimeCondition(
+            args['to'], format_str="%Y%m%d%H%M%S")
+
+    doc.generate_pdf(pdfpath, pdfname)
\ No newline at end of file
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/default.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/default.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/default.py	(working copy)
@@ -0,0 +1,209 @@
+# coding: utf-8
+import os
+import time
+from module.gen_pdf import GeneratePDF
+from module.gen_chart import ChartsComponent, get_chart_size
+from module.session import fetchHostName, getReportPath, getDeviceName
+from module.parse_time import parseTimeCondition
+from utils import format_str
+
+
+def sampling_data(widget, data):
+    if widget['cls'] == "PieGraphWidget":
+        legend = []
+        for series in widget['args']['option']['series']:
+            legend.append(format_str(series['name']))
+        legend.append("count")
+
+        res = [legend]
+
+        for i in range(len(data[0])):
+            temp = [format_str(data[0][i]), data[1][i]]
+            res.append(temp)
+
+        if len(res) > 10:
+            return res[:11]
+        return res
+    elif widget['cls'] == "BarGraphWidget":
+        series_name = format_str(widget['args']['option']['series'][0]['name'])
+        table_data = [["Rank", series_name, "count"]]
+        if 'error' not in data['A'].keys():
+            rows = data['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+        return table_data
+    elif widget['cls'] == "MapGraphWidget":
+        table_data = [["Rank", "Country/Region", "count"]]
+        if 'error' not in data['A'].keys():
+            rows = data['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+        return table_data
+    elif widget['cls'] == "LineGraphWidget":
+        legend = ["Time"]
+        for series in widget['args']['option']['series']:
+            legend.append(format_str(series['name']))
+        if 'error' not in data['A'].keys():
+            # table_data = data['A']['series'][0]['points']
+            table_data = []
+            if data['A']['series'] is not None:
+                for i in range(len(data['A']['series'])):
+                    for j in range(len(data['A']['series'][i]['points'])):
+                        if i == 0:
+                            point = data['A']['series'][i]['points'][j]
+
+                            point[0] = time.strftime(
+                                "%Y-%m-%d %H:%M:%S",
+                                time.localtime(point[0] / 1000))
+                            table_data.append(point)
+                    # pass
+                        else:
+                            table_data[j].append(
+                                data['A']['series'][i]['points'][j][1])
+        return [legend] + table_data
+    return None
+
+
+def default(folderID, pdfname, args):
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    cc = ChartsComponent(chartspath=pdfpath)
+
+    dataMap = {}
+
+    panes = args['panes']
+    for i in range(len(panes)):
+        widgets = panes[i]['widgets']
+        for j in range(len(widgets)):
+            # print(json.dumps(widget))
+
+            data = getattr(cc, widgets[j]['cls'])(widgets[j],
+                                                  str(i) + '_' + str(j),
+                                                  title="")
+            dataMap[str(i) + '_' + str(j)] = sampling_data(widgets[j], data)
+
+    from_str = panes[0]['widgets'][0]['args']['datasource']['from']
+    to_str = panes[0]['widgets'][0]['args']['datasource']['to']
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": 14,
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans Semibold",
+        setCJKmainfont="Open Sans",
+    )
+    doc.header_footer(product_name=format_str(pdfname), report_type="")
+
+    doc.newline()
+    # doc.split_line()
+
+    doc.topic("Information", 0, 1)
+
+    desc = [[
+        "Host Name",
+        format_str(fetchHostName()), "Device",
+        format_str(getDeviceName())
+    ], [
+        "From",
+        parseTimeCondition(from_str), "To",
+        parseTimeCondition(to_str)
+    ], ["Create Time",
+        parseTimeCondition("now"), "Report Type", "Monitor"]]
+
+    if "condition_name" in args.keys():
+        if args["condition_name"] != "":
+            desc.append([
+                format_str(args['condition_name']),
+                format_str(widgets[0]['args']['datasource']['queries'][0]
+                           ['condition']), '', ''
+            ])
+
+    doc.team_desc(desc)
+    doc.newline()
+
+    for i in range(len(panes)):
+        doc.topic(format_str(str(i + 1) + ' ' + format_str(panes[i]['name'])),
+                  0, 1)
+        doc.newline()
+
+        widgets = panes[i]['widgets']
+        for j in range(len(widgets)):
+            chartPath = os.path.join(pdfpath, str(i) + "_" + str(j) + ".png")
+            h, w = get_chart_size(chartPath)
+
+            table_data = dataMap[str(i) + '_' + str(j)]
+
+            if widgets[j]['cls'] == "PieGraphWidget":
+                if 'top' in widgets[j]['args']['option']['chart']:
+                    widget_name = format_str(widgets[j]['name'].replace(
+                        '{0}',
+                        str(widgets[j]['args']['option']['chart']['top'])))
+                else:
+                    widget_name = format_str(widgets[j]['name'])
+
+                topic = "%s.%s %s" % (i + 1, j + 1, format_str(widget_name))
+                doc.topic2(topic)
+                chart_pfal = doc.charts_one_column(chartPath,
+                                                   240,
+                                                   240,
+                                                   int(240 * w / h),
+                                                   isline=False)
+
+                table_cta_profit_source = doc.table_one_column(
+                    280,
+                    table_data,
+                    fontsize="small",
+                    fontsize2="footnotesize",
+                    row_height=0.9)
+
+                report_cta_profit_source = []
+                doc.table_one_two_row(chart_pfal, report_cta_profit_source,
+                                      table_cta_profit_source, [9, 8])
+            else:
+                # doc.topic2(topic)
+                # doc.topic2(topic), 0, 1)
+                # chart_pfal = doc.charts_boxplot(chartPath, 555, 500,
+                #                                 int(500 * w / h))
+                # doc.table_report([""], [50], [chart_pfal])
+                topic = "%s.%s %s" % (i + 1, j + 1,
+                                      format_str(widgets[j]['name']))
+
+                chart_pfal = doc.charts_one_column(chartPath, 550, 500,
+                                                   int(500 * w / h))
+                doc.table_report([topic], [98], [chart_pfal])
+
+                if table_data is not None:
+                    doc.long_table(table_data,
+                                   fontsize="small",
+                                   fontsize2="footnotesize",
+                                   isline=False,
+                                   row_height=0.9)
+
+            doc.newline()
+
+    pdfname += "_" + parseTimeCondition(
+        from_str, format_str="%Y%m%d%H%M%S") + "_" + parseTimeCondition(
+            to_str, format_str="%Y%m%d%H%M%S")
+
+    doc.generate_pdf(pdfpath, pdfname)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/group_status.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/group_status.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/group_status.py	(working copy)
@@ -0,0 +1,945 @@
+# -*- coding: UTF-8 -*-
+import os
+from module.gen_pdf import GeneratePDF
+from module.gen_chart import ChartsComponent, get_chart_size
+from module.parse_time import parseTimeCondition, calTimeDiff, parseWeekDay
+from module.session import fetchHostName, getReportPath, tsdbQuery
+from utils import format_str, PieConfig, BarConfig, MapConfig, LineConfig
+import json
+
+
+def getGroupThroughput(args, group_name):
+    res = tsdbQuery(
+        json.dumps({
+            "from":
+            args['from'],
+            "to":
+            args['to'],
+            "queries": [{
+                "datasourceId":
+                3,
+                "type":
+                "traffic_general",
+                "rawSql":
+                "select sum(bytes) from (select sum(total_bytes_in+total_bytes_out) as bytes from ads_group_traffic_inbound WHERE $__timeFilter(time) AND group_name = '%s' UNION ALL select sum(total_bytes_in+total_bytes_out) from ads_group_traffic_outbound WHERE $__timeFilter(time) AND group_name = '%s')"
+                % (group_name, group_name),
+                "format":
+                "table"
+            }]
+        }))
+
+    througput_num = 0
+    if 'error' not in res['A'].keys():
+        rows = res['A']['tables'][0]['rows']
+        for row in rows:
+            if row[0] is not None:
+                througput_num += row[0]
+
+    return througput_num
+
+
+def group_status(folderID, pdfname, args):
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    from_str = parseTimeCondition(args['from'])
+    to_str = parseTimeCondition(args['to'])
+    time_diff = calTimeDiff(from_str, to_str)
+
+    group_name = args['group_name']
+
+    througput_num = getGroupThroughput(args, group_name)
+
+    attackSeverityWidgetObj = {
+        "name": "attack_severity",
+        "args": {
+            "option": {
+                "chart": {
+                    "legends2": [
+                        "EMERG", "ALERT", "CRITICAL", "ERROR", "WARNING",
+                        "NOTICE", "DEBUG"
+                    ]
+                },
+                "series": [{
+                    "name": "",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select severity, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '%s' AND srv = '-' group by severity"
+                    % (group_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    attackTypeWidgetObj = {
+        "name": "attack_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select atktype, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND atktype != '-' AND grp = '%s' AND srv = '-' group by atktype"
+                    % (group_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    attackRegionWidgetObj = {
+        "name": "attack_region",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": MapConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND sip != '-' AND grp = '%s' AND srv = '-' group by sip"
+                    % (group_name),
+                    "format":
+                    "geoip"
+                }]
+            }
+        }
+    }
+
+    attackTimeWidgetObj = {
+        "name": "attack_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '"
+                    + group_name + "' AND srv = '-' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosSeverityWidgetObj = {
+        "name": "ddos_severity",
+        "args": {
+            "option": {
+                "chart": {
+                    "legends2": [
+                        "EMERG", "ALERT", "CRITICAL", "ERROR", "WARNING",
+                        "NOTICE", "DEBUG"
+                    ]
+                },
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select severity, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '%s' AND srv = '-' group by severity"
+                    % (group_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosTypeWidgetObj = {
+        "name": "ddos_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select atktype, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND atktype != '-' AND grp = '%s' AND srv = '-' group by atktype"
+                    % (group_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosIPWidgetObj = {
+        "name": "ddos_ip",
+        "args": {
+            "option": {
+                "chart": {
+                    "top": 10
+                },
+                "series": [{
+                    "name": "",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) as num from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '%s' AND srv = '-' AND sip != '-' group by sip"
+                    % (group_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosRegionWidgetObj = {
+        "name": "ddos_region",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": MapConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) as num from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '%s' AND srv = '-' AND sip != '-' group by sip"
+                    % (group_name),
+                    "format":
+                    "geoip"
+                }]
+            }
+        }
+    }
+
+    ddosTimeWidgetObj = {
+        "name": "ddos_time",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '"
+                    + group_name + "' AND srv = '-' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    httpThroughputWidgetObj = {
+        "name": "http_throughput",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "traffic_general",
+                    "rawSql":
+                    "select timef, avg(throughput) from (SELECT $__timeGroup(time, $__interval) AS timef, avg(total_bytes_in+total_bytes_out)/30720.0 as throughput FROM ads_group_traffic_inbound WHERE $__timeFilter(time) AND group_name = '%s' group by timef union all SELECT $__timeGroup(time, $__interval) AS timef, avg(total_bytes_in+total_bytes_out)/30720.0 FROM ads_group_traffic_outbound WHERE $__timeFilter(time) AND group_name = '%s' group by timef) group by timef"
+                    % (group_name, group_name),
+                    "format":
+                    "time_series"
+                }]
+            }
+        }
+    }
+
+    dropReasonWidgetObj = {
+        "name": "drop_reason",
+        "args": {
+            "option": {
+                "chart": {
+                    "legends": [
+                        "TCP source authen", "TCP session check",
+                        "TCP dynamic blacklist", "TCP ACL", "UDP fingerprint",
+                        "UDP ACL", "UDP no enough PCB", "ICMP ACL",
+                        "ICMP no enough PCB"
+                    ]
+                },
+                "series": [{
+                    "name": "drop_reason",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "traffic_drop",
+                    "rawSql":
+                    "SELECT sum(tcp_source_authen), sum(tcp_session_check), sum(tcp_auto_blacklist), sum(tcp_acl), sum(udp_fingerprint), sum(udp_acl), sum(udp_no_resources), sum(icmp_acl), sum(icmp_no_resources) FROM ads_group_drop WHERE $__timeFilter(time) AND group_name='%s'"
+                    % (group_name),
+                    "format":
+                    "table"
+                }]
+            }
+        }
+    }
+
+    dropTimeWidgetObj = {
+        "name": "filter_time",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "traffic_drop",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(total) from ads_group_drop WHERE $__timeFilter(time) AND group_name = '"
+                    + group_name + "' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    cc = ChartsComponent(chartspath=pdfpath)
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": "0.3in",
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans Semibold",
+        setCJKmainfont="Open Sans",
+    )
+
+    doc.header_footer(product_name="Security Status Report for",
+                      report_type="ASF Group \"" + format_str(group_name) +
+                      "\"")
+    doc.newline()
+    doc.split_line()
+    doc.new_line()
+
+    desc = [["Host Name", format_str(fetchHostName())],
+            ["Report Type", "ASF Group Security Status"],
+            ["Statistical Period", from_str + " - " + to_str]]
+
+    doc.one_row_desc(desc)
+    doc.new_line()
+
+    doc.topic("1 Overview", 0, 1)
+    security_class = "Unknown"
+    top5_attack_type = []
+    attack_num = 0
+
+    if througput_num == 0:
+        doc.landscape_navigations([
+            "No traffic has passed this group yet. For the security of your group, it is recommended to use the appliance to defense your group as soon as possible."
+        ])
+        doc.newline()
+        doc.newline()
+    else:
+
+        attackSeverityData = cc.PieGraphWidget(attackSeverityWidgetObj,
+                                               "attack_severity")
+        severity_list = attackSeverityData[1]
+        attack_num = sum(severity_list)
+        if sum(severity_list[2:6]) == 0:
+            security_class = "Secure"
+        elif sum(severity_list[2:5]) == 0:
+            security_class = "Low Risky"
+        elif sum(severity_list[2:4]) == 0:
+            security_class = "Medium Risky"
+        else:
+            security_class = "High Risky"
+
+        attackTypeData = cc.BarGraphWidget(attackTypeWidgetObj, "attack_type")
+        if 'error' not in attackTypeData['A'].keys():
+            rows = attackTypeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:5]
+            for row in rows:
+                top5_attack_type.append(format_str(row[0]))
+
+        cc.MapGraphWidget(attackRegionWidgetObj, "attack_region")
+        cc.BarGraphWidget(attackTimeWidgetObj, "attack_time")
+
+        doc.landscape_navigations([
+            "During the evaluation period between %s and %s, the security class of \"%s\" is %s."
+            % (from_str, to_str, format_str(group_name), security_class),
+            "During this period, group \"%s\" has encountered %d attacks or threats. See the following graphs for details."
+            % (format_str(group_name), attack_num)
+        ])
+
+        doc.newline()
+        doc.newline()
+
+        h, w = get_chart_size(os.path.join(pdfpath, "attack_severity.png"))
+        chart_path_allocation_margin = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_severity.png"),
+            263,
+            int(100 * h / w),
+            100,
+            mini_w=int(100 * h / w))
+        chart_path_allocation_market_value = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_type.png"),
+            263,
+            250,
+            100,
+            mini_w=250)
+
+        doc.table_report(
+            [
+                "Attack/Threat Severity Distribution",
+                "Attack/Threat Type Distribution"
+            ], [98, 98],
+            [chart_path_allocation_margin, chart_path_allocation_market_value])
+        doc.newline()
+        doc.newline()
+
+        h, w = get_chart_size(os.path.join(pdfpath, "attack_time.png"))
+        chart_holding_fashion = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_time.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report(["Attack/Threat Time Distribution by Hour"], [98],
+                         [chart_holding_fashion])
+        doc.newline()
+        doc.newline()
+
+        h, w = get_chart_size(os.path.join(pdfpath, "attack_region.png"))
+        chart_holding_fashion = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_region.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report(["Attack/Threat Source Region Distribution"], [98],
+                         [chart_holding_fashion])
+        doc.newline()
+        doc.newline()
+
+    doc.topic("2 DDoS Attack Analysis", 0, 1)
+    doc.newline()
+
+    ddosSeverityData = cc.BarGraphWidget(ddosSeverityWidgetObj,
+                                         "ddos_severity")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_severity.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "ddos_severity.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["2.1 Attack Analysis by Severity"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Attack Severity", "Count"]]
+    if 'error' not in ddosSeverityData['A'].keys():
+        rows = ddosSeverityData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, rows[i][0], rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    ddosTypeData = cc.BarGraphWidget(ddosTypeWidgetObj, "ddos_type")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_type.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "ddos_type.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["2.2 Attack Analysis by Type"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Attack Type", "Count"]]
+    if 'error' not in ddosTypeData['A'].keys():
+        rows = ddosTypeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    doc.topic2("2.3 Attack Analysis by Source IP")
+    ddosIPData = cc.PieGraphWidget(ddosIPWidgetObj, "ddos_ip")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_ip.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "ddos_ip.png"),
+                                       240,
+                                       240,
+                                       int(240 * w / h),
+                                       isline=False)
+
+    table_data = [["Rank", "Source IP", "Count"]]
+    for i in range(len(ddosIPData[0])):
+        if i < 10:
+            table_data.append([i + 1, ddosIPData[0][i], ddosIPData[1][i]])
+
+    table_cta_profit_source = doc.table_one_column(285,
+                                                   table_data,
+                                                   fontsize="small",
+                                                   fontsize2="footnotesize",
+                                                   row_height=0.9,
+                                                   isline=False)
+
+    doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+    doc.newline()
+    doc.newline()
+
+    ddosRegionData = cc.MapGraphWidget(ddosRegionWidgetObj, "ddos_region")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_region.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "ddos_region.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["2.4 Attack Analysis by Source Region"], [98],
+                     [chart_pfal])
+
+    table_data = [["Rank", "Country/Region", "Count"]]
+    if 'error' not in ddosRegionData['A'].keys():
+        rows = ddosRegionData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    ddosTimeWidgetObj['args']['datasource']['queries'][0][
+        'rawSql'] = "select strftime('%H', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '" + group_name + "' AND srv = '-' group by times"
+    ddosTimeData = cc.BarGraphWidget(ddosTimeWidgetObj,
+                                     "ddos_hour",
+                                     title="Attack Analysis by Hour")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_hour.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "ddos_hour.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["2.5 Attack Analysis by Time"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Hour", "Count"]]
+    if 'error' not in ddosTimeData['A'].keys():
+        rows = ddosTimeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([i + 1, hour_str, rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    if time_diff >= 30 * 24 * 60 * 60:
+        ddosTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%d', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '" + group_name + "' AND srv = '-' group by times"
+        ddosTimeData = cc.BarGraphWidget(ddosTimeWidgetObj,
+                                         "ddos_month",
+                                         title="Attack Analysis by Date")
+        h, w = get_chart_size(os.path.join(pdfpath, "ddos_month.png"))
+        chart_pfal = doc.charts_boxplot(
+            os.path.join(pdfpath, "ddos_month.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Date", "Count"]]
+        if 'error' not in ddosTimeData['A'].keys():
+            rows = ddosTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, rows[i][0], rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    elif time_diff >= 7 * 24 * 60 * 60:
+        ddosTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%w', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND grp = '" + group_name + "' AND srv = '-' group by times"
+        ddosTimeData = cc.WeekBarGraphWidget(
+            ddosTimeWidgetObj, "ddos_week", title="Attack Analysis by Weekday")
+        h, w = get_chart_size(os.path.join(pdfpath, "ddos_week.png"))
+        chart_pfal = doc.charts_boxplot(os.path.join(pdfpath, "ddos_week.png"),
+                                        550, 500, int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Weekday", "Count"]]
+        if 'error' not in ddosTimeData['A'].keys():
+            rows = ddosTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append(
+                    [i + 1, parseWeekDay(rows[i][0]), rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    doc.topic("3 Traffic Analysis", 0, 1)
+    doc.newline()
+
+    cc.LineGraphWidget(httpThroughputWidgetObj, "http_throughput")
+    h, w = get_chart_size(os.path.join(pdfpath, "http_throughput.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "http_throughput.png"), 550, 500,
+        int(500 * w / h))
+    doc.table_report(["3.1 HTTP Throughput Analysis"], [98], [chart_pfal])
+
+    res = tsdbQuery(
+        json.dumps({
+            "from":
+            args['from'],
+            "to":
+            args['to'],
+            "queries": [{
+                "datasourceId":
+                3,
+                "type":
+                "traffic_general",
+                "rawSql":
+                "select strftime('%H', time) as timef, avg(traffic)/30720.0, max(traffic)/30720.0 from (select time, sum(throughput) as traffic from (SELECT time, total_bytes_in+total_bytes_out as throughput FROM ads_group_traffic_inbound WHERE $__timeFilter(time) AND group_name = '"
+                + group_name +
+                "' union all SELECT time, total_bytes_in+total_bytes_out FROM ads_group_traffic_outbound WHERE $__timeFilter(time) AND group_name = '"
+                + group_name + "') group by time) group by timef",
+                "format":
+                "cluster"
+            }]
+        }))
+
+    table_data = [[
+        "Time", "Average Throughput (Kbps)", "Peak Throughput (Kbps)"
+    ]]
+    if 'error' not in res['A'].keys():
+        rows = res['A']['tables'][0]['rows']
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([hour_str, rows[i][1], rows[i][2]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.7)
+    # doc.table_report([""], [80], [table_profit_ability])
+
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.8)
+
+    doc.topic("4 Packet Drop Analysis", 0, 1)
+    doc.newline()
+
+    doc.topic2("4.1 Packet Drop Analysis by Reason")
+
+    dropReasonData = cc.PieGraphWidget(dropReasonWidgetObj, "drop_reason")
+    h, w = get_chart_size(os.path.join(pdfpath, "drop_reason.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath,
+                                                    "drop_reason.png"),
+                                       240,
+                                       240,
+                                       int(240 * w / h),
+                                       isline=False)
+
+    table_data = [["Drop Reason", "Drop Count"]]
+    for i in range(len(dropReasonData[0])):
+        if i < 10:
+            table_data.append([dropReasonData[0][i], dropReasonData[1][i]])
+
+    table_cta_profit_source = doc.table_one_column(285,
+                                                   table_data,
+                                                   fontsize="small",
+                                                   fontsize2="footnotesize",
+                                                   row_height=0.9,
+                                                   isline=False)
+
+    doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+    doc.newline()
+    doc.newline()
+
+    dropTimeData = cc.BarGraphWidget(dropTimeWidgetObj,
+                                     "drop_hour",
+                                     title="Packet Drop Analysis by Hour")
+    h, w = get_chart_size(os.path.join(pdfpath, "drop_hour.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "drop_hour.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["4.2 Packet Drop Analysis by Time"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Hour", "Count"]]
+    if 'error' not in dropTimeData['A'].keys():
+        rows = dropTimeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([i + 1, hour_str, rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    if time_diff >= 30 * 24 * 60 * 60:
+        dropTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%d', time) as times, sum(total) from ads_group_drop WHERE $__timeFilter(time) AND group_name = '" + group_name + "' group by times"
+        dropTimeData = cc.BarGraphWidget(dropTimeWidgetObj,
+                                         "drop_month",
+                                         title="Packet Drop Analysis by Date")
+        h, w = get_chart_size(os.path.join(pdfpath, "drop_month.png"))
+        chart_pfal = doc.charts_boxplot(
+            os.path.join(pdfpath, "drop_month.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Date", "Count"]]
+        if 'error' not in dropTimeData['A'].keys():
+            rows = dropTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, rows[i][0], rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    elif time_diff >= 7 * 24 * 60 * 60:
+        dropTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%w', time) as times, sum(total) from ads_group_drop WHERE $__timeFilter(time) AND group_name = '" + group_name + "' group by times"
+        dropTimeData = cc.WeekBarGraphWidget(
+            dropTimeWidgetObj,
+            "drop_week",
+            title="Packet Drop Analysis by Weekday")
+        h, w = get_chart_size(os.path.join(pdfpath, "drop_week.png"))
+        chart_pfal = doc.charts_boxplot(os.path.join(pdfpath, "drop_week.png"),
+                                        550, 500, int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Weekday", "Count"]]
+        if 'error' not in dropTimeData['A'].keys():
+            rows = dropTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append(
+                    [i + 1, parseWeekDay(rows[i][0]), rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    doc.topic("7 Summary", 0, 1)
+
+    if security_class == "Secure":
+        doc.landscape_navigations([
+            "During the period between %s and %s, the security status of group \"%s\" is \"%s\". You do not need to add additional defense configurations for it temporarily."
+            % (from_str, to_str, format_str(group_name), security_class)
+        ])
+    else:
+
+        top5_source_ip = []
+        sourceIPData = tsdbQuery(
+            json.dumps({
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND sip != '-' AND grp = '%s' AND srv = '-' group by sip"
+                    % (group_name),
+                    "format":
+                    "cluster"
+                }]
+            }))
+        if 'error' not in sourceIPData['A'].keys():
+            rows = sourceIPData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:5]
+            for row in rows:
+                top5_source_ip.append("%s (%s times) " %
+                                      (format_str(row[0]), row[1]))
+
+        navigations = [
+            "During the period between %s and %s, the security status of group \"%s\" is %s."
+            % (from_str, to_str, format_str(group_name), security_class)
+        ]
+
+        navigations_content = "The data show that your group has encounters %s attacks in this period." % (
+            attack_num)
+        if len(top5_attack_type) > 0:
+            navigations_content += "The top 5 attack types are: %s." % (
+                ", ".join(top5_attack_type))
+        if len(top5_source_ip) > 0:
+            navigations_content += "The most suspicious attackers are: %s. It is recommended that you add these IPs into the system blacklist if you have confirmed that they are malicious users." % (
+                ", ".join(top5_source_ip))
+
+        navigations.append(navigations_content)
+        if througput_num != 0:
+            navigations.append(
+                "The system have defended against these attacks and threats. Please keep or strengthen the defense configuration for this group. "
+            )
+        doc.landscape_navigations(navigations)
+
+    pdfname += "_" + parseTimeCondition(
+        args['from'], format_str="%Y%m%d%H%M%S") + "_" + parseTimeCondition(
+            args['to'], format_str="%Y%m%d%H%M%S")
+
+    doc.generate_pdf(pdfpath, pdfname)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/pci_dss.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/pci_dss.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/pci_dss.py	(working copy)
@@ -0,0 +1,202 @@
+# -*- coding: UTF-8 -*-
+import os
+from module.gen_pdf import GeneratePDF
+from module.parse_time import parseTimeCondition
+from module.session import fetchServiceAddress, getReportPath, fetchServicePCIDSS
+from utils import format_str
+
+
+def fetch_pci_row(section, status):
+    status_map = {0: "Not Compliant", 1: "Partially compliant", 2: "Compliant"}
+    section_map = {
+        "2.3": {
+            "requirement":
+            "Encrypt all non-console administrative access using strong cryptography.",
+            "solution":
+            "Please ensure that the service is of the HTTPS protocol type."
+        },
+        "3.3": {
+            "requirement":
+            "Mask PAN when displayed (the first six and last four digits are the maximum number of digits to be displayed), such that only personnel with a legitimate business need can see more than the first six/last four digits of the PAN.",
+            "solution":
+            "Please configure DLP rules to prevent leakage of sensitive information."
+        },
+        "4.1": {
+            "requirement": [
+                "Use strong cryptography and security protocols to safeguard sensitive cardholder data during transmission over open, public networks, including the following:",
+                u"• \qquad Only trusted keys and certificates are accepted.",
+                u"• \qquad The protocol in use only supports secure versions or configurations.",
+                u"• \qquad The encryption strength is appropriate for the encryption methodology in use."
+            ],
+            "solution":
+            "Please ensure that the service is of the HTTPS protocol type."
+        },
+        "6.1": {
+            "requirement":
+            "Establish a process to identify security vulnerabilities, using reputable outside sources for security vulnerability information, and assign a risk ranking (for example, as \"high\", \"medium\" or \"low\") to newly discovered security vulnerabilities.",
+            "solution":
+            "ASF supports manual and auto update of the signature library and identifies the risk levels of vulnerabilities. Please configure ASL automatic update to ensure that new vulnerabilities can be protected."
+        },
+        "6.5.1": {
+            "requirement":
+            "Injection flaws",
+            "solution":
+            "Please ensure that a WAF profile with generic signatures enabled has been associated with the service and the defense mode of the negative WAF is set to \"block\". The generic signatures cover defense rules to counter against SQL injection, LDAP injection, command injection, and other injection attacks."
+        },
+        "6.5.2": {
+            "requirement":
+            "Buffer overflows",
+            "solution":
+            "Please ensure that a WAF profile with generic signatures enabled has been enabled for the service and the defense mode of the negative WAF is set to \"block\"."
+        },
+        "6.5.4": {
+            "requirement":
+            "Insecure communications",
+            "solution":
+            "Please ensure that the service is of the HTTPS protocol type."
+        },
+        "6.5.5": {
+            "requirement":
+            "Improper error handling",
+            "solution":
+            "Please ensure that advanced HTTP settings have been configured to block client access when 403 or 5xx error code is returned/redirected by server."
+        },
+        "6.5.7": {
+            "requirement":
+            "Cross-site scripting (XSS)",
+            "solution":
+            "Please ensure that a WAF profile with generic signatures enabled has been associated with the service and the defense mode of the negative WAF is set to \"block\". Generic signatures cover defense rules to counter against XSS attacks."
+        },
+        "6.5.8": {
+            "requirement":
+            "Improper access control",
+            "solution":
+            "Please ensure that HTTP filter rules have been configured to block client access using the request method other than GET, POST and HEAD."
+        },
+        "6.5.9": {
+            "requirement":
+            "Cross-site request forgery (CSRF)",
+            "solution":
+            "Please ensure that a WAF profile with generic signatures enabled has been associated with the service and the defense mode of the negative WAF is set to \"block\". Generic signatures cover defense rules to counter against CSRF attacks."
+        },
+        "6.6": {
+            "requirement": [
+                "For public-facing web applications, address new threats and vulnerabilities on an ongoing basis and ensure these applications are protected against known attacks by either of the following methods:",
+                u"• \qquad Reviewing public-facing web applications via manual or automated application vulnerability security assessment tools or methods, at least annually and after any changes.",
+                u"• \qquad Installing web- application firewall"
+            ],
+            "solution":
+            "Please ensure that the WAF feature is enabled, the system is not in TAP mode and this site is protected by WAF."
+        },
+        "7.1": {
+            "requirement":
+            "Limit access to system components and cardholder data to only those individuals whose job requires such access.",
+            "solution":
+            "Please ensure that HTTP filter rules have been configured to block client access using the request method other than GET, POST and HEAD."
+        },
+        "11.4": {
+            "requirement":
+            "Use intrusion-detection and/or intrusion-prevention techniques to detect and/or prevent intrusions into the network. Monitor all traffic at the perimeter of the cardholder data environment as well as at critical points in the cardholder data environment, and alert personnel to suspected compromises.",
+            "solution":
+            "Please ensure that negative WAF has been enabled and its defense mode is set to \"block\" for the WAF profile associated with the service."
+        }
+    }
+    return [
+        section,
+        section_map[section]['requirement'],
+        status_map[status],
+        section_map[section]['solution'],
+    ]
+
+
+def pci_dss(folderID, pdfname, args):
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    # service_type = args['service_type'].lower()
+    service_name = args['service_name']
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": "0.3in",
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans",
+        setCJKmainfont="Open Sans",
+    )
+
+    doc.header_footer(product_name="ASF PCI DSS Compliance Report for",
+                      report_type="ASF Service \"" + format_str(service_name) +
+                      "\"")
+    doc.newline()
+    doc.split_line()
+    doc.new_line()
+
+    desc = [
+        [
+            "Report generation time",
+            parseTimeCondition("now", format_str="%Y-%m-%d %H:%M:%S")
+        ],
+        [
+            "Note",
+            "This reports adheres to Payment Card Industry (PCI) Data Security Standard version 3.2. This reports only access the requirements related to the product's defense scope and therefore should not replace the PCI audit report issued by qualified PCI DSS accessors."
+        ], ["Service Name", format_str(service_name)],
+        ["Service address",
+         format_str(fetchServiceAddress(service_name))]
+    ]
+
+    doc.one_row_desc(desc)
+    doc.new_line()
+
+    result = fetchServicePCIDSS(service_name)
+
+    doc.topic2(
+        "The following table shows the results of PCI DSS compliance checks:",
+        is_line=False)
+
+    if result['result'] == "Success.":
+        table_data = [[
+            "PCI Section", "PCI Requirement", "Compliance Status", "Solution"
+        ]]
+
+        for i in range(12):
+            rows = result['PCI_DSS']['PCI_DSS_' + str(i + 1)]
+            if len(rows) != 0:
+                for row in rows:
+                    table_data.append(fetch_pci_row(row['item'], row['match']))
+
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="small",
+                       fontcolor2="74,74,74",
+                       table_spec=[1.8, 6.8, 2.9, 5.9],
+                       isline=False,
+                       row_height=1.0)
+    else:
+        doc.landscape_navigations([format_str(result['result'])])
+
+    # table_profit_ability = doc.table_one_column(555,
+    #                                             table_data,
+    #                                             fontsize="small",
+    #                                             fontsize2="footnotesize",
+    #                                             row_height=1.0)
+
+    # doc.table_report([""], [80], [table_profit_ability])
+
+    pdfname += "_" + parseTimeCondition('now', format_str="%Y%m%d%H%M%S")
+    doc.generate_pdf(pdfpath, pdfname)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/service_status.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/service_status.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/service_status.py	(working copy)
@@ -0,0 +1,1661 @@
+# -*- coding: UTF-8 -*-
+import os
+from module.gen_pdf import GeneratePDF
+from module.gen_chart import ChartsComponent, get_chart_size
+from module.parse_time import parseTimeCondition, calTimeDiff, parseWeekDay
+from module.session import fetchHostName, fetchServiceAddress, getReportPath, tsdbQuery
+from utils import format_str, getPieValue, PieConfig, BarConfig, MapConfig, LineConfig
+import json
+
+
+def getServiceThroughput(args, service_name, service_type):
+
+    if service_type == "https":
+        rawSql = "select sum(throughput) from (SELECT sum(ssl_total_bytes_in+ssl_total_bytes_out) as throughput FROM ads_service_%s_traffic_inbound WHERE $__timeFilter(time) AND service_name = '%s' union all SELECT sum(ssl_total_bytes_in+ssl_total_bytes_out) FROM ads_service_%s_traffic_outbound WHERE $__timeFilter(time) AND service_name = '%s')" % (
+            service_type, service_name, service_type, service_name)
+    else:
+        rawSql = "select sum(throughput) from (SELECT sum(total_bytes_in+total_bytes_out) as throughput FROM ads_service_%s_traffic_inbound WHERE $__timeFilter(time) AND service_name = '%s' union all SELECT sum(total_bytes_in+total_bytes_out) FROM ads_service_%s_traffic_outbound WHERE $__timeFilter(time) AND service_name = '%s')" % (
+            service_type, service_name, service_type, service_name)
+
+    res = tsdbQuery(
+        json.dumps({
+            "from":
+            args['from'],
+            "to":
+            args['to'],
+            "queries": [{
+                "datasourceId": 3,
+                "type": "traffic_general",
+                "rawSql": rawSql,
+                "format": "table"
+            }]
+        }))
+
+    througput_num = 0
+    if 'error' not in res['A'].keys():
+        rows = res['A']['tables'][0]['rows']
+        for row in rows:
+            if row[0] is not None:
+                througput_num += row[0]
+    return througput_num
+
+
+def getServiceSeverity(args, service_name):
+    res = tsdbQuery(
+        json.dumps({
+            "from":
+            args['from'],
+            "to":
+            args['to'],
+            "queries": [{
+                "datasourceId":
+                3,
+                "type":
+                "agent_log",
+                "rawSql":
+                "select severity, sum(counts) from (select severity, counts from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '%s' UNION ALL select severity, counts from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s') group by severity"
+                % (service_name, service_name),
+                "format":
+                "cluster"
+            }]
+        }))
+
+    list = [0, 0, 0, 0, 0, 0, 0]
+    if 'error' not in res['A'].keys():
+        rows = res['A']['tables'][0]['rows']
+        for row in rows:
+            if row[0] == 'EMERG':
+                list[0] = row[1]
+            elif row[0] == 'ALERT':
+                list[1] = row[1]
+            elif row[0] == 'CRITICAL':
+                list[2] = row[1]
+            elif row[0] == 'ERROR':
+                list[3] = row[1]
+            elif row[0] == 'WARNING':
+                list[4] = row[1]
+            elif row[0] == 'NOTICE':
+                list[5] = row[1]
+            elif row[0] == 'DEBUG':
+                list[6] = row[1]
+    return list
+
+
+def service_status(folderID, pdfname, args):
+
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    from_str = parseTimeCondition(args['from'])
+    to_str = parseTimeCondition(args['to'])
+    time_diff = calTimeDiff(from_str, to_str)
+
+    service_type = args['service_type'].lower()
+    service_name = args['service_name']
+
+    througput_num = getServiceThroughput(args, service_name, service_type)
+
+    attackCategoryWidgetObj = {
+        "name": "attack_category",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select type, sum(num) from (select 'DDoS Attack' as type , sum(counts) as num from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '%s' union all select 'Web Attack', sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' union all select 'HTTP Filter', sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '%s') group by type"
+                    % (service_name, service_name, service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    attackTypeWidgetObj = {
+        "name": "attack_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select atktype, sum(counts) from (select atktype, counts from asf_global_ddos_attack WHERE $__timeFilter(time) AND atktype != '-' AND srv = '%s' UNION ALL select attack_type, counts from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' union all select type, counts from asf_global_filter WHERE $__timeFilter(time) AND srv = '%s') group by atktype"
+                    % (service_name, service_name, service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    attackRegionWidgetObj = {
+        "name": "attack_region",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": MapConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) from (select sip, counts from asf_global_ddos_attack WHERE $__timeFilter(time) AND sip != '-' AND srv = '%s' UNION ALL select client_ip, counts from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' union all select sip, counts from asf_global_filter WHERE $__timeFilter(time) AND srv = '%s') group by sip"
+                    % (service_name, service_name, service_name),
+                    "format":
+                    "geoip"
+                }]
+            }
+        }
+    }
+
+    attackTimeWidgetObj = {
+        "name": "attack_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select times, sum(counts) from (select strftime('%H', time) as times, counts from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '"
+                    + service_name +
+                    "' UNION ALL select strftime('%H', time), counts from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '"
+                    + service_name +
+                    "' union all select strftime('%H', time), counts from asf_global_filter WHERE $__timeFilter(time) AND srv = '"
+                    + service_name + "') group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    wafSeverityWidgetObj = {
+        "name": "waf_severity",
+        "args": {
+            "option": {
+                "chart": {
+                    "legends2": [
+                        "EMERG", "ALERT", "CRITICAL", "ERROR", "WARNING",
+                        "NOTICE", "DEBUG"
+                    ]
+                },
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select severity, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' group by severity"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    wafTypeWidgetObj = {
+        "name": "waf_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select attack_type, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' group by attack_type"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    wafIPWidgetObj = {
+        "name": "waf_ip",
+        "args": {
+            "option": {
+                "chart": {
+                    "top": 10
+                },
+                "series": [{
+                    "name": "",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select client_ip, sum(counts) as num from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' group by client_ip"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    wafRegionWidgetObj = {
+        "name": "waf_region",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": MapConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select client_ip, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' group by client_ip"
+                    % (service_name),
+                    "format":
+                    "geoip"
+                }]
+            }
+        }
+    }
+
+    wafTimeWidgetObj = {
+        "name": "waf_time",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '"
+                    + service_name + "' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosSeverityWidgetObj = {
+        "name": "ddos_severity",
+        "args": {
+            "option": {
+                "chart": {
+                    "legends2": [
+                        "EMERG", "ALERT", "CRITICAL", "ERROR", "WARNING",
+                        "NOTICE", "DEBUG"
+                    ]
+                },
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select severity, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '%s' group by severity"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosTypeWidgetObj = {
+        "name": "ddos_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select atktype, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND atktype != '-' AND srv = '%s' group by atktype"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosIPWidgetObj = {
+        "name": "ddos_ip",
+        "args": {
+            "option": {
+                "chart": {
+                    "top": 10
+                },
+                "series": [{
+                    "name": "",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) as num from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '%s' AND sip != '-' group by sip"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    ddosRegionWidgetObj = {
+        "name": "ddos_region",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": MapConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '%s' AND sip != '-' group by sip"
+                    % (service_name),
+                    "format":
+                    "geoip"
+                }]
+            }
+        }
+    }
+
+    ddosTimeWidgetObj = {
+        "name": "ddos_time",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '"
+                    + service_name + "' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    filterTypeWidgetObj = {
+        "name": "filter_type",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select type, sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '"
+                    + service_name + "' group by type",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    filterIPWidgetObj = {
+        "name": "filter_ip",
+        "args": {
+            "option": {
+                "chart": {
+                    "top": 10
+                },
+                "series": [{
+                    "name": "",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) as num from asf_global_filter WHERE $__timeFilter(time) AND srv = '%s' group by sip"
+                    % (service_name),
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    filterRegionWidgetObj = {
+        "name": "filter_region",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": MapConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '%s' group by sip"
+                    % (service_name),
+                    "format":
+                    "geoip"
+                }]
+            }
+        }
+    }
+
+    filterTimeWidgetObj = {
+        "name": "filter_time",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '"
+                    + service_name + "' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    if service_type == "https":
+        throughput_rawSql = "select timef, sum(throughput) from (SELECT $__timeGroup(time, $__interval) AS timef, avg(ssl_total_bytes_in+ssl_total_bytes_out)/30720.0 as throughput FROM ads_service_%s_traffic_inbound WHERE $__timeFilter(time) AND service_name = '%s' group by timef union all SELECT $__timeGroup(time, $__interval) AS timef, avg(ssl_total_bytes_in+ssl_total_bytes_out)/30720.0 FROM ads_service_%s_traffic_outbound WHERE $__timeFilter(time) AND service_name = '%s' group by timef) group by timef" % (
+            service_type, service_name, service_type, service_name)
+    else:
+        throughput_rawSql = "select timef, sum(throughput) from (SELECT $__timeGroup(time, $__interval) AS timef, avg(total_bytes_in+total_bytes_out)/30720.0 as throughput FROM ads_service_%s_traffic_inbound WHERE $__timeFilter(time) AND service_name = '%s' group by timef union all SELECT $__timeGroup(time, $__interval) AS timef, avg(total_bytes_in+total_bytes_out)/30720.0 FROM ads_service_%s_traffic_outbound WHERE $__timeFilter(time) AND service_name = '%s' group by timef) group by timef" % (
+            service_type, service_name, service_type, service_name)
+
+    httpThroughputWidgetObj = {
+        "name": "http_throughput",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId": 3,
+                    "type": "traffic_general",
+                    "rawSql": throughput_rawSql,
+                    "format": "time_series"
+                }]
+            }
+        }
+    }
+
+    dropReasonWidgetObj = {
+        "name": "drop_reason",
+        "args": {
+            "option": {
+                "chart": {
+                    "legends": [
+                        "Source authen", "Dynamic blacklist", "ACL", "DDoS",
+                        "WAF", "Anomaly ", "Parse fail", "No enough resource"
+                    ]
+                },
+                "series": [{
+                    "name": "drop_reason",
+                    "config": PieConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "traffic_drop",
+                    "rawSql":
+                    "SELECT sum(source_authen), sum(auto_blacklist), sum(acl), sum(ddos), sum(waf), sum(anomaly), sum(parsefail), sum(no_resources) FROM ads_service_%s_drop WHERE $__timeFilter(time) AND service_name='%s'"
+                    % (service_type, service_name),
+                    "format":
+                    "table"
+                }]
+            }
+        }
+    }
+
+    dropTimeWidgetObj = {
+        "name": "filter_time",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "",
+                    "config": BarConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "traffic_drop",
+                    "rawSql":
+                    "select strftime('%H', time) as times, sum(total) from ads_service_"
+                    + service_type +
+                    "_drop WHERE $__timeFilter(time) AND service_name = '" +
+                    service_name + "' group by times",
+                    "format":
+                    "cluster"
+                }]
+            }
+        }
+    }
+
+    cc = ChartsComponent(chartspath=pdfpath)
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": "0.3in",
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans Semibold",
+        setCJKmainfont="Open Sans",
+    )
+
+    doc.header_footer(product_name="Security Status Report for",
+                      report_type="ASF Service \"" + format_str(service_name) +
+                      "\"")
+    doc.newline()
+    doc.split_line()
+    doc.new_line()
+
+    desc = [["Host Name", format_str(fetchHostName())],
+            ["Report Type", "ASF Service Security Status"],
+            ["Statistical Period", from_str + " - " + to_str],
+            ["Service address",
+             fetchServiceAddress(service_name)]]
+
+    doc.one_row_desc(desc)
+    doc.new_line()
+
+    doc.topic("1 Overview", 0, 1)
+    security_class = "Unknown"
+    top5_attack_type = []
+    attack_num = 0
+
+    if througput_num == 0:
+        doc.landscape_navigations([
+            "No traffic has passed this service yet. For the security of your service, it is recommended to use the appliance to defense your service as soon as possible."
+        ])
+        doc.newline()
+        doc.newline()
+    else:
+
+        attackCategoryData = cc.PieGraphWidget(attackCategoryWidgetObj,
+                                               "attack_category")
+
+        severity_list = getServiceSeverity(args, service_name)
+
+        if sum(severity_list[2:6]) == 0:
+            security_class = "Secure"
+        elif sum(severity_list[2:5]) == 0:
+            security_class = "Low Risky"
+        elif sum(severity_list[2:4]) == 0:
+            security_class = "Medium Risky"
+        else:
+            security_class = "High Risky"
+
+        attackTypeData = cc.BarGraphWidget(attackTypeWidgetObj, "attack_type")
+        if 'error' not in attackTypeData['A'].keys():
+            rows = attackTypeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:5]
+            for row in rows:
+                top5_attack_type.append(format_str(row[0]))
+
+        cc.MapGraphWidget(attackRegionWidgetObj, "attack_region")
+        cc.BarGraphWidget(attackTimeWidgetObj, "attack_time")
+
+        waf_num = getPieValue(attackCategoryData, 'Web Attack')
+        ddos_num = getPieValue(attackCategoryData, 'DDoS Attack')
+        http_num = getPieValue(attackCategoryData, 'HTTP Filter')
+
+        attack_num = waf_num + ddos_num + http_num
+        doc.landscape_navigations([
+            "During the evaluation period between %s and %s, the security class of \"%s\" is %s."
+            % (from_str, to_str, format_str(service_name), security_class),
+            "During this period, service \"%s\" has encountered %d attacks or threats, among which there are %d Web attacks, %d DDoS attacks and %d HTTP filter violations. See the following graphs for details."
+            %
+            (format_str(service_name), attack_num, waf_num, ddos_num, http_num)
+        ])
+
+        doc.newline()
+        doc.newline()
+
+        h, w = get_chart_size(os.path.join(pdfpath, "attack_category.png"))
+        chart_path_allocation_margin = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_category.png"),
+            263,
+            int(100 * h / w),
+            100,
+            mini_w=int(100 * h / w))
+        chart_path_allocation_market_value = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_type.png"),
+            263,
+            250,
+            100,
+            mini_w=250)
+
+        doc.table_report(
+            [
+                "Attack/Threat Category Distribution",
+                "Attack/Threat Type Distribution"
+            ], [98, 98],
+            [chart_path_allocation_margin, chart_path_allocation_market_value])
+        doc.newline()
+        doc.newline()
+
+        h, w = get_chart_size(os.path.join(pdfpath, "attack_time.png"))
+        chart_holding_fashion = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_time.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report(["Attack/Threat Time Distribution by Hour"], [98],
+                         [chart_holding_fashion])
+        doc.newline()
+        doc.newline()
+
+        h, w = get_chart_size(os.path.join(pdfpath, "attack_region.png"))
+        chart_holding_fashion = doc.charts_one_column(
+            os.path.join(pdfpath, "attack_region.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report(["Attack/Threat Source Region Distribution"], [98],
+                         [chart_holding_fashion])
+        doc.newline()
+        doc.newline()
+
+    doc.topic("2 Web Attack Analysis", 0, 1)
+    doc.newline()
+
+    wafSeverityData = cc.BarGraphWidget(wafSeverityWidgetObj, "waf_severity")
+    h, w = get_chart_size(os.path.join(pdfpath, "waf_severity.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "waf_severity.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["2.1 Attack Analysis by Severity"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Attack Severity", "Count"]]
+    if 'error' not in wafSeverityData['A'].keys():
+        rows = wafSeverityData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, rows[i][0], rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    wafTypeData = cc.BarGraphWidget(wafTypeWidgetObj, "waf_type")
+    h, w = get_chart_size(os.path.join(pdfpath, "waf_type.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "waf_type.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["2.2 Attack Analysis by Type"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Attack Type", "Count"]]
+    if 'error' not in wafTypeData['A'].keys():
+        rows = wafTypeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    doc.topic2("2.3 Attack Analysis by Source IP")
+    wafIPData = cc.PieGraphWidget(wafIPWidgetObj, "waf_ip")
+    h, w = get_chart_size(os.path.join(pdfpath, "waf_ip.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "waf_ip.png"),
+                                       240,
+                                       240,
+                                       int(240 * w / h),
+                                       isline=False)
+
+    table_data = [["Rank", "Source IP", "Count"]]
+    for i in range(len(wafIPData[0])):
+        if i < 10:
+            table_data.append([i + 1, wafIPData[0][i], wafIPData[1][i]])
+
+    table_cta_profit_source = doc.table_one_column(285,
+                                                   table_data,
+                                                   fontsize="small",
+                                                   fontsize2="footnotesize",
+                                                   row_height=0.9,
+                                                   isline=False)
+
+    doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+    doc.newline()
+    doc.newline()
+
+    wafRegionData = cc.MapGraphWidget(wafRegionWidgetObj, "waf_region")
+    h, w = get_chart_size(os.path.join(pdfpath, "waf_region.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "waf_region.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["2.4 Attack Analysis by Source Region"], [98],
+                     [chart_pfal])
+
+    table_data = [["Rank", "Country/Region", "Count"]]
+    if 'error' not in wafRegionData['A'].keys():
+        rows = wafRegionData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    wafTimeWidgetObj['args']['datasource']['queries'][0][
+        'rawSql'] = "select strftime('%H', time) as times, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '" + service_name + "' group by times"
+    wafTimeData = cc.BarGraphWidget(wafTimeWidgetObj,
+                                    "waf_hour",
+                                    title="Attack Analysis by Hour")
+    h, w = get_chart_size(os.path.join(pdfpath, "waf_hour.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "waf_hour.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["2.5 Attack Analysis by Time"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Hour", "Count"]]
+    if 'error' not in wafTimeData['A'].keys():
+        rows = wafTimeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([i + 1, hour_str, rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    if time_diff >= 30 * 24 * 60 * 60:
+        wafTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%d', time) as times, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '" + service_name + "' group by times"
+        wafTimeData = cc.BarGraphWidget(wafTimeWidgetObj,
+                                        "waf_month",
+                                        title="Attack Analysis by Date")
+        h, w = get_chart_size(os.path.join(pdfpath, "waf_month.png"))
+        chart_pfal = doc.charts_boxplot(os.path.join(pdfpath, "waf_month.png"),
+                                        550, 500, int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Date", "Count"]]
+        if 'error' not in wafTimeData['A'].keys():
+            rows = wafTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, rows[i][0], rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    elif time_diff >= 7 * 24 * 60 * 60:
+        wafTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%w', time) as times, sum(counts) from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '" + service_name + "' group by times"
+        wafTimeData = cc.WeekBarGraphWidget(wafTimeWidgetObj,
+                                            "waf_week",
+                                            title="Attack Analysis by Weekday")
+        h, w = get_chart_size(os.path.join(pdfpath, "waf_week.png"))
+        chart_pfal = doc.charts_boxplot(os.path.join(pdfpath, "waf_week.png"),
+                                        550, 500, int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Weekday", "Count"]]
+        if 'error' not in wafTimeData['A'].keys():
+            rows = wafTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append(
+                    [i + 1, parseWeekDay(rows[i][0]), rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    doc.topic("3 DDoS Attack Analysis", 0, 1)
+    doc.newline()
+
+    ddosSeverityData = cc.BarGraphWidget(ddosSeverityWidgetObj,
+                                         "ddos_severity")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_severity.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "ddos_severity.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["3.1 Attack Analysis by Severity"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Attack Severity", "Count"]]
+    if 'error' not in ddosSeverityData['A'].keys():
+        rows = ddosSeverityData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, rows[i][0], rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    ddosTypeData = cc.BarGraphWidget(ddosTypeWidgetObj, "ddos_type")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_type.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "ddos_type.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["3.2 Attack Analysis by Type"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Attack Type", "Count"]]
+    if 'error' not in ddosTypeData['A'].keys():
+        rows = ddosTypeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    doc.topic2("3.3 Attack Analysis by Source IP")
+    ddosIPData = cc.PieGraphWidget(ddosIPWidgetObj, "ddos_ip")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_ip.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "ddos_ip.png"),
+                                       240,
+                                       240,
+                                       int(240 * w / h),
+                                       isline=False)
+
+    table_data = [["Rank", "Source IP", "Count"]]
+    for i in range(len(ddosIPData[0])):
+        if i < 10:
+            table_data.append([i + 1, ddosIPData[0][i], ddosIPData[1][i]])
+
+    table_cta_profit_source = doc.table_one_column(285,
+                                                   table_data,
+                                                   fontsize="small",
+                                                   fontsize2="footnotesize",
+                                                   row_height=0.9,
+                                                   isline=False)
+
+    doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+    doc.newline()
+    doc.newline()
+
+    ddosRegionData = cc.MapGraphWidget(ddosRegionWidgetObj, "ddos_region")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_region.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "ddos_region.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["3.4 Attack Analysis by Source Region"], [98],
+                     [chart_pfal])
+
+    table_data = [["Rank", "Country/Region", "Count"]]
+    if 'error' not in ddosRegionData['A'].keys():
+        rows = ddosRegionData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    ddosTimeWidgetObj['args']['datasource']['queries'][0][
+        'rawSql'] = "select strftime('%H', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '" + service_name + "' group by times"
+    ddosTimeData = cc.BarGraphWidget(ddosTimeWidgetObj,
+                                     "ddos_hour",
+                                     title="Attack Analysis by Hour")
+    h, w = get_chart_size(os.path.join(pdfpath, "ddos_hour.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "ddos_hour.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["3.5 Attack Analysis by Time"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Hour", "Count"]]
+    if 'error' not in ddosTimeData['A'].keys():
+        rows = ddosTimeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([i + 1, hour_str, rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    if time_diff >= 30 * 24 * 60 * 60:
+        ddosTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%d', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '" + service_name + "' group by times"
+        ddosTimeData = cc.BarGraphWidget(ddosTimeWidgetObj,
+                                         "ddos_month",
+                                         title="Attack Analysis by Date")
+        h, w = get_chart_size(os.path.join(pdfpath, "ddos_month.png"))
+        chart_pfal = doc.charts_boxplot(
+            os.path.join(pdfpath, "ddos_month.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Date", "Count"]]
+        if 'error' not in ddosTimeData['A'].keys():
+            rows = ddosTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, rows[i][0], rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    elif time_diff >= 7 * 24 * 60 * 60:
+        ddosTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%w', time) as times, sum(counts) from asf_global_ddos_attack WHERE $__timeFilter(time) AND srv = '" + service_name + "' group by times"
+        ddosTimeData = cc.WeekBarGraphWidget(
+            ddosTimeWidgetObj, "ddos_week", title="Attack Analysis by Weekday")
+        h, w = get_chart_size(os.path.join(pdfpath, "ddos_week.png"))
+        chart_pfal = doc.charts_boxplot(os.path.join(pdfpath, "ddos_week.png"),
+                                        550, 500, int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Weekday", "Count"]]
+        if 'error' not in ddosTimeData['A'].keys():
+            rows = ddosTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append(
+                    [i + 1, parseWeekDay(rows[i][0]), rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    doc.topic("4 HTTP Filter Violation Analysis", 0, 1)
+    doc.newline()
+
+    filterTypeData = cc.BarGraphWidget(filterTypeWidgetObj, "filter_type")
+    h, w = get_chart_size(os.path.join(pdfpath, "filter_type.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "filter_type.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["4.1 Violation Analysis by Type"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Violation Type", "Count"]]
+    if 'error' not in filterTypeData['A'].keys():
+        rows = filterTypeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, rows[i][0], rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    doc.topic2("4.2 Violation Analysis by Source IP")
+    filterIPData = cc.PieGraphWidget(filterIPWidgetObj, "filter_ip")
+    h, w = get_chart_size(os.path.join(pdfpath, "filter_ip.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "filter_ip.png"),
+                                       240,
+                                       240,
+                                       int(240 * w / h),
+                                       isline=False)
+
+    table_data = [["Rank", "Source IP", "Count"]]
+    for i in range(len(filterIPData[0])):
+        if i < 10:
+            table_data.append([i + 1, filterIPData[0][i], filterIPData[1][i]])
+
+    table_cta_profit_source = doc.table_one_column(285,
+                                                   table_data,
+                                                   fontsize="small",
+                                                   fontsize2="footnotesize",
+                                                   row_height=0.9,
+                                                   isline=False)
+
+    doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+    doc.newline()
+    doc.newline()
+
+    # doc.topic2("4.3 Violation Analysis by Source Region")
+    # filterRegionData = cc.MapGraphWidget(filterRegionWidgetObj, "filter_region")
+    # h, w = get_chart_size(os.path.join(pdfpath, "filter_region.png"))
+    # chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "filter_region.png"), 240, 240, int(240 * w / h), isline=False)
+
+    # table_data = [["Rank", "Country/Region", "Count"]]
+    # if 'error' not in filterRegionData['A'].keys():
+    #     rows = filterRegionData['A']['tables'][0]['rows']
+    #     rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+    #     for i in range(len(rows)):
+    #         table_data.append([i+1, rows[i][0], rows[i][1]])
+
+    # table_cta_profit_source = doc.table_one_column(
+    #     285,
+    #     table_data,
+    #     fontsize="small",
+    #     fontsize2="footnotesize",
+    #     row_height=0.9, isline=False)
+
+    # doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+
+    filterRegionData = cc.MapGraphWidget(filterRegionWidgetObj,
+                                         "filter_region")
+    h, w = get_chart_size(os.path.join(pdfpath, "filter_region.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "filter_region.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["4.3 Violation Analysis by Source Region"], [98],
+                     [chart_pfal])
+
+    table_data = [["Rank", "Country/Region", "Count"]]
+    if 'error' not in filterRegionData['A'].keys():
+        rows = filterRegionData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            table_data.append([i + 1, format_str(rows[i][0]), rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    filterTimeWidgetObj['args']['datasource']['queries'][0][
+        'rawSql'] = "select strftime('%H', time) as times, sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '" + service_name + "' group by times"
+    filterTimeData = cc.BarGraphWidget(filterTimeWidgetObj,
+                                       "filter_hour",
+                                       title="Violation Analysis by Hour")
+    h, w = get_chart_size(os.path.join(pdfpath, "filter_hour.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "filter_hour.png"), 550, 500, int(500 * w / h))
+    doc.table_report(["4.4 Violation Analysis by Time"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Hour", "Count"]]
+    if 'error' not in filterTimeData['A'].keys():
+        rows = filterTimeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([i + 1, hour_str, rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    if time_diff >= 30 * 24 * 60 * 60:
+        filterTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%d', time) as times, sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '" + service_name + "' group by times"
+        filterTimeData = cc.BarGraphWidget(filterTimeWidgetObj,
+                                           "filter_month",
+                                           title="Violation Analysis by Date")
+        h, w = get_chart_size(os.path.join(pdfpath, "filter_month.png"))
+        chart_pfal = doc.charts_boxplot(
+            os.path.join(pdfpath, "filter_month.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Date", "Count"]]
+        if 'error' not in filterTimeData['A'].keys():
+            rows = filterTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, rows[i][0], rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    elif time_diff >= 7 * 24 * 60 * 60:
+        filterTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%w', time) as times, sum(counts) from asf_global_filter WHERE $__timeFilter(time) AND srv = '" + service_name + "' group by times"
+        filterTimeData = cc.WeekBarGraphWidget(
+            filterTimeWidgetObj,
+            "filter_week",
+            title="Violation Analysis by Weekday")
+        h, w = get_chart_size(os.path.join(pdfpath, "filter_week.png"))
+        chart_pfal = doc.charts_boxplot(
+            os.path.join(pdfpath, "filter_week.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Weekday", "Count"]]
+        if 'error' not in filterTimeData['A'].keys():
+            rows = filterTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append(
+                    [i + 1, parseWeekDay(rows[i][0]), rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    doc.topic("5 Traffic Analysis", 0, 1)
+    doc.newline()
+
+    cc.LineGraphWidget(httpThroughputWidgetObj, "http_throughput")
+    h, w = get_chart_size(os.path.join(pdfpath, "http_throughput.png"))
+    chart_pfal = doc.charts_one_column(
+        os.path.join(pdfpath, "http_throughput.png"), 550, 500,
+        int(500 * w / h))
+
+    if service_type == "https":
+        doc.table_report(["5.1 SSL Throughput Analysis"], [98], [chart_pfal])
+        throughput_rawSql = (
+            "select strftime('%H', time) as timef, avg(traffic)/30720.0, max(traffic)/30720.0 from (select time, sum(throughput) as traffic from (SELECT time, ssl_total_bytes_in+ssl_total_bytes_out as throughput FROM ads_service_"
+            + service_type +
+            "_traffic_inbound WHERE $__timeFilter(time) AND service_name = '" +
+            service_name +
+            "' union all SELECT time, ssl_total_bytes_in+ssl_total_bytes_out FROM ads_service_"
+            + service_type +
+            "_traffic_outbound WHERE $__timeFilter(time) AND service_name = '"
+            + service_name + "') group by time) group by timef")
+
+    else:
+        doc.table_report(["5.1 HTTP Throughput Analysis"], [98], [chart_pfal])
+        throughput_rawSql = (
+            "select strftime('%H', time) as timef, avg(traffic)/30720.0, max(traffic)/30720.0 from (select time, sum(throughput) as traffic from (SELECT time, total_bytes_in+total_bytes_out as throughput FROM ads_service_"
+            + service_type +
+            "_traffic_inbound WHERE $__timeFilter(time) AND service_name = '" +
+            service_name +
+            "' union all SELECT time, total_bytes_in+total_bytes_out FROM ads_service_"
+            + service_type +
+            "_traffic_outbound WHERE $__timeFilter(time) AND service_name = '"
+            + service_name + "') group by time) group by timef")
+
+    res = tsdbQuery(
+        json.dumps({
+            "from":
+            args['from'],
+            "to":
+            args['to'],
+            "queries": [{
+                "datasourceId": 3,
+                "type": "traffic_general",
+                "rawSql": throughput_rawSql,
+                "format": "cluster"
+            }]
+        }))
+
+    table_data = [[
+        "Time", "Average Throughput (Kbps)", "Peak Throughput (Kbps)"
+    ]]
+    if 'error' not in res['A'].keys():
+        rows = res['A']['tables'][0]['rows']
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([hour_str, rows[i][1], rows[i][2]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.7)
+    # doc.table_report([""], [80], [table_profit_ability])
+
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.8)
+
+    doc.topic("6 Packet Drop Analysis", 0, 1)
+    doc.newline()
+
+    doc.topic2("6.1 Packet Drop Analysis by Reason")
+
+    if service_type == 'http':
+        dropReasonWidgetObj['args']['option']['chart']['legends'] = [
+            "Source authen", "Dynamic blacklist", "ACL", "DDoS", "WAF",
+            "Anomaly ", "Parse fail", "No enough resource"
+        ]
+        dropReasonWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "SELECT sum(source_authen), sum(auto_blacklist), sum(acl), sum(ddos), sum(waf), sum(anomaly), sum(parsefail), sum(no_resources) FROM ads_service_%s_drop WHERE $__timeFilter(time) AND service_name='%s'" % (
+                service_type, service_name)
+    elif service_type == 'https':
+        dropReasonWidgetObj['args']['option']['chart']['legends'] = [
+            "Source authen", "Dynamic blacklist", "ACL", "DDoS", "WAF",
+            "Anomaly ", "Parse fail", "No enough resource"
+        ]
+        dropReasonWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "SELECT sum(http_source_authen), sum(ssl_auto_blacklist+http_auto_blacklist), sum(http_acl), sum(http_ddos), sum(http_waf), sum(ssl_anomaly+http_anomaly), sum(http_parsefail), sum(ssl_no_resources+http_no_resources) FROM ads_service_%s_drop WHERE $__timeFilter(time) AND service_name='%s'" % (
+                service_type, service_name)
+    elif service_type == 'dns':
+        dropReasonWidgetObj['args']['option']['chart']['legends'] = [
+            "Source authen", "Dynamic blacklist", "ACL", "Anomaly ",
+            "No enough resource"
+        ]
+        dropReasonWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "SELECT sum(source_authen), sum(auto_blacklist), sum(acl), sum(anomaly), sum(no_resources) FROM ads_service_%s_drop WHERE $__timeFilter(time) AND service_name='%s'" % (
+                service_type, service_name)
+
+    dropReasonData = cc.PieGraphWidget(dropReasonWidgetObj, "drop_reason")
+    h, w = get_chart_size(os.path.join(pdfpath, "drop_reason.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath,
+                                                    "drop_reason.png"),
+                                       240,
+                                       240,
+                                       int(240 * w / h),
+                                       isline=False)
+
+    table_data = [["Drop Reason", "Drop Count"]]
+    for i in range(len(dropReasonData[0])):
+        if i < 10:
+            table_data.append([dropReasonData[0][i], dropReasonData[1][i]])
+
+    table_cta_profit_source = doc.table_one_column(285,
+                                                   table_data,
+                                                   fontsize="small",
+                                                   fontsize2="footnotesize",
+                                                   row_height=0.9,
+                                                   isline=False)
+
+    doc.table_one_two_row(chart_pfal, [], table_cta_profit_source, [9, 8])
+    doc.newline()
+    doc.newline()
+
+    dropTimeWidgetObj['args']['datasource']['queries'][0][
+        'rawSql'] = "select strftime('%H', time) as times, sum(total) from ads_service_" + service_type + "_drop WHERE $__timeFilter(time) AND service_name = '" + service_name + "' group by times"
+    dropTimeData = cc.BarGraphWidget(dropTimeWidgetObj,
+                                     "drop_hour",
+                                     title="Packet Drop Analysis by Hour")
+    h, w = get_chart_size(os.path.join(pdfpath, "drop_hour.png"))
+    chart_pfal = doc.charts_one_column(os.path.join(pdfpath, "drop_hour.png"),
+                                       550, 500, int(500 * w / h))
+    doc.table_report(["6.2 Packet Drop Analysis by Time"], [98], [chart_pfal])
+
+    table_data = [["Rank", "Hour", "Count"]]
+    if 'error' not in dropTimeData['A'].keys():
+        rows = dropTimeData['A']['tables'][0]['rows']
+        rows = sorted(rows, key=lambda student: student[1], reverse=True)[0:10]
+        for i in range(len(rows)):
+            hour_str = rows[i][0] + ':00-' + rows[i][0] + ':59'
+            table_data.append([i + 1, hour_str, rows[i][1]])
+    # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+    # doc.table_report([""], [80], [table_profit_ability])
+    doc.long_table(table_data,
+                   fontsize="small",
+                   fontsize2="footnotesize",
+                   isline=False,
+                   row_height=0.9)
+
+    if time_diff >= 30 * 24 * 60 * 60:
+        dropTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%d', time) as times, sum(total) from ads_service_" + service_type + "_drop WHERE $__timeFilter(time) AND service_name = '" + service_name + "' group by times"
+        dropTimeData = cc.BarGraphWidget(dropTimeWidgetObj,
+                                         "drop_month",
+                                         title="Packet Drop Analysis by Date")
+        h, w = get_chart_size(os.path.join(pdfpath, "drop_month.png"))
+        chart_pfal = doc.charts_boxplot(
+            os.path.join(pdfpath, "drop_month.png"), 550, 500,
+            int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Date", "Count"]]
+        if 'error' not in dropTimeData['A'].keys():
+            rows = dropTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append([i + 1, rows[i][0], rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    elif time_diff >= 7 * 24 * 60 * 60:
+        dropTimeWidgetObj['args']['datasource']['queries'][0][
+            'rawSql'] = "select strftime('%w', time) as times, sum(total) from ads_service_" + service_type + "_drop WHERE $__timeFilter(time) AND service_name = '" + service_name + "' group by times"
+        dropTimeData = cc.WeekBarGraphWidget(
+            dropTimeWidgetObj,
+            "drop_week",
+            title="Packet Drop Analysis by Weekday")
+        h, w = get_chart_size(os.path.join(pdfpath, "drop_week.png"))
+        chart_pfal = doc.charts_boxplot(os.path.join(pdfpath, "drop_week.png"),
+                                        550, 500, int(500 * w / h))
+        doc.table_report([""], [98], [chart_pfal])
+
+        table_data = [["Rank", "Weekday", "Count"]]
+        if 'error' not in dropTimeData['A'].keys():
+            rows = dropTimeData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:10]
+            for i in range(len(rows)):
+                table_data.append(
+                    [i + 1, parseWeekDay(rows[i][0]), rows[i][1]])
+        # table_profit_ability = doc.table_one_column(555, table_data, fontsize="small", fontsize2="footnotesize", isline=False, row_height=0.9)
+        # doc.table_report([""], [80], [table_profit_ability])
+        doc.long_table(table_data,
+                       fontsize="small",
+                       fontsize2="footnotesize",
+                       isline=False,
+                       row_height=0.9)
+
+    doc.topic("7 Summary", 0, 1)
+
+    if security_class == "Secure":
+        doc.landscape_navigations([
+            "During the period between %s and %s, the security status of service \"%s\" is \"%s\". You do not need to add additional defense configurations for it temporarily."
+            % (from_str, to_str, format_str(service_name), security_class)
+        ])
+    else:
+
+        top5_source_ip = []
+        sourceIPData = tsdbQuery(
+            json.dumps({
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId":
+                    3,
+                    "type":
+                    "agent_log",
+                    "rawSql":
+                    "select sip, sum(counts) from (select sip, counts from asf_global_ddos_attack WHERE $__timeFilter(time) AND sip != '-' AND srv = '%s' UNION ALL select client_ip, counts from asf_global_waf_attack WHERE $__timeFilter(time) AND match_service = '%s' union all select sip, counts from asf_global_filter WHERE $__timeFilter(time) AND srv = '%s') group by sip"
+                    % (service_name, service_name, service_name),
+                    "format":
+                    "cluster"
+                }]
+            }))
+        if 'error' not in sourceIPData['A'].keys():
+            rows = sourceIPData['A']['tables'][0]['rows']
+            rows = sorted(rows, key=lambda student: student[1],
+                          reverse=True)[0:5]
+            for row in rows:
+                top5_source_ip.append("%s (%s times) " %
+                                      (format_str(row[0]), row[1]))
+
+        navigations = [
+            "During the period between %s and %s, the security status of service \"%s\" is %s."
+            % (from_str, to_str, format_str(service_name), security_class)
+        ]
+
+        navigations_content = "The data show that your service has encounters %s attacks in this period." % (
+            attack_num)
+        if len(top5_attack_type) > 0:
+            navigations_content += "The top 5 attack types are: %s." % (
+                ", ".join(top5_attack_type))
+        if len(top5_source_ip) > 0:
+            navigations_content += "The most suspicious attackers are: %s. It is recommended that you add these IPs into the system blacklist if you have confirmed that they are malicious users." % (
+                ", ".join(top5_source_ip))
+
+        navigations.append(navigations_content)
+        if througput_num != 0:
+            navigations.append(
+                "The system have defended against these attacks and threats. Please keep or strengthen the defense configuration for this service. "
+            )
+        doc.landscape_navigations(navigations)
+
+    pdfname += "_" + parseTimeCondition(
+        args['from'], format_str="%Y%m%d%H%M%S") + "_" + parseTimeCondition(
+            args['to'], format_str="%Y%m%d%H%M%S")
+
+    doc.generate_pdf(pdfpath, pdfname)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/setting.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/setting.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/setting.py	(working copy)
@@ -0,0 +1,15 @@
+from sys_status import sys_status
+from service_status import service_status
+from group_status import group_status
+from pci_dss import pci_dss
+from amp_device import amp_device
+from amp_service import amp_service
+
+router = {
+    "bduhj1gt8741vi2k0q8g": sys_status,
+    "bduhjg0t8741vle2o0h0": service_status,
+    "bduhjhot8741vomvcsj0": group_status,
+    "bduhjhot8741voklscm1": pci_dss,
+    "bduhjhot8741voklscm2": amp_device,
+    "bduhjhot8741voklscm3": amp_service,
+}
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/sys_status.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/sys_status.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/sys_status.py	(working copy)
@@ -0,0 +1,424 @@
+# -*- coding: UTF-8 -*-
+import os
+from module.gen_pdf import GeneratePDF
+from module.gen_chart import ChartsComponent, get_chart_size
+from module.parse_time import parseTimeCondition
+from module.session import fetchHostName, getReportPath, getDeviceName
+from utils import format_str, LineConfig
+
+
+def combineData(data, title):
+    data = data['A']['series'][0]['points']
+    res = [title]
+    period = int(len(data) / 10)
+
+    temp = []
+    j = 0
+
+    for i in range(len(data)):
+        if j >= period:
+
+            peak = max(temp)
+
+            num = 0
+            sum = 0
+            for t in temp:
+                if t is not None:
+                    num += 1
+                    sum += t
+
+            if num == 0:
+                avg = None
+            else:
+                avg = round(sum / num, 2)
+
+            res.append([parseTimeCondition(str(data[i][0])), avg, peak])
+            j = 0
+            temp = []
+        temp.append(data[i][1])
+        j += 1
+    if len(res) > 10:
+        return res[:11]
+    return res
+
+
+def combineData2(data, title1, title2):
+
+    data1 = data['A']['series'][0]['points']
+    data2 = data['A']['series'][1]['points']
+
+    res = [title1, title2]
+    period = int(len(data1) / 10)
+
+    temp = []
+    temp2 = []
+    j = 0
+
+    for i in range(len(data1)):
+        if j >= period:
+
+            peak = max(temp)
+            peak2 = max(temp2)
+
+            num = 0
+            sum = 0
+            for t in temp:
+                if t is not None:
+                    num += 1
+                    sum += t
+
+            if num == 0:
+                avg = None
+            else:
+                avg = round(sum / num, 2)
+
+            num2 = 0
+            sum2 = 0
+            for t in temp2:
+                if t is not None:
+                    num2 += 1
+                    sum2 += t
+
+            if num2 == 0:
+                avg2 = None
+            else:
+                avg2 = round(sum2 / num2, 2)
+
+            res.append(
+                [parseTimeCondition(str(data1[i][0])), avg, peak, avg2, peak2])
+            j = 0
+            temp = []
+            temp2 = []
+        temp.append(data1[i][1])
+        temp2.append(data2[i][1])
+        j += 1
+    if len(res) > 10:
+        return res[:11]
+    return res
+
+
+def sys_status(folderID, pdfname, args):
+    pdfname = pdfname.replace("/", "_")
+    pdfpath = os.path.join(getReportPath(), folderID)
+
+    if not os.path.exists(pdfpath):
+        os.makedirs(pdfpath)
+
+    cpuWidgetObj = {
+        "name": "cpu_usage",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "cpu",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId": 3,
+                    "type": "agent_general",
+                    "rawSql":
+                    "SELECT $__timeGroup(time, $__interval, NULL) AS timef, 100 - avg(usage_idle) FROM cpu WHERE $__timeFilter(time) AND cpu = 'cpu-total' group by timef",
+                    "format": "time_series"
+                }]
+            }
+        }
+    }
+
+    memWidgetObj = {
+        "name": "mem_usage",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "memory",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId": 3,
+                    "type": "agent_general",
+                    "rawSql":
+                    "SELECT $__timeGroup(time, $__interval, NULL) AS timef, avg(used_percent) FROM mem WHERE $__timeFilter(time) group by timef",
+                    "format": "time_series"
+                }]
+            }
+        }
+    }
+
+    throughputWidgetObj = {
+        "name": "network_throughput",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "config": LineConfig,
+                    "name": "Sent"
+                }, {
+                    "config": LineConfig,
+                    "name": "Received"
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId": 3,
+                    "type": "agent_general",
+                    "rawSql":
+                    "select $__timeGroup(time, $__interval, NULL) AS timef, avg(bytes_sent)/1280.0, avg(bytes_recv)/1280.0 from net WHERE $__timeFilter(time) AND interface='all' group by timef",
+                    "format": "time_series"
+                }]
+            }
+        }
+    }
+
+    diskWidgetObj = {
+        "name": "disk_usage",
+        "args": {
+            "option": {
+                "chart": {},
+                "series": [{
+                    "name": "disk",
+                    "config": LineConfig
+                }]
+            },
+            "datasource": {
+                "from":
+                args['from'],
+                "to":
+                args['to'],
+                "queries": [{
+                    "datasourceId": 3,
+                    "type": "agent_general",
+                    "rawSql":
+                    "SELECT $__timeGroup(time, $__interval, NULL) AS timef, avg(used_percent) FROM disk WHERE $__timeFilter(time) group by timef",
+                    "format": "time_series"
+                }]
+            }
+        }
+    }
+
+    cc = ChartsComponent(chartspath=pdfpath)
+
+    cpuData = cc.LineGraphWidget(cpuWidgetObj, "cpu_usage")
+    cpuPath = os.path.join(pdfpath, "cpu_usage.png")
+    cpuTable = combineData(cpuData, ["Time", 'Average', 'Peak'])
+
+    memData = cc.LineGraphWidget(memWidgetObj, "mem_usage")
+    memPath = os.path.join(pdfpath, "mem_usage.png")
+    memTable = combineData(memData, ["Time", 'Average', 'Peak'])
+
+    throughputData = cc.LineGraphWidget(throughputWidgetObj,
+                                        "network_throughput")
+    throughputPath = os.path.join(pdfpath, "network_throughput.png")
+    throughputTable = combineData2(throughputData,
+                                   ["Time", 'Sent', 'Received'],
+                                   ['', 'Average', 'Peak', 'Average', 'Peak'])
+
+    diskData = cc.LineGraphWidget(diskWidgetObj, "disk_usage")
+    diskPath = os.path.join(pdfpath, "disk_usage.png")
+    diskTable = combineData(diskData, ["Time", 'Average', 'Peak'])
+
+    desc_contents = []
+
+    from_str = parseTimeCondition(args['from'])
+    to_str = parseTimeCondition(args['to'])
+
+    for i in range(len(cpuTable)):
+        if i == 0:
+            continue
+
+        if i == len(cpuTable) - 1:
+            to1 = to_str
+        else:
+            to1 = cpuTable[i + 1][0]
+
+        average = cpuTable[i][1]
+        peak = cpuTable[i][2]
+
+        if average is not None and average >= 80:
+            desc_contents.append(
+                "In the period " + cpuTable[i][0] + " to " + to1 +
+                ", the average CPU usage exceeded 80\%, value: " +
+                str(average) + ".")
+        if peak is not None and peak >= 90:
+            desc_contents.append(
+                "In the period " + cpuTable[i][0] + " to " + to1 +
+                ", the peak CPU usage exceeded 90\%, value: " + str(peak) +
+                ".")
+
+    for i in range(len(memTable)):
+        if i == 0:
+            continue
+
+        if i == len(memTable) - 1:
+            to1 = to_str
+        else:
+            to1 = memTable[i + 1][0]
+        average = memTable[i][1]
+        peak = memTable[i][2]
+
+        if average is not None and average >= 80:
+            desc_contents.append(
+                "In the period " + memTable[i][0] + " to " + to1 +
+                ", the average memory usage exceeded 80\%, value: " +
+                str(average) + ".")
+        if peak is not None and peak >= 90:
+            desc_contents.append(
+                "In the period " + memTable[i][0] + " to " + to1 +
+                ", the peak memory usage exceeded 90\%, value: " + str(peak) +
+                ".")
+
+    options = {
+        "paperwidth": 595,
+        "paperheight": 842,
+        "left": 0,
+        "right": 0,
+        "top": 14,
+        "head": "25pt",
+        "bottom": "0.3in",
+        "includeheadfoot": True
+    }
+
+    doc = GeneratePDF(options)
+    doc.create_doc(
+        "fontawesome",
+        "booktabs",
+        "xcolor",
+        "mathspec",
+        setmainfont="Open Sans Semibold",
+        setCJKmainfont="Open Sans",
+    )
+    doc.header_footer(product_name="System Running Status Report",
+                      report_type="")
+    doc.newline()
+    doc.split_line()
+
+    doc.topic("Information", 0, 1)
+
+    desc = [[
+        "Host Name",
+        format_str(fetchHostName()), "Device",
+        format_str(getDeviceName())
+    ], ["From", from_str, "To", to_str],
+            [
+                "Create Time",
+                parseTimeCondition("now"), "Report Type", "Running Status"
+            ]]
+    doc.team_desc(desc)
+
+    doc.newline()
+    doc.topic("CPU Usage (\%)", 0, 1)
+    h, w = get_chart_size(cpuPath)
+    chart_pfal = doc.charts_boxplot(cpuPath, 555, 500, int(500 * w / h))
+    ct_pfal = [chart_pfal]
+    doc.table_report([""], [50], ct_pfal)
+
+    table_pati = doc.table_one_column(555,
+                                      cpuTable,
+                                      fontsize="small",
+                                      fontsize2="footnotesize",
+                                      row_height=1.0)
+    tb_pati = [table_pati]
+    doc.table_report(["CPU Usage (\%)"], [30], tb_pati)
+
+    # second page
+    # doc.newpage()
+    # doc.header_footer(product_name="System Running Status Report",
+    #                   report_type="")
+    # doc.newline()
+    # doc.split_line()
+
+    doc.newline()
+    doc.newline()
+    doc.topic("Memory Usage (\%)", 0, 1)
+    h, w = get_chart_size(memPath)
+    chart_pfal = doc.charts_boxplot(memPath, 555, 500, int(500 * w / h))
+    ct_pfal = [chart_pfal]
+    doc.table_report([""], [50], ct_pfal)
+
+    table_pati = doc.table_one_column(555,
+                                      memTable,
+                                      fontsize="small",
+                                      fontsize2="footnotesize",
+                                      row_height=1.0)
+    tb_pati = [table_pati]
+    doc.table_report(["Memory Usage (\%)"], [30], tb_pati)
+
+    doc.newline()
+    doc.topic("Network Throughput (Kbps)", 0, 1)
+    h, w = get_chart_size(throughputPath)
+    chart_pfal = doc.charts_boxplot(throughputPath, 555, 500, int(500 * w / h))
+    ct_pfal = [chart_pfal]
+    doc.table_report([""], [50], ct_pfal)
+
+    # third page
+    # doc.newpage()
+    # doc.header_footer(product_name="System Running Status Report",
+    #                   report_type="")
+    # doc.newline()
+    # doc.split_line()
+
+    table_pati = doc.table_multi_column_secondEX(555,
+                                                 throughputTable,
+                                                 10,
+                                                 fontsize="small",
+                                                 fontsize2="footnotesize")
+    tb_pati = [table_pati]
+    doc.table_report(["Network Throughput (Kbps)"], [30], tb_pati)
+
+    doc.newline()
+    doc.topic("Disk Usage (\%)", 0, 1)
+    h, w = get_chart_size(diskPath)
+    chart_pfal = doc.charts_boxplot(diskPath, 555, 500, int(500 * w / h))
+    ct_pfal = [chart_pfal]
+    doc.table_report([""], [50], ct_pfal)
+
+    table_pati = doc.table_one_column(555,
+                                      diskTable,
+                                      fontsize="small",
+                                      fontsize2="footnotesize",
+                                      row_height=1.0)
+    tb_pati = [table_pati]
+    doc.table_report(["Disk Usage (\%)"], [30], tb_pati)
+
+    # forth page
+    # doc.newpage()
+    # doc.header_footer(product_name="System Running Status Report",
+    #                   report_type="")
+    # doc.newline()
+    # doc.split_line()
+
+    if len(desc_contents) == 0:
+        desc_contents.append("During the period from " + from_str + " to " +
+                             to_str +
+                             ", the system was running in a healthy status.")
+    else:
+        desc_contents.insert(
+            0, "During the period from " + from_str + " to " + to_str +
+            ", the system encountered the following abnormal conditions:")
+    doc.newline()
+    doc.newline()
+    doc.topic("Conclusion", 0, 1)
+    desc_tmal = doc.description(555, desc_contents)
+    d_tmal = [desc_tmal]
+    doc.table_report([""], [30], d_tmal)
+
+    pdfname += "_" + parseTimeCondition(
+        args['from'], format_str="%Y%m%d%H%M%S") + "_" + parseTimeCondition(
+            args['to'], format_str="%Y%m%d%H%M%S")
+
+    doc.generate_pdf(pdfpath, pdfname)
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/utils.py
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/utils.py	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/reporting/template/utils.py	(working copy)
@@ -0,0 +1,53 @@
+PieConfig = {
+    "is_label_show": False,
+    "is_toolbox_show": False,
+    "label_pos": "center",
+    "label_formatter": "{b}",
+    "label_emphasis_textsize": 15,
+    "label_emphasis_textweight": "bold",
+    "radius": [60, 80],
+    "center": [35, 50],
+    "legend_orient": "vertical",
+    "legend_pos": "right"
+}
+
+BarConfig = {
+    "is_toolbox_show": False,
+    "is_splitline_show": False,
+    "xaxis_interval": 0,
+    "is_label_show": True,
+    "label_pos": "top"
+}
+
+MapConfig = {
+    "maptype": "world",
+    "is_map_symbol_show": False,
+    "is_toolbox_show": False,
+    "is_visualmap": True,
+    "visual_range_color": ['#37A2DA', '#FFDB5C', '#FB7293']
+}
+
+LineConfig = {
+    "is_smooth": True,
+    "tooltip_tragger": "axis",
+    "is_toolbox_show": False,
+    "is_splitline_show": False,
+    "xaxis_type": "time",
+    "yaxis_min": 0,
+    #     "area_opacity": 0.4,
+    "is_label_emphasis": False,
+    "is_symbol_show": False,
+    #     "is_legend_show": False
+}
+
+
+def format_str(str):
+    return str.replace('%', '\%').replace('_', '\_')
+
+
+def getPieValue(data, key):
+    for i in range(len(data[0])):
+        if data[0][i] == key:
+            if data[1][i] is not None:
+                return data[1][i]
+    return 0
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/app.ini
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/app.ini	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/app.ini	(working copy)
@@ -0,0 +1,22 @@
+[default]
+db.engine         = sqlite3
+db.host           = 127.0.0.1
+db.port           = 5432
+db.user           = 
+db.password       = 
+db.database       = /usr/local/share/composer/ui/conf/composer.db
+db.prefix         = 
+db.charset        = utf8
+db.max.idle.conns = 30
+db.max.open.conns = 100
+allow_ips         = 
+app.name          = Composer WebUI Manager
+api.key           = wjb59724bf8534d3cb
+api.secret        = 59e0340f0df438d329cd308210091cd8
+enable_tls        = false
+concurrency.queue = 100
+auth_secret       = bd3ecd073f22e4f95ac18b3bfe5f29dabae45b4d0e9f03dc6de360795b8eaf51
+ca_file           = 
+cert_file         = 
+key_file          = 
+geoip_file        = /usr/local/etc/composer/GeoLite2-City.mmdb
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/server.crt
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/server.crt	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/server.crt	(working copy)
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIJAOUMepl6zwE2MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTgwMjI3MDgyNjQwWhcNMTkwMjI3MDgyNjQwWjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAweMnATNDd8zIgA6hydemQNjg/KweVh97ciQkvr8j2/7iG1Kp3CF79SJD
+hJuXa58fSuaNvyh6bDv1cdBgBxeBRrH0WV7XDQJVUT4p5LySy0L0uk9hgZXuPHkR
+xexegKASGjObxBhaOAkHPk4RqZyQb/7Ol0Wa0RBu1+AaorQ8ETUWN6P0rKsjLBOl
+zjrRvyuV/K+kGjyfxpn1P/epHwzYhlQS4esfAcsb3INh+yNeZJkn+zhVo9N4mVit
+ELBMHItEAejjyAWfcgLK5QMzMGYwBGpJz/lWEGlN3ADHCAGHt4MctcYe8x4ThlFE
+f/fCIhZQ3d8UX3ROu0Z+3crAfyIiqQIDAQABo1AwTjAdBgNVHQ4EFgQUC5caPmCU
+zdbWT3h1qlA+j1g3jHIwHwYDVR0jBBgwFoAUC5caPmCUzdbWT3h1qlA+j1g3jHIw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAUjSky9ucGJ17qUMPbOSN
+G6GVvg+5MwLXqnfzaPhhYESuofjbXb8+rb5bQGAq1rSVOah07Jae6L0rDuslR5sl
+vLul1zfAx1D+pFAKyjRgE5ee8fLDTNvnarjPvjVlYXxXYIDv15mbcAFES8IvFRUQ
+r47a5y9H35O5zLWahA+EOR1jHIL8WyjlVa2cMF4pNNVIO/kWqH59hkIdDmgdbC1x
+xVonvQwwMuAt2GQtt9EW3SRzLUzachZPZ6BtgXhFhexxX2O5t7r4O++w1ufnWhHl
+dGs1BK+du1kIWFw/kaxPDkIA0nwb8j+0SFz3liqQ3a+iekXST3FcR9WtfPk8+sKD
+8A==
+-----END CERTIFICATE-----
Index: /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/server.key
===================================================================
--- /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/server.key	(revision 0)
+++ /branches/amp_3_7/src/webui/webui/htdocs/new/src/cm/report/ui/conf/server.key	(working copy)
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAweMnATNDd8zIgA6hydemQNjg/KweVh97ciQkvr8j2/7iG1Kp
+3CF79SJDhJuXa58fSuaNvyh6bDv1cdBgBxeBRrH0WV7XDQJVUT4p5LySy0L0uk9h
+gZXuPHkRxexegKASGjObxBhaOAkHPk4RqZyQb/7Ol0Wa0RBu1+AaorQ8ETUWN6P0
+rKsjLBOlzjrRvyuV/K+kGjyfxpn1P/epHwzYhlQS4esfAcsb3INh+yNeZJkn+zhV
+o9N4mVitELBMHItEAejjyAWfcgLK5QMzMGYwBGpJz/lWEGlN3ADHCAGHt4MctcYe
+8x4ThlFEf/fCIhZQ3d8UX3ROu0Z+3crAfyIiqQIDAQABAoIBAGepKe5zWQwRGdWV
+fRysRn//NHMDFwkWtep1touhJ+v0HzFaheRipqKOGikpAtEQdyuVjo14d9OsTvL1
+5JGGGKESfcDWewXCjJjuMnnP9G/mMW/3BvvAjGoalM0MLg55BpSpqQsztfClqxC9
+rqXPRk4Knqu0FCzYq1qRv8vjrwXHO+nzUKyKGp/EvwCBqr6radtUiqy9V9FCnQOt
+2ZBBUTV3DPAuuE4kZTlZT2KReDKdBDFO6u29PGsYV0A9f1rQpl1i6ye8qzLVV4Ft
+9GPPF8ESXpCXGbpiFUlijL14sdblF68DiIT6uDk9Y7TRFvKHBxH8v/yh9jKFBe8B
+dRonIS0CgYEA9YMna6tpnZEJCfoPjCin+bUXzxXY3E81o7XQnPGkKA7xkbzAaMZb
+jUEGAt9OuAZPkuvMIK9FO72f60FCD8wNeMo7KNhOWoIBGQzEIraLUZNnFW/p7q5u
+Dn/podwTnQbOuGyD01BSm1v2wbMXC84eJPuf8dBSEYcicNPUNfULSF8CgYEAyitx
+hS9So5VrmXWyGPtB40o6Sp9CBumMF1Y20dvlKSS+OuyTcR33CD/O7pSStNG68iF/
+TarMg5+JExvaztCgYxjszNqDxqtH9JaIEZS5MrWWS2eNKYSg6NClgwazjZGyp+z5
+NUwbC+OAW27sGM9xhalcvzqybzQSzxxi4/gvEfcCgYBs/ap0bAZZAtgGa9KXID1h
+53kIX+SD+U4QvVg9NDDx76BiWG76lIR0MteeUtA5dePBj5hxMh4EJWxnHfNb2/Rn
+GTAmM9Ck8W3XVwmDd5JlxpBOvf4WDa2iFjr7th2m6iy/Rr1HBDOH8M2ctAqZHQnY
+1TPuP9MPIPSzLfbZdU1q9QKBgQC/VS4ypf7H4nna2pCbI+/PdEiGpwKOGCoFTArF
+wh63OZbvnUZNH9bTb9Af62yMxJDw5tLcZnD3gNzxwMLsSHYCU2yI06UzOJb43B4a
+xW4gl8qNworOaD8BF7YMsyLrMKCsXJHd5xERx1WLMwcu0+TUYtzr/lkw9U93w52z
+swaZMQKBgQCkH9/SabGs9AwQl7oCX0uoJh4OiMWItLfQ6htlnkDEHgrWOLbH0Pd9
+j/mHI8x0O2sSe/h420eM/KtSJlPfOpBWpH7Q2fN0KAcKHT88Q2aXrLw+eT/j7/J/
+rGI6A9zgXP0QoJkZXdAt5mGNq3vOqkkEyt/WYk84CoN7f94S4V5YJA==
+-----END RSA PRIVATE KEY-----
