import requests
import json
import os
from pprint import pformat

url = "https://statsapi.mlb.com/api/v1/"

lookup_api_endpoints = [
    f"{url}awards",
    f"{url}baseballStats",
    f"{url}conferences",
    f"{url}divisions",
    f"{url}eventTypes",
    f"{url}fielderDetailTypes",
    f"{url}gameStatus",
    f"{url}gameTypes",
    f"{url}highLow/types",
    f"{url}hitTrajectories",
    f"{url}jobTypes",
    f"{url}languages",
    f"{url}league",
    f"{url}leagueLeaderTypes",
    f"{url}logicalEvents",
    f"{url}metrics",
    f"{url}pitchCodes",
    f"{url}pitchTypes",
    f"{url}playerStatusCodes",
    f"{url}positions",
    f"{url}reviewReasons",
    f"{url}rosterTypes",
    f"{url}runnerDetailTypes",
    f"{url}scheduleEventTypes",
    f"{url}seasons?sportId=1",
    f"{url}situationCodes",
    f"{url}sky",
    f"{url}sports",
    f"{url}standings?leagueId=103,104",
    f"{url}standingsTypes",
    f"{url}statGroups",
    f"{url}statTypes",
    f"{url}teams",
    f"{url}venues",
    f"{url}windDirection",
]

def mkdir_p(file_name):
    """
    Create any (sub)folders needed for filepath.
    """
    full_folder_path = os.path.dirname(file_name)
    if not os.path.exists(full_folder_path):
        os.makedirs(full_folder_path)
        print(f"Created folder: {full_folder_path}")

def load_lookup_tables(folder_path = "scrapper/lookups/api/"):
    """
    Download Lookup Tables from MLB Stats API.

    :param folder_path: Folder path to save json files
    :param type: Str
    """
    for lookup_url in lookup_api_endpoints:
        file_name = os.path.join(folder_path, lookup_url[len(url):] + ".json")
        mkdir_p(file_name)
        with open(file_name, "w") as file:
            json_response = json.loads(requests.get(lookup_url).text)
            json.dump(json_response, file, indent=4, sort_keys=True)

def lookupByValue(map, value):
    """
    Lookup the key associated with a value in map.

    :param map: A mapping of keys to values, typically ids to names/descriptions.
    :param type: Dict[Str,Str]
    :param value: A value in map.
    :param type: Str
    """
    if value is None:
        return value
    for k, v in map.items():
        if value in v:
            return k
    raise Exception(f"Key not found! Value: {value}, Map: {map}")

load_lookup_tables()


import os
import sys
import argparse
import subprocess
import time
import platform
import signal
import inspect
from datetime import datetime
import psutil

mosquitto_ip_default     = '127.0.0.1'      # ip address of the mosquitto server'
mosquitto_path_default   = ''               # path to directory of the mosquitto executable')
robot_name_default       = 'stickman'       # name of the robot (stickman,pepper,nao)')
robot_ip_default         = '127.0.0.1'      # help='ip address of the robot')
robot_conda_env_default  = ""                # conda environment used for robot')
message_default          = '"Hello World"'    # message to be spoken by the robot')
video_file_default       = 'video.mp4'      # path to the video input file')
vosk_model_path_default  = os.path.join(os.path.expanduser("~"),".sobotify","vosk","models") # path to vosk_model')
keyword_default          = 'apple tree'     # key word to activate vosk listener')
data_path_default        = os.path.join(os.path.expanduser("~"),".sobotify","data") # 'path to movement/speech data')
language_default         = 'english'        # choose language (english,german)')
min_speech_speed_default = 70              # minimum speech speed of robot
max_speech_speed_default = 110             # maximum speech speed of robot')
ffmpeg_path_default      = os.path.join(os.path.expanduser("~"),".sobotify","ffmpeg","bin") # directory path to ffmpeg tools (bin directory)
sound_device_default     = 0               # number of sound device, can be found with: import sounddevice;sounddevice.query_devices()')
llm_name_default         = 'dummy'         # name of the llm api
llm_options_default      = ''              # llm options
show_video_default       = "on"            # show video during emotion detection
show_stickman_default    = "on"            # show stickman during emotion detection
frame_rate_default       = 1               # frame rate for emotion detection
cam_device_default       = "0"             # camera device for emotion detection
text_default             = ""              # text to checked for grammar
URL_default              = "http://localhost:8081/v2/check" # LanguageTool server URL
languagetool_path_default = os.path.join(os.path.expanduser("~"),".sobotify","languagetool")
java_path_default         = os.environ.get("JAVA_HOME","")
if java_path_default:
    java_path_default     = os.path.join(java_path_default,"bin")
robot_options_default     = ""

if os.path.isfile(os.path.join(os.path.expanduser("~"),"miniconda3","condabin","conda.bat")):
	conda_exe=os.path.join(os.path.expanduser("~"),"miniconda3","condabin","conda.bat")
elif os.path.isfile(os.path.join(os.path.expanduser("~"),"AppData","Local","miniconda3","condabin","conda.bat")):
	conda_exe=os.path.join(os.path.expanduser("~"),"AppData","Local","miniconda3","condabin","conda.bat")
else :
	print ("Cannot find Conda executable path. Abort")
	exit()

