"""
Author: Mona
Date: Jan 7, 2021
Name: lesson
Description: Will teach the user the content about Ancient Egypt!
"""

#Import modules
import pygame, sys, os, time
from pygame.locals import *
from pygame.color import THECOLORS
from pygame import mixer

#If you get the no available video device error
import platform, os

#This code is necessary for python to work on tdsb computers
import platform
if platform.system() == "Windows":
    os.environ['SDL_VIDEODRIVER'] = 'windib'

#Initial library itself
pygame.init()

#Set-up the main screen display window
size = (850,600)
window = pygame.display.set_mode(size)
pygame.display.set_caption('Poisonous Pyramids')
screen = pygame.display.get_surface()

#Change the logo of our window
pygame_icon = pygame.image.load("images/logo.png")
pygame.display.set_icon(pygame_icon)

#Clock
clock = pygame.time.Clock()
refresh_rate=30
'''
#Adding music
# Starting the mixer
mixer.init()
# Loading the song
mixer.music.load("music/music.wav")
# Setting the volume
mixer.music.set_volume(0.3)
# Start playing the song
mixer.music.play()
'''

#Setting up the font and the size
myfont_title = pygame.font.SysFont("Papyrus", 60)
myfont_special=pygame.font.SysFont("Papyrus", 40)
myfont_body = pygame.font.SysFont("times new roman", 30)
myfont_small = pygame.font.SysFont("times new roman", 15)
myfont_medium = pygame.font.SysFont("times new roman", 22)
test=pygame.display.get_driver()
lesson_font_big = pygame.font.SysFont("Papyrus", 75)

def next_button_back_button():
    pygame.draw.rect(screen, THECOLORS['antiquewhite'], (720, 525, 100, 60))
    pygame.draw.rect(screen, THECOLORS['brown'], (725, 530, 90, 50))
    screen.blit(myfont_body.render("NEXT", 1, THECOLORS['antiquewhite']), (730,538))
    pygame.draw.rect(screen, THECOLORS['antiquewhite'], (610, 525, 100, 60))
    pygame.draw.rect(screen, THECOLORS['brown'], (615, 530, 90, 50))
    screen.blit(myfont_body.render("BACK", 1, THECOLORS['antiquewhite']), (620,538))

# The Game Loop
running=True
show="lesson"
try:
    while running:
        clock.tick(60) #frame rate/second

        if show == "lesson":

            #first screen background
            lesson_screen = pygame.image.load("images/lesson_background.png")
            screen.blit(lesson_screen,(0,0))

            screen.blit(lesson_font_big.render("LESSON", 1, THECOLORS['antiquewhite']), (315,50))

            x=45
            y=160
            pygame.draw.rect(screen, THECOLORS['aquamarine4'], (40, 150, 770, 120))
            pygame.draw.rect(screen, THECOLORS['aquamarine4'], (40, 275, 225, 200))
            pygame.draw.rect(screen, THECOLORS['aquamarine4'], (600, 300, 210, 170))
            with open("textFiles/lessonintro.txt") as word_file:
                for sentence in word_file:
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))
                    y+=40

            #start button------

            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (295, 295, 285, 110))
            pygame.draw.rect(screen, THECOLORS['brown'], (300, 300, 275, 100))
            screen.blit(myfont_title.render("START", 1, THECOLORS['antiquewhite']), (365,312))
            #-----------------------

            #UNIT BUTTONS
            #lesson 1
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (10, 485, 158, 95))
            pygame.draw.rect(screen, THECOLORS['brown'], (15, 490, 148, 85))
            screen.blit(myfont_body.render("Unit 1", 1, THECOLORS['antiquewhite']), (46, 500))
            screen.blit(myfont_medium.render("Geography", 1, THECOLORS['antiquewhite']), (38,535))
            #lesson 2

            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (178, 485, 158, 95))
            pygame.draw.rect(screen, THECOLORS['brown'], (183, 490, 148, 85))
            screen.blit(myfont_body.render("Unit 2", 1, THECOLORS['antiquewhite']), (218,500))
            screen.blit(myfont_medium.render("Egyptian Rule", 1, THECOLORS['antiquewhite']), (197,535))

            #lesson 3
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (346, 485, 158, 95))
            pygame.draw.rect(screen, THECOLORS['brown'], (351, 490, 148, 85))
            screen.blit(myfont_body.render("Unit 3", 1, THECOLORS['antiquewhite']), (383,500))
            screen.blit(myfont_medium.render("Old Kingdom", 1, THECOLORS['antiquewhite']), (363,535))

            #lesson 4
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (514, 485, 158, 95))
            pygame.draw.rect(screen, THECOLORS['brown'], (519, 490, 148, 85))
            screen.blit(myfont_body.render("Unit 4", 1, THECOLORS['antiquewhite']), (554,500))
            screen.blit(myfont_medium.render("The Arts", 1, THECOLORS['antiquewhite']), (555,535))

            #lesson 5
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (682, 485, 158, 95))
            pygame.draw.rect(screen, THECOLORS['brown'], (687, 490, 148, 85))
            screen.blit(myfont_body.render("Unit 5", 1, THECOLORS['antiquewhite']), (722,500))
            screen.blit(myfont_medium.render("Materials", 1, THECOLORS['antiquewhite']), (720,535))

            pygame.display.flip()

        elif show=="lesson 1":

            surface = pygame.image.load("images/lesson_screen_1.png")
            screen.blit(surface,(0,0))
            screen.blit(lesson_font_big.render("1. Geography", 1, THECOLORS['antiquewhite']), (315,50))
            #images
            '''
            nile = pygame.image.load("images/nile river.jpeg")
            screen.blit(nile,(50,25))
            '''
            x=50
            y=160
            with open("textFiles/lesson_1_quick_geography.txt") as word_file:
                for sentence in word_file:
                    y+=40
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))

            next_button_back_button()
            pygame.display.flip()

        elif show=="lesson 2":

            surface = pygame.image.load("images/lesson_screen_2.png")
            screen.blit(surface,(0,0))
            screen.blit(myfont_title.render("2. Timeline ", 1, THECOLORS['antiquewhite']), (250,50))
            x=50
            y=85
            with open("textFiles/Lesson_2_egyptian_rule.txt") as word_file:
                for sentence in word_file:
                    y+=40
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))
            next_button_back_button()
            pygame.display.flip()

        elif show=="lesson 3":

            surface = pygame.image.load("images/lesson_screen_1.png")
            screen.blit(surface,(0,0))
            screen.blit(myfont_title.render("3.The Old Kingdom ", 1, THECOLORS['antiquewhite']), (315,50))
            #text
            x=50
            y=160
            with open("textFiles/lesson_3_the_old_kingdom.txt") as word_file:
                for sentence in word_file:
                    y+=40
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))
            next_button_back_button()
            pygame.display.flip()

        elif show=="lesson 4":
            surface = pygame.image.load("images/lesson_screen_2.png")
            screen.blit(surface,(0,0))
            screen.blit(myfont_special.render("4. The Middle Kingdom and The Arts", 1, THECOLORS['antiquewhite']), (50,50))
            x=50
            y=70
            with open("textFiles/lesson_4_the_middle_kingdom.txt") as word_file:
                for sentence in word_file:
                    y+=40
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))
            next_button_back_button()
            pygame.display.flip()

        elif show=="lesson 5":
            surface = pygame.image.load("images/lesson_screen_2.png")
            screen.blit(surface,(0,0))
            screen.blit(myfont_special.render("5. What did they write on?", 1, THECOLORS['antiquewhite']), (100,50))
            x=50
            y=75
            with open("textFiles/seperate_but_what_did_they_write_on.txt") as word_file:
                for sentence in word_file:
                    y+=40
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))

            #done button
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (720, 525, 100, 60))
            pygame.draw.rect(screen, THECOLORS['brown'], (725, 530, 90, 50))
            screen.blit(myfont_body.render("DONE", 1, THECOLORS['antiquewhite']), (730,538))
            #back button
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (610, 525, 100, 60))
            pygame.draw.rect(screen, THECOLORS['brown'], (615, 530, 90, 50))
            screen.blit(myfont_body.render("BACK", 1, THECOLORS['antiquewhite']), (620,538))

            pygame.display.flip()

        elif show=="done":
            lesson_screen = pygame.image.load("images/lesson_background.png")
            screen.blit(lesson_screen,(0,0))

            screen.blit(lesson_font_big.render("END OF LESSON!", 1, THECOLORS['antiquewhite']), (100,50))

            x=50
            y=180
            pygame.draw.rect(screen, THECOLORS['aquamarine4'], (40, 160, 250, 375))
            with open("textFiles/done.txt") as word_file:
                for sentence in word_file:
                    screen.blit(myfont_medium.render(sentence, 1, THECOLORS['antiquewhite']), (x,y))
                    y+=40

            #main menu
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (495, 150, 285, 110))
            pygame.draw.rect(screen, THECOLORS['brown'], (500, 155, 275, 100))
            screen.blit(myfont_title.render("Main menu", 1, THECOLORS['antiquewhite']), (515,155))

            #back to start
            pygame.draw.rect(screen, THECOLORS['antiquewhite'], (495, 295, 285, 110))
            pygame.draw.rect(screen, THECOLORS['brown'], (500, 300, 275, 100))
            screen.blit(myfont_special.render("Back to start", 1, THECOLORS['antiquewhite']), (515,325))

            pygame.display.flip()

        # The Event Loop #
        events=pygame.event.get()

        #Allow user to click buttons
        for event in events:
            pos = pygame.mouse.get_pos()
            butt = pygame.mouse.get_pressed()
            x=pos[0]
            y=pos[1]

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_s:
                    show = "lesson"

            #lesson buttons

            if show == "lesson": #from lesson page
                #start button
                if x>300 and x<300+300 and y>300 and y<300+100 and butt[0]==1:
                    show = "lesson 1"
                #UNIT BUTTONS
                #to lesson 1
                elif x>10 and x<10+158 and y>485 and y<485+95 and butt[0]==1:
                    show = "lesson 1"
                #to lesson 2
                elif x>178 and x<178+158 and y>485 and y<485+95 and butt[0]==1:
                    show = "lesson 2"
                #to lesson 3
                elif x>346 and x<346+158 and y>485 and y<485+95 and butt[0]==1:
                    show = "lesson 3"
                #to lesson 4
                elif x>514 and x<514+158 and y>485 and y<485+95 and butt[0]==1:
                    show = "lesson 4"
                #to lesson 5
                elif x>682 and x<682+158 and y>485 and y<485+95 and butt[0]==1:
                    show = "lesson 5"

            #NEXT AND BACK
            elif show=="lesson 1":
                #next button to lesson 2
                if x>720 and x<720+100 and y>525 and y<525+60 and butt[0]==1:
                    show = "lesson 2"
                #back button to lesson start page
                elif x>610 and x<610+100 and y>525 and y<525+60 and butt[0]==1:
                    show="lesson"

            elif show=="lesson 2":
                #next button to lesson 3
                if x>720 and x<720+100 and y>525 and y<525+60 and butt[0]==1:
                    show = "lesson 3"
                #back button to lesson 1
                elif x>610 and x<610+100 and y>525 and y<525+60 and butt[0]==1:
                    show="lesson 1"

            elif show=="lesson 3":
                #next button to lesson 4
                if x>720 and x<720+100 and y>525 and y<525+60 and butt[0]==1:
                    show = "lesson 4"
                #back button to lesson 2
                elif x>610 and x<610+100 and y>525 and y<525+60 and butt[0]==1:
                    show="lesson 2"

            elif show=="lesson 4":
                #next button to lesson 5
                if x>720 and x<720+100 and y>525 and y<525+60 and butt[0]==1:
                    show = "lesson 5"
                #back button to lesson 3
                elif x>610 and x<610+100 and y>525 and y<525+60 and butt[0]==1:
                    show="lesson 3"

            elif show=="lesson 5":
                #next button to lesson done
                if x>720 and x<720+100 and y>525 and y<525+60 and butt[0]==1:
                    show = "done"
                #back button to lesson 4
                elif x>610 and x<610+100 and y>525 and y<525+60 and butt[0]==1:
                    show="lesson 4"

            elif show=="done":
                '''
                #go to main menu
                if x>495 and x<495+285 and y>150 and y<150+110 and butt[0]==1:
                    show = "main menu"
                '''
                #go to start of lesson
                # change following if to elif in main program

                if x>495 and x<495+285 and y>295 and y<295+110 and butt[0]==1:
                    show="lesson"

            #Exit
            elif(event.type == QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE)):
                x=0
                y=0
                credit_screen=pygame.image.load("images/roll_credits.png").convert_alpha()

                #scroll
                while y!=-600:
                    y-=5
                    screen.blit(credit_screen,(x, y))
                    pygame.display.flip()	 #update screen
                    clock.tick(refresh_rate)
                running=False

        pygame.display.update()

