from docx.shared import Mm
from docx.shared import Pt
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import RGBColor, Inches
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml

##
#cloudos2.0 api端口为9000
#cloudos3.0 api端口为8000

# 创建表格,默认行距为1cm
def createTable(document, row, col):
    # table = document.add_table(row, col, style='Medium Grid 1 Accent 1')
    table = document.add_table(row, col, style='Table Grid')
    table.style.font.name = u'宋体'
    table.style.font.size = Pt(11)
    for i in table.rows[0].cells:
        shading_elm_2 = parse_xml(r'<w:shd {} w:fill="B0C4DE"/>'.format(nsdecls('w')))
        i._tc.get_or_add_tcPr().append(shading_elm_2)
        del shading_elm_2
    # table = document.add_table(row, col, style='Medium Shading 2 Accent 1')
    for i in table.rows:
        i.height = Mm(10)
    return table

# 合并单元格,返回单元格地址
def mergeCell(table, beginRow, beginCol, endRow, endCol):
    c1 = table.cell(beginRow, beginCol)
    c2 = table.cell(endRow, endCol)
    return c1.merge(c2)

# document = openDocument(r'cas.docx')
# serverList为参数列表，包含6个参数，从参数0-6分别为：服务器型号、服务器规格、CAS版本、CVM部署方式、
# S1020V版本、是否使用临时license
def casBasicDocument(document, list1):
    h1 = document.add_heading('CAS平台巡检结果')
    h1.paragraph_format.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    h2 = document.add_heading('1.CAS平台基本信息')
    t1 = createTable(document, 7, 2)

    # 初始化表格
    t1.cell(0, 0).text = "巡检项"
    t1.cell(0, 1).text = "参数"
    t1.cell(1, 0).text = "服务器型号"
    t1.cell(2, 0).text = "服务格器规"
    t1.cell(3, 0).text = "CAS版本号"
    t1.cell(4, 0).text = "CVM部署方式"
    t1.cell(5, 0).text = "S1020V版本号"
    t1.cell(6, 0).text = "是否有使用临时license"
    # 参数赋值
    for i in range(6):
        run = t1.cell(i + 1, 1).paragraphs[0].add_run(list1[i])
        # run.font.name = '宋体'
        # run.font.size = Pt(11)
    return

# li1,li2为参数列表，list1为巡检结果，list2为巡检结果说明
# list1
def clusterDocument(document, list1, list2):
    h1 = document.add_heading('2.集群巡检')
    count = 0
    text = ''
    for i in list2:
      if i:
          count += 1
    p1 = document.add_paragraph()
    run1 = p1.add_run("巡检小结：")
    run1.font.name = u'宋体'
    run1.font.size = Pt(11)
    text = "对集群虚拟化进行巡检，巡检异常项数：" + (str)(count) + "；" + "正常项数：" + (str)(len(list2) - count)
    p2 = document.add_paragraph()
    p2.paragraph_format.first_line_indent = Inches(0.3)
    run2 = p2.add_run(text)
    run2.font.name = u'宋体'
    run2.font.size = Pt(11)

    t1 = createTable(document, 7, 4)
    # 初始化表格
    t1.cell(0, 0).text = "检查内容"
    t1.cell(0, 1).text = "检查方法"
    t1.cell(0, 2).text = "检查结果"
    t1.cell(0, 3).text = "说明"
    t1.cell(1, 0).text = "集群高可靠性（HA）功能：查看集群的高可靠性（HA）功能是否正常开启"
    t1.cell(1, 1).text = "在<云资源>/<主机池>/<集群>的“高可靠性”页面检查是否选择了“启用HA”"
    t1.cell(2, 0).text = "集群动态资源调度（DRS）功能：查看集群的动态" \
                         "资源调度（DRS）功能是否正常开启"
    t1.cell(2, 1).text = "在<云资源>/<主机池>/<集群>的“动态资源调度”" \
                         "页面检查是否选择了“开启动态资源调度”"
    t1.cell(3, 0).text = "集群下虚拟交换机分配：查" \
                         "看集群下虚拟交换机的分配情况。"
    t1.cell(3, 1).text = "在<云资源>/<主机池>/<主机>的“虚拟交" \
                         "换机”页面检查集群下的所有主机是否都" \
                         "有相同名称的虚拟交换机"
    t1.cell(4, 0).text = "集群下共享存储分配：" \
                         "查看集群下共享存储的分配情况"
    t1.cell(4, 1).text = "在<云资源>/<主机池>/<集群>的“存储”" \
                         "页面检查集群下的主机是否都分配了相同的共享存储"
    t1.cell(5, 0).text = "集群下共享存储使用率：查看集群下共享存" \
                         "储的实际使用情况，实际使用率超过70%标记为不" \
                         "正常。实际使用率超过90%，标记为平台重大风险项。"
    t1.cell(5, 1).text = "在<云资源>/<主机池>/<集群>的“存储”页面检" \
                         "查集群下的共享存储可用容量"
    t1.cell(6, 0).text = "集群高可靠性生效最小节点数：查看集群中正常运行的主机数量不少于“HA生效最小节点数”"
    t1.cell(6, 1).text = "在<云资源>/<主机池>/<集群>的“高可靠性”页面检查“HA生效最小节点数”和集群内正常运行的主机数量"

    t1.columns[2].width = Mm(20)
    # 参数赋值
    for i in range(6):
        if not list2[i]:
            t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
        else:
            run = t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
            run.font.color.rgb = RGBColor(255, 0, 0)
            t1.cell(i + 1, 3).paragraphs[0].add_run(list2[i])
    return

def hostDocument(document, list1, list2):
    h1 = document.add_heading('3.主机巡检')
    count = 0
    text = ''
    for i in list2:
      if i:
          count += 1
    p1 = document.add_paragraph()
    run1 = p1.add_run("巡检小结：")
    run1.font.name = u'宋体'
    run1.font.size = Pt(11)
    text = "对主机CVK进行巡检，巡检异常项数：" + (str)(count) + "；" + "正常项数：" + (str)(len(list2) - count)
    p2 = document.add_paragraph()
    p2.paragraph_format.first_line_indent = Inches(0.3)
    run2 = p2.add_run(text)
    run2.font.name = u'宋体'
    run2.font.size = Pt(11)
    t1 = createTable(document, 8, 4)
    # 初始化表格
    t1.cell(0, 0).text = "检查内容"
    t1.cell(0, 1).text = "检查方法"
    t1.cell(0, 2).text = "检查结果"
    t1.cell(0, 3).text = "说明"
    t1.cell(1, 0).text = "*主机状态：\n*查看所有主机的运行状态。"
    t1.cell(1, 1).text = "在<云资源>的“主机”页面检查所有主" \
                         "机的运行状态是否显示“正常”"
    t1.cell(2, 0).text = "主机CPU占用率：查看所有主机CPU占用率，不超过80%"
    t1.cell(2, 1).text = "在<云资源>的“主机”页面检查所有主机的CPU占用率是否正常。"
    t1.cell(3, 0).text = "主机内存占用率：查看所有主机内存占用率，不超过80%。"
    t1.cell(3, 1).text = "在<云资源>的“主机”页面检查所有主机的内存占用率是否正常。"
    t1.cell(4, 0).text = "主机的磁盘和分区占用率：查看主机的磁盘和分区占用率，各个分区的占用率不超过80%。"
    t1.cell(4, 1).text = "在<云资源>/<主机池>/<集群>/<主机>的“性能监控”页面，查看“磁盘利用率”和“分区利用率”"
    t1.cell(5, 0).text = "主机的存储池：查看主机的存储池资源是否正常。\n*状态：活动"
    t1.cell(5, 1).text = "在<云资源>/<主机池>/<集群>/<主机>的“存储”页面，查看状态是否为“活动”，是否有足够的存储资源"
    t1.cell(6, 0).text = "主机的虚拟交换机：查看主机的虚拟交换机池资源是否正常。\n*状态：活动"
    t1.cell(6, 1).text = "在<云资源>/<主机池>/<集群>/<主机>的“虚拟交换机”页面，查看状态是否为“活动”，并且仅配置一个网关"
    t1.cell(7, 0).text = "主机的物理网卡：查看主机的物理网卡是否正常。" \
                         "\n*状态：活动\n*速率：与物理网卡实际速率保持一致" \
                         "\n*工作模式：full"
    t1.cell(7, 1).text = "在<云资源>/<主机池>/<集群>/<主机>的“物理网卡”" \
                         "页面，查看“状态”、“速率”以及“工作模式”是否正常。"

    # t1.cell(8, 0).text = "主机的FC HBA卡状态（可选）：查看主机的FC HBA卡是否" \
    #                      "正常。\n*状态：活动\n*速率：与物理FC HBA卡实际速率保持一致"
    # t1.cell(8, 1).text = "在<云资源>/<主机池>/<集群>/<主机>的“FC HBA”" \
    #                      "页面，查看“状态”和“速率”是否正常。"

    # 参数赋值
    shading_elm_1 = parse_xml(r'<w:shd {} w:fill="FF0000"/>'.format(nsdecls('w')))
    for i in range(7):
        if not list2[i]:
            t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
        else:
            run = t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
            run.font.color.rgb = RGBColor(255, 0, 0)
            t1.cell(i + 1, 3).paragraphs[0].add_run(list2[i])
    return

def vmDocument(document, list1, list2):
    h1 = document.add_heading('4.虚拟机巡检')
    count = 0
    text = ''
    for i in list2:
        if i:
            count += 1
    p1 = document.add_paragraph()
    run1 = p1.add_run("巡检小结：")
    run1.font.name = u'宋体'
    run1.font.size = Pt(11)
    text = "对主机虚拟机进行巡检，巡检异常项数：" + (str)(count) + "；" + "正常项数：" + (str)(len(list2) - count)
    p2 = document.add_paragraph()
    p2.paragraph_format.first_line_indent = Inches(0.3)
    run2 = p2.add_run(text)
    run2.font.name = u'宋体'
    run2.font.size = Pt(11)
    t1 = createTable(document, 8, 4)
    # 初始化表格
    t1.cell(0, 0).text = "检查内容"
    t1.cell(0, 1).text = "检查方法"
    t1.cell(0, 2).text = "检查结果"
    t1.cell(0, 3).text = "说明"
    t1.cell(1, 0).text = "*虚拟机状态：\n*查看所有虚拟机的运行状态"
    t1.cell(1, 1).text = "在<云资源>的“虚拟机”页面检查所有虚拟机的运行状态。"
    t1.cell(2, 0).text = "虚拟机CPU占用率：查看所有虚拟机CPU占用率，不超过80%"
    t1.cell(2, 1).text = "在<云资源>的“虚拟机”页面检查所有主机的CPU占用率是否正常。"
    t1.cell(3, 0).text = "虚拟机内存占用率：查看所有虚拟机内存占用率，不超过80%。"
    t1.cell(3, 1).text = "在<云资源>的“虚拟机”页面检查所有虚拟机的内存占用率是否正常。"
    t1.cell(4, 0).text = "虚拟机的CAS Tools：查看虚拟机的CAS Tools工具是否正常运行。"
    t1.cell(4, 1).text = "在<云资源>/<主机池>/<集群>/<主机>/<虚拟机>的“概要”页面，查看“CAS Tools”是否为运行状态"
    t1.cell(5, 0).text = "虚拟机的磁盘和分区占用率：查看虚拟机的磁盘和分区占用率，各个分区的占用率不超过80%。"
    t1.cell(5, 1).text = "在<云资源>/<主机池>/<集群>/<主机>/<虚拟机>的“性能监控”页面，查看“磁盘利用率”和“分区利用率”"
    t1.cell(6, 0).text = "虚拟机的磁盘类型（大云可选）：查看虚拟机的磁盘信息。\n" \
                         "*设备对象：virtio磁盘 XXX\n" \
                         "*源路径：共享存储路径\n" \
                         "*缓存方式：建议使用“directsync”\n" \
                         "*存储格式：建议使用“智能”"
    t1.cell(6, 1).text = "在<云资源>/<主机池>/<集群>/<主机>/<虚拟机>的“修改虚拟机”对话框，查看“总线类型”和“存储卷路径”等"
    t1.cell(7, 0).text = "拟机的网卡（大云可选）：" \
                         "查看虚拟机的网卡信息。\n" \
                         "*设备型号：virtio网卡\n" \
                         "*内核加速：勾选"
    t1.cell(7, 1).text = "在<云资源>/<主机池>/<集群>/<主机>/<虚拟机>的“修改虚拟机”对话框，查看网卡类型。"
    # 参数赋值
    for i in range(7):
        if not list2[i]:
            t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
        else:
            run = t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
            run.font.color.rgb = RGBColor(255, 0, 0)
            t1.cell(i + 1, 3).paragraphs[0].add_run(list2[i])
    return

