# -*- coding: utf-8 -*-
# @Time : 2021/3/10 15:53
# @Author : Mr.WANG
# @Version :
# @Function :病人注册及收费
from unittests.pages.requestpage import R
from unittests.pages.logpage import Log
from unittests.pages.CSVpage import datapath, getdata
from unittests.pages.person_info import persominfo
from unittests.pages.configpage import conf
from unittests.pages.loginpage import Test_GetToken
import unittest
import random
import time

class Test_patient_mz(unittest.TestCase):
    # def setUp(self):
    #     file = datapath + '/logindata.xls'
    #     data = getdata(file)
    #     self.Authorization = Test_GetToken(data[0][0], data[0][1], data[0][2], data[0][3]).gettoken()
    #     self.g = globals()
    #     self.localhost = conf.getconf("main").url

    @classmethod
    def setUpClass(cls):
        file1 = datapath + '/logindata.xls'
        data1 = getdata(file1)
        cls.Authorization = Test_GetToken(data1[0][0], data1[0][1], data1[0][2], data1[0][3]).gettoken()
        cls.orgid = Test_GetToken(data1[0][0], data1[0][1], data1[0][2], data1[0][3]).get_orgid()
        cls.g = globals()
        cls.localhost = conf.getconf("main").url

    @classmethod
    def tearDownClass(cls):
        pass

    # def tearDown(self):
    #     pass

    def testcase_001_getdictionary(self):
        """获取病人注册相关各种字典id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-config/v1/dictionary/page'
            datas = {'pageNo': 1,
                     'pageSize': 10000}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            self.g['nation'] = lst[0]['id']
            self.g['sex'] = lst[1]['id']
            self.g['marry'] = lst[2]['id']
            self.g['profession'] = lst[3]['id']
            self.g['family'] = lst[4]['id']
            self.g['country'] = lst[5]['id']
            self.g['education'] = lst[6]['id']
            Log.logsinfo('病人注册相关字典id:{0}'.format(lst))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_002_getsexid(self):
        """获取性别id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-config/v1/dictionary-item/page'
            datas = {'pageNo': 1,
                     'pageSize': 10000,
                     'dictId': self.g['sex']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            if persominfo['sex'] == '男':
                self.g['sexid'] = lst[1]['id']
            elif persominfo['sex'] == '女':
                self.g['sexid'] = lst[3]['id']
            Log.logsinfo('病人性别:{0}，性别id：{1}'.format(persominfo['sex'], self.g['sexid']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_003_getcertificateTypeid(self):
        """获取证件类型id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-common/common-dictionary/org/list'
            datas = {'dictTypeId': 1205314304593182722}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            lst = respone['data']
            for i in lst:
                if i['dictValue'] == '居民户口本':
                    self.g['certificateTypeid'] = i['id']
                    Log.logsinfo('证据类型:居民户口本，证件id：{0}'.format(self.g['certificateTypeid']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_004_getcountryid(self):
        """获取国家id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-config/v1/dictionary-item/page'
            datas = {'pageNo': 1,
                     'pageSize': 10000,
                     'dictId': self.g['country']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            self.g['countyrid'] = lst[1]['id']
            Log.logsinfo('国籍:中国，国籍id：{0}'.format(self.g['countyrid']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_005_getnationid(self):
        """获取民族id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-config/v1/dictionary-item/page'
            datas = {'pageNo': 1,
                     'pageSize': 10000,
                     'dictId': self.g['nation']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            self.g['nationid'] = lst[0]['id']
            Log.logsinfo('民族id：{0}'.format(self.g['nationid']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_006_getmaritalStatusid(self):
        """获取婚姻状况id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-config/v1/dictionary-item/page'
            datas = {'pageNo': 1,
                     'pageSize': 10000,
                     'dictId': self.g['marry']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            self.g['maritalStatusid'] = lst[0]['id']
            Log.logsinfo('婚姻状况未婚id：{0}'.format(self.g['maritalStatusid']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_007_getcardTypeId(self):
        """获取金卡id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-common/v1/organization-card-type/valid-list'
            datas = {'orgId': self.orgid}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            lst = respone['data']
            for i in lst:
                if i['cardType'] == '金卡':
                    self.g['cardTypeid'] = i['id']
            Log.logsinfo('金卡id：{0}'.format(self.g['cardTypeid']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_008_getcardno(self):
        """获取金卡卡号"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-clinic/v1/patient-card/generateCardNumberByCardType/{0}'.format(
                self.g['cardTypeid'])
            datas = None
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            self.g['card_no'] = respone['data']
            Log.logsinfo('会员卡卡号：{0}'.format(self.g['card_no']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_009_patient_reg(self):
        """病人注册"""
        try:
            method = 'post'
            url = self.localhost + '/api/his-platform-global-clinic/v1/patient-card'
            data = {'threeNoPerson': False,
                    'crmId': '',
                    'id': '',
                    'groupPatientId': '',
                    'name': persominfo['name'],
                    'sex': self.g['sexid'],
                    'birthday': persominfo['birthday_stamp'],
                    'certificateType': self.g['certificateTypeid'],
                    'certificateNo': persominfo['idnum'],
                    'country': self.g['countyrid'],
                    'nation': self.g['nationid'],
                    'maritalStatus': self.g['maritalStatusid'],
                    'profession': '',
                    'educationLevel': '',
                    'phoneNo': persominfo['phone'],
                    'medicalInsuranceType': '',
                    'email': '',
                    'generalRegionProvince': '',
                    'generalRegionCity': '',
                    'generalRegionArea': '',
                    'domicileRegionProvince': '',
                    'domicileRegionCity': '',
                    'domicileRegionArea': '',
                    'mensesTime': '',
                    'remark': '',
                    'generalRegionDetail': '',
                    'domicileRegionDetail': '',
                    'contactName': '',
                    'contactRelationId': '',
                    'contactPhoneNo': '',
                    'orgPatientId': '',
                    'cardId': '',
                    'cardTypeId': self.g['cardTypeid'],
                    'cardNo': self.g['card_no'],
                    'cardPwd': 111111,
                    'invoiceType': '',
                    'lastMenstrualPeriod': '',
                    'billNo': '',
                    'paymentWayId': '',
                    'billTypeId': '',
                    'needCardNumberRule': '',
                    'cardStatus': 1,
                    'stamp': 2}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, data, headers)
            self.assertEqual(respone['code'], 200, msg=respone)
            self.g['groupPatientId'] = respone['data']['groupPatientId']
            self.g['orgPatientId'] = respone['data']['orgPatientId']
            Log.logsinfo('病人注册接口返回信息:{0}'.format(respone['data']))
            Log.logsinfo('病人身份信息：{0}'.format(persominfo))

        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            Log.logsinfo('病人身份信息：{0}'.format(persominfo))
            raise

    def testcase_010_regdiscounts(self):
        """获取挂号优惠信息"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-config-center/v1/registration-discount/page-list'
            datas = None
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            self.g['discount'] = random.choice(respone['data'])
            Log.logsinfo('挂号优惠信息：{0}'.format(self.g['discount']['registrationDiscountName']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_011_schedule_info(self):
        """获取医生排班信息"""
        try:
            t = time.strftime('%Y-%m-%d', time.localtime())
            method = 'post'
            paramtype = 'json'
            url = self.localhost + '/api/his-platform-global-clinic/v1/scheduling-setting/scheduleDoctorInfoPageForRegistration'
            datas = {"pageNo": 1, "pageSize": 20, "deptId": "", "orgId": self.orgid,
                     "scheduleDate": t, "scheduleDetailsId": "", "shiftId": [], "userId": []}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers, paramtype)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            for i in lst:
                if i['theSourceNumber'] == '0':
                    lst.remove(i)
            self.g['scheduleinfo'] = random.choice(lst)
            Log.logsinfo(
                '挂号医生信息:{0}，挂号科室信息:{1}'.format(self.g['scheduleinfo']['userName'], self.g['scheduleinfo']['deptName']))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_012_getclassinfo(self):
        """获取班次时间段信息"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-config-center/outCallClassesConfigController/page-list'
            datas = {'keyWord': '', 'pageNo': 1, 'pageSize': 1000}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '处理成功', msg=respone)
            lst = respone['data']['list']
            for i in lst:
                if i['id'] == self.g['scheduleinfo']['shiftId']:
                    self.g['visitShiftName'] = i['classesName'] + '（' + i['classesStartDate'] + '-' + i[
                        'classesEndDate'] + '）'

        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_013_getBillTypeId(self):
        """获取纸质发票id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-common/charge-business/getBillTypeIdByBusinessCode'
            datas = {'businessCode': 'registration'}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            self.g['BillTypeId'] = respone['data']

        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_014_getBillNo(self):
        """获取纸质发票流水号"""
        try:
            method = 'get'
            url = self.localhost + '/api/global-bill/v1/bill/use/getBillNowNo'
            datas = {'billTypeId': self.g['BillTypeId']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            self.g['billno'] = respone['data']['nowNum']

        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_015_PayMoneyInfo(self):
        """获取挂号实际支付信息"""
        try:
            method = 'post'
            paramtype = 'json'
            url = self.localhost + '/api/his-platform-global-clinic/v1/globalRegistrationSystem/selectScheduleToCountMoney'
            datas = {"cardNo": self.g['card_no'], "deptId": self.g['scheduleinfo']['deptId'],
                     "fee": self.g['scheduleinfo']['fee'], "isEnjoyDiscountCard": 0,
                     "payCardNo": self.g['card_no'], "registrationDiscountId": self.g['discount']['id'],
                     "scheduleDetailsId": self.g['scheduleinfo']['scheduleDetailsId'],
                     "shiftId": self.g['scheduleinfo']['shiftId'],
                     "userId": self.g['scheduleinfo']['userId'], "visitLevelId": self.g['scheduleinfo']['visitLevelId']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers, paramtype)
            self.assertEqual(respone['msg'], '', msg=respone)
            self.g['PayInfo'] = respone['data']
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_016_getTreatmentTypeId(self):
        """获取治疗类型id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-config-center/v1/treatment/type/list'
            datas = {'orgId': self.orgid}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            lst = respone['data']
            for i in lst:
                if i['name'] == '门诊':
                    self.g['TreatmenTypeId'] = i['id']
                    self.g['TreatmenTypeName'] = i['name']

        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_017_getPayWayTypeId(self):
        """获取支付方式id"""
        try:
            method = 'get'
            url = self.localhost + '/api/his-platform-global-common/charge-business/list'
            datas = {'businessCode': 'registration',
                     'cardNo': self.g['card_no']}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers)
            self.assertEqual(respone['msg'], '', msg=respone)
            lst = respone['data']
            for i in lst:
                if i['businessDesc'] == '挂号':
                    PayWayList = i['payWayList']
            for j in PayWayList:
                for key, value in j.items():
                    if value == '现金':
                        self.g['PayWayTypeId'] = key

        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

    def testcase_018_registration(self):
        """挂号"""
        try:
            method = 'post'
            paramtype = 'json'
            url = self.localhost + '/api/his-platform-global-clinic/v1/globalRegistrationSystem/registrationRecord'
            datas = {"orgId": self.orgid, "groupId": None, "groupPatientId": self.g['groupPatientId'],
                     "orgPatientId": self.g['orgPatientId'], "cardTypeId": self.g['cardTypeid'], "cardTypeName": "金卡",
                     "cardStatus": "1", "patientName": persominfo['name'], "birthDate": persominfo['birthday_stamp'],
                     "phoneNo": persominfo['phone'], "sex": self.g['sexid'], "age": persominfo['age'],
                     "cardBalance": None, "balanceAmount": None, "cardDiscount": None,
                     "insideDiscount": None, "extWhetherDiscount": None, "vipCard": None, "allowCharge": None,
                     "payCardNo": self.g['card_no'], "cardNo": self.g['card_no'], "other": None, "registrationType": 1,
                     "discountMoneyOfRegistration": self.g['PayInfo']['discountMoneyOfRegistration'],
                     "discountMonetOfmemberCard": self.g['PayInfo']['discountMonetOfmemberCard'],
                     "isEnjoyDiscountCard": self.g['PayInfo']['isEnjoyDiscountCard'],
                     "invoiceNo": self.g['billno'], "payMoney": self.g['PayInfo']['payMoney'],
                     "registrationDiscountId": self.g['discount']['id'],
                     "invoiceType": 2,
                     "treatmentTypeName": self.g['TreatmenTypeName'], "treatmentTypeId": self.g['TreatmenTypeId'],
                     "billTypeId": self.g['BillTypeId'],
                     "classesName": None, "deptId": self.g['scheduleinfo']['deptId'],
                     "deptName": self.g['scheduleinfo']['deptName'], "fee": self.g['scheduleinfo']['fee'],
                     "scheduleDetailsId": self.g['scheduleinfo']['scheduleDetailsId'],
                     "shiftId": self.g['scheduleinfo']['shiftId'],
                     "userId": self.g['scheduleinfo']['userId'],
                     "userName": self.g['scheduleinfo']['userName'],
                     "visitLevelId": self.g['scheduleinfo']['visitLevelId'],
                     "visitLevelName": self.g['scheduleinfo']['visitLevelName'],
                     "visitShiftName": self.g['visitShiftName'],
                     "visitTimeDate": self.g['scheduleinfo']['scheduleDate'],
                     "sourceNumberType": self.g['scheduleinfo']['sourceNumberWay'],
                     "categoryDTOForMtList": self.g['PayInfo']['categoryDTOForMtList'],
                     "feeDetailForPackageDTOS": self.g['PayInfo']['feeDetailForPackageDTOS'],
                     "discountMembercardId": self.g['card_no'], "payCardId": self.g['PayInfo']['payCardId'],
                     "isPrintInvoice": True,
                     "tradeRecordPaymentTypeRequests": [
                         {"paymentType": self.g['PayWayTypeId'], "paymentTypeName": "现金",
                          "payAmount": self.g['PayInfo']['payMoney'],
                          "payType": 1}],
                     "gender": self.g['sexid'], "remark": ""}
            headers = {'Authorization': self.Authorization}
            respone = R.request(method, url, datas, headers, paramtype)
            self.assertEqual(respone['msg'], '挂号成功！', msg=respone)
            registrationID = respone['data']['id']
            Log.logsinfo('挂号记录ID：{0}'.format(registrationID))
        except Exception as e:
            Log.logsinfo(self._testMethodName + '\n' + str(e))
            raise

if __name__ == '__main__':
    unittest.main()


#%%
from pprint import pprint
from rasa.nlu.model import Interpreter

utterance = u"what was my energy consumption for yesterday"
model = "./models/nlu"

# loading the model from one directory or zip file
interpreter = Interpreter.load(model)

# parsing the utterance
interpretation = interpreter.parse(utterance)

# printing the parsed output
pprint(interpretation)

# %%

#hjzdcekjhzbcjehbdzjce


import random

def start_game():
    hands = ['R', 'P', 'S']
    loop_hole = 0

    print('Starting the Rock Paper Scissors game!')
    player_name = input('Please enter your name: ')

    while loop_hole == 0:
        print('Pick a hand: (R for Rock, P for Paper, S for Scissors)')
        player_hand = input('Please enter a hand: ')
        player_hand.upper()

        for x in player_hand:
            if player_hand == 'R' or 'P' or 'S':

                cpu_hand = random.choice(hands)

                print(player_name.capitalize() + '(' + player_hand.upper() + ')' + " : " "CPU" + '(' + cpu_hand + ')')

                if player_hand == 'R' and cpu_hand == 'S':
                    print("Congratulations, You Won")
                    loop_hole += 1

                elif player_hand == 'S' and cpu_hand == 'P':
                    print("Congratulations, You Won")
                    loop_hole += 1

                elif player_hand == 'P' and cpu_hand == 'R':
                    print("Congratulations, You Won")
                    loop_hole += 1

                elif player_hand == cpu_hand:
                    print("It's a tie")

                else:
                    print("You lose")
                    loop_hole += 1

            else:
                print("Please enter a valid hand, try again")

start_game()


import time
import datetime
import base64
import picamera

#base64 image function
def base64Image():
        filename = '/home/pi/Desktop/SeniorDesign/ProjectCode/Images/' + datetime.datetime.now().strftime("%Y-%m-%d-%H.%M.%S.jpg")

        cam = picamera.PiCamera()
        cam.resolution = (640, 480)
        cam.capture(filename)
        time.sleep(.5)

        image = open(filename, 'rb')
        image_read = image.read()
        image_64_encode = base64.encodestring(image_read)

        return image_64_encode


import json
import logging
import os
from datetime import datetime

from dictdiffer import diff
from dotenv import load_dotenv
from logger import setup_logger

from utils import get_new_token, get_order_status, notify

logger = setup_logger(__name__, logging.DEBUG)

load_dotenv()

line_token = os.getenv("LINE_TOKEN")
tesla_token = os.getenv("TESLA_TOKEN")
tesla_refresh_token = os.getenv("TESLA_REFRESH_TOKEN")

# test get_new_token

try:
    new_token = get_new_token(tesla_token, tesla_refresh_token)
except Exception as e:
    notify(f"Error in get_new_token \n\n{e}", line_token)
    logger.error(e)
    raise e

if new_token["access_token"] != tesla_token:
    logger.debug("New token is generated")

    # save new token to .env
    with open(".env", "w") as f:
        f.writelines(
            [
                "# Refresh on " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n",
                f"LINE_TOKEN={line_token}\n",
                "TESLA_TOKEN=" + new_token["access_token"] + "\n",
                "TESLA_REFRESH_TOKEN=" + new_token["refresh_token"] + "\n",
            ]
        )

    tesla_token = new_token["access_token"]

# get order status

# load old status from data/status.json if exists
old_status = {}
if os.path.exists("data/status.json"):
    with open("data/status.json", "r") as f:
        old_status = json.load(f)

new_status = get_order_status(tesla_token)

# get diffwith dictdiffer

diffs = list(diff(old_status, new_status))

# Notify if there is any change

if diffs:
    logger.debug(diffs)

    change_msg = []
    for change in diffs:
        msg = ""
        change_pos = change[1]
        if not isinstance(change_pos, str):
            change_pos = ".".join([str(i) for i in change_pos])
        if change_pos == "":
            change_pos = "root"

        if change[0] == "add":
            msg += f"New Value At: {change_pos}\n"
            msg += f"Value: {change[2]}\n"
        elif change[0] == "change":
            msg += f"Change At: {change_pos}\n"
            msg += f"Old value: {change[2][0]}\n"
            msg += f"New value: {change[2][1]}\n"
        elif change[0] == "remove":
            msg += f"Remove: {change_pos}\n"
        change_msg += [msg]

    out_msg = "There is a change in order status\n\n"
    out_msg += f'\n{"*"*10}\n\n'.join(change_msg)
    logger.info(out_msg)
    notify(out_msg, line_token)
else:
    logger.info("No change")

# save new status to data/status.json
with open("data/status.json", "w") as f:
    json.dump(new_status, f, indent=2)


__author__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"

import sys
import os
import numpy
import logging
from PyMca5 import StackPluginBase
from PyMca5.PyMcaGui import PyMcaQt as qt
from PyMca5.PyMcaGui import FFTAlignmentWindow
from PyMca5.PyMcaMath import ImageRegistration
from PyMca5.PyMcaMath.fitting import SpecfitFuns
from PyMca5.PyMcaGui.misc import CalculationThread
from PyMca5.PyMcaIO import ArraySave
from PyMca5.PyMcaGui.io import PyMcaFileDialogs
from PyMca5.PyMcaIO import specfilewrapper
from PyMca5.PyMcaGui import HDF5Widget

_logger = logging.getLogger(__name__)

try:
    from PyMca5.PyMcaGui.math import SIFTAlignmentWindow
    sift = SIFTAlignmentWindow.sift
    ocl = SIFTAlignmentWindow.silx.opencl.ocl
    SIFT = True
except Exception:
    _logger.info("SIFTAlignmentWindow not successful")
    SIFT = False

try:
    import h5py
    HDF5 = True
except Exception:
    HDF5 = False

class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase):
    def __init__(self, stackWindow, **kw):
        if _logger.getEffectiveLevel() == logging.DEBUG:
            StackPluginBase.pluginBaseLogger.setLevel(logging.DEBUG)
        StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw)
        self.methodDict = {'FFT Alignment':[self._fftAlignment,
                                            "Align using FFT",
                                            None]}
        self.__methodKeys = ['FFT Alignment']
        if SIFT:
            key = 'SIFT Alignment'
            self.methodDict[key] = [self._siftAlignment,
                                    "Align using SIFT Algorithm",
                                    None]
            self.__methodKeys.append(key)
        key = 'From File Alignment'
        self.methodDict[key] = [self._shiftFromFile,
                                "Align using shifts from file",
                                None]
        self.__methodKeys.append(key)
        self.widget = None

    def stackUpdated(self):
        self.widget = None

    #Methods implemented by the plugin
    def getMethods(self):
        return self.__methodKeys

    def getMethodToolTip(self, name):
        return self.methodDict[name][1]

    def getMethodPixmap(self, name):
        return self.methodDict[name][2]

    def applyMethod(self, name):
        return self.methodDict[name][0]()

    def _fftAlignment(self):
        stack = self.getStackDataObject()
        if stack is None:
            return
        mcaIndex = stack.info.get('McaIndex')
        if not (mcaIndex in [0, -1, 2]):
            raise IndexError("1D index must be 0, 2, or -1")

        if self.widget is None:
            self.widget = FFTAlignmentWindow.FFTAlignmentDialog()
        self.widget.setStack(stack)
        ret = self.widget.exec()
        if ret:
            ddict = self.widget.getParameters()
            self.widget.setDummyStack()
            offsets = [ddict['Dim 0']['offset'], ddict['Dim 1']['offset']]
            widths = [ddict['Dim 0']['width'], ddict['Dim 1']['width']]
            if mcaIndex == 0:
                reference = stack.data[ddict['reference_index']]
            else:
                reference = ddict['reference_image']
            crop = False
            if ddict['file_use']:
                filename = ddict['file_name']
            else:
                filename = None
            if filename is not None:
                self.__hdf5 = self.initializeHDF5File(filename)

            if _logger.getEffectiveLevel() == logging.DEBUG:
                shifts = self.calculateShiftsFFT(stack,
                                                 reference,
                                                 offsets=offsets,
                                                 widths=widths,
                                                 crop=crop)
                result = self.shiftStack(stack,
                                         shifts,
                                         crop=crop,
                                         filename=filename)
            else:
                result = self.__calculateShiftsFFT(stack,
                                                   reference,
                                                   offsets=offsets,
                                                   widths=widths,
                                                   crop=crop)
                # result[0] contains the string "Exception" in case
                # of error. However, direct comparison will raise an
                # error
                if isinstance(result[0], str):
                    if result[0] == 'Exception':
                        # exception occurred
                        raise Exception(result[1], result[2], result[3])
                else:
                    shifts = result
                result = self.__shiftStack(stack,
                                           shifts,
                                           crop=crop,
                                           filename=filename)
                if result is not None:
                    # exception occurred
                    raise Exception(result[1], result[2], result[3])
            if filename is not None:
                hdf = self.__hdf5
                alignmentGroup = hdf['/entry_000/Alignment']
                outputShifts = self.getHDF5BufferIntoGroup(alignmentGroup,
                                                     shape=(stack.data.shape[mcaIndex], 2),
                                                     name="shifts",
                                                     dtype=numpy.float32)
                outputShifts[:,:] = shifts
                attributes={'interpretation':'image'}
                referenceFrame = self.getHDF5BufferIntoGroup(alignmentGroup,
                                                     shape=reference.shape,
                                                     name="reference_frame",
                                                     dtype=numpy.float32,
                                                     attributes=attributes)
                referenceFrame[:,:] = reference[:,:]
                maskFrame = self.getHDF5BufferIntoGroup(alignmentGroup,
                                                   shape=reference.shape,
                                                   name="reference_mask",
                                                   dtype=numpy.uint8,
                                                   attributes=attributes)

                maskData = numpy.zeros(reference.shape, dtype=numpy.uint8)
                maskData[offsets[0]:offsets[0] + widths[0], offsets[1] : offsets[1] + widths[1]] = 1
                maskFrame[:,:] = maskData[:,:]
                # fill the axes information
                dataGroup = hdf['/entry_000/Data']
                try:
                    activeCurve = self.getActiveCurve()
                    if activeCurve is None:
                        activeCurve = self.getAllCurves()[0]
                    x, y, legend, info = activeCurve
                    dataGroup[info['xlabel']] = numpy.array(x, dtype=numpy.float32)
                    dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1)
                    axesAttribute = '%s:dim_1:dim_2' % info['xlabel']
                except Exception:
                    if _logger.getEffectiveLevel() == logging.DEBUG:
                        raise
                    dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32)
                    dataGroup['dim_0'].attrs['axis'] = numpy.int32(1)
                    axesAttribute = 'dim_0:dim_1:dim_2'
                dataGroup['dim_1'] = numpy.arange(reference.shape[0]).astype(numpy.float32)
                dataGroup['dim_1'].attrs['axis'] = numpy.int32(2)
                dataGroup['dim_2'] = numpy.arange(reference.shape[1]).astype(numpy.float32)
                dataGroup['dim_2'].attrs['axis'] = numpy.int32(3)
                dim2 = numpy.arange(reference.shape[1]).astype(numpy.float32)
                dataGroup['data'].attrs['axes'] = axesAttribute
                self.finishHDF5File(hdf)
            else:
                self.setStack(stack)

    def __calculateShiftsFFT(self, *var, **kw):
        self._progress = 0.0
        thread = CalculationThread.CalculationThread(\
                calculation_method=self.calculateShiftsFFT,
                calculation_vars=var,
                calculation_kw=kw)
        thread.start()
        CalculationThread.waitingMessageDialog(thread,
                                               message="Please wait. Calculation going on.",
                                               parent=self.widget,
                                               modal=True,
                                               update_callback=self._waitingCallback)
        return thread.result

    def __shiftStack(self, *var, **kw):
        self._progress = 0.0
        thread = CalculationThread.CalculationThread(\
                calculation_method=self.shiftStack,
                calculation_vars=var,
                calculation_kw=kw)
        thread.start()
        CalculationThread.waitingMessageDialog(thread,
                                               message="Please wait. Calculation going on.",
                                               parent=self.widget,
                                               modal=True,
                                               update_callback=self._waitingCallback)
        return thread.result

    def __calculateShiftsSIFT(self, *var, **kw):
        self._progress = 0.0
        thread = CalculationThread.CalculationThread(\
                calculation_method=self.calculateShiftsSIFT,
                calculation_vars=var,
                calculation_kw=kw)
        thread.start()
        CalculationThread.waitingMessageDialog(thread,
                                               message="Please wait. Calculation going on.",
                                               parent=self.widget,
                                               modal=True,
                                               update_callback=self._waitingCallback)
        return thread.result

    def _waitingCallback(self):
        ddict = {}
        ddict['message'] = "Calculation Progress = %d %%" % self._progress
        return ddict

    def _siftAlignment(self):
        if not SIFT:
            try:
                import pyopencl
            except Exception:
                raise ImportError("PyOpenCL does not seem to be installed on your system")
        if ocl is None:
            raise ImportError("PyOpenCL does not seem to be installed on your system")
        stack = self.getStackDataObject()
        if stack is None:
            return
        mcaIndex = stack.info.get('McaIndex')
        if not (mcaIndex in [0, 2, -1]):
            raise IndexError("Unsupported 1D index %d" % mcaIndex)
        widget = SIFTAlignmentWindow.SIFTAlignmentDialog()
        widget.setStack(stack)
        mask = self.getStackSelectionMask()
        widget.setSelectionMask(mask)
        ret = widget.exec()
        if ret:
            ddict = widget.getParameters()
            widget.setDummyStack()
            reference = ddict['reference_image']
            mask = ddict['mask']
            if ddict['file_use']:
                filename = ddict['file_name']
            else:
                filename = None
            if filename is not None:
                self.__hdf5 = self.initializeHDF5File(filename)
            crop = False
            device = ddict['opencl_device']
            if _logger.getEffectiveLevel() == logging.DEBUG:
                result = self.calculateShiftsSIFT(stack, reference, mask=mask, device=device,
                                                  crop=crop, filename=filename)
            else:
                result = self.__calculateShiftsSIFT(stack, reference, mask=mask, device=device,
                                                    crop=crop, filename=filename)
                if result is not None:
                    if len(result):
                        if isinstance(result[0], str):
                            if result[0] == 'Exception':
                                # exception occurred
                                raise Exception(result[1], result[2], result[3])
            if filename is None:
                self.setStack(stack)

    def calculateShiftsSIFT(self, stack, reference, mask=None, device=None, crop=None,
                            sigma=None,
                            filename=None):
        mask = self.getStackSelectionMask()
        if mask is not None:
            if mask.sum() == 0:
                mask = None
        if device is None:
            siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
                                            devicetype="cpu",
                                            init_sigma=sigma)
        else:
            siftInstance = sift.LinearAlign(reference.astype(numpy.float32),
                                            deviceid=device,
                                            init_sigma=sigma)
        data = stack.data
        mcaIndex = stack.info['McaIndex']
        if not (mcaIndex in [0, 2, -1]):
             raise IndexError("Unsupported 1D index %d" % mcaIndex)
        total = float(data.shape[mcaIndex])
        if filename is not None:
            hdf = self.__hdf5
            dataGroup = hdf['/entry_000/Data']
            attributes = {}
            attributes['interpretation'] = "image"
            attributes['signal'] = numpy.int32(1)
            outputStack = self.getHDF5BufferIntoGroup(dataGroup,
                                                      shape=(data.shape[mcaIndex],
                                                            reference.shape[0],
                                                            reference.shape[1]),
                                                      name="data",
                                                      dtype=numpy.float32,
                                                      attributes=attributes)
        shifts = numpy.zeros((data.shape[mcaIndex], 2), dtype=numpy.float32)
        if mcaIndex == 0:
            for i in range(data.shape[mcaIndex]):
                _logger.debug("SIFT Shifting image %d", i)
                result = siftInstance.align(data[i].astype(numpy.float32), shift_only=True, return_all=True)
                _logger.debug("Index = %d shift = %.4f, %.4f",
                              i, result['offset'][0], result['offset'][1])
                if filename is None:
                    stack.data[i] = result['result']
                else:
                    outputStack[i] = result['result']
                shifts[i, 0] = result['offset'][0]
                shifts[i, 1] = result['offset'][1]
                self._progress = (100 * i) / total
        else:
            image2 = numpy.zeros(reference.shape, dtype=numpy.float32)
            for i in range(data.shape[mcaIndex]):
                _logger.debug("SIFT Shifting image %d", i)
                image2[:, :] = data[:, :, i]
                result = siftInstance.align(image2, shift_only=True, return_all=True)
                _logger.debug("Index = %d shift = %.4f, %.4f",
                              i, result['offset'][0], result['offset'][1])
                if filename is None:
                    stack.data[:, :, i] = result['result']
                else:
                    outputStack[i] = result['result']
                shifts[i, 0] = result['offset'][0]
                shifts[i, 1] = result['offset'][1]
                self._progress = (100 * i) / total
        if filename is not None:
            hdf = self.__hdf5
            alignmentGroup = hdf['/entry_000/Alignment']
            outputShifts = self.getHDF5BufferIntoGroup(alignmentGroup,
                                                 shape=(stack.data.shape[mcaIndex], 2),
                                                 name="shifts",
                                                 dtype=numpy.float32)
            outputShifts[:,:] = shifts
            attributes={'interpretation':'image'}
            referenceFrame = self.getHDF5BufferIntoGroup(alignmentGroup,
                                                 shape=reference.shape,
                                                 name="reference_frame",
                                                 dtype=numpy.float32,
                                                 attributes=attributes)
            referenceFrame[:,:] = reference[:,:]
            maskFrame = self.getHDF5BufferIntoGroup(alignmentGroup,
                                               shape=reference.shape,
                                               name="reference_mask",
                                               dtype=numpy.uint8,
                                               attributes=attributes)

            if mask is None:
                maskData = numpy.ones(reference.shape, dtype=numpy.uint8)
            else:
                maskData = mask
            maskFrame[:,:] = maskData[:,:]
            # fill the axes information
            dataGroup = hdf['/entry_000/Data']
            try:
                activeCurve = self.getActiveCurve()
                if activeCurve is None:
                    activeCurve = self.getAllCurves()[0]
                x, y, legend, info = activeCurve
                dataGroup[info['xlabel']] = numpy.array(x, dtype=numpy.float32)
                dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1)
                axesAttribute = '%s:dim_1:dim_2' % info['xlabel']
            except Exception:
                if _logger.getEffectiveLevel() == logging.DEBUG:
                    raise
                dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32)
                dataGroup['dim_0'].attrs['axis'] = numpy.int32(1)
                axesAttribute = 'dim_0:dim_1:dim_2'
            dataGroup['dim_1'] = numpy.arange(reference.shape[0]).astype(numpy.float32)
            dataGroup['dim_1'].attrs['axis'] = numpy.int32(2)
            dataGroup['dim_2'] = numpy.arange(reference.shape[1]).astype(numpy.float32)
            dataGroup['dim_2'].attrs['axis'] = numpy.int32(3)
            dim2 = numpy.arange(reference.shape[1]).astype(numpy.float32)
            dataGroup['data'].attrs['axes'] = axesAttribute
            self.finishHDF5File(hdf)

    def calculateShiftsFFT(self, stack, reference, offsets=None, widths=None, crop=False):
        _logger.debug("Offsets = %s", offsets)
        _logger.debug("Widths = %s", widths)
        data = stack.data
        if offsets is None:
            offsets = [0.0, 0.0]
        if widths is None:
            widths = [reference.shape[0], reference.shape[1]]
        fft2Function = numpy.fft.fft2
        if 1:
            DTYPE = numpy.float32
        else:
            DTYPE = numpy.float64
        image2 = numpy.zeros((widths[0], widths[1]), dtype=DTYPE)
        shape = image2.shape

        USE_APODIZATION_WINDOW = False
        apo = [10, 10]
        if USE_APODIZATION_WINDOW:
            # use apodization window
            window = numpy.outer(SpecfitFuns.slit([0.5, shape[0] * 0.5, shape[0] - 4 * apo[0], apo[0]],
                                          numpy.arange(float(shape[0]))),
                                 SpecfitFuns.slit([0.5, shape[1] * 0.5, shape[1] - 4 * apo[1], apo[1]],
                                          numpy.arange(float(shape[1])))).astype(DTYPE)
        else:
            window = numpy.zeros((shape[0], shape[1]), dtype=DTYPE)
            window[apo[0]:shape[0] - apo[0], apo[1]:shape[1] - apo[1]] = 1
        image2[:,:] = window * reference[offsets[0]:offsets[0]+widths[0],
                                         offsets[1]:offsets[1]+widths[1]]
        image2fft2 = fft2Function(image2)
        mcaIndex = stack.info.get('McaIndex')
        shifts = numpy.zeros((data.shape[mcaIndex], 2), numpy.float64)
        image1 = numpy.zeros(image2.shape, dtype=DTYPE)
        total = float(data.shape[mcaIndex])
        if mcaIndex == 0:
            for i in range(data.shape[mcaIndex]):
                image1[:,:] = window * data[i][offsets[0]:offsets[0]+widths[0],
                                               offsets[1]:offsets[1]+widths[1]]

                image1fft2 = fft2Function(image1)
                shifts[i] = ImageRegistration.measure_offset_from_ffts(image2fft2,
                                                                       image1fft2)
                _logger.debug("Index = %d shift = %.4f, %.4f",
                              i, shifts[i][0], shifts[i][1])
                self._progress = (100 * i) / total
        elif mcaIndex in [2, -1]:
            for i in range(data.shape[mcaIndex]):
                image1[:,:] = window * data[:,:,i][offsets[0]:offsets[0]+widths[0],
                                               offsets[1]:offsets[1]+widths[1]]

                image1fft2 = fft2Function(image1)
                shifts[i] = ImageRegistration.measure_offset_from_ffts(image2fft2,
                                                                       image1fft2)
                _logger.debug("Index = %d shift = %.4f, %.4f",
                              i, shifts[i][0], shifts[i][1])
                self._progress = (100 * i) / total
        else:
            raise IndexError("Only stacks of images or spectra supported. 1D index should be 0 or 2")
        return shifts

    def _shiftFromFile(self):
        stack = self.getStackDataObject()
        if stack is None:
            return
        data = stack.data
        mcaIndex = stack.info.get('McaIndex')
        if not (mcaIndex in [0, -1, 2]):
            raise IndexError("1D index must be 0, 2, or -1")
        filefilter = ['HDF5 Files (*.h5 *.nxs *.hdf *.hdf5)', 'CSV 2-column (*.csv)', 'ASCII 2-column (*)']
        filename, ffilter = PyMcaFileDialogs.\
                    getFileList(parent=None,
                        filetypelist=filefilter,
                        message='Load',
                        mode='OPEN',
                        single=True,
                        getfilter=True,
                        currentfilter=filefilter[0])
        if len(filename):
            _logger.debug("file name = %s file filter = %s", filename, ffilter)
        else:
            _logger.debug("nothing selected")
            return
        filename = filename[0]
        if ffilter.startswith('HDF5'):
            # browse
            self.__hdf5Dialog = qt.QDialog()
            self.__hdf5Dialog.setWindowTitle('Select your data set by a double click')
            self.__hdf5Dialog.mainLayout = qt.QVBoxLayout(self.__hdf5Dialog)
            self.__hdf5Dialog.mainLayout.setContentsMargins(0, 0, 0, 0)
            self.__hdf5Dialog.mainLayout.setSpacing(0)
            fileModel = HDF5Widget.FileModel()
            fileView = HDF5Widget.HDF5Widget(fileModel)
            with h5py.File(filename, "r") as hdfFile:
                fileModel.appendPhynxFile(hdfFile, weakreference=True)
                self.__shiftsDataset = None
                fileView.sigHDF5WidgetSignal.connect(self._hdf5WidgetSlot)
                self.__hdf5Dialog.mainLayout.addWidget(fileView)
                self.__hdf5Dialog.resize(400, 200)
                ret = self.__hdf5Dialog.exec()
                if not ret:
                    return
                shifts = hdfFile[self.__shitfsDataset].value
        else:
            sf = specfilewrapper.Specfile(filename)
            nScans = len(sf)
            targetScan = None
            for scan in sf:
                if scan.lines() ==  data.shape[stack.info['McaIndex']]:
                    targetScan = scan
                    break
            if targetScan is None:
                scan = None
                sf = None
                raise IOError("Number of read lines does not match stack shape")
            shifts = targetScan.data()
            targetScan = None
            scan = None
            sf = None
            if shifts.shape[0] == 3 and\
               shifts.shape[1] == data.shape[stack.info['McaIndex']]:
                # one column was added (point number)
                shifts = shifts[1:].T

        filename = None
        if not isinstance(data, numpy.ndarray):
            filefilter = ['HDF5 Files (*.h5)']
            filename = PyMcaFileDialogs.\
                        getFileList(parent=None,
                        filetypelist=filefilter,
                        message='Select output file',
                        mode='SAVE',
                        single=True,
                        getfilter=False,
                        currentfilter=filefilter[0])
            if len(filename):
                filename = filename[0]
                _logger.debug("file name = %s", filename)
            else:
                raise IOError("No output file selected")
        if filename is not None:
            self.__hdf5 = self.initializeHDF5File(filename)
        crop = False
        if _logger.getEffectiveLevel() == logging.DEBUG:
            result = self.shiftStack(stack,
                                     shifts,
                                     crop=crop,
                                     filename=filename)
        else:
            result = self.__shiftStack(stack,
                                       shifts,
                                       crop=crop,
                                       filename=filename)
            if result is not None:
                # exception occurred
                raise Exception(result[1], result[2], result[3])

        if filename is not None:
            hdf = self.__hdf5
            alignmentGroup = hdf['/entry_000/Alignment']
            outputShifts = self.getHDF5BufferIntoGroup(alignmentGroup,
                                                 shape=(stack.data.shape[mcaIndex], 2),
                                                 name="shifts",
                                                 dtype=numpy.float32)
            outputShifts[:,:] = shifts
            attributes={'interpretation':'image'}
            # fill the axes information
            dataGroup = hdf['/entry_000/Data']
            if mcaIndex == 0:
                reference_shape = data[0].shape
            else:
                reference_shape = data.shape[0], data.shape[1]
            try:
                activeCurve = self.getActiveCurve()
                if activeCurve is None:
                    activeCurve = self.getAllCurves()[0]
                x, y, legend, info = activeCurve
                dataGroup[info['xlabel']] = numpy.array(x, dtype=numpy.float32)
                dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1)
                axesAttribute = '%s:dim_1:dim_2' % info['xlabel']
            except Exception:
                if _logger.getEffectiveLevel() == logging.DEBUG:
                    raise
                dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32)
                dataGroup['dim_0'].attrs['axis'] = numpy.int32(1)
                axesAttribute = 'dim_0:dim_1:dim_2'
            dataGroup['dim_1'] = numpy.arange(reference_shape[0]).astype(numpy.float32)
            dataGroup['dim_1'].attrs['axis'] = numpy.int32(2)
            dataGroup['dim_2'] = numpy.arange(reference_shape[1]).astype(numpy.float32)
            dataGroup['dim_2'].attrs['axis'] = numpy.int32(3)
            dim2 = numpy.arange(reference_shape[1]).astype(numpy.float32)
            dataGroup['data'].attrs['axes'] = axesAttribute
            self.finishHDF5File(hdf)
        else:
            self.setStack(stack)

    def _hdf5WidgetSlot(self, ddict):
        if ddict['event'] == "itemDoubleClicked":
            if ddict['type'].lower() in ['dataset']:
                self.__shitfsDataset = ddict['name']
                self.__hdf5Dialog.accept()

    def shiftStack(self, stack, shifts, crop=False, filename=None):
        """
        """
        data = stack.data
        mcaIndex = stack.info['McaIndex']
        if mcaIndex not in [0, 2, -1]:
             raise IndexError("Only stacks of images or spectra supported. 1D index should be 0 or 2")
        if mcaIndex == 0:
            shape = data[mcaIndex].shape
        else:
            shape = data.shape[0], data.shape[1]
        d0_start, d0_end, d1_start, d1_end = \
                  ImageRegistration.get_crop_indices(shape,
                                                     shifts[:, 0],
                                                     shifts[:, 1])
        window = numpy.zeros(shape, numpy.float32)
        window[d0_start:d0_end, d1_start:d1_end] = 1.0
        self._progress = 0.0
        total = float(data.shape[mcaIndex])
        if filename is not None:
            hdf = self.__hdf5
            dataGroup = hdf['/entry_000/Data']
            attributes = {}
            attributes['interpretation'] = "image"
            attributes['signal'] = numpy.int32(1)
            outputStack = self.getHDF5BufferIntoGroup(dataGroup,
                                                      shape=(data.shape[mcaIndex],
                                                            shape[0],
                                                            shape[1]),
                                                      name="data",
                                                      dtype=numpy.float32,
                                                      attributes=attributes)
        for i in range(data.shape[mcaIndex]):
            #tmpImage = ImageRegistration.shiftFFT(data[i], shifts[i])
            if mcaIndex == 0:
                tmpImage = ImageRegistration.shiftBilinear(data[i], shifts[i])
                #tmpImage = ImageRegistration.shiftImage(data[i], -shifts[i], method="fft")
                if filename is None:
                    stack.data[i] = tmpImage * window
                else:
                    outputStack[i] = tmpImage * window
            else:
                tmpImage = ImageRegistration.shiftBilinear(data[:,:,i], shifts[i])
                if filename is None:
                    stack.data[:, :, i] = tmpImage * window
                else:
                    outputStack[i] = tmpImage * window
            _logger.debug("Index %d bilinear shifted", i)
            self._progress = (100 * i) / total

    def initializeHDF5File(self, fname):
        #for the time being overwriting
        if os.path.exists(fname):
            os.remove(fname)
        hdf = h5py.File(fname, 'w')
        entryName = "entry_000"
        nxEntry = hdf.require_group(entryName)
        if 'NX_class' not in nxEntry.attrs:
            nxEntry.attrs['NX_class'] = 'NXentry'.encode('utf-8')
        nxEntry['title'] = numpy.string_("PyMca saved 3D Array".encode('utf-8'))
        nxEntry['start_time'] = numpy.string_(ArraySave.getDate().encode('utf-8'))

        alignmentGroup = nxEntry.require_group('Alignment')
        dataGroup = nxEntry.require_group('Data')
        dataGroup.attrs['NX_class'] = 'NXdata'.encode('utf-8')
        return hdf

    def finishHDF5File(self, hdf):
        #add final date
        toplevelEntry = hdf["entry_000"]
        toplevelEntry['end_time'] = numpy.string_(ArraySave.getDate().encode('utf-8'))
        hdf.flush()
        hdf.close()

    def getHDF5BufferIntoGroup(self, h5Group, shape,
                               name="data", dtype=numpy.float32,
                               attributes=None,
                               compression=None,
                               shuffle=False,
                               chunks=None,
                               chunk_cache=None):
        dataset = h5Group.require_dataset(name,
                                          shape=shape,
                                          dtype=dtype,
                                          chunks=chunks,
                                          shuffle=shuffle,
                                          compression=compression)
        if attributes is None:
            attributes = {}
        for attribute in attributes:
            dataset.attrs[attribute] = attributes[attribute]
        return dataset

