# -*- coding: utf-8 -*-
"""
Course: CS 4365/5354 [Computer Vision]
Author: Jose Perez [ID: 80473954]
Assignment: Lab 2
Instructor: Olac Fuentes
"""
from timeit import default_timer as timer
import numpy as np
from scipy import signal
# ========================= Constants =========================

# Matrix used for convolution of the HOGs
convolution_matrix = np.array([[-1, 0, 1]])

def integral_sums_image(im, region, number_of_bars=12):
    # Initialize using the first color channel
    imx = np.zeros(im[:,:,0].shape)
    imx = signal.convolve(im[:,:,0], convolution_matrix, mode='same')

    imy = np.zeros(im[:,:,0].shape)
    imy = signal.convolve(im[:,:,0], np.transpose(convolution_matrix), mode='same')

    magnitude = np.sqrt(imx**2+imy**2)
    direction = (np.arctan2(imy, imx) * 180 / np.pi) + 180 # From 0 to 360

    # Go through the other color channels
    # Get the maximum magnitude for each
    for i in range(1, 3):
        imx = np.zeros(im[:,:,i].shape)
        imx = signal.convolve(im[:,:,i], convolution_matrix, mode='same')

        imy = np.zeros(im[:,:,i].shape)
        imy = signal.convolve(im[:,:,i], np.transpose(convolution_matrix), mode='same')

        curr_magnitude = np.sqrt(imx**2+imy**2)
        curr_direction = (np.arctan2(imy, imx) * 180 / np.pi) + 180 # From 0 to 360

        magnitude = np.maximum(magnitude, curr_magnitude)
        direction = np.maximum(direction, curr_direction)

    #print "[Integral HOG] Finished getting magnitude and direction"

    start_time = timer()
    angle_step = 360 / number_of_bars
    angle_range = xrange(0, 360, angle_step)

    (w, h) = region.shape[:2]
    (row, column) = im.shape[:2]
    row += 1
    column += 1
    integral_sums = np.zeros((12, row-h, column-w ), dtype=np.float64)

    i = 0
    #print "[Integral HOG] Starting calculation of sums"
    for angle in angle_range:
        integral = magnitude.copy().astype(np.float64)
        # Set the magnitude for all other angles to 0
        integral[np.logical_or(direction<angle, direction>=angle+30)] = 0
        integral = integral.cumsum(1).cumsum(0)
        integral = np.pad(integral, (1, 0), 'constant', constant_values=(0))

        A = integral[0:row-h, 0:column-w]
        B = integral[0:row-h, w:column]
        C = integral[h:row, 0:column-w]
        D = integral[h:, w:]

        #pdb.set_trace()
        integral_sums[i] = A + D - B - C
        i = i + 1

    end_time = timer()
    print('[Integral HOG] Duration: ' + str(end_time - start_time))

    return integral_sums


#*
#    SLAM.py: the implementation of SLAM
#    created and maintained by Ty Nguyen
#    tynguyen@seas.upenn.edu
#    Feb 2020
#*
import sys
ros_path = '/opt/ros/kinetic/lib/python2.7/dist-packages'

if ros_path in sys.path:
    sys.path.remove(ros_path)
from MapUtils.bresenham2D import *
from probs_utils import *
import numpy as np
import matplotlib.pyplot as plt
import load_data as ld
import os, sys, time
import p3_util as ut
from read_data import LIDAR, JOINTS
import probs_utils as prob
import math
import cv2
import transformations as tf
from copy import deepcopy
from mpl_toolkits.mplot3d import Axes3D
import logging
if (sys.version_info > (3, 0)):
    import pickle
else:
    import cPickle as pickle

logger = logging.getLogger()
logger.setLevel(os.environ.get("LOGLEVEL", "INFO"))