class sobotify (object) :

    def __init__(self,start_mqtt_server=True,app_name="app",start_mqtt_client=True,mosquitto_path=mosquitto_path_default,mosquitto_ip=mosquitto_ip_default,debug=False,log=False) :
        print ("init sobotify")
        self.debug=debug
        self.analyze_proc=0
        self.mosquitto_proc=0
        self.rocontrol_proc=0
        self.speech_recognition_proc=0
        self.llm_proc=0
        self.robot_done_flag=False
        self.statement_pending=False
        self.statement = ""
        self.dominant_emotion_available=False
        self.dominant_emotion = ""
        self.grammar_checking_result_available=False
        self.grammar_checking_result = ""
        self.start_mqtt_client=start_mqtt_client
        self.init_speech_recognition_done_flag = False
        self.init_chatbot_done_flag = False
        self.init_robot_done_flag = False
        self.init_facial_processing_done_flag = False
        self.init_grammar_checking_done_flag =True
        self.init_logging_server_done_flag=False
        self.log_enabled=log
        self.init_teleoperator_done_flag =False
        self.language=language_default
        self.sound_device=sound_device_default
        self.partial_text_pending=False

        if start_mqtt_server==True:
            self.start_mosquitto(mosquitto_path)
        if self.start_mqtt_client==True :
            from sobotify.commons.mqttclient import mqttClient
            self.mqtt_client = mqttClient(mosquitto_ip,app_name)
        if self.log_enabled==True :
            self.start_logging_server()
            from sobotify.tools.logger import LoggerClient
            self.logger=LoggerClient(self.mqtt_client)

    def stop_service(self,service):
        if not service==None:
            try:
                project_process=psutil.Process(service.pid)
                project_children=project_process.children(recursive=True)
                print(project_children)
                for child in project_children:
                    try:
                        #print(f"kill process {child.name} with pid: {child.pid}")
                        child.kill()
                    except:
                        #print(f"process {child.name} with pid: {child.pid} already finished")
                        pass
                try:
                    #print(f"kill process with pid: {self.project_proc.pid}")
                    service.kill()
                except:
                    #print(f"process with pid: {self.project_proc.pid} already finished")
                    pass
            except:
                #print(f"process with pid: {self.project_proc.pid} does not exist (anymore)")
                pass
        else:
            #print("no process to kill")
            pass
        service=None

    def log(self,message,topic=""):
        if self.log_enabled==True :
            self.logger.message(message,topic,level=2)

    def subscribe_face_detection(self,callback):
        self.mqtt_client.subscribe("robot_control/command/follow_head",callback)

    def subscribe_face_name(self,callback):
        self.mqtt_client.subscribe("facial_processing/name",callback)

    def subscribe_chatbot(self,callback):
         self.mqtt_client.subscribe("llm/reply",callback)

    def subscribe_listener(self,callback):
         self.mqtt_client.subscribe("speech-recognition/statement",callback)

    def store_statement(self,statement) :
        self.statement = statement
        print("got statement from human: "+ self.statement)
        self.statement_pending=True

    def store_partial_text(self,partial_text) :
        self.partial_text = partial_text
        #print("got statement from human: "+ self.statement)
        self.partial_text_pending=True

    def robot_done(self,message) :
        print("got info robot is done: "+ message)
        self.robot_done_flag=True

    def wait_for_robot(self):
        self.mqtt_client.subscribe("robot/done",self.robot_done)
        print("waiting for robot to finish ...")
        while not self.robot_done_flag==True:
            time.sleep(1)
        self.robot_done_flag=False
        print(" ... done")

    def reply_from_listener(self):
            self.mqtt_client.subscribe("speech-recognition/partial-text",self.store_partial_text)
            timestamp=datetime.now()
            while not self.statement_pending:
                time.sleep(1)
                if self.partial_text_pending==True:
                    timestamp=datetime.now()
                    self.partial_text_pending=False
                waiting_time=(datetime.now()-timestamp).total_seconds()
                print ("waiting time=",waiting_time)
                if waiting_time > 12:  ## service not responding ==> restart
                    self.stop_service(self.speech_recognition_proc)
                    self.start_listener(language=self.language,sound_device=self.sound_device)
                    time.sleep(0.5)
                    if self.language=="english":
                        self.speak("Sorry, I couldn't listen to you. Could you please say that again?")
                    if self.language=="german":
                        self.speak("Entschuldige, leider konnte ich dir nicht zuhören. Kannst du das bitte wiederholen?")
                    self.mqtt_client.publish("speech-recognition/control/record/start","")
                    return False
            return True

    def listen(self,listen_to_keyword=False,keyword=keyword_default,detect_emotion=False):
        if (listen_to_keyword==True) :
            self.mqtt_client.publish("speech-recognition/control/record/listen_to_keyword",keyword)
        else :
            if detect_emotion:
                self.detect(command="start")
            self.mqtt_client.subscribe("speech-recognition/statement",self.store_statement)
            self.mqtt_client.publish("speech-recognition/control/record/start","")
            while not self.reply_from_listener():
                time.sleep(0.2)
            self.statement_pending=False
            if detect_emotion:
                emotion=self.detect(command="stop")
                return self.statement, emotion
            else:
                return self.statement

    def speak(self,message,gesture="",speed=0,detect_emotion=False):
        if detect_emotion:
            self.detect(command="start")
        if  (speed==0) :
            self.mqtt_client.publish("robot/control/set-min-speed",min_speech_speed_default)
            self.mqtt_client.publish("robot/control/set-max-speed",max_speech_speed_default)
        else :
            self.mqtt_client.publish("robot/control/set-speed",speed)
        if gesture:
            message=gesture+"|"+message
        self.mqtt_client.publish("robot/speak-and-gesture",message)
        self.wait_for_robot()
        if detect_emotion:
            emotion=self.detect(command="stop")
            return emotion

    def chat(self,message):
         self.mqtt_client.publish("llm/query",message)

    def store_dominant_emotion(self,dominant_emotion) :
        self.dominant_emotion = dominant_emotion
        print("got dominant_emotion: "+ self.dominant_emotion)
        self.dominant_emotion_available=True

    def detect(self,command,type="emotion"):
        if command=="start":
            if type=="emotion":
                self.mqtt_client.publish("facial_processing/start")
        elif command=="stop":
            if type=="emotion":
                self.mqtt_client.publish("facial_processing/stop")
                self.mqtt_client.subscribe("facial_processing/dominant_emotion",self.store_dominant_emotion)
                while not self.dominant_emotion_available:
                    time.sleep(1)
                self.dominant_emotion_available=False
                return self.dominant_emotion

    def teleoperate(self,timeout=10,blocking=True):
        self.mqtt_client.publish("teleoperator/command/start")
        if blocking==True:
            time.sleep(timeout)
            self.mqtt_client.publish("teleoperator/command/stop")

    def stop_teleoperation(self):
        self.mqtt_client.publish("teleoperator/command/stop")

    def store_grammar_check_result(self,result) :
        self.grammar_checking_result = result
        print("got grammar check result: "+ self.grammar_checking_result)
        self.grammar_checking_result_available=True

    def grammar_check(self,text):
        self.mqtt_client.publish("grammar_checking/text",text)
        self.mqtt_client.subscribe("grammar_checking/result",self.store_grammar_check_result)
        while not self.grammar_checking_result_available:
            time.sleep(1)
        self.grammar_checking_result_available=False
        return self.grammar_checking_result

    def start_extract(self,video_file=video_file_default,data_path=data_path_default,robot_name=robot_name_default,
                      ffmpeg_path=ffmpeg_path_default,vosk_model_path=vosk_model_path_default,language=language_default,show_video=show_video_default):
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        arguments=[sys.executable,os.path.join(sobotify_path,'tools','extract','extract.py')]
        arguments.extend(('--video_file',video_file))
        arguments.extend(('--robot_name',robot_name))
        arguments.extend(('--ffmpeg_path',ffmpeg_path))
        arguments.extend(('--vosk_model_path',vosk_model_path))
        arguments.extend(('--data_path',data_path))
        arguments.extend(('--language',language))
        arguments.extend(('--show_video',show_video))
        if self.debug==True:
            print (*arguments)
        self.analyze_proc=subprocess.Popen(arguments)
        print ('started gesture/speech analysis, pid=',self.analyze_proc.pid)

    def start_mosquitto(self,mosquitto_path=mosquitto_path_default):
        if platform.system()=="Windows":
            if mosquitto_path=="":
                mosquitto_path="C:\Program Files\mosquitto"
            full_mosquitto_path=mosquitto_path+"\mosquitto.exe"
        elif platform.system()=="Linux":
            if mosquitto_path=="":
                full_mosquitto_path="mosquitto"
            else :
                full_mosquitto_path=mosquitto_path+"/mosquitto"
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        arguments=[full_mosquitto_path]
        arguments.append("-v")
        arguments.extend(('-c',os.path.join(sobotify_path,'tools','mosquitto.conf')))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.mosquitto_proc=subprocess.Popen(arguments,stdout=subprocess.PIPE, creationflags=creationflags)
        time.sleep(3)
        print ('started mosquitto, pid=',self.mosquitto_proc.pid)

   ########################################################################################################
    def init_teleoperator_done(self,message) :
        print("got init done: "+ message)
        self.init_teleoperator_done_flag =True

    def wait_for_init_teleoperator_done(self):
        self.mqtt_client.subscribe("teleoperator/status/init-done",self.init_teleoperator_done)
        print("waiting for logging server to finish initalization ...")
        while not self.init_teleoperator_done_flag==True:
            time.sleep(0.5)
        print(" ... done")

    def start_teleoperator(self,mqtt=True,mosquitto_ip=mosquitto_ip_default,robot_name=robot_name_default,cam_device=cam_device_default,frame_rate=frame_rate_default,show_video=show_video_default,show_stickman=show_stickman_default):
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','teleoperator.py')
        arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        arguments.extend(('--robot_name',robot_name))
        arguments.extend(('--cam_device',cam_device))
        arguments.extend(('--frame_rate',str(frame_rate)))
        arguments.extend(('--show_video',show_video))
        arguments.extend(('--show_stickman',show_stickman))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.teleoperator_proc=subprocess.Popen(arguments,creationflags=creationflags)
        print ('started teleoperator, pid=',self.teleoperator_proc.pid)
        if mqtt== True:
            self.wait_for_init_teleoperator_done()

    ########################################################################################################
    def init_logging_server_done(self,message) :
        print("got init done: "+ message)
        self.init_logging_server_done_flag =True

    def wait_for_init_logging_server_done(self):
        self.mqtt_client.subscribe("logging_server/status/init-done",self.init_logging_server_done)
        print("waiting for logging server to finish initalization ...")
        while not self.init_logging_server_done_flag==True:
            time.sleep(0.5)
        print(" ... done")

    def start_logging_server(self,mqtt=True,mosquitto_ip=mosquitto_ip_default):
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','logger.py')
        arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.logging_server_proc=subprocess.Popen(arguments,creationflags=creationflags)
        print ('started logging server, pid=',self.logging_server_proc.pid)
        if mqtt== True:
            self.wait_for_init_logging_server_done()

    ########################################################################################################
    def init_robot_done(self,message) :
        print("got init done: "+ message)
        self.init_robot_done_flag =True

    def wait_for_init_robot_done(self):
        self.mqtt_client.subscribe("robot/status/init-done",self.init_robot_done)
        print("waiting for robot to finish initalization ...")
        while not self.init_robot_done_flag==True:
            time.sleep(1)
        print(" ... done")

    def start_robotcontroller(self,mqtt=True,mosquitto_ip=mosquitto_ip_default,robot_name=robot_name_default,robot_ip=robot_ip_default,
                           robot_options=robot_options_default,cam_device=cam_device_default,robot_conda_env=robot_conda_env_default,data_path=data_path_default,language=language_default,
                           min_speech_speed=min_speech_speed_default,max_speech_speed=max_speech_speed_default,message=message_default) :
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','robotcontrol','robotcontrol.py')
        if robot_conda_env == "" :
            if robot_name.lower() == "pepper" or robot_name.lower() == "nao" :
                robot_conda_env = "sobotify_naoqi"
        if not robot_conda_env == "" :
            arguments=[conda_exe]
            arguments.append("run")
            arguments.extend(('-n',robot_conda_env))
            arguments.append("--no-capture-output")
            arguments.append("python")
            arguments.append(script_path)
        else :
            arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        arguments.extend(('--robot_name',robot_name))
        arguments.extend(('--message',message))
        arguments.extend(('--robot_ip',robot_ip))
        arguments.extend(('--robot_options','"'+robot_options+'"'))
        arguments.extend(('--data_path',data_path))
        arguments.extend(('--language',language))
        arguments.extend(('--min_speech_speed',str(min_speech_speed)))
        arguments.extend(('--max_speech_speed',str(max_speech_speed)))
        arguments.extend(('--cam_device',cam_device))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.rocontrol_proc=subprocess.Popen(arguments,creationflags=creationflags)
        #rocontrol_proc=subprocess.Popen(arguments)
        print ('started robot controller, pid=',self.rocontrol_proc.pid)
        if mqtt== True:
            self.wait_for_init_robot_done()

    ########################################################################################################
    def init_speech_recognition_done(self,message) :
        print("got init done: "+ message)
        self.init_speech_recognition_done_flag =True

    def wait_for_init_speech_recognition_done(self):
        self.mqtt_client.subscribe("speech-recognition/status/init-done",self.init_speech_recognition_done)
        print("waiting for speech recognition to finish initalization ...")
        while not self.init_speech_recognition_done_flag==True:
            time.sleep(1)
        print(" ... done")

    def start_listener(self,mqtt=True,mosquitto_ip=mosquitto_ip_default,vosk_model_path=vosk_model_path_default,language=language_default,
                                 keyword=keyword_default,sound_device=sound_device_default):
        self.language=language
        self.sound_device=sound_device
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','speech_recognition.py')
        arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        arguments.extend(('--vosk_model_path',vosk_model_path))
        arguments.extend(('--language',language))
        arguments.extend(('--keyword',keyword))
        arguments.extend(('--sound_device',str(sound_device)))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.speech_recognition_proc=subprocess.Popen(arguments,creationflags=creationflags)
        print ('started speech recognition, pid=',self.speech_recognition_proc.pid)
        if mqtt== True:
            self.wait_for_init_speech_recognition_done()

    ########################################################################################################
    def init_chatbot_done(self,message) :
        print("got init done: "+ message)
        self.init_chatbot_done_flag =True

    def wait_for_init_chatbot_done(self):
        self.mqtt_client.subscribe("llm/status/init-done",self.init_chatbot_done)
        print("waiting for chatbot to finish initalization ...")
        while not self.init_chatbot_done_flag==True:
            time.sleep(1)
        print(" ... done")

    def start_chatbot(self,mqtt=True,mosquitto_ip=mosquitto_ip_default,llm_name=llm_name_default,
                      llm_options=llm_options_default):
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','chatbot.py')
        arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        arguments.extend(('--llm_name',llm_name))
        arguments.extend(('--llm_options','"'+llm_options+'"'))

        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.llm_proc=subprocess.Popen(arguments,creationflags=creationflags)
        print ('started chatbot, pid=',self.llm_proc.pid)
        if mqtt== True:
            self.wait_for_init_chatbot_done()

    ########################################################################################################
    def init_facial_processing_done(self,message) :
        print("got init done: "+ message)
        self.init_facial_processing_done_flag =True

    def wait_for_init_facial_processing_done(self):
        self.mqtt_client.subscribe("facial_processing/status/init-done",self.init_facial_processing_done)
        print("waiting for facial_processing to finish initalization ...")
        while not self.init_facial_processing_done_flag==True:
            time.sleep(1)
        print(" ... done")

    def start_facial_processing(self,mqtt=True,mosquitto_ip=mosquitto_ip_default,robot_name=robot_name_default,robot_ip=robot_ip_default,cam_device=cam_device_default,frame_rate=frame_rate_default,show_video=show_video_default):
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','facial_processing.py')
        arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        arguments.extend(('--robot_name',robot_name))
        arguments.extend(('--robot_ip',robot_ip))
        arguments.extend(('--cam_device',cam_device))
        arguments.extend(('--frame_rate',str(frame_rate)))
        arguments.extend(('--show_video',show_video))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.facial_processing_proc=subprocess.Popen(arguments,creationflags=creationflags)
        print ('started facial processing, pid=',self.facial_processing_proc.pid)
        if mqtt== True:
            self.wait_for_init_facial_processing_done()

    ########################################################################################################
    def init_grammar_checking_done(self,message) :
        print("got init done: "+ message)
        self.init_grammar_checking_done_flag =True

    def wait_for_init_grammar_checking_done(self):
        self.mqtt_client.subscribe("grammar_checking/status/init-done",self.init_grammar_checking_done)
        print("waiting for grammar_checking to finish initalization ...")
        while not self.init_grammar_checking_done_flag==True:
            time.sleep(1)
        print(" ... done")

    def start_grammar_checking(self,mqtt=True,mosquitto_ip=mosquitto_ip_default,languagetool_path=languagetool_path_default,java_path=java_path_default,language=language_default,URL=URL_default,text=text_default):
        sobotify_path=os.path.dirname(os.path.abspath(__file__))
        script_path=os.path.join(sobotify_path,'tools','grammar_checking.py')
        arguments=[sys.executable,script_path]
        if mqtt== True:
            arguments.extend(('--mqtt',"on"))
        arguments.extend(('--mosquitto_ip',mosquitto_ip))
        arguments.extend(('--language',language))
        arguments.extend(('--languagetool_path',languagetool_path))
        arguments.extend(('--java_path',java_path))
        arguments.extend(('--languagetool_url',URL))
        arguments.extend(('--text',text))
        if self.debug==True:
            print (*arguments)
            creationflags=subprocess.CREATE_NEW_CONSOLE
        else:
            creationflags=subprocess.CREATE_NO_WINDOW
        self.grammar_checking_proc=subprocess.Popen(arguments,creationflags=creationflags)
        print ('started grammar checking, pid=',self.grammar_checking_proc.pid)
        if mqtt== True:
            self.wait_for_init_grammar_checking_done()
    ########################################################################################################

    def terminate(self):
        if not self.analyze_proc==0: self.analyze_proc.kill()
        if not self.mosquitto_proc==0: self.mosquitto_proc.kill()
        if not self.speech_recognition_proc==0: self.speech_recognition_proc.kill()
        if not self.llm_proc==0: self.llm_proc.kill()
        if not self.rocontrol_proc==0: self.rocontrol_proc.kill()