def systemHaDocument(document, list1, list2):
    h1 = document.add_heading('5.系统可靠性巡检')
    count = 0
    text = ''
    for i in list2:
        if i:
            count += 1
    p1 = document.add_paragraph()
    run1 = p1.add_run("巡检小结：")
    run1.font.name = u'宋体'
    run1.font.size = Pt(11)
    text = "对系统可靠性进行巡检，巡检异常项数：" + (str)(count) + "；" + "正常项数：" + (str)(len(list2) - count)
    p2 = document.add_paragraph()
    p2.paragraph_format.first_line_indent = Inches(0.3)
    run2 = p2.add_run(text)
    run2.font.name = u'宋体'
    run2.font.size = Pt(11)
    t1 = createTable(document, 5, 4)
    t1.style.font.name = '微软雅黑'
    t1.style.font.size = Pt(9)
    # 初始化表格
    t1.cell(0, 0).text = "检查内容"
    t1.cell(0, 1).text = "检查方法"
    t1.cell(0, 2).text = "检查结果"
    t1.cell(0, 3).text = "说明"
    t1.cell(1, 0).text = "链路冗余：查看系统的链路冗余情况。"
    t1.cell(1, 1).text = "在<云资源>/<主机池>/<集群>/<主机>/<虚拟交换机>页面，检查各个虚拟交换机是否进行了链路冗余（动态或者静态聚合）"
    t1.cell(2, 0).text = "CVM配置备份：查看CVM配置的备份情况。用户CVM主机故障时的系统配置恢复。"
    t1.cell(2, 1).text = "在<系统管理>/<安全管理>的“CVM备份配置”页面，确认已启用了定时备份功能，推荐备份到远端目录。"
    t1.cell(3, 0).text = "CVM双机热备状态检查：检查CAS的CVM双机热备状态是否正常。"
    t1.cell(3, 1).text = "在CVM双机热备环境中，随意登录CVM主机后台执行“crm status”检查双机热备状态。"
    t1.cell(4, 0).text = "虚拟机的备份：检查重要虚拟机是否已经开启备份功能。"
    t1.cell(4, 1).text = "检查运行客户重要业务的虚拟机是否开启了定时备份功能。"
    # 参数赋值
    for i in range(4):
        if not list2[i]:
            t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
        else:
            run = t1.cell(i + 1, 2).paragraphs[0].add_run(list1[i])
            run.font.color.rgb = RGBColor(255, 0, 0)
            t1.cell(i + 1, 3).paragraphs[0].add_run(list2[i])
    return

# cvm平台信息巡检
def cvmCheck(document, casInfo):
    list1 = []
    list1.append(casInfo['productVersion'])
    list1.append(casInfo['deviceDmide'])
    list1.append(casInfo['casVersion'])
    list1.append(casInfo['installType'])
    list1.append(casInfo['ovsVersion'])
    list1.append(casInfo['licenseInfo'])
    casBasicDocument(document, list1)
    del list1
    return

##################
# 集群巡检        #
##################
def clusterCheck(document, casInfo):
    list1 = []
    list2 = ['' for n in range(7)]

    # 集群是否开启HA和DRS
    tempHa = ''
    tempLB = ''
    for i in casInfo['clusterInfo']:
        if i['enableHA'] == '0':
            list2[0] += "集群" + i['name'] + " HA未开启\n"
        if i['enableLB'] == '0':
            list2[1] = "集群" + i['name'] + " DRS未开启\n"

    # 集群下主机虚拟交换机部署是否合规
    dict1 = dict()
    for i in casInfo['clusterInfo']:
        dict1[i['name']] = list()
        for j in i['cvkInfo']:
            if j['status'] == '1':
                for k in j['vswitch']:
                    if not k['name'] in dict1[i['name']]:
                        dict1[i['name']].append(k['name'])
    for i in casInfo['clusterInfo']:
        if len(dict1[i['name']]) != 3:
            list2[2] += "集群" + i['name'] + "下交换机的部署不合规\n"

    # cvk共享存储池部署是否一致
    dict1 = {}  # 存储集群下的所有共享存储池
    dict2 = {}  # 存储主机下的共享存储池
    for i in casInfo['clusterInfo']:
        dict1[i['name']] = set()
        for j in i['cvkInfo']:
            dict2[j['name']] = set()
            if j['status'] == '1':
                for k in j['sharePool'] :
                    dict1[i['name']].add(k['name'])
                    dict2[j['name']].add(k['name'])

        for m in i['cvkInfo']:
            if m['status'] == '1':
                if dict1[i['name']] != dict2[m['name']]:
                    list2[3] += "集群" + i['name'] + "下主机" + m['name'] + "共享存储池与集群不一致"
    del dict1, dict2

    # 共享存储利用率：
    for i in casInfo['clusterInfo']:
        li1 = list()
        for j in i['cvkInfo']:
            if j['status'] == '1':
                for k in j['sharePool']:
                    if not k in li1:
                        li1.append(k)
        for h in li1:
            if h['rate'] > 0.8:
                list2[4] = "集群" + i['name'] + "下共享存储池" + h['name'] + "利用率超过80%达到" + str(h['rate'])
        del li1

    # 集群最小主机节点
    for i in casInfo['clusterInfo']:
        if i['enableHA'] == '0':
            list2[5] = "集群未开启高可靠"
        else:
            if (int)(i['HaMinHost']) > len(i['cvkInfo']):
                list2[5] = "Ha最小节点数小正常运行主机数"

    for i in list2:
        if not i:
            list1.append("正常")
        else:
            list1.append("异常")

    clusterDocument(document, list1, list2)
    del list1, list2
    return

#######################################
# 主机巡检                            #
#                                     #
########################################
def cvkCheck(document, casInfo):
    list1 = []
    list2 = ['' for n in range(7)]
    dict1 = {}
    dict2 = {}
    dict3 = {}
    dict4 = {}
    for i in casInfo['clusterInfo']:
        for j in i['cvkInfo']:
            dict1[j['name']] = ''
            dict2[j['name']] = ''
            dict3[j['name']] = ''
            dict4[j['name']] = ''
            # 主机状态检测
            if j['status'] != '1':
                if not list2[0]:
                    list2[0] += "状态异常主机如下" + j['name'] + '\n'
                else:
                    list2[0] += j['name'] + '\n'
            else:
                # 主机cpu利用率
                if j['cpuRate'] > 80:
                    if not list2[1]:
                        list2[1] += "cpu利用率超过80%主机如下：" + j['name'] + '\n'
                    else:
                        list2[1] += j['name'] + '\n'

                # 主机内存利用率
                if j['memRate'] > 80:
                    if not list2[2]:
                        list2[2] += "内存利用率超过80%主机如下：" + j['name'] + '\n'
                    else:
                        list2[2] += j['name'] + '\n'

                # 主机磁盘利用率
                for k in j['diskRate']:
                    if (float)(k['usage']) > 80:
                        if not dict1[j['name']]:
                            dict1[j['name']] += "\n主机" + j["name"] + "磁盘利用率查过80%的磁盘如下：" + k["name"]
                        else:
                            dict1[j['name']] += ("、" + k["name"])

                # 主机存储池状态：
                for m in j['storagePool']:
                    if m['status'] != '1':
                        if not dict2[j['name']]:
                            dict2[j['name']] = "\n主机" + j['name'] + "状态异常磁盘如下：" + m['name']
                        else:
                            dict2[j['name']] += ("、" + m['name'])

                # 虚拟交换机状态
                for k in j['vswitch']:
                    if k['status'] != '1':
                        if not dict3[j['name']]:
                            dict3[j['name']] = "\n主机" + j['name'] + "状态异常虚拟交换机如下：" + k['name']
                        else:
                            dict3[j['name']] += ("、" + k['name'])

                #网卡状态
                for k in j['network']:
                    if k['status'] != '1':
                        if not dict4[j['name']]:
                            dict4[j['name']] = "\n主机" + j['name'] + "状态异常网卡如下：" + k['name']
                        else:
                            dict4[j['name']] += ("、" + k['name'])

    for h in dict1.values():
        list2[3] += h

    for h in dict2.values():
        list2[4] += h

    for h in dict3.values():
        list2[5] += h

    for h in dict4.values():
        list2[6] += h
    del dict1, dict2, dict3, dict4
    # 主机巡检结果写入docx
    for i in list2:
        if not i:
            list1.append("正常")
        else:
            list1.append("异常")
    hostDocument(document, list1, list2)
    del list1, list2
    return

#######################################
# 虚拟机巡检                           #
########################################

def vmCheck(document, casInfo):
    list1 = []
    list2 = ['' for n in range(7)]
    for i in casInfo['clusterInfo']:
        for j in i['cvkInfo']:
            dict1 = {}
            dict2 = {}
            if j['status'] == '1':
                for k in j['vmInfo']:
                    # print(k)
                    # 虚拟机状态
                    if k['status'] != 'running' and k['status'] != 'shutOff':
                        if not list2[0]:
                            list2[0] = "状态异常虚拟机如下：" + k['name']
                        else:
                            list2[0] += '、' + k['name']
                    else:
                        if k['status'] == 'running':
                        # 虚拟机cpu利用率是否超过80%
                            if k['cpuReate'] > 80:
                                if not list2[1]:
                                    list2[1] = "cpu利用率超过80%虚拟机如下：" + k['name']
                                else:
                                    list2[1] += '、' + k['name']

                            # 虚拟机内存利用率是否超过80%
                            if k['memRate'] > 80:
                                if not list2[2]:
                                    list2[2] = "内存利用率超过80%虚拟机如下：" + k['name']
                                else:
                                    list2[2] += '、' + k['name']

                            # 虚拟机castool状态异常
                            if k['castoolsStatus'] != '1':
                                if not list2[3]:
                                    list2[3] = "castool状态虚拟机如下：" + k['name']
                                else:
                                    list2[3] += '、' + k['name']

                            # 虚拟机磁盘分区巡检
                            tmp = ''
                            for m in k['diskRate']:
                                if m['usage'] > 80:
                                    if not tmp:
                                        tmp = "\n虚拟机" + k['name'] + '磁盘利用率超过80%的磁盘如下：' + m['name']
                                    else:
                                        tmp += '、' + m['name']
                            list2[4] += tmp
                            del tmp

                            # 虚拟机磁盘巡检
                            dict1[k['name']] = ''
                            for n in k['vmdisk']:
                                tmp = n['path'].split('/')
                                path = '/' + tmp[1] + '/' + tmp[2]
                                bool1 = False
                                for m in j['sharePool']:
                                    if path == m['path']:
                                        bool1 = True
                                if not bool1:
                                    if not dict1[k['name']]:
                                        dict1[k['name']] = "\n虚拟机" + k['name'] + "磁盘" + n['name'] + '使用了非共享存储池'
                                    else:
                                        dict1[k['name']] += "磁盘" + n['name'] + '使用了非共享存储池'
                                if n['format'] != 'qcow2':
                                    if not dict1[k['name']]:
                                        dict1[k['name']] = "\n虚拟机" + k['name'] + "磁盘" + n['name'] + '格式错误'
                                    else:
                                        dict1[k['name']] += "磁盘" + n['name'] + '格式错误'
                                if n['cacheType'] != 'directsync':
                                    if not dict1[k['name']]:
                                        dict1[k['name']] = "\n虚拟机" + k['name'] + "磁盘" + n['name'] + '缓存方式错误'
                                    else:
                                        dict1[k['name']] += "磁盘" + n['name'] + '缓存方式错误'
                            list2[5] += dict1[k['name']]

                            # 虚拟机网卡巡检
                            dict2[k['name']] = ''
                            for m in k['vmNetwork']:
                                if m['mode'] != 'virtio':
                                    if not dict2[k['name']]:
                                        dict2[k['name']] = '\n虚拟机' + k['name'] + '网卡' + m['name'] + '模式错误'
                                    else:
                                        dict2[k['name']] = '网卡' + m['name'] + '模式错误'
                                if m['KernelAccelerated'] != '1':
                                    if not dict2[k['name']]:
                                        dict2[k['name']] = '\n虚拟机' + k['name'] + '网卡' + m['name'] + '未开启内核加速'
                                    else:
                                        dict2[k['name']] = '网卡' + m['name'] + '未开启内核加速'
                            list2[6] += dict2[k['name']]
            del dict1, dict2

    for i in list2:
        if not i:
            list1.append("正常")
        else:
            list1.append("异常")
    vmDocument(document, list1, list2)
    del list1, list2
    return