class SLAM(object):
    def __init__(self):
        self._characterize_sensor_specs()

    def _read_data(self, src_dir, dataset=0, split_name='train'):
        self.dataset_= str(dataset)
        if split_name.lower() not in src_dir:
            src_dir  = src_dir + '/' + split_name
        print('\n------Reading Lidar and Joints (IMU)------')
        self.lidar_  = LIDAR(dataset=self.dataset_, data_folder=src_dir, name=split_name + '_lidar'+ self.dataset_)
        print ('\n------Reading Joints Data------')
        self.joints_ = JOINTS(dataset=self.dataset_, data_folder=src_dir, name=split_name + '_joint'+ self.dataset_)

        res = self.lidar_.data_[0]['res'][0][0]
        self.lidar_angles = np.arange(-135*np.pi/180,135.003*np.pi/180,res).reshape(1,-1)

        self.num_data_ = len(self.lidar_.data_)
        # Position of odometry
        self.odo_indices_ = np.empty((2,self.num_data_),dtype=np.int64)
        self.temp = 0

    def _characterize_sensor_specs(self, p_thresh=None):
        # High of the lidar from the ground (meters)
        self.h_lidar_ = 0.93 + 0.33 + 0.15
        # Accuracy of the lidar
        self.p_true_ = 9
        self.p_false_ = 1.0/9

        #TODO: set a threshold value of probability to consider a map's cell occupied
        self.p_thresh_ = 0.6 if p_thresh is None else p_thresh # > p_thresh => occupied and vice versa
        # Compute the corresponding threshold value of logodd
        self.logodd_thresh_ = prob.log_thresh_from_pdf_thresh(self.p_thresh_)

    def getJointTime(self,time):
        t = self.temp
        # print("getinggg",self.joints_.data_['ts'][0][1]-self.joints_.data_['ts'][0][0])
        # print(len(self.lidar_.data_),len(self.joints_.data_['ts'][0]))
        while ((self.lidar_.data_[time]['t'][0]-self.lidar_.data_[0]['t'][0]>(self.joints_.data_['ts'][0][t]-self.joints_.data_['ts'][0][0])) and ( t+1 < len(self.joints_.data_['ts'][0]))):
            # print(self.lidar_.data_[time]['t'][0],self.joints_.data_['ts'][0][t])
            t = t+1
        self.temp = t
        return t-1

    def _init_particles(self, num_p=0, mov_cov=None, particles=None, weights=None, percent_eff_p_thresh=None):
        # Particles representation
        self.num_p_ = num_p
        #self.percent_eff_p_thresh_ = percent_eff_p_thresh
        self.particles_ = np.zeros((3,self.num_p_),dtype=np.float64) if particles is None else particles

        # Weights for particles
        self.weights_ = 1.0/self.num_p_*np.ones(self.num_p_) if weights is None else weights

        # Position of the best particle after update on the map
        self.best_p_indices_ = np.empty((2,self.num_data_),dtype=np.int64)
        # Best particles
        self.best_p_ = np.empty((3,self.num_data_))
        # Corresponding time stamps of best particles
        self.time_ =  np.empty(self.num_data_)

        # Covariance matrix of the movement model
        tiny_mov_cov   = np.array([[1e-8, 0, 0],[0, 1e-8, 0],[0, 0 , 1e-8]])
        self.mov_cov_  = mov_cov if mov_cov is not None else tiny_mov_cov
        # To generate random noise: x, y, z = np.random.multivariate_normal(np.zeros(3), mov_cov, 1).T
        # this return [x], [y], [z]

        # Threshold for resampling the particles
        self.percent_eff_p_thresh_ = percent_eff_p_thresh

    def _init_map(self, map_resolution=0.05):
        '''*Input: resolution of the map - distance between two grid cells (meters)'''
        # Map representation
        MAP= {}
        MAP['res']   = map_resolution #meters
        MAP['xmin']  = -20  #meters
        MAP['ymin']  = -20
        MAP['xmax']  =  20
        MAP['ymax']  =  20
        MAP['sizex']  = int(np.ceil((MAP['xmax'] - MAP['xmin']) / MAP['res'] + 1)) #cells
        MAP['sizey']  = int(np.ceil((MAP['ymax'] - MAP['ymin']) / MAP['res'] + 1))

        MAP['map'] = np.zeros((MAP['sizex'],MAP['sizey']),dtype=np.int8) #DATA TYPE: char or int8
        self.MAP_ = MAP
        self.bresenDict = {}

        self.log_odds_ = np.zeros((self.MAP_['sizex'],self.MAP_['sizey']),dtype = np.float64)
        self.occu_ = np.ones((self.MAP_['sizex'],self.MAP_['sizey']),dtype = np.float64)
        # Number of measurements for each cell
        self.num_m_per_cell_ = np.zeros((self.MAP_['sizex'],self.MAP_['sizey']),dtype = np.uint64)

    # def getCorrMap(self,map,occX,occY):
    #     r = np.zeros(map.shape)
    #     r[occX,occY] = 1
    #     return np.sum(np.logical_and(r,map))

    def getMapCoord(self,x,y):
        x_map = np.uint16((x-self.MAP_['xmin'])/self.MAP_['res'])
        y_map = np.uint16((y-self.MAP_['ymin'])/self.MAP_['res'])
        return x_map,y_map

    def buildMAP(self,t,x,y,theta):
        # MAP = self.MAP_
        tj0 = self.getJointTime(t)
        scan = self.lidar_.data_[t]['scan'][0]
        neck_angle,head_angle = self.joints_.data_['head_angles'][:,tj0][0],self.joints_.data_['head_angles'][:,tj0][1]
        body_2_lidar_rot = tf.homo_transform(np.dot(tf.rot_z_axis(neck_angle), tf.rot_y_axis(head_angle)),[0,0,0])
        ground_2_body = tf.homo_transform(tf.rot_z_axis(theta),[x,y,self.h_lidar_])
        #Got the transforms
        homoscan = np.empty((4,(self.lidar_angles).shape[1]),dtype=np.float)
        homoscan[0,:] = np.cos(self.lidar_angles)*scan
        homoscan[1,:] = np.sin(self.lidar_angles)*scan
        homoscan[2,:] = np.zeros((1,self.lidar_angles.shape[1]))
        homoscan[3,:] = np.ones(self.lidar_angles.shape[1])
        # xscan = np.cos(self.lidar_angles)*scan
        # yscan = np.sin(self.lidar_angles)*scan
        # zscan = np.zeros((1,xscan.shape[1]))
        # Onescan = np.ones(zscan.shape)
        ground_2_lidar = np.dot(ground_2_body,body_2_lidar_rot)
        # homoscan = np.vstack((xscan,yscan,zscan,Onescan))
        trans_scan = (np.dot(ground_2_lidar,homoscan)).astype(np.float16)
        ground_zz = trans_scan[2]<0.1
        x_new = ((trans_scan[0]-self.MAP_['xmin'])//self.MAP_['res']).astype(np.uint16)
        y_new = ((trans_scan[1]-self.MAP_['ymin'])//self.MAP_['res']).astype(np.uint16)
        x_start = ((x-self.MAP_['xmin'])//self.MAP_['res']).astype(np.uint16)
        y_start = ((y-self.MAP_['xmin'])//self.MAP_['res']).astype(np.uint16)
        if not(self.psx==x_start and self.psy==y_start):
            self.bresenDict = {}

        self.psx = x_start
        self.psy = y_start
        for x_n,y_n,ground in zip(x_new,y_new,ground_zz):
            if abs(x_n)<self.MAP_['sizex'] and abs(y_n)<self.MAP_['sizey']:
                if (self.bresenDict.get((x_n,y_n)) is None):
                    ray_cells = bresenham2D(x_start,y_start,x_n,y_n)
                    self.bresenDict[(x_n,y_n)] = ray_cells
                else:
                    ray_cells = self.bresenDict[(x_n,y_n)]
                    self.dict_use_count = self.dict_use_count +1
                    # print("using dict")
                x = np.asarray(ray_cells[0],dtype=int)
                y = np.asarray(ray_cells[1],dtype=int)
                x_end = x[-1]
                y_end = y[-1]
                x = x[:-1]
                y = y[:-1]
                self.log_odds_[x,y] = self.log_odds_[x,y] + np.log(self.p_false_)
                self.MAP_['map'][x,y] = self.log_odds_[x,y]>np.log(1.5)
                self.log_odds_[x_end,y_end] = self.log_odds_[x_end,y_end]+(1-ground)*np.log(self.p_true_)

                # for temp in range(ray_cells.shape[1]-1):

                #     x = ray_cells[:,temp][1]
                #     y = ray_cells[:,temp][0]
                #     # print(x,y)

                #     self.log_odds_[int(y),int(x)] = self.log_odds_[int(y),int(x)] + np.log(self.p_false_)
                #     if self.log_odds_[int(y),int(x)]>np.log(1.5):
                #         self.MAP_['map'][int(y),int(x)] = 1
                #     else:
                #         self.MAP_['map'][int(y),int(x)] = 0
                # if ground==0:
                #     self.log_odds_[int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])] = self.log_odds_[int(ray_cells[:,-1][0]), \
                #                                                             int(ray_cells[:,-1][1])] + np.log(self.p_true_)
                #     if self.log_odds_[int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])]>np.log(1.5):
                #         self.MAP_['map'][int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])] = 1
                #     else:
                #         self.MAP_['map'][int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])] = 0

    def _build_first_map(self,t0=0,use_lidar_yaw=True):
        """Build the first map using first lidar"""
        self.t0 = t0
        # Extract a ray from lidar data
        # MAP = self.MAP_

        print('\n--------Doing build the first map--------')

        #TODO: student's input from here

        # tj0 = self.getJointTime(t0)
        # scan = self.lidar_.data_[t0]['scan'][0]
        # neck_angle,head_angle = self.joints_.data_['head_angles'][:,tj0][0],self.joints_.data_['head_angles'][:,tj0][1]
        # print("printtt",neck_angle,head_angle)
        # pos_init = self.lidar_.data_[t0]['pose'][0]
        # body_2_lidar_rot = tf.homo_transform(np.dot(tf.rot_z_axis(neck_angle), tf.rot_y_axis(head_angle)),[0,0,0])
        # ground_2_body = tf.homo_transform(tf.rot_z_axis(pos_init[2]),[pos_init[0],pos_init[1],self.h_lidar_])
        #Got the transforms
        # xscan = np.cos(self.lidar_angles)*scan
        # yscan = np.sin(self.lidar_angles)*scan
        # zscan = np.zeros((1,xscan.shape[1]))
        # Onescan = np.ones(zscan.shape)
        # ground_2_lidar = np.dot(ground_2_body,body_2_lidar_rot)
        # homoscan = np.vstack((xscan,yscan,zscan,Onescan))
        # trans_scan = np.dot(ground_2_lidar,homoscan)
        # ground_zz = trans_scan[2]<0.1
        # x_new = np.array((trans_scan[0]-MAP['xmin'])/MAP['res'],dtype=int)
        # y_new = np.array((trans_scan[1]-MAP['ymin'])/MAP['res'],dtype=int)
        # x_start = (pos_init[0]-MAP['xmin'])/MAP['res']
        # y_start = (pos_init[1]-MAP['xmin'])/MAP['res']
        best_p_i = np.argmax(self.weights_)
        best_p = self.particles_[:,best_p_i]
        x = best_p[0]
        y = best_p[1]
        self.psx = x
        self.psy = y
        theta = best_p[2]
        self.buildMAP(t0,x,y,theta)
        self.best_p_[:,t0] = best_p
        self.best_p_indices_[:,t0] = self.getMapCoord(x,y)

        # print(max(x_new-x_start),max(y_new-y_start))
        # plt.plot(self.MAP_)
        # for x_n,y_n,ground in zip(x_new,y_new,ground_zz):
        #     # print("printinggg",x_start,y_start)
        #     ray_cells = bresenham2D(x_start,y_start,x_n,y_n)
        #     for temp in range(ray_cells.shape[1]-1):
        #         x = ray_cells[:,temp][1]
        #         y = ray_cells[:,temp][0]
        #         # print(x,y)
        #         self.log_odds_[int(y),int(x)] = self.log_odds_[int(y),int(x)] + np.log(self.p_false_)
        #         if self.log_odds_[int(y),int(x)]>np.log(1.5):
        #             self.MAP_['map'][int(y),int(x)] = 1
        #         else:
        #             self.MAP_['map'][int(y),int(x)] = 0
        #     if ground==0:

        #         self.log_odds_[int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])] = self.log_odds_[int(ray_cells[:,-1][0]), \
        #                                                                 int(ray_cells[:,-1][1])] + np.log(self.p_true_)
        #         if self.log_odds_[int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])]>np.log(1.5):
        #             self.MAP_['map'][int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])] = 1
        #         else:
        #             self.MAP_['map'][int(ray_cells[:,-1][0]),int(ray_cells[:,-1][1])] = 0

    def _predict(self,t,use_lidar_yaw=True):
        logging.debug('\n-------- Doing prediction at t = {0}------'.format(t))

        #TODO: student's input from here
        # for i in range(self.num_p_):
        #     w_i = np.random.multivariate_normal(np.zeros(3),self.mov_cov_)
        #     self.particles_[:,i] = tf.twoDSmartPlus(self.particles_[:,i],w_i)
        for i in range(self.num_p_):
            #odo_diff = tf.twoDSmartMinus(self.lidar_.data_[t]['pose'][0],self.lidar_.data_[t-1]['pose'][0])
            #delta = tf.twoDSmartPlus(np.random.multivariate_normal(np.zeros(3),self.mov_cov_),odo_diff)
            delta = np.random.multivariate_normal(np.zeros(3),self.mov_cov_)
            self.particles_[:,i] = tf.twoDSmartPlus(self.particles_[:,i],delta)
        #End student's input

    def _update(self,t,t0=0,fig='on'):
        """Update function where we update the """

        # MAP = self.MAP_
        if t == t0:
            self._build_first_map(t0,use_lidar_yaw=True)
            return

        #TODO: student's input from here
        tj0 = self.getJointTime(t)
        neck_angle,head_angle = self.joints_.data_['head_angles'][:,tj0][0],self.joints_.data_['head_angles'][:,tj0][1]
        body_2_lidar_rot = tf.homo_transform(np.dot(tf.rot_z_axis(neck_angle), tf.rot_y_axis(head_angle)),[0,0,0])
        scan = self.lidar_.data_[t]['scan'][0]
        xscan = np.cos(self.lidar_angles)*scan
        yscan = np.sin(self.lidar_angles)*scan
        zscan = np.zeros((1,xscan.shape[1]))
        Onescan = np.ones(zscan.shape)
        corr = []
        for i in range(self.num_p_):
            pose_i = self.particles_[:,i]
            ground_2_body = tf.homo_transform(tf.rot_z_axis(pose_i[2]),[pose_i[0],pose_i[1],self.h_lidar_])
            #Got the transforms
            ground_2_lidar = np.dot(ground_2_body,body_2_lidar_rot)
            homoscan = np.vstack((xscan,yscan,zscan,Onescan))
            trans_scan = np.dot(ground_2_lidar,homoscan)
            # vp = np.vstack((xscan,yscan))
            # print("zz",min(trans_scan[1]))
            trans_scan = trans_scan[:,abs(trans_scan[0])<20]
            trans_scan = trans_scan[:,abs(trans_scan[1])<20]
            x_ind,y_ind = self.getMapCoord(trans_scan[0],trans_scan[1])

            occupied_indices = np.vstack((x_ind,y_ind))
            corr.append(mapCorrelation(self.MAP_['map'],occupied_indices))
        # print(self.num_p_)
            # corr.append(self.getCorrMap(self.MAP_['map'],x_ind,y_ind))
	    # space = 0.02
            # xs = np.arange(pose_i[0]-space,pose_i[0]+space,space/4)
            # ys = np.arange(pose_i[1]-space,pose_i[1]+space,space/4)
            #self.weights_[i] = self.weights_[i]*np.sum(mapCorrelation(self.MAP_['map'], np.array([self.MAP_['xmin'],self.MAP_['xmax']]), \
                                         # np.array([self.MAP_['ymin'],self.MAP_['ymax']]), vp, xs, ys))
            #self.weights_[i] = self.weights_[i]*mapCorrelation(self.MAP_['map'],occupied_indices)

        #self.weights_ = self.weights_/np.sum(self.weights_)
        corr = np.asarray(corr)
        self.weights_ = prob.update_weights(self.weights_,corr)
        best_p_i = np.argmax(self.weights_)
        best_p = self.particles_[:,best_p_i]
        x = best_p[0]
        y = best_p[1]
        theta = best_p[2]
        self.buildMAP(t,x,y,theta)
        self.best_p_[:,t] = best_p
        self.best_p_indices_[:,t] = self.getMapCoord(x,y)

        #End student's input

        # self.MAP_ = MAP
        return self.MAP_


import argparse
import itertools
import os
import subprocess
from collections import OrderedDict

import numpy as np
import torch
import torch.nn as nn
from torch import linalg
from torch.nn import functional as F

def mix_many_models():
    model_paths = [
        os.path.join(args.model_path, file_name)
        for file_name in os.listdir(args.model_path)
    ]

    alphas = np.arange(0, 1.1, 0.1)
    alpha_combinations = list(itertools.product(alphas, repeat=len(model_paths)))
    alpha_combinations = [
        alpha_combination
        for alpha_combination in alpha_combinations
        if sum(alpha_combination) == 1.0
    ]
    #alpha_combinations = [[0.25, 0.25, 0.25, 0.25]]
    alpha_combinations = [[1/len(model_paths)]*len(model_paths)]
    for i, alpha_combination in enumerate(alpha_combinations):
        print(f"Combination {i + 1} of {len(alpha_combinations)}")
        print(f"Alphas: {alpha_combination}")

        # Load models and calculate weighted average
        theta = {}
        for j, model_path in enumerate(model_paths):
            alpha = alpha_combination[j]
            theta_j = torch.load(model_path)["model"]

            for key in theta_j.keys():
                if key not in theta:
                    theta[key] = alpha * theta_j[key]
                else:
                    theta[key] += alpha * theta_j[key]

        # update the model acccording to the new weights

        #torch.load(model_path)
        torch.save(
            {
                "model": theta,
            },
            "/home/nick/shortcuts/monodepth3_checkpoints/soup/res.pt",
        )
        #subprocess.call(["python", "local_evaluation.py"])

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("model_path", help="path to model")
    args = parser.parse_args()

    mix_many_models()


import pickle
import DLfunctions as dl
from keras.preprocessing.sequence import pad_sequences

print("What is the name of the hyperparams file?(Local directory):")
params_file_name = input()

a_file = open(params_file_name, "rb")
params = pickle.load(a_file)

w = params["w"]
b = params["b"]

print("What is the questionable URL?")
X_URL = input()
X_URL_list = []

#convert to array
X_URL_list.append([ord(c) for c in X_URL][:-2])
print(X_URL_list)
padded = pad_sequences(X_URL_list,maxlen=3063,padding='post')
print(padded)
X_TEST = padded.T

if(dl.predict(w, b, X_TEST)):
    print("This is probably a bad URL!")
else:
    print("This is probably an okay URL!")


from django import forms
from .models import Museum, Group
from user.models import UserProfile

class CreateGroupForm(forms.Form):
    name = forms.CharField(max_length=50)
    number = forms.IntegerField(min_value=1, max_value=200)
    museum = forms.ModelChoiceField(Museum.objects.all())

    def create_users_pdf(self, user):
        museum = self.cleaned_data['museum']
        name = self.cleaned_data['name']

        group = Group(
            museum=museum,
            name=name,
            created_by=user
        )
        group.save()
        tokens = []
        for x in range(self.cleaned_data['number']):
            profile = UserProfile()
            profile.display_name = f'space cadet {x + 1}'
            profile.save()
            group.profiles.add(profile)
            museum.profiles.add(profile)
            tokens.append(profile.qr_token)

        group.save()
        museum.save()


# coding: UTF-8

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# 使用する変数の宣言 znは原子番号
i = 0
zn = 18.0

# グラフの作成 azim,elevオプションで見る角度設定可能
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d', aspect='equal')

# 軸ラベルの設定
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
ax.set_zlabel("Z-axis")
ax.set_xlim([-0.5, 0.5])
ax.set_ylim([-0.5, 0.5])
ax.set_zlim([-0.5, 0.5])

# モンテカルロ法による電子雲描画 rはボーア半径との比 plsは2pz軌道の波動関数
while i < 300000:
	p = np.random.rand()
	x = np.random.rand() * 1.0 - 0.5
	y = np.random.rand() * 1.0 - 0.5
	z = np.random.rand() * 1.0 - 0.5
	r = np.sqrt(x ** 2 + y ** 2 + z ** 2)
	rho = zn * r
	pls = 0.5 / np.sqrt(6.0) * zn * np.sqrt(zn) * rho * np.exp( - rho * 0.5) * 0.5 * np.sqrt(3.0 / np.pi) * z / r
	if p < pls ** 2 and z > 0:
		ax.scatter3D(x, y, z, s=0.1, color='#FF0000', alpha=0.01)
		i += 1
	elif p < pls ** 2 and z < 0:
		ax.scatter3D(x, y, z, s=0.1, color='#0000FF', alpha=0.01)
		i += 1

#グラフを描画
plt.savefig("Argraph2pz.png")


# -*- coding: utf-8 -*-
import numpy as np
from collections import deque, OrderedDict
from datetime import datetime
from common.funcs import *
from common.layers import *
from common.optimizers import *

class Planner_separate():

    def __init__(self, name, env, state_dim, action_dim):

        #name：このPlannerインスタンスの名前
        #env：このPlannerインスタンスが対象とする環境
        #state_dim：このPlannerインスタンスが認識する状態の要素数
        #action_dim：このPlannerインスタンスが認識する行動の要素数

        self._name = name
        self._env = env
        self._state_dim = state_dim
        self._action_dim = action_dim

        ###Layersの定義###

        output_dim_afn1 = self._state_dim*10
        output_dim_afn3 = self._action_dim*10
        output_dim_afn2 = np.ceil( np.sqrt(output_dim_afn1*output_dim_afn3) ).astype(np.int)

        ##ActorのLayersの定義##

        self._layers_actor = OrderedDict()

        #①Affine 「afn1_actor」　instance of Affine
        opt_afn1_actor = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn1_actor = Affine(name="afn1_actor", input_shape=(state_dim,), output_shape=(output_dim_afn1,), optimizer=opt_afn1_actor,
                        init_weight_option="xavier")
        self._layers_actor[afn1_actor.name] = afn1_actor
        prev_layer = afn1_actor

        #②Tanh　「tanh_afn1_actor」　instance of Tanh
        tanh_afn1_actor = Tanh(name="tanh_afn1_actor", input_shape=prev_layer.output_shape)
        self._layers_actor[tanh_afn1_actor.name] = tanh_afn1_actor
        prev_layer = tanh_afn1_actor

        #③Affine 「afn2_actor」　instance of Affine
        opt_afn2_actor = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn2_actor = Affine(name="afn2_actor", input_shape=prev_layer.output_shape, output_shape=(output_dim_afn2,), optimizer=opt_afn2_actor,
                        init_weight_option="xavier")
        self._layers_actor[afn2_actor.name] = afn2_actor
        prev_layer = afn2_actor

        #④Tanh　「tanh_afn2_actor」　instance of Tanh
        tanh_afn2_actor = Tanh(name="tanh_afn2_actor", input_shape=prev_layer.output_shape)
        self._layers_actor[tanh_afn2_actor.name] = tanh_afn2_actor
        prev_layer = tanh_afn2_actor

        #⑤Affine 「afn3_actor」　instance of Affine
        opt_afn3_actor = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn3_actor = Affine(name="afn3_actor", input_shape=prev_layer.output_shape, output_shape=(output_dim_afn3,), optimizer=opt_afn3_actor,
                        init_weight_option="xavier")
        self._layers_actor[afn3_actor.name] = afn3_actor
        prev_layer = afn3_actor

        #⑥Tanh　「tanh_afn3_actor」　instance of Tanh
        tanh_afn3_actor = Tanh(name="tanh_afn3_actor", input_shape=prev_layer.output_shape)
        self._layers_actor[tanh_afn3_actor.name] = tanh_afn3_actor
        prev_layer = tanh_afn3_actor

        #Actor　平均μの出力のlayers　中身はAffine1個とTanh1個
        opt_afn_actor_mu = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        self._out_actor_mu = Actor_Output(name="out_actor_mu", input_shape=prev_layer.output_shape,
                                          output_shape=(action_dim,), optimizer=opt_afn_actor_mu)
        #self._layers_actorに含めないので注意

        #Actor　分散varのlog(var)の出力のlayers　中身はAffine1個とTanh1個
        opt_afn_actor_log_var = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        self._out_actor_log_var = Actor_Output(name="out_actor_log_var", input_shape=prev_layer.output_shape,
                                               output_shape=(action_dim,), optimizer=opt_afn_actor_log_var)
        #self._layers_actorに含めないので注意

        ##ActorのLayersの定義　終わり##

        ##CriticのLayersの定義##

        self._layers_critic = OrderedDict()

        #①Affine 「afn1_critic」　instance of Affine
        opt_afn1_critic = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn1_critic = Affine(name="afn1_critic", input_shape=(state_dim,), output_shape=(output_dim_afn1,), optimizer=opt_afn1_critic,
                        init_weight_option="xavier")
        self._layers_critic[afn1_critic.name] = afn1_critic
        prev_layer = afn1_critic

        #②Tanh　「tanh_afn1_critic」　instance of Tanh
        tanh_afn1_critic = Tanh(name="tanh_afn1_critic", input_shape=prev_layer.output_shape)
        self._layers_critic[tanh_afn1_critic.name] = tanh_afn1_critic
        prev_layer = tanh_afn1_critic

        #③Affine 「afn2_critic」　instance of Affine
        opt_afn2_critic = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn2_critic = Affine(name="afn2_critic", input_shape=prev_layer.output_shape, output_shape=(output_dim_afn2,), optimizer=opt_afn2_critic,
                        init_weight_option="xavier")
        self._layers_critic[afn2_critic.name] = afn2_critic
        prev_layer = afn2_critic

        #④Tanh　「tanh_afn2_critic」　instance of Tanh
        tanh_afn2_critic = Tanh(name="tanh_afn2_critic", input_shape=prev_layer.output_shape)
        self._layers_critic[tanh_afn2_critic.name] = tanh_afn2_critic
        prev_layer = tanh_afn2_critic

        #⑤Affine 「afn3_critic」　instance of Affine
        opt_afn3_critic = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn3_critic = Affine(name="afn3_critic", input_shape=prev_layer.output_shape, output_shape=(output_dim_afn3,), optimizer=opt_afn3_critic,
                        init_weight_option="xavier")
        self._layers_critic[afn3_critic.name] = afn3_critic
        prev_layer = afn3_critic

        #⑥Tanh　「tanh_afn3_critic」　instance of Tanh
        tanh_afn3_critic = Tanh(name="tanh_afn3_critic", input_shape=prev_layer.output_shape)
        self._layers_critic[tanh_afn3_critic.name] = tanh_afn3_critic
        prev_layer = tanh_afn3_critic

        #⑦Affine 「afn4_critic」　instance of Affine　出力layer　活性化関数は無し（linear）
        opt_afn4_critic = Adam(lr=0.001, rho1=0.9, rho2=0.999)
        afn4_critic = Affine(name="afn4_critic", input_shape=prev_layer.output_shape, output_shape=(1,), optimizer=opt_afn4_critic,
                        init_weight_option="xavier")
        self._layers_critic[afn4_critic.name] = afn4_critic

        ##CriticのLayersの定義　終わり##

        #ActorとCritic　Lossの定義##

        #ActorのLoss
        self._loss_actor = Actor_Loss("loss_actor")

        #criticのLoss
        self._loss_critic = Critic_Loss("loss_critic")

        ##ActorとCritic　Lossの定義　終わり##

    def predict_best_action(self, a_state):
        #最適な行動を推測

        if a_state.ndim==1:
            a_state = a_state.reshape(1, self._state_dim)
        elif a_state.shape[0]!=1:
            raise ValueException("a_stateは1件だけにしてください。1件のstateについてbest actionを推測します。")

        #Actorから正規分布の平均μと分散varのlog_varを得る。
        #どちらも(1, action_dim)
        mu, log_var = self._forward_output_actor(a_state, train_flg=False)

        #分散var
        #(1, action_dim)
        var = np.exp(log_var)

        #muとvarからバッチ数のaxis=0を削除し、(action_dim,)にする
        mu = mu[0]
        var = var[0]

        #平均μと分散varの正規分布からサンプリング
        best_action = np.random.normal(loc=mu, scale=np.sqrt(var))

        return best_action

    def _forward_output_actor(self, state, train_flg):
        #Actorの出力
        #分岐以外の、勾配に影響を与える演算はしないこと

        if state.ndim==1:
            state = state.reshape(1, self._state_dim)

        ##Actor中間layersの出力##
        #出力値を「m」とする
        #(N, M) 「M」は最後の中間layerのAffineのニューロン数
        x = state
        for layer in self._layers_actor.values():
            x = layer.forward(x, train_flg)
        m = x
        ##Actor中間layersの出力　終わり##

        ##Actorの出力##

        #2つの出力layersにActor中間layersの出力を渡す。
        #Actor中間layersの出力が2分岐する。

        #Actorのμ出力layersからの出力 (N, action_dim)
        mu = self._out_actor_mu.forward(m, train_flg)

        #Actorのlog(var)出力layersからの出力 (N, action_dim)
        log_var = self._out_actor_log_var.forward(m, train_flg)

        ##Actorの出力　終わり##

        return mu, log_var

    def _backward_output_actor(self, d_mu, d_log_var):
        #Actorの出力から最初までの誤差逆伝播

        ##Actorの出力の逆伝播##

        #Actorのμ出力部分の逆伝播
        #(N, M) 「M」は共有最終layerのAffineのニューロン数
        d_m_mu = self._out_actor_mu.backward(d_mu)

        #Actorのlog(var)出力部分の逆伝播
        #(N, M) 「M」はActor中間layersの最終layerのAffineのニューロン数
        d_m_log_var = self._out_actor_log_var.backward(d_log_var)

        #forwardでActor中間layersの最終layerの出力mを
        #Actorのμ出力、Actorのlog(var)出力
        #に2分岐したので、これらから逆伝播してきた勾配を合算する。
        d_m = d_m_mu + d_m_log_var

        ##Actorの出力の逆伝播　終わり##

        ##Actor中間layers（最初まで）の逆伝播##
        #(N, state_dim)
        layers_shared = list(self._layers_actor.values())
        layers_shared.reverse()
        d_out = d_m
        for layer in layers_shared:
            d_out = layer.backward(d_out)
        d_state = d_out
        ##Actor中間layers（最初まで）の逆伝播　終わり##

        return d_state

    def _forward_output_critic(self, state, train_flg):
        #Criticの出力
        #分岐以外の、勾配に影響を与える演算はしないこと

        if state.ndim==1:
            state = state.reshape(1, self._state_dim)

        x = state
        for layer in self._layers_critic.values():
            x = layer.forward(x, train_flg)
        V = x

        return V

    def _backward_output_critic(self, d_V):
        #Criticの出力から最初までの誤差逆伝播

        layers_shared = list(self._layers_critic.values())
        layers_shared.reverse()
        d_out = d_V
        for layer in layers_shared:
            d_out = layer.backward(d_out)
        d_state = d_out

        return d_state

    def _forward_loss_actor(self, state, action, G, V, softplus_to_advantage, weight_decay_lmd):
        #Actorのloss
        #action, Gのもとになったstateは、引数stateと同じ並びであること
        #分岐以外の、勾配に影響を与える演算はしないこと
        #V：Criticの出力　(N, 1)

        ##Actorの出力##
        #Actorの出力μ、Actorの出力log(var)
        #(N, action_dim), (N, action_dim),
        mu, log_var = self._forward_output_actor(state, train_flg=True)
        ##Actorの出力　終わり##

        ##Actorのloss##
        La = self._loss_actor.forward(mu, log_var, action, V, G, softplus_to_advantage)
        ##Actorのloss　終わり##

        #荷重減衰
        if weight_decay_lmd > 0:
            sum_all_weights_square = self._sum_all_weights_square(role=0)
            La = La + 0.5*weight_decay_lmd*sum_all_weights_square

        return La

    def _backward_loss_actor(self, d_La=1):
        #Actorのlossから最初までの一気通貫の誤差逆伝播

        ##Actorのloss　逆伝播##
        #どちらも(N, action_dim)
        d_mu, d_log_var = self._loss_actor.backward(d_La)
        ##Actorのloss　逆伝播　終わり##

        ##Actorの出力と中間Layersの逆伝播　最初まで##
        #(N, state_dim)
        d_states = self._backward_output_actor(d_mu, d_log_var)
        ##Actorの出力と中間Layersの逆伝播　最初まで　終わり##

        return d_states

    def _forward_loss_critic(self, state, G, weight_decay_lmd):
        #Criticのloss
        #Gのもとになったstateは、引数stateと同じ並びであること
        #分岐以外の、勾配に影響を与える演算はしないこと

        ##Criticの出力##
        #Criticの出力V
        #(N, 1),
        V = self._forward_output_critic(state, train_flg=True)
        ##Criticの出力　終わり##

        ##Criticのloss##
        Lc = self._loss_critic.forward(V, G)  #Gは教師信号として使用される
        ##Criticのloss　終わり##

        #荷重減衰
        if weight_decay_lmd > 0:
            sum_all_weights_square = self._sum_all_weights_square(role=1)
            Lc = Lc + 0.5*weight_decay_lmd*sum_all_weights_square

        #戻り値にVがあるのは、呼び出し元で使うから
        return Lc, V

    def _backward_loss_critic(self, d_Lc=1):
        #Criticのlossから最初までの一気通貫の誤差逆伝播

        ##Criticのloss　逆伝播##
        #(N, 1)
        d_V = self._loss_critic.backward(d_Lc)
        ##Criticのloss　逆伝播#　終わり##

        ##Criticの出力と中間Layersの逆伝播　最初まで##
        #(N, state_dim)
        d_states = self._backward_output_critic(d_V)
        ##Criticの出力と中間Layersの逆伝播　最初まで　終わり##

        return d_states

    def train(self, episodes, steps_per_episode, gamma=0.99, metrics=1, standardize_G=True, softplus_to_advantage=False,
              weight_decay_lmd=0, verbose_interval=100):

        start_time = datetime.now()

        #エピソード毎の記録list生成
        loss_episodes = [] #エピソード毎のlossのlist
        loss_actor_episodes = [] #エピソード毎のActorのlossのlist
        loss_critic_episodes = [] #エピソード毎のCriticのlossのlist
        step_count_episodes = [] #エピソード毎のステップ数のlist
        score_episodes = [] #エピソード毎のスコア（Σステップ毎の即時reward）のlist

        episode_count = 0
        step_count_total = 0
        best_step_count = 0 #今までのepisodeの中で最も多いstep回数
        best_score = -np.inf #今までのepisodeの中で最も大きいscore
        best_metrics_count = 0

        #エピソード反復
        for ep in range(0, episodes):
            #1エピソード

            #このエピソード中の全ステップ記録のlist生成
            state_steps_episode = []
            action_steps_episode = []
            reward_steps_episode = []
            next_state_steps_episode = []

            step_count_ep = 0
            score_ep = 0
            save_temp_params = False

            #環境の開始時点にagentをセット
            curr_st = self._env.reset()

            #ステップ反復
            for st in range(steps_per_episode):
                #1ステップ

                #ステップ実行
                action_predicted = self.predict_best_action(curr_st)
                next_st, reward_earned, done, info = self._env.step(action_predicted)

                #このエピソード中の全ステップ記録のlistに追加
                state_steps_episode.append(curr_st)
                action_steps_episode.append(action_predicted)
                reward_steps_episode.append(reward_earned)
                next_state_steps_episode.append(next_st)

                step_count_ep += 1
                step_count_total += 1

                #ステップ反復終了判定　steps_per_episodeに達したかenvからdone=Trueが返ってきたか
                #終了するならbreak
                if step_count_ep>=steps_per_episode or done==True:
                    break
                else:
                    curr_st = next_st

            #ステップ反復　for　終わり

            #このエピソードのスコア算出
            #各ステップの即時報酬の単純合計
            score_ep = sum(reward_steps_episode)

            #このエピソードの”成績”が過去最高なら、パラメーターを退避

            if metrics==0 and (step_count_ep>=best_step_count):
                #step countで成績を計測
                best_step_count = step_count_ep
                best_metrics_count += 1
                save_temp_params = True
            elif metrics==1 and (score_ep>=best_score):
                #scoreで成績を計測
                best_score = score_ep
                best_metrics_count += 1
                save_temp_params = True

            if save_temp_params==True:
                #パラメーターを一時退避
                self._keep_temporarily_all_learnable_params()

            #割引報酬和「G」算出
            li_G = self._calc_G_of_step_in_an_episode(reward_steps_episode, gamma)

            #割引報酬和Gの標準化　引数standardize_Gでやるかやらないか指定される
            if standardize_G==True:
                Gs = standardize(li_G, with_mean=False).reshape(-1, 1) #平均を0にしない標準化
            else:
                Gs = np.array(li_G).reshape(-1, 1)

            #ActorとCriticのloss算出の順伝播　引数の準備
            states = np.array(state_steps_episode)
            actions = np.array(action_steps_episode)

            #Critic　loss算出の順伝播　Actorで使用するVも取得
            loss_critic_ep, Vs = self._forward_loss_critic(state=states, G=Gs, weight_decay_lmd=weight_decay_lmd)
            #Critic　逆伝播
            _ = self._backward_loss_critic(d_Lc=1)
            #Critic　パラメーター更新
            self._update_all_learnable_params(role=1, weight_decay_lmd=weight_decay_lmd)

            #Actor　loss算出の順伝播
            loss_actor_ep = self._forward_loss_actor(state=states, action=actions, G=Gs, V=Vs,
                                                     softplus_to_advantage=softplus_to_advantage,
                                                     weight_decay_lmd=weight_decay_lmd)
            #Actor　逆伝播
            _ = self._backward_loss_actor(d_La=1)
            #Actor　パラメーター更新
            self._update_all_learnable_params(role=0, weight_decay_lmd=weight_decay_lmd)

            #このエピソードの記録をエピソード毎の記録listに追加
            step_count_episodes.append(step_count_ep) #ステップ数
            loss_actor_episodes.append(loss_actor_ep) #Actorのloss
            loss_critic_episodes.append(loss_critic_ep) #Criticのloss
            score_episodes.append(score_ep) #score

            if verbose_interval>0 and ( (ep+1)%verbose_interval==0 or ep==0 or (ep+1)==episodes ):

                time_string = datetime.now().strftime('%H:%M:%S')

                if metrics==0:
                    best_metrics_string = " best step count:" + str(best_step_count) + "(" + str(best_metrics_count) + "回)"
                elif metrics==1:
                    best_metrics_string = " best score:" + str(best_score) + "(" + str(best_metrics_count) + "回)"
                else:
                    best_metrics_string=""

                if save_temp_params==True:
                    params_saved_string = " ベストなパラメーターを一時退避"
                else:
                    params_saved_string = ""

                print("Episode:" + str(ep) + " score:" + str(score_ep) + " step count:" + str(step_count_ep) + \
                      " loss_actor:" + str(loss_actor_ep) + " loss_critic:" + str(loss_critic_ep) + \
                      best_metrics_string + params_saved_string + " time:" + time_string)

            episode_count += 1

        #エピソード反復　for　終わり

        #一時退避させてたパラメーターを戻す
        self._adopt_all_learnable_params_kept_temporarily()
        if verbose_interval>0:
            print("一時退避したベストなパラメーターを正式採用")

        end_time = datetime.now()

        processing_time_total = end_time - start_time #総処理時間　datetime.timedelta
        processing_time_total_string = timedelta_HMS_string(processing_time_total) #総処理時間の文字列表現

        #resultを生成し、エピソード毎の記録listや引数やらを追加
        result = {}
        result["name"] = self._name
        result["episode_count"] = episode_count
        result["loss_actor_episodes"] = loss_actor_episodes
        result["loss_critic_episodes"] = loss_critic_episodes
        result["step_count_episodes"] = step_count_episodes
        result["score_episodes"] = score_episodes
        result["step_count_total"] = step_count_total
        result["processing_time_total_string"] = processing_time_total_string
        result["processing_time_total"] = processing_time_total
        #以下引数
        result["episodes"] = episodes
        result["steps_per_episode"] = steps_per_episode
        result["gamma"] = gamma
        result["metrics"] = metrics
        result["softplus_to_advantage"] = softplus_to_advantage
        result["weight_decay_lmd"] = weight_decay_lmd

        return result

    def _calc_G_of_step_in_an_episode(self, li_reward_in_an_episode, gamma):
        #エピソード1個分の記録中の各ステップの割引報酬和Gを計算する。
        #li_reward_in_an_episode：エピソード1個分の全ステップのrewardのlist。
        #戻り値は、このエピソード1個の中の各ステップのsum_of_discounted_rewardsのlist。listのlenはステップ数。
        #※もしExperience Replay方式にする場合、ここは、エピソード1個分の全ステップ記録にGを付加し、そのエピソード1個分の記録を
        #経験バッファに追加、となる。

        li_G = []
        for t, r in enumerate(li_reward_in_an_episode):
            li_discounted_rewards_future = \
            [r_following * (gamma**t_diff) for t_diff, r_following in enumerate(li_reward_in_an_episode[t:])]
            sum_of_discounted_rewards = sum(li_discounted_rewards_future)
            li_G.append(sum_of_discounted_rewards)

        return li_G

    def _update_all_learnable_params(self, role, weight_decay_lmd):
        #role：Actor（0）かCritic（1）か
        #指定されたroleの全Layersのtrainableなパラメーターを一括更新する。

        if role==0:
            #Actor
            for layer in self._layers_actor.values():
                if layer.trainable == True:
                    layer.update_learnable_params(weight_decay_lmd)
            self._out_actor_mu.update_learnable_params(weight_decay_lmd)
            self._out_actor_log_var.update_learnable_params(weight_decay_lmd)
        elif role==1:
            #Critic
            for layer in self._layers_critic.values():
                if layer.trainable == True:
                    layer.update_learnable_params(weight_decay_lmd)

    def save_params_in_file(self, file_dir, file_name=""):
        #このモデルインスタンスのパラメーターをファイル保存する。

        if file_name=="":
            file_name = self._name + ".pickle"

        file_path = file_dir + file_name

        #Dictionaryにして保存。keyはlayer.name。
        #all_params_dic(Dictionary)
        # --learnable layer1の保存したいパラメーターのtuple(weightsのndarray, biasesのndarray)
        # --learnable layer2の保存したいパラメーターのtuple(weightsのndarray, biasesのndarray)
        #　・
        #　・
        # --Actor outout layersの保存したいパラメーターのtuple(weightsのndarray, biasesのndarray)

        all_params_dic = {}

        #Actorのパラメーター分
        for layer in self._layers_actor.values():
            if layer.trainable == True:
                params_tpl = layer.copy_params()
                all_params_dic[layer.name] = params_tpl
        all_params_dic[self._out_actor_mu.name] = self._out_actor_mu.copy_params()
        all_params_dic[self._out_actor_log_var.name] = self._out_actor_log_var.copy_params()

        #Criticのパラメーター分
        for layer in self._layers_critic.values():
            if layer.trainable == True:
                params_tpl = layer.copy_params()
                all_params_dic[layer.name] = params_tpl

        save_pickle_file(all_params_dic, file_path)

        return file_name

    def overwrite_params_from_file(self, file_path):
        #このモデルインスタンスの全パラメーターを、ファイル保存されている別の物に差し替える。

        param_layer_tpls_dic = read_pickle_file(file_path)

        for layer_name in param_layer_tpls_dic.keys():

            #上書きするパラメーターをLayer毎に取り出す
            layer_params_tpl = param_layer_tpls_dic[layer_name]

            #コピー先Layer毎に上書きする。
            #名前が同じLayerがコピー先Layer。

            if layer_name in self._layers_actor.keys():
                #Actor　中間layers
                to_layer = self._layers_actor[layer_name]
                if to_layer.trainable==True:
                    #ltrainableなLayer　上書き
                    to_layer.overwrite_params(layer_params_tpl)
            elif layer_name==self._out_actor_mu.name:
                #Actor　μ出力layers
                self._out_actor_mu.overwrite_params(layer_params_tpl)
            elif layer_name==self._out_actor_log_var.name:
                #Actor　log(var)出力layers
                self._out_actor_log_var.overwrite_params(layer_params_tpl)
            elif layer_name in self._layers_critic.keys():
                #Critic　全layers
                to_layer = self._layers_critic[layer_name]
                if to_layer.trainable==True:
                    #ltrainableなLayer　上書き
                    to_layer.overwrite_params(layer_params_tpl)

    def _keep_temporarily_all_learnable_params(self):

        #配下の各trainableなLayerに対し、現時点でのlearnableパラメーターの一時退避を指示

        #Actor
        for layer in self._layers_actor.values():
            if layer.trainable == True:
                layer.keep_temporarily_learnable_params()
        self._out_actor_mu.keep_temporarily_learnable_params()
        self._out_actor_log_var.keep_temporarily_learnable_params()

        #Critic
        for layer in self._layers_critic.values():
            if layer.trainable == True:
                layer.keep_temporarily_learnable_params()

    def _adopt_all_learnable_params_kept_temporarily(self):

        #配下の各trainableなLayerに対し、一時退避していたlearnableパラメーターの正式採用を指示

        #Actor
        for layer in self._layers_actor.values():
            if layer.trainable == True:
                layer.adopt_learnable_params_kept_temporarily()
        self._out_actor_mu.adopt_learnable_params_kept_temporarily()
        self._out_actor_log_var.adopt_learnable_params_kept_temporarily()

        #Critic
        for layer in self._layers_critic.values():
            if layer.trainable == True:
                layer.adopt_learnable_params_kept_temporarily()

    def _sum_all_weights_square(self, role):
        #role：Actor（0）かCritic（1）か
        #weightを持つtrainableな全Layerと出力layersのweightの2乗の総和を返す。
        #荷重減衰（weight decay）のため。

        if role==0:
            #Actor
            sum_of_weights_square = 0
            for layer in self._layers_actor.values():
                if layer.trainable == True and isinstance(layer, Affine):
                    sum_of_weights_square += layer.sum_weights_square()
            sum_of_weights_square += self._out_actor_mu.sum_weights_square()
            sum_of_weights_square += self._out_actor_log_var.sum_weights_square()
        elif role==1:
            #Critic
            sum_of_weights_square = 0
            for layer in self._layers_critic.values():
                if layer.trainable == True and isinstance(layer, Affine):
                    sum_of_weights_square += layer.sum_weights_square()
        else:
            sum_of_weights_square = 0

        return sum_of_weights_square

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    @property
    def env(self):
        return self._env

    @property
    def state_dim(self):
        return self._state_dim

    @property
    def action_dim(self):
        return self._action_dim


from html.parser import HTMLParser
from read_site_content import read_site_content
import datetime
import all_id_pages

class HabrPageParser(HTMLParser):

    bull_title = False
    bull_user = False
    bull_hash = False
    bull_ul = False
    bull_data = False

    title=''
    user = ''
    data = []
    hash = []

    def handle_starttag(self, tag, attrs):
        if tag == 'ul':
            for attr in attrs:
                if attr[1] == 'post__hubs post__hubs_full-post inline-list':
                    self.bull_ul=True

        if tag == 'a':
            for index, attr in enumerate(attrs):
                if str(attr[1])[21:25] == 'hub/':
                    self.hash.append(str(attr[1])[25:])
                if str(attr[1]) == 'inline-list__item-link hub-link ':
                    if str(attrs[index - 1][1])[21:29] == 'company/':
                        self.hash.append(str(attrs[index - 1][1])[29:])
                        self.bull_ul = False

        if tag == 'span':
            for attr in attrs:
                if attr[1] == 'post__title-text':
                    self.bull_title = True
                if attr[1] == 'user-info__nickname user-info__nickname_small':
                    self.bull_user = True
                if attr[1] == 'post__time':
                    self.bull_data = True

    def handle_data(self, data):
        day=''
        month=''
        year=''
        time=''

        if self.bull_title:
            self.title = data
            self.bull_title = False

        if self.bull_user:
            self.user = data
            self.bull_user = False

        if self.bull_hash:
            self.hash = data
            self.bull_hash = False

        if self.bull_data:
            split = data.lstrip().split(' ')
            all_month = {'января':1, 'февраля':2, 'марта':3, 'апреля':4, 'мая':5, 'июня':6,
                         'июля':7, 'августа':8, 'сентября':9, 'октября':10, 'ноября':11,'декабря':12,}
            if split[0] == 'вчера' or split[0] == 'сегодня':
                date = datetime.datetime.today()
                yesterday_date = date - datetime.timedelta(days=1)
                all_date = {'вчера':yesterday_date.day, 'сегодня':date.day}
                day = all_date.get(split[0])
                month = date.month
            else:
                day = split[0]

                month = all_month.get(split[1])

            time =split[-1].split(':')

            if len(split) > 4:
                year = split[2]
            else:
                year = str(datetime.datetime.now()).split('-')[0]

            self.data = datetime.datetime(int(year), int(month), int(day), int(time[0]),int(time[1]))
            self.bull_data = False

    def clean_hash(self):
        self.hash = []

id_pages = all_id_pages.all_id_pages[:3]

print('id_pages ', id_pages )

def parse_page(id_pages):
    lenn = len(id_pages)
    parser = HabrPageParser()
    result=[]
    for index, id_page in enumerate(id_pages):
            print(index,'/',lenn)
            link = 'https://habrahabr.ru/post/' + id_page[1]
            habr_page = read_site_content(link)
            parser.feed(habr_page)
            id = id_page[1]
            type = id_page [0]
            title = parser.title
            author = parser.user
            hashes = parser.hash
            parser.clean_hash()
            data = parser.data
            result.append([id, type, title, author, data, hashes])
    return result


import logging
from concurrent.futures import ThreadPoolExecutor
from time import sleep
from typing import List, Any, Union

from django.core.files.uploadedfile import InMemoryUploadedFile

from app.forms import UploadFilesForm
from app.models import TaxonomyAbundance
from app.util.file_parser import parse_taxonomy_file, FILE_TYPE_TAXONOMY, TaxonomyAbundanceParserResult, \
    FILE_TYPE_TAXONOMY_MERGED, parse_taxonomy_merged_file, TaxonomyParserResult
from app.util.helper import Message
# import logging as log
from app.views_admin import *

# Get an instance of a logger
log = logging.getLogger("app")

@login_not_required
def public_index(request):
    log.info("public page")
    return render(request, 'public/index.html')

def dashboard(request):
    return render(request, 'dashboard.html')

# class UploadFilesView(FormView):
#     form_class = UploadFilesForm
#     template_name = 'upload_files.html'
#     success_url = 'upload_files.html'
#
#     def post(self, request, *args, **kwargs):
#         form_class = self.get_form_class()
#         form = self.get_form(form_class)
#         files = request.FILES.getlist('files')
#         if form.is_valid():
#             for f in files:
#                 ...  # Do something with each file.
#             return self.form_valid(form)
#         else:
#             return self.form_invalid(form)

def upload_files(request):
    if request.method == 'POST':
        log.debug("request.user %s", request.user)
        form = UploadFilesForm(request.POST, request.FILES, user=request.user, )
        messages = []
        if form.is_valid():
            # files = form.cleaned_data['files']
            files = request.FILES.getlist('files')
            file_type = form.cleaned_data['type']
            project = form.cleaned_data['project']
            if file_type == FILE_TYPE_TAXONOMY:
                for f in files:
                    tax_parse_result = parse_taxonomy_file(f)
                    messages.extend(handle_one_sample_taxonomy(project, tax_parse_result))
            if file_type == FILE_TYPE_TAXONOMY_MERGED:
                for f in files:
                    result: List[TaxonomyParserResult] = parse_taxonomy_merged_file(f)
                    for tax_parser_result in result:
                        messages.extend(handle_one_sample_taxonomy(project, tax_parser_result))

            form = UploadFilesForm(user=request.user)
            return render(request, 'upload_files.html',
                          {'form': form, 'message': 'Sve ok uneseno u formu', 'messages': messages})
    else:
        form = UploadFilesForm(user=request.user)

    return render(request, 'upload_files.html', {'form': form, 'message': ''})

def handle_one_sample_taxonomy(project: Project, tax_parse_result: TaxonomyParserResult) -> List[str]:
    messages = []
    sample: Sample = Sample.objects.filter(name=tax_parse_result.sample_name).first()
    if sample is not None:
        messages.append(f"Exist sample {tax_parse_result.sample_name}, remove prijasnje rezultate")
        TaxonomyAbundance.objects.filter(sample=sample).delete()
    else:
        messages.append(f"Create new sample {tax_parse_result.sample_name} in project {project.name}")
        sample = Sample.objects.create(name=tax_parse_result.sample_name, project=project)
        sample.save()

    tax_parse_result.normalise()

    tax: TaxonomyAbundanceParserResult
    taxes = []
    for tax in tax_parse_result.taxonomy_abundances:
        if tax.abundance == 0:
            continue
        tax = tax.to_model()
        tax_int = tax.to_int_model()
        tax.sample = sample
        taxes.append(tax)
        if len(taxes) > 5_000:
            log.debug(f"spremam  5 000 njih prvo")
            TaxonomyAbundance.objects.bulk_create(taxes)
            taxes.clear()

    log.debug(f"spremam u bazu  ostatak od {len(taxes)} redova za sample {sample.name}, bilo ih je {len(tax_parse_result.taxonomy_abundances)}")
    TaxonomyAbundance.objects.bulk_create(taxes)
    log.debug(f"gotovo")

    messages.append(f"Add {len(taxes)} taxonomy-abundances into db")
    return messages

# @permission_required("dsf")
# @login_required
# def projects(request):
#     my_projects = Project.objects.filter(user_admins=request.user)
#     return render(request, 'projects.html', {"projects": my_projects})

# def projects_new(request):
#     if request.method == 'POST':
#         form = CreateProjectForm(request.POST)
#
#         if form.is_valid():
#             new_project: Project = form.save(False)
#             new_project.user_creator = request.user
#
#             new_project.save()
#             new_project.user_admins.add(request.user)
#             new_project.save()
#             print(form.cleaned_data)
#
#             messages.add_message(request, messages.INFO, f"Successfully added project '{new_project.name}'.")
#             return HttpResponseRedirect(reverse('projects'))
#     else:
#         id = request.GET.get('id')
#         if id is not None:
#             project = get_object_or_404(Project, pk=id)

#             # if project.user_admins. != request.user:
#             #     return HttpResponseForbidden()
#             form = CreateProjectForm(instance=project)
#             print(project)
#         else:
#             form = CreateProjectForm()
#
#     return render(request, 'projects_new.html', {'form': form})

class ProjectViewMixin(UserPassesTestMixin):
    def test_func(self):
        pass

# class CheckUserIsProjectAdmin(LoginRequiredMixin):
#
#
# class UserPassesTestMixin(LoginRequiredMixin):
#     """Verify that the current user is authenticated."""
#
#
#
#     def get_project(self):
#
#     def dispatch(self, request, *args, **kwargs):
#         return super().dispatch(request, *args, **kwargs)

# LoginRequiredMixin,
class ProjectListView(UserPassesTestMixin, ListView):
    model = Project

    def get_queryset(self):
        u: CustomUser = self.request.user
        return Project.objects.filter(member=u)

    def test_func(self, **kwargs):
        return True

class ProjectCreateView(CreateView):
    # Ko si moze raditi projekt? ????
    model = Project
    form_class = ProjectForm

    def form_valid(self, form):
        project: Project = form.instance
        user: CustomUser = self.request.user
        project.created_by = user
        form.save()
        Membership.objects.create(project=project, user=user, role=UserRole.ADMIN.value)
        return super().form_valid(form)

class ProjectDetailView(DetailView):
    model = Project

    def get_object(self, queryset=None):
        project: Project = super(ProjectDetailView, self).get_object(queryset)
        if not Membership.is_user_project_member(project, self.request.user):
            raise Http404("dont have permission")

        return project

class ProjectUpdateView(UpdateView):
    model = Project
    form_class = ProjectForm

    def get_object(self, queryset=None):
        p = super(ProjectUpdateView, self).get_object(queryset)
        if not Membership.is_user_project_admin(p, self.request.user):
            raise Http404(Message.dont_have_permission)
        return p

class SampleListView(ListView):
    model = Sample

    def get_queryset(self):
        u: CustomUser = self.request.user
        membership = Membership.objects.filter(user=u)
        project_ids = []
        m: Membership
        for m in membership:
            project_ids.append(m.project.id)

        print("Nasao project ids ", project_ids)
        return Sample.objects.filter(project__in=project_ids)

class SampleCreateView(CreateView):
    model = Sample
    form_class = SampleForm

    def get_object(self, queryset=None):
        super()

class SampleDetailView(DetailView):
    model = Sample

class SampleUpdateView(UpdateView):
    model = Sample
    form_class = SampleForm

class SampleFilesListView(ListView):
    model = SampleFiles
    paginate_by = 10

    def get_queryset(self):
        q = super(SampleFilesListView, self).get_queryset()
        q = q.prefetch_related('sample', 'sample__project')
        return q

class SampleFilesCreateView(CreateView):
    model = SampleFiles
    form_class = SampleFilesForm

class SampleFilesDetailView(DetailView):
    model = SampleFiles

class SampleFilesUpdateView(UpdateView):
    model = SampleFiles
    form_class = SampleFilesForm


import logging
from abc import ABC

import tensorflow as tf

from detectors.AbstractDetector import AbstractDetector
from utils.setup_logger import logger
from utils.tensorflow import label_map_util
from utils.util import *

# Create class logger
logger = logging.getLogger('TensorFlowDetector')

class TensorFlowDetector(AbstractDetector, ABC):
    def __init__(self):
        logger.info('Initializing')

        # Load config
        self.config = load_config()['object_detection']
        self.config_tf = self.config['tensorflow']

        # Create empty attribute fields
        self.sess = None
        self.image_tensor = None
        self.detection_boxes = None
        self.detection_scores = None
        self.detection_classes = None
        self.num_detections = None

        # Load label map for visualisation
        self.category_index = self.load_label_map()

    def load_label_map(self):
        """ Load the label map.
        :return: TensorFlow specific label map
        """

        logger.info('Loading label map')

        label_map = label_map_util.load_labelmap(self.config_tf['label_map'])
        categories = label_map_util.convert_label_map_to_categories(label_map,
                                                                    max_num_classes=self.config_tf['max_class_id'],
                                                                    use_display_name=True)
        return label_map_util.create_category_index(categories)

    def load_model(self):
        """ Load the TensorFlow model into memory and get tensor names
        """
        logger.info('Loading model')

        # Set gpu device for process
        os.environ["CUDA_VISIBLE_DEVICES"] = str(self.config['gpu_id'])

        # with tf.device('/gpu:{}'.format(self.config['gpu_id'])):
        detection_graph = tf.Graph()

        with detection_graph.as_default():
            od_graph_def = tf.GraphDef()

            with tf.gfile.GFile(self.config_tf['graph_path'], 'rb') as fid:
                serialized_graph = fid.read()
                od_graph_def.ParseFromString(serialized_graph)
                tf.import_graph_def(od_graph_def, name='')

            # Save session for later access
            self.sess = tf.Session(graph=detection_graph)

        # Input tensor is the image
        self.image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')

        # Output tensors are the detection boxes, scores, and classes
        # Each box represents a part of the image where a particular object was detected
        self.detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')

        # Each score represents level of confidence for each of the objects.
        # The score is shown on the result image, together with the class label.
        self.detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
        self.detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')

        # Number of objects detected
        self.num_detections = detection_graph.get_tensor_by_name('num_detections:0')

        logger.info('Model loaded')

    def detect(self, frames):
        """ Runs the detection for one or more frames with the loaded model.

        :param frames: loaded and preprocessed frames
        :return: (boxes, scores, classes, num)
        """

        # Perform the actual detection by running the model with the frame as input
        return self.sess.run(
            [self.detection_boxes, self.detection_scores, self.detection_classes, self.num_detections],
            feed_dict={self.image_tensor: frames})

    def visualize(self, frames, detections):
        """ Visualize detections in frames
        """
        # TODO create
        pass

    def process_detections(self, results, append_all_detections_dict, append_per_class_dict):
        ((boxes, scores, classes, num), video_meta) = results

        # Get detections above threshold
        detections = np.where(scores >= self.config_tf['thresh'])

        # Iterate through detections in frames
        for frame_i in np.unique(detections[0]).tolist():
            # Count objects in scene
            objects_in_scene_count = np.where(detections[0] == frame_i)[0].size

            # Create empty placeholder
            timestamp = 0
            class_id = []
            score = []
            bbox = []

            # Iterate objects in scene
            for object_i in range(objects_in_scene_count):
                # Get object information
                timestamp = video_meta['timestamps'][detections[0][object_i]]
                class_id.append(int(classes[detections][object_i]))
                score.append(scores[detections][object_i])

                # Transform relative to absolute values
                ymin, xmin, ymax, xmax = boxes[detections][object_i].tolist()
                bbox.append({
                    'ymin': ymin * video_meta['im_height'],
                    'xmin': xmin * video_meta['im_width'],
                    'ymax': ymax * video_meta['im_height'],
                    'xmax': xmax * video_meta['im_width']
                })

                # Append to all_detections dict
                append_all_detections_dict(video_meta['filename'], timestamp, class_id[object_i], score[object_i],
                                           bbox[object_i], object_i + 1, objects_in_scene_count)

            # Append to per_class_detections dict
            append_per_class_dict(video_meta['filename'], timestamp, class_id, score)


#!/usr/bin/env python
import rospy
from tf2_msgs.msg import TFMessage
import tf
from tf.transformations import euler_from_quaternion
from std_msgs.msg import String
from geometry_msgs.msg import PoseStamped

import numpy as np  # For random numbers
import tf
import time
import math
import geometry_msgs.msg

class Transformation:

	def __init__(self):
		self.pose = None
		self.code = ''
		self.d = []
		self.sec = []
		self.number_qr = None
		rospy.Subscriber('visp_auto_tracker/code_message', String, self._code_cal)
		rospy.Subscriber('visp_auto_tracker/object_position', PoseStamped, self._obj_cal)
		self.br = tf.TransformBroadcaster()
		self.listener = tf.TransformListener()  # to get translation & rotations between the frames
		self.pr = tf.TransformBroadcaster()  # to publish new frames
		self.trs = {}  # dictionary for storing all info from the qr

# Create callback. This is what happens when a new message is received
	def _obj_cal(self, msg):
		self.pose = msg.pose

	def _code_cal(self, msg):
	# import pdb; pdb.set_trace()
		self.code = msg.data  # to get output from the qr code
		if self.code is not '':  # split the output & use it afterwards
			fir = self.code.split("\r\n")
			self.sec = []
			for i, e in enumerate(fir):
				self.sec.append(e.split("="))
			self.number_qr = self.sec[-2][1]

	def get_qr_code(self):
		if self.code is not '':
			now = rospy.Time.now()
			self.br.sendTransform([self.pose.position.x, self.pose.position.y, self.pose.position.z],
									[self.pose.orientation.x, self.pose.orientation.y, self.pose.orientation.z,
									self.pose.orientation.w],
									now,
									"qr_frame",
									"camera_optical_link")
			#rospy.sleep(3.)
			self.listener.waitForTransform("/map", "/qr_frame", now, rospy.Duration(4.0))
			try:
				# http://wiki.ros.org/tf/Tutorials/tf%20and%20Time%20%28Python%29
				self.listener.waitForTransform("/map", "/qr_frame", now, rospy.Duration(4.0))
				(trans1, rot1) = self.listener.lookupTransform('/map', '/qr_frame', now)
			except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException) as e:
				print(e)

			# Use qr_code to map frame translations
			self.pr.sendTransform(trans1,
									[0.0, 0.0, 0.0, 1.0],
									now,
									"tr_frame",
									"map")
			qr_name = 'qr_%d' % float(self.number_qr)

			if qr_name not in self.trs:
				self.trs[qr_name] = [trans1, float(self.sec[0][1]), float(self.sec[1][1]), float(self.sec[2][1]),
									 float(self.sec[3][1]),
									 float(self.sec[4][1]), self.sec[5][1]]
				self.d.append(qr_name)
			return now

	def get_hidden_frame(self, timestamp):

		if len(self.trs) == 2:  # if you detect two qr codes
			# name = trs.keys() #list of keys for the dictionary
			qr1_coords_world = self.trs[self.d[0]][0]
			qr2_coords_world = self.trs[self.d[1]][0]
			qr1_coords_qr = self.trs[self.d[0]][1:3]
			qr2_coords_qr = self.trs[self.d[1]][1:3]

			world_x = qr2_coords_world[0] - qr1_coords_world[0]  # create vector
			world_y = qr2_coords_world[1] - qr1_coords_world[1]
			distance_w = math.sqrt(world_x ** 2 + world_y ** 2)  # Modulus
			theta_w = math.acos(world_y / distance_w)  # Angle of rotation
		if world_x < 0.0: theta_w = 2 * math.pi - theta_w

		qr_x = qr2_coords_qr[0] - qr1_coords_qr[0]
		qr_y = qr2_coords_qr[1] - qr1_coords_qr[1]
		distance_qr = math.sqrt(qr_x ** 2 + qr_y ** 2)  # Modulus
		theta_qr = math.acos(qr_y / distance_qr)  # Angle of rotation
		if qr_x < 0.0: theta_qr = 2 * math.pi - theta_qr

		final_theta = theta_qr - theta_w  # rotation between qr codes frame and map frame
		print("Angle between hidden and map frame:", final_theta)

		now = timestamp
		# to get zero rotation wrt qr codes frame
		self.pr.sendTransform([0.0, 0.0, 0.0], tf.transformations.quaternion_from_euler(0.0, 0.0, final_theta),
							now,
							"rr_frame",
							"tr_frame")
		#now = rospy.Time.now()
		# translate to qr codes frame, Bingo
		self.pr.sendTransform([-qr2_coords_qr[0], -qr2_coords_qr[1], 0.0],
							tf.transformations.quaternion_from_euler(0.0, 0.0, 0.0),
							now,
							"qr_pre_frame",
							"rr_frame")

		# now you need to save wrt something static, because it vanishes after you move
		self.listener.waitForTransform("/map", "/qr_pre_frame", timestamp, rospy.Duration(4.))
		success = False
		try:
			#now = rospy.Time.now()
			self.listener.waitForTransform('/map', 'qr_pre_frame', now, rospy.Duration(4.0))
			(trans2, rot2) = self.listener.lookupTransform('/map', '/qr_pre_frame', now)
			success = True
		except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException) as e:
			print(e)

		final_now = rospy.Time.now()
		self.pr.sendTransform(trans2, rot2,
								final_now,
								"qr_coordinate_frame",
								"map")
		return final_now


'''
「検査陽性者の状況」画像から注記を抽出する処理 パターン２
'''

import re
import pytesseract
import cv2
import numpy as np

# 画像内の矩形を抽出
# https://stackoverflow.com/a/60068297
def cropTable(src):

    hei = src.shape[0]
    wid = src.shape[1]
    totalArea = wid * hei

    original = src.copy()
    gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    # Find contours, obtain bounding box, extract and save ROI
    ROI_number = 0
    cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    lst = []
    for c in cnts:
        x,y,w,h = cv2.boundingRect(c)
        cv2.rectangle(src, (x, y), (x + w, y + h), (36,255,12), 2)
        ROI = original[y:y+h, x:x+w]
        # cv2.imwrite('ROI_{}.png'.format(ROI_number), ROI)

        # 面積が最大の矩形を記憶（ただし画像全体を覆う矩形は除外）
        area = w * h
        if (totalArea * 0.9) > area:
            lst.append((ROI_number, area, x, y, w, h))

        ROI_number += 1

    # 矩形面積の降順に並び替え
    lst.sort(key=lambda x:-x[1])

    # 1番目：「クラスターの感染」、2番目：「○月～」なハズなので
    # 2番目の y+h から 1番目の y までを切りだす
    first = lst[0]
    scond = lst[1]
    top = (scond[3]+scond[5])
    bottom = first[3]

    if top >= bottom:
        print("注記位置を特定できませんでした")
        return src

    img = original[top:bottom]
    return img

# 拡大と白黒化
def grayAndResize(src):
    neiborhood24 = np.array(
        [
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
        ],
        np.uint8,
    )

    height = src.shape[0]
    width = src.shape[1]

    dilated = cv2.dilate(src, neiborhood24, iterations=1)
    diff = cv2.absdiff(dilated, src)
    contour = 255 - diff

    gray2 = cv2.resize(contour, (int(width * 2), int(height * 2)))
    th, img = cv2.threshold(gray2, 180, 255, cv2.THRESH_BINARY)
    return img

def recognize(jpg_path):
    src = cv2.imread(str(jpg_path))
    hei = src.shape[0]
    wid = src.shape[1]

    # 画像の上25%～60%でカット
    img = src[int(hei * 0.25):int(hei * 0.6)]
    # cv2.imwrite('remarks_ptn2_1_cropped.jpg', img)

    # 画像内の矩形を抽出
    img = cropTable(img)
    # cv2.imwrite('remarks_ptn2_2_rected.jpg', img)

    # 拡大と白黒化
    img = grayAndResize(img)
    # cv2.imwrite('remarks_ptn2_3_resized.jpg', img)

    # 範囲指定
    # ref http://blog.machine-powers.net/2018/08/02/learning-tesseract-command-utility/
    txt = pytesseract.image_to_string(img, lang="jpn", config="--psm 11").replace(".", "").replace(",", "")
    print(txt)

    # ※1 ※2 または (注) で始まる文を抽出
    remarks = re.findall("^(.*?\d{1} .*|\(.?.* .*)$", txt, re.M)

    def normalize(txt):
        # 行頭の ※1 ※2 や (注) を削除（空白以降を抽出）
        txt = txt[txt.find(' ') + 1:]
        # 空白を除去
        txt = txt.replace(' ', '')
        # 画像切れて認識できない「掲載。」を補完
        txt = re.sub('検査を行ったものについて掲.*$', '検査を行ったものについて掲載。', txt)
        return txt

    remarks = list(map(normalize, remarks))
    print(remarks)
    return remarks


from cProfile import label
from tkinter import*
from tkinter import messagebox
from tkinter.filedialog import askopenfilename
import os
# import win32com.client
from pdf2docx import Converter

class ventana(Tk):
    # Constructor
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.title("Convertidor de pdf a word")
        self.geometry("300x200")
        self.resizable(0,0)
        self.widgest()

    def salir(self):
        valor = messagebox.askquestion(title="Convertidor de pdf a word",message="¿Esta seguro que deseas salir?")
        if valor == "yes":
            self.destroy()

    def archivo(self):
        valor = askopenfilename(defaultextension=".pdf",filetypes=[("Selecciona solo archivos .pdf","*.pdf")])
        if valor:
            self.generate_word2(valor)

    def generate_word2(self,valor):
        try:
            labelFile = Label(self,text="Cargando...")
            labelFile.place(x=30,y=39)
            ruta = os.path.abspath(valor)
            ruta_final = os.path.abspath(valor[0:-4] +".docx".format())
            cv = Converter(ruta)
            cv.convert(ruta_final,start=0,end=None)
            cv.close()
            labelFile.destroy()
            messagebox.showinfo(title="Convertidor de pdf a word",message='El archivo se genero correctamente en la siguiente ruta: '+ruta_final)
        except Exception as e :
            messagebox.showerror(title="Convertidor de pdf a word",message=str(e))

    # def generate_word(self,valor):
    #     try:
    #         word = win32com.client.Dispatch("word.Application")
    #         word.visible = 0
    #         ruta = os.path.abspath(valor)
    #         wb=word.Documents.Open(ruta)
    #         ruta_final = os.path.abspath(valor[0:-4] +"docx".format())
    #         wb.SaveAs2(ruta_final,FileFormat=16)
    #         wb.Close()
    #         word.Quit()
    #         # labelFile.destroy()
    #         messagebox.showinfo(title="Convertidor de pdf a word",message='El archivo se genero correctamente en la siguiente ruta: '+ruta_final)
    #     except Exception as e :
    #         messagebox.showerror(title="Convertidor de pdf a word",message=str(e))

    def widgest(self):
        labelFile=Label(self,text="Selecciona el pdf que deseas convertir.")
        labelFile.place(x=30,y=15)
        # Botones
        btnquitar=Button(self, text="Seleccionar Archivo", command=self.archivo, width=35)
        btnquitar.place(x=30, y=90)

        btnquitar=Button(self,text="Salir", command=self.salir, width=35)
        btnquitar.place(x=30, y=130)

if __name__ == "__main__":
    app=ventana()
    app.mainloop()


# 9-13 Practice
from collections import OrderedDict

word_dict = OrderedDict()
word_dict['if'] = "如果"
word_dict['else'] = "其他情况"
word_dict['for'] = "有限循环"
word_dict['while'] = "无限循环"
word_dict['raise'] = "抛出异常"
word_dict['try'] = "捕获异常"
word_dict['catch'] = "处理异常"
word_dict['finally'] = "捕获异常之后"
word_dict['def'] = "函数"
word_dict['break'] = "停止"
for k, v in word_dict.items():
    print(k + ": " + v)

# 9-14 Practice
from random import randint

class Die():

    def __init__(self, sides=6):
        self.sides = sides

    def roll_die(self):
        return randint(1, self.sides)

six_sides = Die(6)
ten_sides = Die(10)
twenty_sides = Die(20)

for side in range(0, 10):
    print("第" + str(side + 1) + "次： " + str(six_sides.roll_die()))

for side in range(0, 10):
    print("第" + str(side + 1) + "次： " + str(ten_sides.roll_die()))

for side in range(0, 10):
    print("第" + str(side + 1) + "次： " + str(twenty_sides.roll_die()))

# 9-15 Practice
# Python module of the week


#!/usr/bin/env python
"""Setup script for installing sofia."""

from setuptools import setup

config = {
    'name': 'sofia',
    'version': '0.0.1',
    'description': 'GUI',
    'author': 'Danna Xue',
    'author email': 'dannaxue@stanford.edu',
    'url': 'https://github.com/dannaxue/sofia.git',
    'download_url': 'https://github.com/dannaxue/sofia',
    'license': 'MIT',
    'packages': ['sofia'],
    'scripts': ['bin/sofia']
}

setup(**config)


import asyncio
from datetime import datetime

from aiogram import types
from aiogram.utils.markdown import code

from init import bot, config, dp
from utils import try_sending_message
from verify import *
from verify import Status

# init

async def on_startup(app) -> None:
    """Simple hook for aiohttp application which manages webhook"""
    await bot.delete_webhook()
    await bot.set_webhook(config["webhook_url"])

async def start_worker() -> None:
    await bot.delete_webhook()
    await dp.start_polling()

# handlers

@dp.callback_query_handler()
async def pressed_verification_button(cb: types.CallbackQuery) -> None:
    user_id = cb.from_user.id
    chat_id = cb.message.chat.id
    key = cb.data

    if not Verify.can_verify(chat_id, user_id):
        return

    if key == config["key"]:
        await Verify.authorize(chat=cb.message.chat, user_id=user_id)
        text = f"Welcome {code(cb.from_user.full_name)}, have a lot of fun!"
        await try_sending_message(bot, chat_id=chat_id, text=text, parse_mode="Markdown")

    elif Verify.has_last_chance(chat_id, user_id):
        text = "Incorrect answer. Make sure to get it right next time or you will be banned *permanently*."
        response_msg = await try_sending_message(bot,
            chat_id=chat_id, text=text, parse_mode="Markdown"
        )
        Verify.chats[chat_id].users[user_id].pending_messages_ids.append(
            response_msg.message_id
        )
    else:
        await Verify.reject(bot, cb.message.chat, user_id)

@dp.message_handler(content_types=types.ContentTypes.NEW_CHAT_MEMBERS)
async def just_joined(message: types.Message) -> None:
    user_id: int = message.from_user.id
    user_name: str = message.from_user.username or message.from_user.full_name
    chat = message.chat

    if not Verify.can_request_verification(chat.id, user_id):
        return

    values = [getattr(u, "_values") for u in message.new_chat_members]
    uids = [u["id"] for u in values if not u["is_bot"]]

    if not uids:
        return

    response_msg = await try_sending_message(
        bot,
        chat_id=chat.id,
        text=f"Hi [@{user_name}](tg://user?id={str(user_id)})! Please answer the question below within the next (*{config['delay']} seconds*). Which emoji below represents an animal often associated with openSUSE?",
        parse_mode="Markdown",
        reply_markup=create_verification_keyboard(),
    )

    for task in asyncio.as_completed([Verify.restrict(chat, _id) for _id in uids]):
        uid = await task
        if not chat.id in Verify.chats:
            Verify.chats[chat.id] = Chat(chat.id)
        Verify.chats[chat.id].users[uid] = User(
            pending_messages_ids=[response_msg.message_id],
            joined_at=datetime.now(),
            attempts=0,
            status=Status.challenged_to_verify,
        )
        Verify.schedule_reject(bot, chat, uid)

@dp.message_handler(content_types=types.ContentTypes.ANY)
async def handle_otherwise(_any) -> None:
    print(f"Silently handled: {_any}")

if __name__ == "__main__":
    from sys import argv

    import uvloop

    loop = uvloop.new_event_loop()
    asyncio.set_event_loop(loop)

    if len(argv) >= 2 and "--webhook" in argv:
        print(
            f"Called with {argv}, running as aiohttp server after setting webhook."
        )
        from aiogram.utils import executor

        executor.start_webhook(
            dispatcher=dp,
            webhook_path=config['webhook_path'],
            skip_updates=True,
            on_startup=on_startup,
            host=config["app_host"],
            port=config["app_port"],
        )
    else:
        print(f"Called with {argv}, running as long-polling worker.")
        asyncio.run(start_worker())