# -*- coding: utf-8 -*-
"""
Created on Sun Jan 27 19:13:39 2019

@author: asus
"""

from data import *
from collections import OrderedDict as od
from eacal import EACal, lang
import datetime as dt
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from lunardate import LunarDate
import math

c=EACal(zh_s=True)

class Location():

    def __init__(self,deg):
        self.zuo=''
        self.xiang=''
        self.jianzuo=None
        self.jianxiang=None

        if deg<=352.5 and deg>=7.5:
            #print(1)
            for k,v in dingxiang.iterrows():
                if v.loc['逆左']<=deg and v.loc['顺右']>=deg:
                    self.zuo=k
                    self.xiang=shan.dui(self.zuo)
                    if v.loc['正左']>=deg:
                        self.jianzuo=shan.ni(self.zuo,2)
                        self.jianxiang=shan.dui(self.jianzuo)
                    elif v.loc['正右']<=deg:
                        self.jianzuo=shan.shun(self.zuo,2)
                        self.jianxiang=shan.dui(self.jianzuo)
        else:
            self.zuo='子'
            self.xiang='午'
            if 355.5>=deg:
                self.jianzuo=shan.ni(self.zuo,2)
                self.jianxiang=shan.dui(self.jianzuo)
            elif 4.5<=deg:
                self.jianzuo=shan.shun(self.zuo,2)
                self.jianxiang=shan.dui(self.jianzuo)

class House():

    def __init__(self,year,liunian,zuo,xiang,jianzuo=None,jianxiang=None):
        self.year=year
        self.liunian=liunian
        self.liunianyun=self.getLiunianyun(self.liunian)
        self.yun=self.getYuanyun()
        self.zheng,self.ling,self.zhao=self.getSanshen()
        self.zuo,self.xiang=self.getShanxiang(zuo,xiang)
        self.zuogua=shangua.loc[self.zuo,'八卦']
        self.xianggua=shangua.loc[self.xiang,'八卦']
        self.luantou=None
        if jianzuo and jianxiang:
            #self.zuo,self.xiang=self.getShanxiang(jianzuo,jianxiang)
            self.isjian=True
            self.jianzuo=jianzuo
            self.jianxiang=jianxiang
        else:
            self.isjian=False
        self.pan=deepcopy(dipan)
        self.getTianpan()
        self.shanshunni=''
        self.xiangshunni=''
        self.shanshu=self.getShanxiangshu(self.zuo)
        self.xiangshu=self.getShanxiangshu(self.xiang)
        if self.isjian:
            self.getJianshanpan()
            self.getJianxiangpan()
        else:
            self.getShanpan()
            self.getXiangpan()
        self.xingyun=self.getStarsyun()
        self.caiwei=self.getCaiwei()
        self.geju=[]
        self.getGeju()
        self.liunianfeixing=self.getLiunianfeixing()
        self.wenchangwei=''
        self.wenchangwei=self.getWenchangwei()
    def getBybagua(self,bagua):
        return self.pan.xs(bagua,level='八卦')
    def getYuanyun(self):
        cond1=yuanyun.loc[:,'起始']<=self.year
        cond2=yuanyun.loc[:,'终止']>=self.year
        return yuanyun.loc[cond1&cond2]['运'].values[0]
    def getShanxiang(self,zuo,xiang):
        if shan.isDui(zuo,xiang):
            return zuo,xiang
    def feixing(self,pantype,zhong,sn):
        self.pan[pantype]=list(['']*9)
        tmpdict=od.fromkeys(self.pan.index.get_level_values('卦数'))
        for i,v in enumerate(shunni[sn]):
            tmpdict[v]=jiu.shun(zhong,i+1)
        self.pan[pantype]=tmpdict.values()
    def feixing_notpan(self,pantype,zhong,sn):
        tmppan=deepcopy(dipan)
        tmppan[pantype]=list(['']*9)
        tmpdict=od.fromkeys(tmppan.index.get_level_values('卦数'))
        for i,v in enumerate(shunni[sn]):
            tmpdict[v]=jiu.shun(zhong,i+1)
        tmppan[pantype]=tmpdict.values()
        return tmppan
    def shan2gua(self,s):
            return shangua.loc[s,'八卦']
    def shu2gua(self,s):
        if s!='五':
            return gonggua.loc[s,'八卦']
        else:
            return None
    def getGuayinyang(self,gua):
        return gonggua[gonggua['八卦']==gua]['阴阳'].values[0]
    def getTianpan(self):
        self.feixing('天盘',self.yun,'顺')
    def getShanxiangshu(self,zhong):
        #以山星为例，先按二十四山取其在地盘对应的卦，然后按后天八卦取卦数，、
        #最后按此卦数把天盘中对应的飞星找出来，飞星用数字表示
        zuogua=self.shan2gua(zhong)
        dipanguashu=gonggua[gonggua['八卦']==zuogua].index.values[0]
        return self.pan.loc[dipanguashu,'天盘'].values[0]

    def getShunniyinyang(self,zhong,shu):
        tmpbagua=self.shu2gua(shu)
        if tmpbagua:
            tmppan=shangua[shangua['八卦']==tmpbagua]
            tmpxing=tmppan[tmppan['元龙']==shangua.loc[zhong,'元龙']]
            return tmpxing,tmpxing['阴阳'].values[0]
        else:
            return None,shangua.loc[zhong,'阴阳']

    def getShanxiangpan(self,pantype,zhong,shu):
        #以山星为例，把山星数视为后天八卦数，找出对应的八卦，然后在此八卦对应的二十四山中、
        #找出与山星元龙属性相同的对应八卦的阴阳，从而决定顺飞还是逆飞。
        tmpxing,yinyang=self.getShunniyinyang(zhong,shu)
        if pantype=='山盘':
            self.shanshunni=shunnidict[yinyang]
        elif pantype=='向盘':
            self.xiangshunni=shunnidict[yinyang]
        self.feixing(pantype,shu,shunnidict[yinyang])
    def getJianshanxiangpan(self,pantype,zhong,shu):
        #与正向类似，差异在找替星过程。
        tmpxing,yinyang=self.getShunniyinyang(zhong,shu)
        if tmpxing is None:
            tmpshu=shangua.loc[zhong,'替星']
        else:
            tmpshu=tmpxing['替星'].values[0]
        if pantype=='山盘':
            self.shanshu=tmpshu
        elif pantype=='向盘':
            self.xiangshu=tmpshu
        self.feixing(pantype,tmpshu,shunnidict[yinyang])

    def getShanpan(self):
        self.getShanxiangpan('山盘',self.zuo,self.shanshu)
    def getXiangpan(self):
        self.getShanxiangpan('向盘',self.xiang,self.xiangshu)
    def getJianshanpan(self):
        self.getJianshanxiangpan('山盘',self.zuo,self.shanshu)
    def getJianxiangpan(self):
        self.getJianshanxiangpan('向盘',self.xiang,self.xiangshu)

    def getShanxianglocation(self,shanxiang):
        return self.shan2gua(shanxiang)

    def getStarsyun(self):

        tmp=self.pan[['生旺','天盘']]
        tmp=tmp.set_index('生旺')
        yundict=dict.fromkeys(list('旺生死煞退'))
        yundict['旺']=gonggua.loc[tmp.loc['旺'].values.tolist()[0],'九星']
        yundict['退']=gonggua.loc[tmp.loc['退'].values.tolist()[0],'九星']
        yundict['生']=gonggua.loc[[i[0] for i in tmp.loc['生'].values.tolist()],'九星'].values.tolist()
        yundict['煞']=gonggua.loc[[i[0] for i in tmp.loc['煞'].values.tolist()],'九星'].values.tolist()
        yundict['死']=gonggua.loc[[i[0] for i in tmp.loc['死'].values.tolist()],'九星'].values.tolist()

        return yundict

    def isWangshanWangshui(self,shanbagua,xiangbagua):

        tmpshanshu=self.getBybagua(shanbagua)['山盘'].values[0]
        tmpxiangshu=self.getBybagua(xiangbagua)['向盘'].values[0]
        if tmpshanshu==self.yun and tmpxiangshu==self.yun:
            return True,['旺山旺水']
        else:
            return False,['无']
    def isShangshanxiashui(self,shanbagua,xiangbagua):
        tmpshanshu=self.getBybagua(xiangbagua)['山盘'].values[0]
        tmpxiangshu=self.getBybagua(shanbagua)['向盘'].values[0]
        if tmpshanshu==self.yun and tmpxiangshu==self.yun:
            return True,['上山下水']
        else:
            return False,['无']
    def isShuangxinghuixiang(self,shanbagua,xiangbagua):
        tmpshanshu=self.getBybagua(xiangbagua)['山盘'].values[0]
        tmpxiangshu=self.getBybagua(xiangbagua)['向盘'].values[0]
        if tmpshanshu==self.yun and tmpxiangshu==self.yun:
            return True,['双星会向']
        else:
            return False,['无']
    def isShuangxinghuizuo(self,shanbagua,xiangbagua):
        tmpshanshu=self.getBybagua(shanbagua)['山盘'].values[0]
        tmpxiangshu=self.getBybagua(shanbagua)['向盘'].values[0]
        if tmpshanshu==self.yun and tmpxiangshu==self.yun:
            return True,['双星会坐']
        else:
            return False,['无']
    def isFufuheshi(self):

        tmppan=deepcopy(self.pan)
        tmppan['山盘数']=self.pan['山盘'].apply(lambda x:shudict[x])
        tmppan['向盘数']=self.pan['向盘'].apply(lambda x:shudict[x])
        tmppan['天盘数']=self.pan['天盘'].apply(lambda x:shudict[x])
        if (tmppan['山盘数']+tmppan['天盘数']==10).all() or (tmppan['山盘数']+tmppan['向盘数']==10).all() or (tmppan['向盘数']+tmppan['天盘数']==10).all():
            return True,['全局合十']
        elif tmppan.loc[self.shanshu,'天盘数'].values[0]+tmppan.loc[self.xiangshu,'天盘数'].values[0]==10 and tmppan.loc[self.shanshu,'天盘数'].values[0]+tmppan.loc[self.xiangshu,'天盘数'].values[0]==10 and tmppan.loc[self.shanshu,'天盘数'].values[0]+tmppan.loc[self.xiangshu,'天盘数'].values[0]==10:
            return True,['对宫合十']
        else:
            return False,['无']
    def isFuyin(self):
        geju=[]
        #全局伏吟
        if self.shanshu=='五' and (self.pan['山盘']==self.pan['地盘']).any() and self.shanshunni=='顺':
            geju.extend(['山星伏吟'])
        elif self.shanshu=='五' and (self.pan['向盘']==self.pan['地盘']).any() and self.xiangshunni=='顺':
            geju.extend(['向星伏吟'])
        #单宫伏吟
        shandanyin=self.pan[(self.pan['山盘']==self.pan['地盘'])|(self.pan['山盘']==self.pan['地盘'])]
        xiangdanyin=self.pan[(self.pan['向盘']==self.pan['地盘'])|(self.pan['向盘']==self.pan['地盘'])]
        shandanyin=shandanyin.dropna(axis=0)
        xiangdanyin=xiangdanyin.dropna(axis=0)
        if not shandanyin.empty:
            geju.extend(['伏吟在山，宫位在'+''.join(shandanyin.index.get_level_values('八卦').tolist())])
        elif not xiangdanyin.empty:
            geju.extend(['伏吟在向，宫位在'+''.join(xiangdanyin.index.get_level_values('八卦').tolist())])
        if geju:
            return True,geju
        else:
            return False,['无']
    def isFanyin(self):
        geju=[]
        #全局反吟
        if self.shanshu=='五' and (self.pan['山盘']==self.pan['地盘']).any() and self.shanshunni=='逆':
            geju.extend(['山星伏吟'])
        elif self.shanshu=='五' and (self.pan['向盘']==self.pan['地盘']).any() and self.xiangshunni=='逆':
            geju.extend(['向星伏吟'])
        #单宫反吟，注意与单宫伏吟规则不同
        tmppan=deepcopy(self.pan)
        tmppan['山盘数']=self.pan['山盘'].apply(lambda x:shudict[x])
        tmppan['向盘数']=self.pan['向盘'].apply(lambda x:shudict[x])
        tmppan['地盘数']=self.pan['地盘'].apply(lambda x:shudict[x])
        tmppan['山地合十']=tmppan['山盘数']+tmppan['地盘数']
        tmppan['向地合十']=tmppan['向盘数']+tmppan['地盘数']

        shandanyin=tmppan[tmppan['山地合十']==10]
        xiangdanyin=tmppan[tmppan['向地合十']==10]
        shandanyin=shandanyin.dropna(axis=0)
        xiangdanyin=xiangdanyin.dropna(axis=0)
        if not shandanyin.empty:
            geju.extend(['反吟在山，宫位在'+''.join(shandanyin.index.get_level_values('八卦').tolist())])
        elif not xiangdanyin.empty:
            geju.extend(['反吟在向，宫位在'+''.join(xiangdanyin.index.get_level_values('八卦').tolist())])
        if geju:
            return True,geju
        else:
            return False,['无']
    def isJianfufanyin(self):
        if self.isjian and self.yun=='五':
            if self.zuo+self.xiang in '乾巽 巽乾 亥巳 巳亥 辰戌 戌辰'.split():
                return True,['替卦反伏吟']
            else:
                return False,['无']
        else:
            return False,['无']
    def isLianzhusanban(self):
        lianzhu=sorted([shudict[self.yun],shudict[self.shanshu],shudict[self.xiangshu]])
        if lianzhu[1]-lianzhu[0]==1 and lianzhu[2]-lianzhu[1]==1:
            return True,['连珠三般']
        else:
            return False,['无']
    def isFumusanban(self):
        lianzhu=sorted([shudict[self.yun],shudict[self.shanshu],shudict[self.xiangshu]])
        if lianzhu[1]-lianzhu[0]==3 and lianzhu[2]-lianzhu[1]==3:
            return True,['父母三般']
        else:
            return False,['无']
    def isLigongdajie(self,shanbagua,xiangbagua):
        tmpxiangshu=self.getBybagua(xiangbagua)['向盘'].values[0]
        xiangsanban=bool()
        shansanban=bool()
        if tmpxiangshu==self.yun:
            qianxiang=self.getBybagua('乾')['向盘'].values[0]
            lixiang=self.getBybagua('离')['向盘'].values[0]
            zhenxiang=self.getBybagua('震')['向盘'].values[0]
            xianglianzhu=sorted([shudict[qianxiang],shudict[lixiang],shudict[zhenxiang]])
            if xianglianzhu[1]-xianglianzhu[0]==3 and xianglianzhu[2]-xianglianzhu[1]==3:
                xiangsanban=True
            qianshan=self.getBybagua('乾')['山盘'].values[0]
            lishan=self.getBybagua('离')['山盘'].values[0]
            zhenshan=self.getBybagua('震')['山盘'].values[0]
            shanlianzhu=sorted([shudict[qianshan],shudict[lishan],shudict[zhenshan]])
            if shanlianzhu[1]-shanlianzhu[0]==3 and shanlianzhu[2]-shanlianzhu[1]==3:
                shansanban=True
            if xiangsanban and shansanban and xianglianzhu==shanlianzhu:
                return True,['离宫打劫']
            else:
                return False,['无']
        else:
            return False,['无']
    def isKangongdajie(self,shanbagua,xiangbagua):
        tmpxiangshu=self.getBybagua(xiangbagua)['向盘'].values[0]
        xiangsanban=bool()
        shansanban=bool()
        if tmpxiangshu==self.yun:
            qianxiang=self.getBybagua('巽')['向盘'].values[0]
            lixiang=self.getBybagua('坎')['向盘'].values[0]
            zhenxiang=self.getBybagua('兑')['向盘'].values[0]
            xianglianzhu=sorted([shudict[qianxiang],shudict[lixiang],shudict[zhenxiang]])
            if xianglianzhu[1]-xianglianzhu[0]==3 and xianglianzhu[2]-xianglianzhu[1]==3:
                xiangsanban=True
            qianshan=self.getBybagua('巽')['山盘'].values[0]
            lishan=self.getBybagua('坎')['山盘'].values[0]
            zhenshan=self.getBybagua('兑')['山盘'].values[0]
            shanlianzhu=sorted([shudict[qianshan],shudict[lishan],shudict[zhenshan]])
            if shanlianzhu[1]-shanlianzhu[0]==3 and shanlianzhu[2]-shanlianzhu[1]==3:
                shansanban=True
            if xiangsanban and shansanban and xianglianzhu==shanlianzhu:
                return True,['坎宫打劫']
            else:
                return False,['无']
        else:
            return False,['无']
    def isRuqiushan(self):
        if self.yun!='五':
            if not self.isjian:
                if shudict[self.yun]+1==shudict[self.shanshu]:
                    return True
                else:
                    return False
            else:
                if shudict[self.yun]==shudict[self.shanshu]:
                    return True
                else:
                    return False
    def isRuqiuxiang(self):
        if self.yun!='五':
            if not self.isjian:
                if shudict[self.yun]+1==shudict[self.xiangshu]:
                    return True
                else:
                    return False
            else:
                if shudict[self.yun]==shudict[self.xiangshu]:
                    return True
                else:
                    return False
    def getWenchangwei(self):
        tmppan=deepcopy(self.pan)
        tmppan=tmppan[['天盘','山盘','向盘']]
        tmppan['三盘数']=tmppan['天盘']+tmppan['山盘']+tmppan['向盘']
        tmppan=tmppan[tmppan['三盘数'].str.contains('一四')|tmppan['三盘数'].str.contains('四一')]
        tmppan=tmppan.dropna()
        words=[]
        if not tmppan.empty:
            words=''.join(tmppan.index.get_level_values('八卦').tolist())
        if words:
            if '巽' in words:
                return words
            else:
                return '巽'+words
        else:
            return '巽'

    def getCaiwei(self):
        shengwang=[v[0] for k,v in self.xingyun.items() if k in ['生','旺']]
        cond1=self.pan['向盘'].isin(shengwang)

        tmp=self.pan['向盘'][cond1]
        tmp=self.pan.loc[tmp.index,['天盘','山盘','向盘']]
        tmp['山向']=tmp['山盘']+tmp['向盘']
        tmp['山向list']=tmp['山向'].apply(lambda x:list(x))
        caiweizuhe['组合list']=caiweizuhe['组合'].apply(lambda x:list(x))
        caiwei=[]
        zuhe=[]
        for k,v in tmp['山向list'].iteritems():
            if v in caiweizuhe['组合list'].tolist():
                caiwei.extend(k[1])
                if v[0]+v[1] in caiweizuhe['组合'].tolist():
                    zuhe.extend(caiweizuhe[caiweizuhe['组合']==v[0]+v[1]]['解释'])
                else:
                    zuhe.extend(caiweizuhe[caiweizuhe['组合']==v[1]+v[0]]['解释'])

        if caiwei:
            total=zip(caiwei,zuhe)
            words=[i[0]+'，'+i[1] for i in total]
            return ';'.join(words)
        else:
            caiwei=[i[1] for i in tmp.index.values]
            return '、'.join(caiwei)+'，但财位相对强度弱'

    def isGeju(self,*args):
        if args[0][0]:
            self.geju.extend(args[0][1])
    def getGeju(self):
        shanbagua=self.getShanxianglocation(self.zuo)
        xiangbagua=self.getShanxianglocation(self.xiang)
        self.isGeju(self.isWangshanWangshui(shanbagua,xiangbagua))
        self.isGeju(self.isShangshanxiashui(shanbagua,xiangbagua))
        self.isGeju(self.isShuangxinghuixiang(shanbagua,xiangbagua))
        self.isGeju(self.isShuangxinghuizuo(shanbagua,xiangbagua))
        self.isGeju(self.isFufuheshi())
        self.isGeju(self.isFuyin())
        self.isGeju(self.isFanyin())
        self.isGeju(self.isJianfufanyin())
        self.isGeju(self.isLigongdajie(shanbagua,xiangbagua))
        self.isGeju(self.isKangongdajie(shanbagua,xiangbagua))
    def getLiunianyun(self,liunian):
            for i in range(9):
                if liunian>=yuanyun.loc[i,'起始'] and liunian<=yuanyun.loc[i,'终止']:
                    return yuanyun.loc[i,'运']
    def getLiunianfeixing(self):
        return self.feixing_notpan('流年紫白飞星',nianzb.loc[c.get_cycle_ymd(dt.datetime(self.liunian,4,1))[0],self.liunianyun].values[0],'顺')
    def getSanshen(self):
        zheng=self.yun
        ling=zidict[10-shudict[zheng]]
        zhao1,zhao2=jiu.shun(ling,2),jiu.ni(ling,2)
        return zheng,ling,(zhao1,zhao2)
    def getShengkebi(self,zhu,ke):
        if shengke.loc[zhu,'生']==ke:
            return '生入'
        elif shengke.loc[zhu,'克']==ke:
            return '克入'
        elif shengke.loc[ke,'生']==zhu:
            return '生出'
        elif shengke.loc[ke,'克']==zhu:
            return '克出'
        elif zhu==ke:
            return '比'
    def getXingshengkebi(self,zhuxing,kexing):
        zhu=gonggua.loc[zhuxing,'五行']
        ke=gonggua.loc[kexing,'五行']
        skb=self.getShengkebi(zhu,ke)
        return zhu,ke,skb