####################
# cvm可靠性巡检
####################
def cvmHaCheck(document, casInfo):
    list1 = []
    list2 = ['' for n in range(4)]

    # 虚拟交换机的是否配置冗余链路

    # cvm是否开启备份策略
    if casInfo['BackupEnable'] != '1':
        list2[1] = 'cvm未开启备份策略'
    # cvm是否开启HA高可靠
    if not casInfo['HA']:
        list2[2] = '未开启HA高可靠'
    # 检查虚拟机是否配置高可靠
    if casInfo['vmBackPolicy'] == 'NONE':
        list2[3] = '未配置虚拟机备份'
    else:
        for i in casInfo['vmBackPolicy']:
            if i['state'] != '1':
                if not list2[3]:
                    list2[3] = '状态异常备份策略如下：' + i['name']
                else:
                    list2[3] += '、' + i['name']
    for i in list2:
        if not i:
            list1.append("正常")
        else:
            list1.append("异常")
    systemHaDocument(document, list1, list2)
    return


import boto3
import os
import requests #Import module into this directory -- pip install requests -t ./
from requests.structures import CaseInsensitiveDict
import json
cloudwatch = boto3.client('cloudwatch')
def lambda_handler(event, context):
    REGION = os.environ['AWS_REGION']
    print(REGION)
    url = "https://reqbin.com/echo/get/json"
    headers = CaseInsensitiveDict()
    headers["Accept"] = "application/json"
    resp = requests.get(url, headers=headers)
    data = resp.json()
    if data['success'] == 'true':
        metricValue = 1
    else:
        metricValue = 0
    print (metricValue)
    cloudwatch.put_metric_data(
        MetricData=[
            {
            'MetricName': 'nodeready',
            'Dimensions': [
                {
                'Name': 'Environment',
                'Value': 'UAT'
                },
                {
                'Name': 'Region',
                'Value': REGION
                },
                {
                'Name': 'Node',
                'Value': '2'
                }
            ],
            'Unit': 'None',
            'Value': metricValue
            }
        ],
        Namespace='Tests'
    )
    return {
        'statusCode': 200,
        'body': 'metric published'
    }

def demo_run():
    url = "https://reqbin.com/echo/get/json"
    headers = CaseInsensitiveDict()
    headers["Accept"] = "application/json"
    resp = requests.get(url, headers=headers)
    data = resp.json()
    if data['success'] == 'true':
        metricValue = 1
    else:
        metricValue = 0
    print (metricValue)

    return {
        'statusCode': 200,
        'body': 'metric published'
    }

if __name__ == "__main__":
    demo_run()


# -*- coding: utf-8 -*-

import pymc3 as pm
from collections import OrderedDict

def create_poly_modelspec(k=1):
    '''
    Convenience function:
    Create a polynomial modelspec string for patsy
    '''
    return ('y ~ 1 + x ' + ' '.join(['+ np.power(x,{})'.format(j)
                                     for j in range(2, k+1)])).strip()

def run_models(df, upper_order=5):
    '''
    Convenience function:
    Fit a range of pymc3 models of increasing polynomial complexity.
    Suggest limit to max order 5 since calculation time is exponential.
    '''

    models, traces = OrderedDict(), OrderedDict()

    for k in range(1, upper_order+1):

        nm = 'k{}'.format(k)
        fml = create_poly_modelspec(k)

        with pm.Model() as models[nm]:

            print('\nRunning: {}'.format(nm))
            pm.glm.GLM.from_formula(fml, df,
                                    priors={'Intercept':pm.Normal.dist(mu=0, sigma=100)},
                                    family=pm.glm.families.Normal())

            traces[nm] = pm.sample(2000)

    return models, traces


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import logging
import os
import sys

from ipykernel import jsonutil
from ipykernel import zmqshell
from IPython.core import interactiveshell
from IPython.core.events import available_events
from ipython_genutils import py3compat

from google.colab import _event_manager
from google.colab import _pip
from google.colab import _shell_customizations
from google.colab import _system_commands

# The code below warns the user that a runtime restart is necessary if a
# package that is already imported is pip installed. Setting the
# SKIP_COLAB_PIP_WARNING environment variable will disable this warning.
def _show_pip_warning():
  return os.environ.get('SKIP_COLAB_PIP_WARNING', '0') == '0'

class Shell(zmqshell.ZMQInteractiveShell):
  """Shell with additional Colab-specific features."""

  def init_events(self):
    self.events = _event_manager.ColabEventManager(self, available_events)
    self.events.register('pre_execute', self._clear_warning_registry)

  def _should_use_native_system_methods(self):
    return os.getenv('USE_NATIVE_IPYTHON_SYSTEM_COMMANDS', False)

  def getoutput(self, *args, **kwargs):
    if self._should_use_native_system_methods():
      return super(Shell, self).getoutput(*args, **kwargs)

    output = _system_commands._getoutput_compat(self, *args, **kwargs)  # pylint:disable=protected-access

    if _show_pip_warning() and _pip.is_pip_install_command(*args, **kwargs):
      _pip.print_previous_import_warning(output.nlstr)

    return output

  def system(self, *args, **kwargs):
    if self._should_use_native_system_methods():
      return super(Shell, self).system(*args, **kwargs)

    pip_warn = _show_pip_warning() and _pip.is_pip_install_command(
        *args, **kwargs)

    if pip_warn:
      kwargs.update({'also_return_output': True})

    output = _system_commands._system_compat(self, *args, **kwargs)  # pylint:disable=protected-access

    if pip_warn:
      _pip.print_previous_import_warning(output)

  def _send_error(self, exc_content):
    topic = (self.displayhook.topic.replace(b'execute_result', b'err') if
             self.displayhook.topic else None)
    self.displayhook.session.send(
        self.displayhook.pub_socket,
        u'error',
        jsonutil.json_clean(exc_content),
        self.displayhook.parent_header,
        ident=topic)

  def _showtraceback(self, etype, evalue, stb):
    # This override is largely the same as the base implementation with special
    # handling to provide error_details in the response if a ColabErrorDetails
    # item was passed along.
    sys.stdout.flush()
    sys.stderr.flush()

    error_details = None
    if isinstance(stb, _shell_customizations.ColabTraceback):
      colab_tb = stb
      error_details = colab_tb.error_details
      stb = colab_tb.stb

    exc_content = {
        'traceback': stb,
        'ename': py3compat.unicode_type(etype.__name__),
        'evalue': py3compat.safe_unicode(evalue),
    }

    if error_details:
      exc_content['error_details'] = error_details
    self._send_error(exc_content)
    self._last_traceback = stb

  def object_inspect(self, oname, detail_level=0):
    info = self._ofind(oname)
    if info['found'] and sys.getsizeof(info.get('obj', '')) > 5000:
      obj = info.pop('obj')
      info['name'] = oname
      info['string_form'] = (
          _extra_object_info(obj) + '<Object too large to display>')
      info['string_form_abbreviated'] = True
      info['type_name'] = type(obj).__name__
      return info
    result = super(Shell, self).object_inspect(oname, detail_level=detail_level)
    if result.get('string_form', None) is not None:
      result['string_form'] = (
          _extra_object_info(info['obj']) + result['string_form'])
    return result

interactiveshell.InteractiveShellABC.register(Shell)

def _extra_object_info(obj):
  """Return a string with any extra info to include for this object."""
  try:
    # We want to include DataFrame size info, but don't want to raise an
    # exception in the case of a type called `DataFrame` with an unusual shape.
    # We also want to avoid importing pandas, as it's slow to import.
    if type(obj).__name__ == 'DataFrame' and hasattr(obj, 'shape'):
      rows, cols = obj.shape
      # We want this line to be separate from the DataFrame display, so we add
      # *two* newlines to the end.
      #
      # TODO(b/133258663): We also add backticks around the newlines to work
      # around a peculiarity in our markdown quoting; remove this.
      return '{} rows x {} columns`\n\n`'.format(rows, cols)
  except Exception as e:  # pylint: disable=broad-except
    logging.warning('Exception caught during _extra_object_info: %s', e)
  return ''


text = "This paper explores the political economy of network. Our model shows a r sqaured of 5%."

text_clean = str(text).lower()

text_clean = clean_text(text_clean)
print(text_clean)

text_tokens = word_tokenize(text)

tokens_without_sw = [word for word in text_tokens if not word in stopwords.words()]
tokens_without_sw = [word for word in text_tokens if not word in ['play', 'however']]
filtered_sentence = (" ").join(tokens_without_sw)

# developing

df = pd.DataFrame(data=[
        [1, 'John', 'Smith', 'a'],
        [1, 'John', 'Smith', 'b'],
        [2, 'Kate', 'Smith', 'c'],
    ],
    columns=['ID', 'First', 'Last', 'Avail']
)

output = (df
          .groupby(['ID', 'First', 'Last'], as_index=False)
          .agg({'Avail': lambda x: ';'.join(x)}))


def solution(numbers):
    answer = [-1] * len(numbers)
    st = []

    for i in range(len(numbers)):
        # stack에 담겨있는 값이 새로 나온 값보다 작으면 그때 값 바꿔주기
        while st and numbers[st[-1]] < numbers[i]:
            answer[st.pop()] = numbers[i]
        st.append(i) # 값이 numbers[st[-1]]보다 작으면 stack에 담기

    return answer

뒤에 있는 큰 수 찾기.py


# Base classes for interface with the simulation software
#
import threading
import logging
from abc import ABC, abstractmethod

from cockpitdecks import SPAM_LEVEL, now

loggerDataref = logging.getLogger("Dataref")
# loggerDataref.setLevel(SPAM_LEVEL)
# loggerDataref.setLevel(logging.DEBUG)

logger = logging.getLogger(__name__)
# logger.setLevel(SPAM_LEVEL)  # To see when dataref are updated
# logger.setLevel(logging.DEBUG)

# ########################################
# Command
#
# The command keywords are not executed, ignored with a warning
NOT_A_COMMAND = ["none", "noop", "no-operation", "no-command", "do-nothing"]  # all forced to lower cases

class Command:
    """
    A Button activation will instruct the simulator software to perform an action.
    A Command is the message that the simulation sofware is expecting to perform that action.
    """
    def __init__(self, path: str, name: str = None):

        self.path = path            # some/command
        self.name = name

    def __str__(self) -> str:
        return self.name if self.name is not None else (self.path if self.path is not None else "no command")

    def has_command(self) -> bool:
        return self.path is not None and not self.path.lower() in NOT_A_COMMAND

# ########################################
# Dataref
#
INTERNAL_DATAREF_PREFIX = "data:"  # "internal" datarefs (not exported to X-Plane) start with that prefix
NOT_A_DATAREF = ["DatarefPlaceholder"]