# Event Handling End #
finally:
    pygame.quit()  # Keep this IDLE friendly


import os
import tensorflow
from dotenv import load_dotenv

load_dotenv("../.env")

BATCH_SIZE = 32
IMG_SIZE = (512, 512)

#
# _train_ds = tensorflow.keras.utils.image_dataset_from_directory(os.getenv('IMG_TRAIN'),
#                                                        # validation_split=0.2,
#                                                        # subset="training",
#                                                        seed=123,
#                                                        image_size=IMG_SIZE,
#                                                        batch_size=BATCH_SIZE)
_test_ds = tensorflow.keras.utils.image_dataset_from_directory(os.getenv('IMG_TEST'),
                                                      # validation_split=0.2,
                                                      # subset="validation",
                                                      seed=123,
                                                      image_size=IMG_SIZE,
                                                      batch_size=BATCH_SIZE)
# Use buffered prefetching to load images from disk without having I/O become blocking
AUTOTUNE = tensorflow.data.AUTOTUNE
# train_dataset = _train_ds.prefetch(buffer_size=AUTOTUNE)
validation_dataset = _test_ds.prefetch(buffer_size=AUTOTUNE)


from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTP
import datetime
from datetime import datetime
from basis.dal import get_recipients
from basis.dal import get_content

sender = 'tatsm.reg@gmail.com'
subject = "Daily news"

def format_content():
    content = get_content()
    body = ''
    lines = content.split(',')
    cnt = 0
    for line in lines:
        if line:
            line += '\n'
            cnt += 1
            if cnt == 2:
                line += '\n'
                cnt = 0
            body += line

    return body

def create_message():
    recipients = get_recipients()
    content = format_content()
    msg = MIMEMultipart()
    msg["Subject"] = subject
    msg["From"] = sender
    msg["To"] = ", ".join(recipients)
    body = MIMEText(content)
    msg.attach(body)
    return msg

def send_email():
    print("Mailing started at ", datetime.now(), '.\n')
    message = create_message()
    try:
        server = SMTP('smtp.gmail.com:587')
        server.starttls()
        server.login('tatsm.reg@gmail.com', 'TatSmReg2019*')
        server.sendmail(message["From"], message["To"].split(","), message.as_string())
        server.quit()
        print("News sent successfully at ", datetime.now(), '.\n')
        return True
    except Exception as ex:
        print('News send failed', ex, '\n')
        return False

# success = send_email()


# -*- coding: utf-8 -*-
import requests, re, copy
from bs4 import BeautifulSoup
from requests.auth import HTTPBasicAuth
from time import sleep
from pprint import pprint
import urllib3