class People():
    def __init__(self,name,gender,year,month,day,hour=0):

        self.name=name
        self.gender=gender
        self.birthday=c.get_cycle_ymd(dt.datetime(year,month,day))
        tmpbirthday=c.get_cycle_ymd(dt.datetime(year,1,1))
        if tmpbirthday==self.birthday[0]:
            for i in [0,3,6]:
                if year-1>=yuanyun.loc[i,'起始'] and year-1<=yuanyun.loc[i+2,'终止']:
                    self.yuan=yuanyun.loc[i,'元']
        else:
            for i in [0,3,6]:
                if year>=yuanyun.loc[i,'起始'] and year<=yuanyun.loc[i+2,'终止']:
                    self.yuan=yuanyun.loc[i,'元']
        self.minggua=self.getBazhai()
        self.birthdayfull=self.getbirthday(year,month,day,hour,'阳历')
        self.sizhu=self.get_sizhu(self.birthdayfull)

    def getBazhai(self):
        mingguadict=dict.fromkeys('命卦 配卦 阴阳方 八宅星 化权 化科 化吉 化凶'.split())
        mingguadict['命卦']=minggua.loc[self.yuan,self.birthday[0]][self.gender]
        if mingguadict['命卦'] in '坎离震巽'.split():
            mingguadict['配卦']='东四命'
            mingguadict['阴阳方']='乾坎艮震'
        else:
            mingguadict['配卦']='西四命'
            mingguadict['阴阳方']='巽离坤兑'
        mingguadict['八宅星']=bazhai.loc[mingguadict['命卦']]
        mingguadict['化权']=mingguadict['八宅星'][mingguadict['八宅星']=='延年'].dropna().index.values[0]
        mingguadict['化科']=mingguadict['八宅星'][mingguadict['八宅星']=='天医'].dropna().index.values[0]
        mingguadict['化吉']=mingguadict['八宅星'][mingguadict['八宅星'].isin(['生气','延年','天医'])].dropna().index.values.tolist()
        mingguadict['化凶']=mingguadict['八宅星'][mingguadict['八宅星'].isin(['伏位','五鬼','六煞','绝命','祸害'])].dropna().index.values.tolist()

        return mingguadict

    def getbirthday(self,year,month,day,hour,birthdaytype):

        f=open(datafolder+'万年历.txt')
        cal=pd.read_csv(f,header=0,index_col=0,encoding='utf-8')
        if birthdaytype=='阳历':
            l=cal.loc[dt.date(year,month,day).strftime('%Y-%m-%d')]

            return {'阳历':dt.datetime(year,month,day,hour),\
                    '阴历':{'生日':[l[0],l[1],l[2],hour]}
                    }
        elif birthdaytype=='阴历':

            l=LunarDate(year,month,day,isLeapMonth).toSolarDate()
            return {'阳历':dt.datetime(l[0],l[1],l[2],hour),\
                    '阴历':{'生日':[year,month,day,hour]}
                    }

    def get_sizhu(self,t):
        yanli=t['阳历']
        year_zhu,month_zhu,day_zhu=c.get_cycle_ymd(yanli)
        yinli=t['阴历']['生日']
        year_zhu=c.get_cycle_year(yinli[0])
        '''
        month_tg=2*tiangan2numDict[year_zhu[0]]+yint.month
        if month_tg<=10:
                t_tg=num2tianganDict[month_tg]
            else:
                t_tg=num2tianganDict[month_tg%10]
        month_dz=num2numDict[yint.month]
        '''
        t_dz=num2dizhiDict[math.ceil(yinli[3]/2)+1]
        tmp=math.ceil(yinli[3]/2)+tiangan2numDict[day_zhu[0]]*2-1

        t_tg=num2tianganDict[self.TianganCycleCheck(tmp)]
        return [year_zhu,month_zhu,day_zhu,t_tg+t_dz]

    def TianganCycleCheck(self,num):
        if num==10:
            return 10
        elif num%10==0:
            return 10
        elif num<10 and num>0:
            return num
        elif num<0 and num>-10:
            return num+10
        elif num<-10 and num>-20:
            return num+20
        else:
            return num%10

    def sizhuwuxing(self):
        swxdict=dict()
        index='年月日时'
        for i,item in enumerate(self.sizhu):
            swxdict.update({index[i]:{'天干':tianganexcel.loc[item[0],'五行'],'地支':dizhiexcel.loc[item[1],'五行']}})
        swxdf=pd.DataFrame.from_dict(swxdict,orient='index')
        wxdict=dict.fromkeys(list('木火土金水'))
        values=swxdf.values.reshape(1,-1).tolist()[0]
        wxdict['木']=values.count('木')
        wxdict['火']=values.count('火')
        wxdict['土']=values.count('土')
        wxdict['金']=values.count('金')
        wxdict['水']=values.count('水')
        wxser=pd.Series(wxdict)
        wxser.sort_values(inplace=True)
        if wxser.iloc[0:4].sum()==0:
            return wxser.index[0],wxser.index[1],wxser.index[2],wxser.index[3]
        elif wxser.iloc[0:3].sum()==0:
            return wxser.index[0],wxser.index[1],wxser.index[2]
        elif wxser.iloc[0:2].sum()==0:
            return wxser.index[0],wxser.index[1]
        else:
            return wxser.index[0]