def handler(signal_received, frame):
    # Handle cleanup here
    print('SIGINT or CTRL-C detected. Exiting gracefully')
    sobot.terminate()
    exit(0)

def handler2(signal_received, frame):
    # Handle cleanup here
    print('SIGINT or CTRL-C detected. Exiting gracefully')
    sobot.terminate()
    exit(0)

if __name__ == "__main__":
    signal.signal (signal.SIGINT,handler)
    signal.signal (signal.SIGTERM,handler2)

    parser=argparse.ArgumentParser(prog='sobotify',description='The Social Robot Framework')
    parser.add_argument('-d',default="false",action="store_true",help='debug')
    parser.add_argument('-e',default="false",action="store_true",help='start gesture/speech extract tool')
    parser.add_argument('-m',default="false",action="store_true",help='start mosquitto')
    parser.add_argument('-r',default="false",action="store_true",help='start robot controller')
    parser.add_argument('-l',default="false",action="store_true",help='start listener (speech recognition)')
    parser.add_argument('-c',default="false",action="store_true",help='start chatbot')
    parser.add_argument('-f',default="false",action="store_true",help='start facial processing')
    parser.add_argument('-g',default="false",action="store_true",help='start grammar checker')
    parser.add_argument('--mosquitto_ip',default='127.0.0.1',help='ip address of the mosquitto server')
    parser.add_argument('--mosquitto_path',default='',help='path to directory of the mosquitto executable')
    parser.add_argument('--robot_name',default='stickman',help='name of the robot (stickman,pepper,nao)')
    parser.add_argument('--robot_ip',default='127.0.0.1',help='ip address of the robot')
    parser.add_argument('--robot_options',default='',help='robot specific options')
    parser.add_argument('--robot_conda_env',default="",help='conda environment used for robot')
    parser.add_argument('--message',default='Hello World',help='message to be spoken by the robot')
    parser.add_argument('--video_file',default='video.mp4',help='path to the video input file')
    parser.add_argument('--vosk_model_path',default=os.path.join(os.path.expanduser("~"),".sobotify","vosk","models"),help='path to vosk_model')
    parser.add_argument('--keyword',default='apple tree',help='key word to activate speech recognition')
    parser.add_argument('--data_path',default=os.path.join(os.path.expanduser("~"),".sobotify","data"),help='path to movement/speech data')
    parser.add_argument('--language',default="english",help='choose language (english,german)')
    parser.add_argument('--min_speech_speed',default=70,help='minimum speech speed of robot')
    parser.add_argument('--max_speech_speed',default=110,help='maximum speech speed of robot')
    parser.add_argument('--ffmpeg_path',default=os.path.join(os.path.expanduser("~"),".sobotify","ffmpeg","bin"),help='directory path to ffmpeg tools (bin directory)')
    parser.add_argument('--sound_device',default=0,type=int,help='number of sound device, can be found with: import sounddevice;sounddevice.query_devices()')
    parser.add_argument('--llm_name',default="dummy",help='name of llm api')
    parser.add_argument('--llm_options',default="",help='options for llm')
    parser.add_argument('--text',default='',help='Text to be checked by the grammar checker')
    parser.add_argument('--languagetool_path',default=os.path.join(os.path.expanduser("~"),".sobotify","languagetool"),help='directory path to LanguageTool')
    parser.add_argument('--java_path',default=os.path.join(os.environ["JAVA_HOME"],"bin"),help='directory path to java executable')
    parser.add_argument('--languagetool_url',default=URL_default,help='URL of LanguageTool server')
    parser.add_argument('--cam_device',default='0',help='camera device name or number for emotion detection')
    parser.add_argument('--frame_rate',default=1,type=float,help='frame rate for emotion detection')
    parser.add_argument('--show_video',default="on",help='enable/disable video output of emotion detection or gesture extraction on screen')
    args=parser.parse_args()

    sobot = sobotify(start_mqtt_server=args.m,start_mqtt_client=False, mosquitto_path=args.mosquitto_path,debug=args.d)

    if args.e==True:
        sobot.start_extract(args.video_file,args.data_path,args.robot_name,args.ffmpeg_path,args.vosk_model_path,args.language,args.show_video)
    if args.r==True:
        sobot.start_robotcontroller(args.m,args.mosquitto_ip,args.robot_name,args.robot_ip,args.robot_options,args.cam_device,args.robot_conda_env,args.data_path,args.language,args.min_speech_speed,args.max_speech_speed, args.message)
    if args.l==True:
        sobot.start_listener(args.m,args.mosquitto_ip,args.vosk_model_path,args.language,args.keyword,args.sound_device)
    if args.c==True:
        sobot.start_chatbot(args.m,args.mosquitto_ip,args.llm_name,args.llm_options)
    if args.f==True:
        sobot.start_facial_processing(args.m,args.mosquitto_ip,args.robot_name,args.robot_ip,args.cam_device,args.frame_rate,args.show_video)
    if args.g==True:
        sobot.start_grammar_checking(args.m,args.mosquitto_ip,args.languagetool_path,args.java_path,args.language,args.languagetool_url,args.text)

    while(True):
        time.sleep(1000)


from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.webdriver.remote.webelement import WebElement
import schedule
import time
import re