class Dataref:
    """
    A Dataref is an internal value of the simulation software made accessible to outside modules,
    plugins, or other software in general.
    """

    def __init__(self, path: str, is_decimal:bool = False, is_string:bool = False, length:int = None):

        self.path = path            # some/path/values[6]
        self.dataref = path      # some/path/values
        self.index = 0            # 6
        self.length = length        # length of some/path/values array, if available.
        self.sim_datatype = None
        self.data_type = "float"    # int, float, byte
        self.is_array = False      # array of above
        self.is_decimal = is_decimal
        self.is_string = is_string
        self._previous_value = None  # raw values
        self._current_value = None
        self._last_updated = None
        self._last_changed = None
        self._updated = 0  # number of time value updated
        self._changed = 0  # number of time value changed
        self.previous_value = None
        self.current_value = None
        self.current_array = []
        self.listeners = []  # buttons using this dataref, will get notified if changes.
        self.round = None

        # dataref/path:t where t in d, i, f, s, b.
        if len(path) > 3 and path[-2:-1] == ":" and path[-1] in "difsb":  # decimal, integer, float, string, byte(s)
            path = path[:-2]
            typ = path[-1]
            if typ == "d":
                self.is_decimal = True
                self.data_type = "int"
            elif typ == "s":
                self.is_string = True
                self.data_type = "str"
                self.is_array = True
            elif typ == "b":
                self.is_string = "byte"

        if is_decimal and is_string:
            loggerDataref.error(f"__init__: index {path} cannot be both decimal and string")

        if length is not None and length > 1:
            self.is_array = True

        # is dataref a path to an array element?
        if "[" in path:  # sim/some/values[4]
            self.dataref = self.path[:self.path.find("[")]
            self.index = int(self.path[self.path.find("[")+1:self.path.find("]")])
            self.is_array = True
            if self.length is None:
                self.length = self.index + 1  # at least that many values
            if self.index >= self.length:
                loggerDataref.error(f"__init__: index {self.index} out of range [0,{self.length-1}]")

    @staticmethod
    def is_internal_dataref(path):
        return path.startswith(INTERNAL_DATAREF_PREFIX)

    @staticmethod
    def mk_internal_dataref(path):
        return INTERNAL_DATAREF_PREFIX + path

    def is_internal(self):
        return self.path.startswith(INTERNAL_DATAREF_PREFIX)

    def set_round(self, rounding):
        self.round = rounding

    def value(self):
        return self.current_value

    def value_typed(self):
        # May fail during conversion
        if self.current_value is None:
            return None
        if self.data_type == "float":
            return float(self.current_value)
        elif self.data_type == "int" or self.is_decimal:
            return int(self.current_value)
        elif self.data_type == "str" or self.data_type == "string" or self.is_string:
            return str(self.current_value)
        # arrays, etc
        return self.current_value

    def exists(self):
        return self.path is not None

    def has_changed(self):
        if self.previous_value is None and self.current_value is None:
            return False
        elif self.previous_value is None and self.current_value is not None:
            return True
        elif self.previous_value is not None and self.current_value is None:
            return True
        return self.current_value != self.previous_value

    def updated(self) -> bool:
        # Returns True if updated at least once
        return self._updated > 0

    def update_value(self, new_value, cascade: bool = False):
        self._previous_value = self._current_value
        self._current_value = new_value
        self.previous_value = self.current_value
        if self.round is not None and type(new_value) in [int, float]:
            self.current_value = round(new_value, self.round)
            loggerDataref.debug(f"dataref {self.path} value {new_value} rounded to {self.current_value}")
        else:
            self.current_value = new_value
        self._updated = self._updated + 1
        self._last_updated = now()
        if self.has_changed():
            self._changed = self._changed + 1
            self._last_changed = now()
            loggerDataref.log(SPAM_LEVEL, f"dataref {self.path} updated {self.previous_value} -> {self.current_value}")
            if cascade:
                self.notify()
        # loggerDataref.error(f"dataref {self.path} updated")

    def add_listener(self, obj):
        if not isinstance(obj, DatarefListener):
            loggerDataref.warning(f"{self.dataref} not a listener {obj}")
        if obj not in self.listeners:
            self.listeners.append(obj)
        loggerDataref.debug(f"{self.dataref} added listener ({len(self.listeners)})")

    def notify(self):
        if self.has_changed():
            for dref in self.listeners:
                dref.dataref_changed(self)
                if hasattr(dref, "page") and dref.page is not None:
                    loggerDataref.log(SPAM_LEVEL, f"{self.path}: notified {dref.page.name}/{dref.name}")
                else:
                    loggerDataref.log(SPAM_LEVEL, f"{self.path}: notified {dref.name} (not on a page)")
        # else:
        #    loggerDataref.error(f"dataref {self.path} not changed")

class DatarefListener(ABC):
    # To get notified when a dataref has changed.

    def __init__(self):
        self.name = "unnamed"

    @abstractmethod
    def dataref_changed(self, dataref):
        pass

# ########################################
# Simulator
#
class Simulator(ABC):
    """
    Abstract class for execution of operations and collection of data in the simulation software.
    """
    def __init__(self, cockpit):
        self.cockpit = cockpit
        self.use_flight_loop = False
        self.running = False
        self.all_datarefs = {}

        self.datarefs_to_monitor = {}  # dataref path and number of objects monitoring
        self.simdrefValues = {}      # key = dataref-path, value = value

        # Values of datarefs
        self.previous_values = {}
        self.current_values = {}

        self.dataref_db_lock = threading.RLock()

        self.roundings = {} # path: int
        self.slow_datarefs = {}

        self._startup = True

        self.cockpit.set_logging_level(__name__)

    def set_roundings(self, roundings):
        self.roundings = roundings

    def set_slow_datarefs(self, slow_datarefs):
        self.slow_datarefs = slow_datarefs

    def detect_changed(self):
        """
        Update dataref values that have changed between 2 fetches.
        """
        try:
            currvalues = None
            with self.dataref_db_lock:
                currvalues = self.current_values.copy()  # we take a copy first so that it does not change...

            if currvalues is not None:
                for d in currvalues.keys():
                    if d not in self.previous_values.keys() or currvalues[d] != self.previous_values[d]:
                        # logger.debug(f"{d}={self.current_values[d]} changed (was {self.previous_values[d] if d in self.previous_values else 'None'}), notifying..")
                        if d in self.datarefs_to_monitor.keys():
                            self.all_datarefs[d].update_value(currvalues[d], cascade=True)
                        else:
                            self.all_datarefs[d].update_value(currvalues[d], cascade=False)  # we just update the value but no notification
                            # logger.warning(f"updated dataref '{d}' not in datarefs to monitor. No propagation") #  (was {self.datarefs_to_monitor.keys()})
                            # This means we got a value from X-Plane we never asked for this run...
                            # It could be a dataref-request leak (!) or someone else is requesting datarefs over UDP.
                        # logger.debug(f"..done")
                    # else:
                    #    logger.debug(f"{d}={self.current_values[d]} not changed (was {self.previous_values[d]})")
            else:
                logger.warning(f"no current values") #  (was {self.datarefs_to_monitor.keys()})
        except RuntimeError:
            logger.warning(f"detect_changed:", exc_info=True)

    def set_rounding(self, dataref):
        if dataref.path.find("[") > 0:
            rnd = self.roundings.get(dataref.path)
            if rnd is not None:
                dataref.set_round(rounding=rnd)         # rounds this very priecise dataref
            else:
                idx = dataref.path.find("[")
                base = dataref.path[:idx]
                rnd = self.roundings.get(base+"[*]")    # rounds all datarefs in array, explicit
                if rnd is not None:
                    dataref.set_round(rounding=rnd)     # rounds this very priecise dataref
                # rnd = self.roundings.get(base)        # rounds all datarefs in array
                # if rnd is not None:
                #   dataref.set_round(rounding=rnd)     # rounds this very priecise dataref
        else:
            dataref.set_round(rounding=self.roundings.get(dataref.path))

    def register(self, dataref):
        if dataref.path not in self.all_datarefs:
            if dataref.exists():
                self.set_rounding(dataref)
                self.all_datarefs[dataref.path] = dataref
            else:
                logger.warning(f"invalid dataref {dataref.path}")
        return dataref

    # ################################
    # Cockpit interface
    #
    def clean_datarefs_to_monitor(self):
        self.datarefs_to_monitor = {}

    def add_datarefs_to_monitor(self, datarefs: dict):
        prnt = []
        for d in datarefs.values():
            if d.path.startswith(INTERNAL_DATAREF_PREFIX):
                logger.debug(f"local dataref {d.path} is not monitored")
                continue
            if d.path not in self.datarefs_to_monitor.keys():
                self.datarefs_to_monitor[d.path] = 1
                prnt.append(d.path)
            else:
                self.datarefs_to_monitor[d.path] = self.datarefs_to_monitor[d.path] + 1
        logger.debug(f"added {prnt}")
        logger.debug(f"currently monitoring {self.datarefs_to_monitor}")

    def remove_datarefs_to_monitor(self, datarefs):
        prnt = []
        for d in datarefs.values():
            if d.path.startswith(INTERNAL_DATAREF_PREFIX):
                logger.debug(f"local dataref {d.path} is not monitored")
                continue
            if d.path in self.datarefs_to_monitor.keys():
                self.datarefs_to_monitor[d.path] = self.datarefs_to_monitor[d.path] - 1
                if self.datarefs_to_monitor[d.path] == 0:
                    prnt.append(d.path)
                    del self.datarefs_to_monitor[d.path]
            else:
                if not self._startup:
                    logger.warning(f"dataref {d.path} not monitored")
        logger.debug(f"removed {prnt}")
        logger.debug(f"currently monitoring {self.datarefs_to_monitor}")

    def remove_all_datarefs(self):
        logger.debug(f"removing..")
        self.all_datarefs = {}
        self.datarefs_to_monitor = {}
        self.simdrefValues = {}
        self.previous_values = {}
        self.current_values = {}
        logger.debug(f"..removed")

    @abstractmethod
    def start(self):
        pass

    @abstractmethod
    def terminate(self):
        pass

    # ################################
    # X-Plane Interface
    #
    @abstractmethod
    def commandOnce(self, command: Command):
        pass

    @abstractmethod
    def commandBegin(self, command: Command):
        pass

    @abstractmethod
    def commandEnd(self, command: Command):
        pass

from .collector import MAX_COLLECTION_SIZE, DatarefSet, DatarefSetListener, DatarefSetCollector


from spreadAnalysis.some.vkontakte import Vkontakte
from spreadAnalysis.io.config_io import Config

actor = "anonymousnews_org"
conf = Config()
vk = Vkontakte(conf.get_auth()["vkontakte"])
"""data = vk.actor_content(actor,start_date="2023-03-01")
print (data)
print (len(data["output"]))
sys.exit()"""

query = 'independentnorth.net'
data = vk.url_referals(query,start_date="2019-12-01")
print (data)
print (len(data["output"]))
sys.exit()
#print (vk.update_actor_info(["-202864751"],verbose=True))
#sys.exit()
data = vk.actor_content("https://vk.com/nordfront_danmark",start_date="2021-01-01")
#data = vk.url_referals("https://report24.news")
print (data)
print (len(data))
print (len(data["output"]))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Mar  1 12:01:12 2022