MENU_TEXT = "Image Alignment Tool"
def getStackPluginInstance(stackWindow, **kw):
    ob = ImageAlignmentStackPlugin(stackWindow)
    return ob


class Solution:
    # @param a, a string
    # @param b, a string
    # @return a boolean
    def compareVersion(self, version1, version2):
        v1list = version1.split(".")
        v2list = version2.split(".")
        len1 = len(v1list)
        len2 = len(v2list)
        # 比较两个List的长度
        lenMax = max(len1, len2)
        for x in range(lenMax):
            v1Token = 0
            if x < len1:
                # 将字符串有string分割为若干个string组成的list，记得要将string转换为interger
                v1Token = int(v1list[x])
            v2Token = 0
            if x < len2:
                v2Token = int(v2list[x])
            if v1Token < v2Token:
                return -1
            if v1Token > v2Token:
                return 1
        return 0


import time

import requests
import ujson as json

ERROR_KEY = u'error'
STATUS_FIELD = u'status'

URL_FIELD = u'url'
PAGERANK_FIELD = u'pageRank'

COSINE_FIELD = u'cosine'

ANNOTATION_DATA_FIELD = u'annotation_data'

_WIKIFIER_URL = u"http://www.wikifier.org/annotate-article"
_WIKIFIER_MAX_SERVER_LIMIT = 25000
WIKIFIER_MAX_CHAR_CEILING = round(_WIKIFIER_MAX_SERVER_LIMIT * .99)  # 99% of max allowed num chars for a post request