def apply_jobs_dice():
    # Initialize the driver
    driver = webdriver.Chrome()

    # Open dice.com login page
    driver.get("https://www.dice.com/dashboard/login")

    # Find the username and password input fields and enter the credentials
    print("Enter email")
    username_input = driver.find_element(By.ID,"email")
    password_input = driver.find_element(By.ID,"password")

    username_input.send_keys("sumanbcloud@gmail.com")
    password_input.send_keys("Dice1234")
    password_input.send_keys(Keys.ENTER)

    # Wait for the dashboard to load
    wait = WebDriverWait(driver, 20)

    # wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "dashboard-page-container")))
    # Wait for the page to load
    time.sleep(5)

    # Search for jobs with the keyword "Dynatrace"
    keyword = ['dynatrace consultant', 'dynatrace engineer', 'application performance monitoring', 'splunk engineer', 'devops', 'infrastructure performance monitoring']
    search_box = driver.find_element(By.XPATH, "//*[@id='typeaheadInput']")
    for key in keyword:
        search_box.send_keys(key)
        search_box.send_keys(Keys.RETURN)

        # Wait for the search results to load
        time.sleep(5)

        # Filter with jobs that are posted today
        today_button = driver.find_element(By.XPATH,"//*[@id='facets']/dhi-accordion[2]/div[2]/div/js-single-select-filter/div/div/button[2]").click()
        # last_seven_button = driver.find_element(By.XPATH,"//*[@id='facets']/dhi-accordion[2]/div[2]/div/js-single-select-filter/div/div/button[4]").click()

        # Filter with "Easy Apply" jobs only
        easy_apply_button = driver.find_element(By.XPATH,"//*[@id='singleCheckbox']/span/button/i")
        easy_apply_button.click()

        # find the select element for item view per page
        select_element = Select(driver.find_element(By.XPATH,"//*[@id='pageSize_2']"))

        # select the desired item view option
        select_element.select_by_value('100')  # change to the value of your desired option

        # wait for the page to reload with the new item view
        time.sleep(3)

        links = driver.find_elements(By.TAG_NAME,"a")
        print("Links by Class : ", links)

        counter=1

        for link in links:
            print("===================================================")
            print(link)

            try:
                href = link.get_attribute("href")
                if "https://www.dice.com/job-detail/" in href:
                    print("HREF: ", href)
                    driver.execute_script("window.open('" + href + "', '_blank');")
                    print("In Loop: ", counter)

                    # Switch to the new tab
                    driver.switch_to.window(driver.window_handles[-1])

                    # Navigate to the href link
                    driver.get(href)

                    # Wait for the page to load
                    time.sleep(3)
                else:
                    continue
            except:
                print("Failed at href: ", href)
                continue

            try:
                # Click on "Easy Apply" and wait for the page to load
                easy_apply_button = driver.find_element(By.XPATH,"//*[@id='__next']/div/main/header/div/div/div[4]/div[2]/div[2]").click()
                # easy_apply_button.click()
                print("clicked on EASY APPLY BUTTON")
                time.sleep(5)

                # Click on "Next" and wait for the page to load
                next_button = driver.find_element(By.XPATH,"//*[@id='app']/div/span/div/main/div[4]/button[2]").click()
                # next_button.click()
                print("clicked on NEXT BUTTON")
                time.sleep(5)

                # Click on "Apply" and wait for the page to load
                apply_button = driver.find_element(By.XPATH,"//*[@id='app']/div/span/div/main/div[3]/button[2]").click()
                # apply_button.click()
                print("clicked on APPLY BUTTON")
                time.sleep(5)

                # # Check if the application was submitted successfully
                # success_message = driver.find_element(By.XPATH,'//div[contains(text(), "You have successfully applied")]')
                # if success_message:
                print("Successfully Submitted")

                # Close the tab
                driver.close()

                # Switch back to the main tab
                driver.switch_to.window(driver.window_handles[0])
                counter = counter +1
                continue  # go to the next job if application was submitted successfully

            except:
                # Close the tab
                print("Already Applied or Not Easy Apply")
                driver.close()

                # Switch back to the main tab
                driver.switch_to.window(driver.window_handles[0])
                counter = counter +1
                continue  # go to the next job if application was submitted successfully

            # except:
            #     print("Failed on Easy Apply Button")
            #     # driver.back()
            #     continue

        # Close the browser
        driver.quit()

# schedule the script to run every 6 hours
schedule.every(3).hours.do(apply_jobs_dice)

while True:
    schedule.run_pending()
    time.sleep(1)


from flask import Blueprint

from .api import create_request_events_bp, create_requests_bp
from .ui import create_ui_blueprint

blueprint = Blueprint("invenio-requests-ext", __name__)

@blueprint.record_once
def init(state):
    """Register the module's services and indexers to the central registries."""
    svc_reg = state.app.extensions["invenio-records-resources"].registry
    idx_reg = state.app.extensions["invenio-indexer"].registry
    requests_ext = state.app.extensions["invenio-requests"]
    requests_service = requests_ext.requests_service
    events_service = requests_ext.request_events_service

    svc_reg.register(requests_service)
    svc_reg.register(events_service)

    idx_reg.register(requests_service.indexer, indexer_id="requests")
    idx_reg.register(events_service.indexer, indexer_id="events")

__all__ = (
    "blueprint",
    "create_ui_blueprint",
    "create_requests_bp",
    "create_request_events_bp",
)


# My attempt at point cloud clustering
# Author: Harris Mohamed

from __future__ import print_function # Python 2/3 compatibility
import boto3
import json
import decimal
import sys
import os
import ast
from boto3.dynamodb.conditions import Key, Attr
from subprocess import call
import numpy as np
import heapq
from ast import literal_eval
import random

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

import RANSAC.RANSAC as ransac
import KALMAN as kalman

dynamodb = boto3.resource('dynamodb', region_name='us-east-2', endpoint_url='http://dynamodb.us-east-2.amazonaws.com')
table = dynamodb.Table('SENTINEL')

def readFromAWS(name):
        """ Grabs all scans associated with a certain name

            Args:
                Name we are interested in
            Return:
                A list of dictionaries
        """

        output = []

        response = table.query(KeyConditionExpression=Key('Name').eq(name))

        for scan in response['Items']:
            output.append(scan)

        return output

# Lines to handle python class
if __name__=="__main__":
    output = readFromAWS('hallway_scan_3-8-2020')

scan = 'arc_test1_2'

curr_scan = readFromAWS(scan)

for data in curr_scan:
    data['euler'] = kalman.Gravity([[float(data['Ax'])], [float(data['Ay'])], [float(data['Az'])]]).__repr__()

curr_coordinates = ransac.ConvertToCartesianEulerAngles(curr_scan)

actual_coordinates = []

for key, value in curr_coordinates.items():
    hold = []
    for coordinate in value:
        hold.append(coordinate[0])
    actual_coordinates.append(hold)

# Helper function to find distance between points
def distPoints(p0, p1):
    return (np.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2 + (p0[2] - p1[2])**2))

# Point cloud clustering begins here
CLUSTER_POINTS = 1000
clusters = {}
normal_vectors = {}
center_points = []

# Populate both the dictionaries
# clusters is a dict where the key is the center point and the value is the list of points associated with the cluster
# normal_vectors is a dict where the key is the center point and the value is the normal vector associated with the cluster
while len(actual_coordinates) != 0:

    # Pick a random point to find the cluster of
    random_point_idx = random.randrange(0, len(actual_coordinates))
    random_point = actual_coordinates[random_point_idx]
    actual_coordinates.remove(random_point)

    # Find the closest points to make the cluster with
    closest_points_buffer= []
    heapq.heapify(closest_points_buffer)

    # This step is expensive, but oh well
    for point in actual_coordinates:
        heapq.heappush(closest_points_buffer, (distPoints(random_point, point), point))

    # Can't form a cluster with less than 3 points, just discard it
    if (len(actual_coordinates) < 3):
        break

    # If we don't have enough points left, we will use what is left for the last cluster
    if (len(actual_coordinates) < CLUSTER_POINTS):
        CLUSTER_POINTS = len(actual_coordinates)

    cluster_buffer = []
    cluster_buffer.append(random_point)

    # Populate the cluster buffer array and find the center point at the same time(ish)
    x_val = 0
    y_val = 0
    z_val = 0
    for i in range(CLUSTER_POINTS):
        curr_min = heapq.heappop(closest_points_buffer)[1]
        x_val = x_val + curr_min[0]
        y_val = y_val + curr_min[1]
        z_val = z_val + curr_min[2]
        cluster_buffer.append(curr_min)
        actual_coordinates.remove(curr_min)

    # Find the actual center point
    x_avg = (x_val + cluster_buffer[0][0]) / (CLUSTER_POINTS + 1)
    y_avg = (y_val + cluster_buffer[0][1]) / (CLUSTER_POINTS + 1)
    z_avg = (z_val + cluster_buffer[0][2]) / (CLUSTER_POINTS + 1)
    center_point = [x_avg, y_avg, z_avg]

    # Find the point that is the closest to the center point
    min_dist = 999999999
    min_point = cluster_buffer[0]
    for i in range(CLUSTER_POINTS + 1):
        dist_calc = distPoints(cluster_buffer[i], center_point)
        if (dist_calc < min_dist):
            min_dist = dist_calc
            min_point = cluster_buffer[i]

    # Now find the normal vector associated with each cluster
    x_coor = []
    y_coor = []
    z_coor = []
    tmp_A = []
    tmp_B = []

    for i in range(CLUSTER_POINTS + 1):
        curr_point = cluster_buffer[i]
        x_coor.append(curr_point[0])
        y_coor.append(curr_point[1])
        z_coor.append(curr_point[2])

    for i in range(CLUSTER_POINTS + 1):
        tmp_A.append([x_coor[i], y_coor[i], 1])
        tmp_B.append(z_coor[i])
    b = np.matrix(tmp_B).T
    A = np.matrix(tmp_A)
    orig_output = (A.T * A).I * A.T * b
    normal_vec = [orig_output[0,0], orig_output[1,0], -1, orig_output[2,0]]

    # normal_vec is of form [a, b, c]
    # But the plane is of form Ax + By - z = -C
    # Normalize the normal vector
    magnitude = np.sqrt(normal_vec[0]**2 + normal_vec[1]**2 + normal_vec[2]**2)
    normalized = [(normal_vec[0] / magnitude), (normal_vec[1] / magnitude), (normal_vec[2] / magnitude), normal_vec[3]]

    # Store the cluster
    clusters[str(center_point)] = cluster_buffer
    normal_vectors[str(center_point)] = normalized
    center_points.append(center_point)

    # print("The cluster contains: ")
    # for i in cluster_buffer:
    #     print(str(i))

    # print(" ")
    # print("The center point of the cluster is: ")
    # print(str(center_point))

    # print(" ")
    # print("The center point I found is: ")
    # print(str(min_point))

    # print(" ")
    # print("The plane I found is: ")
    # print(str(orig_output[0,0]) + "x + " + str(orig_output[1,0]) + "y + 1 = -" + str(orig_output[2,0]))

    # print(" ")
    # print("The normal vector representing the cluster is: ")
    # print(str(normal_vec))

    # print(" ")
    # print("The normalized vector is: ")
    # print(str(normalized))
    # break