class surfer:

    def __init__(self, base_url='', with_session=True, allow_redirects=False, credentials=None, debug=False):
        self.base_url = base_url
        self.debug = debug
        self.with_session = with_session
        if with_session: self.session = requests.Session()
        self.allow_redirects = allow_redirects
        self.credentials = credentials
        # By Nike, some fucked up servers have weak SSL, and you need to cope with it despite the error throuwn by default by the SSL lib...
        requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL:@SECLEVEL=1'
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

    def surf(self, waves, entry_wave):
        self.extracted_values = {}
        self.waves = waves
        self.next_wave = entry_wave
        while self.next_wave is not None :
            if ('delay' in self.waves[self.next_wave]) and (self.waves[self.next_wave]['delay']):
                sleep(self.waves[self.next_wave]['delay'])
            self._surf_wave()

    def _surf_wave(self):
        self.cur_wave = self.next_wave
        if self.debug: print('BASE=%s | WAVEURL=%s' %(self.base_url, self.waves[self.cur_wave]['sub_url']))
        if self.waves[self.cur_wave]['sub_url'].lower().startswith('https://') or self.waves[self.cur_wave]['sub_url'].lower().startswith('http://'):
            url = self.waves[self.cur_wave]['sub_url']
        else:
            if self.waves[self.cur_wave]['sub_url'].startswith('/'):
                url = self.base_url+self.waves[self.cur_wave]['sub_url']
            else:
                url = self.base_url+'/'+self.waves[self.cur_wave]['sub_url']
        self._prepare_params()
        self._prepare_headers()

        req_meth_name = self.waves[self.cur_wave]['method'].lower()
        if req_meth_name not in ('get','put', 'post', 'delete', 'head', 'options', ): return
        if self.with_session :
            req_meth = getattr(self.session, req_meth_name)
        else:
            req_meth = getattr(requests, req_meth_name)

        if self.debug: print('Surfing to %s\n    Method:%s\n    Headers:%s\n    Params:%s\n    Cookies:%s\n' %(url, req_meth_name, self.headers, self.params, self.session.cookies.items()))
        if self.credentials:
            try:
                if req_meth_name.lower() == 'post':
                    r = req_meth(   url,
                                    allow_redirects = self.allow_redirects,
                                    headers = self.headers,
                                    data = self.params,
                                    auth=(self.credentials['user'], self.credentials['pass']),
                                    timeout=(10, 20),
                                    verify=False,
                                )
                else:
                    r = req_meth(   url,
                                    allow_redirects = self.allow_redirects,
                                    headers = self.headers,
                                    params = self.params,
                                    auth=(self.credentials['user'], self.credentials['pass']),
                                    timeout=(10, 20),
                                    verify=False,
                                )
            except Exception as e:
                if ('if_not_accessible' in self.waves[self.cur_wave]) and callable(self.waves[self.cur_wave]['if_not_accessible']):
                    self.waves[self.cur_wave]['if_not_accessible'](e.message, self)
                    self.next_wave = self.waves[self.cur_wave]['next_wave']
                    return
                else:
                    raise e
        else:
            try:
                if req_meth_name.lower() == 'post':
                    r = req_meth(   url,
                                    allow_redirects = self.allow_redirects,
                                    headers = self.headers,
                                    data = self.params,
                                    timeout=(10, 20),
                                    verify=False,
                                )
                else:
                    r = req_meth(   url,
                                allow_redirects = self.allow_redirects,
                                headers = self.headers,
                                params = self.params,
                                timeout=(10, 20),
                                verify=False,
                            )

            except Exception as e:
                if ('if_not_accessible' in self.waves[self.cur_wave]) and callable(self.waves[self.cur_wave]['if_not_accessible']):
                    self.waves[self.cur_wave]['if_not_accessible'](e.message, self)
                    self.next_wave = self.waves[self.cur_wave]['next_wave']
                    return
                else:
                    raise e

        if self.debug: print('Cookies after wave %s : %s' %(self.cur_wave, self.session.cookies.items()))

        self.next_wave = self.waves[self.cur_wave]['next_wave']
        if r.status_code != 200:
            if self.debug: print('Error; http status=%s' %r.status_code)
            if callable(self.waves[self.cur_wave]['if_not_200']):
                self.waves[self.cur_wave]['if_not_200'](r, self)
        else:
            if 'text' == self.waves[self.cur_wave]['parsing']:
                if self.debug: print('Parsing TEXT...')
                data = r.text
                self.extracted_values = {}
                self._regexp_extract(data)
            elif 'json' == self.waves[self.cur_wave]['parsing']:
                if self.debug: print('Parsing JSON...')
                data = r.json()
                self.extracted_values = {'json_data' : data}
            elif 'html' == self.waves[self.cur_wave]['parsing']:
                if self.debug: print('Parsing HTML...');
                self.extracted_values = {}
                self._regexp_extract(r.text)
                data = BeautifulSoup(r.text, features="html.parser")
                self._html_xtract(data)
            elif 'xml' == self.waves[self.cur_wave]['parsing']:
                if self.debug: print('Parsing XML...')
                self.extracted_values = {}
                self._regexp_extract(r.text)
                data = BeautifulSoup(r.text, 'xml') #features="xml.parser"
                self._xml_xtract(data)
            else:
                if self.debug: print('WARNING: No parsing !!')
                data = r.content

            if callable(self.waves[self.cur_wave]['test_response']):
                test_ok = self.waves[self.cur_wave]['test_response'](data, self)
                if not test_ok and self.debug:
                    with open('surfer_debug.log', 'w') as fil: fil.write(r.text.encode('utf-8', 'ignore'))
            else:
                test_ok = True

            if self.debug: print('Tested content:%s' %(('ok' if test_ok else 'not ok!')))

            if test_ok and callable(self.waves[self.cur_wave]['if_test_ok']):
                self.waves[self.cur_wave]['if_test_ok'](data, self)
            elif (not test_ok) and callable(self.waves[self.cur_wave]['if_test_fail']):
                self.waves[self.cur_wave]['if_test_fail'](data, self)

    def _html_xtract(self, parsed_html):
        if 'extract' not in self.waves[self.cur_wave]: return
        for needle in self.waves[self.cur_wave]['extract']:
            if 'bs4_selectors' not in needle: continue
            node = parsed_html
            for selector in needle['bs4_selectors']:
                res = node.select(selector)
                if res:
                    #if self.debug:  print('Selector %s match ! %s' %(selector, res))
                    node = res[0]
                    if self.debug: print('Selector %s found !' %(selector))
                else:
                    if self.debug:  print('Selector %s NOT match !' %selector)
                    break

            if res:
                if ('bs4_getall' in needle) and needle['bs4_getall']:
                    nodes = res
                    extracts = []
                    for node in nodes:
                        if 'bs4_extractor' in needle and callable(needle['bs4_extractor']):
                            if self.debug:  print('[Getall] Adding node %s using external extractor...' %node)
                            extracts.append(needle['bs4_extractor'](node))
                        else:
                            if self.debug:  print('[Getall] Adding node %s as string...' %node)
                            extracts.append(node.string)

                elif 'bs4_getone' in needle:
                    node = res[needle['bs4_getone']]
                    if 'bs4_extractor' in needle and callable(needle['bs4_extractor']):
                        if self.debug:  print('[GetOne] Adding node %s using external extractor...' %node)
                        extracts = needle['bs4_extractor'](node)
                    else:
                        if self.debug:  print('[Getall] Adding node %s as string...' %node)
                        extracts = node.string

                else:
                    node = res[0]
                    if 'bs4_extractor' in needle and callable(needle['bs4_extractor']):
                        if self.debug:  print('[default] Adding node %s using external extractor...' %node)
                        extracts = needle['bs4_extractor'](node)
                    else:
                        if self.debug:
                            if node.string : print('[default] Adding node %s as string...%s' %(node, node.string.encode('utf-8', 'ignore')))
                            else:print('[default] Adding node %s [EMPTY]' %(node))
                        extracts = node.string

                self.extracted_values[needle['name']] = extracts
            else:
                if self.debug: print('HTML Needle %s NOT Found!' %needle['name'])
                if needle['name'] not in self.extracted_values: self.extracted_values[needle['name']] = None
        if self.debug: print('HTML Extracted: %s' %self.extracted_values)

    def _xml_xtract(self, parsed_xml):
        if 'extract' not in self.waves[self.cur_wave]: return
        for needle in self.waves[self.cur_wave]['extract']:
            if 'bs4_selectors' not in needle: continue
            node = parsed_xml
            for selector in needle['bs4_selectors']:
                res = node.select(selector)
                if res:
                    #if self.debug:  print('Selector %s match ! %s' %(selector, res))
                    node = res[0]
                    if self.debug: print('Selector %s found !' %(selector))
                else:
                    if self.debug:  print('Selector %s NOT match !' %selector)
                    break

            if res:
                if ('bs4_getall' in needle) and needle['bs4_getall']:
                    nodes = res
                    extracts = []
                    for node in nodes:
                        if 'bs4_extractor' in needle and callable(needle['bs4_extractor']):
                            extracts.append(needle['bs4_extractor'](node))
                        else:
                            extracts.append(node.string)
                elif 'bs4_getone' in needle:
                    node = res[needle['bs4_getone']]
                    if 'bs4_extractor' in needle and callable(needle['bs4_extractor']):
                        extracts = needle['bs4_extractor'](node)
                    else:
                        extracts = node.string
                else:
                    node = res[0]
                    if 'bs4_extractor' in needle and callable(needle['bs4_extractor']):
                        extracts = needle['bs4_extractor'](node)
                    else:
                        extracts = node.string

                if self.debug: print('XML Needle Found : %s' %extracts)
                self.extracted_values[needle['name']] = extracts
            else:
                if self.debug: print('XML Needle %s NOT Found!' %needle['name'])
                if needle['name'] not in self.extracted_values: self.extracted_values[needle['name']] = None
        if self.debug: print('XML Extracted: %s' %self.extracted_values)

    def _regexp_extract(self, content):
        if 'extract' not in self.waves[self.cur_wave]: return
        for needle in self.waves[self.cur_wave]['extract']:
            if 'regexp' not in needle: continue
            if self.debug: print('Searching for: %s' %needle)
            matches = re.findall(needle['regexp'], content, needle['regexp_flags'])
            if matches:
                if self.debug: print('TEXT Needle Found : %s' %matches)
                if isinstance(matches[0], tuple):
                    self.extracted_values[needle['name']] = matches[0][needle['regexp_group_index']]
                else:
                    self.extracted_values[needle['name']] = matches[0]
            else:
                if self.debug: print('TEXT Needle %s NOT found!' %needle['name'])
                if needle['name'] not in self.extracted_values: self.extracted_values[needle['name']] = None
        if self.debug: print('TEXT Extracted: %s' %self.extracted_values)

    def _prepare_params(self):
        self.params = copy.deepcopy(self.waves[self.cur_wave]['params'])
        if isinstance(self.params,dict) :
            for k, v in self.extracted_values.items():
                for par,parval in self.params.items():
                    if isinstance(v, list) or isinstance(v, tuple): v = ' '.join(v)
                    self.params[par]=parval.replace('%%{%s}'%k.encode('utf-8', 'ignore'), v.encode('utf-8', 'ignore'))
        elif isinstance(self.params,str) :
            for k, v in self.extracted_values.items():
                if isinstance(v, list) or isinstance(v, tuple): v = ' '.join(v)
                self.params=self.params.replace('%%{%s}'%k.encode('utf-8', 'ignore'), v.encode('utf-8', 'ignore'))

        # If replacement in keys is necessary do it here

    def _prepare_headers(self):
        self.headers = copy.deepcopy(self.waves[self.cur_wave]['headers'])
        for k, v in self.extracted_values.items():
            if v == None:
                v=''
            elif isinstance(v, list) or isinstance(v, tuple):
                v = ' '.join([x if x else '' for x in v])
            elif isinstance(v, bool):
                v = 'True' if v else 'False'

            for par,parval in self.headers.items():
                if isinstance(v, str) or isinstance(v, unicode):
                    self.headers[par]=parval.replace('%%{%s}'%k.encode('utf-8', 'ignore'), v)

        # If replacement in keys is necessary do it here


# -*- coding:utf-8 -*-
import requests, time, pymysql
import pandas as pd
from datetime import datetime,timedelta
from connect import get_response,get_conn

# Connect to mysql
conn = get_conn()
cur = conn.cursor()
cur.execute("SELECT max(content_id) FROM chat_logs where group_name='bitmex'")
latest_start = cur.fetchall()[0][0]

# Parameters
url = "https://www.bitmex.com/api/v1/chat"
paras = {
        'count':500,
        'channelID':2,
        'start':latest_start+1,
        'test':False}
        #'start':304825
#url = "https://www.bitmex.com/api/v1/chat?count=500&channelID=2&start=304825&test=False"

while(1):
    df = get_response(url,paras)
    if(len(df)==0):
        break
    df['time'] = pd.to_datetime(df['date'])
    #df['time'] = df.time.dt.tz_localize('UTC').dt.tz_convert('Asia/Shanghai')
    df['time'] = df['time'].dt.strftime('%Y-%m-%d %H:%M:%S')
    df['group_name'] = 'Bitmex'
    df['group_type'] = 'Exchanger'
    df = df.fillna(0)

    cur.executemany('INSERT IGNORE INTO chat_logs(time,content,group_name,user,content_id,group_type) VALUES(%s,%s,%s,%s,%s,%s)',df[['time','message','group_name','user','id','group_type']].values.tolist())
    conn.commit()

    paras['start'] = max(df['id'])+1
    print('start_time_utc:%s\tcounter:%d\ttime_local:%s' %(df['time'][0],paras['start'],datetime.now()))
    time.sleep(2)

cur.close()
conn.close()


from functools import reduce, wraps
from pathlib import Path

import matplotlib.pyplot as plt
import pandas as pd
import seaborn

IMG_DIR = Path(".") / "img"
IMG_DIR.mkdir(parents=True, exist_ok=True)

def save_with_root(root: Path):
    def make_name(func):
        @wraps(func)
        def inner(*args, **kwargs):
            name = kwargs.pop("name")
            if isinstance(name, str):
                name = root / name
            else:
                # 可迭代的
                name = reduce(lambda x, y: x / y, name, root)
            name.parent.mkdir(parents=True, exist_ok=True)
            return func(*args, name=str(name), **kwargs)

        return inner

    return make_name