def _get_wikififier_concepts(resp):
    annotations = [{URL_FIELD: ann[URL_FIELD],
                    COSINE_FIELD: ann[COSINE_FIELD],
                    PAGERANK_FIELD: ann[PAGERANK_FIELD]} for ann in resp.get("annotations", [])]

    return {
        ANNOTATION_DATA_FIELD: annotations,
        STATUS_FIELD: resp[STATUS_FIELD]
    }

def _get_wikifier_response(text, api_key, df_ignore, words_ignore):
    params = {"text": text,
              "userKey": api_key,
              "nTopDfValuesToIgnore": df_ignore,
              "nWordsToIgnoreFromList": words_ignore}
    r = requests.post(_WIKIFIER_URL, params)
    if r.status_code == 200:
        resp = json.loads(r.content)
        if ERROR_KEY in resp:
            raise ValueError("error in response : {}".format(resp[ERROR_KEY]))
        return resp
    else:
        raise ValueError("http status code 200 expected, got status code {} instead".format(r.status_code))

def wikify(text, key, df_ignore, words_ignore):
    """This function takes in a text representation of a lecture transcript and associates relevant Wikipedia topics to
    it using www.wikifier.org entity linking technology.

    Args:
        text (str): text that needs to be Wikified (usually lecture transcript string)
        key (str): API key for Wikifier obtained from http://www.wikifier.org/register.html
        df_ignore (int): Most common words to ignore based on Document frequency
        words_ignore (int): Most common words to ignore based on Term frequency

    Returns:
        [{key:val}]: a dict with status of the request and the list of Wiki topics linked to the text
    """
    try:
        resp = _get_wikifier_response(text, key, df_ignore, words_ignore)
        resp[STATUS_FIELD] = 'success'
    except ValueError as e:
        try:
            STATUS_ = e.message
        except:
            STATUS_ = e.args[0]
        return {
            STATUS_FIELD: STATUS_
        }
    time.sleep(0.5)
    return _get_wikififier_concepts(resp)