features = {}

current_center_point_idx = random.randrange(0, len(center_points))
current_center_point = center_points[current_center_point_idx]
current_cluster_points = clusters[str(current_center_point)]
current_normal = normal_vectors[str(current_center_point)]

# Set the first feature to the randomly selected cluster
features[str(current_normal)] = current_cluster_points
center_points.remove(current_center_point)

while len(center_points) != 0:
    # Find the closest cluster to the current one
    min_point = center_points[0]
    min_dist = 999999999
    for point in center_points:
        dist_calc = distPoints(point, current_center_point)
        if (dist_calc < min_dist):
            min_dist = dist_calc
            min_point = point

    closest_cluster = clusters[str(min_point)]
    closest_normal = normal_vectors[str(min_point)]
    center_points.remove(min_point)

    # MIGHT NEED TO ADD LOGIC TO ENSURE THEY ARE NEIGHBORS. For now, I will proceed with the assumption that they are neighbors.
    # To carry out the above comment, check the angle between the vector that connects the points and the average normal vector

    FOUND = False
    # Check which of the existing features the closest normal matches up with
    for key, value in features.items():
        feature_normal = literal_eval(key)

        # Find the angle between the normal vectors of the feature and the closest cluster
        angle = np.degrees(np.arccos(feature_normal[0]*closest_normal[0] + feature_normal[1]*closest_normal[1] + feature_normal[2]*closest_normal[2]))

        ANGLE_THRESHOLD = 70

        # If the conditions are met, it is combined with the current feature
        if (angle < ANGLE_THRESHOLD):
            avg_normal = [((feature_normal[0] + closest_normal[0]) / 2), ((feature_normal[1] + closest_normal[1]) / 2), ((feature_normal[2] + closest_normal[2]) / 2), ((feature_normal[3] + closest_normal[3]) / 2)]
            features[str(avg_normal)] = features[str(feature_normal)]
            features[str(avg_normal)].append(clusters[str(min_point)])
            del features[str(feature_normal)]
            FOUND = True
            break

    # If FOUND has not been changed, we have found a new feature
    if FOUND == False:
        features[str(closest_normal)] = clusters[str(min_point)]

    # No matter what, update the current center point
    current_center_point = min_point

print("Number of features found: " + str(len(features)))

for key, value in features.items():
    print("Features found: " + key)
    # print("Coordinates found: " + str(value))
# random_cl_point_idx = random.randrange(0, len(center_points))
# random_cl_point = center_points[random_cl_point_idx]
# cluster_points = clusters[str(random_cl_point)]
# cluster_normal = normal_vectors[str(random_cl_point)]
# features[str(cluster_normal)] = cluster_points
# center_points.remove(random_cl_point)

# # Loop through the points
# while len(center_points) != 0:

#     # Find the closest cluster to the one we are looking at
#     min_point = center_points[0]
#     min_dist = 9999999
#     for point in center_points:
#         dist_calc = distPoints(point, random_cl_point)
#         if (dist_calc < min_dist):
#             min_dist = dist_calc
#             min_point = point

#     center_points.remove(min_point)

#     ANGLE_THRESHOLD = 45
#     # If the vector between the center points is perpendicular to the
#     for key, value in features.items():
#         # First check the angle between the normal vectors
#         normal_vec_feature = literal_eval(key)
#         normal_vec_min = normal_vectors[str(min_point)]
#         angle = np.degrees(np.arccos(normal_vec_feature[0]*normal_vec_min[0] + normal_vec_feature[1]*normal_vec_min[1] + normal_vec_feature[2]*normal_vec_min[2]))

#         # If the if statement is satisfied, then the vectors are part of the same feature
#         if (angle < ANGLE_THRESHOLD) or (angle > 180 - ANGLE_THRESHOLD):
#             avg_normal = [((normal_vec_feature[0] + normal_vec_min[0]) / 2), ((normal_vec_feature[1] + normal_vec_min[1]) / 2), ((normal_vec_feature[2] + normal_vec_min[2]) / 2)]
#             hold = features[str(normal_vec_feature)]
#             features[str(avg_normal)] = hold.append(clusters[str()])
#         # Otherwise, it's a new feature
#         else:

#     # Check the angle between the normal vectors
#     normal_vec_random_cl = normal_vectors[str(random_cl_point)]
#     normal_vec_min = normal_vectors[str(min_point)]

#     angle = np.degrees(np.arccos(normal_vec_random_cl[0]*normal_vec_min[0] + normal_vec_random_cl[1]*normal_vec_min[1] + normal_vec_random_cl[2]*normal_vec_min[2]))


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

################################################################################################
# 题目：输入两个正整数m和n，求其最大公约数和最小公倍数。
# 方法一：利用分解因数法
################################################################################################

# from MyClass.SimpleTool import factorization
# import time
#
#
# def lcm(m, n):
#     m_prime_list, n_prime_list, divisor_list = factorization(m), factorization(n), []
#     m_list, n_list = m_prime_list[:], n_prime_list[:]
#     for divisor in m_prime_list:
#         if divisor in n_prime_list:
#             divisor_list.append(divisor)
#             n_prime_list.remove(divisor)
#     for divisor in divisor_list:
#         m_list.remove(divisor)
#         n_list.remove(divisor)
#     divisor_list = divisor_list + m_list + n_list
#     lcm_num = 1
#     for divivsor in divisor_list:
#         lcm_num = lcm_num * divivsor
#     return lcm_num
#
#
# def gcd(m, n):
#     m_prime_list, n_prime_list, divisor_list = factorization(m), factorization(n), []
#     for divisor in m_prime_list:
#         if divisor in n_prime_list:
#             divisor_list.append(divisor)
#             n_prime_list.remove(divisor)
#     gcd_num = 1
#     for divisor in divisor_list:
#         gcd_num = gcd_num * divisor
#     return gcd_num

################################################################################################
# 题目：输入两个正整数m和n，求其最大公约数和最小公倍数。
# 方法二：利用欧几里德算法，效率比分解因式法高很多
################################################################################################

def gcd(m, n):
    while m != 0:
        m, n = n % m, m
    return n

def lcm(m, n):
    divisor = gcd(m, n)
    return int(m * n / divisor)

while True:
    m = input("please input the 1st number: ")
    n = input("please input the 2nd number: ")
    try:
        m, n = int(m), int(n)
    except ValueError:
        print("numbers should be integer!", end="\n\n")
    else:
        if m < 1 or n < 1:
            print("numbers should be greater than 0!")
        else:
            print("gcd is: %d" % gcd(m, n))
            print("lcm is: %d" % lcm(m, n), end="\n\n")


from unittest.mock import patch

from pandas.util.testing import assert_frame_equal

import performance.billing as billing
from performance.tests.fixtures import get_sample_verifications_by_rp_dataframe, get_sample_rp_mapping
from performance import prod_config as config

@patch('os.path.exists', return_value=True)
@patch('pandas.read_csv')
@patch('performance.billing.get_report_file')
def test_extract_verifications_with_local_rp_csv_for_date(mock_get_report,
                                                          mock_pandas_read_csv, mock_path_exists):
    date_start = '2018-07-02'
    expected_verification_csv_filepath_to_load = f'{config.VERIFY_DATA_PIPELINE_CONFIG_PATH}/data/verifications/verifications_by_rp_2018-07-02_2018-07-08.csv'  # noqa

    billing.extract_verifications_by_rp_csv_for_date(date_start)

    mock_get_report.assert_not_called()
    mock_pandas_read_csv.assert_called_with(expected_verification_csv_filepath_to_load)

@patch('os.path.exists', side_effect=[False, True])  # File does not exist but data/verifications directory does
@patch('pandas.read_csv', return_value={})
@patch('performance.billing.get_report_file')
def test_retrieve_report_file_from_s3_when_no_local_exists(mock_get_report, mock_pandas_read_csv, mock_path_exists):
    date_start = '2018-07-02'
    file_name = 'verifications_by_rp_2018-07-02_2018-07-08.csv'
    s3_path = f'rp/{file_name}'
    destination_path = f'{config.VERIFY_DATA_PIPELINE_CONFIG_PATH}/data/verifications/{file_name}'

    billing.extract_verifications_by_rp_csv_for_date(date_start)

    mock_get_report.assert_called_with(config.S3_BILLING_REPORTS_BUCKET, s3_path, destination_path)