if __name__=='__main__':
    #l=Location(35)
    #print(l.zuo,l.xiang,l.jianzuo,l.jianxiang)
    #a=House(1963,2013,'坤','艮')
    #a=House(2004,2013,'乙','辛')
    #print(a.pan['生旺'],a.xingyun)

    b=People('xx','男',1985,10,2,14)
    b.sizhuwuxing()
    #print(b.birthday,b.yuan,b.minggua)
    #a.getFigure()


N, M = list(map(int,input().split()))

MAP = []
for _ in range(N):
    MAP.append(list(map(int,input().split())))

DP=[[0]*M for _ in range(N)]

temp = 0

for i in range(N):
    if MAP[i][0] == 0:
        DP[i][0] = 1
        temp = 1
    else:
        DP[i][0] = 0

for j in range(M):
    if MAP[0][j] == 0:
        DP[0][j] = 1
        temp = 1
    else:
        DP[0][j] = 0

for i in range(1,N):
    for j in range(1,M):

        if MAP[i][j] == 0:

            DP[i][j] = min(DP[i-1][j-1],DP[i-1][j],DP[i][j-1])+1

            temp = max(temp, DP[i][j])

print(temp)


# Licensed under a 3-clause BSD style license - see LICENSE.rst

import re

from astropy import log
import bottleneck as bn
import numpy as np

from sofia_redux.instruments.exes.lincor import lincor
from sofia_redux.instruments.exes.get_badpix import get_badpix
from sofia_redux.instruments.exes.utils import get_reset_dark

__all__ = ['readraw']

def readraw(data, header, do_lincor=False, algorithm=None,
            toss_nint=0, copy_int=True):
    """
    Correct for nonlinearity combine individual readouts.

    First corrects nonlinearity for each readout frame (`exes.lincor`),
    then determines the readout pattern from the OTPAT keyword.

    For readout coadding methods, this step currently has support for Fowler
    mode, simple destructive read, and equally spaced sample-up-the-ramp
    patterns.  Frames are combined and variance is calculated based on the
    readout pattern, using algorithms from the following paper:

        Nonlinearity Corrections and Statistical Uncertainties
        Associated with Near-Infrared Arrays, William D. Vacca,
        Michael C. Cushing and John T. Rayner (2004, PASP 116, 352).

    The readout algorithm may also be directly specified by the `algorithm`
    parameter, which takes the following possible integer values:

        - 0 : Use the last destructive frame only
        - 1 : Simple destructive mode
        - 2 : Use the first and last frames only
        - 3 : Use the second and penultimate frames only
        - 4 : Fowler mode
        - 5 : Sample-up-the-ramp mode

    After readout coadd, multiple frames taken at the same nod position (as
    indicated by the NINT keyword) are averaged.  Extra frames that
    do not match the OTPAT or NINT pattern are dropped.

    Parameters
    ----------
    data : numpy.ndarray
        [nframe, nspec, nspat] array of float values.
    header : fits.Header
        FITS header produced by `exes.readhdr`.  Note that the header will
        be updated in-place.
    do_lincor : bool, optional
        If True, do the nonlinear correction.  If False, no check is
        performed on data quality: the output mask will be all False
        (no bad pixels).
    algorithm : int, optional
        Used to select processing mode.  If None, defaults to that determined
        by `check_readout_pattern`.
    toss_nint : int, optional
        If provided and greater than 0 but less than the number of
        integrations present in the data, `toss_nint` integrations will be
        discarded from the beginning of the data array.  If the number
        equals the number of integrations, the first nod is a B nod,
        and there is another B nod in the data array, the first integrations
        are instead replaced with a copy of the second B nod.
    copy_int : bool, optional
        If `toss_nint` is greater than 0 and `copy_int` is True, replacement
        integrations are always copied from the next B nod, regardless of
        the number of integrations available.

    Returns
    -------
    coadd_data, variance, mask : 3-tuple of numpy.ndarray
       The coadded data, variance, and good data mask.  The coadd_data and
       variance have shape (nframes, ny, nx).  The mask has shape (ny, nx)
       and Boolean data type, where True indicates a good pixel; False
       indicates a bad pixel.
    """
    _check_header(header)
    data = _check_data(data)
    data, mask = _get_data_subarray(data, header)
    data, readmode = _check_readout_pattern(data, header)

    if isinstance(algorithm, int):
        touse_lookup = {
            0: 'last destructive',
            1: 'destructive',
            2: 'first/last nd',
            3: 'second/penultimate nd',
            4: 'fowler',
            5: 'sample-up-the-ramp'}
        touse = touse_lookup.get(algorithm)
        if touse is None:
            raise ValueError(f'Invalid algorithm: {touse}')
    else:
        touse = readmode['mode']

    if do_lincor:
        log.info("Applying linear correction")
        lindata, linmask = lincor(data, header)
        # "And" the output mask to get all nonlinear detector pixels
        mask &= np.all(linmask, axis=0)
    else:
        log.info("Linear correction not applied: do_lincor=False")
        lindata = data.copy()

    log.info('')
    log.info(f'Using read mode algorithm: {touse}')
    log.info('')
    if touse == 'destructive' or touse == 'last destructive':
        coadd_data, variance = _process_destructive(data, header, readmode)
    elif touse == 'first/last nd':
        coadd_data, variance = _process_nondestructive1(
            lindata, header, readmode)
    elif touse == 'second/penultimate nd':
        coadd_data, variance = _process_nondestructive2(
            lindata, header, readmode)
    elif touse == 'fowler':
        coadd_data, variance = _process_fowler(lindata, header, readmode)
    elif touse == 'sample-up-the-ramp':
        coadd_data, variance = _process_sample_up_the_ramp(
            data, header, readmode)
    else:  # pragma: no cover
        # shouldn't be reachable
        raise ValueError(f'Unrecognized readmode: {readmode["mode"]}')

    coadd_data, variance = _combine_nods(coadd_data, variance, header,
                                         readmode, toss_nint, copy_int)

    return coadd_data, variance, mask

def _get_data_subarray(data, header):
    ectpat = str(header.get('ECTPAT', 'UNKNOWN')).split()
    if len(ectpat) == 6:
        ectpat = np.asarray(ectpat, dtype=int)
        ystart = ectpat[2] * 2
        ystop = ystart + (ectpat[3] * 2)
        xstart = ectpat[4]
        xstop = xstart + (ectpat[5])
    else:
        xstart = 0
        xstop = data.shape[2]
        ystart = 0
        ystop = data.shape[1]

    nframes, ny, nx = data.shape

    bpm = get_badpix(header)
    if bpm is not None:
        if bpm.shape[0] < ny or bpm.shape[1] < nx:
            raise ValueError(
                "Bad pixel mask is too small %s; data shape is %s" %
                (repr(bpm.shape), repr(data.shape[1:])))

        # Reference columns are marked as 2 in the badpix mask
        refidx = bpm == 2
        if refidx.any():
            xrange = np.where(~refidx)[1]
            data = data[:, :, xrange.min():xrange.max() + 1]
            bpm = bpm[:, xrange.min():xrange.max() + 1]
            nx = data.shape[2]
            xstart = 0
            xstop = nx

        # Take subarray if needed
        bpm = bpm[ystart:ystop, xstart:xstop]

    mask = np.full((ny, nx), True)
    if bpm is not None:
        mask[bpm != 1] = False

    # Store data size
    header['DETSEC'] = '[%i:%i,%i:%i]' % (
        xstart + 1, xstop, ystart + 1, ystop)
    header['NSPAT'] = nx
    header['NSPEC'] = ny

    # Correct frametime for subarray size as needed
    header['FRAMETIM'] *= ny / 1024.

    return data, mask

def _check_header(header):
    """Ensure header values are of the correct type"""
    header['OTPAT'] = str(header['OTPAT']).upper().strip()
    header['NINT'] = int(header['NINT'])
    header['FRAMETIM'] = float(header['FRAMETIM'])
    header['READNOIS'] = float(header['READNOIS'])
    header['DARKVAL'] = float(header['DARKVAL'])

    try:
        header['PAGAIN'] = float(header['PAGAIN'])
    except (KeyError, ValueError):
        header['PAGAIN'] = 1.0

    try:
        header['EPERADU'] = float(header['EPERADU'])
    except (KeyError, ValueError):
        header['EPERADU'] = 1.0

def _check_data(data):
    data = np.asarray(data, dtype=float)
    if data.ndim == 2:
        data = data[None]
    if data.ndim != 3:
        raise ValueError("Data must be a 3-D cube (nframe, nspec, nspat)")
    return data