@author: lcabral4
"""

# Define the new Kernel that mimics RW
def VerticalMovement(particle, fieldset, time):

    # set particle salinity at new depth for output
    particle.salt =  fieldset.salt[time, particle.depth, particle.lat, particle.lon]
    particle.temp = fieldset.temp[time, particle.depth, particle.lat, particle.lon]

    # can code vertical diffusivity here with random walk
    # ocean parcels has some random walk functions as well
    # have particle.dt for time step, particle.depth for depth

    # for now, lock to depth (surface)
#    particle.depth = 0

def OutOfBounds ( particle , fieldset , time ):

    particle.delete ()

from parcels import FieldSet, ParticleSet, JITParticle, AdvectionRK4, ErrorCode, Variable
from datetime import timedelta, datetime
import numpy as np
import random
import netCDF4
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
#from mpl_toolkits.basemap import Basemap
from cartopy import config
import cartopy.crs as ccrs
import cartopy.mpl.ticker as cticker
from parcels import plotting
import matplotlib.pylab as pl
import cartopy.feature as cfeature
#from x import *
from Greenland_1_1_2015 import *

# Load the HYCOM Analysis data in the Gulf of Maine
# The paths/datafiles should be read in from a control file
filenames = {'U': "./hycom_data/HAB2*",
             'V': "./hycom_data/HAB2*",
             'salt': "./hycom_data/HAB2*",
             'temp': "./hycom_data/HAB2*"}
variables = {'U': 'water_u',
             'V': 'water_v',
             'salt': 'salinity',
             'temp': 'water_temp'}
dimensions = {'lat': 'lat', 'lon': 'lon', 'time': 'time'}
fieldset = FieldSet.from_netcdf(filenames, variables, dimensions,allow_time_extrapolation = True)
fieldset.mindepth = fieldset.U.depth[0]  # uppermost layer in the hydrodynamic data

#npart=2
# print the domain boundaries to the screen
print("domain boundaries")
print(fieldset.U.lon[0],fieldset.U.lon[-1],fieldset.U.lat[0],fieldset.U.lat[-1])

# Define a new Particle type including extra Variables
#class ArgoParticle(JITParticle):
#    # Phase of cycle: init_descend=0, drift=1, profile_descend=2, profile_ascend=3, transmit=4
#    cycle_phase = Variable('cycle_phase', dtype=np.int32, initial=0.)
#    cycle_age = Variable('cycle_age', dtype=np.float32, initial=0.)
#    drift_age = Variable('drift_age', dtype=np.float32, initial=0.)
#    S = Variable('S', dtype=np.float32, initial=np.nan)  # store salinity

# Define a new Particle type including extra Variables
class HabParticle(JITParticle):
    # Phase of cycle: init_descend=0, drift=1, profile_descend=2, profile_ascend=3, transmit=4
    salt = Variable('salt', dtype=np.float32, initial=np.nan)  # store salinity
    temp = Variable('temp', dtype=np.float32, initial=np.nan)  # store water temperature

# Initiate two Isopycnal Floats with staggered starts and different programmed drift densities initiated from
# different depths and horizontal locations.  These variables here (lon, lat, time, float_density) should
# be read in from a control file.

#%matplotlib inline

#lon = -70.20
#lat = 42.95
#depth = 0.

# pset = ParticleSet.from_list(fieldset=fieldset,
#                             pclass=HabParticle,
#                             lon=[-70.20,-70.18],
#                             lat=[42.85,43.0],
#                             depth=[0.,0.],
#                             time=[datetime(2015, 1, 1),
#                             datetime(2015,1,1)])

#baffin
line_start
line_end

#cross-gom
line_start
line_end
Np

days
year
month
pset = ParticleSet.from_line(fieldset=fieldset,
                            pclass=HabParticle,
                            start=line_start,
                            finish=line_end,
                            size=Np,
                            time=[datetime(year, month, day)],
                            repeatdt=5184000)

x = []
y = []
m = []

#lonmin
#lonmax
#latmin
#latmax
#n
days
year
month
day
outputminutes
dtminutes

kernels = VerticalMovement + pset.Kernel(AdvectionRK4)
output_file = pset.ParticleFile(name="float_output/Line_Greenland/1_1_2015_Line_Greenland", outputdt=timedelta(minutes=outputminutes))

# combine Argo vertical movement kernel with built-in Advection kernel
#kernels = VerticalMovement + pset.Kernel(AdvectionRK4)

# Create a ParticleFile object to store the output
# outputdt might be read in from a control file
#output_file = pset.ParticleFile(name="case3", outputdt=timedelta(minutes=240))

# dt and runtime might be read in from a control file
pset.execute(kernels, runtime=timedelta(days=days), dt=timedelta(minutes=dtminutes),
           output_file=output_file, recovery={ErrorCode.ErrorOutOfBounds: OutOfBounds})
pset.show(field=fieldset.U)
output_file.export()

#pset.execute(kernels, runtime=timedelta(days=days), dt=timedelta(minutes=dtminutes), output_file=output_file, recovery={ErrorCode.ErrorOutOfBounds: OutOfBounds})

#pset.execute(kernels, runtime=timedelta(days=600.), dt=timedelta(minutes=-30), output_file=output_file, recovery={ErrorCode.ErrorOutOfBounds: OutOfBounds})

#output_file.export()  # export the trajectory data to a netcdf file

nc = netCDF4.Dataset("float_output/Line_Greenland/1_1_2015_Line_Greenland.nc")

x = nc.variables["lon"][:].squeeze()
time = nc.variables["time"][:].squeeze()
y = nc.variables["lat"][:].squeeze()
z = nc.variables["z"][:].squeeze()
salt = nc.variables["salt"][:].squeeze()
temp = nc.variables["temp"][:].squeeze()
nc.close()
fig = plt.figure(figsize=(13,10))
for p in range(x.shape[0]):
    cb = plt.scatter(x[p,:], y[p,:], c=temp[p,:], s=0.01, marker = "o")
    plt.scatter(x[:,0], y[:,0], s= 20, marker = 's')
plt.title('Greenland Temperature')
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.savefig("Greenland_1_1_2015.png")

plt.show()

fig = plt.figure(figsize=(13,10))
#    for p in range(x.shape[0]):
#        cb = plt.scatter(x[p], y[p], c=temp[p], s=20, marker = "o")
ax = plt.axes(projection=ccrs.PlateCarree())
ax.set_extent([-74,-1, 70, 20], ccrs.PlateCarree())
ax.coastlines()
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.COASTLINE)
#x = np.linspace(-65, -75)
#y = np.linspace(35, 45)
#plt.title('Temperature Variable')
#ax.set_xlabel("Longitude")
#ax.set_ylabel("Latitude")
#ax.set_xticks(np.arange(-80,-65,100), crs=ccrs.PlateCarree())
lon_formatter = cticker.LongitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.set_xticks([-75, -70, -65, -60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10,-5, 0], crs=ccrs.PlateCarree())
ax.set_yticks([30, 35, 40, 45, 50, 55, 60, 65, 70, 75], crs=ccrs.PlateCarree())
#ax.set_yticks(np.arange(40,50,20), crs=ccrs.PlateCarree())
lat_formatter = cticker.LatitudeFormatter()
#ax.yaxis.set_major_formatter(lat_formatter)
#lon, lat = np.meshgrid(x, y)
for p in range(x.shape[0]):
    cb = plt.scatter(x[p,:], y[p,:], c=temp[p,:], s=0.0001, marker = "o")
    plt.scatter(x[:,0], y[:,0])
print(temp, 'temp')

# plot

plt.title('Greenland')
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.savefig("Greenland_1_1_2015_temp.png")
plt.show()


import re
from turtle import right
from typing import List

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        l, r = 0, len(nums)-1

        while l <= r:
            mid = (l+r)//2
            if (mid == 0 or nums[mid - 1] < nums[mid]) and (mid == len(nums)-1 or nums[mid+1] < nums[mid]):
                return mid

            if nums[mid] < nums[mid-1]:
                r = mid - 1
            else:
                l = mid + 1

        if nums[0] < nums[len(nums)-1]:
            return 1
        else:
            return 0

print(Solution().findPeakElement([1, 2]))


import numpy as np

def classic_multi(A, B):
    if len(B) != len(A[0]):
        print("Different dimension of the matrics")
        return

    n = len(A)
    m = len(A[0])
    t = len(B[0])

    answer = [[0 for i in range(t)] for j in range(n)]
    for i in range(n):
        for j in range(m):
            for k in range(t):
                answer[i][k] += A[i][j] * B[j][k]
    return answer

if __name__ == "__main__":
    A = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
    B = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8]]
    print(classic_multi(A, B))


import heapq

# def heap_sort(nums):
# 	heap = []
# 	for num in nums:
# 		heapq.heappush(heap, num)

# 	sorted_nums = []
# 	while heap:
# 		sorted_nums.append(heapq.heappop(heap))
# 	return sorted_nums

# print(heap_sort([4, 1, 7, 3, 8, 5]))

# nums = [4, 1, 7, 3, 8, 5]
# heap = []

# for num in nums:
# 	heapq.heappush(heap, (-num, num))

# while heap:
# 	print(heapq.heappop(heap)[1])

# print(heap)

# def kth_smallest(nums, k):
# 	heap = []
# 	for num in nums:
# 		heapq.heappush(heap, num)

# 	kth_min = None
# 	for i in range(k):
# 		kth_min = heapq.heappop(heap)
# 	print(kth_min)
# 	return kth_min

# print(kth_smallest([4, 1, 7, 3, 8, 5], 3))

queue = []

heapq.heappush(queue, [2, 'A'])
heapq.heappush(queue, [5, 'B'])
heapq.heappush(queue, [1, 'C'])
heapq.heappush(queue, [7, 'D'])
print(queue)

for i in range(len(queue)):
	print(heapq.heappop(queue))


import matplotlib.pyplot as pl
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# import Dataset from csv
dataset = pd.read_csv('Salary_Data.csv')
x = dataset.iloc[:, :-1].values
y = dataset.iloc[:, -1].values

# splitting dataset to training and test
[X_train, X_test, Y_train, Y_test] = train_test_split(x, y, test_size=0.2, random_state=0)
print(len(Y_train))
# Train simple model by LinearRegression class
regression: object = LinearRegression()
regression.fit(X_train, Y_train)

# Predicting Test result
Y_perdict: object = regression.predict(X_test)

# print predict 1 year experience

print(regression.coef_)
print(regression.intercept_)
# Y = b0 + b1*X
# dependent value DV =  intercept_ + ( coef_ * independent value IV)
# Salary =
print(regression.predict([[12]]))
print( (regression.coef_*12) + regression.intercept_)

# Visualising Training
plot1 = pl.figure(1)
pl.scatter(X_train, Y_train, color='red')
pl.plot(X_train, regression.predict(X_train), color='black')
pl.title('Salary Vs Experience (Training)')
pl.xlabel('Years of Experience')
pl.ylabel('Salary')

# Visualising Test
plot2 = pl.figure(2)
pl.scatter(X_test, Y_test, color='red')
pl.plot(X_train, regression.predict(X_train), color='blue')
pl.title('Salary Vs Experience (Test)')
pl.xlabel('Years of Experience')
pl.ylabel('Salary')
pl.show()


import argparse
import create_cert
import renew

# Entry point, determines if it should renew or create certs
def main(parser):
    args = process_args(parser)

    if args.renew:
        renew()
    else:
        create_cert.create_cert(args.email)

# Create the args for the help and later processing
def create_args():
    parser = argparse.ArgumentParser(description='Automatically obtain certs for subdomains in nginx configs')

    parser.add_argument('--renew', dest='renew', action='store_true',
                        help='If this flag is set the script will run in renew mode. '
                             'Renew mode will issue a renew command instead of register, '
                             'as such it will not automatically scrape the nginx config. '
                             "Certbot's renew will use the same configuration"
                             "as the previous registration command")

    parser.add_argument('--email', dest='email', action='store',
                        default='', type=str,
                        help='This is the email to be used in the registration process, '
                             'if left blank the user will be prompted to enter it later.\n')
    return parser

# Parse the args into a variable for later use
def process_args(parser):
    args = parser.parse_args()
    return args

# Create the args then start the main method
if __name__ == "__main__":
    args_parser = create_args()
    main(args_parser)


import numpy as np
import math
import matplotlib.pyplot as plt

from analysis import covariance_matrix, scale_less

korean = scale_less([95, 90, 80, 60, 40, 80, 95, 30, 15, 60])
english = scale_less([95, 95, 75, 70, 35, 80, 90, 25, 10, 70])

data_length = len(korean)

print('국어성적 z-score', korean)
print('영어성적 z-score', english)

cov_mat = covariance_matrix(korean, english)
print('공분산 행렬:', cov_mat)

mat = np.array(cov_mat)

w, v = np.linalg.eig(mat)
print('고유값', np.round(w, 2))
print('고유백터', np.round(v, 2))

# 고유벡터에 대응하는 값 구하기
PC1s = [np.round(korean[i] * v[0][0] + english[i] * v[0][1], 2) for i in range(data_length)]
PC2s = [np.round(korean[i] * v[1][0] + english[i] * v[1][1], 2) for i in range(data_length)]

print('새롭게 만들어 진 데이터 PCA')
print("PC1:", PC1s)
print("PC2:", PC2s)

plt.plot(korean, english, 'ro')
plt.axis([-5, 5, -5, 5])

# 첫 번째 고유벡터 그리기
plt.quiver(0, 0, v[0][0], v[0][1], color = 'blue') # 고유값: 1.99

# 두 번째 고유벡터 그리기
plt.quiver(0, 0, v[1][0], v[1][1], color = 'green') # 고유값: 0.02

plt.grid()
plt.show()


# Essential classes for simulator
# Xuening Wang
# 2022/04/14

from random_generators import *
from model_reschedule import *

class ProductItem:
    def __init__(self, index):
        self.index = index
        self.status = 1 #1 for in inventory, 0 for on the way
        self.return_periods = 0
        self.cir_cnt = 0
        self.exp_regular_return_periods = 0

    def init_out(self, rp, errp):
        self.status = 0
        self.return_periods = rp
        self.exp_regular_return_periods = errp
        self.cir_cnt += 1

    def send_out(self, rp, median_cycle_duration):
        if self.status == 1:
            self.status = 0
            self.return_periods = rp
            self.exp_regular_return_periods = median_cycle_duration
            self.cir_cnt += 1

    def update_rp_errp_per_period(self):
        if self.status == 0 and self.return_periods > 0:
           self.return_periods -= 1
           self.exp_regular_return_periods -= 1 #may be negative if delayed

    def check_in(self):
        if self.status == 0 and self.return_periods == 0:
            self.status = 1
            self.exp_regular_return_periods = 0
            return self.index

class Inventory:
    def __init__(self, paras):
        self.paras = paras
        # Create item set(list)
        self.num_items = paras['total_items']
        self.items = [ProductItem(i) for i in range(self.num_items)]
        self.enable_output_file = paras['enable_output_file']

    def initialize(self):
        # starting_inv = self.paras['starting_inv']
        # num_out = self.num_items - starting_inv
        #
        # regular_return_periods = self.paras['regular_return_periods']
        # return_delay_geom_mean = self.paras['return_delay_geom_mean']
        # return_delay_seq = geom_discrete_seq(num_out, return_delay_geom_mean)
        # for j in range(num_out):
        #     errp = uniform_discrete_one(1, regular_return_periods + 1)
        #     self.items[j].init_out(rp = errp + return_delay_seq[j], errp = errp)  # first random number generated here!

        # 9/6 change: no regular_return_periods and delays, replaced with only cycle_duration
        # use only a unif(1, median_cycle_duration+1)
        # and return period (rp) = exp return period (errp), we know exactly when they will come back
        # in the parameters after calibration, num_out should be 0 (so no change essentially)
        starting_inv = self.paras['starting_inv']
        self.current_inv = starting_inv

        num_out = self.num_items - starting_inv
        cycle_duration_lognormal_percentile = self.paras['cycle_duration_lognormal_percentile']
        if num_out > 0:
            for j in range(num_out):
                errp = uniform_discrete_one(1, cycle_duration_lognormal_percentile+1)
                self.items[j].init_out(rp = errp, errp = errp) # first random number generated here!

    def update_rp_errp_per_period(self):
        for it in self.items:
            it.update_rp_errp_per_period()

    def receive_returns(self):
        return_items = []
        for it in self.items:
            id = it.check_in()
            if id:
                return_items.append(id)
        self.current_inv += len(return_items)
        # REPORT
        if self.enable_output_file:
            print("Returned items", return_items)
        return return_items

    def take_inv_items_list(self):
        return [it for it in self.items if it.status == 1]

    def sendout_items(self, item_index_list, errp_list, rp_list):
        for i in range(len(item_index_list)):
            self.items[item_index_list[i]].send_out(rp_list[i], errp_list[i])
            self.current_inv -= 1
        # REPORT
        if self.enable_output_file:
            print("Send out items: ", item_index_list)
            print("Will be back in: ", rp_list, " (realized), expected to be back in: ", errp_list[i])

    def predict_future_inv_median_cycle(self, time, future_time, inv_occup_record):
        current_inv = 0
        future_exp_return = 0
        for it in self.items: # inv + on time now could come back before a future time
            if it.status == 1:
                current_inv += 1
            elif it.status == 0:
                if time + it.exp_regular_return_periods <= future_time: # note: all the overdue items are counted too
                    future_exp_return += 1

        num_occupied_items = inv_occup_record[future_time]
        future_raw_inv = current_inv + future_exp_return - num_occupied_items

        return future_raw_inv, current_inv, future_exp_return, num_occupied_items

    def report_current_inv(self):
        # REPORT
        if self.enable_output_file:
            print("Current inv quantity:", self.current_inv)
        return self.current_inv

    def report_current_inv_id(self):
        in_stock_items = [it.index for it in self.items if it.status == 1]
        return in_stock_items

    def report_one_item_status(self, index):
        return self.items[index].status

    def report_return_flow(self):
        return [[it.index, it.exp_regular_return_periods, it.return_periods] for it in self.items if it.status == 0]

    def report_exp_return_flow(self):
        return [[it.index, it.exp_regular_return_periods] for it in self.items if it.status == 0]

    def report_max_item_return_time(self):
        max_time = 0
        for it in self.items:
            if it.status == 0 and it.return_periods > max_time:
                max_time = it.return_periods
        return max_time

    def report_item_cir_stats(self):
        item_cir_cnt = []
        for it in self.items:
            item_cir_cnt.append(it.cir_cnt)
        avg_cir_cnt = sum(item_cir_cnt)/self.num_items
        return avg_cir_cnt, item_cir_cnt

class CustomerRequest:
    def __init__(self, index, order_time, desired_periods, realized_cycle_duration):
        self.index = index
        self.order_time = order_time
        self.desired_periods = desired_periods
        self.desired_time = order_time + desired_periods
        self.status = 0  #0 for new, 1 for admitted/active order, -1 for rejected

        self.realized_cycle_duration = realized_cycle_duration

    def admit(self):
        self.status = 1

    def reject(self):
        self.status = -1

    def write_story_when_admit_by_current(self, current_inv):
        self.toa_current_inv = current_inv

    def write_story_when_admit_by_predict(self, inv_ref, current_inv, future_exp_return, num_occupied_items, use_uncmtd = 0, uncmtd_cnt = 0):
        self.toa_current_inv = current_inv
        self.toa_future_exp_return = future_exp_return
        self.toa_occupied_by_pred_same_period = num_occupied_items
        self.predict_with_uncmtd = use_uncmtd
        self.toa_uncmtd_cnt = uncmtd_cnt
        self.toa_inv_ref = inv_ref

class CustomerOrder: #only for admitted (available & chosen) requests
    def __init__(self, req_index, order_time, desired_periods, realized_cycle_duration, enable_output_file):
        self.req_index = req_index
        self.order_time = order_time
        self.desired_periods = desired_periods
        self.desired_time = order_time + desired_periods
        self.status = 0 # 0 for "admit"

        self.realized_cycle_duration = realized_cycle_duration

        self.enable_output_file = enable_output_file

    def commit_order(self, item_index, commit_time):
        self.status = 1 # 1 for "commit"
        self.commit_item = item_index
        self.commit_time = commit_time
        # REPORT
        if self.enable_output_file:
            print("  assign item %d to order %d" % (item_index, self.req_index))

    def finish_order(self, finish_time):
        self.status = 2 # 2 for "success"
        self.finish_time = finish_time
        # REPORT
        if self.enable_output_file:
            print("  order %d successful, desired time %s :)" % (self.req_index, self.desired_time))

    def fail_order(self, fail_time):
        self.status = -2 # -2 for "failure"
        self.fail_time = fail_time
        # REPORT
        if self.enable_output_file:
            print("  order %d expired and failed, desired time %s :(" %(self.req_index, self.desired_time))

    # def save_later_order(self):
    #     self.status = 5
    #     print("  order saved for later: %d"%self.req_index)

class NominalSchedule:
    def __init__(self):
        self.ns_start = {}
        self.ns_length = {}
        self.ns_assign_item = {}
        self.on_schedule_req_list = []

    def initialize(self, num_items, initial_rt_flow):
        self.num_items = num_items
        self.item_exp_release_time = {item: 0 for item in range(num_items)}
        self.item_exp_release_time.update({rt[0]: rt[1] for rt in initial_rt_flow}) #key-value in form of item_index: errp. see Inventory.report__return_flow for details

    def reschedule_for_one_new_request(self, cr, median_cycle_duration, t, T): #t stands for current time
        new_req_index = cr.index
        new_req_desired_time = cr.desired_time
        new_req_exp_length = median_cycle_duration

        update_assign = self.__model_complete_reschedule_for_new_request(new_req_index, new_req_desired_time, new_req_exp_length, t, T)
        if update_assign: # available YES
            self.on_schedule_req_list.append(new_req_index)
            self.ns_start.update({new_req_index: new_req_desired_time})
            self.ns_length.update({new_req_index: new_req_exp_length})
            # use newly solved schedule as the nominal schedule for all requests
            self.ns_assign_item = update_assign
            return True # can accommodate the new request
        else:
            return False

    def __model_complete_reschedule_for_new_request(self, new_req_index, new_req_desired_time, new_req_exp_length, t, T):
        req_index_list = self.on_schedule_req_list.copy()
        req_index_list.append(new_req_index)

        ns_start = self.ns_start.copy()
        ns_start.update({new_req_index: new_req_desired_time})
        ns_length = self.ns_length.copy()
        ns_length.update({new_req_index: new_req_exp_length})

        # # DEBUG
        # print("Scheduling debug!")
        # if req_index_list[0] == 0: #the first one
        #     print(req_index_list)
        #     print(ns_start)
        #     print(ns_length)
        #     print(self.num_items)
        #     print(self.item_exp_release_time)

        obj_val, updated_assign = model_complete_reschedule(req_index_list, ns_start, ns_length,
                                            self.num_items, self.item_exp_release_time.copy(), t, T)

        if obj_val == len(self.on_schedule_req_list) + 1: # can accommodate the new request
            return updated_assign

    def check_order_to_commit_now(self, t):
        due_orders = []
        assign_info = {}
        for req_index, start_time in self.ns_start.items():
            if start_time == t:
                due_orders.append(req_index)
                assign_info.update({req_index: self.ns_assign_item[req_index]}) #assigned item id
        return due_orders, assign_info

    def commit_order_one(self, req_index, median_cycle_duration, t):
        # update release time for the attributed item
        item_index = self.ns_assign_item[req_index]
        self.item_exp_release_time.update({item_index: t+median_cycle_duration})
        self.__remove_nominal_schedule_one(req_index)

    def fail_order_one(self, req_index):
        self.__remove_nominal_schedule_one(req_index)

    def __remove_nominal_schedule_one(self, req_index):
        self.on_schedule_req_list.remove(req_index)
        self.ns_start.pop(req_index)
        self.ns_length.pop(req_index)
        self.ns_assign_item.pop(req_index)

    def extend_release_time_for_delay(self, item_index, t, exp_delay_window):
        self.item_exp_release_time.update({item_index: t+exp_delay_window})
        for req_index, assign_item in self.ns_assign_item.items():
            if assign_item == item_index and self.ns_start[req_index] < self.item_exp_release_time[item_index]:
                affected_req_index = req_index
                return affected_req_index #Note: here we may have a invalid schedule before further processing

    def reschedule_for_one_item_delay(self, affected_req_index, t, T):
        updated_assign = self.__model_complete_reschedule_for_delay(t, T)
        if updated_assign: #available YES
            self.ns_assign_item = updated_assign
            return True
        else: # have to fail the affected req
            self.fail_order_one(affected_req_index)
            return False

    def __model_complete_reschedule_for_delay(self, t, T):
        obj_val, updated_assign = model_complete_reschedule(self.on_schedule_req_list.copy(), self.ns_start.copy(), self.ns_length.copy(),
                                                            self.num_items, self.item_exp_release_time.copy(), t, T)

        if obj_val == len(self.on_schedule_req_list): # can resolve conflict
            return updated_assign

    # def check_schedule_validity(self): # for safety

# TEST BELOW (outdated)
# initial_rt_flow = [[0, 3, 1], [1, 0, 0], [2, 5, 3]]
# regular_return_period = 2
# exp_delay_window = 2
# T = 5
#
# schedule = NominalSchedule()
# schedule.initialize(initial_rt_flow)
# t=1
# cr_1 = CustomerRequest(index=1, order_time=1, desired_periods=1, realized_return_delay=2) #desired at time 2
# schedule.reschedule_for_one_new_request(cr_1, regular_return_period, exp_delay_window, t, T)
# cr_2 = CustomerRequest(index=2, order_time=1, desired_periods=2, realized_return_delay=2) #desired at time 3
# schedule.reschedule_for_one_new_request(cr_2, regular_return_period, exp_delay_window, t, T)
# cr_3 = CustomerRequest(index=3, order_time=1, desired_periods=4, realized_return_delay=2) #desired at time 4
# schedule.reschedule_for_one_new_request(cr_3, regular_return_period, exp_delay_window, t, T)
#
# cr_4 = CustomerRequest(index=4, order_time=1, desired_periods=0, realized_return_delay=2)
# schedule.reschedule_for_one_new_request(cr_4, regular_return_period, exp_delay_window, t, T)


"""
@description:主模块
"""
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量

load_dotenv()

import os
import logging
from logging import handlers
import uvicorn
from fastapi import FastAPI, Request, status, WebSocket
from fastapi.responses import HTMLResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.openapi.docs import (
    get_swagger_ui_html,
    get_swagger_ui_oauth2_redirect_html,
)
from fastapi_pagination import add_pagination
from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.exceptions import RequestValidationError
from apps.chat.router import router as user_router, websocket_llm_handler
from apps.chat.admin_router import router as admin_router
from utils.custom_response import util_response
from utils.custom_config import BASE_DIR

ENV = os.environ.get('ENV_PROFILE')

# 主程序
app = FastAPI(
    title="FastAPI结构示例",  # 文档标题
    description="使用FastAPI实现基础的用户验证，权限管理，增删改查，文件上传下载等功能. 🚀",  # 文档简介
    version="0.0.1",  # 文档版本号
    docs_url=None, redoc_url=None,  # 配置离线文档
)

# 配置日志记录【记录 uvicorn 的日志】
@app.on_event("startup")
async def startup_event():
    log_path = os.path.join(BASE_DIR, 'logs')
    if not os.path.exists(log_path):
        os.mkdir(log_path)
    format_str = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")  # 设置日志格式
    logger = logging.getLogger("uvicorn.access")  # 获取日志对象
    # sh = logging.StreamHandler()  # 往屏幕上输出
    rh = handlers.RotatingFileHandler("logs/uvicorn.log", maxBytes=100 * 1024, backupCount=7, encoding='utf-8')  # 写入文件
    # sh.setFormatter(format_str)  # 指定格式
    rh.setFormatter(format_str)  # 指定格式
    # logger.addHandler(sh)
    logger.addHandler(rh)

# 跨域设置
app.add_middleware(
    CORSMiddleware,
    allow_origins=['*'],  # 允许跨域请求的源列表。
    allow_credentials=True,  # 指示跨域请求支持 cookies。
    allow_methods=["*"],  # 允许跨域请求的 HTTP 方法列表。
    allow_headers=["*"],  # 允许跨域请求的 HTTP 请求头列表。
)

# 挂载静态文件
app.mount("/static", StaticFiles(directory="static"), name="static")
# app.mount("/media", StaticFiles(directory="media"), name="media")

# 离线文档配置-由于资源文档经常请求不到，这里搞离线文档
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=app.openapi_url,
        title=app.title + " - Swagger UI",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        swagger_js_url="/static/doc/swagger-ui-bundle.js",
        swagger_css_url="/static/doc/swagger-ui.css",
    )

@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
    return get_swagger_ui_oauth2_redirect_html()

# 覆盖 HTTPException 错误处理器
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return util_response(http_status=exc.status_code, msg=str(exc.detail))

# 覆盖默认异常处理器[RequestValidationError是 Pydantic 的ValidationError的子类。]
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return util_response(http_status=status.HTTP_400_BAD_REQUEST, msg=str(exc))

# todo 这里先这样定义全局异常返回，待优化
@app.middleware('http')
async def db_session_middleware(request: Request, call_next):
    response = util_response(http_status=status.HTTP_500_INTERNAL_SERVER_ERROR,
                             msg='Internal server error')
    # finally:
    #     return response
    # if ENV=='dev':
    #     try:
    #         response = await call_next(request)
    #     except Exception as e:
    #         response = util_response(http_status=status.HTTP_500_INTERNAL_SERVER_ERROR,
    #                              msg=f'Internal server error:{str(e)}')
    #         # msg=f'Internal server error:{str(e)}')
    #         logging.error(str(e))
    #         print(str(e))
    # elif ENV=='prod':
    #     response = await call_next(request)
    response = await call_next(request)
    return response

# 路由注册
app.include_router(user_router)
app.include_router(admin_router)

@app.get("/", tags=['测试'], deprecated=True)
async def root():
    return util_response(data='fast_api!')

@app.websocket("/ws/chat")
async def websocket_endpoint(websocket: WebSocket, x_current_user_id: int):
    await websocket_llm_handler(websocket, x_current_user_id)

add_pagination(app)

html = """
<!DOCTYPE html>

        <title>Chat</title>