"""
Date : 22.01.27
Title : if문
Project :
Name : 박상현
"""
T = True
if T:  # if(T) = if T:
    print("T는")  # Python의 if문은 { }를 들여쓰기 "    "로 구분한다
    print("True입니다.")
    #   print("Error!") 들여쓰기 2번은 Error!
else:
    print("Dead code")

T1 = True
T2 = True
if T1 and T2:  # or, not
    print("T1과 T2 모두 True 입니다")

list = [1, 2, 3]
if 1 in list: #in, not in
    print("list안에 1이 있습니다")

F = False
if F:
    print("거짓!")
else:
    pass #무시한다

F1 = F2 = False
if F1:
    print("F!")
elif F2: #else if
    print("F2")
elif T:
    print("T")

print("TURE!") if T else print("False!")
# if T:
#     print("TURE!")
# else:
#     print("False!")


import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models

def multi_input_lstm_embedding_model(timesteps, columns_size, max_words, max_len):
    # lstm model
    lstm_input = layers.Input(shape=(timesteps, columns_size))
    lstm_out = layers.LSTM(64, dropout=0.3, recurrent_dropout=0.3, name='lstm_out')(lstm_input)
    test_out = layers.Dense(100)(lstm_input)

    lstm_model = models.Model(inputs=lstm_input, outputs={'lstm_out': lstm_out, 'test_out': test_out})

    # embedding model
    embed_input = layers.Input(shape=(None,))
    embed_out = layers.Embedding(max_words, 8, input_length=max_len)(embed_input)
    embed_out = layers.Bidirectional(layers.LSTM(64, dropout=0.3, recurrent_dropout=0.3))(embed_out)

    embed_model = models.Model(inputs=embed_input, outputs=embed_out)

    # concatenate
    print(lstm_model.output, type(lstm_model.output), len(lstm_model.output))
    concatenated = layers.concatenate([lstm_model.output['lstm_out'], embed_model.output])
    concatenated = layers.Dense(32, activation='relu')(concatenated)
    concatenated = layers.BatchNormalization()(concatenated)
    concat_out = layers.Dense(2, activation='sigmoid')(concatenated)

    concat_model = models.Model([lstm_input, embed_input], concat_out)

    return concat_model