@save_with_root(IMG_DIR)
def draw_layered(rr_df: pd.DataFrame, name):
    """画分层图，用于展示不同状态的走势
    rr_df 列是不同状态的收益率
    name 是保存的文件名
    """
    index_date = rr_df.index
    fig, ax = plt.subplots(1, 1, constrained_layout=True, figsize=(16, 9))
    index_x = list(range(len(index_date)))
    pretty_x = index_x[:: len(index_x) // 20]
    pretty_date = index_date[:: len(index_date) // 20]
    ax.set_xticks(pretty_x)
    ax.set_xticklabels(pretty_date, rotation=30)
    lines = ax.plot(index_x, rr_df.cumsum().values, label=rr_df.columns)
    ax.legend(lines, rr_df.columns)
    print(f"{name}.png")
    fig.savefig(f"{name}.png", dpi=160)

def draw_scatter(state, state_group, index_date, close):
    """画散点图，用于在价格走势上展示隐藏状态

    state 状态序列
    state_group 状态所在的组，涨还是跌
    index_date 要画图的时间序列索引
    close 价格走势, 时间跨度要包含index_date的跨度
    """
    color_list = []
    for s in state:
        if s in state_group.rise_state:
            color_list.append("red")
        elif s in state_group.fall_state:
            color_list.append("green")
        else:
            color_list.append("gray")

    fig, ax = plt.subplots(1, 1, constrained_layout=True, figsize=(16, 9))
    index_x = list(range(len(index_date)))
    pretty_x = index_x[:: len(index_x) // 20]
    pretty_date = index_date[:: len(index_date) // 20]
    ax.set_xticks(pretty_x)
    ax.set_xticklabels(pretty_date, rotation=30)
    ax.scatter(
        index_x, close[index_date[0] : index_date[-1]].values, color=color_list, s=7  # type: ignore
    )
    plt.show()
    fig.savefig(IMG_DIR / "scatter.png", dpi=300)  # type:ignore

@save_with_root(IMG_DIR)
def draw_heatmap(data, name):
    fig, ax = plt.subplots(1, 1, constrained_layout=True, figsize=(9, 9))
    seaborn.heatmap(data, ax=ax)
    fig.savefig(f"{name}.png", dpi=160)


""" Core definition of a Materials Document """
from __future__ import annotations

from datetime import datetime
from typing import Sequence, Type, TypeVar, List

from pydantic import Field
from pymatgen.core.structure import Molecule

from emmet.core.material import PropertyOrigin
from emmet.core.mpid import MPID
from emmet.core.structure import MoleculeMetadata

__author__ = "Evan Spotte-Smith <ewcspottesmith@lbl.gov>"

S = TypeVar("S", bound="PropertyDoc")

class PropertyDoc(MoleculeMetadata):
    """
    Base model definition for any singular molecule property. This may contain any amount
    of molecule metadata for the purpose of search
    This is intended to be inherited and extended not used directly
    """

    property_name: str
    molecule_id: MPID = Field(
        ...,
        description="The ID of the molecule, used as a universal reference across property documents."
        "This comes in the form of an MPID or int",
    )

    deprecated: bool = Field(
        ...,
        description="Whether this property document is deprecated.",
    )

    deprecation_reasons: List[str] = Field(
        None,
        description="List of deprecation tags detailing why this document isn't valid",
    )

    last_updated: datetime = Field(
        description="Timestamp for the most recent calculation update for this property",
        default_factory=datetime.utcnow,
    )

    origins: Sequence[PropertyOrigin] = Field(
        [], description="Dictionary for tracking the provenance of properties"
    )

    warnings: Sequence[str] = Field(
        [], description="Any warnings related to this property"
    )

    @classmethod
    def from_molecule(  # type: ignore[override]
        cls: Type[S], meta_molecule: Molecule, molecule_id: MPID, **kwargs
    ) -> S:
        """
        Builds a molecule document using the minimal amount of information
        """

        return super().from_molecule(meta_molecule=meta_molecule, molecule_id=molecule_id, **kwargs)  # type: ignore


from apiclient import discovery, http
from oauth2client import file, tools, client

import httplib2
import mimetypes
import os
import io
import hashlib

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

class GoogleDrive:

    scopes = "https://www.googleapis.com/auth/drive"
    app_name = "GDsycncer"
    secret_file = ""
    credentials = None
    service = None

    def __init__(self, secret_file):
        """
        Set the secret_file variable
        :param string secret_file: path to the client_id.json
        """
        self.secret_file = secret_file

    def authenticate(self, credentials_path='credentials.dat'):
        """
        Redirect the user to a web authentication portal if not authenticated and then build the drive service.
        :param string credentials_path: Path to the file containing the user credentials
        :return: None
        """
        flow = client.flow_from_clientsecrets(self.secret_file, self.scopes)
        storage = file.Storage(credentials_path)
        cred = storage.get()
        if cred is None or cred.invalid:
            flow.user_agent = self.app_name
            cred = tools.run_flow(flow,storage)
        self.credentials = cred
        httpobj = httplib2.Http()
        httpobj = cred.authorize(httpobj)
        self.service = discovery.build('drive', 'v3', http=httpobj)

    def get_directory_id(self, name):
        """
        Get the id matching to the given name argument
        :param name: Exact name of the directory to be searched.
        :type name : String
        :return: ID(String) of the matching directory if it exists or else None
        """
        query = "mimeType = 'application/vnd.google-apps.folder' and name = '%s'" % name
        directory = self.service.files().list(q=query).execute()
        return directory.get('files')[0].get('id')

    def list_files(self, directory_id):
        """
        Get a list of all files in directory in the form of dict
        :param directory_id: Alphanumerical id of the parent directory
        :return: A dict with key as file name and value as file id
        """
        response = self.service.files().list(q="'%s' in parents" % directory_id, fields='files').execute()
        return response.get('files')

    def upload_file(self, file_path, folder_id=''):
        """
        Upload a file to a specified directory.
        :param file_path: Absolute or relative path to the file
        :param folder_id: The id of the directory to which the file is to be uploaded
        :return:
        """
        (directory, filename) = os.path.split(file_path)
        (mime, encoding) = mimetypes.guess_type(file_path)
        if mime is None:
            mime = "application/octet-stream"

        media = http.MediaFileUpload(file_path, mimetype=mime, resumable=True)
        body = {
            'name': filename,
            'parents': [folder_id]
        }
        self.service.files().create(body=body, media_body=media).execute()

    def create_folder(self, folder_name, parent_folder_id = ''):
        """
        Create a folder
        :param folder_name: Name of the folder to be created.
        :param parent_folder_id: Id of the parent folder. Created in the root folder by default.
        :return: ID of the created folder.
        """
        file_metadata = {
            'name': folder_name,
            'mimeType': 'application/vnd.google-apps.folder',
            'parents': parent_folder_id
        }

        file = self.service.files().create(body=file_metadata, fields='id').execute()
        return file.get('id')

    def download_file(self, file_id):
        """
        Download a file given it's file id.
        :param file_id: File ID of the file to be downloaded.
        :return: ByteIO object of the file which can be saved to a file in the local system.
        """
        request = self.service.files().get_media(fileId=file_id)
        file_handler = io.BytesIO()
        downloader = http.MediaIoBaseDownload(file_handler, request)
        done = False
        while not done:
            status, done = downloader.next_chunk()
        return file_handler

class Watcher:

    def __init__(self, fold_name, root_dir, drive_object):
        self.root_dir = os.path.abspath(root_dir)
        self.drive_object = drive_object
        self.current_id = self.drive_object.get_directory_id(fold_name)
        contents = os.listdir(self.root_dir)
        self.local_files = set()
        self.local_folders = set()
        self.cloud_files = dict()
        self.cloud_folders = dict()
        md5 = lambda path : hashlib.md5(open(path,'rb').read()).hexdigest()
        for content in contents:
            path = os.path.join(root_dir, content)
            if os.path.isfile(path):
                self.local_files.add(content)
            else:
                self.local_folders.add(content)

        response = drive_object.list_files(self.current_id)
        # TODO 1: check for hashsum
        for file in response:
            if file.get("mimeType") == "application/vnd.google-apps.folder":
                if file.get('name') not in self.local_folders:
                    self.cloud_folders[file.get('name')] = file.get('id')
            else:
                if file.get('name') not in self.local_files:
                    self.cloud_files[file.get('name')] = file.get('id')
                else:
                    self.local_files.remove(file.get('name'))

    def push(self):
        # TODO 2: recursively upload(folder within a folder)
        for file in self.local_files:
                path = os.path.join(self.root_dir, file)
                print(bcolors.OKBLUE+"Uploading %s" % file + bcolors.ENDC)
                self.drive_object.upload_file(path, self.current_id)

    def pull(self):
        for name, id in self.cloud_files.items():
            file = open(os.path.join(self.root_dir, name), 'wb')
            print(bcolors.OKGREEN+"Downloading %s" % name + bcolors.ENDC)
            file.write(self.drive_object.download_file(id).getvalue())


from django.shortcuts import render,redirect
from django.http  import Http404
import datetime as dt
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
# from .forms import GalleryLetterForm
from django.http import HttpResponse, Http404,HttpResponseRedirect
# # from .email import send_welcome_email
from .models import Profile ,Project,Votes
from .forms import NewProfileForm,ProjectForm,VotesForm
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import  Profile,Project ,Votes
from .serializer import ProfileSerializer,ProjectSerializer
from rest_framework import status
from .permissions import IsAdminOrReadOnly

@login_required(login_url='/accounts/login/')
def index(request):
    projects = Project.objects.all()
    grades= Votes.objects.filter().all()
    profile = Profile.objects.get()
    message = "welcome"
    return render(request, 'home.html',{"message":message,"projects":projects,"profile":profile,"grades":grades})

class ProfileList(APIView):

    def get (self,request):
        profile = Profile.objects.all()
        serializer = ProfileSerializer(profile,many=True)
        return Response(serializer.data)
        permission_classes = (IsAdminOrReadOnly,)

    def post(self, request, format=None):
        serializers = ProfileSerializer(data=request.data)
        if serializers.is_valid():
            serializers.save()
            return Response(serializers.data, status=status.HTTP_201_CREATED)
        return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request, pk, format=None):
        profile = self.get_profile(pk)
        serializers = ProfileSerializer(data=request.data)
        if serializers.is_valid():
            serializers.save()
            return Response(serializers.data)
        else:
            return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        profile = self.get_profile(profile_pk)
        profile.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

class ProjectList(APIView):
    def get(self,request):
        project = Project.objects.all()
        serializer=ProjectSerializer(project,many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializers = ProjectSerializer(data=request.data)
        if serializers.is_valid():
            serializers.save()
            return Response(serializers.data, status=status.HTTP_201_CREATED)
        return Response(serializers.errors, status=status.HTTP_400_BAD_REQUEST)

def ProjectLetterForm(request):
    name = request.POST.get('your_name')
    email = request.POST.get('email')

    recipient = NewsLetterRecipients(name=name, email=email)
    recipient.save()
    send_welcome_email(name, email)
    data = {'success': 'You have been successfully added to mailing list'}
    return JsonResponse(data)

@login_required(login_url='/accounts/login/')
def new_profile(request):
    current_user = request.user
    if request.method == 'POST':
        form = NewProfileForm(request.POST, request.FILES)
        if form.is_valid():
            profile = form.save(commit=False)
            profile.user = current_user
            profile.save()
        return redirect("home")

    else:
        form = NewProfileForm()
    return render(request, 'all_gallery/new-profile.html',{"form": form})

def profile(request):
    current_user = request.user
    profile = Profile.objects.get(user = current_user)
    print(profile.user_id)
    return render(request,'all_gallery/profile.html',{"profile":profile})

def more(request):
    return render(request,'all_gallery/details.html')

@login_required(login_url='/accounts/login/')
def projects(request):
    current_user = request.user
    if request.method == 'POST':
        form = ProjectForm(request.POST, request.FILES)
        if form.is_valid():
            projects = form.save(commit=False)
            projects.user = current_user
            projects.profile = current_user
            projects.save()

        return redirect("home")

    else:
        form = ProjectForm()
    return render(request, 'projects.html', {"form": form})

@login_required(login_url='/accounts/login/')
def photo(request,projects_id):
    projects = Project.objects.get(id = projects_id)
    return render(request,"all_gallery/details.html", {"projects":projects})

@login_required(login_url='/accounts/login/')
def search_results(request):
    current_user = request.user
    profile =Profile.objects.get(user=current_user)
    if 'project' in request.GET and request.GET["project"]:
        search_term = request.GET.get("project")
        projects = Project.search_project(search_term)
        message=f"{search_term}"
        return render(request,'search.html',{"message":message,"projects":projects,"profile":profile})

    else:
        message="You haven't searched for any term"
        return render(request,'search.html',{"message":message})

def votes(request,id):
    current_user = request.user
    post = Project.objects.get(id=id)
    votes = Votes.objects.get(project=id)

    if request.method == 'POST':
            vote = VotesForm(request.POST)
            if vote.is_valid():
                design = vote.cleaned_data['design']
                usability = vote.cleaned_data['usability']
                content = vote.cleaned_data['content']
                rating = Votes(design=design,usability=usability,content=content,user=request.user,project=post)
                rating.save()
                return redirect('project')
    else:
        form = VotesForm()
        return render(request, 'vote.html', {"form":form,'post':post,'user':current_user,'votes':votes})


import argparse
import os
import numpy as np
import math

import PIL
import time
import tensorflow.keras.layers as layers
import tensorflow.keras as keras
import tensorflow as tf
import matplotlib.pyplot as plt

parser = argparse.ArgumentParser()
parser.add_argument("--n_epochs", type=int, default=200, help="number of epochs of training")
parser.add_argument("--freq", type=int, default=1, help="number of epochs of saving")
parser.add_argument("--batch_size", type=int, default=256, help="size of the batches")
parser.add_argument("--buffer_size", type=int, default=60000, help="size of the buffers")
parser.add_argument("--lr", type=float, default=0.0002, help="adam: learning rate")
parser.add_argument("--n_cpu", type=int, default=8, help="number of cpu threads to use during batch generation")
parser.add_argument("--latent_dim", type=int, default=100, help="dimensionality of the latent space")
parser.add_argument("--img_size", type=int, default=28, help="size of each image dimension")
parser.add_argument("--channels", type=int, default=1, help="number of image channels")
parser.add_argument("--sample_interval", type=int, default=400, help="interval betwen image samples")
opt = parser.parse_args()
print(opt)

img_shape = (opt.img_size, opt.img_size, opt.channels)

# data load & preprocessing
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()
BUFFER_SIZE=train_images.shape[0]
train_images= train_images / 255.0
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_labels=tf.one_hot(train_labels,depth=10)
train_dataset = tf.data.Dataset.from_tensor_slices((train_images, train_labels)).shuffle(BUFFER_SIZE).batch(opt.batch_size,drop_remainder=True)
num_examples_to_generate = 16

# We will reuse this seed overtime (so it's easier)
# to visualize progress in the animated GIF)
seed = tf.random.normal([num_examples_to_generate, opt.latent_dim])

# define discriminator
class Discriminator(tf.keras.Model):
    def __init__(self, is_training=True):
        super(Discriminator, self).__init__(name='discriminator')
        self.is_training = is_training
        self.conv_1 = layers.Conv2D(64, 4,strides=2, padding='same')
        self.conv_2 = layers.Conv2D(128, 4,strides=2, padding='same')
        self.bn_1 = layers.BatchNormalization(trainable=self.is_training)
        self.bn_2 = layers.BatchNormalization(trainable=self.is_training)
        self.fc_1 = layers.Dense(1024)
        self.fc_2 = layers.Dense(1)

    def call(self, inputs, training):
        x = self.conv_1(inputs)
        x = layers.LeakyReLU(alpha=0.2)(x)
        x = self.conv_2(x)
        x = self.bn_1(x, training)
        x = layers.LeakyReLU(alpha=0.2)(x)
        x = layers.Flatten()(x)
        x = self.fc_1(x)
        x = self.bn_2(x, training)
        x = layers.LeakyReLU(alpha=0.2)(x)
        out_logits = self.fc_2(x)
        out = keras.activations.sigmoid(out_logits)
        return out, out_logits, x

class Generator(tf.keras.Model):
    def __init__(self, is_training=True):
        super(Generator, self).__init__(name='generator')
        self.is_training = is_training
        self.fc_1 = layers.Dense(1024)
        self.fc_2 = layers.Dense(128*7*7)
        self.bn_1 = layers.BatchNormalization(trainable=self.is_training)
        self.bn_2 = layers.BatchNormalization(trainable=self.is_training)
        self.bn_3 = layers.BatchNormalization(trainable=self.is_training)
        self.up_conv_1 = layers.Conv2DTranspose(64, 4, 2,padding='same')
        self.up_conv_2 = layers.Conv2DTranspose(1, 4, 2,padding='same')

    def call(self, inputs, training):
        x = self.fc_1(inputs)
        x = self.bn_1(x, training)
        x = layers.ReLU()(x)
        x = self.fc_2(x)
        x = self.bn_2(x, training)
        x = layers.ReLU()(x)
        x = layers.Reshape((7, 7, 128))(x)
        x = self.up_conv_1(x)
        x = self.bn_3(x, training)
        x = layers.ReLU()(x)
        x = self.up_conv_2(x)
        x = keras.activations.sigmoid(x)
        return x

class Classifier(tf.keras.Model):
    def __init__(self, y_dim, is_training=True):
        super(Classifier, self).__init__(name='classifier')
        self.is_training = is_training
        self.y_dim = y_dim
        self.fc_1 = layers.Dense(64)
        self.fc_2 = layers.Dense(self.y_dim)
        self.bn_1 = layers.BatchNormalization(trainable=self.is_training)

    def call(self, inputs, training):
        x = self.fc_1(inputs)
        x = self.bn_1(x, training)
        x = layers.LeakyReLU(alpha=0.2)(x)
        out_logits = self.fc_2(x)
        out=keras.layers.Softmax()(out_logits)
        return out, out_logits

def get_random_z(z_dim, batch_size):
    return tf.random.uniform([batch_size, z_dim], minval=-1, maxval=1)

# Initialize generator and discriminator and classifier
g = Generator()
d = Discriminator()
c = Classifier(10)
# Loss function
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

def generator_loss(fake_output):
    return  tf.reduce_mean(
            tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.ones_like(fake_output), logits=fake_output))

def discriminator_loss(real_output, fake_output):
    d_loss_real = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.ones_like(real_output), logits=real_output))
    d_loss_fake = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(labels=tf.zeros_like(fake_output), logits=fake_output))
    total_loss = d_loss_fake + d_loss_real
    return total_loss