@patch('performance.billing.config.rp_mapping', get_sample_rp_mapping())
def test_augment_verifications_by_rp_with_rp_name():
    sample_verifications_by_rp = get_sample_verifications_by_rp_dataframe()
    expected_transformed_data = get_sample_verifications_by_rp_dataframe(with_rp_name=True)

    billing.augment_verifications_by_rp_with_rp_name(sample_verifications_by_rp)
    assert_frame_equal(expected_transformed_data, sample_verifications_by_rp)


class Solution:
    def isPalindrome(self, s: str) -> bool:
        res=True
        l=[]
        for i in range(len(s)):
            if 65<=ord(s[i])<=90 or 97<=ord(s[i])<=122:
                l.append(s[i].lower())
            elif 48<=ord(s[i])<=57:
                l.append(s[i])
            else:
                continue
        for i in range(len(l)):
            if l[i]!=l[(len(l))-1-i]:
                res = False
            else:
                continue
        return res


#!/usr/bin/env python
# -*- coding: utf-8 -*-

""" __init__.py: tohback """

from tohback import TOHBack
import sources

__author__ = "Abhay Arora ( @BeliefLimitless )"
__copyright__ = "Copyright (c) 2015 Abhay Arora."
__email__ = "belieflimitless@icloud.com"
__date__ = "18/10/15"

__all__ = [TOHBack, sources]


# -*- coding: UTF-8 -*-

from fastapi import APIRouter, Request
from starlette.templating import Jinja2Templates

router = APIRouter()

templates = Jinja2Templates(directory="static")

@router.get('/',include_in_schema=False)
async def root(request: Request):
    return templates.TemplateResponse("index.html",{"request": request})


import pytest

from flatbot.notifications import Notifier
from flatbot.tracking.manager import Manager
from flatbot.tracking.tracker import Tracker, TrackerFactory

@pytest.fixture
def mock_tracker_factory(config, async_return, mocker, mock_storage, mock_scraper):
    def get_factory(tracker):
        factory = mocker.Mock(spec=TrackerFactory)
        factory.get.return_value = async_return(tracker)
        return factory
    return get_factory

@pytest.fixture
def mock_notifier(mocker):
    notifier = mocker.Mock(spec=Notifier)
    return notifier

@pytest.fixture
def mock_tracker(async_return, mocker):
    tracker = mocker.Mock(spec=Tracker)
    tracker.id = 1

    tracker.add.return_value = async_return(None)
    tracker.remove.return_value = async_return(None)
    tracker.cancel.return_value = async_return(None)
    tracker.active = False

    return tracker

async def test_manager(config, mock_tracker_factory, mock_tracker, mock_notifier):
    config = config('config_full.yml')
    factory = mock_tracker_factory(mock_tracker)
    manager = Manager(factory, mock_notifier, config)

    await manager.track('kuba', 'url')
    mock_tracker.add.assert_called_once_with('kuba')

    await manager.untrack('kuba', 'url')
    mock_tracker.remove.assert_called_once_with('kuba')
    mock_tracker.cancel.assert_called_once_with()

@pytest.mark.slow
def test_manager_db():
    # manager = Manager()
    pass


'''
MeTube Statistics
Let’s create a video platform such as YouTube. It will be called MeTube. Your task is to store videos, videos’ views and likes.
You will be receiving lines in the following format: "{videoName}-{views}" until you receive "stats time". You should store video and its views, if the video already exists add the views to it.
You can receive a command to rate a video in the following format: "like:{video}" or "dislike:{video}". The like command will give a single like whereas the dislike command will remove a like, but the given video needs to exist.
After receiving "stats time" you will receive an order criterion – either "by views" or "by likes". If you receive "by views" order the videos by views in descending order, otherwise order the videos by likes in descending order.
Print each of the videos in the following format:
"{video} - {views} views - {likes} likes"
Input
•	Until you receive " stats time " you will be receiving videos in the following format: "{video}-{views}".
•	You can receive a rate command -> "like {video}" or "dislike {video}".
•	After "stats time" you will receive either "by views" or "by likes".
Output
•	Print the statistics for each video in the following format:  "{video} - {views} views - {likes} likes"
Constraints
•	The views will be a valid integer in the range [1-1000].
•	The video's name will not contain dashes ('-') or colon (':').
•	Allowed working time / memory: 100ms / 16MB.
Examples
Input
Eninem Venom-500
like:Eninem Venom
Funny Cats-700
like:Funny Cats
like:Funny Cats
Eninem Venom-300
stats time
by likes
Output
Funny Cats - 700 views - 2 likes
Eninem Venom - 800 views - 1 likes
Eminem Ringer-300
Messi Top Goals-500

like:Eminem Ringer
like:Eminem Ringer
dislike:Eminem Ringer
stats time
by views
Output
Messi Top Goals - 500 views - 0 likes
Eminem Ringer - 300 views - 1 likes

'''

class Movie:
    def __init__(self, name, views, likes):
        self.Name = name
        self.Views = views
        self.Likes = likes

    def dislike(self):
        self.Likes = self.Likes - 1

    def like(self):
        self.Likes = self.Likes + 1

    def update_views(self, views):
        self.Views = self.Views + views

    def print_self(self):
        print(f"{str(self.Name)} - {str(self.Views)} views - {str(self.Likes)} likes")

movies = {}

line = input()

while line != "stats time":
    tokens_movies = [x for x in line.split('-')]

    if len(tokens_movies) == 1:
        tokens_likes = [x for x in line.split(':')]
        if tokens_likes[0] == "like":
            name_inp = tokens_likes[1]
            movies[name_inp].like()
        if tokens_likes[0] == "dislike":
            name_inp = tokens_likes[1]
            movies[name_inp].dislike()
    else:
        views_inp = int(tokens_movies[1])
        name_inp = tokens_movies[0]
        likes_inp = int(0)
        if name_inp not in movies:
            movies[name_inp] = Movie(name_inp, views_inp, likes_inp)
        else:
            movies[name_inp].update_views(views_inp)

    line = input()
else:
    command = input()
    if command == "by views":
        sorted_dict = sorted(movies.values(), key=lambda x: -x.Views)
        for row in sorted_dict:
            row.print_self()
    elif command == "by likes":
        sorted_dict = sorted(movies.values(), key=lambda x: -x.Likes)
        for row in sorted_dict:
            row.print_self()


import re
import string
import os
from collections import defaultdict
import joblib
import pickle

import pandas as pd
import numpy as np

import torch

import nltk
# download the required resources if necessary
try:
    from nltk.stem import WordNetLemmatizer
except:
    # i'm lazy; this was easier than looking up the minimum packages needed
    nltk.download('all')
    from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import pkg_resources
from symspellpy import SymSpell, Verbosity

try:
    LEMMATIZER = WordNetLemmatizer()
    STOP_WORDS = set(stopwords.words('english'))
except:
    nltk.download('all')
    LEMMATIZER = WordNetLemmatizer()
    STOP_WORDS = set(stopwords.words('english'))
SYM_SPELL = SymSpell(max_dictionary_edit_distance=3, prefix_length=7)
SYM_SPELL.load_dictionary(
    pkg_resources.resource_filename("symspellpy", "frequency_dictionary_en_82_765.txt"),
    term_index=0,
    count_index=1
)

MISSING_IN_VOCAB = '<mvt>'
MISSING_IDX = 0
PADDING = '<pad>'
PADDING_IDX = 1

VOCAB_LOCATION = 'processed/vocab.joblib'
ENCODED_LOCATION = 'processed/encoded.joblib'

#=====================

def _preprocessor(text):
    # remove IP addresses (typically found at the end)
    text = re.sub('[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}', '', text)
    # convert whitespace to space
    text = re.sub('\n|\t|\r', ' ', text)
    # remove punctuation
    text = text.translate(str.maketrans('', '', string.punctuation))
    return text.lower()

def _tokenizer(text):
    result = []
    for word in word_tokenize(text):
        if word in STOP_WORDS:
            continue
        # attempt to fix spelling errors
        suggestions = SYM_SPELL.lookup(
            word,
            Verbosity.CLOSEST,
            max_edit_distance=2,
            include_unknown=True
        )
        result.append(LEMMATIZER.lemmatize(suggestions[0].term))

    return result

def _create_vocab(tokenized_array, vocab_length):
    word_counts = defaultdict(int)

    # count words
    for document in tokenized_array:
        for word in document:
            word_counts[word] += 1

    # convert to {word: number} vocabulary
    sorted_words = sorted(word_counts.keys(), key=lambda x: word_counts[x], reverse=True)[:vocab_length]
    # add 2 to leave room for the 2 special toks
    vocab = {v: i + 2 for i, v in enumerate(sorted_words)}
    vocab[MISSING_IN_VOCAB] = MISSING_IDX
    vocab[PADDING] = PADDING_IDX

    return vocab

def encode_single_input(text, vocab, max_length=500):
    text_array = _tokenizer(_preprocessor(text))
    encoded = [vocab[PADDING] for i in range(max_length)]
    for i, word in enumerate(text_array):
        if i >= max_length:
            break
        encoded[i] = vocab.get(word, vocab[MISSING_IN_VOCAB])
    encoded.insert(0, min(len(text_array), max_length))
    return np.array(encoded).reshape(1, -1)

def decode_text(encoded_text, vocab):
    # horrible and slow. i should have kept a mapping back to the original input!
    text_tok = []
    for i in encoded_text[1:]:
        if i == vocab[PADDING]:
            break
        for k, v in vocab.items():
            if i == v:
                text_tok.append(k)
                break

    return text_tok