if __name__ == '__main__':
    model = multi_input_lstm_embedding_model(50, 10, 100, 100)
    model.summary()


from measures import *

class RiskSpace(Measure):
    """
    Return a signaller's position in 'risk space'. i.e.
    a tuple of values corresponding to the risk associated
    with each signal.
    Returns valuespace for cpt players, and signal space for heuristic
    players.
    """

    def measure_one(self, woman):
        player_type = str(woman)
        if "prospect" in player_type:
            LOG.debug(
                "Measuring valuespace for player %d, type %d, rule %s" % (hash(woman), woman.player_type, str(woman)))
            res = map(lambda signal: woman.cpt_value(woman.collect_prospects(signal)), woman.signals)
        elif "lexic" in player_type:
            LOG.debug(
                "Measuring signalspace for player %d, type %d, rule %s" % (hash(woman), woman.player_type, str(woman)))
            res = woman.signal_search()
        else:
            LOG.debug(
                "Measuring riskspace for player %d, type %d, rule %s" % (hash(woman), woman.player_type, str(woman)))
            res = map(lambda signal: woman.risk(signal), woman.signals)
        return res

    def measure(self, roundnum, women, game):
        res = map(lambda x: (self.measure_one(x), hash(x), x.player_type), women)
        return res

class SignalSpace(RiskSpace):
    """
    Return a signaller's preferred signal at this time.
    """

    def measure_one(self, woman):
        return woman.signal_search()