def q_loss_fun(code_logit_real, code_logit_fake, batch_labels):
    q_real_loss = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(labels=batch_labels, logits=code_logit_real))
    q_fake_loss = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(labels=batch_labels, logits=code_logit_fake))
    q_loss = q_real_loss + q_fake_loss
    return q_loss

g_optimizer = keras.optimizers.Adam(lr=5 * opt.lr, beta_1=0.5)
d_optimizer = keras.optimizers.Adam(lr=opt.lr, beta_1=0.5)
q_optimizer = keras.optimizers.Adam(lr=5 * opt.lr, beta_1=0.5)
# metrics setting
g_loss_metrics = tf.metrics.Mean(name='g_loss')
d_loss_metrics = tf.metrics.Mean(name='d_loss')
q_loss_metrics = tf.keras.metrics.Mean('q_loss', dtype=tf.float32)

checkpoint_dir = './training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(step=tf.Variable(0),
                                              generator_optimizer=g_optimizer,
                                              discriminator_optimizer=d_optimizer,
                                              classifier_optimizer=q_optimizer,
                                              generator=g,
                                              discriminator=d,
                                              classifier=c)

@tf.function
def train_step(batch_images,batch_labels):
    z = get_random_z(opt.latent_dim, batch_images.shape[0])
    z_y = tf.concat([z, batch_labels], 1)
    real_images = batch_images

    with tf.GradientTape() as g_tape, tf.GradientTape() as d_tape, tf.GradientTape() as q_tape:
      fake_imgs = g(z_y, training=True)

      _, d_fake_logits, input4classifier_fake = d(fake_imgs, training=True)
      _, d_real_logits, input4classifier_real = d(real_images, training=True)

      g_loss = generator_loss(d_fake_logits)
      d_loss = discriminator_loss(d_real_logits, d_fake_logits)

      code_fake, code_logit_fake = c(input4classifier_fake, training=True)
      code_real, code_logit_real = c(input4classifier_real, training=True)
      q_loss = q_loss_fun(code_logit_real, code_logit_fake, batch_labels)

    gradients_of_d = d_tape.gradient(d_loss, d.trainable_variables)
    gradients_of_g = g_tape.gradient(g_loss, g.trainable_variables)
    # q loss backprop to all the trainable-variables

    trainable_variables_q = c.trainable_variables + d.trainable_variables + g.trainable_variables
    gradients_q = q_tape.gradient(q_loss, trainable_variables_q)

    d_optimizer.apply_gradients(zip(gradients_of_d, d.trainable_variables))
    g_optimizer.apply_gradients(zip(gradients_of_g, g.trainable_variables))
    q_optimizer.apply_gradients(zip(gradients_q, trainable_variables_q))
    return g_loss, d_loss, q_loss

# ----------
#  Training
# ----------
def train(dataset, epochs):
    for epoch in range(epochs):
        start = time.time()

        for batch_idx, (batch_images, batch_labels) in enumerate(dataset):
            g_loss, d_loss, q_loss = train_step(batch_images, batch_labels)
            g_loss_metrics(g_loss)
            d_loss_metrics(d_loss)
            q_loss_metrics(q_loss)

            template = '[Epoch{}/{}], Batch[{}/{}] D_loss={:.5f} G_loss={:.5f} q_loss={:.5f}'
            print(template.format(epoch, epochs, batch_idx, len(dataset), d_loss_metrics.result(),
                                  g_loss_metrics.result(), q_loss_metrics.result()))
            g_loss_metrics.reset_states()
            d_loss_metrics.reset_states()
            q_loss_metrics.reset_states()

        # Produce images for the GIF as we go
        generate_and_save_images(g,epoch + 1, seed)

        # Save the model every 15 epochs
        if (epoch + 1) % opt.freq == 0:
            checkpoint.save(file_prefix=checkpoint_prefix)

        print('Time for epoch {} is {} sec'.format(epoch + 1, time.time() - start))

    # # Generate after the final epoch
    generate_and_save_images(g,epochs,seed)