def encode_text(df, use_cache=True, vocab_length=10000, max_length=500):
    if use_cache and os.path.exists(VOCAB_LOCATION):
        with open(VOCAB_LOCATION, 'rb') as f:
            vocab = joblib.load(f)
        with open(ENCODED_LOCATION, 'rb') as f:
            encoded_text = joblib.load(f)
    else:
        text_array = list(df['comment_text'])

        # clean
        for i in range(len(text_array)):
            text_array[i] = _tokenizer(_preprocessor(text_array[i]))

        # encode using vocab
        encoded_text = []
        vocab = _create_vocab(text_array, vocab_length)
        for document in text_array:
            # create document with padding
            encoded_document = [vocab[PADDING] for i in range(max_length)]
            for i, word in enumerate(document):
                if i >= max_length:
                    break
                encoded_document[i] = vocab.get(word, vocab[MISSING_IN_VOCAB])
            # prepend the length
            encoded_document.insert(0, min(len(document), max_length))
            encoded_text.append(encoded_document)
        encoded_text = np.array(encoded_text)

        # cache
        os.makedirs('processed', exist_ok=True)
        with open(VOCAB_LOCATION, 'wb') as f:
            joblib.dump(vocab, f)
        with open(ENCODED_LOCATION, 'wb') as f:
            joblib.dump(encoded_text, f)

    return vocab, encoded_text

#=====================


alice = int(input())
beto = int(input())
clara = int(input())

vencedor = "*"

if alice != beto and alice != clara :
   vencedor = "A"

elif beto != alice and beto != clara :
   vencedor = "B"

elif clara != alice and clara != beto :
   vencedor = "C"

print(vencedor)


### 1 [3차]압축
## LZW(Lempel–Ziv–Welch) 압축을 구현
def solution(msg):
    answer = []
    dic = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
    start = 0
    end = 1
    while end <= len(msg):
        start = end-1
        end = start + 1
        check = True
        while check:# end를 정하기 위한 반복문
            end += 1
            if msg[start:end] not in dic or end > len(msg):
                check = False
        if end <= len(msg): # 마지막 추가를 제외하기 위한 조건
            dic.append(msg[start:end])
        answer.append(dic.index(msg[start:end-1])+1)
    return answer

### 2 가장 큰 정사각형 찾기
## 표에서 1로 이루어진 가장 큰 정사각형을 찾아 넓이를 return
## 입출력 예  [[0,1,1,1],[1,1,1,1],[1,1,1,1],[0,0,1,0]]->9
#효율성 실패
def solution(board):
    answer=0
    for row in range(len(board)):
        for col in range(len(board[0])):
            side = 0
            if board[row][col] != 0:
                check = True
                while check:
                    side += 1
                    if (row+side >= len(board)) or (col+side >= len(board[0])): #board 범위 넘으면
                        break
                    for cside in range(row, row+side+1): # 세로줄 확인
                        if board[cside][col+side] == 0:
                            check = False
                            break
                    if check == True:
                        for rside in range(col, col+side): # 가로줄 확인
                            if board[row+side][rside] == 0:
                                check = False
                                break
            answer = max(answer, side)
    return answer*answer

### 3 [3차] 방금그곡
#실패

### 4 방문 길이
## 캐릭터가 처음 걸어본 길의 길이
## 입출력 예  "ULURRDLLU"->7 / "LULLLLLLU"->7
def solution(dirs):
    answer = 0
    row, col = 0,0
    nrow, ncol = 0,0
    paths=[]
    for i in dirs:
        if i=='L': #움직일 좌표
            nrow = row
            ncol = col-1
        elif i=='R':
            nrow = row
            ncol = col+1
        elif i=='U':
            nrow = row+1
            ncol = col
        else:
            nrow = row-1
            ncol = col

        if nrow in range(-5,6) and ncol in range(-5,6): # 범위 내에 있는 경우
            if [row,col,nrow,ncol] not in paths:
                paths.append([row,col,nrow,ncol])
                paths.append([nrow,ncol,row,col])
                answer += 1
            row,col = nrow,ncol
        else:
            nrow,ncol = row,col
    return answer

### 5 [1차] 다트 게임
## 점수|보너스|[옵션]"으로 이루어진 문자열 3세트
## 입출력 예  1S2D*3T->37 (11 * 2 + 22 * 2 + 33)
def solution(dartResult):
    answer = 0
    dart = [] #3개의 점수가 들어갈 리스트
    bonus = {"S":1, "D":2, "T":3}
    dis=[0] #3번의 기회 구별할 인덱스
    for i in range(1, len(dartResult)): #3번의 기회 구별하기 위한 숫자 찾기
        if dartResult[i].isdigit() and dartResult[i-1]!= '1':
            dis.append(i)
    dis.append(len(dartResult))

    for i in range(len(dis)-1):
        one = dartResult[dis[i]:dis[i+1]] #한번의 다트 문자열

        for j in range(len(one)): #보너스(S,D,T)의 위치 찾기
            if not one[j].isdigit():
                le = j
                break

        if len(one) == j+1: #옵션 없는 경우
            dart.append([int(one[:le])**bonus[one[le:le+1]]]) #계산된 점수
        else:
            dart.append([int(one[:le])**bonus[one[le:le+1]], one[le+1:]]) #계산된 점수와 옵션
    #[[1], [4, '*'], [27]]

    if '*' in dart[0]: #처음에 * 있는 경우
        dart[0] = [dart[0][0]*2]

    for i in [0,1,2]: #계산 과정
        if len(dart[i])==2:
            if dart[i][1] == '#':
                dart[i][0] = -dart[i][0]
            else:
                dart[i][0] = 2*dart[i][0]
                dart[i-1][0] = 2*dart[i-1][0]

    answer = sum(dart[i][0] for i in [0,1,2])
    return answer


import requests
import sys
from bs4 import BeautifulSoup

def getHtmlText(url):
    try:
        #向指定url地址发送get请求
        response = requests.get(url)
        #如果HTTP请求返回了不成功的状态码，Response.raise_for_status()会抛出一个HTTPError异常
        response.raise_for_status()
        response.encoding = "utf-8"
        return response.text
    except:
        return "Something Wrong!"

#遍历“非小号”首页
for index in range(1, 22):
    url = "https://www.feixiaohao.com/list_" + str(index) + ".html"
    htmlText = getHtmlText(url)
    soup = BeautifulSoup(htmlText, "html.parser")
    sys.setrecursionlimit(1000000)#避免递归深度不足报错
    #找到货币列表
    tds = soup.find_all("td")
    #去掉第一行标题栏
    for td in tds:
        print(td.text)


COUNTRY_DICT = {
    "United States": "US"
}

ABBREV_COUNTRY_DICT = {
    "US": "United States"
}

ABBREV_STATE_DICT = {
    'AK': 'Alaska',
    'AL': 'Alabama',
    'AR': 'Arkansas',
    'AS': 'American Samoa',
    'AZ': 'Arizona',
    'CA': 'California',
    'CO': 'Colorado',
    'CT': 'Connecticut',
    'DC': 'District of Columbia',
    'DE': 'Delaware',
    'FL': 'Florida',
    'GA': 'Georgia',
    'GU': 'Guam',
    'HI': 'Hawaii',
    'IA': 'Iowa',
    'ID': 'Idaho',
    'IL': 'Illinois',
    'IN': 'Indiana',
    'KS': 'Kansas',
    'KY': 'Kentucky',
    'LA': 'Louisiana',
    'MA': 'Massachusetts',
    'MD': 'Maryland',
    'ME': 'Maine',
    'MI': 'Michigan',
    'MN': 'Minnesota',
    'MO': 'Missouri',
    'MP': 'Northern Mariana Islands',
    'MS': 'Mississippi',
    'MT': 'Montana',
    'NA': 'National',
    'NC': 'North Carolina',
    'ND': 'North Dakota',
    'NE': 'Nebraska',
    'NH': 'New Hampshire',
    'NJ': 'New Jersey',
    'NM': 'New Mexico',
    'NV': 'Nevada',
    'NY': 'New York',
    'OH': 'Ohio',
    'OK': 'Oklahoma',
    'OR': 'Oregon',
    'PA': 'Pennsylvania',
    'PR': 'Puerto Rico',
    'RI': 'Rhode Island',
    'SC': 'South Carolina',
    'SD': 'South Dakota',
    'TN': 'Tennessee',
    'TX': 'Texas',
    'UT': 'Utah',
    'VA': 'Virginia',
    'VI': 'Virgin Islands',
    'VT': 'Vermont',
    'WA': 'Washington',
    'WI': 'Wisconsin',
    'WV': 'West Virginia',
    'WY': 'Wyoming'
}

STATE_DICT = {
    'Alaska': 'AK',
    'Alabama': 'AL',
    'Arkansas': 'AR',
    'American Samoa': 'AS',
    'Arizona': 'AZ',
    'California': 'CA',
    'Colorado': 'CO',
    'Connecticut': 'CT',
    'District of Columbia': 'DC',
    'Delaware': 'DE',
    'Florida': 'FL',
    'Georgia': 'GA',
    'Guam': 'GU',
    'Hawaii': 'HI',
    'Iowa': 'IA',
    'Idaho': 'ID',
    'Illinois': 'IL',
    'Indiana': 'IN',
    'Kansas': 'KS',
    'Kentucky': 'KY',
    'Louisiana': 'LA',
    'Massachusetts': 'MA',
    'Maryland': 'MD',
    'Maine': 'ME',
    'Michigan': 'MI',
    'Minnesota': 'MN',
    'Missouri': 'MO',
    'Northern Mariana Islands': 'MP',
    'Mississippi': 'MS',
    'Montana': 'MT',
    'National': 'NA',
    'North Carolina': 'NC',
    'North Dakota': 'ND',
    'Nebraska': 'NE',
    'New Hampshire': 'NH',
    'New Jersey': 'NJ',
    'New Mexico': 'NM',
    'Nevada': 'NV',
    'New York': 'NY',
    'Ohio': 'OH',
    'Oklahoma': 'OK',
    'Oregon': 'OR',
    'Pennsylvania': 'PA',
    'Puerto Rico': 'PR',
    'Rhode Island': 'RI',
    'South Carolina': 'SC',
    'South Dakota': 'SD',
    'Tennessee': 'TN',
    'Texas': 'TX',
    'Utah': 'UT',
    'Virginia': 'VA',
    'Virgin Islands': 'VI',
    'Vermont': 'VT',
    'Washington': 'WA',
    'Wisconsin': 'WI',
    'West Virginia': 'WV',
    'Wyoming': 'WY'
}