class ReferralEvents(Measure):
    """
    Log the id number and type of all players referred this round.
    """

    def measure(self, roundnum, women, game):
        res = map(lambda x: (hash(x), x.player_type), filter(lambda x: 1 in x.get_response_log(), women))
        return res

def space_measures_women(signals=None, base=None):
    if not signals:
        signals = [0, 1]
    measures = OrderedDict()
    measures["riskspace"] = RiskSpace()
    measures["referralevents"] = ReferralEvents()
    measures["signalspace"] = SignalSpace()
    if base is None:
        base = measures_women(signals=signals)
    base.add(Measures(measures))
    return base

def space_measures_mw(signals=None, base=None):
    if not signals:
        signals = [0, 1]
    measures = OrderedDict()
    if base is None:
        base = measures_midwives(signals=signals)
    base.add(Measures(measures))
    return base


# texto (String / str)
titulo = 'Curso de Python'
titulo_dos = "Curso de Python comillas dobles"

mensaje = '''Esta es una variable String
escrita en más de una linea.
'''

print(mensaje)
print(type(mensaje))                    # type() muestra el tipo de dato de una variable.

# Enteros (int) positivos/negativos
x = 10
y = -50

# Numeros con decimales (float)
z = 3.1416
w = -10.1256

div_entera = 10//3
div_decimal = 10/3

print(div_entera, div_decimal, sep='***')       # sep indica el caracter de separación entre las cadenas.

# Booleanos (bool)
encendido = True
apagado = False


import collections
import json
import os
import pkg_resources
import platform

from google.gax import api_callable
from google.gax import config
from google.gax import path_template
import google.gax

from google.api import metric_pb2 as api_metric_pb2
from google.cloud.gapic.monitoring.v3 import enums
from google.cloud.proto.monitoring.v3 import common_pb2
from google.cloud.proto.monitoring.v3 import metric_pb2 as v3_metric_pb2
from google.cloud.proto.monitoring.v3 import metric_service_pb2

_PageDesc = google.gax.PageDescriptor