def _check_readout_pattern(data, header):
    regex = re.compile('[STNDC][0-9]+')
    if regex.match(header['OTPAT']) is None:
        raise ValueError("Unreadable OT pattern. OTPAT=%s" % header['OTPAT'])
    patterns = regex.findall(header['OTPAT'])

    spin = trash = nondest = dest = coadd = nread = npass = 0
    for pattern in patterns:
        optype, n_op = pattern[0], int(pattern[1:]) + 1
        if optype == 'S':
            spin += n_op
            npass += n_op
        elif optype == 'T':
            trash += n_op
        elif optype == 'D':
            dest += n_op
            npass += n_op
        elif optype == 'C':
            coadd += n_op
            dest += n_op
            npass += n_op
        elif optype == 'N':
            nread += 1
            nondest += n_op
            npass += n_op

    nframes = coadd if coadd > 0 else (nondest + dest)
    npattern = data.shape[0] // nframes
    if npattern == 0:
        raise ValueError(f"Data does not match OTPAT={header['OTPAT']}."
                         " A full pattern is not present; aborting.")
    elif (npattern * nframes) != data.shape[0]:
        log.warning(f"Data does not match OTPAT={header['OTPAT']}."
                    " Dropping extra frames.")
        data = data[:npattern * nframes]

    if nread == 2 or (nread == 1 and nondest == 1):
        mode = 'fowler'
    elif nondest == 0 and dest == 1 and nframes == 1:
        mode = 'destructive'
    elif nondest != 0 and dest == 1:
        mode = 'sample-up-the-ramp'
    else:
        raise ValueError("Unrecognized readmode")

    log.info('')
    log.info(f"Readout pattern: {header['OTPAT']}")
    log.info(f"Frame(s) per pattern: {nframes}")
    log.info(f"Total frames: {data.shape[0]}")
    log.info(f"Recommended readout mode: {mode}")

    readmode = {'spin': spin,
                'trash': trash,
                'nondest': nondest,
                'dest': dest,
                'coadd': coadd,
                'nread': nread,
                'npass': npass,
                'nframes': nframes,
                'npattern': npattern,
                'mode': mode}

    return data, readmode

def _process_destructive(data, header, readmode):
    # Using D only
    log.info('Last destructive read')
    frametime = float(header['FRAMETIM'])
    interval = (readmode['dest'] + readmode['nondest']
                + readmode['spin']) * frametime
    log.info(f'Interval = {interval}')

    read_noise = float(header['READNOIS'])
    gain = float(header['PAGAIN'])
    eperadu = float(header['EPERADU'])
    zeroval = float(header['DARKVAL']) / (frametime * gain)
    gain_factor = interval * gain
    v_gain_factor = interval * eperadu

    shape = readmode['npattern'], data.shape[1], data.shape[2]
    coadd_data = np.empty(shape, dtype=float)
    variance = np.empty(shape, dtype=float)

    dark1s = get_reset_dark(header)
    for i in range(readmode['npattern']):
        if readmode['coadd'] == 1:  # pragma: no cover
            # The Fowler coadd/subtraction should have been done in hardware
            # (this OTPAT was never used for EXES)
            coadd_data[i] = zeroval - data[i] / gain_factor
        else:
            pattern_start = i * readmode['nframes']
            pattern_end = pattern_start + readmode['nframes']
            signal = data[pattern_end - 1]
            coadd_data[i] = zeroval - (signal - dark1s[None]) / gain_factor

        variance[i] = (np.abs(coadd_data[i]) / v_gain_factor
                       + (read_noise / v_gain_factor) ** 2)

    header['NFRAME'] = 1
    header['BEAMTIME'] = interval
    return coadd_data, variance

def _process_nondestructive1(lindata, header, readmode):
    if readmode['nondest'] + readmode['dest'] < 2:
        raise ValueError('OTPAT is not suitable for First/Last ND mode')

    log.info("First/Last ND mode")
    frametime = float(header['FRAMETIM'])
    nread = (readmode['nondest'] + readmode['dest']) // 2

    interval = (readmode['dest']
                + readmode['nondest']
                + readmode['spin'] - 1) * frametime
    log.info(f'Interval = {interval}')

    gain = float(header['PAGAIN'])
    gainfac = gain * interval
    vgainfac = float(header['EPERADU']) * interval
    readnoise = float(header['READNOIS'])
    darkval = float(header['DARKVAL'])
    zeroval = darkval / (frametime * gain)
    nframes = readmode['nframes']

    shape = readmode['npattern'], lindata.shape[1], lindata.shape[2]
    coadd_data = np.empty(shape, dtype=float)
    variance = np.empty(shape, dtype=float)

    for i in range(shape[0]):
        if readmode['coadd'] == 1:  # pragma: no cover
            # (this OTPAT was never used for EXES)
            coadd_data[i] = zeroval - lindata[i] / gainfac
        else:
            pattern_start = i * nframes  # 1st frame
            pattern_end = pattern_start + nframes  # last frame
            pattern_data = lindata[pattern_start:pattern_end]
            pedestal = pattern_data[0]
            signal = pattern_data[pattern_end - pattern_start - 1]
            coadd_data[i] = zeroval - ((signal - pedestal) / gainfac)

        variance[i] = ((np.abs(coadd_data[i]) / vgainfac)
                       * (1 - (frametime * (nread ** 2 - 1))
                          / (3 * interval * nread))
                       + 2 * (readnoise ** 2) / ((vgainfac ** 2) * nread))

    header['NFRAME'] = nread
    header['BEAMTIME'] = interval
    return coadd_data, variance

def _process_nondestructive2(lindata, header, readmode):
    if readmode['nondest'] + readmode['dest'] < 4:
        raise ValueError('OTPAT is not suitable for '
                         'Second/Penultimate ND mode')

    log.info("Second/Penultimate ND mode")
    frametime = float(header['FRAMETIM'])
    nread = (readmode['nondest'] - 1) // 2

    interval = (readmode['nondest'] + readmode['spin'] - 2) * frametime
    log.info(f'Interval = {interval}')

    gain = float(header['PAGAIN'])
    gainfac = gain * interval
    vgainfac = float(header['EPERADU']) * interval
    readnoise = float(header['READNOIS'])
    darkval = float(header['DARKVAL'])
    zeroval = darkval / (frametime * gain)
    nframes = readmode['nframes']

    shape = readmode['npattern'], lindata.shape[1], lindata.shape[2]
    coadd_data = np.empty(shape, dtype=float)
    variance = np.empty(shape, dtype=float)

    for i in range(shape[0]):
        if readmode['coadd'] == 1:  # pragma: no cover
            # (this OTPAT was never used for EXES)
            coadd_data[i] = zeroval - lindata[i] / gainfac
        else:
            pattern_start = i * nframes + 1  # 2nd frame
            pattern_end = pattern_start + nframes - 2  # penultimate frame
            pattern_data = lindata[pattern_start:pattern_end]
            pedestal = pattern_data[0]

            signal = pattern_data[pattern_end - pattern_start - 1]
            coadd_data[i] = zeroval - ((signal - pedestal) / gainfac)

            variance[i] = ((np.abs(coadd_data[i]) / vgainfac)
                           * (1 - (frametime * (nread ** 2 - 1))
                              / (3 * interval * nread))
                           + 2 * (readnoise ** 2) / ((vgainfac ** 2) * nread))

    header['NFRAME'] = nread
    header['BEAMTIME'] = interval
    return coadd_data, variance

def _process_fowler(lindata, header, readmode):
    log.info("Fowler mode")
    frametime = float(header['FRAMETIM'])
    gain = float(header['PAGAIN'])
    eperadu = float(header['EPERADU'])
    readnoise = float(header['READNOIS'])
    darkval = float(header['DARKVAL'])
    zeroval = darkval / (frametime * gain)

    nread = (readmode['nondest'] + readmode['dest']) // 2
    interval = (readmode['npass'] - nread) * frametime
    gainfac = interval * gain
    vgainfac = interval * eperadu
    log.info(f'Interval = {interval}')

    shape = readmode['npattern'], lindata.shape[1], lindata.shape[2]
    coadd_data = np.empty(shape, dtype=float)
    variance = np.empty(shape, dtype=float)

    for i in range(shape[0]):
        if readmode['coadd'] == 1:  # pragma: no cover
            # The Fowler coadd/subtraction should have been done in hardware
            # (this OTPAT was never used for EXES)
            coadd_data[i] = zeroval - lindata[i] / gainfac
        else:
            pattern_start = i * readmode['nframes']
            pattern_end = pattern_start + readmode['nframes']
            pattern_data = lindata[pattern_start:pattern_end]

            if nread > 1:
                # Add initial reads for pedestal level
                pedestal = bn.nansum(pattern_data[:nread], axis=0)
                # Add final reads for signal level
                signal = bn.nansum(
                    pattern_data[nread:readmode['nframes']], axis=0)
            else:
                pedestal = pattern_data[0]
                signal = pattern_data[1]
            coadd_data[i] = zeroval - ((signal - pedestal) / (nread * gainfac))

        variance[i] = ((np.abs(coadd_data[i]) / vgainfac)
                       * (1 - (frametime * (nread ** 2 - 1))
                          / (3 * interval * nread))
                       + 2 * (readnoise ** 2) / ((vgainfac ** 2) * nread))

    header['NFRAME'] = nread
    header['BEAMTIME'] = interval
    return coadd_data, variance

def _process_sample_up_the_ramp(data, header, readmode):
    if readmode['nondest'] + readmode['dest'] < 3:
        raise ValueError('OTPAT is not suitable for '
                         'Second/Penultimate ND mode')

    log.info("Sample-up-the-ramp mode")
    frametime = float(header['FRAMETIM'])
    gain = float(header['PAGAIN'])
    eperadu = float(header['EPERADU'])
    darkval = float(header['DARKVAL'])
    zeroval = darkval / (frametime * gain)
    readnoise = float(header['READNOIS'])

    nread = readmode['nframes']
    interval = (readmode['npass'] - 1) * frametime
    alpha = nread * (nread + 1) // 12
    gainfac = interval * gain
    vgainfac = interval * eperadu
    log.info(f'Interval = {interval}')

    shape = readmode['npattern'], data.shape[1], data.shape[2]
    coadd_data = np.empty(shape, dtype=float)
    variance = np.empty(shape, dtype=float)

    for i in range(readmode['npattern']):
        if readmode['coadd'] == 1:  # pragma: no cover
            # The SUTR fit should have been done in hardware
            # (this OTPAT was never used for EXES)
            coadd_data[i] = zeroval - (data[i] / gainfac)
        else:
            nframes = readmode['nframes']
            pattern_start = i * nframes
            pattern_end = pattern_start + nframes
            pattern_data = data[pattern_start:pattern_end]

            fac = ((np.arange(nread) + 1) - ((nread + 1) / 2)) / alpha
            s = bn.nansum(pattern_data[:nread] * fac[:, None, None], axis=0)
            coadd_data[i] = zeroval - (s / gainfac)

        variance[i] = (6 * np.abs(coadd_data[i]) * ((nread ** 2) + 1))
        variance[i] /= (5 * vgainfac * nread * (nread + 1))
        variance[i] += ((12 * (readnoise ** 2) * (nread - 1))
                        / ((vgainfac ** 2) * nread * (nread + 1)))

    header['NFRAME'] = nread
    header['BEAMTIME'] = interval
    return coadd_data, variance

def _combine_nods(coadd_data, variance, header, readmode, toss_nint, copy_int):
    # Check for multiple frames at the same nod position
    nint = int(header['NINT'])
    if nint <= 1:
        return coadd_data, variance

    npatt = readmode['npattern']
    nout = npatt // nint

    itot = header['BEAMTIME'] * nint * nout
    header['INTTIME'] = itot
    if 'OFF_SLIT' in str(header.get('INSTMODE', 'UNKNOWN')).upper():
        header['EXPTIME'] = itot / 2.
    else:
        header['EXPTIME'] = itot
    header['NEXP'] = nint * nout

    log.info(f"Combining {nint} frames per nod position")
    if npatt < nint:
        raise ValueError(f"Data does not match NINT={nint}")
    elif npatt % nint != 0:
        log.warning(f"Data does not match NINT={nint}; "
                    f"ignoring extra frames.")

    shape = nout, coadd_data.shape[1], coadd_data.shape[2]
    mcoadd = np.empty(shape, dtype=float)
    mvar = np.empty(shape, dtype=float)
    nodn = header.get('NODN', 1)
    for i in range(nout):
        if i == 0:
            if toss_nint > 0:
                if toss_nint < nint and (not copy_int or nodn < 2):
                    log.info(f'Dropping the first {toss_nint} frames')
                    start = toss_nint
                else:
                    if toss_nint <= nint and nodn >= 2:
                        # allow copying the sky data from the next nod
                        # if available
                        log.warning('Copying the first '
                                    'integration(s) from the next B nod')
                        cstart = 2 * nint
                        cstop = 2 * nint + nint
                        coadd_data[0:nint] = coadd_data[cstart:cstop]
                        variance[0:nint] = variance[cstart:cstop]
                    else:
                        # otherwise, just ignore the toss for this file
                        log.warning('TOSS_NINT is set higher than '
                                    'NINT; ignoring.')

                    # in either case, use all frames
                    start = 0
            else:
                start = 0
        else:
            start = i * nint
        stop = i * nint + nint
        ncomb = stop - start
        mcoadd[i] = bn.nansum(coadd_data[start:stop], axis=0) / ncomb
        mvar[i] = bn.nansum(variance[start:stop], axis=0) / (ncomb ** 2)

    return mcoadd, mvar