WebSocket Chat

Your ID:

        <form action="" onsubmit="sendMessage(event)">
            <input type="text" id="messageText" autocomplete="off"/>
            <button>Send</button>
        </form>

"""

@app.get("/ws-html")
async def get():
    return HTMLResponse(html)

if __name__ == '__main__':
    uvicorn.run("main:app", host='0.0.0.0', port=8002, reload=True, log_config='uvicorn_config.json')  # 可以直接运行此脚本


import time

from lava_dispatcher.action import Action, Pipeline
from lava_dispatcher.logical import RetryAction

class DummyAction(Action):
    def __init__(self):
        super().__init__()
        self.ran = 0

    def run(self, connection, max_end_time):
        assert connection is None  # nosec - unit test support.
        assert max_end_time == 1  # nosec - unit test support.
        self.ran += 1

def test_repeat_action(monkeypatch):
    monkeypatch.setattr(time, "monotonic", lambda: 0)
    ra = RetryAction()
    ra.parameters = {"repeat": 5}
    ra.level = "1"
    ra.pipeline = Pipeline(parent=ra)
    ra.pipeline.add_action(DummyAction())
    ra.run(None, 1)
    assert ra.pipeline.actions[0].ran == 5  # nosec - unit test support.


import tkinter as tk

window=tk.Tk()
window.title("five window GUI")
window.geometry("200x300")

l=tk.Label(window,bg="orange",width=20,text="empty")
l.pack()

def print_selection():
    l.config(text="you select radio"+var.get())

var=tk.StringVar()
r1=tk.Radiobutton(window,text="Radio A",variable=var,value="A",command=print_selection)
r1.pack()

# var=tk.StringVar()
r2=tk.Radiobutton(window,text="Radio B",variable=var,value="B",command=print_selection)
r2.pack()

# var=tk.StringVar()
r3=tk.Radiobutton(window,text="Radio C",variable=var,value="C",command=print_selection)
r3.pack()

window.mainloop()


import sys
from optparse import OptionParser

from typing import Optional, Tuple
import time

import locale
locale.setlocale( locale.LC_ALL, '' )

from loguru import logger
logger.add("logs/ftx_static_cash_and_carry_perpetual.log", rotation="100 MB")

from cryptomancer.security_master import SecurityMaster

from cryptomancer.account.ftx_account import FtxAccount
from cryptomancer.exchange_feed.ftx_exchange_feed import FtxExchangeFeed

from cryptomancer.execution_handler.execution_session import execution_scope

from cryptomancer.execution_handler.limit_order import LimitOrder

def static_cash_and_carry(account: FtxAccount, exchange_feed: FtxExchangeFeed, underlying: str,
                        cash_collateral_target: float, cash_collateral_bounds: Tuple[float, float],
                        minimum_size: Optional[float] = 0.001,
                        force: Optional[bool] = False):
    underlying_name = f'{underlying}/USD'
    future_name = f'{underlying}-0924'

    # set up exchange subscriptions
    _ = exchange_feed.get_ticker(underlying_name)
    _ = exchange_feed.get_ticker(future_name)

    # get the current positions
    positions = account.get_positions()

    for position in positions:
        logger.info(f'Current Position | {position.name} | {position.side} | {position.size} | {locale.currency(position.usd_value, grouping = True)}')

    usd_coins = list(filter(lambda position: position.name == 'USD', positions))
    underlying_positions = list(filter(lambda position: position.name.upper() == underlying, positions))
    perpetual_positions = list(filter(lambda position: position.name.upper() == future_name, positions))

    # figure out how much cash collateral we have
    # we have to be careful here because USD will already *include* PERP gains/losses,
    # 	so we don't want to double-count those values
    portfolio_value = sum([position.usd_value for position in usd_coins]) + \
                        sum([position.usd_value for position in underlying_positions])

    logger.info(f'Current Portfolio Value | {locale.currency(portfolio_value, grouping = True)}')

    usd_value = sum([position.usd_value for position in usd_coins])
    underlying_size = sum([position.net_size for position in underlying_positions])
    perpetual_size = sum([position.net_size for position in perpetual_positions])

    # SHOULD THE LOGIC HERE ACCOUNT FOR TARGET POSITION VS CURRENT POSITION
    # e.g. WHAT DO WE DO WITH OTHER COINS / PERPS IN THE ACCOUNT?!  LIQUIDATE?

    margin_pct = usd_value / portfolio_value

    logger.info(f'Current Margin | ' + '{:.2%}'.format(margin_pct))

    # if we're within our collateral bounds, do nothing
    if force or (margin_pct < cash_collateral_bounds[0] or margin_pct > cash_collateral_bounds[1]):
        if (margin_pct < cash_collateral_bounds[0] or margin_pct > cash_collateral_bounds[1]):
            logger.info('Margin Target Out of Bounds (' + '{:.2%}'.format(cash_collateral_bounds[0]) + ', ' +
                                                    '{:.2%}'.format(cash_collateral_bounds[1]) + ')')
        else:
            logger.info('Trade Forced.')

        # otherwise, figure out what our target positions are
        target_margin_usd = portfolio_value * cash_collateral_target
        target_exposure_usd = portfolio_value * (1 - cash_collateral_target)

        current_exposure_usd = sum([position.usd_value for position in underlying_positions])

        target_usd_trade = target_exposure_usd - current_exposure_usd

        # go half way
        target_usd_trade = target_usd_trade / 2

        # we do the trade in the underlying first because we're trying to hit a specific
        # dollar amount; once we get that dollar amount executed, we can match it with
        # a corresponding trade in the perpetuals
        side = 'buy' if target_usd_trade > 1e-8 else 'sell'
        logger.info(f'{side.upper()} {locale.currency(target_usd_trade, grouping = True)} {underlying_name}')

        while True:
            try:
                market = exchange_feed.get_ticker(underlying_name)
                mid_point = (market['bid'] + market['ask']) / 2.
                width = (market['ask'] - market['bid']) / mid_point
            except:
                continue

            price = mid_point * (1 - width / 2) if side == 'buy' else mid_point * (1 + width / 2)
            size = abs(target_usd_trade) / price

            try:
                with execution_scope(wait = True, timeout = 10) as session:
                    underlying_order = LimitOrder(account = account,
                                                    market = underlying_name,
                                                    side = side,
                                                    size = size,
                                                    price = price,
                                                    post_only = True)

                    session.add(underlying_order)

            except TimeoutError:
                logger.debug(f'Timed out.  Retrying.')
                pass

            order_status = session.get_order_statuses()
            if len(order_status) == 0:
                # the order errored out
                logger.info(f'{side.upper()} {locale.currency(target_usd_trade, grouping = True)} {underlying_name} FAILED')
                continue

            else:
                order_status = order_status[0]

                while order_status.status == "open":
                    # make sure we don't get stuck in the loop; e.g. what happens if the cancel never got sent?
                    try:
                        ftx_account.cancel_order(order_status.order_id)
                    except:
                        pass
                    time.sleep(0.1)
                    order_status = session.get_order_statuses()[0]

                # figure out how much of the order was actually filled
                filled_size = order_status.filled_size if order_status.side == "buy" else -order_status.filled_size
                filled_price = order_status.average_fill_price

                if abs(filled_size) < 1e-8:
                    continue

                underlying_size = underlying_size + filled_size
                logger.info(f'Filled {filled_size} in {underlying_name} | Total: {underlying_size}')

                target_usd_trade = target_usd_trade - filled_size * filled_price

                # We might've gotten a partial fill; see if the remaining
                # capital to trade is less than the minimum trade size
                if abs(target_usd_trade) / filled_price < minimum_size:
                    break

    # if we have 5 underlying, we need -5 perpetuals
    # so we want to take that target and subtract what we already own
    perpetual_to_buy = (-underlying_size - perpetual_size)
    perpetual_to_buy = int(perpetual_to_buy / minimum_size) * minimum_size

    side = 'buy' if perpetual_to_buy > 1e-8 else 'sell'
    size = abs(perpetual_to_buy)

    if abs(perpetual_to_buy) > minimum_size:
        while True:
            market = exchange_feed.get_ticker(future_name)
            mid_point = (market['bid'] + market['ask']) / 2.
            width = (market['ask'] - market['bid']) / mid_point

            price = mid_point * (1 - width / 2) if side == 'buy' else mid_point * (1 + width / 2)

            try:
                with execution_scope(wait = True, timeout = 10) as session:
                    logger.info(f"{side.upper()} {size} {future_name}")
                    perpetual_order = LimitOrder(account = account,
                                        market = future_name,
                                        side = side,
                                        size = size,
                                        price = price,
                                        post_only = True)

                    session.add(perpetual_order)

            except TimeoutError:
                logger.debug(f'Timed out.  Retrying.')
                pass

            order_status = session.get_order_statuses()
            if len(order_status) == 0:
                # the order errored out
                logger.info(f'{side.upper()} {size} {future_name} FAILED')
                continue

            else:
                order_status = order_status[0]

                while order_status.status == "open":
                    time.sleep(0.1)
                    order_status = session.get_order_statuses()[0]

                filled_size = order_status.filled_size if order_status.side == "buy" else -order_status.filled_size

                if abs(filled_size) < 1e-8:
                    continue

                total_perpetual = sum([position.net_size for position in perpetual_positions])
                total_perpetual = total_perpetual + filled_size

                logger.info(f'Filled {filled_size} in {future_name} | Total: {total_perpetual}')
                break

if __name__ == '__main__':
    usage = "usage: " + sys.argv[0] + " <FTX Account Name> <Underlying> [optional-args]"
    parser = OptionParser(usage = usage)

    parser.add_option("-m", "--margin",
                      help="Margin target", type=float, dest="margin", default=0.2)
    parser.add_option("-l", "--margin-lower",
                      help="Lower bound threshold for margin (forced rebalance)", type=float, dest="margin_low", default=0.15)
    parser.add_option("-u", "--margin-upper",
                      help="Upper bound threshold for margin (forced rebalance)", type=float, dest="margin_high", default=0.25)
    parser.add_option("-f", "--force",
                      help="Force the trade to go through", dest="force", default=False, action="store_true")

    (options, args) = parser.parse_args()
    if len(args) < 2:
        print(usage)
        sys.exit(1)

    if options.margin < options.margin_low:
        print("Margin target must be higher than lower margin threshold.")
        sys.exit(0)

    if options.margin > options.margin_high:
        print("Margin target must be lower than upper margin threshold.")
        sys.exit(0)

    if options.margin < 0 or options.margin > 1:
        print("Margin target must be between 0-100%.")
        sys.exit(0)

    if options.margin_low < 0:
        print("Margin lower bound must be greater than 0%.")
        sys.exit(0)

    if options.margin_high > 1:
        print("Margin upper bound must be less than 100%.")
        sys.exit(0)

    account_name = args[0]
    underlying = args[1].upper()

    sm = SecurityMaster("FTX")
    try:
        market_spec = sm.get_market_spec(underlying + "/USD")
    except:
        logger.exception("Invalid underlying (does not exist in Securities Master database)")
        sys.exit(0)

    try:
        contract_spec = sm.get_contract_spec(underlying + '-PERP')
    except:
        logger.exception("No associated perpetual contract at FTX (does not exist in Securities Master database)")
        sys.exit(0)

    min_size = max(market_spec['sizeIncrement'], contract_spec['sizeIncrement'])

    try:
        ftx_account = FtxAccount(account_name)
        ftx_feed = FtxExchangeFeed(account_name)
    except Exception as e:
        logger.exception(e)
        sys.exit(0)

    static_cash_and_carry(ftx_account, ftx_feed, underlying,
                            cash_collateral_target = options.margin,
                            cash_collateral_bounds = (options.margin_low, options.margin_high),
                            minimum_size = min_size,
                            force = options.force)


class Warrior:
    def __init__(self):
        self.health = 50
        self.attack = 5

    @property
    def is_alive(self):
        return True if self.health > 0 else False

class Knight(Warrior):
    def __init__(self):
        super().__init__()
        self.attack = 7

def fight(unit_1, unit_2):
    while all([unit_1.is_alive, unit_2.is_alive]):
        unit_2.health -= unit_1.attack
        if unit_2.is_alive:
            unit_1.health -= unit_2.attack
    return unit_1.is_alive

if __name__ == '__main__':
    #These "asserts" using only for self-checking and not necessary for auto-testing

    chuck = Warrior()
    bruce = Warrior()
    carl = Knight()
    dave = Warrior()
    mark = Warrior()

    assert fight(chuck, bruce) == True
    assert fight(dave, carl) == False
    assert chuck.is_alive == True
    assert bruce.is_alive == False
    assert carl.is_alive == True
    assert dave.is_alive == False
    assert fight(carl, mark) == False
    assert carl.is_alive == False

    print("Coding complete? Let's try tests!")


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 21 10:02:17 2022

@author: valter
"""