def generate_and_save_images(model, epoch, test_input):
    # Notice `training` is set to False.
    # This is so all layers run in inference mode (batchnorm).
    predictions = model(test_input, training=False)

    fig = plt.figure(figsize=(4, 4))

    for i in range(predictions.shape[0]):
        plt.subplot(4, 4, i + 1)
        plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')
        plt.axis('off')

    plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
    # plt.show()
if __name__ == "__main__":
    train(train_dataset,opt.n_epochs)
    # x = tf.random.uniform([2, 28,28,1], minval=-1, maxval=1)
    # y = tf.random.uniform([2, 10], minval=-1, maxval=1)
    # c = conv_cond_concat(x, y)
    # print(c.shape)


import os, re
from collections import deque

input_path = os.path.join(os.getcwd(),'9','input.txt')

data = open(input_path).read()

expression = re.compile('\d+')
result = expression.findall(data)
num_players, num_marbles = int(result[0]),int(result[1])
num_marbles *= 100
num_marbles += 1 # The input is in points, but there is an extra marble worth 0

scores = [0 for i in range(num_players)]
available = [i for i in reversed(range(num_marbles))]

circle = deque([])
marble = available.pop()
circle.append(marble)

def insert_marble(player):
    marble = available.pop()
    if marble % 23 != 0:
        if len(circle) > 1:
            circle.rotate(-2)

        circle.appendleft(marble)
    else:
        scores[player] += marble
        circle.rotate(7)
        scores[player] += circle.popleft()

while len(available) > 0:
    for i in range(num_players):
        if len(available) == 0:
            break
        insert_marble(i)
        # print(f'{i+1}: {circle}')

print('Scores:')
print(f'High Score: {max(scores)}')
#for i in range(num_players):
#    print(f'{i+1}: {scores[i]}')


import zmq
import cv2
import time
import sys

def collector1(port1, port2):
    """
    Receives images from port1, and send it to port2
    :param port1: port to receive from
    :param port2: port to send to
    :return: nothing
    """
    context = zmq.Context()
    collector1_rec = context.socket(zmq.PULL)
    collector1_rec.bind("tcp://127.0.0.1:%s" % port1)

    collector1_sender = context.socket(zmq.PUSH)
    collector1_sender.bind("tcp://*:%s" % port2)

    while True:
        msg = collector1_rec.recv_pyobj()
        print('msg received from consumer1')
        collector1_sender.send_pyobj(msg)
        print('msg sent to consumer2')
        time.sleep(1)

port1 = int(sys.argv[1])
port2 = int(sys.argv[2])
collector1(port1, port2)


import Graph
import Dashboard
import Run_Stations
from datetime import datetime