import numpy as np
import cv2
import glob
import os
import PIL as Image
import os.path as osp

from tqdm import tqdm
current_dir = os.getcwd()
print("path", current_dir)
# path= ''.join([current_dir, folder])
count = 1
if __name__ == "__main__":
    # path_an = sorted(glob.glob('/home/airlab/Desktop/New_training/01_Annotation/ANNOTATION/test/*.png'))
    # path_im = sorted(glob.glob('/home/airlab/Desktop/New_training/01_Annotation/IMG/test/*.jpg'))
    name = 'train'
    path_im = sorted(glob.glob('C:\\Users\\ptthi\\OneDrive\\Desktop\\Image_processing\\DATA_PROCESS\\BACKGROUND\\*.png'))
    print("path", path_im)
    # tao folder moi
    if not os.path.exists(current_dir + '/' + "{}_new".format(name)):
        os.makedirs(current_dir + '/' + '{}_new'.format(name))
    for i,im in enumerate(path_im):
        base_an = osp.splitext(osp.basename(im))[0]
        print("name of image:", i)
        if i % 2 == 0:
            print("True")
            file_im = cv2.imread(im)
            cv2.imwrite(current_dir + '/' + '{}_new'.format(name) + '/' + '{}.jpg'.format(count),file_im)
            count += 1
        print("count",count)


from fabric.api import *
env.hosts = ['servername']

def _annotate_hosts_with_ssh_config_info():
    from os.path import expanduser
    from paramiko.config import SSHConfig

    def hostinfo(host, config):
        hive = config.lookup(host)
        if 'hostname' in hive:
            host = hive['hostname']
        if 'user' in hive:
            host = '%s@%s' % (hive['user'], host)
        if 'port' in hive:
            host = '%s:%s' % (host, hive['port'])
        return host

    try:
        config_file = file(expanduser('~/.ssh/config'))
    except IOError:
        pass
    else:
        config = SSHConfig()
        config.parse(config_file)
        keys = [config.lookup(host).get('identityfile', None)
            for host in env.hosts]
        env.key_filename = [expanduser(key) for key in keys if key is not None]
        env.hosts = [hostinfo(host, config) for host in env.hosts]

        for role, rolehosts in env.roledefs.items():
            env.roledefs[role] = [hostinfo(host, config) for host in rolehosts]

_annotate_hosts_with_ssh_config_info()


from __future__ import annotations

from typing import TYPE_CHECKING

from ..messaging.lazy_payload import VariablePayloadWID, vp_compile
from ..messaging.serialization import Payload

if TYPE_CHECKING:
    from ..types import Address

def encode_connection_type(type: str) -> tuple[int, int]:  # noqa: A002
    """
    Convert a type string to a tuple.
    """
    if type == "public":
        return 1, 0
    if type == "symmetric-NAT":
        return 1, 1
    return 0, 0

def decode_connection_type(bit_0: int, bit_1: int) -> str:
    """
    Convert connection type flags to a type string.
    """
    bits = (bit_0, bit_1)
    if bits == (0, 0):
        return "unknown"
    if bits == (1, 0):
        return "public"
    if bits == (1, 1):
        return "symmetric-NAT"
    return "N/A"

class IntroductionRequestPayload(Payload):
    """
    Payload sent to peers that we are not connected to yet but have been punctured for us.
    """

    msg_id = 246
    format_list = ['ipv4', 'ipv4', 'ipv4', 'bits', 'H', 'raw']

    def __init__(self, destination_address: Address, source_lan_address: Address,  # noqa: PLR0913
                 source_wan_address: Address, advice: bool, connection_type: str, identifier: int, extra_bytes: bytes,
                 supports_new_style: bool = True) -> None:
        """
        Create the payload for an introduction-request message.

        DESTINATION_ADDRESS is the address of the receiver.  Effectively this should be the
        wan address that others can use to contact the receiver.

        SOURCE_LAN_ADDRESS is the lan address of the sender.  Nodes in the same LAN
        should use this address to communicate.

        SOURCE_WAN_ADDRESS is the wan address of the sender.  Nodes not in the same
        LAN should use this address to communicate.

        ADVICE is a boolean value.  When True the receiver will introduce the sender to a new
        node.  This introduction will be facilitated by the receiver sending a puncture-request
        to the new node.

        CONNECTION_TYPE is a unicode string indicating the connection type that the message
        creator has. Currently, the following values are supported: u"unknown", u"public", and
        u"symmetric-NAT".

        IDENTIFIER is a number that must be given in the associated introduction-response.  This
        number allows to distinguish between multiple introduction-response messages.

        EXTRA_BYTES is a string that can be used to piggyback extra information.
        """
        super().__init__()
        self.destination_address = destination_address
        self.source_lan_address = source_lan_address
        self.source_wan_address = source_wan_address
        self.advice = advice
        self.supports_new_style = supports_new_style
        self.connection_type = connection_type
        self.identifier = identifier % 65536
        self.extra_bytes = extra_bytes

    def to_pack_list(self) -> list[tuple]:
        """
        Convert this payload to a pack list.
        """
        encoded_connection_type = encode_connection_type(self.connection_type)
        return [('ipv4', self.destination_address),
                ('ipv4', self.source_lan_address),
                ('ipv4', self.source_wan_address),
                ('bits', encoded_connection_type[0], encoded_connection_type[1], self.supports_new_style, 0, 0, 0, 0,
                 self.advice),
                ('H', self.identifier),
                ('raw', self.extra_bytes)]

    @classmethod
    def from_unpack_list(cls: type[IntroductionRequestPayload], destination_address: Address,  # noqa: PLR0913
                         source_lan_address: Address, source_wan_address: Address, connection_type_0: bool,
                         connection_type_1: bool, supports_new_style: bool,
                         dflag1: bool, dflag2: bool, tunnel: bool, sync: bool,  # noqa: ARG003
                         advice: bool, identifier: int, extra_bytes: bytes) -> IntroductionRequestPayload:
        """
        Unpack a payload from the given data.
        """
        return IntroductionRequestPayload(destination_address,
                                          source_lan_address,
                                          source_wan_address,
                                          [True, False][advice],
                                          decode_connection_type(connection_type_0, connection_type_1),
                                          identifier,
                                          extra_bytes,
                                          supports_new_style)

@vp_compile
class NewIntroductionRequestPayload(VariablePayloadWID):
    """
    New introduction request that supports non-IPv4 addresses.
    """

    msg_id = 234
    format_list = ['ip_address', 'ip_address', 'ip_address', 'H', 'bits', 'raw']
    names = ["destination_address", "source_lan_address", "source_wan_address", "identifier", "connection_type_0",
             "connection_type_1", "supports_new_style", "dflag1", "dflag2", "tunnel", "sync", "advice", "extra_bytes"]

    destination_address: Address
    source_lan_address: Address
    source_wan_address: Address
    identifier: int
    connection_type_0: int
    connection_type_1: int
    supports_new_style: int
    dflag1: int
    dflag2: int
    tunnel: int
    sync: int
    advice: int
    extra_bytes: bytes

class IntroductionResponsePayload(Payload):
    """
    Response to introduction requests.
    """

    msg_id = 245
    format_list = ['ipv4', 'ipv4', 'ipv4', 'ipv4', 'ipv4', 'bits', 'H', 'raw']

    def __init__(self, destination_address: Address, source_lan_address: Address,  # noqa: PLR0913
                 source_wan_address: Address, lan_introduction_address: Address,
                 wan_introduction_address: Address, connection_type: str, identifier: int, extra_bytes: bytes,
                 supports_new_style: bool = True, intro_supports_new_style: bool = False,
                 peer_limit_reached: bool = False) -> None:
        """
        Create the payload for an introduction-response message.

        DESTINATION_ADDRESS is the address of the receiver.  Effectively this should be the
        wan address that others can use to contact the receiver.

        SOURCE_LAN_ADDRESS is the lan address of the sender.  Nodes in the same LAN
        should use this address to communicate.

        SOURCE_WAN_ADDRESS is the wan address of the sender.  Nodes not in the same
        LAN should use this address to communicate.

        LAN_INTRODUCTION_ADDRESS is the lan address of the node that the sender
        advises the receiver to contact.  This address is zero when the associated request did
        not want advice.

        WAN_INTRODUCTION_ADDRESS is the wan address of the node that the sender
        advises the receiver to contact.  This address is zero when the associated request did
        not want advice.

        CONNECTION_TYPE is a unicode string indicating the connection type that the message
        creator has. Currently, the following values are supported: u"unknown", u"public", and
        u"symmetric-NAT".

        IDENTIFIER is a number that was given in the associated introduction-request.  This
        number allows to distinguish between multiple introduction-response messages.

        EXTRA_BYTES is a string that can be used to piggyback extra information.

        When the associated request wanted advice the sender will also sent a puncture-request
        message to either the lan_introduction_address or the wan_introduction_address
        (depending on their positions).  The introduced node must sent a puncture message to the
        receiver to punch a hole in its NAT.
        """
        super().__init__()
        self.destination_address = destination_address
        self.source_lan_address = source_lan_address
        self.source_wan_address = source_wan_address
        self.lan_introduction_address = lan_introduction_address
        self.wan_introduction_address = wan_introduction_address
        self.connection_type = connection_type
        self.supports_new_style = supports_new_style
        self.intro_supports_new_style = intro_supports_new_style
        self.peer_limit_reached = peer_limit_reached
        self.identifier = identifier % 65536
        self.extra_bytes = extra_bytes

    def to_pack_list(self) -> list[tuple]:
        """
        Convert this payload to a pack list.
        """
        encoded_connection_type = encode_connection_type(self.connection_type)
        return [('ipv4', self.destination_address),
                ('ipv4', self.source_lan_address),
                ('ipv4', self.source_wan_address),
                ('ipv4', self.lan_introduction_address),
                ('ipv4', self.wan_introduction_address),
                ('bits', encoded_connection_type[0], encoded_connection_type[1], 0, self.supports_new_style,
                 self.intro_supports_new_style, self.peer_limit_reached, 0, 0),
                ('H', self.identifier),
                ('raw', self.extra_bytes)]

    @classmethod
    def from_unpack_list(cls: type[IntroductionResponsePayload], destination_address: Address,  # noqa: PLR0913
                         source_lan_address: Address, source_wan_address: Address, introduction_lan_address: Address,
                         introduction_wan_address: Address, connection_type_0: bool, connection_type_1: bool,
                         dflag0: bool, supports_new_style: bool, intro_supports_new_style: bool,  # noqa: ARG003
                         peer_limit_reached: bool, dflag4: bool, dflag5: bool, identifier: int,  # noqa: ARG003
                         extra_bytes: bytes) -> IntroductionResponsePayload:
        """
        Convert the raw data to a payload.
        """
        return IntroductionResponsePayload(destination_address,
                                           source_lan_address,
                                           source_wan_address,
                                           introduction_lan_address,
                                           introduction_wan_address,
                                           decode_connection_type(connection_type_0, connection_type_1),
                                           identifier,
                                           extra_bytes,
                                           supports_new_style,
                                           intro_supports_new_style,
                                           peer_limit_reached)