from mechpy import Loads

M_0 = Loads.Load(tag='M0',
                 position=(0,0,0),
                 value=(0,'?',0),
                 load_type='m'
                 )

F_1 = Loads.Load(tag='F1',
                 position=(0,0,0),
                 value=('','',0)
                 )

F_2 = Loads.Load(tag='F2',
                 position=(3,0,0),
                 value=(0,'',0)
                 )

F_3 = Loads.Load(tag='F3',
                 position=(2,0,0),
                 value=(5,2,0)
                 )

T1 = Loads.Load(tag='T1',
                 position=(0,0,0),
                 value=(5,0,0),
                 load_type='m'
                 )

T2 = Loads.Load(tag='T2',
                 position=(2,0,0),
                 value=(-5,0,0),
                 load_type='m'
                 )

M1 = Loads.Load(tag='M1',
                 position=(2,0,0),
                 value=(0,1,0),
                 load_type='m'
                 )

R = Loads.solve_reactions(M_0,F_1,F_2,F_3,T1,T2,M1,
                          coords='ijk')
for key,value in R.items():
    print(f'{key} = {value}')

F_1.set_value([R['F1_x'],
               R['F1_y'],
               F_1.value_z])

F_2.set_value([F_2.value_x,
               R['F2_y'],
               F_2.value_z])