class coordinator():

    def __init__(self):
        self.base = Graph.graph()
        self.dash = Dashboard.dashboard()

    def Find_Index_Key(self,data,valor):
        return(data.index(valor))

    # ACCIONES CELDA DE MANUFACTURA
    def Start_Process(self):
        dash = self.dash
        base = self.base

        # Bring all the nodes type order with status Created
        orders_keys,orders_values = base.get_data_especific('order','State','Created')
        # If we dont have orders to run, notified
        if len(orders_values) == 0:
            return("Lo lamento, en este momento no hay ninguna orden para ejecutar")

        # Run the steps of the order created
        for order in orders_values:

            locations = eval(order[self.Find_Index_Key(orders_keys[0],'Locations')])
            ID = order[self.Find_Index_Key(orders_keys[0],'ID_Order')]
            amount = order[self.Find_Index_Key(orders_keys[0],'Amount')]
            piece = order[self.Find_Index_Key(orders_keys[0],'Piece')]
            steps,files,stations = base.get_steps(piece)

            # Update data
            base.update_data(ID,'order',['Running'],['State'])
            dash.Modified_Row(ID,'Running','Ordenes',1,8)
            create = 1
            progress = [0]*len(steps)

            if progress[-1] != amount:

                if (create <= len(steps)) and (create <= amount):
                    finish = Run_Stations.run_process(ID,files[:create],locations[0])
                    if finish:
                        for n in range(create):
                            progress[n]=+1
                        create=+1
                        locations.pop(0)
                    else:
                        #COMPLETAR LOGICA DE ERROR
                        return("Se presento un ERROR en la ejecución")

                else:
                    if progress[0] != amount:
                        finish = Run_Stations.run_process(ID,files[:len(steps)],locations[0])
                        if finish:
                            for n in range(len(progress)):
                                progress[n]=+1
                            if len(locations)==0:
                                locations =""
                            else:
                                locations.pop(0)
                        else:
                            #COMPLETAR LOGICA DE ERROR
                            return("Se presento un ERROR en la ejecución")
                    else:
                        progress.pop(0)
                        files.pop(0)
                        steps.pop(0)

            # Update data
            base.update_data(ID,'order',['Finished'],['State'])
            dash.Modified_Row(ID,'Finished','Ordenes',1,8)

            # INSERTA LOGICA DE BOTON APAGADO

    def get_orders(self): # Show all the orders
        base = self.base
        key,orders = base.get_data('order')
        f_orders =[]

        for i in orders:
            amount = i[self.Find_Index_Key(key[0],'Amount')]
            material = i[self.Find_Index_Key(key[0],'Material')]
            ID = i[self.Find_Index_Key(key[0],'ID_Order')]
            piece = i[self.Find_Index_Key(key[0],'Piece')]
            date = i[self.Find_Index_Key(key[0],'Create_Date')]
            state= i[self.Find_Index_Key(key[0],'State')]

            f_orders.append([ID,amount,material,piece,date,state])
        return(f_orders)

    def information_order(self,ID): # Get an especific order node
        base = self.base
        key,order = base.get_data_especific('order','Name',ID)

        return(key[0],order[0])

    def get_ID(self): # Get all the order IDs with state created
        base = self.base
        ID =[]
        key,values = base.get_data_especific('order','State','Created')
        index = self.Find_Index_Key(key[0],'ID_Order')

        for i in values:
            ID.append(i[index])

        return(ID)

    def get_storage(self): # Get Storage properties
        base = self.base
        key,value = base.get_data_especific('storage','Name','Storage')
        return(key[0],value[0])

    def create_order(self,material,piece,amount):
        dash = self.dash
        base = self.base
        keys,values= base.get_data_especific('material','Name',material)

        disponible = values[0]

        available = eval(disponible[self.Find_Index_Key(keys[0],'Available')]) # valor cantidad disponible material
        locations = eval(disponible[self.Find_Index_Key(keys[0],'Location')]) # Ubicaciones
        used = eval(disponible[self.Find_Index_Key(keys[0],'Used')]) # Usadas

        if (int(available == 0) or (int(available)< amount)):
            return(False,"")

        else:
            # Update locations
            location = locations[0:amount]
            del locations[0:amount]
            used.extend(location)
            available = int(available) - amount

            base.update_data(material,'material',[available,locations,used,str(datetime.now())],['Available','Location','Used','Update_Date'])

            # Create and Update Order
            data = base.create_order(material,amount,piece,location)
            dash.Add_End(data,'Ordenes')

            return(True,data)

    def delete_order(self,ID):
        dash = self.dash
        base = self.base

        # Bring order information
        order_k,order_v = self.information_order(ID)
        amount = eval(order_v[self.Find_Index_Key(order_k,'Amount')])
        material = order_v[self.Find_Index_Key(order_k,'Material')]
        location =  order_v[self.Find_Index_Key(order_k,'Locations')]

        # Bring materials information
        keys,values= base.get_data_especific('material','Name',material)

        disponible = values[0]
        available = eval(disponible[self.Find_Index_Key(keys[0],'Available')]) # valor cantidad disponible material
        locations = eval(disponible[self.Find_Index_Key(keys[0],'Location')]) # Ubicaciones
        used = eval(disponible[self.Find_Index_Key(keys[0],'Used')]) # Usadas

        available= int(available) + amount
        locations.extend(eval(location))
        new_used = [valor for valor in used if valor not in eval(location)]

        locations =sorted(locations, key=lambda x: (x[0], x[1]))

        # Update data information
        base.update_data(material,'material',[available,locations,new_used,str(datetime.now())],['Available','Location','Used','Update_Date'])

        # Delete order in data and dashboard
        base.delete_node('order',ID)
        dash.Delete_Row(ID,'Ordenes')

        return('La orden '+str(ID)+' fue eliminada con éxito')

    def modify_order(self,ID,piece,material,amount,cpiece,cmaterial,camount):
        # PREGUNTAR SI ES NECESARIO MODIFICAR EL ID
        dash = self.dash
        base = self.base

        # Bring order information
        order_k,order_v = self.information_order(ID)
        last_amount = int(order_v[self.Find_Index_Key(order_k,'Amount')])
        last_material = order_v[self.Find_Index_Key(order_k,'Material')]
        last_piece = order_v[self.Find_Index_Key(order_k,'Piece')]
        location =  order_v[self.Find_Index_Key(order_k,'Locations')]

        key_E,value_E= base.get_data_especific('material','Name','Empack')
        available_E = int(value_E[0][self.Find_Index_Key(key_E[0],'Available')]) # valor cantidad disponible material
        locations_E = eval(value_E[0][self.Find_Index_Key(key_E[0],'Location')]) # Ubicaciones
        used_E = eval(value_E[0][self.Find_Index_Key(key_E[0],'Used')]) # Usadas

        key_A,value_A= base.get_data_especific('material','Name','Aluminio')
        available_A = int(value_A[0][self.Find_Index_Key(key_A[0],'Available')]) # valor cantidad disponible material
        locations_A = eval(value_A[0][self.Find_Index_Key(key_A[0],'Location')]) # Ubicaciones
        used_A = eval(value_A[0][self.Find_Index_Key(key_A[0],'Used')]) # Usadas

        if cpiece:
            base.delete_relation('PIECE',ID,last_piece,'order',last_piece)
            base.relation('PIECE','order',piece,ID,piece)
            base.update_data(ID,'order',[piece,str(datetime.now())],['Piece','Update_Date'])
            dash.Modified_Row(ID,piece,'Ordenes',1,5) #piece

        if cmaterial & (not camount):  # If the material change but the amount not
            if last_material == 'Empack':
                if available_A==0 or available_A< amount :
                    return('Lo lamento no se puede modificar la orden por falta de material')
                else:
                    locations = locations_A[0:amount]

                    available_A = int(available_A) - amount
                    available_E = int(available_E) + amount

                    locations_E.extend(eval(location))
                    locations_E = sorted(locations_E, key=lambda x: (x[0], x[1]))
                    del locations_A[0:amount]

                    used_A.extend(locations)
                    used_A = sorted(used_A, key=lambda x: (x[0], x[1]))
                    used_E = [valor for valor in used_E if valor not in eval(location)]

                    base.update_data('Empack','material',[available_E,locations_E,used_E,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data('Aluminio','material',[available_A,locations_A,used_A,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data(ID,'order',[material,amount,locations,str(datetime.now())],['Material','Amount','Locations','Update_Date'])
                    dash.Modified_Row(ID,material,'Ordenes',1,4) #material
                    return('La orden '+str(ID)+' fue modificada con éxito')

            else:

                if available_E==0 or available_E< amount :
                    return('Lo lamento no se puede modificar la orden por falta de material')
                else:
                    locations = locations_E[0:amount]

                    available_A = int(available_A) + amount
                    available_E = int(available_E) - amount

                    locations_A.extend(eval(location))
                    locations_A = sorted(locations_A, key=lambda x: (x[0], x[1]))
                    del locations_E[0:amount]

                    used_E.extend(locations)
                    used_E = sorted(used_E, key=lambda x: (x[0], x[1]))
                    used_A = [valor for valor in used_A if valor not in eval(location)]

                    base.update_data('Empack','material',[available_E,locations_E,used_E,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data('Aluminio','material',[available_A,locations_A,used_A,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data(ID,'order',[material,amount,locations,str(datetime.now())],['Material','Amount','Locations','Update_Date'])
                    dash.Modified_Row(ID,material,'Ordenes',1,4) #material
                    return('La orden '+str(ID)+' fue modificada con éxito')

        if camount & (not cmaterial):  # If the amount change but the material not
            if last_material == 'Empack':
                if available_E==0 or (available_E+last_amount) < amount :
                    return('Lo lamento no se puede modificar la orden por falta de material')
                else:
                    locations_E.extend(eval(location))
                    locations_E = sorted(locations_E, key=lambda x: (x[0], x[1]))
                    locations = locations_E[0:amount]
                    del locations_E[0:amount]

                    available_E = int(available_E) + last_amount- amount

                    used_E = [valor for valor in used_E if valor not in eval(location)]
                    used_E.extend(locations)
                    used_E = sorted(used_E, key=lambda x: (x[0], x[1]))

                    base.update_data('Empack','material',[available_E,locations_E,used_E,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data(ID,'order',[material,amount,locations,str(datetime.now())],['Material','Amount','Locations','Update_Date'])
                    dash.Modified_Row(ID,amount,'Ordenes',1,6) #amount
                    dash.Modified_Row(ID,material,'Ordenes',1,4) #material
                    return('La orden '+str(ID)+' fue modificada con éxito')

            else:

                if available_A==0 or (available_A+last_amount) < amount :
                    return('Lo lamento no se puede modificar la orden por falta de material')
                else:
                    locations_A.extend(eval(location))
                    locations_A = sorted(locations_A, key=lambda x: (x[0], x[1]))
                    locations = locations_A[0:amount]
                    del locations_A[0:amount]

                    available_A = int(available_A) + last_amount- amount

                    used_A = [valor for valor in used_A if valor not in eval(location)]
                    used_A.extend(locations)
                    used_A = sorted(used_A, key=lambda x: (x[0], x[1]))

                    base.update_data('Aluminio','material',[available_A,locations_A,used_A,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data(ID,'order',[material,amount,locations,str(datetime.now())],['Material','Amount','Locations','Update_Date'])
                    dash.Modified_Row(ID,amount,'Ordenes',1,6) #amount
                    dash.Modified_Row(ID,material,'Ordenes',1,4) #material
                    return('La orden'+str(ID)+'fue modificada con éxito')

        if camount & cmaterial:  # If both changed
            if last_material == 'Empack':
                if available_A==0 or available_A< amount :
                    return('Lo lamento no se puede modificar la orden por falta de material')
                else:
                    locations_E.extend(eval(location))
                    locations_E = sorted(locations_E, key=lambda x: (x[0], x[1]))

                    locations = locations_A[0:amount]
                    del locations_A[0:amount]

                    available_A = int(available_A) - amount
                    available_E = int(available_E) + last_amount

                    used_A.extend(locations)
                    used_A = sorted(used_E, key=lambda x: (x[0], x[1]))
                    used_E = [valor for valor in used_E if valor not in eval(location)]

                    base.update_data('Empack','material',[available_E,locations_E,used_E,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data('Aluminio','material',[available_A,locations_A,used_A,str(datetime.now())],['Available','Location','Used','Update_Date'])
                    base.update_data(ID,'order',[material,amount,locations,str(datetime.now())],['Material','Amount','Locations','Update_Date'])
                    dash.Modified_Row(ID,amount,'Ordenes',1,6) #amount
                    dash.Modified_Row(ID,material,'Ordenes',1,4) #material
                    return('La orden '+str(ID)+' fue modificada con éxito')

            else:
                pass

    def modify_storage(self,name,data,propiedades): #modify storage properties
        base = self.base
        base.update_data(name,'storage',data,propiedades)
        return('El storage fue actualizado con éxito')
        # TENER EN CUENTA QUE LA NUEVA INFORMACION DEBE CUMPLIR CON LOS CRITERIOS

run = coordinator()

run.Start_Process()
#print(run.get_ID())
#print(run.information_order('AP1_2023_30_8_C5_H11_T33'))
#print(run.get_storage())
#print(run.get_orders())
#print(run.create_order('Aluminio',"Piece1",3))
#print(run.create_order('Empack',"Piece2",5))
#print(run.delete_order('AP1_2023_10_8_C5_H18_T22',5,'Aluminio','[[1, 1], [1, 2], [2, 1], [2, 2], [3, 1]]'))
#print(run.get_orders())
#print(run.modify_order('EP2_2023_10_8_C5_H21_T0','piece2','Empack',2,'piece2','Empack',3,False,False,True,'[[1, 3], [1, 4], [1, 5], [2, 3], [2, 4]]'))


from flask import Flask,request,render_template,session
from flask_session import Session

app=Flask(__name__)
# app.config["SESSION_PERMANENT"] = False
# app.config["SESSION_TYPE"] = "filesystem"

notes = []
# using counter to add ID's
counter = 0
@app.route('/post', methods=['POST'])
def event():
    if request.method == 'POST':
        note = request.form.get('note')
        new_note = {
            'id':counter,
            'todo':note
        }
        up()
        notes.append(new_note)
    return render_template("home.html", notes=notes)

@app.route('/', methods=['GET'])
def find():
    if request.method == 'GET':
        note = request.form.get('note')

    return render_template("home.html", notes=notes)

@app.route('/delete', methods=['POST'])
def delete():
        for note in notes:
            if id == request.form.get(id):
                notes.remove(note)

        return render_template("home.html", notes=notes)

def up():
    global counter
    counter += 1

if __name__ == "__main__":
    app.run()


import tensorflow as tf
from config import Config
import models
import numpy as np

class ActorCritic() :
    def __init__(self,sess,state_size,action_size,is_discrete) :
        self.input_size = [None]
        self.output_size = action_size
        self.is_discrete = is_discrete
        if(Config.network_type == 'lstm') :
            self.input_size.append(Config.timestamps)
        if(Config.use_pixels) :
            if(Config.network_type == 'mlp' or Config.network_type == 'lstm') :
                self.input_size.append(Config.resized_height * Config.resized_width)
            else :
                self.input_size.append(Config.resized_height)
                self.input_size.append(Config.resized_width)
                self.input_size.append(Config.stack_size)
        else :
            for shape in state_size :
                self.input_size.append(shape)

        self.sess = sess
        self.build_network()

    def init(self,writer=None) :
        self.writer = writer
        if(Config.actor_critic_type == 'seperate') :
            params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='actor') + tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='critic')
        else :
            params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='actor_critic')
        self.saver = tf.train.Saver(params)
        if(Config.start_timestep > 0) :
            self.load()

    def load(self) :
        dir = Config.root_dir + '/models/timestep-' + str(Config.start_timestep) + '/actor_critic/model.ckpt-' + str(Config.start_timestep)

        self.saver.restore(self.sess,dir)

    def save(self,dir,current_timestep) :
        self.saver.save(self.sess,dir + '/actor_critic/model.ckpt',global_step=current_timestep)

    def build_network(self) :
        if(self.is_discrete) :
            self.build_network_discrete()
            self.calc_loss(self.action_prob,self.action_old_prob)
        else :
            self.build_network_continuous()
            self.calc_loss(self.probs,self.old_probs)

    def build_actor_continuous(self) :
        base_network = self.build_base_network(self.state)
        mu_1 = tf.layers.dense(base_network,units=self.output_size,activation=tf.nn.tanh,kernel_initializer=tf.orthogonal_initializer(np.sqrt(2)))

        high = Config.env.env.action_space.high
        low = Config.env.env.action_space.low
        mu = (mu_1 * (high - low) + high + low) / 2

        log_sigma = tf.Variable(-0.5 * np.ones(self.output_size, dtype=np.float32))
        sigma = tf.exp(log_sigma)

        dist = tf.contrib.distributions.Normal(mu,sigma)
        self.action = tf.clip_by_value(dist.sample(),low,high,name='action')
        self.probs = dist.prob(self.action,name='probs')

        return base_network

    def build_network_continuous(self) :
        self.lr = tf.placeholder(shape=[],dtype=tf.float32,name='lr')
        self.advantage = tf.placeholder(shape=[None,1],dtype=tf.float32,name='advantage')
        self.old_probs = tf.placeholder(shape=[None,self.output_size],dtype=tf.float32,name='old_prob')
        self.reward = tf.placeholder(shape=[None,1],dtype=tf.float32,name='reward')
        self.old_preds = tf.placeholder(shape=[None,1],dtype=tf.float32,name='old_preds')
        self.state = tf.placeholder(shape=self.input_size,dtype=tf.float32,name='state')
        self.action = tf.placeholder(shape=[None,self.output_size],dtype=tf.float32,name='action')

        if(Config.actor_critic_type == 'seperate') :
            with tf.variable_scope('actor') as s:
                base_network = self.build_actor_continuous()
            with tf.variable_scope('critic') as s:
                self.build_critic(base_network)
        else :
            with tf.variable_scope('actor_critic') :
                base_network = self.build_actor_continuous()
                self.build_critic(base_network)

    def build_actor_discrete(self) :
        base_network = self.build_base_network(self.state)
        self.action_outputs = tf.layers.dense(base_network,units=self.output_size,activation=tf.nn.softmax,kernel_initializer=tf.orthogonal_initializer(np.sqrt(2)),name='action_outputs')

        action_one_hot = tf.one_hot(self.action,self.output_size)
        self.action_prob = action_one_hot * self.action_outputs
        self.action_old_prob = action_one_hot * self.old_probs
        return base_network

    def build_critic(self,base_network) :
        if(Config.actor_critic_type == 'seperate') :
            base_network_value = self.build_base_network(self.state)
        else :
            base_network_value = base_network
        self.value_outputs = tf.layers.dense(base_network_value,units=1,activation=None,kernel_initializer=tf.orthogonal_initializer(np.sqrt(2)),name='value_outputs')

    def build_network_discrete(self) :
        self.lr = tf.placeholder(shape=[],dtype=tf.float32,name='lr')
        self.action = tf.placeholder(shape=[None],dtype=tf.int64,name='action')
        self.advantage = tf.placeholder(shape=[None,1],dtype=tf.float32,name='advantage')
        self.reward = tf.placeholder(shape=[None,1],dtype=tf.float32,name='reward')
        self.old_preds = tf.placeholder(shape=[None,1],dtype=tf.float32,name='old_preds')
        self.old_probs = tf.placeholder(shape=[None,self.output_size],dtype=tf.float32,name='old_probs')
        self.state = tf.placeholder(shape=self.input_size,dtype=tf.float32,name='state')

        if(Config.actor_critic_type == 'seperate') :
            with tf.variable_scope('actor') as s:
                base_network = self.build_actor_discrete()
            with tf.VariableScope('critic') as s:
                self.build_critic(base_network)
        else :
            with tf.variable_scope('actor_critic') as s:
                base_network = self.build_actor_discrete()
                self.build_critic(base_network)

    def build_base_network(self,x,output_size=None,output_activation=None,output_name=None) :
        if(Config.use_pixels) :
            if(Config.network_type == 'mlp') :
                return models.create_network_pixels_mlp(x,Config.mlp_hidden_layers,Config.mlp_hidden_units,tf.nn.tanh,output_size,output_activation,output_name)
            elif(Config.network_type == 'conv2d') :
                return models.create_network_pixels_conv(x,Config.conv_layers,Config.conv_units,Config.kernel_size,Config.strides,tf.nn.relu,Config.mlp_hidden_layers,Config.mlp_hidden_units,tf.nn.relu,output_size,output_activation,output_name)
            elif(Config.network_type == 'lstm')  :
                return models.create_network_lstm(x,Config.lstm_layers,Config.lstm_units,Config.unit_type,Config.mlp_hidden_layers,Config.mlp_hidden_units,tf.nn.tanh,output_size,output_activation,output_name)
        elif(Config.network_type == 'mlp') :
            return models.create_mlp_network(x,Config.mlp_hidden_layers,Config.mlp_hidden_units,tf.nn.tanh,output_size,output_activation,output_name)
        elif(Config.network_type == 'lstm') :
            return models.create_network_lstm(x,Config.lstm_layers,Config.lstm_units,Config.unit_type,Config.mlp_hidden_layers,Config.mlp_hidden_units,tf.nn.tanh,output_size,output_activation,output_name)
        else :
            raise Exception('Unable to create base network,check config')

    def clip_by_global_norm(self,loss,optimizer,clip,scope) :
        params = tf.trainable_variables(scope)
        gradients, variables = zip(*optimizer.compute_gradients(loss,params))
        gradients, _ = tf.clip_by_global_norm(gradients, clip)
        optimize = optimizer.apply_gradients(zip(gradients, variables))
        return optimize

    def calc_loss(self,action_prob,action_old_prob) :
        ratio = action_prob / (tf.maximum(1e-10,action_old_prob))
        policy_unclipped = -ratio * self.advantage
        policy_clipped = -tf.clip_by_value(ratio,1-Config.epsilon,1+Config.epsilon) * self.advantage
        policy_loss = tf.reduce_mean(tf.maximum(policy_unclipped,policy_clipped))

        #value_clipped = self.old_preds + tf.clip_by_value(self.value_outputs - self.old_preds, - Config.epsilon, Config.epsilon)
        #value_loss_unclipped = tf.square(self.value_outputs - self.reward)
        #value_loss_clipped = tf.square(value_clipped - self.reward)

        #value_loss = 0.5 * tf.reduce_mean(tf.maximum(value_loss_unclipped, value_loss_clipped))

        entropy = -tf.reduce_mean(tf.reduce_sum(action_prob * tf.log(tf.maximum(action_prob,1e-10)), 1),0)
        if(Config.actor_critic_type == 'seperate') :
            actor_loss = policy_loss - Config.entropy * entropy
            value_loss = 0.5 * tf.reduce_mean(tf.square(self.value_outputs - self.reward))
            actor_optimizer = tf.train.AdamOptimizer(learning_rate=self.lr)
            actor_optimizer = self.clip_by_global_norm(actor_loss,actor_optimizer,Config.gradient_clip,'actor')
            critic_optimizer = tf.train.AdamOptimizer(learning_rate=self.lr)
            critic_optimizer = self.clip_by_global_norm(value_loss,critic_optimizer,Config.gradient_clip,'critic')
            self.optimizer = [actor_optimizer,critic_optimizer]
        else :
            value_clipped = self.old_preds + tf.clip_by_value(self.value_outputs - self.old_preds, - Config.epsilon, Config.epsilon)
            value_loss_unclipped = tf.square(self.value_outputs - self.reward)
            value_loss_clipped = tf.square(value_clipped - self.reward)

            value_loss = 0.5 * tf.reduce_mean(tf.maximum(value_loss_unclipped, value_loss_clipped))
            loss = policy_loss - Config.entropy * entropy + value_loss * 0.5

            optimizer = tf.train.AdamOptimizer(learning_rate=self.lr)
            self.optimizer = self.clip_by_global_norm(loss,optimizer,Config.gradient_clip,'actor_critic')

        if(Config.with_summary) :
            self.policy_loss_summary = tf.summary.scalar(name='policy_loss', tensor=policy_loss)
            self.value_loss_summary = tf.summary.scalar(name='value_loss', tensor=value_loss)
            self.entropy_summary = tf.summary.scalar(name='entropy', tensor=entropy)
            #self.loss_summary = tf.summary.scalar(name='loss', tensor=loss)

    def predict_value(self,state) :
        values = self.sess.run(self.value_outputs,feed_dict={self.state:state})
        return values.reshape(values.shape[0])

    def predict_action(self,state) :
        if(self.is_discrete) :
            action_probs = self.sess.run(self.action_outputs,feed_dict={self.state:state})
            action_probs = action_probs.reshape([action_probs.shape[1]])
            action = np.random.choice(range(len(action_probs)),p=action_probs)
            return action,action_probs
        else :
            action = self.sess.run(self.action,feed_dict={self.state:state})
            action_probs = self.sess.run(self.probs,feed_dict={self.state:state,self.action:action})
            return action[0],action_probs[0]

    def train(self,batch,current_timestep) :
        current_update = current_timestep / Config.buffer_size
        total_updates = Config.timesteps / Config.buffer_size
        frac = 1.0 - (current_update - 1.0) / total_updates
        lr = Config.actor_learning_rate(frac)
        #lr = Config.actor_learning_rate
        states,rewards,actions,old_probs,advantages,old_preds = batch

        advantages = (advantages - advantages.mean()) / (advantages.std() + 1e-6)

        randomize = np.arange(len(states))
        for epoch in range(Config.epochs) :
            if(Config.use_shuffle and Config.network_type != 'lstm') :
                np.random.shuffle(randomize)
            for index in range(int(Config.buffer_size/Config.batch_size)) :

                batch_states,batch_advantages,batch_old_probs,batch_actions,batch_rewards,batch_old_preds = self.prepare_batch(states,advantages,old_probs,actions,rewards,old_preds,index,randomize)
                if(Config.with_summary) :
                    policy_loss_t,value_loss_t,entropy_t,_ = self.sess.run([self.policy_loss_summary,self.value_loss_summary,self.entropy_summary,self.optimizer],feed_dict={self.state:batch_states,self.advantage:batch_advantages
                        ,self.old_probs:batch_old_probs,self.action:batch_actions,self.reward:batch_rewards,self.old_preds:batch_old_preds,self.lr:lr})
                    if(index == int(Config.buffer_size/Config.batch_size)-1 and epoch == Config.epochs-1) :
                        self.writer.add_summary(policy_loss_t)
                        self.writer.add_summary(value_loss_t)
                        self.writer.add_summary(entropy_t)
                        #self.writer.add_summary(loss)
                else :
                    self.sess.run(self.optimizer,feed_dict={self.state:batch_states,self.advantage:batch_advantages
                        ,self.old_probs:batch_old_probs,self.action:batch_actions,self.reward:batch_rewards,self.old_preds:batch_old_preds,self.lr:lr})

    def prepare_batch(self,states,advantages,old_probs,actions,rewards,old_preds,current_batch,randomize) :
        current_index = int(current_batch * Config.batch_size)
        batch_states = states[current_index : current_index + Config.batch_size]
        batch_advantages = advantages[current_index : current_index + Config.batch_size]
        batch_old_probs = old_probs[current_index : current_index + Config.batch_size]
        batch_actions = actions[current_index : current_index + Config.batch_size]
        batch_rewards = rewards[current_index : current_index + Config.batch_size]
        batch_old_preds = old_preds[current_index : current_index + Config.batch_size]

        return batch_states,batch_advantages,batch_old_probs,batch_actions,batch_rewards,batch_old_preds


# python3
# -*- coding: utf-8 -*-
# @Time    : 2022/8/14 13:15
# @Author  : yzyyz
# @Email   :  youzyyz1384@qq.com
# @File    : path.py
# @Software: PyCharm
from pathlib import Path

LOCAL = Path() / "教务工具"
SCORE_PATH = LOCAL / "score"
CONFIG_PATH = Path() / 'config.yml'
ACCOUNT_PATH = LOCAL / 'account.yml'
OUTPUT_PATH = LOCAL / 'output'
IMG_OUTPUT_PATH = LOCAL / 'img_output'


import time
import logging

logging.basicConfig(filename="timing.log", level=logging.INFO, filemode="w")

def timer(funct):
    start_time = time.time()
    res = funct()
    end_time = time.time()
    exect_time = end_time - start_time
    logging.info(f"Функція '{funct.__name__}' виконана за {exect_time} секунд")
    return res, exect_time

def sleep():
    time.sleep(2)
    return "<result>"

result, execution_time = timer(sleep)
print(f"Результат: {result}")
print(f"Час виконання: {int(execution_time)} секунд")