@vp_compile
class NewIntroductionResponsePayload(VariablePayloadWID):
    """
    New introduction response that supports non-IPv4 addresses.
    """

    msg_id = 233
    format_list = ['ip_address', 'ip_address', 'ip_address', 'ip_address', 'ip_address', 'H', 'bits', 'raw']
    names = ["destination_address", "source_lan_address", "source_wan_address", "lan_introduction_address",
             "wan_introduction_address", "identifier", "intro_supports_new_style", "flag1", "flag2", "flag3",
             "flag4", "flag5", "flag6", "flag7", "extra_bytes"]

    destination_address: Address
    source_lan_address: Address
    source_wan_address: Address
    lan_introduction_address: Address
    wan_introduction_address: Address
    identifier: int
    intro_supports_new_style: bool
    flag1: int
    flag2: int
    flag3: int
    flag4: int
    flag5: int
    flag6: int
    flag7: int
    extra_bytes: bytes

class PunctureRequestPayload(Payload):
    """
    Payload to ask someone to puncture a third party for us.
    """

    msg_id = 250
    format_list = ['ipv4', 'ipv4', 'H']

    def __init__(self, lan_walker_address: Address, wan_walker_address: Address, identifier: int) -> None:
        """
        Create the payload for a puncture-request payload.

        LAN_WALKER_ADDRESS is the lan address of the node that the sender wants us to
        contact.  This contact attempt should punch a hole in our NAT to allow the node to
        connect to us.

        WAN_WALKER_ADDRESS is the wan address of the node that the sender wants us to
        contact.  This contact attempt should punch a hole in our NAT to allow the node to
        connect to us.

        IDENTIFIER is a number that was given in the associated introduction-request.  This
        number allows to distinguish between multiple introduction-response messages.
        """
        super().__init__()
        self.lan_walker_address = lan_walker_address
        self.wan_walker_address = wan_walker_address
        self.identifier = identifier % 65536

    def to_pack_list(self) -> list[tuple]:
        """
        Convert this payload to a pack list.
        """
        return [('ipv4', self.lan_walker_address),
                ('ipv4', self.wan_walker_address),
                ('H', self.identifier)]

    @classmethod
    def from_unpack_list(cls: type[PunctureRequestPayload], lan_walker_address: Address, wan_walker_address: Address,
                         identifier: int) -> PunctureRequestPayload:
        """
        Create a payload from the given data.
        """
        return PunctureRequestPayload(lan_walker_address, wan_walker_address, identifier)

@vp_compile
class NewPunctureRequestPayload(VariablePayloadWID):
    """
    New puncture request that supports non-IPv4 addresses.
    """

    msg_id = 232
    format_list = ['ip_address', 'ip_address', 'H']
    names = ["lan_walker_address", "wan_walker_address", "identifier"]

    lan_walker_address: Address
    wan_walker_address: Address
    identifier: int

class PuncturePayload(Payload):
    """
    Attempt to puncture a NAT layer.
    """

    msg_id = 249
    format_list = ['ipv4', 'ipv4', 'H']

    def __init__(self, source_lan_address: Address, source_wan_address: Address, identifier :int) -> None:
        """
        Create the payload for a puncture message.

        SOURCE_LAN_ADDRESS is the lan address of the sender.  Nodes in the same LAN
        should use this address to communicate.

        SOURCE_WAN_ADDRESS is the wan address of the sender.  Nodes not in the same
        LAN should use this address to communicate.

        IDENTIFIER is a number that was given in the associated introduction-request.  This
        number allows to distinguish between multiple introduction-response messages.
        """
        super().__init__()
        self.source_lan_address = source_lan_address
        self.source_wan_address = source_wan_address
        self.identifier = identifier % 65536

    def to_pack_list(self) -> list[tuple]:
        """
        Convert this payload to a pack list.
        """
        return [('ipv4', self.source_lan_address),
                ('ipv4', self.source_wan_address),
                ('H', self.identifier)]

    @classmethod
    def from_unpack_list(cls: type[PuncturePayload], lan_walker_address: Address, wan_walker_address: Address,
                         identifier: int) -> PuncturePayload:
        """
        Conver the given data to a payload.
        """
        return PuncturePayload(lan_walker_address, wan_walker_address, identifier)

@vp_compile
class NewPuncturePayload(VariablePayloadWID):
    """
    New puncture payload that supports non-IPv4 addresses.
    """

    msg_id = 231
    format_list = ['ip_address', 'ip_address', 'H']
    names = ["source_lan_address", "source_wan_address", "identifier"]

    source_lan_address: Address
    source_wan_address: Address
    identifier: int


import torch
import torch.nn as nn
from nets.vgg16 import decom_vgg16
from nets.resnet50 import resnet50
from nets.rpn import RegionProposalNetwork
from nets.classifier import VGG16RoIHead,Resnet50RoIHead
import time
import numpy as np
class FasterRCNN(nn.Module):
    def __init__(self, num_classes,
                mode = "training",
                loc_normalize_mean = (0., 0., 0., 0.),
                loc_normalize_std = (0.1, 0.1, 0.2, 0.2),
                feat_stride = 16,
                anchor_scales = [8, 16, 32],
                ratios = [0.5, 1, 2],
                backbone = 'vgg'
    ):
        super(FasterRCNN, self).__init__()

        self.loc_normalize_mean = loc_normalize_mean
        self.loc_normalize_std = loc_normalize_std
        self.feat_stride = feat_stride
        if backbone == 'vgg':
            self.extractor, classifier = decom_vgg16()
            self.rpn = RegionProposalNetwork(
                512, 512,
                ratios=ratios,
                anchor_scales=anchor_scales,
                feat_stride=self.feat_stride,
                mode = mode
            )
            self.head = VGG16RoIHead(
                n_class=num_classes + 1,
                roi_size=7,
                spatial_scale=(1. / self.feat_stride),
                classifier=classifier
            )
        elif backbone == 'resnet50':
            self.extractor, classifier = resnet50()

            self.rpn = RegionProposalNetwork(
                1024, 512,
                ratios=ratios,
                anchor_scales=anchor_scales,
                feat_stride=self.feat_stride,
                mode = mode
            )
            self.head = Resnet50RoIHead(
                n_class=num_classes + 1,
                roi_size=14,
                spatial_scale=(1. / self.feat_stride),
                classifier=classifier
            )
    def forward(self, x, scale=1.):
        img_size = x.shape[2:]
        h = self.extractor(x)

        rpn_locs, rpn_scores, rois, roi_indices, anchor = \
            self.rpn.forward(h, img_size, scale)

        # print(np.shape(h))
        # print(np.shape(rois))
        # print(roi_indices)
        roi_cls_locs, roi_scores = self.head.forward(h, rois, roi_indices)
        return roi_cls_locs, roi_scores, rois, roi_indices

    def freeze_bn(self):
        for m in self.modules():
            if isinstance(m, nn.BatchNorm2d):
                m.eval()


import json
import logging
import re
import textwrap
import dateutil.parser
from dojo.models import Finding

logger = logging.getLogger(__name__)

CWE_REGEX = r'cwe-\d+$'

class SarifParser(object):
    """OASIS Static Analysis Results Interchange Format (SARIF) for version 2.1.0 only.

    https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=sarif
    """

    def get_scan_types(self):
        return ["SARIF"]

    def get_label_for_scan_types(self, scan_type):
        return scan_type  # no custom label for now

    def get_description_for_scan_types(self, scan_type):
        return "SARIF report file can be imported in SARIF format."

    def get_findings(self, filehandle, test):
        tree = json.load(filehandle)
        return self.get_items(tree, test)

    def get_items(self, tree, test):
        items = list()
        # for each runs
        for run in tree.get('runs', list()):
            # load rules
            rules = get_rules(run)
            artifacts = get_artifacts(run)
            # get the timestamp of the run if possible
            run_date = self._get_last_invocation_date(run)
            for result in run.get('results', list()):
                item = get_item(result, rules, artifacts, run_date)
                items.append(item)
        return items

    def _get_last_invocation_date(self, data):
        invocations = data.get('invocations', [])
        if len(invocations) == 0:
            return None
        # try to get the last 'endTimeUtc'
        raw_date = invocations[-1].get('endTimeUtc')
        if raw_date is None:
            return None
        # if the data is here we try to convert it to datetime
        return dateutil.parser.isoparse(raw_date)

def get_rules(run):
    rules = {}
    for item in run['tool']['driver'].get('rules', []):
        rules[item['id']] = item
    return rules

def get_rule_tags(rule):
    if 'properties' not in rule:
        return []
    if 'tags' not in rule['properties']:
        return []
    else:
        return rule['properties']['tags']

def get_rule_cwes(rule):
    cwes = []
    for tag in get_rule_tags(rule):
        matches = re.search(CWE_REGEX, tag, re.IGNORECASE)
        if matches:
            cwes.append(int(matches[0].split("-")[1]))
    return cwes

def get_artifacts(run):
    artifacts = {}
    custom_index = 0  # hack because some tool doesn't generate this attribute
    for tree_artifact in run.get('artifacts', []):
        artifacts[tree_artifact.get('index', custom_index)] = tree_artifact
        custom_index += 1
    return artifacts

def get_severity(data):
    """Convert level value to severity
    """
    if 'warning' == data:
        return 'Medium'
    elif 'error' == data:
        return 'Critical'
    else:
        return 'Info'

def get_message_from_multiformatMessageString(data, rule):
    """Get a message from multimessage struct

    See here for the specification: https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317468
    """
    if rule is not None and 'id' in data:
        text = rule['messageStrings'][data['id']].get('text')
        arguments = data.get('arguments', [])
        # argument substitution
        for i in range(6):  # the specification limit to 6
            substitution_str = "{" + str(i) + "}"
            if substitution_str in text:
                text = text.replace(substitution_str, arguments[i])
            else:
                return text
    else:
        # TODO manage markdown
        return data.get('text')

def cve_try(val):
    # Match only the first CVE!
    cveSearch = re.search("(CVE-[0-9]+-[0-9]+)", val, re.IGNORECASE)
    if cveSearch:
        return cveSearch.group(1).upper()
    else:
        return None

def get_item(result, rules, artifacts, run_date):
    mitigation = result.get('Remediation', {}).get('Recommendation', {}).get('Text', "")
    references = result.get('Remediation', {}).get('Recommendation', {}).get('Url')

    # if there is a location get it
    file_path = None
    line = -1
    if "locations" in result:
        location = result['locations'][0]
        if 'physicalLocation' in location:
            file_path = location['physicalLocation']['artifactLocation']['uri']
            # 'region' attribute is optionnal
            if 'region' in location['physicalLocation']:
                line = location['physicalLocation']['region']['startLine']

    # test rule link
    rule = rules.get(result['ruleId'])
    title = result['ruleId']
    if 'message' in result:
        description = get_message_from_multiformatMessageString(result['message'], rule)
        if len(description) < 150:
            title = description
    description = ''
    severity = get_severity('warning')
    if rule is not None:
        # get the severity from the rule
        if 'defaultConfiguration' in rule:
            severity = get_severity(rule['defaultConfiguration'].get('level', 'warning'))

        if 'shortDescription' in rule:
            description = get_message_from_multiformatMessageString(rule['shortDescription'], rule)
        elif 'fullDescription' in rule:
            description = get_message_from_multiformatMessageString(rule['fullDescription'], rule)
        elif 'name' in rule:
            description = rule['name']
        else:
            description = rule['id']

    # we add a special 'None' case if there is no CWE
    cwes = [0]
    if rule is not None:
        cwes_extracted = get_rule_cwes(rule)
        if len(cwes_extracted) > 0:
            cwes = cwes_extracted

    finding = Finding(title=textwrap.shorten(title, 150),
                    severity=severity,
                    description=description,
                    mitigation=mitigation,
                    references=references,
                    cve=cve_try(result['ruleId']),  # for now we only support when the id of the rule is a CVE
                    cwe=cwes[0],
                    static_finding=True,  # by definition
                    dynamic_finding=False,  # by definition
                    file_path=file_path,
                    line=line)

    if run_date:
        finding.date = run_date

    return finding


import sys

