#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed May 10 17:17:40 2023

@author: johnmorgan
"""

def min_minutes_to_rot(grid):
    minutes = 0
    good = 0
    rotten = []
    for ri, row in enumerate(grid):
        for ci, col in enumerate(row):
            if grid[ri][ci] == 2:
                rotten.append([ri, ci])
            elif grid[ri][ci] == 1:
                good += 1
    newly_rotten = []
    for elem in rotten:
        newly_rotten.append(elem)
    while newly_rotten and good > 0:
        last_rotten = newly_rotten
        newly_rotten = []
        while last_rotten:
            curr = last_rotten.pop(0)
            row, col = curr[0], curr[1]
            if row > 0 and grid[row - 1][col] == 1:
                grid[row - 1][col] = 2
                newly_rotten.append([row - 1, col])
                good -= 1
            if row < len(grid) - 1 and grid[row + 1][col] == 1:
                grid[row + 1][col] = 2
                newly_rotten.append([row + 1, col])
                good -= 1
            if col > 0 and grid[row][col - 1] == 1:
                grid[row][col - 1] = 2
                newly_rotten.append([row, col - 1])
                good -= 1
            if col < len(grid[0]) - 1 and grid[row][col + 1] == 1:
                grid[row][col + 1] = 2
                newly_rotten.append([row, col + 1])
                good -= 1
        minutes += 1
    if good > 0:
        return -1
    return minutes

grid = [[2,1,1],[1,1,0],[0,1,1]]
print(min_minutes_to_rot(grid))

def min_minutes_to_rot(grid):
    rotten = []
    good = 0
    for row_index, row in enumerate(grid):
        for col_index, val in enumerate(row):
            if val == 2:
                rotten += [[row_index, col_index]]
            elif val == 1:
                good += 1
    minutes = 0
    while rotten and good > 0:
        newly_rotten = []
        for bad in rotten:
            if bad[0] > 0:
                if grid[bad[0] - 1][bad[1]] == 1:
                    grid[bad[0] - 1][bad[1]] = 2
                    newly_rotten.append([bad[0] - 1, bad[1]])
                    good -= 1
            if bad[0] < len(grid) - 1:
                if grid[bad[0] + 1][bad[1]] == 1:
                    grid[bad[0] + 1][bad[1]] = 2
                    newly_rotten.append([bad[0] + 1, bad[1]])
                    good -= 1
            if bad[1] > 0:
                if grid[bad[0]][bad[1] - 1] == 1:
                    grid[bad[0]][bad[1] - 1] = 2
                    newly_rotten.append([bad[0], bad[1] - 1])
                    good -= 1
            if bad[1] < len(grid[0]) - 1:
                if grid[bad[0]][bad[1] + 1] == 1:
                    grid[bad[0]][bad[1] + 1] = 2
                    newly_rotten.append([bad[0], bad[1] + 1])
                    good -= 1
        rotten = newly_rotten
        minutes += 1
    if good == 0:
        return minutes
    return -1


from flask import Flask, request, jsonify
from model import *

app = Flask("Test server")

width = 30
height = 30
num_agents = 0
num_boxes = 0
storageModel = None
currentStep = 0

def sortAgents():
    organizingAgents = []
    boxAgents = []
    for a, x, y in storageModel.grid.coord_iter():
        for agent in a:
            if isinstance(agent, OrganizingAgent):
                organizingAgents.append(agent)
            elif isinstance(agent, BoxAgent):
                boxAgents.append(agent)

    organizingAgents.sort(key=lambda x: x.unique_id)
    boxAgents.sort(key=lambda x: x.unique_id)

    return organizingAgents, boxAgents

@app.route("/")
def default():
    print("Request Recieved")
    return "Hello there!"

@app.route("/config", methods=['POST'])
def configure():
    global num_agents, num_boxes, width, height, storageModel, currentStep
    num_agents = int(request.form.get("numAgents"))
    num_boxes = int(request.form.get("numBoxes"))
    width = int(request.form.get("width"))
    height = int(request.form.get("height"))
    currentStep = 0
    print(
        f"Recieved num_agents = {num_agents}, num_boxes = {num_boxes}, width = {width}, height = {height}")
    storageModel = StorageModel(num_agents, num_boxes, width, height)

    return jsonify({"OK": num_agents})

@app.route("/getOrganizing", methods=['GET'])
def getAgents():
    global storageModel
    organizingAgents, boxAgents = sortAgents()
    agentPositions = [{"x": a.pos[0], "y": 0.5, "z": a.pos[1]}
                      for (a) in organizingAgents]

    return jsonify({'positions': agentPositions})

@app.route("/getBoxes", methods=['GET'])
def getBoxes():
    global storageModel
    organizingAgents, boxAgents = sortAgents()
    agentPositions = [{"x": a.pos[0], "y": 0.5, "z": a.pos[1]}
                      for (a) in boxAgents]

    return jsonify({'positions': agentPositions})

@app.route('/update', methods=['GET'])
def updateModel():
    global currentStep, storageModel
    storageModel.step()
    currentStep += 1
    return jsonify({'message': f'Model updated to step {currentStep}.', 'currentStep': currentStep})

app.run()


# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
  def buildTree(self, inorder, postorder):
    """
    :type inorder: List[int]
    :type postorder: List[int]
    :rtype: TreeNode
    """
    if inorder and postorder:
      postorder.reverse()
      self.index = 0
      d = {}
      for i in range(0, len(inorder)):
        d[inorder[i]] = i
      return self.dfs(inorder, postorder, 0, len(postorder) - 1, d)

  def dfs(self, inorder, postorder, start, end, d):
    if start <= end:
      root = TreeNode(postorder[self.index])
      mid = d[postorder[self.index]]
      self.index += 1
      root.right = self.dfs(inorder, postorder, mid + 1, end, d)
      root.left = self.dfs(inorder, postorder, start, mid - 1, d)
      return root


import turtle
import random
import time

def fot0():
    turtle.penup()
    turtle.fd(5)
def one(logic):
    fot0()
    turtle.pendown() if logic else turtle.penup()
    turtle.fd(30)
    fot0()
    turtle.right(90)
def two(digit):
    if digit == 1:
        turtle.penup()
        turtle.fd(-20)
    one(True) if digit in [2,3,4,5,6,8,9] else one(False)
    one(True) if digit in [0,1,3,4,5,6,7,8,9] else one(False)
    one(True) if digit in [0,2,3,5,6,8,9] else one(False)
    one(True) if digit in [0,2,6,8] else one(False)
    turtle.left(90)
    one(True) if digit in [0,4,5,6,8,9] else one(False)
    one(True) if digit in [0,2,3,5,6,7,8,9] else one(False)
    one(True) if digit in [0,1,2,3,4,7,8,9] else one(False)
    turtle.left(180)
    turtle.penup()
    turtle.fd(20)
def fot1():
    turtle.penup()
    turtle.fd(-10)
def fot2():
    turtle.penup()
    turtle.fd(40)
def ser(date):
    for i in date:
        turtle.pencolor(random.random(),random.random(),random.random())
        if i=='-':
            fot1()
            turtle.write('年',font=("楷体",20,"normal"))
            fot2()
        elif i=='+':
            fot1()
            turtle.write('月',font=("楷体",20,"normal"))
            fot2()
        elif i=='=':
            fot1()
            turtle.write('日',font=("楷体",20,"normal"))
        else :
            two(eval(i))
def main():
    turtle.setup(800,350,200,200)
    turtle.penup()
    turtle.fd(-250)
    turtle.pensize(5)
    ser(time.strftime('%Y-%m+%d=',time.gmtime()))
    turtle.hideturtle()
    turtle.done()
main()


#!/bin/env python3
# -*- coding: utf-8 -*-

#- needed import ----------------------------------------------------
#import $PYTHON_LIB$
import os
import sys
import time
import datetime
import signal
import subprocess
import glob
import configparser as ConfigParser
import csv
import copy
import json

#import $MOBIGEN_LIB$
import Mobigen.Common.Log_PY3 as Log; Log.Init()
import Mobigen.Utils.FileProgress_py3 as FileProgress
import socket
#from Mobigen.Utils.EFClient import EFClient
#import Mobigen.Utils.LogClient as SendLog
#import $PROJECT_LIB$

#- shutdown  ----------------------------------------------------
SHUTDOWN = False

def shutdown(signalnum, handler):
	global SHUTDOWN
	SHUTDOWN = True
	sys.stderr.write('Catch Signal: %s \n' % signalnum)
	sys.stderr.flush()

signal.signal(signal.SIGTERM, shutdown) # sigNum 15 : Terminate
signal.signal(signal.SIGINT, shutdown)  # sigNum  2 : Keyboard Interrupt
signal.signal(signal.SIGHUP, shutdown)  # sigNum  1 : Hangup detected
signal.signal(signal.SIGPIPE, shutdown) # sigNum 13 : Broken Pipe

'''
	On Windows, signal() can only be called with
	SIGABRT, SIGFPE,SIGILL, SIGINT, SIGSEGV, or SIGTERM.
	A ValueError will be raised in any other case.
'''

#- def global setting ----------------------------------------------------

def stderr(msg) :

	sys.stderr.write(msg + '\n')
	sys.stderr.flush()
	__LOG__.Trace('Std ERR : %s' % msg)

def stdout(msg) :

	sys.stdout.write(msg + '\n')
	sys.stdout.flush()
	__LOG__.Trace('Std OUT : %s' % msg)

def makedirs(path) :

	try :
		os.makedirs(path)
		__LOG__.Trace( path )
	except : pass

#- Class ----------------------------------------------------

class Standardization:

	def __init__(self, conf, debug_mode, log_arg) :

		section = 'STANDARD'
		self.debug_mode = debug_mode
		self.log_arg = log_arg

		self.center_id = conf.get('GENERAL', 'CENTER_ID')
		self.center_name = conf.get('GENERAL', 'CENTER_NAME')

		self.ref_path = conf.get(section, 'REF_PATH')
		self.ref_column_name = conf.get(section, 'REF_COLUMN_NAME')
		self.ref_code_name = conf.get(section, 'REF_CODE_NAME')
		#self.ref_hdong_name = conf.get(section, 'REF_HDONG_NAME')
		#self.ref_hbdong_name = conf.get(section, 'REF_HBDONG_NAME')
		self.ref_sep = conf.get(section, 'REF_SEP')
		self.date_column_name_list = conf.get(section, 'DATE_COLUMN_NAME').split(';')
		self.date_column_length_list = conf.get(section, 'DATE_COLUMN_LENGTH').split(';')
		if len(self.date_column_name_list) != len(self.date_column_length_list) :
			raise Exception('Please check configure [DATE_COLUMN_NAME|DATE_COLUMN_LENGTH]')
		self.json_path	= conf.get(section, 'JSON_PATH')
		self.leave_error_log = conf.getint(section, 'LEAVE_ERROR_LOG')

		try:
			self.csv_read_sep = conf.get(section, 'CSV_READ_SEP')
		except:
			self.csv_read_sep = ','

		self.colum_file_ctime = None
		self.code_file_ctime = None
		#self.hdong_file_ctime = None
		#self.hbdong_file_ctime = None

		self.get_colum_dict()
		self.get_code_dict()

		self.SendLogInit()

		self.sock = None
		self.host = socket.gethostname()
		self.port = conf.getint('GENERAL', 'LOG_PORT')

	def __del__(self):

		self.SockDisconn()

	def SockConn(self):

		if not self.sock :
			self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			self.sock.connect((self.host, self.port))

	def SockDisconn(self):

		if self.sock :
			self.sock.close()
		self.sock = None

	def SendLogInit(self) :

		self.center_name = self.center_name
		self.center_id = self.center_id
		self.start_time = ''
		self.std_in = ''
		self.in_file_size = ''
		self.in_file_row_cnt = ''
		self.result_flag = ''
		self.total_row_cnt = ''
		self.fail_reason = ''
		self.header_cnt = ''
		self.comp_row_cnt = ''
		self.error_column_length = ''
		self.error_check_notnull = ''
		self.error_check_type_legth = ''
		self.error_check_format = ''
		self.error_change_cont = ''
		self.error_value_range = ''

		self.product_cd = ''
		self.product_nm = ''
		self.dataset_cd = ''
		self.ps_duration = ''

		self.min_period = ''
		self.max_period = ''
		self.fail_type = ''

#	def dump_dict(self, dicts, path):
#
#		try:
#			with open(path, 'w') as fd:
#				json.dump(dicts, fd)
#
#			__LOG__.Trace("dump_dict : %s " % (path))
#
#		except:
#			__LOG__.Exception()
#

	def get_lastest_file(self, glob_name):

		list_of_files = glob.glob(glob_name)
		#latest_file = max(list_of_files, key=os.path.getctime)
		latest_file = max(list_of_files)
		#latest_file_ctime = os.path.getctime(latest_file)
		latest_file_ctime = os.path.basename(latest_file).rsplit('_',1)[-1].split('.')[0]
		return [ latest_file, latest_file_ctime ]

	def	get_colum_dict(self):

		file_name, file_ctime = self.get_lastest_file( os.path.join(self.ref_path, '%s*.dat' % self.ref_column_name) )
		if self.colum_file_ctime == None or file_ctime > self.colum_file_ctime:
			__LOG__.Trace("!! NEW === COLUMN REF FILE CHANGED [ %s ]" % file_name)
			self.colum_file_ctime = file_ctime

			self.dataset_dict = {}
			self.table_dict = {}
			self.colum_dict = {}
			self.table_header_dict = {}
			self.new_table_header_dict = {}
			self.column_func_dict = {}
			line_count = 0

			with open(file_name) as fd:
				for line in fd:
					line_list = line.strip().split( self.ref_sep )
					if line_count == 0 :
						header_list = line_list
						line_count += 1
					else:
						#CNTR_NM^CNTR_ID^PRD_CD^PRD_NM^PREV_TB_NM^DTST_CD^NW_TB_NM^IDX^PREV_CLMN_NM^KOR_CLMN_NM^NW_CLMN_NM^DMN_LRG_CTGRY^DMN_MDDL_CTGRY^
						#KOR_DMN_NM^TYPE_LNTH^DATA_FRMT^NOTNULL_YN^MINM_VL^MAX_VL^XCPTN_VL^CLMN_FUNC^DATA_CONT_FUNC^RMKS^CREATE_TIME^UPDATE_TIME
						if line_list[header_list.index('CNTR_ID')].upper().strip() == self.center_id.upper().strip():

							#try:
							self.dataset_dict.setdefault(line_list[header_list.index('DTST_CD')].upper().strip(), \
														[ line_list[header_list.index('PRD_CD')].upper().strip(), line_list[header_list.index('PRD_NM')].strip()] )
							self.table_dict.setdefault(line_list[header_list.index('DTST_CD')].upper().strip(), \
														[ line_list[header_list.index('PRD_CD')].upper().strip(), line_list[header_list.index('NW_TB_NM')].upper().strip() ] )

							if line_list[header_list.index('IDX')].strip() != '' :
								self.colum_dict.setdefault(line_list[header_list.index('DTST_CD')].upper().strip(), {}).setdefault( line_list[header_list.index('PREV_CLMN_NM')].upper().strip(), \
																																							[ line_list[header_list.index('TYPE_LNTH')].upper().strip(), \
																																								line_list[header_list.index('NOTNULL_YN')].upper().strip(), \
																																								line_list[header_list.index('DATA_FRMT')].strip(), \
																																								line_list[header_list.index('DATA_CONT_FUNC')].strip(), \
																																								line_list[header_list.index('MINM_VL')].strip(), \
																																								line_list[header_list.index('MAX_VL')].strip(), \
																																								line_list[header_list.index('XCPTN_VL')].strip() \
																																								])

								self.table_header_dict.setdefault(line_list[header_list.index('DTST_CD')].upper().strip(), []).append(\
																		[int(line_list[header_list.index('IDX')].strip()), line_list[header_list.index('PREV_CLMN_NM')].upper().strip()])
								self.new_table_header_dict.setdefault(line_list[header_list.index('DTST_CD')].upper().strip(), []).append(\
																		[int(line_list[header_list.index('IDX')].strip()), line_list[header_list.index('NW_CLMN_NM')].upper().strip()])
								self.column_func_dict.setdefault(line_list[header_list.index('DTST_CD')].upper().strip(), []).append(\
																		[int(line_list[header_list.index('IDX')].strip()), line_list[header_list.index('CLMN_FUNC')].strip()])

							#except:
							#	__LOG__.Exception()
							#	__LOG__.Trace(line)

			#__LOG__.Watch(self.table_dict)
			#self.dump_dict( self.table_dict, os.path.join( self.json_path, 'sd_table_dict%s.json' % self.log_arg))
			#__LOG__.Watch(self.colum_dict)
			#self.dump_dict( self.colum_dict, os.path.join( self.json_path, 'sd_colum_dict%s.json' % self.log_arg))

			for keys in self.table_header_dict:
				self.table_header_dict[keys] = [ x[1] for x in sorted(self.table_header_dict[keys], key=lambda x:x[0]) ]

			#__LOG__.Watch(self.table_header_dict)
			#self.dump_dict( self.table_header_dict, os.path.join( self.json_path, 'sd_table_header_dict%s.json' % self.log_arg))

			for keys in self.new_table_header_dict:
				self.new_table_header_dict[keys] = [ x[1] for x in sorted(self.new_table_header_dict[keys], key=lambda x:x[0]) ]

			#__LOG__.Watch(self.new_table_header_dict)
			#self.dump_dict( self.new_table_header_dict, os.path.join( self.json_path, 'sd_new_table_header_dict%s.json' % self.log_arg))

			for keys in self.column_func_dict:
				self.column_func_dict[keys] = [ x[1] for x in sorted(self.column_func_dict[keys], key=lambda x:x[0]) ]

			#__LOG__.Watch(self.column_func_dict)
			#self.dump_dict( self.column_func_dict, os.path.join( self.json_path, 'sd_column_func_dict%s.json' % self.log_arg))

	def	get_code_dict(self):

		afile_name, afile_ctime = self.get_lastest_file( os.path.join(self.ref_path, '%s*.dat' % self.ref_code_name) )

		if self.code_file_ctime == None or afile_ctime > self.code_file_ctime:

			self.code_dict = {}

			__LOG__.Trace("!!! NEW === CODE REF FILE CHANGED [ %s ]" % afile_name)
			self.code_file_ctime = afile_ctime

			line_count = 0
			with open(afile_name) as fd:
				for line in fd:
					line_list = line.strip().split( self.ref_sep )
					if line_count == 0 :
						header_list = line_list
						line_count += 1
					else:
						#CNTR_ID^CNTR_NM^CD_NM^CD_VL^CD_KOR_MNNG^CD_ENG_MNNG^CD_EXPLN^CREATE_TIME^UPDATE_TIME
						if line_list[header_list.index('CNTR_ID')].upper() == self.center_id.upper() or line_list[header_list.index('CNTR_ID')].upper() == 'CM' :
							self.code_dict.setdefault(line_list[header_list.index('CNTR_ID')].upper(), {}).setdefault(line_list[header_list.index('CD_NM')], {}).setdefault(\
																		line_list[header_list.index('CD_VL')], line_list[header_list.index('CD_KOR_MNNG')] )

			#self.dump_dict( self.code_dict, os.path.join( self.json_path, 'sd_code_dict%s.json' % self.log_arg))

	def check_type_legth( self, in_data, ty_len):

		result = False

		try:
			types, length = ty_len.split('|')

			# 글자일때
			if types.lower() == 'text':
				if len(in_data) <= int(length) : result = True

			# 정수일때
			elif types.lower() == 'integer':

				if in_data.startswith('-'):
					in_data = in_data[1:]

				if type(eval(in_data)).__name__ == 'int' and len(in_data) <= int(length) : result = True

			# 소수점 있을때
			elif types.lower() == 'real' :

				if in_data.startswith('-'):
					in_data = in_data[1:]

				tot_len, decimal_place =  length.split(',')
				if type(eval(in_data)).__name__ == 'float' and len(in_data.split('.')[0]) <= int(tot_len) - int(decimal_place) and len(in_data.split('.')[1]) <= int(decimal_place) : result = True

		#else:
		#	raise Exception('TYPES ERROR : types must in [integer/text/real] : %s' % types)

		#except SyntaxError: pass
		except : pass
		#except:
		#	__LOG__.Exception()

		#if not result : __LOG__.Watch([in_data, ty_len])

		return result

	def check_notnull( self, in_data, notnull ):

		result = False

		if notnull.lower() in ( 'not null', 'notnull', 'y', 'yes' ):
			if len(in_data) > 0 :
				result = True

		else: result = True

		return result

	def check_format( self, in_data, formats ):

		result = False

		if formats.lower() == 'yyyymm':
			try:
				datetime.datetime.strptime(in_data,'%Y%m')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower() == 'yyyymmdd':
			try:
				datetime.datetime.strptime(in_data,'%Y%m%d')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower() == 'yyyymmddhhmm':
			try:
				datetime.datetime.strptime(in_data,'%Y%m%d%H%M')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower() == 'yyyymmddhhmmss':
			try:
				datetime.datetime.strptime(in_data,'%Y%m%d%H%M%S')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower() == 'yyyymmddhhmmss.ffffff':
			try:
				datetime.datetime.strptime(in_data,'%Y%m%d%H%M%S.%f')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower() == 'hh':
			try:
				datetime.datetime.strptime(in_data,'%H')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower() == 'hhmm':
			try:
				datetime.datetime.strptime(in_data,'%H%M')
				result = True
			except: pass
			#__LOG__.Exception()

		elif formats.lower().startswith('in_'):
			key_list = formats.lower().split('in_')[1].split(',')
			if in_data.lower() not in key_list : result = False
			else: result = True

		elif formats.lower().startswith('code_'):
			key = formats.split('code_')[1]

			try:
				if in_data in self.code_dict['CM'][key].keys(): result = True

			except:
				try:
					if 'NOT CHECK' in self.code_dict[self.center_id][key].keys() : result = True
					elif in_data in self.code_dict[self.center_id][key].keys() : result = True

				except: pass
					#__LOG__.Exception()

		elif formats.lower().startswith('phone_number'):

			try:
				in_data_list = in_data.split(';')
				false_count = 0

				for one_number in in_data_list :
					phone_number_count = 0
					for letter in one_number:
						phone_number_count += 1
						if phone_number_count == 1 and letter == '+': continue
						elif type(eval(letter)).__name__ == 'int' : continue
						else: false_count += 1

				if false_count == 0 : result = True
			except: pass

		#if not result : __LOG__.Watch([in_data, formats])

		return result

	def change_data_cont( self, in_data, change_rule):

		def split_use(in_data, delimiter, use_index):
			if in_data != '' :
				return in_data.strip().split(delimiter)[use_index]
			else: return in_data

		#표준화 CM으로 치환
		def change_to_cmcode(in_data, cm_name):
			if in_data != '' :
				#self.code_dict <'dict> = {'KC': { '성별구분코드': {'1': '남성', '2': '여성'} , CM': {'성별구분코드': {'M': '남성', 'F': '여성'}}}
				in_meaning = self.code_dict[self.center_id][cm_name][in_data]
				return next(( k for k, v in self.code_dict['CM'][cm_name].items() if v == in_meaning), None)
			else: return in_data

		def codemean_to_codekey(in_data, code_name):
			if in_data != '' :
				if in_data in self.code_dict[self.center_id][code_name] : return in_data
				else: return next((k for k, v in self.code_dict[self.center_id][code_name].items() if v == in_data), None)
			else: return in_data

		#행정동코드 자리수 맞추기 = 뒤에서 부터 0 채우기(KC)
		#09시간 -> 0900시간으로 변경(KS)
		def op_zfill(in_data, length):
			if in_data == '99999999': return in_data + '9'*( length - len(in_data))
			else: return in_data + '0'*( length - len(in_data))

		def zfill(in_data, length):
			return in_data.zfill(length)

		def strstrip(in_data):
			return in_data.strip()

		def division(in_data, length):
			if in_data != '' :
				return float(in_data)/length
			else: return in_data

		def image_to_alphabet(in_data):
			if in_data == '○' : return 'N'
			elif in_data == '●' : return 'Y'
			elif in_data == '-' : return 'X'
			elif in_data == '.' : return 'E'
			else: return in_data

		def letter_change(in_data, obj, obj_true):
			#if obj == '' : obj = 'None'
			if in_data.upper() == obj.upper(): return obj_true
			else: return in_data

		#리눅스timestamp to date
		def timestamp_to_dt(in_data):
			if in_data != '' :
				return datetime.datetime.fromtimestamp(int(in_data)).strftime('%Y%m%d%H%M%S')
				#a = datetime.datetime.fromtimestamp(int(in_data)).strftime('%Y%m%d%H%M%S')
				#if not a.startswith('202006'): __LOG__.Trace("!!!ERROR!!!!!: %s %s" % (in_data, a))
				#return a
			else: return in_data

		def tran_to_decimal(in_data):

			if in_data != '' :
				try:
					if type(eval(in_data)).__name__ != 'float': return float(in_data)
					else: return in_data
				except: return None
			else: return in_data

		def float_round(in_data):
			if in_data != '' :
				if type(eval(in_data)).__name__ == 'float': return str(round(eval(in_data)))
				else : return in_data
			else: return in_data

		def time_to_time(in_format, out_format, in_data):
			if in_data != '' :
				return datetime.datetime.strptime(in_data, in_format).strftime(out_format)
			else: return in_data

		def phone_number(in_data):

			if in_data != '' :
				in_data = in_data.strip().replace('-','').replace(' ','')

				if in_data[-2] == '~' and ( int(in_data[-3]) < int(in_data[-1]) ) and int(in_data[-1]) <= 9 :

					new_number_list = []
					pre_num = in_data[:-3]
					for x in range( int(in_data[-3]), int(in_data[-1])+1 ) :
						new_number_list.append( pre_num + str(x) )

					in_data = ';'.join(new_number_list)

				elif in_data[-3] == '(' and in_data[-1] == ')' :
					pre_num = in_data[:-4]
					new_number_list = [ pre_num+in_data[-4], pre_num+in_data[-2]]
					in_data = ';'.join(new_number_list)

				in_data = in_data.replace('(','').replace(')','')
				return in_data
			else: return in_data

		try:
			return eval(change_rule)
		except:
			#__LOG__.Exception()
			#os._exit(1)
			return None

	def exception_check( self, in_data, rules):

		if in_data in [x.strip() for x in rules.split(';')]: return True
		else: return False

	def data_value_range_check( self, in_data, min_val, max_val):

		result = False
		min_len = len(in_data)
		max_len = len(in_data)
		inFlag = False

		if min_val.startswith('date_') or max_val.startswith('date_'):
			inFlag = True

			import Mobigen.Utils.CodeFormat as CodeFormat
			cf = CodeFormat.CodeFormat(self.center_id + '_DATE')
			unzipFileDict   = cf.extract_path_variable(self.fail_reason)

			def get_keyvalue(value):
				new_val = []
				for key in value.split('_')[1:]:
					new_val.append(unzipFileDict[key.upper()])
				return len(''.join(new_val)), ''.join(new_val)

			if min_val != '' :
				min_len, min_val = get_keyvalue(min_val)
			if max_val != '' :
				max_len, max_val = get_keyvalue(max_val)

		if min_val != '' and max_val != '' :
			if float(min_val) <= float(in_data[:min_len]) and float(max_val) >= float(in_data[:max_len]): result = True
		elif min_val != '' :
			if float(min_val) <= float(in_data[:min_len]) : result = True
		elif max_val != '' :
			if float(max_val) >= float(in_data[:max_len]) : result = True

		return result, min_val, max_val, inFlag

	def processing(self, in_file) :

		__LOG__.Trace( ' === processing ===' )
		__LOG__.Watch( in_file )

		### input 과 output file 명, etc 에 대하여
		out_data_dict = {}
		#/home/ds_center/DATA/DATA_COMP/KCB_T003_DEMO_RES3_202008.CSV/LineSplit/T003_DEMO_RES3:KCB_T003_DEMO_RES3_202008.CSV_19_20_1945746
		dataset_code, rest_file_name = os.path.basename(in_file).split(':')
		self.dataset_cd = dataset_code = dataset_code.upper()

		self.fail_reason = rest_file_name.rsplit('_',3)[0]

		try:
			save_base_name = '-'.join( self.table_dict[dataset_code] )
		except KeyError:
			#__LOG__.Exception()
			__LOG__.Trace("FA!!! 데이터셋 미등록: [%s] %s" % (dataset_code, in_file))

			self.result_flag 			= 'FA'
			self.fail_type				= '데이터셋 미등록'

			os.remove(in_file)
			__LOG__.Trace('데이터셋 미등록 파일 삭제 : %s' % in_file)
			return

		#rest_file_name.rsplit('_',3)[-3] = split file index
		#rest_file_name.rsplit('_',3)[-2] = split file 총 갯수
		#rest_file_name.rsplit('_',3)[-1] = 원본 총 row수

		### input 컬럼 명세
		try:
			header_list = self.table_header_dict[dataset_code]
			__LOG__.Watch( [dataset_code , len(header_list), header_list ])
		except KeyError:
			__LOG__.Trace("FA!!! 표준화정보 미등록: [%s] %s" % (dataset_code, in_file))

			self.result_flag			= 'FA'
			self.fail_type			  	= '표준화정보 미등록'

			os.remove(in_file)
			__LOG__.Trace('표준화정보 미등록 파일 삭제 : %s' % in_file)
			return

		file_num = rest_file_name.rsplit('_',3)[-3]
		split_cnt = rest_file_name.rsplit('_',3)[-2]
		row_cnt = rest_file_name.rsplit('_',3)[-1]

		#- csv 파일 이 LineSplit 을 탔니 안탔니에 따라 달라지는 디렉토리 depth 를 output 통일로 맞추기
		if not file_num.isdigit() or not split_cnt.isdigit() or not row_cnt.isdigit():
			#/home/ds_center/DATA/DATA_COMP/KCB_T003_DEMO_RES3_202008.CSV/T003_DEMO_RES3:KCB_T003_DEMO_RES3_202008.CSV
			save_path = os.path.join(os.path.dirname(in_file), 'Standardization')
			rest_name = '.csv'
			split_flag = False
			__LOG__.Trace('!!!!!!!!!!!!!!!! 여기 지나가면 안되는데 왜 지나가지? 확인 필요!!!!!!!!!!!!!!!!!!!!!!!!!!')
			### LinSplit 변경되서 이제 사용 안하는 부분이지만 일단 냅두는 것으로

		else:
			#/home/ds_center/DATA/DATA_COMP/KCB_T003_DEMO_RES3_202008.CSV/LineSplit/T003_DEMO_RES3:KCB_T003_DEMO_RES3_202008.CSV_19_20_1945746
			save_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname(in_file), os.pardir)), 'Standardization')
			rest_name = '.csv_%s_%s_%s' % (file_num, split_cnt, row_cnt)
			split_flag = True

		makedirs(save_path)

		### output 컬럼 명세, 삭제 컬럼 대상 확인

		new_header_list = copy.deepcopy( self.new_table_header_dict[dataset_code] )
		#__LOG__.Watch( [ dataset_code, len(new_header_list), new_header_list ])

		column_remove_idx = []
		#column_rename_list = []
		for i, func in enumerate(self.column_func_dict[dataset_code]):
			if func == 'column_remove()':
				column_remove_idx.append(i)
			#elif func.startswith('column_rename'):
				#column_rename_list.append([i, func])

		__LOG__.Watch(column_remove_idx)
		#__LOG__.Watch(column_rename_list)

		#def column_rename(new_name):
		#	return new_name

		#for idx, func in column_rename_list :
		#	new_header_list[idx] = eval(func)

		remove_idx_cnto = 0
		for i in column_remove_idx:
			del new_header_list[i - remove_idx_cnto]
			remove_idx_cnto += 1

		__LOG__.Watch( [ dataset_code, len(new_header_list), new_header_list ])

		### csv 파일 열어서 데이터 확인 시작
		progress = FileProgress.Progress( in_file=in_file )
		with open( in_file, newline='', encoding='utf-8') as csvread:
			#for row in csv.reader(csvread, delimiter=' ', quotechar='|')

			total_row_cnt = 0
			error_column_length = 0
			error_check_type_legth = 0
			error_check_notnull = 0
			error_check_format = 0
			error_change_cont = 0
			error_value_range = 0
			comp_row_cnt = 0
			header_cnt = 0

			### 파일의 로우별로 읽어서
			for index, row in enumerate(csv.reader(csvread, delimiter=self.csv_read_sep),1):

				total_row_cnt += 1

				###헤더확인  => file 이 쪼개져서 들어오기 때문에 여기서 하면 안되고 split 하는데서 해야함 2021.01.14 (예:포항을 생각해볼것)
				#if index == 1 and int(file_num) == 0:

				#	in_header = [x.upper() for x in row]
				#	if in_header == header_list :
				#		header_cnt += 1
				#		continue
				#	else:
				#		__LOG__.Trace("FA!!! 등록헤더 미매칭: 등록헤더%s, 들어온헤더%s " % (header_list, in_header))

				#		self.result_flag			= 'FA'
				#		self.fail_type			  = '등록헤더 미매칭'

				#		return

				## 모든 데이터 strip() 추가 2021.02.10
				row = [x.strip() for x in row]

				## 컬럼 갯수 비교
				if len(header_list) != len(row):
					out_data_dict.setdefault('error_column_length', []).append('|^|'.join(row))
					error_column_length += 1
					#if error_column_length < self.leave_error_log :
						#__LOG__.Watch(['!!!ERROR : COLUMN CNT!!!', index, len(header_list), len(row)])
					self.erSendLog(index, '컬럼갯수', '등록갯수[%s개] 들어온갯수[%s개] 데이터[%s]' % (len(header_list), len(row), row))
					continue

				#헤더가 들어가있을 경우 무시
				row_compare = [x.upper() for x in row]
				if header_list == row_compare :
					header_cnt += 1
					continue

				#if self.debug_mode: __LOG__.Watch(row)

				### 로우의 데이터별 확인
				row_comp_flag = True

				break_flag = False
				for i, in_data in enumerate(row):

					## 왜 strip() 이 안되지? 하나더 추가 2021.02.10
					in_data = in_data.strip()
					rules = self.colum_dict[dataset_code][header_list[i]]

					if rules[3] != '' :
						#DATA_CONT_FUNC 변경
						#if self.debug_mode: __LOG__.Watch([ in_data, row[i] ])

						for rule in [ x.strip() for x in rules[3].split('->') ]:

							#if in_data != '':

							c_value = str(self.change_data_cont( in_data, rule))

							if c_value == 'None':
								out_data_dict.setdefault('error_change_cont', []).append('|^|'.join(row))
								error_change_cont += 1
								row_comp_flag = False
								#if error_change_cont < self.leave_error_log :
									#__LOG__.Watch(['!!!ERROR : DATA_CONT_FUNC!!!', header_list[i], i, in_data, rule ])
								self.erSendLog(index, '데이터변형', '변형룰[%s] 컬럼명[%s] 데이터[%s]' % (rule, header_list[i], in_data) )
								break_flag = True
								break

							else:
								in_data = row[i] = c_value

						if break_flag: break

						#if self.debug_mode: __LOG__.Watch([in_data, row[i], c_value])

					# 예외데이터 기능 추가 rules[6] XCPTN_VL(;구분자), 예외일 경우 아래의 rule 무시
					if rules[6] != '' and in_data != '' and self.exception_check( in_data, rules[6]): continue

					#NOTNULL 여부에 체크
					if not self.check_notnull( in_data, rules[1] ):
						out_data_dict.setdefault('error_check_notnull', []).append('|^|'.join(row))
						error_check_notnull += 1
						row_comp_flag = False
						#if error_check_notnull < self.leave_error_log :
							#__LOG__.Watch(['!!!ERROR : NOT_NULL!!!', header_list[i], i, in_data, rules[1]])
						self.erSendLog(index, '빈값불가여부', 'NOTNULL여부[%s] 컬럼명[%s] 데이터[%s]' % (rules[1], header_list[i], in_data) )
						break

					#타입과 글자수 체크
					if not self.check_type_legth( in_data, rules[0] ) and in_data != '':
						out_data_dict.setdefault('error_check_type_legth', []).append('|^|'.join(row))
						error_check_type_legth += 1
						row_comp_flag = False
						#if error_check_type_legth < self.leave_error_log :
							#__LOG__.Watch(['!!!ERROR : TYPE AND LENGTH!!!', header_list[i], i, in_data, rules[0]])
						self.erSendLog(index, '데이터타입', '타입|길이[%s] 컬럼명[%s] 데이터[%s]' % (rules[0], header_list[i], in_data) )
						break

					if rules[2] != '' and in_data != '':
						#FORMAT 체크
						if not self.check_format( in_data, rules[2] ):
							out_data_dict.setdefault('error_check_format', []).append('|^|'.join(row))
							error_check_format += 1
							row_comp_flag = False
							#if error_check_format < self.leave_error_log :
								#__LOG__.Watch(['!!!ERROR : FORMAT!!!', header_list[i], i, in_data, rules[2]])
							self.erSendLog(index, '데이터형식', '형식[%s] 컬럼명[%s] 데이터[%s]' % (rules[2], header_list[i], in_data) )
							break

					# 데이터범위 기능추가 rules[4] MINM_VL rules[5] MAX_VL
					if (rules[4] != '' or rules[5] != '') and in_data != '':
						#__LOG__.Trace('첫번째 데이터범위 IF')
						result, min_val, max_val, inFlag = self.data_value_range_check( in_data, rules[4], rules[5])
						#if not self.data_value_range_check( in_data, rules[4], rules[5]):
						if not result:
							#__LOG__.Trace('두번째 데이터범위 IF')
							out_data_dict.setdefault('error_value_range', []).append('|^|'.join(row))
							error_value_range += 1
							row_comp_flag = False
							#if error_check_format < self.leave_error_log :

							if inFlag :
								self.erSendLog(index, '데이터값범위', '범위[%s이상-%s이하] 컬럼명[%s] 데이터[%s]' % (min_val, max_val, header_list[i], in_data) , 'IN_EXC')

							else :
								self.erSendLog(index, '데이터값범위', '범위[%s이상-%s이하] 컬럼명[%s] 데이터[%s]' % (min_val, max_val, header_list[i], in_data) )
							break

				#row의 모든 데이터가 OK 통과하면
				if row_comp_flag:

					date_key = None
					for x,y in zip(self.date_column_name_list, self.date_column_length_list):
						if x.upper() in header_list :
							#date_key = row[header_list.index(self.date_column_name)][:self.date_column_length]
							date_key = row[header_list.index(x.upper())][:int(y)]

					if date_key == None:
						for x,y in zip(self.date_column_name_list, self.date_column_length_list):
							if x.upper() == 'SDTMAKEDATE':
								date_key = datetime.datetime.now().strftime('%Y%m%d%H%M%S')[:int(y)]

					if date_key == None:
						__LOG__.Trace('!!!!!!!!!!!!!!!! 여기 지나가면 안되는데 왜 지나가지? 확인 필요!!!!!!!!!!!!!!!!!!!!!!!!!!')

					else:
						out_data_dict.setdefault(date_key, []).append('|^|'.join(row))
						comp_row_cnt += 1

				progress.getStatus(index)

				####### test 용 #######
				#if total_row_cnt == 5:
				#	break
				#	__LOG__.Watch(out_data_dict)
				#	__LOG__.Watch([total_row_cnt, error_check_type_legth, error_check_notnull, error_check_format, error_change_cont, comp_row_cnt])
				#	os._exit(1)

		__LOG__.Trace('< total_row_cnt = %s, header_cnt = %s >:[comp_row_cnt = %s, error_column_length = %s, error_check_notnull = %s, error_check_type_legth = %s, error_check_format = %s, error_change_cont = %s, error_value_range = %s]' % \
							(total_row_cnt, header_cnt, comp_row_cnt, error_column_length, error_check_notnull, error_check_type_legth, error_check_format, error_change_cont, error_value_range))

		self.total_row_cnt = total_row_cnt
		self.header_cnt = header_cnt
		self.comp_row_cnt = comp_row_cnt
		self.error_column_length = error_column_length
		self.error_check_notnull = error_check_notnull
		self.error_check_type_legth = error_check_type_legth
		self.error_check_format = error_check_format
		self.error_change_cont = error_change_cont
		self.error_value_range = error_value_range

		if total_row_cnt - header_cnt == 0 :
			__LOG__.Trace("FA!!! 빈 데이터: [%s] %s" % (dataset_code, in_file))
			self.result_flag			= 'FA'
			self.fail_type			  	= '빈 데이터'

			os.remove(in_file)
			__LOG__.Trace('빈 데이터 파일 삭제 : %s' % in_file)
			return

		#표준화 결과 분류
		error_total = self.error_column_length + self.error_check_notnull+ self.error_check_type_legth + self.error_check_format + self.error_change_cont + self.error_value_range
		if self.comp_row_cnt != 0 and error_total == 0:
			self.result_flag = 'SC'
		elif self.comp_row_cnt == 0 and error_total != 0:
			self.result_flag = 'ERR'
		else:
			self.result_flag = 'PSC'

		period_list = [int(i) for i in out_data_dict.keys() if not i.startswith('error_')]

		if len(period_list) == 0 :
			self.min_period = ''
			self.max_period = ''
		else:
			self.min_period = min(period_list)
			self.max_period = max(period_list)

		##csv file 쓰기 (삭제할 컬럼은 쓸때 정리)
		if split_flag : rest_name += '_%s' % header_cnt
		for keys in out_data_dict:

			save_file_name = os.path.join(save_path, '%s-%s%s' % (save_base_name, keys, rest_name))
			ctl_file_name = os.path.join(save_path, '%s-%s.ctl' % (save_base_name, keys))

			with open(save_file_name, mode='w') as csvwrite:

				#error
				if keys.startswith('error'):
					prefix = 'error'
					for line in out_data_dict[keys]:
						csv_writer = csv.writer(csvwrite, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
						line_list = line.split('|^|')
						csv_writer.writerow(line_list)

					with open(ctl_file_name, 'w') as erf:
						erf_writer = csv.writer(erf, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
						erf_writer.writerow(header_list)

				#표준화 완료
				else:
					prefix = 'csv'
					for line in out_data_dict[keys]:
						csv_writer = csv.writer(csvwrite, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
						line_list = line.split('|^|')

						remove_idx_cntt = 0
						for i in column_remove_idx:
							del line_list[i - remove_idx_cntt]
							remove_idx_cntt += 1

						csv_writer.writerow(line_list)

					with open(ctl_file_name, 'w') as cpf:
						cpf_writer = csv.writer(cpf, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
						cpf_writer.writerow(new_header_list)

			stdout( '%s://%s' % ('ctl', ctl_file_name) )
			stdout( '%s://%s' % (prefix, save_file_name) )

	def psSendLog(self):

		try: self.product_cd = self.dataset_dict[self.dataset_cd][0]
		except: self.product_cd = ''
		try: self.product_nm = self.dataset_dict[self.dataset_cd][1]
		except: self.product_nm = ''

		sendLogData = '|^|'.join(map(str, [   self.center_name
											, self.center_id
											, self.product_cd
											, self.product_nm
											, self.dataset_cd
											, self.min_period
											, self.max_period
											, self.start_time
											, self.ps_duration
											, self.std_in
											, self.in_file_size
											, self.in_file_row_cnt
											, self.result_flag
											, self.total_row_cnt
											, self.fail_type
											, self.fail_reason
											, self.header_cnt
											, self.comp_row_cnt
											, self.error_column_length
											, self.error_check_notnull
											, self.error_check_type_legth
											, self.error_check_format
											, self.error_change_cont
											, self.error_value_range 	]))

		sockline = "PS_LOG://%s\n" % sendLogData
		__LOG__.Trace(sockline)

		self.SockConn()
		self.sock.send(sockline.encode())

	def erSendLog(self, error_index, error_type, error_reason, preFix='ER_LOG'):

		sendLogData = '|^|'.join(map(str, [   self.center_name
											, self.center_id
											, self.dataset_dict[self.dataset_cd][0] #self.product_cd
											, self.dataset_dict[self.dataset_cd][1] #self.product_nm
											, self.dataset_cd
											, self.start_time
											, self.std_in
											, error_index
											, error_type
											, error_reason   	]))

		sockline = "%s://%s\n" % (preFix, sendLogData)
		#__LOG__.Trace(sockline)

		self.SockConn()
		self.sock.send(sockline.encode())

	def run(self):

		while not SHUTDOWN :

			std_in = None
			is_std_err = False

			try:

				self.SendLogInit()
				#csv:///home/ds_center/DATA/DATA_COMP/KCB_T003_DEMO_RES3_202008.CSV/LineSplit/T003_DEMO_RES3:KCB_T003_DEMO_RES3_202008.CSV_19_20_1945746
				std_in = sys.stdin.readline().strip()
				self.std_in = std_in

				if not std_in :
					is_std_err = True
					continue

				__LOG__.Trace('STD  IN : %s' % std_in )

				try :
					prefix, in_file = std_in.split('://', 1)
				except :
					is_std_err = True
					__LOG__.Trace( 'Input format error : %s' % std_in )
					continue

				if prefix != 'csv' :
					is_std_err = True
					__LOG__.Trace('Prefix is not match : %s' % prefix)
					continue

				if not os.path.exists( in_file )  :
					is_std_err = True
					__LOG__.Trace('Not found file : %s' % in_file)
					continue

				stime = time.time()
				self.start_time = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
				self.in_file_size = os.path.getsize(in_file)
				self.in_file_row_cnt = subprocess.getstatusoutput('/usr/bin/wc -l %s' % in_file)[-1].split()[0]

				self.get_colum_dict()
				self.get_code_dict()
				self.processing(in_file)

				etime = time.time()

				self.ps_duration = etime - stime
				__LOG__.Trace( 'Duration %s sec' % self.ps_duration )

				self.psSendLog()
				is_std_err = True

			except:
				if not SHUTDOWN : __LOG__.Exception()

			finally :
				if std_in != None and is_std_err :
					stderr( std_in )

				time.sleep(1)

#- main function ----------------------------------------------------
def main():

	module = os.path.basename(sys.argv[0])

	if len(sys.argv) < 2:
		sys.stderr.write('Usage 	: %s conf {option:[[log_arg]-d]}\n' % module )
		sys.stderr.write('Usage 	: %s conf {option:[[log_arg]-d]}\n' % module )
		#python3 /home/test/Project_name/bin/py3/BaseModule.py /home/test/Project_name/conf/BaseModule.conf
		#python3 /home/test/Project_name/bin/py3/BaseModule.py /home/test/Project_name/conf/BaseModule.conf 0
		#python3 /home/test/Project_name/bin/py3/BaseModule.py /home/test/Project_name/conf/BaseModule.conf -d
		sys.stderr.flush()
		os._exit(1)

	config_file = sys.argv[1]

	conf = ConfigParser.ConfigParser()
	conf.read(config_file)

	debug_mode = False

	log_arg = ''
	if '-d' not in sys.argv :

		etc_argv = sys.argv[2:]

		if len(sys.argv[2:]) > 0 :
			log_arg = '_' + sys.argv[2]

		log_path = conf.get('GENERAL', 'LOG_PATH')

		makedirs( log_path )

		log_file = os.path.join(log_path, '%s%s.log' % (os.path.splitext(module)[0], log_arg ))
		Log.Init(Log.CRotatingLog(log_file, 10240000, 9))

	else:
		Log.Init()
		debug_mode = True

	pid = os.getpid()
	__LOG__.Trace('============= %s START [pid:%s]==================' % ( module, pid ))

	Standardization(conf, debug_mode, log_arg).run()

	__LOG__.Trace('============= %s END [pid:%s]====================' % (module, pid ))

#- if name start ----------------------------------------------
if __name__ == "__main__" :
	main()


#
#  The Model to be loaded into the training code
#
#
import torch.nn as nn

class FashionCNN(nn.Module):
    """FashionCNN Model

    A Pytorch model to run classification on the Fashion-MNist Dataset

    """

    def __init__(self):
        """Pytorch Model Initialisation

        This consists of a simple network with 2 Convolution Layers to encode the images
        followed by three Linear layers to produce the final classification

        """
        super(FashionCNN, self).__init__()

        self.layer1 = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.layer2 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2)
        )

        self.fc1 = nn.Linear(in_features=64*6*6, out_features=600)
        self.drop = nn.Dropout2d(0.25)
        self.fc2 = nn.Linear(in_features=600, out_features=120)
        self.fc3 = nn.Linear(in_features=120, out_features=10)

    def forward(self, x):
        """Pytorch Model Forward function

        Takes a sample batch of images and feeds it through the network
        Pytorch uses N x C x H x W

        Arguments:
             x (Torch.tensor): a valid batch of images

        """

        out = self.layer1(x)
        out = self.layer2(out)
        out = out.view(out.size(0), -1)
        out = self.fc1(out)
        out = self.drop(out)
        out = self.fc2(out)
        out = self.fc3(out)

        return out


"""Video Generation with TGAN."""
import torch
import torch.nn as nn
import numpy as np
from moviepy.editor import ImageSequenceClip

class TemporalGenerator(nn.Module):
    def __init__(self):
        super().__init__()
        # Create a sequential model to turn one vector into 16
        self.model = nn.Sequential(
            nn.ConvTranspose1d(100, 512, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm1d(512),
            nn.ReLU(),
            nn.ConvTranspose1d(512, 256, kernel_size=4, stride=2, padding=1),
            nn.BatchNorm1d(256),
            nn.ReLU(),
            nn.ConvTranspose1d(256, 128, kernel_size=4, stride=2, padding=1),
            nn.BatchNorm1d(128),
            nn.ReLU(),
            nn.ConvTranspose1d(128, 128, kernel_size=4, stride=2, padding=1),
            nn.BatchNorm1d(128),
            nn.ReLU(),
            nn.ConvTranspose1d(128, 100, kernel_size=4, stride=2, padding=1),
            nn.Tanh()
        )

        # initialize weights according to paper
        self.model.apply(self.init_weights)

    def init_weights(self, m):
        if type(m) == nn.ConvTranspose1d:
            nn.init.xavier_uniform_(m.weight, gain=2 ** 0.5)

    def forward(self, x):
        # reshape x so that it can have convolutions done
        x = x.view(-1, 100, 1)
        # apply the model and flip the
        x = self.model(x).transpose(1, 2)
        return x

class VideoGenerator(nn.Module):
    def __init__(self):
        super().__init__()
        # instantiate the temporal generator
        self.temp = TemporalGenerator()

        # create a transformation for the temporal vectors
        self.fast = nn.Sequential(
            nn.Linear(100, 256 * 4 ** 2, bias=False),
            nn.BatchNorm1d(256 * 4 ** 2),
            nn.ReLU()
        )

        # create a transformation for the content vector
        self.slow = nn.Sequential(
            nn.Linear(100, 256 * 4 ** 2, bias=False),
            nn.BatchNorm1d(256 * 4 ** 2),
            nn.ReLU()
        )

        # define the image generator
        self.model = nn.Sequential(
            nn.ConvTranspose2d(512, 256, kernel_size=4, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.ConvTranspose2d(32, 3, kernel_size=3, stride=1, padding=1),
            nn.Tanh()
        )

        # initialize weights according to the paper
        self.fast.apply(self.init_weights)
        self.slow.apply(self.init_weights)
        self.model.apply(self.init_weights)

    def init_weights(self, m):
        if type(m) == nn.ConvTranspose2d or type(m) == nn.Linear:
            nn.init.uniform_(m.weight, a=-0.01, b=0.01)

    def forward(self, x):
        # pass our latent vector through the temporal generator and reshape
        z_fast = self.temp(x).contiguous()
        z_fast = z_fast.view(-1, 100)

        # transform the content and temporal vectors
        z_fast = self.fast(z_fast).view(-1, 256, 4, 4)
        z_slow = self.slow(x).view(-1, 256, 4, 4).unsqueeze(1)
        # after z_slow is transformed and expanded we can duplicate it
        z_slow = torch.cat([z_slow] * 16, dim=1).view(-1, 256, 4, 4)

        # concatenate the temporal and content vectors
        z = torch.cat([z_slow, z_fast], dim=1)

        # transform into image frames
        out = self.model(z)

        return out.view(-1, 16, 3, 64, 64).transpose(1, 2)

class VideoDiscriminator(nn.Module):
    def __init__(self):
        super().__init__()
        self.model3d = nn.Sequential(
            nn.Conv3d(3, 64, kernel_size=4, padding=1, stride=2),
            nn.LeakyReLU(0.2),
            nn.Conv3d(64, 128, kernel_size=4, padding=1, stride=2),
            nn.BatchNorm3d(128),
            nn.LeakyReLU(0.2),
            nn.Conv3d(128, 256, kernel_size=4, padding=1, stride=2),
            nn.BatchNorm3d(256),
            nn.LeakyReLU(0.2),
            nn.Conv3d(256, 512, kernel_size=4, padding=1, stride=2),
            nn.BatchNorm3d(512),
            nn.LeakyReLU(0.2)
        )

        self.conv2d = nn.Conv2d(512, 1, kernel_size=4, stride=1, padding=0)

        # initialize weights according to paper
        self.model3d.apply(self.init_weights)
        self.init_weights(self.conv2d)

    def init_weights(self, m):
        if type(m) == nn.Conv3d or type(m) == nn.Conv2d:
            nn.init.xavier_normal_(m.weight, gain=2 ** 0.5)

    def forward(self, x):
        h = self.model3d(x)
        # turn a tensor of R^NxTxCxHxW into R^NxCxHxW
        h = torch.reshape(h, (32, 512, 4, 4))
        h = self.conv2d(h)
        return h

# update discriminator
pr = dis(real)
fake = gen(torch.rand((batch_size, 100), device='cuda') * 2 - 1)
pf = dis(fake)
dis_loss = torch.mean(-pr) + torch.mean(pf)
dis_loss.backward()
disOpt.step()

# update generator
genOpt.zero_grad()
fake = gen(torch.rand((batch_size, 100), device='cuda') * 2 - 1)
pf = dis(fake)
gen_loss = torch.mean(-pf)
gen_loss.backward()
genOpt.step()

# instantiate the generator, load the weights, and create a sample
gen = VideoGenerator().cuda()
gen.load_state_dict(torch.load('state_normal81000.ckpt')['model_state_dict'][0])
genSamples(gen)


class BoardPainter:
    _width = 150
    _height = 150
    _canvas = None
    _board = None

    def __init__(self, canvas, left, top):
        self._left = left
        self._top = top
        self._canvas = canvas
        self._canvas.pack()

    def setBoard(self, board):
        self._board = board
        self._board.on_next_move = self._paint
        self._paint()

    def translateCoordinates(self, x, y):
        row = None
        col = None

        if self._left <= x and x < self._left + self._width/3:
            col = 0
        elif self._left + self._width/3 <= x and x < self._left + self._width/1.5:
            col = 1
        elif self._left + self._width/1.5 <= x and x < self._left + self._width:
            col = 2

        if self._top <= y and y < self._top + self._height / 3:
            row = 0
        elif self._top + self._height / 3 <= y and y < self._top + self._height / 1.5:
            row = 1
        elif self._top + self._height / 1.5 <= y and y < self._top + self._height:
            row = 2

        return row, col

    def _paint(self):
        self._paint_empty_board()
        for rowIndex in range(len(self._board.data)):
            for colIndex in range(len(self._board.data[rowIndex])):
                self._paint_sign(self._board.data[rowIndex][colIndex], colIndex, rowIndex)

    def _paint_empty_board(self):
        self._canvas.create_rectangle(self._left, self._top, self._left + self._width, self._top + self._height, fill="#dddddd", outline="")
        # vertical lines
        self._canvas.create_line(self._left + self._width/3, self._top, self._left + self._width/3, self._top + self._height)
        self._canvas.create_line(self._left + self._width/1.5, self._top, self._left + self._width/1.5, self._top + self._height)
        # horizontal lines
        self._canvas.create_line(self._left, self._top + self._height/3, self._left + self._width, self._top + self._height/3)
        self._canvas.create_line(self._left, self._top + self._height/1.5, self._left + self._width, self._top + self._height/1.5)

    def _paint_sign(self, sign, row, col):
        if sign == "": return
        x = row * self._width / 3 + self._width / 6 + self._left
        y = col * self._height / 3 + self._height / 6 + self._top
        x1 = x - self._width / 10
        y1 = y - self._height / 10
        x2 = x + self._width / 10
        y2 = y + self._height / 10
        if sign == "0":
            self._canvas.create_oval(x1, y1, x2, y2)
        if sign == "X":
            self._canvas.create_line(x1, y1, x2, y2)
            self._canvas.create_line(x2, y1, x1, y2)


import falcon
import ramlfications
import jsonschema

class ParameterChecker(object):
    """Check parameters with RAML."""

    def __init__(self, raml_file_path):
        """Load the RAML file."""
        self._raml = ramlfications.parse(raml_file_path)

    def process_resource(self, request, response, falcon_resource, uri_params):
        """Check parameters in the request.

        This function checks 3 parts:

        1. headers
        2. query parameters
        3. body
          a. json body
          b. form body parameters

        Note that it overrides process_resource instead of process_request
        because request.uri_template maybe None in process_request.
        Please see:
        http://falcon.readthedocs.io/en/stable/api/request_and_response.html#Request.uri_template
        """
        raml_resource = \
            self._get_raml_resource(request.method, request.uri_template)

        if raml_resource is None:
            return

        if raml_resource.headers:
            for header in raml_resource.headers:
                self._check_header(request, header)

        if raml_resource.query_params:
            for query_param in raml_resource.query_params:
                self._check_param(request, query_param)

        if raml_resource.body:
            if request.content_type is None:
                raise falcon.HTTPBadRequest('Bad request', 'No content type')
            matched = False
            for body in raml_resource.body:
                if body.mime_type != request.content_type:
                    continue
                matched = True
                if body.mime_type == 'application/json':
                    self._check_json_body(request, body.schema)
                elif body.mime_type == 'application/x-www-form-urlencoded':
                    for form_param_tuple in body.form_params.items():
                        form_param = self._make_form_param(form_param_tuple)
                        self._check_param(request, form_param)
                else:
                    # No other content type is supported yet
                    matched = False
            if not matched:
                raise falcon.HTTPBadRequest(
                    'Bad request',
                    'Unsupported content type: {}'.format(request.content_type)
                )

    def _get_raml_resource(self, method, uri_template):
        """Get the RAML resource by method and URI template.

        This is the best we can do for now:
        https://github.com/spotify/ramlfications/issues/112
        """
        for raml_resource in self._raml.resources:
            if raml_resource.method is None or raml_resource.path is None:
                continue
            if raml_resource.method.lower() != method.lower():
                continue
            if uri_template != raml_resource.path:
                continue
            return raml_resource
        return None

    def _check_header(self, request, raml_header):
        """Check if the request headers are valid.

        It checks 2 things:

        1. the existence (if required)
        2. the type (if given)

        It raises HTTPMissingHeader and HTTPInvalidHeader,
        respectively.
        """
        header = request.get_header(raml_header.display_name)

        if raml_header.required and header is None:
            raise falcon.HTTPMissingHeader(raml_header.display_name)

        if raml_header.type and header is not None:
            self.check_value_with_raml_type(
                raml_header,
                header,
                falcon.HTTPInvalidHeader
            )

    def _check_param(self, request, raml_param):
        """Check if the request parameters are valid.

        The behavior of this function is like _check_header, but
        for query parameters and body form parameters.
        """
        param = request.get_param(raml_param.name)

        if raml_param.required and param is None:
            raise falcon.HTTPMissingParam(raml_param.name)

        if raml_param.type and param is not None:
            self.check_value_with_raml_type(
                raml_param,
                param,
                falcon.HTTPInvalidParam
            )

    def _check_json_body(self, request, raml_json_body_schema):
        """Check JSON body with jsonschema.

        This function works only if falconraml.JsonTranslator
        is used in the middlewares.
        """
        if 'json' not in request.context:
            raise falcon.HTTPInternalServerError(
                'Internal server error',
                'Please use falconraml.JsonTranslator to parse json body.'
            )

        if type(raml_json_body_schema) is not dict:
            raise falcon.HTTPInternalServerError(
                'Internal server error',
                'Failed to parse jsonschema.'
            )

        request_json_body = request.context['json']

        try:
            jsonschema.validate(request_json_body, raml_json_body_schema)
        except jsonschema.exceptions.ValidationError as e:
            raise falcon.HTTPBadRequest('Bad request body', e.message)

    def check_value_with_raml_type(self, raml_spec, string, exception):
        """Check a string value with a RAML type.

        The listed types are from:
        https://github.com/raml-org/raml-spec/blob/master/versions/raml-08/raml-08.md#type
        """
        if raml_spec.type == 'string':
            # No need to check anything
            pass
        elif raml_spec.type == 'number':
            if not self._can_parse_as_python_type(float, string):
                raise exception('Should be a number.', raml_spec.name)
        elif raml_spec.type == 'integer':
            if not self._can_parse_as_python_type(int, string):
                raise exception('Should be an integer.', raml_spec.name)
        elif raml_spec.type == 'date':
            # Not supported yet
            pass
        elif raml_spec.type == 'boolean':
            if string not in ('true', 'false'):
                raise exception('Should be "true" or "false".', raml_spec.name)
        elif raml_spec.type == 'file':
            # Not supported yet
            pass

    def _can_parse_as_python_type(self, python_type, string):
        """Check if a string can be converted to a python type.

        Currently supports float and int.
        """
        try:
            python_type(string)
            return True
        except ValueError:
            return False

    def _make_form_param(self, param_tuple):
        """Make a FormParameter from a parameter tuple.

        This is a workaround for weird ramlfications parsing:
        https://github.com/spotify/ramlfications/issues/122
        """
        param_name = param_tuple[0]
        param_config = param_tuple[1]

        form_param = ramlfications.parameters.FormParameter(
            param_name,
            {},
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            {},
            [],
        )

        if 'required' in param_config:
            form_param.required = param_config['required']
        if 'type' in param_config:
            form_param.type = param_config['type']

        return form_param


#tests / conftest.py
import logging
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from app.database import Base
import sys
sys.path.append(r"C:/Users/61435/OneDrive - PHM Technology/Python/BasicApp")

SQLALCHEMY_TEST_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_TEST_DATABASE_URL)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

@pytest.fixture(scope="session")
def db():
    Base.metadata.create_all(bind=engine)
    session = TestingSessionLocal()
    yield session
    session.close()
    Base.metadata.drop_all(bind=engine)

@pytest.fixture(scope="function")
def clear_data():
    for table in reversed(Base.metadata.sorted_tables):
        engine.execute(table.delete())
    yield


from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import get_list_or_404, get_object_or_404
from rest_framework.response import Response
from rest_framework.views import APIView

from api.serializers import ProductSerializer
from shop.models import Product

class ProductView(APIView):
    def get(self, request, *args, **kwargs):
        if kwargs.get('product_pk'):
            objects = get_list_or_404(Product, shop_id=kwargs['shop_pk'], category_id=kwargs['categories_pk'], pk=kwargs['product_pk'])
        elif len(kwargs) == 0:
            objects = Product.objects.all()
        elif kwargs.get('categories_pk'):
            objects = get_list_or_404(Product, shop_id=kwargs['shop_pk'], category_id=kwargs['categories_pk'])
            paginator = Paginator(objects, 5)
            page = request.GET.get('page')
            if page:
                try:
                    objects = paginator.page(page)
                except PageNotAnInteger:
                    objects = paginator.page(1)
                except EmptyPage:
                    return Response("Такой страницы нет")
        else:
            objects = get_list_or_404(Product, shop_id=kwargs['shop_pk'])
        serializer = ProductSerializer(objects, many=True)
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
        serializer = ProductSerializer(data=request.data)
        if serializer.is_valid():
            product = serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors, status=400)

    def put(self, request, *args, **kwargs):
        objects = get_object_or_404(Product, shop_id=kwargs['shop_pk'], category_id=kwargs['categories_pk'], pk=kwargs['product_pk'])
        serializer = ProductSerializer(objects, request.data)
        if serializer.is_valid():
            product = serializer.save()
            objects.update_counter += 1
            objects.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors, status=400)


# Note: This is year-wise unlike the other webcrawlers!
import requests
from bs4 import BeautifulSoup
from pprint import pprint
import json

ses = requests.session()

def article_catch(url_list, j):
    articles = []
    for i, url in enumerate(url_list):
        Soup = BeautifulSoup(ses.get(url).text, "html.parser")
        # title = Soup.find('h1')
        article = Soup.find('article')
        title = article.find('h1', {'class': 'entry-title'})
        time_part = article.find('span', {'class': 'entry-meta-date updated'})
        fig = article.find('figure')
        content_div = article.find('div', {'class': 'entry-content clearfix'})
        content = ""
        for par in content_div.find_all('p'):
            if content != "":
                content = content + '\n' + par.text
            else:
                content = par.text
        try:
            image = fig.find('img').get('src')
        except AttributeError or TypeError:
            image = None
        dit = {
            'title': title.text,
            'time': time_part.find('a').text,
            'image': image,
            'content': content
        }
        articles.append(dit)
        with open('DailyBonnet{0}.json'.format(j), 'w+') as f:
            f.write(json.dumps(articles))

url_base = 'https://www.dailybonnet.com/2018/page'
for i in range(90):
    url2scrape = url_base + '/' + str(i+1)
    Soup = BeautifulSoup(ses.get(url2scrape).text, "html.parser")
    titl = Soup.find('title').text
    if "Daily" not in titl:
        print('page', i+1)
        break
    url_list = []
    for article in Soup.find_all('article'):
        head = article.find('h3', {'class': 'entry-title mh-posts-list-title'})
        url_list.append(head.find('a').get('href'))

    pprint(url_list)
    article_catch(url_list, i)
    print(i, "Done")


from .file import *

from ..ext.ext_csv import *

CSV_SNIFF_MIN = 1024

class CSV(File):
	"""
	EXPERIMENTAL

	"""

	# READ
	def read(self, data=None, mode='r', **k):
		return CSVReader(self.open(mode, **k)).read()

	# WRITE
	def write(self, data=None, mode='w', **k):
		if 'text' in k:
			text = k.pop('text')
			File.write(self, k['text'], mode, **k)
		elif isinstance(data, basestring):
			File.write(self, data, mode, **k)
		else:
			w = CSVWriter(self.open(mode, **k), **k).write(data)
			w.write(data)

	# READER
	def reader(self, **k):
		"""
		Returns a reader for the file this object represents (self.path)

		Pass keyword arguments:
		 - encoding = encoding with which to decode binary to unicode
		 - errors   = optional - how to handle encoding errors
		 - mode     = optional - mode (default 'rb')

		To create with a stream, pass keyword argument:
		 - stream = A byte or text stream
		"""
		# pop all these so csv reader can have the rest of the kwargs
		mode = k.pop('mode', None)
		stream = k.pop('stream', None)

		if stream:
			return CSVReader(stream, **k)
		else:
			return CSVReader(self.open(mode or 'rb'), **k)

	# WRITER
	def writer(self, **k):
		"""
		Return a CSVWriter object pointing to this file.
		"""
		mode = k.pop('mode', None)
		stream = k.pop('stream', None)

		if stream:
			return CSVReader(stream, **k)
		else:
			return CSVReader(self.open(mode or 'wb'), **k)

class CSVReader(Reader):
	"""
	EXPERIMENTAL

	The CSVReader is very sensitive to encoding across python 2/3. It
	currently yields string results for every field - bytes in python 2
	and unicode strings for python 3.
	"""

	def __init__(self, stream, **k):
		"""
		Pass a stream that produces lines of csv data. The stream may
		produce text as bytes or unicode.

		ALWAYS PASS AN ENCODING!
		Always pass the correct encoding so that bytes may be converted
		to unicode if necessary, or so that unicode text may be converted
		to bytes if necessary.

		 * When the stream produces bytes, the encoding may be necessary
		 to if the csv.reader object requires unicode.

		 * When the stream produces unicode characters, the encoding may
		   be necessary to encode the bytes if the csv.reader object
		   requires bytes.

		Passing the encoding gives CSVReader what it needs to work in
		either python 2 or 3.
		"""

		# Extract encoding kwargs first! They MUST NOT reach the reader.
		ek = EncodingHelper(encoding='utf8').extractEncoding(k)

		# make sure we have a seekable stream
		try:
			stream.seek(0)
		except:
			# I don't want to extract to a tempfile - at least not yet -
			# so if it's a zip file (or some stream that can't seek) then
			# we need to read the whole file up front.
			buf = Buffer()
			buf.write(stream.read())
			stream = buf.reader()

		# --- at this point, stream is seekable ---

		# default sniff can be overridden with values > 1024
		try:
			sniff = k.pop('sniff')
			if sniff < CSV_SNIFF_MIN:
				sniff = CSV_SNIFF_MIN
		except:
			sniff = CSV_SNIFF_MIN

		# sniff for a Dialect object and to detect stream data type
		dialect = None
		try:
			# first assume it's a unicode stream
			stream.seek(0)
			coder = ReadCoder(stream, encode=k.get('encoding', DEF_ENCODE))
			dialect = Sniffer().sniff(coder.read(sniff))
			stream.seek(0)
			self.__csv = reader(coder, dialect, **k)
			x = self.__next__()#test
		except TypeError as eencode:
			"""
			eencode = xdata(
				stream=stream, coder=coder, dialect=dict(dialect.__dict__)
			)
			"""
			# if that fails, try it as a byte stream
			stream.seek(0)
			coder = ReadCoder(stream, decode=k.get('encoding', DEF_ENCODE))
			dialect = Sniffer().sniff(coder.read(sniff))
			stream.seek(0)
			self.__csv = reader(coder, dialect, **k)
			try:
				x=self.__next__()#test
			except Exception as ex:
				raise type(ex)('create-reader-fail', xdata(
					stream=stream, coder=coder, dialect=dialect.__dict__
				))

		# ALWAYS RESET TO ZERO
		stream.seek(0)

		#
		# replace some methods (for speed)
		#
		self.readline = self.__next__
		self.next = self.__next__

	# ITER
	def __iter__(self):
		return self.lines

	# NEXT
	def __next__(self):
		return next(self.lines)

	# LINES
	@property
	def lines(self):
		csvr = self.__csv
		for line in csvr:
			yield line

	# READ
	def read(self, *a):
		return [r for r in self]

class CSVWriter(Writer):
	"""
	EXPERIMENTAL

	Use writeline (alias to writerow) to write individual lines (rows)
	into a csv stream.

	Use write (alias to writelines) to write a list of lists to the
	stream.
	"""

	def __init__(self, stream, *a, **k):
		Writer.__init__(self, stream)
		self.__csv = Base.create('csv.writer', stream, *a, **k)
		self.writeline = self.writerow
		self.writelines = self.write

	def write(self, data):
		for row in data:
			self.__csv.writerow(data)

	def writerow(self, data):
		self.__csv.writerow(data)


import numpy as np
import matplotlib.pyplot as plt

from numpy_matrix import multivariate_normal

if __name__ == '__main__':
    mu = np.array([0.5, -0.2])
    cov = np.array([[2.0, 0.3], [0.3, 0.5]])
    xs = ys = np.arange(-5, 5, 0.1)
    # np.meshgrid()⇨格子点を作る
    X, Y = np.meshgrid(xs, ys)
    # np.zeros_like()⇨データ型を受け継ぐ
    Z = np.zeros_like(X)

    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            x = np.array([X[i, j], Y[i, j]])
            Z[i, j] = multivariate_normal(x, mu, cov)

    fig = plt.figure()
    ax1 = fig.add_subplot(1, 2, 1, projection='3d')
    ax1.set_xlabel('x')
    ax1.set_ylabel('y')
    ax1.set_zlabel('z')
    # axes.plot_surface()⇨3次元グラフ描画
    ax1.plot_surface(X, Y, Z, cmap='viridis')

    ax2 = fig.add_subplot(1, 2, 2)
    ax2.set_xlabel('x')
    ax2.set_ylabel('y')
    # axes.contour()⇨等高線グラフ描画
    ax2.contour(X, Y, Z)
    plt.show()
    plt.close()


import requests
import random
import json
import pickle

from fastapi_utils.tasks import repeat_every
from requests_oauthlib import OAuth1Session, OAuth1

from app.managers.instructions_manager import instructions_manager
from app.managers.users_manager import UserManager
from app.managers.transaction_manager import transaction_manager
from app.managers.redis_manager import redis_manager
from app.config import POLL_DURATION
from app.logger import get_logger

log = get_logger()

async def create_cross_connect(item_details):
    '''
    This function send request to the south side to order cross connect
    '''
    log.info("Sending order to equinix to create cross connect")

    # create fictitious Order ID as equinix responds NULL
    with open('db/equinix/order_status.json', 'r') as orders_list:
            order_ids = json.load(orders_list)
    while(True):
        o_id = "CC_ORDER_ID_" + str(random.randint(1000,9999))
        if o_id in order_ids.keys():
            continue
        else:
            with open('db/equinix/order_status.json', 'w') as orders_list:
                order_ids[o_id] = ""
                json.dump(order_ids, orders_list)
                log.info("Generated order ID")
                return o_id

async def ons_mark_complete(po_id, auth):
    '''
    This function updates the PO status in ONS
    '''
    BASE_URL = transaction_manager.north_details["base_url"]
    url = f"{BASE_URL}/services/rest/record/v1/purchaseOrder/{po_id}/!transform/itemReceipt"
    return requests.post(url, auth=auth)

async def update_po_status(po_id, status, user_manager):
    data = {
                "memo" : status[:-2]
            }
    BASE_URL = transaction_manager.north_details["base_url"]
    po_url = f"{BASE_URL}/services/rest/record/v1/purchaseorder/{po_id}"
    response = requests.patch(po_url, json=data, auth=user_manager.user_oauth1)
    if response.status_code == 200:
        log.info("Successfully updated status in ONS")
    else:
        log.error(f"Failed to update status in ONS. Status code: {response.status_code}")

async def process_po_item(item_details):
    if item_details['item']['refName'] == "CrossConnect":
        log.info("Found item cross connect")
        order_id = await create_cross_connect(item_details)
        return f"Order sent to Equinix. ID: {order_id}", order_id
    else:
        return "Item '" + item_details['item']['refName'] + "' Not registered with Lattice, please check with admin.", -1

async def get_ons_details(po_url, user_auth):
    '''
    This function takes ONS endpoint as input,
    makes API call to ONS and returns the response.
    '''
    log.info(f"[{transaction_manager.transaction_id}] Making API call to ONS to get details")
    response = requests.get(po_url,auth=user_auth)
    if response.status_code == 200:
        log.info(f"[{transaction_manager.transaction_id}] API call to ONS successful")
        return response.json()
    else:
        log.error(f"[{transaction_manager.transaction_id}] API call to ONS unsuccessful.")
        log.error(f"Response code: {response.status_code}, message: {response.content}")

async def add_po_to_db(user_id, po_id, item_status):
    '''
    Add PO details to redis.
    '''
    po_details = pickle.loads(redis_manager.redis.get("po_details"))
    # if user data not in redis
    if user_id not in po_details.keys():
         po_details[user_id] = {}
         po_details[user_id][po_id] = {
                                        "items" : item_status,
                                        "transaction_id" : transaction_manager.transaction_id
                                    }
    else:
        po_details[user_id][po_id] = {
                                        "items" : item_status,
                                        "transaction_id" : transaction_manager.transaction_id
                                    }
    redis_manager.redis.set("po_details", pickle.dumps(po_details))

async def execute_api(api_data):
     '''
     This function takes API data as input,
     generates the end point and body parameters and
     makes the API call.
     Return value is response from the API call.
     '''
     api_method = api_data["method"]
     url = api_data["BASE_URL"] + api_data["route"]
     if api_method == "GET":
        response = requests.get(url,auth=api_data["AUTH"])
        return response.json()

@repeat_every(seconds=POLL_DURATION)
async def Poll_PurchaseOrder():
    '''
    This function polls the purchase orders from north.
    '''
    log.info("Polling  PO")
    user_manager = UserManager("vidatt")
    north_id = transaction_manager.north_details["north_id"]

    # get api details from redis
    api_data = pickle.loads(redis_manager.redis.get("north_data"))[north_id]['api_details']['polling']['purchase_order']['get_details']
    api_data["BASE_URL"] = transaction_manager.north_details["base_url"]
    api_data["AUTH"] = user_manager.user_oauth1

    # get PO list
    po_list = await execute_api(api_data)
    log.info("Successfully fetched PO list.")
    new_po  = False

    # check if number of PO is more than 0
    if po_list['totalResults'] == 0:
        log.info("No purchase orders found in the list")
        return
    else:
        log.info("Iterating PO list")
        # process PO
        for po in po_list['items']:
            # if it is a new PO
            if int(po['id']) not in user_manager.processed_po:
                new_po = True
                log.info("Found new PO")
                await transaction_manager.new_transaction_id()
                log.info(f"Created new transaction {transaction_manager.transaction_id}")
                log.info(f"[{transaction_manager.transaction_id}] Get PO details")
                po_details = await get_ons_details(po['links'][0]['href'], user_manager.user_oauth1)
                log.info(f"[{transaction_manager.transaction_id}] Get items list")
                items_list = await get_ons_details(po_details['item']['links'][0]['href'], user_manager.user_oauth1)
                po_status = "Order Status: \n"
                item_count = 0
                items_status = {}
                # process items
                log.info(f"[{transaction_manager.transaction_id}] Iterating items list")
                for item in items_list['items']:
                    item_count += 1
                    log.info(f"[{transaction_manager.transaction_id}] Get item details")
                    item_details = await get_ons_details(item['links'][0]['href'], user_manager.user_oauth1)
                    log.info(f"[{transaction_manager.transaction_id}] Processing item")
                    item_status, south_order_id = await process_po_item(item_details)
                    po_status += f"Item {item_count}: " + item_status + ", \n"
                    items_status[item_count] = {
                                                    "status" : item_status,
                                                    "south_order_id" : south_order_id
                                                }

                (user_manager.processed_po).append(int(po['id']))
                log.info(f"[{transaction_manager.transaction_id}] Update PO status to ONS")
                await update_po_status(int(po['id']), po_status, user_manager)
                log.info(f"[{transaction_manager.transaction_id}] Add PO details to redis")
                await add_po_to_db(user_manager.user_id, int(po['id']), items_status)

        if new_po == False:
             log.info("No new PO found")
        else:
            # update PO list in redis
            log.info("Updating user's PO list in redis")
            await user_manager.update_po_list()

    # clear user variables
    await user_manager.clean_up()
    del user_manager
    log.info("Cleared user's details.")
    log.info("Polling PO completed.")

@repeat_every(seconds=POLL_DURATION)
async def Poll_OrderStatus():
    '''
    This function polls the order status from south
    '''
    log.info("Polling order status")
    user_manager = UserManager('vidatt')
    log.info("Get PO details of user")
    # with open('db/po_details.json', 'r') as po_details_list:
    #         po_details_lst = json.load(po_details_list)
    #         po_details = po_details_lst[user_manager.user_id]

    with open('db/equinix/order_status.json', 'r') as order_status_list:
            order_status_data = json.load(order_status_list)
    po_details_lst = pickle.loads(redis_manager.redis.get("po_details"))
    po_details = po_details_lst[user_manager.user_id]
    log.info("Checking status of items in equinix data.")
    for po_id, po_data in po_details.items():
        status_updated = False
        po_status = "Order Status: \n"
        transaction_id = po_data["transaction_id"]
        item_count = 0
        item_completed = 0
        for item_id, item_data in po_data['items'].items():
            south_order_id = item_data['south_order_id']
            if south_order_id == -1:
                continue
            item_count += 1
            if order_status_data[south_order_id] == "Order completed":
                item_completed += 1
            if item_data['status'] == order_status_data[south_order_id] or order_status_data[south_order_id] == "":
                po_status += f"Item {item_id}: " + item_data['status'] + ', '
            else:
                po_status += f"Item {item_id}: Status in Equinix({south_order_id}) - " + order_status_data[south_order_id] + ','
                status_updated = True
                po_details_lst[user_manager.user_id][po_id]['items'][item_id]['status'] = order_status_data[south_order_id]

        # if all item orders are completed, update PO status in ONS
        if item_count == item_completed:
            log.info(f"All items for transaction {transaction_id} are completed from south")
            ons_status_code = await ons_mark_complete(po_id, user_manager.user_oauth1)
            if ons_status_code == 200:
                log.info("Updated PO status in ONS")
            else:
                log.error("Failed to update PO status in ONS. Response")

        # check if status was updated
        if status_updated:
             await update_po_status(po_id, po_status, user_manager)
             log.info(f"Updating new status in ONS for transaction {transaction_id}")
        else:
             log.info(f"No updates for transaction {transaction_id}")
    # with open('db/po_details.json', 'w') as po_detail_list:
    #             json.dump(po_details_lst, po_detail_list)
    redis_manager.redis.set("po_details", pickle.dumps(po_details_lst))
    log.info("Polling order status completed.")


def maxProfit( prices):
        max_profit = 0
        current_min = prices[0]
        current_max = prices[0]

        for price in prices:
            if current_max < price:
                current_max = price
                max_profit = max(max_profit, current_max - current_min)

            if current_min > price:
                current_min = price
                current_max = price

        return max_profit

prices = [7,1,5,3,6,4]#[1,2,3,0,2]
print(maxProfit(prices))


import uvicorn

from typing import Optional
from multiprocessing import cpu_count
from fastapi.responses import ORJSONResponse
from fastapi import FastAPI, Body, Depends, BackgroundTasks

from functions import process, get_all_users, filter_and_delete_messages, run_background
from dependencies import authenticate, allow_one_process

app = FastAPI(default_response_class=ORJSONResponse)

@app.get('/status', dependencies=[Depends(authenticate)])
def status():
    """
    Статус API
    """

    return {
        'status': 'Blocked' if process.is_blocked else 'Available',
        **process.last_state,
        **process.current_state
        }

@app.get('/delete_messages', dependencies=[Depends(authenticate), Depends(allow_one_process)])
async def delete_messages(background: BackgroundTasks,
                          filter: str = Body(..., embed=True),
                          count_only: Optional[bool] = Body(False, embed=True)):
    """
    Удалить письмо из почты всех пользователей
    """

    # Обозначить данное действие
    process.set_current_state(filter, action='DELETE' if not count_only else 'COUNT')

    try:

        # Заблокировать процесс
        process.add_worker(2)

        # Получить список всех пользователей
        mails: list[str] = get_all_users()

        # Выполнить задачу в фоновом режиме
        background.add_task(filter_and_delete_messages, mails, filter, count_only)

    except:
        raise

    finally:

        # Разблокировать процесс
        process.remove_worker_and_swap()

    return {'result': 'Accepted'}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8754)


from bisect import bisect_left, bisect_right

N = int(input())

arr =list(map(int, input().split()))

arr.sort()

ans = 0
for i in range(N):
    for j in range(N):
        temp1 = bisect_left(arr,arr[i]-arr[j])
        temp2 = bisect_right(arr,arr[i]-arr[j])
        if temp1<N-1 and arr[temp1]+arr[j]-arr[i] == 0 and not(i==j or i==temp1 or j == temp1):
            ans += 1
            break
        elif arr[temp2-1]+arr[j]-arr[i] == 0 and not(i==j or i==temp2-1 or j == temp2-1):
            ans += 1
            break
print(ans)


def swap(num):
    num = str(float(num))
    a,b = num.split('.')
    res = b + '.' + a
    return res

# { Driver Code Starts
if __name__ == '__main__':
        n = input()
        print(swap(n))
# } Driver Code Ends


#!/usr/bin/env python
# Given a string, sort it based on the decreasing frequency of its characters.

from collections import defaultdict
from heapq import *

def sort( arr ):
   count = defaultdict( int )
   for a in arr:
      count[ a ] += 1

   maxHeap = []
   for char, freq in count.items():
      heappush( maxHeap, ( -freq, char ) )

   result = ''
   while maxHeap:
      freq, char = heappop( maxHeap )
      for i in range( -freq ):
         result += char

   return result

testCases = [
      {
         'input' : "Programming",
         'output' : "rrggmmPiano",
      },
      {
         'input' : "abcbab",
         'output' : "bbbaac",
      },
]

for test in testCases:
   i = test[ 'input' ]
   o = test[ 'output' ]
   print( sort( i ) )


from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('base.html')

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    file.save('uploads/' + file.filename)  # Сохраняем файл в папке uploads
    return render_template('index.html')

if __name__ == '__main__':
    app.run(port=8000, host="127.0.0.1", debug=True)