R_in,M_in = Loads.solve_internal(F_1,F_2,F_3,T1,T2,M1,
                                 F_graphs='xyz',
                                 M_graphs='xyz')


import os
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from tensorflow import keras
from tensorflow.keras import layers
import pandas as pd
from sklearn.linear_model import LogisticRegression

# Function to load the FER2013 dataset
def load_fer2013_dataset(dataset_dir):
    X = []  # List to store image data
    y = []  # List to store corresponding labels

    # Define emotion labels based on FER2013 dataset
    emotion_labels = ["angry", "disgust", "fear", "happy", "sad", "surprise", "neutral"]

    for emotion_label in emotion_labels:
        # Construct the path to the folder containing images of the current emotion
        emotion_dir = os.path.join(dataset_dir, emotion_label)

        # Loop through images in the folder
        for image_filename in os.listdir(emotion_dir):
            # Load and preprocess the image
            image_path = os.path.join(emotion_dir, image_filename)
            image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)  # Read image in grayscale
            image = cv2.resize(image, (48, 48))  # Resize to a common size (adjust as needed)

            # Append the image data and corresponding label
            X.append(image)
            y.append(emotion_labels.index(emotion_label))

    # Convert the lists to NumPy arrays
    X = np.array(X)
    y = np.array(y)

    return X, y

# Define the path to your FER2013 dataset folder
dataset_dir = "C:/Users/91950/Downloads/app (1)/train"

# Load the dataset
X, y = load_fer2013_dataset(dataset_dir)

# Split the dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Normalize pixel values (typically scaled between 0 and 1)
X_train = X_train / 255.0
X_test = X_test / 255.0

# Define your CNN model
model = keras.Sequential([
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(48, 48, 1)),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(128, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Flatten(),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(7, activation='softmax')  # 7 emotions
])

# Compile the model
model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.0001),
              loss='sparse_categorical_crossentropy',  # Since y is not one-hot encoded
              metrics=['accuracy'])

# Train the model
model.fit(X_train, y_train, epochs=5, batch_size=32, validation_data=(X_test, y_test))

# Initialize the camera
cap = cv2.VideoCapture(0)  # Use the default camera (you can specify a different camera if needed)

# Define emotion labels for displaying predictions
emotion_labels = ["Angry", "Disgust", "Fear", "Happy", "Sad", "Surprise", "Neutral"]

# Read the music recommendations from the CSV file
music_recommendations_csv = "C:/Users/91950/Downloads/app (1)/mu.xlsx"  # Adjust the filename and path as needed
music_recommendations_df = pd.read_excel(music_recommendations_csv)

# Initialize a logistic regression model
logistic_regression_model = LogisticRegression()
'''def apply_cartoon_filter(frame):
    # Convert the frame to grayscale
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Apply Gaussian blur to the grayscale image
    gray = cv2.medianBlur(gray, 5)

    # Detect edges using adaptive thresholding
    edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 9)

    # Apply a bilateral filter to smooth the image while preserving edges
    color = cv2.bilateralFilter(frame, 9, 300, 300)

    # Combine the color image and edges using bitwise and
    cartoon = cv2.bitwise_and(color, color, mask=edges)

    return cartoon'''
while True:
    # Capture a frame from the camera
    ret, frame = cap.read()
    '''if not ret:
        print("Error: Could not read frame")
        continue'''
    #cartoon_frame = apply_cartoon_filter(frame)
    # Preprocess the frame (resize and convert to grayscale)
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    frame_gray = cv2.resize(frame_gray, (48, 48))

    # Normalize pixel values (same as training data)
    frame_gray = frame_gray / 255.0

    # Make a prediction using the CNN model
    emotion_id = np.argmax(model.predict(np.expand_dims(frame_gray, axis=0)))
    predicted_emotion = emotion_labels[emotion_id]

    # Perform binary classification using logistic regression
    # Define a binary outcome based on your criteria (e.g., "Positive" or "Negative")
    # Modify this logic based on your criteria
    binary_outcome = 0  # Default to "Negative" (e.g., ["Fear", "Angry", "Sad"])
    if predicted_emotion in ["Happy", "Surprise", "Disgust", "Neutral"]:
        binary_outcome = 1  # Set to "Positive"

    # Display both the emotion and binary outcome on the frame
    cv2.putText(frame, f"Emotion: {predicted_emotion}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    cv2.putText(frame, f"Binary Outcome: {binary_outcome}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

    # Find music recommendations based on the detected emotion
    recommendations_for_emotion = music_recommendations_df[predicted_emotion].dropna().tolist()

    print(f"Top 3 Music Recommendations for {predicted_emotion}:")
    for i, recommendation in enumerate(recommendations_for_emotion[:3]):
        print(f"{i+1}. {recommendation}")

    # Display the frame
    cv2.imshow('Emotion Recognition', frame)

    # Exit the loop when 'q' is pressed
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release the camera and close the OpenCV windows
cap.release()
cv2.destroyAllWindows()


import os
import click
from sanic import Sanic
from sanic.response import json
from sanic_cors import CORS

from stage import add_route as stage_add_route

app = None

def path_check():
    path = os.path.join(os.getcwd(), 'tmp/')
    if not os.path.exists(path):
        os.mkdir(path)

@click.command()
@click.option('--host', default='0.0.0.0', type=str)
@click.option('--port', default=8000, type=int)
@click.option('--test', default=False, type=bool)
def run(host, port, test):
    path_check()
    global app
    app = Sanic()
    CORS(app)
    app.add_route(index, '/', methods=['GET'])
    stage_add_route(app)
    if not test:
        app.run(host=host, port=port)

async def index(request):
    return json({'success': True, 'data': 'Hello World!'})

if __name__ == '__main__':
    run()