sys.setrecursionlimit(10**6)

N = int(sys.stdin.readline())
PAINT = [[*sys.stdin.readline().rstrip()] for n in range(N)]

def apply_color_blindness():
    for y in range(N):
        for x in range(N):
            if PAINT[y][x] == 'G':
                PAINT[y][x] = 'R'

def dfs(y, x, visited):
    if visited.get((y, x), False):
        return
    visited[y, x] = True
    if (0 < x) and (PAINT[y][x-1] == PAINT[y][x]):
        dfs(y, x-1, visited)
    if (x+1 < N) and (PAINT[y][x+1] == PAINT[y][x]):
        dfs(y, x+1, visited)
    if (0 < y) and (PAINT[y-1][x] == PAINT[y][x]):
        dfs(y-1, x, visited)
    if (y+1 < N) and (PAINT[y+1][x] == PAINT[y][x]):
        dfs(y+1, x, visited)

def count_areas():
    visited = dict()
    area = 0
    for y in range(N):
        for x in range(N):
            if not visited.get((y, x), False):
                dfs(y, x, visited)
                area += 1
    return area

areas = count_areas()
apply_color_blindness()
areas_cblind = count_areas()
print(areas, areas_cblind)

Baekjoon Online Judge/problem/10026/27795021 맞았습니다!! 31728 KB 108 ms.py


import io
from google.oauth2 import service_account
from google.cloud import vision
from CREDENTIALS import VISION_KEY_PATH

credentials = service_account.Credentials.from_service_account_file(
    VISION_KEY_PATH)

client = vision.ImageAnnotatorClient(credentials=credentials)

def read_image(filepath):
    with io.open(filepath, 'rb') as image_file:
        content = image_file.read()
    image = vision.types.Image(content=content)
    response = client.document_text_detection(image=image)
    document = response.full_text_annotation.text

    if document == '':
        return "Oops, I didn't seem to find anything. Please try again."
    else:
        return document


# Example game using text rendering

WIDTH = sx = 854
HEIGHT = sy = 480
TITLE = "Clooky Clunker"

score, totalscore, clunkers = 0, 0, 0
nextgoal = 0
tgoal = -100
clunks = []
tbuy, buytext = -100, ""
t = 0

buttonrects = [Rect((50, 120 + 85 * j, 180, 70)) for j in range(4)]
buttonnames = ["auto-clunker", "clunkutron",
               "turbo enclunkulator", "clunx capacitor"]
buttoncosts = [10, 400, 12000, 250000]

def on_key_down(key):
    if key == keys.ESCAPE:
        exit()

def on_mouse_down(button, pos):
    global score, totalscore, clunkers, tbuy, buytext
    if button != 1:
        return

    x, y = pos
    # Click on the central circle
    if (x - sx / 2) ** 2 + (y - sy / 2) ** 2 < 100 ** 2:
        score += 1
        totalscore += 1
        # Add a "clunk" indicator at a pseudorandom place near the center
        ix = sx / 2 + 12345678910. / (1 + t) % 1 * 200 - 100
        iy = sy / 2 + 45678910123. / (1 + t) % 1 * 200 - 100
        clunks.append((t, ix, iy))

    # Click on one of the buttons
    for j in range(len(buttonrects)):
        rect, cost = buttonrects[j], buttoncosts[j]
        if rect.collidepoint(x, y) and score >= cost:
            score -= cost
            clunkers += 10 ** j
            tbuy = t
            buytext = "+%s clunk/s" % (10 ** j)
            buttoncosts[j] += int(round(cost * 0.2))

def update(dt):
    global t
    global score, totalscore, goaltext, tgoal, nextgoal
    t += dt
    score += clunkers * dt
    totalscore += clunkers * dt

    # Check for next achievement
    if totalscore > 100 * (1 << nextgoal):
        goaltext = "Achievement unlocked:\nCL%sKY!" % ("O" * (nextgoal + 2))
        tgoal = t
        nextgoal += 1

    clunks[:] = [c for c in clunks if t - c[0] < 1]