class MetricServiceClient(object):
    """
    Manages metric descriptors, monitored resource descriptors, and
    time series data.
    """

    SERVICE_ADDRESS = 'monitoring.googleapis.com'
    """The default address of the service."""

    DEFAULT_SERVICE_PORT = 443
    """The default port of the service."""

    _PAGE_DESCRIPTORS = {
        'list_monitored_resource_descriptors':
        _PageDesc('page_token', 'next_page_token', 'resource_descriptors'),
        'list_metric_descriptors': _PageDesc('page_token', 'next_page_token',
                                             'metric_descriptors'),
        'list_time_series': _PageDesc('page_token', 'next_page_token',
                                      'time_series')
    }

    # The scopes needed to make gRPC calls to all of the methods defined in
    # this service
    _ALL_SCOPES = (
        'https://www.googleapis.com/auth/cloud-platform',
        'https://www.googleapis.com/auth/monitoring',
        'https://www.googleapis.com/auth/monitoring.read',
        'https://www.googleapis.com/auth/monitoring.write', )

    _PROJECT_PATH_TEMPLATE = path_template.PathTemplate('projects/{project}')
    _METRIC_DESCRIPTOR_PATH_TEMPLATE = path_template.PathTemplate(
        'projects/{project}/metricDescriptors/{metric_descriptor=**}')
    _MONITORED_RESOURCE_DESCRIPTOR_PATH_TEMPLATE = path_template.PathTemplate(
        'projects/{project}/monitoredResourceDescriptors/{monitored_resource_descriptor}'
    )

    @classmethod
    def project_path(cls, project):
        """Returns a fully-qualified project resource name string."""
        return cls._PROJECT_PATH_TEMPLATE.render({'project': project, })

    @classmethod
    def metric_descriptor_path(cls, project, metric_descriptor):
        """Returns a fully-qualified metric_descriptor resource name string."""
        return cls._METRIC_DESCRIPTOR_PATH_TEMPLATE.render({
            'project': project,
            'metric_descriptor': metric_descriptor,
        })

    @classmethod
    def monitored_resource_descriptor_path(cls, project,
                                           monitored_resource_descriptor):
        """Returns a fully-qualified monitored_resource_descriptor resource name string."""
        return cls._MONITORED_RESOURCE_DESCRIPTOR_PATH_TEMPLATE.render({
            'project': project,
            'monitored_resource_descriptor': monitored_resource_descriptor,
        })

    @classmethod
    def match_project_from_project_name(cls, project_name):
        """Parses the project from a project resource.

        Args:
          project_name (string): A fully-qualified path representing a project
            resource.

        Returns:
          A string representing the project.
        """
        return cls._PROJECT_PATH_TEMPLATE.match(project_name).get('project')

    @classmethod
    def match_project_from_metric_descriptor_name(cls, metric_descriptor_name):
        """Parses the project from a metric_descriptor resource.

        Args:
          metric_descriptor_name (string): A fully-qualified path representing a metric_descriptor
            resource.

        Returns:
          A string representing the project.
        """
        return cls._METRIC_DESCRIPTOR_PATH_TEMPLATE.match(
            metric_descriptor_name).get('project')

    @classmethod
    def match_metric_descriptor_from_metric_descriptor_name(
            cls, metric_descriptor_name):
        """Parses the metric_descriptor from a metric_descriptor resource.

        Args:
          metric_descriptor_name (string): A fully-qualified path representing a metric_descriptor
            resource.

        Returns:
          A string representing the metric_descriptor.
        """
        return cls._METRIC_DESCRIPTOR_PATH_TEMPLATE.match(
            metric_descriptor_name).get('metric_descriptor')

    @classmethod
    def match_project_from_monitored_resource_descriptor_name(
            cls, monitored_resource_descriptor_name):
        """Parses the project from a monitored_resource_descriptor resource.

        Args:
          monitored_resource_descriptor_name (string): A fully-qualified path representing a monitored_resource_descriptor
            resource.

        Returns:
          A string representing the project.
        """
        return cls._MONITORED_RESOURCE_DESCRIPTOR_PATH_TEMPLATE.match(
            monitored_resource_descriptor_name).get('project')

    @classmethod
    def match_monitored_resource_descriptor_from_monitored_resource_descriptor_name(
            cls, monitored_resource_descriptor_name):
        """Parses the monitored_resource_descriptor from a monitored_resource_descriptor resource.

        Args:
          monitored_resource_descriptor_name (string): A fully-qualified path representing a monitored_resource_descriptor
            resource.

        Returns:
          A string representing the monitored_resource_descriptor.
        """
        return cls._MONITORED_RESOURCE_DESCRIPTOR_PATH_TEMPLATE.match(
            monitored_resource_descriptor_name).get(
                'monitored_resource_descriptor')

    def __init__(self,
                 service_path=SERVICE_ADDRESS,
                 port=DEFAULT_SERVICE_PORT,
                 channel=None,
                 credentials=None,
                 ssl_credentials=None,
                 scopes=None,
                 client_config=None,
                 app_name=None,
                 app_version='',
                 lib_name=None,
                 lib_version='',
                 metrics_headers=()):
        """Constructor.

        Args:
          service_path (string): The domain name of the API remote host.
          port (int): The port on which to connect to the remote host.
          channel (:class:`grpc.Channel`): A ``Channel`` instance through
            which to make calls.
          credentials (object): The authorization credentials to attach to
            requests. These credentials identify this application to the
            service.
          ssl_credentials (:class:`grpc.ChannelCredentials`): A
            ``ChannelCredentials`` instance for use with an SSL-enabled
            channel.
          scopes (list[string]): A list of OAuth2 scopes to attach to requests.
          client_config (dict):
            A dictionary for call options for each method. See
            :func:`google.gax.construct_settings` for the structure of
            this data. Falls back to the default config if not specified
            or the specified config is missing data points.
          app_name (string): The name of the application calling
            the service. Recommended for analytics purposes.
          app_version (string): The version of the application calling
            the service. Recommended for analytics purposes.
          lib_name (string): The API library software used for calling
            the service. (Unless you are writing an API client itself,
            leave this as default.)
          lib_version (string): The API library software version used
            for calling the service. (Unless you are writing an API client
            itself, leave this as default.)
          metrics_headers (dict): A dictionary of values for tracking
            client library metrics. Ultimately serializes to a string
            (e.g. 'foo/1.2.3 bar/3.14.1'). This argument should be
            considered private.

        Returns:
          A MetricServiceClient object.
        """
        # Unless the calling application specifically requested
        # OAuth scopes, request everything.
        if scopes is None:
            scopes = self._ALL_SCOPES

        # Initialize an empty client config, if none is set.
        if client_config is None:
            client_config = {}

        # Initialize metrics_headers as an ordered dictionary
        # (cuts down on cardinality of the resulting string slightly).
        metrics_headers = collections.OrderedDict(metrics_headers)
        metrics_headers['gl-python'] = platform.python_version()

        # The library may or may not be set, depending on what is
        # calling this client. Newer client libraries set the library name
        # and version.
        if lib_name:
            metrics_headers[lib_name] = lib_version

        # Finally, track the GAPIC package version.
        metrics_headers['gapic'] = pkg_resources.get_distribution(
            'gapic-google-cloud-monitoring-v3', ).version

        # Load the configuration defaults.
        default_client_config = json.loads(
            pkg_resources.resource_string(
                __name__, 'metric_service_client_config.json').decode())
        defaults = api_callable.construct_settings(
            'google.monitoring.v3.MetricService',
            default_client_config,
            client_config,
            config.STATUS_CODE_NAMES,
            metrics_headers=metrics_headers,
            page_descriptors=self._PAGE_DESCRIPTORS, )
        self.metric_service_stub = config.create_stub(
            metric_service_pb2.MetricServiceStub,
            channel=channel,
            service_path=service_path,
            service_port=port,
            credentials=credentials,
            scopes=scopes,
            ssl_credentials=ssl_credentials)

        self._list_monitored_resource_descriptors = api_callable.create_api_call(
            self.metric_service_stub.ListMonitoredResourceDescriptors,
            settings=defaults['list_monitored_resource_descriptors'])
        self._get_monitored_resource_descriptor = api_callable.create_api_call(
            self.metric_service_stub.GetMonitoredResourceDescriptor,
            settings=defaults['get_monitored_resource_descriptor'])
        self._list_metric_descriptors = api_callable.create_api_call(
            self.metric_service_stub.ListMetricDescriptors,
            settings=defaults['list_metric_descriptors'])
        self._get_metric_descriptor = api_callable.create_api_call(
            self.metric_service_stub.GetMetricDescriptor,
            settings=defaults['get_metric_descriptor'])
        self._create_metric_descriptor = api_callable.create_api_call(
            self.metric_service_stub.CreateMetricDescriptor,
            settings=defaults['create_metric_descriptor'])
        self._delete_metric_descriptor = api_callable.create_api_call(
            self.metric_service_stub.DeleteMetricDescriptor,
            settings=defaults['delete_metric_descriptor'])
        self._list_time_series = api_callable.create_api_call(
            self.metric_service_stub.ListTimeSeries,
            settings=defaults['list_time_series'])
        self._create_time_series = api_callable.create_api_call(
            self.metric_service_stub.CreateTimeSeries,
            settings=defaults['create_time_series'])

    # Service calls
    def list_monitored_resource_descriptors(self,
                                            name,
                                            filter_='',
                                            page_size=0,
                                            options=None):
        """
        Lists monitored resource descriptors that match a filter. This method does not require a Stackdriver account.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> from google.gax import CallOptions, INITIAL_PAGE
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.project_path('[PROJECT]')
          >>>
          >>> # Iterate over all results
          >>> for element in api.list_monitored_resource_descriptors(name):
          >>>   # process element
          >>>   pass
          >>>
          >>> # Or iterate over results one page at a time
          >>> for page in api.list_monitored_resource_descriptors(name, options=CallOptions(page_token=INITIAL_PAGE)):
          >>>   for element in page:
          >>>     # process element
          >>>     pass

        Args:
          name (string): The project on which to execute the request. The format is
            ``\"projects/{project_id_or_number}\"``.
          filter_ (string): An optional `filter <https://cloud.google.com/monitoring/api/v3/filters>`_ describing
            the descriptors to be returned.  The filter can reference
            the descriptor's type and labels. For example, the
            following filter returns only Google Compute Engine descriptors
            that have an ``id`` label:

            ::

                resource.type = starts_with(\"gce_\") AND resource.label:id
          page_size (int): The maximum number of resources contained in the
            underlying API response. If page streaming is performed per-
            resource, this parameter does not affect the return value. If page
            streaming is performed per-page, this determines the maximum number
            of resources in a page.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Returns:
          A :class:`google.gax.PageIterator` instance. By default, this
          is an iterable of :class:`google.api.monitored_resource_pb2.MonitoredResourceDescriptor` instances.
          This object can also be configured to iterate over the pages
          of the response through the `CallOptions` parameter.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.ListMonitoredResourceDescriptorsRequest(
            name=name, filter=filter_, page_size=page_size)
        return self._list_monitored_resource_descriptors(request, options)

    def get_monitored_resource_descriptor(self, name, options=None):
        """
        Gets a single monitored resource descriptor. This method does not require a Stackdriver account.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.monitored_resource_descriptor_path('[PROJECT]', '[MONITORED_RESOURCE_DESCRIPTOR]')
          >>> response = api.get_monitored_resource_descriptor(name)

        Args:
          name (string): The monitored resource descriptor to get.  The format is
            ``\"projects/{project_id_or_number}/monitoredResourceDescriptors/{resource_type}\"``.
            The ``{resource_type}`` is a predefined type, such as
            ``cloudsql_database``.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Returns:
          A :class:`google.api.monitored_resource_pb2.MonitoredResourceDescriptor` instance.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.GetMonitoredResourceDescriptorRequest(
            name=name)
        return self._get_monitored_resource_descriptor(request, options)

    def list_metric_descriptors(self,
                                name,
                                filter_='',
                                page_size=0,
                                options=None):
        """
        Lists metric descriptors that match a filter. This method does not require a Stackdriver account.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> from google.gax import CallOptions, INITIAL_PAGE
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.project_path('[PROJECT]')
          >>>
          >>> # Iterate over all results
          >>> for element in api.list_metric_descriptors(name):
          >>>   # process element
          >>>   pass
          >>>
          >>> # Or iterate over results one page at a time
          >>> for page in api.list_metric_descriptors(name, options=CallOptions(page_token=INITIAL_PAGE)):
          >>>   for element in page:
          >>>     # process element
          >>>     pass

        Args:
          name (string): The project on which to execute the request. The format is
            ``\"projects/{project_id_or_number}\"``.
          filter_ (string): If this field is empty, all custom and
            system-defined metric descriptors are returned.
            Otherwise, the `filter <https://cloud.google.com/monitoring/api/v3/filters>`_
            specifies which metric descriptors are to be
            returned. For example, the following filter matches all
            `custom metrics <https://cloud.google.com/monitoring/custom-metrics>`_:

            ::

                metric.type = starts_with(\"custom.googleapis.com/\")
          page_size (int): The maximum number of resources contained in the
            underlying API response. If page streaming is performed per-
            resource, this parameter does not affect the return value. If page
            streaming is performed per-page, this determines the maximum number
            of resources in a page.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Returns:
          A :class:`google.gax.PageIterator` instance. By default, this
          is an iterable of :class:`google.api.metric_pb2.MetricDescriptor` instances.
          This object can also be configured to iterate over the pages
          of the response through the `CallOptions` parameter.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.ListMetricDescriptorsRequest(
            name=name, filter=filter_, page_size=page_size)
        return self._list_metric_descriptors(request, options)

    def get_metric_descriptor(self, name, options=None):
        """
        Gets a single metric descriptor. This method does not require a Stackdriver account.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.metric_descriptor_path('[PROJECT]', '[METRIC_DESCRIPTOR]')
          >>> response = api.get_metric_descriptor(name)

        Args:
          name (string): The metric descriptor on which to execute the request. The format is
            ``\"projects/{project_id_or_number}/metricDescriptors/{metric_id}\"``.
            An example value of ``{metric_id}`` is
            ``\"compute.googleapis.com/instance/disk/read_bytes_count\"``.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Returns:
          A :class:`google.api.metric_pb2.MetricDescriptor` instance.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.GetMetricDescriptorRequest(name=name)
        return self._get_metric_descriptor(request, options)

    def create_metric_descriptor(self, name, metric_descriptor, options=None):
        """
        Creates a new metric descriptor.
        User-created metric descriptors define
        `custom metrics <https://cloud.google.com/monitoring/custom-metrics>`_.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> from google.api import metric_pb2 as api_metric_pb2
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.project_path('[PROJECT]')
          >>> metric_descriptor = api_metric_pb2.MetricDescriptor()
          >>> response = api.create_metric_descriptor(name, metric_descriptor)

        Args:
          name (string): The project on which to execute the request. The format is
            ``\"projects/{project_id_or_number}\"``.
          metric_descriptor (:class:`google.api.metric_pb2.MetricDescriptor`): The new `custom metric <https://cloud.google.com/monitoring/custom-metrics>`_
            descriptor.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Returns:
          A :class:`google.api.metric_pb2.MetricDescriptor` instance.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.CreateMetricDescriptorRequest(
            name=name, metric_descriptor=metric_descriptor)
        return self._create_metric_descriptor(request, options)

    def delete_metric_descriptor(self, name, options=None):
        """
        Deletes a metric descriptor. Only user-created
        `custom metrics <https://cloud.google.com/monitoring/custom-metrics>`_ can be deleted.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.metric_descriptor_path('[PROJECT]', '[METRIC_DESCRIPTOR]')
          >>> api.delete_metric_descriptor(name)

        Args:
          name (string): The metric descriptor on which to execute the request. The format is
            ``\"projects/{project_id_or_number}/metricDescriptors/{metric_id}\"``.
            An example of ``{metric_id}`` is:
            ``\"custom.googleapis.com/my_test_metric\"``.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.DeleteMetricDescriptorRequest(name=name)
        self._delete_metric_descriptor(request, options)

    def list_time_series(self,
                         name,
                         filter_,
                         interval,
                         view,
                         aggregation=None,
                         order_by='',
                         page_size=0,
                         options=None):
        """
        Lists time series that match a filter. This method does not require a Stackdriver account.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> from google.cloud.gapic.monitoring.v3 import enums
          >>> from google.cloud.proto.monitoring.v3 import common_pb2
          >>> from google.gax import CallOptions, INITIAL_PAGE
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.project_path('[PROJECT]')
          >>> filter_ = ''
          >>> interval = common_pb2.TimeInterval()
          >>> view = enums.ListTimeSeriesRequest.TimeSeriesView.FULL
          >>>
          >>> # Iterate over all results
          >>> for element in api.list_time_series(name, filter_, interval, view):
          >>>   # process element
          >>>   pass
          >>>
          >>> # Or iterate over results one page at a time
          >>> for page in api.list_time_series(name, filter_, interval, view, options=CallOptions(page_token=INITIAL_PAGE)):
          >>>   for element in page:
          >>>     # process element
          >>>     pass

        Args:
          name (string): The project on which to execute the request. The format is
            \"projects/{project_id_or_number}\".
          filter_ (string): A `monitoring filter <https://cloud.google.com/monitoring/api/v3/filters>`_ that specifies which time
            series should be returned.  The filter must specify a single metric type,
            and can additionally specify metric labels and other information. For
            example:

            ::

                metric.type = \"compute.googleapis.com/instance/cpu/usage_time\" AND
                    metric.label.instance_name = \"my-instance-name\"
          interval (:class:`google.cloud.proto.monitoring.v3.common_pb2.TimeInterval`): The time interval for which results should be returned. Only time series
            that contain data points in the specified interval are included
            in the response.
          aggregation (:class:`google.cloud.proto.monitoring.v3.common_pb2.Aggregation`): By default, the raw time series data is returned.
            Use this field to combine multiple time series for different
            views of the data.
          order_by (string): Specifies the order in which the points of the time series should
            be returned.  By default, results are not ordered.  Currently,
            this field must be left blank.
          view (enum :class:`google.cloud.gapic.monitoring.v3.enums.ListTimeSeriesRequest.TimeSeriesView`): Specifies which information is returned about the time series.
          page_size (int): The maximum number of resources contained in the
            underlying API response. If page streaming is performed per-
            resource, this parameter does not affect the return value. If page
            streaming is performed per-page, this determines the maximum number
            of resources in a page.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Returns:
          A :class:`google.gax.PageIterator` instance. By default, this
          is an iterable of :class:`google.cloud.proto.monitoring.v3.metric_pb2.TimeSeries` instances.
          This object can also be configured to iterate over the pages
          of the response through the `CallOptions` parameter.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        if aggregation is None:
            aggregation = common_pb2.Aggregation()
        # Create the request object.
        request = metric_service_pb2.ListTimeSeriesRequest(
            name=name,
            filter=filter_,
            interval=interval,
            view=view,
            aggregation=aggregation,
            order_by=order_by,
            page_size=page_size)
        return self._list_time_series(request, options)

    def create_time_series(self, name, time_series, options=None):
        """
        Creates or adds data to one or more time series.
        The response is empty if all time series in the request were written.
        If any time series could not be written, a corresponding failure message is
        included in the error response.

        Example:
          >>> from google.cloud.gapic.monitoring.v3 import metric_service_client
          >>> from google.cloud.proto.monitoring.v3 import metric_pb2 as v3_metric_pb2
          >>> api = metric_service_client.MetricServiceClient()
          >>> name = api.project_path('[PROJECT]')
          >>> time_series = []
          >>> api.create_time_series(name, time_series)

        Args:
          name (string): The project on which to execute the request. The format is
            ``\"projects/{project_id_or_number}\"``.
          time_series (list[:class:`google.cloud.proto.monitoring.v3.metric_pb2.TimeSeries`]): The new data to be added to a list of time series.
            Adds at most one data point to each of several time series.  The new data
            point must be more recent than any other point in its time series.  Each
            ``TimeSeries`` value must fully specify a unique time series by supplying
            all label values for the metric and the monitored resource.
          options (:class:`google.gax.CallOptions`): Overrides the default
            settings for this call, e.g, timeout, retries etc.

        Raises:
          :exc:`google.gax.errors.GaxError` if the RPC is aborted.
          :exc:`ValueError` if the parameters are invalid.
        """
        # Create the request object.
        request = metric_service_pb2.CreateTimeSeriesRequest(
            name=name, time_series=time_series)
        self._create_time_series(request, options)


import os
import tensorflow as tf
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras import Sequential
import numpy as np
import pretty_midi

# 定义一些超参数
NUM_TIMESTEPS = 64
NUM_FEATURES = 128
BATCH_SIZE = 128
NUM_EPOCHS = 200

# 读取midi文件并将其转化为numpy数组
def midi_to_numpy(file_path):
    midi_data = pretty_midi.PrettyMIDI(file_path)
    piano_roll = midi_data.get_piano_roll(fs=4)
    piano_roll = piano_roll[:NUM_FEATURES, :]
    piano_roll[piano_roll > 0] = 1
    return piano_roll.T

# 创建训练数据和标签
def create_sequences(data, num_timesteps):
    sequences = []
    targets = []
    for i in range(num_timesteps, len(data)):
        sequences.append(data[i-num_timesteps:i])
        targets.append(data[i])
    return np.array(sequences), np.array(targets)

# 读取midi文件夹下的所有midi文件
def read_midi_files(midi_folder):
    all_data = []
    for root, dirs, files in os.walk(midi_folder):
        for file in files:
            if file.endswith(".midi") or file.endswith(".mid"):
                file_path = os.path.join(root, file)
                data

                data = midi_to_numpy(file_path)
                all_data.append(data)
    return np.vstack(all_data)

# 加载训练数据
midi_folder = "./maestro-v3.0.0/"
data = read_midi_files(midi_folder)

# 创建训练数据和标签
X, y = create_sequences(data, NUM_TIMESTEPS)

# 创建模型
model = Sequential([
    LSTM(256, input_shape=(NUM_TIMESTEPS, NUM_FEATURES), return_sequences=True),
    Dropout(0.2),
    LSTM(256),
    Dropout(0.2),
    Dense(NUM_FEATURES, activation='sigmoid')
])

# 编译模型
model.compile(optimizer='adam', loss='binary_crossentropy')

# 定义训练数据生成器，用于减少内存占用
def data_generator():
    while True:
        for i in range(0, len(X), BATCH_SIZE):
            yield X[i:i+BATCH_SIZE], y[i:i+BATCH_SIZE]

# 定义验证集
val_split = 0.1
val_size = int(len(X) * val_split)
val_X, val_y = X[-val_size:], y[-val_size:]
train_X, train_y = X[:-val_size], y[:-val_size]

# 训练模型并添加早停机制
early_stopping = tf.keras.callbacks.EarlyStopping(patience=10)
model.fit(data_generator(), steps_per_epoch=len(train_X)//BATCH_SIZE, epochs=NUM_EPOCHS,
          validation_data=(val_X, val_y), callbacks=[early_stopping])

# 保存模型
model.save('rnn_model.h5')

# 生成音乐
def generate_music(model, seed_sequence, num_timesteps):
    output_sequence = seed_sequence.copy()
    for i in range(num_timesteps):
        output = model.predict(np.expand_dims(output_sequence[-num_timesteps:], axis=0))
        output_sequence = np.vstack([output_sequence, output])
    return output_sequence

# 选择一个种子序列来生成音乐
seed_index = np.random.randint(0, len(data) - NUM_TIMESTEPS)
seed_sequence = data[seed_index:seed_index+NUM_TIMESTEPS]

# 生成音乐
generated_music = generate_music(model, seed_sequence, 128)

# 将生成的音乐写入midi文件
midi_data = pretty_midi.PrettyMIDI()
piano_program = pretty_midi.instrument_name_to_program('Acoustic Grand Piano')
piano = pretty_midi.Instrument(program=piano_program)
for i, note_sequence in enumerate(generated_music):
    for j, note in enumerate(note_sequence):
        if note > 0:
            note_start = int(j) / 4.0
            note_end = int(j + 1) / 4.0
            midi_note = pretty_midi.Note(
                velocity=int(100), pitch=int(i), start=note_start, end=note_end)
            piano.notes.append(midi_note)
midi_data.instruments.append(piano)
midi_data.write('generated_music.midi')


def classify(number):
    """ A perfect number equals the sum of its positive divisors.

    :param number: int a positive integer
    :return: str the classification of the input integer
    """
    if(number < 0):
        # if a number to be classified is less than 1.
        raise ValueError("Classification is only possible for positive integers.")
    divid = []
    limit = (number//2)+1
    for i in range(1,limit):
        if(number%i == 0):
            divid.append(i)
    if(sum(divid)==number):
        return "perfect"
    if(sum(divid)>number):
        return "abundant"
    return "deficient"

print(classify(6))