def abbreviate_state(state):
    try:
        if len(state) > 2:
            state = STATE_DICT[state]
        return state
    except (TypeError, KeyError) as e:
        if TypeError:
            print('State type was not converted to abbreviated form properly.')
        else:
            print(f"Couldn't find {state} in STATE_DICT")
        print("Skipping state formatting. This will need to manually be fixed")
        return state

def full_form_state(state):
    try:
        if len(state) == 2:
            state = ABBREV_STATE_DICT[state]
        return state
    except (TypeError, KeyError) as e:
        if TypeError:
            print('State type was not converted to full form properly.')
        else:
            print(f"Couldn't find {state} in ABBREV_STATE_DICT")
        print("Skipping state formatting. This will need to manually be fixed")
        return state

def abbreviate_country(country):
    try:
        if len(country) > 2:
            country = COUNTRY_DICT[country]
        return country
    except (KeyError, TypeError) as e:
        if TypeError:
            print('Country type was not converted to abbreviated form properly.')
        else:
            print(f"Couldn't find {country} in COUNTRY_DICT")
        print("Skipping country formatting. This will need to manually be fixed")
        return country

def full_form_country(country):
    try:
        if len(country) == 2:
            country = ABBREV_COUNTRY_DICT[country]
        return country
    except (TypeError, KeyError) as e:
        if TypeError:
            print('Country type was not converted to full form properly.')
        else:
            print(f"Couldn't find {country} in ABBREV_COUNTRY_DICT")
        print("Skipping country formatting. This will need to manually be fixed")
        return country


def greeting(name='Hoang', year =2000):
    '''
    Ham chao hoi
    input: ten, nam sinh
    '''

    Name = name.upper()
    old =  2022-int(year)
    print(f' Chao Bạn "{Name}" - {old} tuổi!')

greeting('Minh Thang', 2003)
def cal_point(score = [2.5, 8.4, 9.5, 3]):
    print('Diem he 10: {}'.format(score))
    so_mon_hoc = len(score)
    tong = 0.0
    for i in score:
        tong+= i
    avr_score = tong/so_mon_hoc
    print('Diem trung binh he 10: ', avr_score)
    print('Diem trung binh he 4:', avr_score*4/10 )
cal_point([9])


import random
import time
time.sleep(.2)
name=input("Enter your name: ")
time.sleep(.4)
print("Hello", name, "welcome to the game DICE")
input("Press any key to start game")
print(" loading...\n")
time.sleep(5)
l=[]
attempt=4
flag=1
l=random.randint(1,6)
m=random.randint(1,6)
game=l+m

while(attempt!=0):
    num=int(input("Guess and enter the sum of two numbers in between of 2 to 12 : "))
    time.sleep(2)
    while(num>12 or num<2):
        if (num>12 or num<2):
            print("Enter the numbers between 2 and 12")
            num=int(input("Guess and enter the sum of two numbers: "))
    if(game==num):
        flag=0
        print("CONGRATULATIONS !!! You win!!!\nThe numbers are: ",l,"and",m,"\n""And the sum is : ",game)
        break
    else:
        print(" number was guessed is wrong!!! You lost a chance!\nGuess a new number, better luck next time!")
        print()
        attempt-=1

if flag==1:
    print("You lose, the number was: ",game)


import heapq

# Time O(nlogk) and space O(k)
def find_dist(coordinate):
    x, y = coordinate
    return x * x + y * y

def find_closest_points(points, k):
    maxHeap = []

    for i in range(k):
        dist = find_dist(points[i])
        heapq.heappush(maxHeap, (-dist, points[i]))

    print(maxHeap)

    # for rest of the elements, if a point is closer to origin than the top of heap,
    # remove top element and add the point
    for i in range(k, len(points)):
        if find_dist(points[i]) < -maxHeap[0][0]:
            heapq.heappop(maxHeap)
            heapq.heappush(maxHeap, (-find_dist(points[i]), points[i]))

    return list(maxHeap)

result = find_closest_points([(1, 3), (3, 4), (2, -1)], 2)

print("Closest points are:", result)


while True:
    a, b = sorted(input().split(), key=int)
    if (a, b) == ('0', '0'):
        break
    count, carry = 0, 0
    for i in range(1, 1+len(a)):
        if int(a[-i]) + int(b[-i]) + carry > 9:
            count += 1
            carry = 1
        else:
            carry = 0
    j = 1+len(a)
    while carry and j <= len(b) and b[-j] == '9':
        count += 1
        j += 1
    print(count)


import io
import os
from urllib.parse import urlparse
from ..control import Control
from ..plugin import Plugin
from ..loader import Loader
from .. import helpers

# Plugin

class S3Plugin(Plugin):
    """Plugin for S3

    API      | Usage
    -------- | --------
    Public   | `from frictionless.plugins.s3 import S3Plugin`

    """

    def create_control(self, resource, *, descriptor):
        if resource.scheme == "s3":
            return S3Control(descriptor)

    def create_loader(self, resource):
        if resource.scheme == "s3":
            return S3Loader(resource)

# Control

class S3Control(Control):
    """S3 control representation

    API      | Usage
    -------- | --------
    Public   | `from frictionless.plugins.s3 import S3Control`

    Parameters:
        descriptor? (str|dict): descriptor
        endpoint_url? (string): endpoint url

    Raises:
        FrictionlessException: raise any error that occurs during the process

    """

    def __init__(
        self, descriptor=None, endpoint_url=None, newline=None, detect_encoding=None
    ):
        self.setinitial("endpointUrl", endpoint_url)
        super().__init__(descriptor, newline=newline, detect_encoding=detect_encoding)

    @property
    def endpoint_url(self):
        return (
            self.get("endpointUrl")
            or os.environ.get("S3_ENDPOINT_URL")
            or DEFAULT_ENDPOINT_URL
        )

    # Expand

    def expand(self):
        """Expand metadata"""
        super().expand()
        self.setdefault("endpointUrl", self.endpoint_url)

    # Metadata

    metadata_profile = {  # type: ignore
        "type": "object",
        "properties": {
            "endpointUrl": {"type": "string"},
            "newline": {"type": "string"},
            "detectEncoding": {},
        },
    }

# Loader

class S3Loader(Loader):
    """S3 loader implementation.

    API      | Usage
    -------- | --------
    Public   | `from frictionless.plugins.s3 import S3Loader`

    """

    remote = True

    # Read

    def read_byte_stream_create(self):
        boto3 = helpers.import_from_plugin("boto3", plugin="s3")
        control = self.resource.control
        parts = urlparse(self.resource.source, allow_fragments=False)
        client = boto3.resource("s3", endpoint_url=control.endpoint_url)
        object = client.Object(bucket_name=parts.netloc, key=parts.path[1:])
        byte_stream = S3ByteStream(object)
        return byte_stream

    # Write

    def write_byte_stream_save(self, byte_stream):
        boto3 = helpers.import_from_plugin("boto3", plugin="s3")
        control = self.resource.control
        parts = urlparse(self.resource.source, allow_fragments=False)
        client = boto3.resource("s3", endpoint_url=control.endpoint_url)
        object = client.Object(bucket_name=parts.netloc, key=parts.path[1:])
        object.put(Body=byte_stream)

# Internal

DEFAULT_ENDPOINT_URL = "https://s3.amazonaws.com"

# https://alexwlchan.net/2019/02/working-with-large-s3-objects/
class S3ByteStream(io.RawIOBase):
    def __init__(self, object):
        self.object = object
        self.position = 0

    def __repr__(self):
        return "<%s object=%r>" % (type(self).__name__, self.object)

    @property
    def size(self):
        return self.object.content_length

    def readable(self):
        return True

    def seekable(self):
        return True

    def tell(self):
        return self.position

    def seek(self, offset, whence=io.SEEK_SET):
        if whence == io.SEEK_SET:
            self.position = offset
        elif whence == io.SEEK_CUR:
            self.position += offset
        elif whence == io.SEEK_END:
            self.position = self.size + offset
        else:
            raise ValueError(
                "invalid whence (%r, should be %d, %d, %d)"
                % (whence, io.SEEK_SET, io.SEEK_CUR, io.SEEK_END)
            )

        return self.position

    def read(self, size=-1):
        if size == -1:
            # EOF
            if self.position >= self.size:
                return b""
            # Read to the end of the file
            range_header = "bytes=%d-" % self.position
            self.seek(offset=0, whence=io.SEEK_END)
        else:
            new_position = self.position + size
            # If we're going to read beyond the end of the object, return
            # the entire object.
            if new_position >= self.size:
                return self.read()
            range_header = "bytes=%d-%d" % (self.position, new_position - 1)
            self.seek(offset=size, whence=io.SEEK_CUR)
        return self.object.get(Range=range_header)["Body"].read()

    def read1(self, size=-1):
        return self.read(size)