def draw():
    screen.fill((0, 30, 30))

    # Draw the circle in the middle
    screen.draw.filled_circle((sx // 2, sy // 2), 106, 'black')
    screen.draw.filled_circle((sx // 2, sy // 2), 100, '#884400')

    # Draw the buttons using screen.draw.textbox
    for rect, name, cost in zip(buttonrects, buttonnames, buttoncosts):
        screen.draw.filled_rect(rect, "#553300")
        screen.draw.filled_rect(rect.inflate(-8, -8), "#332200")
        text = u"%s: %d\u00A0clunks" % (name, cost)
        color = "white" if cost <= score else "#666666"
        box = rect.inflate(-16, -16)
        screen.draw.textbox(
            text, box,
            fontname="bubblegum_sans",
            lineheight=0.9,
            color=color,
            owidth=0.5
        )

    # Draw the HUD
    hudtext = "\n".join([
        "time played: %d" % t,
        "clunks: %d" % score,
        "all-time clunks: %d" % totalscore,
        "clunks per second: %d" % clunkers,
    ])
    screen.draw.text(
        hudtext,
        right=sx - 10,
        top=120,
        fontname="roboto_condensed",
        fontsize=32,
        color=(0, 200, 0),
        scolor=(0, 50, 0),
        shadow=(-1, 1),
        lineheight=1.3
    )

    # Draw the title using a gradient
    screen.draw.text(
        "Clooky Clunker",
        midtop=(sx / 2, 10),
        fontname="cherrycreamsoda",
        fontsize=64,
        owidth=1.2,
        color="#884400",
        gcolor="#442200"
    )

    # Draw "clunk" indicators
    for it, ix, iy in clunks:
        dt = t - it
        pos = ix, iy - 60 * dt
        screen.draw.text(
            "clunk",
            center=pos,
            fontname=None,
            fontsize=28,
            alpha=1 - dt,
            shadow=(1, 1)
        )

    # Draw purchase indicator
    if t - tbuy < 1:
        dt = t - tbuy
        pos = sx / 2, sy / 2
        fontsize = 32 * (1 + 60 * dt) ** 0.2
        screen.draw.text(
            buytext, pos,
            anchor=(0.5, 0.9),
            fontname="bubblegum_sans",
            fontsize=fontsize,
            alpha=1 - dt,
            shadow=(1, 1)
        )

    # Draw achievement unlocked text (text is centered even though we specify
    # bottom right).
    if t - tgoal < 2:
        alpha = min(2 - (t - tgoal), 1)
        screen.draw.text(
            goaltext,
            fontname="boogaloo",
            fontsize=48,
            bottom=sy - 20,
            right=sx - 40,
            color="#AAAAFF",
            gcolor="#4444AA",
            shadow=(1.5, 1.5),
            alpha=alpha,
            align="center"
        )


import logging
import subprocess
from pathlib import Path

log = logging.getLogger(__name__)

class PlexScanner:
    """
    determines if plex should scan its libraries after a new download is completed
    and issues plex scan command
    """

    def __init__(self, config, qbitclient):
        self.config = config
        self.qbitclient = qbitclient

    def get_completed_downloads(self):
        """get the completed downloads unyet processed"""
        completed_list = self.qbitclient.torrents_info(status_filter="completed")
        return [
            i
            for i in completed_list
            if "Processed" not in i.tags and self.get_genre(i.save_path)
        ]

    def get_genre(self, save_path):
        """gets genre of torrent
        Args:
            save_path: torrent save_path
        Returns:
            genre from config or False
        """
        genre_path = Path(save_path).parent
        for key, val in self.config["genres"].items():
            if Path(val["moveToDir"]) == genre_path:
                return key
        return False

    def plex_scan(self):
        """runs plex scan command as subprocess"""
        s_out = (
            subprocess.check_output(self.config["plexScanCommand"])
            .strip()
            .decode("UTF-8")
        )
        if "Got nothing for: It's All Connected" in s_out:
            log.debug(f"Plex scan success, stdout: '{s_out}'")
        else:
            log.debug(f"Plex scan failed, stdout: '{s_out}'")

    def scan_if_needed(self):
        """determines if scanning plex is required and runs command if needed"""
        completed_downloads = self.qbitclient.torrents_info(status_filter="completed")
        requires_scan = [
            i.hash
            for i in completed_downloads
            if self.get_genre(i.save_path)
            and self.config["genres"][self.get_genre(i.save_path)]["scanPlex"]
            and "Scanned" not in i.tags
        ]
        if requires_scan:
            log.debug("Running plex scan")
            self.plex_scan()
            self.qbitclient.torrents_add_tags(
                tags="Scanned", torrent_hashes=requires_scan
            )
        else:
            log.debug("No plex scan needed")


class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack = []
        j = 0
        for val in pushed:
            stack.append(val)
            while stack and stack[-1] == popped[j]:
                stack.pop()
                j += 1
        return not stack


file_name = r'C:\Users\jasonborn\Desktop\文件夹\3D_Work\Untitled.bmp'

# 读取模式， mode
# t 读取文本文件（默认值）  以读为例：默认值 rt
# b 读取二进制文件
with open(file_name, 'rb') as file_obj:
    # 读取文本文件时，size以字符为单位
    # 读取二进制文件时，size以字节为单位
    # print(file_obj.read(100))
    # 将读取的内容写回
    new_name = 'aa.bmp'
    with open(new_name, 'wb') as new_obj:
        while True:
            chunk = 1024 * 100
            content = file_obj.read(chunk)
            if not content:
                break
            new_obj.write(content)


from setuptools import find_packages, setup
from typing import List

HYPEN_E_DOT = '-e .'

def get_requirements(path:str)->List[str]:
    requirements = []
    with open(path, 'r') as f:
        requirements = f.readlines()
        requirements = [req.replace('\t','') for req in requirements]
        if HYPEN_E_DOT in requirements:
            requirements.remove(HYPEN_E_DOT)
    return requirements

setup(
    name='housing_price',
    version='0.0.1',
    author='hau`',
    author_email='tranquochao0102@gmail.com',
    packages= find_packages(),
    install_requires=get_requirements('requirements.txt'),

)


# -*- coding: utf-8 -*-
"""some internal library functions"""

import datetime
import urllib
import unicodedata as ud
import logging

from functools import cmp_to_key
from bs4 import BeautifulSoup

# pylint: disable=E0402
from .consts import URL, alphabet_1, alphabet_2
from .db import dbconnect

def tpl_headers_symbols(link: str):
    """replace link name for html interface"""
    h2s = {
        "start": "HOME",  # was "⌂", # "⌂"
        "self": "RELOAD",  # was "↻",  # "↻", was "🗘"
        "up": "UP",  # was "⇑",  # "⇒"
        "next": "NEXT",  # "⇒",  # "⇑"
        "prev": "PREV"  # "⇐"  # "⇐"
    }
    if link in h2s:
        return h2s[link]
    return link

def cmp_in_arr(arr, char1, char2):
    """compare characters by array"""
    if char1 in arr and char2 in arr:
        idx1 = arr.index(char1)
        idx2 = arr.index(char2)
        if idx1 == idx2:  # pylint: disable=R1705
            return 0
        elif idx1 < idx2:
            return -1
        else:
            return 1
    else:
        return None

def custom_alphabet_sort(slist):
    """custom sort by arrays of characters"""
    ret = []
    ret = sorted(slist, key=cmp_to_key(custom_alphabet_cmp))
    return ret

def unicode_upper(stri: str):
    """custom UPPER + normalize for sqlite and other"""
    ret = ud.normalize('NFKD', stri)
    ret = ret.upper()
    ret = ret.replace('Ё', 'Е')
    ret = ret.replace('Й', 'И')
    ret = ret.replace('Ъ', 'Ь')
    return ret

def custom_char_cmp(char1: str, char2: str):  # pylint: disable=R0911
    """custom compare chars"""
    if char1 == char2:
        return 0

    if char1 in alphabet_1 and char2 not in alphabet_1:
        return -1
    if char1 in alphabet_2 and char2 not in alphabet_2 and char2 not in alphabet_1:
        return -1
    if char2 in alphabet_1 and char1 not in alphabet_1:
        return 1
    if char2 in alphabet_2 and char1 not in alphabet_2 and char1 not in alphabet_1:
        return 1

    # sort by array order
    if char1 in alphabet_1 and char2 in alphabet_1:
        return cmp_in_arr(alphabet_1, char1, char2)
    if char1 in alphabet_2 and char1 in alphabet_2:
        return cmp_in_arr(alphabet_2, char1, char2)

    if char1 < char2:  # pylint: disable=R1705
        return -1
    else:
        return +1

def custom_alphabet_cmp(str1: str, str2: str):  # pylint: disable=R0911
    """custom compare strings"""
    # pylint: disable=R1705
    s1len = len(str1)
    s2len = len(str2)
    i = 0

    # zero-length strings case
    if s1len == i:
        if i == s2len:
            return 0
        else:
            return -1
    elif i == s2len:
        return 1

    while custom_char_cmp(str1[i], str2[i]) == 0:
        i = i + 1
        if i == s1len:
            if i == s2len:
                return 0
            else:
                return -1
        elif i == s2len:
            return 1
    return custom_char_cmp(str1[i], str2[i])

def custom_alphabet_name_cmp(str1, str2):  # pylint: disable=R0911
    """custom compare name fields"""
    s1len = len(str1["name"])
    s2len = len(str2["name"])
    i = 0
    # zero-length strings case
    if s1len == i:
        if i == s2len:  # pylint: disable=R1705
            return 0
        else:
            return -1
    elif i == s2len:
        return 1
    while custom_char_cmp(str1["name"][i], str2["name"][i]) == 0:
        i = i + 1
        if i == s1len:
            if i == s2len:  # pylint: disable=R1705
                return 0
            else:
                return -1
        elif i == s2len:
            return 1
    return custom_char_cmp(str1["name"][i], str2["name"][i])

def custom_alphabet_book_title_cmp(str1, str2):  # pylint: disable=R0911
    """custom compare book_title fields"""
    s1len = len(str1["book_title"])
    s2len = len(str2["book_title"])
    i = 0
    # zero-length strings case
    if s1len == i:
        if i == s2len:  # pylint: disable=R1705
            return 0
        else:
            return -1
    elif i == s2len:
        return 1

    while custom_char_cmp(str1["book_title"][i], str2["book_title"][i]) == 0:
        i = i + 1
        if i == s1len:
            if i == s2len:  # pylint: disable=R1705
                return 0
            else:
                return -1
        elif i == s2len:
            return 1
    return custom_char_cmp(str1["book_title"][i], str2["book_title"][i])

def get_dtiso():
    """return current time in iso"""
    return datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()

def id2path(any_id: str):
    """create path from id"""
    first = any_id[:2]
    second = any_id[2:4]
    return first + "/" + second + "/" + any_id

# pylint: disable=R0913
def get_book_entry(
    date_time: str,
    book_id: str,
    book_title: str,
    authors,
    links,
    category,
    lang: str,
    annotext: str
):
    """create book entry for opds"""
    ret = {
        "updated": date_time,
        "id": "tag:book:" + book_id,
        "title": book_title,
        "author": authors,
        "link": links,
        "category": category,
        "dc:language": lang,
        "dc:format": "fb2",
        "content": {
            "@type": "text/html",
            "#text": html_refine(annotext)
        }
    }
    return ret

# 123456 -> 123k, 1234567 -> 1.23M
def sizeof_fmt(num: int, suffix="B"):
    """format size to human-readable format"""
    for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
        if abs(num) < 1024.0:
            return f"{num:3.1f}{unit}{suffix}"
        num /= 1024.0
    return f"{num:.1f}Yi{suffix}"

def get_seq_link(approot: str, seqref: str, seq_id: str, seq_name: str):
    """create sequence link for opds"""
    ret = {
        "@href": approot + seqref + seq_id,
        "@rel": "related",
        "@title": "Серия '" + seq_name + "'",
        "@type": "application/atom+xml"
    }
    return ret

# ctype == 'dl' for download
def get_book_link(approot: str, zipfile: str, filename: str, ctype: str):
    """create download/read link for opds"""
    title = "Читать онлайн"
    book_ctype = "text/html"
    rel = "alternate"
    if zipfile.endswith('zip'):
        zipfile = zipfile[:-4]
    href = approot + URL["read"] + zipfile + "/" + url_str(filename)
    if ctype == 'dl':
        title = "Скачать"
        book_ctype = "application/fb2+zip"
        rel = "http://opds-spec.org/acquisition/open-access"
        href = approot + URL["dl"] + zipfile + "/" + url_str(filename) + ".zip"
    ret = {
        "@href": href,
        "@rel": rel,
        "@title": title,
        "@type": book_ctype
    }
    return ret

def url_str(string: str):
    """urlencode string (quote + replace some characters to %NN)"""
    transl = {
        '"': '%22',
        "'": '%27',
        # '.': '%2E',
        # '/': '%2F'
    }
    ret = ''
    if string is not None:
        for char in string:
            if char in transl:  # pylint: disable=R1715
                # pylint take here wrong warning
                char = transl[char]
            ret = ret + char
    return urllib.parse.quote(ret, encoding='utf-8')

def html_refine(txt: str):
    """refine html by beautiful soap"""
    html = BeautifulSoup(txt, 'html.parser')
    ret = html.prettify()
    return ret

def pubinfo_anno(pubinfo):
    """create publication info for opds"""
    ret = ""
    if pubinfo["isbn"] is not None and pubinfo["isbn"] != 'None':
        ret = ret + "
Данные публикации:

ISBN: %s
" % pubinfo["isbn"]
    if pubinfo["year"] is not None and pubinfo["year"] != 'None':
        ret = ret + "
Год публикации: %s
" % pubinfo["year"]
    if pubinfo["publisher"] is not None and pubinfo["year"] != 'None':
        ret = ret + "
Издательство: %s
" % pubinfo["publisher"]
    return ret

def get_author_name(auth_id: str):
    """author name by id"""
    ret = ""
    try:
        db_conn = dbconnect()
        dbauthdata = db_conn.get_author(auth_id)
        ret = dbauthdata[0][1]
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret

def get_meta_name(meta_id):
    """author name by id"""
    ret = meta_id
    db_conn = dbconnect()
    dbdata = db_conn.get_meta_name(meta_id)
    if dbdata is not None and dbdata[0] is not None and dbdata[0] != '':
        ret = dbdata[0]
    return ret

def get_genre_name(gen_id: str):
    """genre name by id"""
    ret = gen_id
    db_conn = dbconnect()
    dbdata = db_conn.get_genre_name(gen_id)
    if dbdata is not None and dbdata[0] is not None and dbdata[0] != '':
        ret = dbdata[0]
    return ret

def get_seq_name(seq_id: str):
    """sequence name by id"""
    db_conn = dbconnect()
    return db_conn.get_seq_name(seq_id)

def get_book_authors(book_id: str):
    """one book authors"""
    ret = []
    try:
        db_conn = dbconnect()
        dbdata = db_conn.get_book_authors(book_id)
        for auth in dbdata:
            ret.append({
                "id": auth[0],
                "name": auth[1]
            })
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret

def get_books_authors(book_ids):
    """books authors"""
    ret = {}
    try:
        db_conn = dbconnect()
        dbdata = db_conn.get_books_authors(book_ids)
        for auth in dbdata:
            book_id = auth[0]
            if book_id not in ret:
                ret[book_id] = []
            ret[book_id].append({
                "id": auth[1],
                "name": auth[2]
            })
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret

def get_book_seqs(book_id: str):
    """one book sequences"""
    ret = []
    try:
        db_conn = dbconnect()
        dbdata = db_conn.get_book_seqs(book_id)
        for seq in dbdata:
            ret.append({
                "id": seq[0],
                "name": seq[1],
                "num": seq[2]
            })
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret

def get_books_seqs(book_ids):
    """books sequences"""
    ret = {}
    try:
        db_conn = dbconnect()
        dbdata = db_conn.get_books_seqs(book_ids)
        for seq in dbdata:
            book_id = seq[0]
            if book_id not in ret:
                ret[book_id] = []
            ret[book_id].append({
                "id": seq[1],
                "name": seq[2],
                "num": seq[3]
            })
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret

def get_book_descr(book_id: str):
    """one book title/publication/annotation"""
    book_title = ""
    pub_isbn = None
    pub_year = None
    publisher = None
    publisher_id = None
    annotation = ""
    try:
        db_conn = dbconnect()
        binfo = db_conn.get_book_descr(book_id)
        book_title = binfo[0]
        pub_isbn = binfo[1]
        pub_year = binfo[2]
        publisher = binfo[3]
        publisher_id = binfo[4]
        annotation = binfo[5]
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return book_title, pub_isbn, pub_year, publisher, publisher_id, annotation

def get_books_descr(book_ids):
    """many books title/publication/annotation"""
    ret = {}
    try:
        db_conn = dbconnect()
        dbdata = db_conn.get_books_descr(book_ids)
        for binfo in dbdata:
            book_id = binfo[0]
            ret[book_id] = (binfo[1], binfo[2], binfo[3], binfo[4], binfo[5], binfo[6])
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret

def get_book_cover(book_id):
    """return content-type, image or None, None"""
    ret = None, None
    try:
        db_conn = dbconnect()
        dbdata = db_conn.get_book_cover(book_id)
        if dbdata is not None and dbdata[1] is not None and dbdata[1] != '':
            ret = dbdata[0], dbdata[1]
    except Exception as ex:  # pylint: disable=W0703
        logging.error(ex)
    return ret


# 資料來源 政府開放平台 https://data.gov.tw/dataset/151337

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

url = 'https://www.gender.ey.gov.tw/GecDB/Common/OpenXML.ashx?sn=6yrTVzOhjQtbqd8LlVgtKg@@'
df = pd.read_xml(url)

#年份處理
df['year'] = df["Period"].astype(str).str.replace("00","")
df.loc[df["year"] == '1', 'year'] = "100"

#只取總合欄位
dataTotal = df[df['Category1Title'] == '總計']

#取得每個工作類別
jobList = df['Category2Title'][0:19]

#最小年份跟最大年份，並輸出成一個df
yearStar , yearEnd = int(df['year'].head(1).values), int(df['year'].tail(1).values)
listAll = pd.DataFrame(index=(np.arange(yearStar,yearEnd+1)))

'''
#工作類型變為欄位，並除於1000，起始單元變為千元  參考中位數 center=30
#沒辦法客觀的看待各產業成長幅度，決定棄用
for job in jobList:
    listAll[job] = dataTotal[dataTotal['Category2Title']==job]["Val"].values / 1000
'''

#工作類型變為欄位，並轉換為年增率百分比
for job in jobList:
    listAll[job] = dataTotal[dataTotal['Category2Title']==job]["Val"].pct_change().values * 100

'''
#折線圖，呈現效果不佳，決定棄用
plt.figure(figsize=(50,20),dpi = 200)
plt.rcParams['font.sans-serif'] = 'Microsoft JhengHei'
plt.rcParams['font.size'] = 24

for job in jobList:
    plt.plot(listAll.index,listAll[job],label=job)

plt.ylim(listAll.min().min(), listAll.max().max())
plt.xlim(yearStar, yearEnd)
plt.legend(loc='best', bbox_to_anchor=(1, 1))
plt.savefig("各產業經常性薪資變化.png")
'''

#熱度圖
listAll = listAll[1:].T
plt.figure(figsize=(35,10),dpi = 150)
plt.rcParams['font.sans-serif'] = 'Microsoft JhengHei'
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 16

sns.heatmap( listAll, cmap = 'coolwarm', annot=True, fmt = ".2f", annot_kws={"size" : 10},center=3, cbar_kws={"label":"百分比"})
plt.xlabel("民國年")
plt.title("各產業經常性薪資成長幅度")
plt.savefig("各產業經常性薪資成長幅度.png",bbox_inches='tight')

台灣經常性薪資變化熱度圖.py

台灣經常性薪資變化熱度圖.py