#!/usr/bin/env python3
# Author: Shane Harrell
# Email: shane.harrell@signalwire.com
# Purpose: Working example of an AI bot that will ask questions to a user, and store the answers in a database.

import json
from flask import Flask, redirect, render_template, request, url_for
import sqlite3

surveybot = Flask(__name__)

@surveybot.route('/', methods=['POST'])
def main_ai_prompt():
    swml_web_hook_base_url = '<your_webhook_url>'
    swml_ai_prompt = '''Your name is SurveyBot.  Your job is to survey the caller with questions from a database.

    ### How to follow up on questions answered and protocols to follow
        Stay on focus and on protocol.
        You are not capable of troubleshooting or diagnosing problems.
        Execute functions when appropriate

    ### Step 1
        Determine if the caller already exists in the database.  Use the provided lookup_caller function using the callers phone number as an argument.

    ### Step 2
        We need to gather some data about the caller so that we can record their answers.

    #### Step 2.1
        Ask the caller for their first name

    #### Step 2.2
        Ask the caller for their last name

    #### Step 2.3
        Ask the caller for their age in years

    #### Step 2.4
        Use the calling phone number as the callers phone number.  Use the provided create_user function to create the user in the database.
        Do not tell the caller that a record was created in a database.

    ### Step 3
        Ask the caller the first question when it is returned.
        Continue to use the provided question_and_answer function to record each answer, and get the next question.  Send the question asked in the question argument, and the answer in the answer argument.
        Stay on task and on protocol. Do not make up your own questions.
        Repeat this process until there are no questions remaining.
    '''

    swml = {}
    swml['sections'] = {
        'main': [{
            'ai': {
                'voice': 'en-US-Standard-A',
                'params': {
                    'confidence': 0.6,
                    'barge_confidence': 0.1,
                    'top_p': 0.3,
                    'temperature': 1.0,
                    'swaig_allow_swml': True,
                    'conscience': True
                },
                'prompt': {
                    'text': swml_ai_prompt
                },
                'SWAIG': {
                    'functions': [
                        {
                            'function': 'lookup_caller',
                            'purpose': 'lookup the caller in the database to see if they exist',
                            'web_hook_url': f"{swml_web_hook_base_url}/lookup_caller",
                            'argument': {
                                'type': 'object',
                                'properties': {
                                    'phone_number': {
                                        'type': 'string',
                                        'description': 'the callers phone_number'
                                    }
                                }
                            }
                        },
                        {
                            'function': 'question_and_answer',
                            'purpose': 'record the answer and get the next question for the survey',
                            'web_hook_url': f"{swml_web_hook_base_url}/question_and_answer",
                            'argument': {
                                'type': 'object',
                                'properties': {
                                    'answer': {
                                        'type': 'string',
                                        'description': 'the callers answer to the question'
                                    },
                                    'question': {
                                        'type': 'string',
                                        'description': 'the question that was asked by SurveyBot'
                                    }
                                }
                            }
                        },
                        {
                            'function': 'create_user_record',
                            'purpose': 'submit the payment for the caller',
                            'web_hook_url': f"{swml_web_hook_base_url}/create_user",
                            'argument': {
                                'type': 'object',
                                'properties': {
                                    'first_name': {
                                        'type': 'string',
                                        'description': 'the callers fist name'
                                    },
                                    'last_name': {
                                        'type': 'string',
                                        'description': 'the callers last name'
                                    },
                                    'age': {
                                        'type': 'string',
                                        'description': 'the callers age'
                                    },
                                    'phone_number': {
                                        'type': 'string',
                                        'description': 'the callers phone_number'
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        }]
    }

    return (swml)

# SWAIG FUNCTION ENDPOINTS
@surveybot.route('/lookup_caller', methods=['POST'])
def lookup_caller():
    db = sqlite3.connect("survey.db")
    cursor = db.cursor()

    swml = {}

    # Does this user already exist in the database
    # Don't create a new user if they do
    phone_number = request.json['argument']['parsed'][0]['phone_number']

    rows = cursor.execute(
        "SELECT id, first_name, last_name from user where phone_number = ? limit 1",
        (phone_number,)
    ).fetchall()

    if len(rows) > 0:
        for row in rows:
            global user_id
            user_id = row[0]
            first_name = row[1]
            last_name = row[2]

            add_questions_to_user(user_id)       # Add any new questions to the caller's survey
            question = get_a_question(user_id)   # Get the first/next question for the caller

            if question != "0":
                swml['response'] = f"The user already exists.  They callers name is {first_name} {last_name}.  The the first question is {question}"
                print (f"SWML: {swml}")
            else:
                swml['response'] = f"The user, {first_name} {last_name} already exists and they have already answered all of the questions in the survey.  Let the caller know they have already answered all of the questions and disconnect the call."
    else:
        swml['response'] = "The user does not exist, start with Step 2"

    db.close()
    print (f"{swml}")
    return swml

@surveybot.route('/create_user', methods=['POST'])
def create_user_record():
    db = sqlite3.connect("survey.db")
    cursor = db.cursor()

    swml = {}

    first_name = request.json['argument']['parsed'][0]['first_name']
    last_name = request.json['argument']['parsed'][0]['last_name']
    age = request.json['argument']['parsed'][0]['age']
    phone_number = request.json['argument']['parsed'][0]['phone_number']

    cursor.execute(
        "INSERT INTO user (first_name, last_name, age, phone_number) VALUES (?, ?, ?, ?)",
        (first_name, last_name, age, phone_number,)
    )
    db.commit()

    # Lets sneakily add the user_id as a global var for later inserts, so we don't have to look it up each time
    rows = cursor.execute(
        "SELECT id from user where phone_number = ? limit 1",
        (phone_number,)
    ).fetchall()
    for row in rows:
        global user_id
        user_id = row[0]

    add_questions_to_user(user_id)
    question = get_a_question(user_id)

    if question != "0":
        swml['response'] = f"The first question is {question}"
        print (f"SWML: {swml}")
    else:
        swml['response'] = f"There are no questions left.  Thank the caller and disconnect"
        print (f"SWML: {swml}")

    db.close()
    return swml

@surveybot.route('/question_and_answer', methods=['POST'])
def question_and_answer():
    swml = {}
    global question_id

    # UNCOMMENT FOR DEBUG:
    #print (request.json)

    db = sqlite3.connect("survey.db")
    cursor = db.cursor()

    answer = request.json['argument']['parsed'][0]['answer']

    cursor.execute(
        "UPDATE survey_answers SET answer = ? WHERE user_id = ? AND id = ?",
        (answer, user_id, question_id)
    )
    db.commit()

    rows = cursor.execute(
        "SELECT question, id from survey_answers where user_id = ? and answer is NULL order by id limit 1",
        (user_id,)
    ).fetchall()

    if len(rows) > 0:
        for row in rows:
            question = row[0]
            question_id = row[1]
            swml['response'] = f"Success.  The answer has been recorded.  the next question is {question}"
            print(f"{swml}")
    else:
        swml['response'] = f"Success.  The answer has been recorded.  There are no more questions in the survey.  Please hang up the call"
        print (f"{swml}")

    db.close()
    return swml

def get_a_question(user_id):
    global question_id
    response = ""

    db = sqlite3.connect("survey.db")
    cursor = db.cursor()

    rows = cursor.execute(
        "SELECT question, id from survey_answers where user_id = ? and answer is NULL order by id limit 1",
        (user_id,)
    ).fetchall()

    if len(rows) > 0:
        for row in rows:
            question = row[0]
            question_id = row[1]
            response = question
    else:
        response = "0"

    db.close()
    return (response)

def add_questions_to_user(user_id):
    db = sqlite3.connect("survey.db")
    cursor = db.cursor()

    rows = cursor.execute(
        "select id, question from survey_questions"
    ).fetchall()
    for row in rows:
        survey_question_id = row[0]
        survey_question = row[1]
        cursor.execute(
            "INSERT INTO survey_answers (user_id, question_id, question) SELECT ?, ?, ? WHERE NOT EXISTS (SELECT id from survey_answers where user_id = ? and question_id = ?)",
            (user_id, survey_question_id, survey_question, user_id, survey_question_id,)
        )

    db.commit()
    db.close()
    return

if __name__ == '__main__':
    surveybot.run()


from enigma.enigma import Enigma

def main():
    # assume correct cipher user input
    cipher = input("Enter three letter initial rotor settings in order 'Slow, medium, fast': ")

    machine = initialize_rotors(cipher)

    # Message to be encrypted, using only uppercase letters, lowercase letters, and spaces
    message = input("Message to be encrypted or decrypted: ")
    print(machine.encrypt(message))

def initialize_rotors(cipher):
    """
    Sets up slow, fast, and medium rotors
    :param cipher: Three letter cipher code for rotor positions
    :return: Enigma machine object with rotors set up
    """
    return Enigma(cipher)

if __name__ == '__main__':
    main()


from ecdsa import VerifyingKey, NIST256p
import socket
import argparse
import logging
import base64
import os
import sys
import json
import hashlib
import time
import datetime

# verify the signature in "signed" (JSON object) based on the public key in "cert" (JSON object)
def verify_signature(signed, cert):
    ret = True
    reason = "success"
    if "signature" not in signed:
        ret = False
        reason = "no signature in signed"
    elif "public key" not in cert:
        ret = False
        reason = "no public key in cert"
    else:
        tbv = {}
        keys = list(signed.keys())
        logging.debug("before: {}".format(keys))
        keys.remove("signature")
        logging.debug("after: {}".format(keys))

        for k in keys:
            tbv[k] = signed[k]

        try:
            vk = VerifyingKey.from_pem(cert["public key"].encode())
        except:
            ret = False
            reason = "error in loading the public key from cert"
            return ret, reason

        js = json.dumps(tbv)
        logging.debug("tbv: {}".format(js))
        logging.debug("signature: {}".format(signed["signature"]))
        sig = base64.b64decode(signed["signature"].encode())

        try:
            ret = vk.verify(sig, js.encode(), hashfunc=hashlib.sha256)
        except:
            ret = False
            reason = "verification failure"

    return ret, reason

def chain_validation(chain, trusted):
    curr = chain[0]
    for issuer in chain[1:]:
        ret, reason = verify_signature(curr, issuer)
        if ret:
            curr = issuer
        else:
            logging.debug("reason: {}".format(reason))
            break

    if not ret:
        reason = "verification failure (chain)"
        return ret, reason

    if curr["subject"] == curr["issuer"]:
        if curr["subject"] in trusted:
            ret = True
            reason = "success"
        else:
            ret = False
            reason = "not trusted"
    else:
        if curr["issuer"] in trusted:
            ret, reason = verify_signature(curr, trusted[curr["issuer"]])
            if ret:
                ret = True
                reason = "success"
            else:
                ret = False
                reason = "not trusted"
        else:
            ret = False
            reason = "not trusted"

    return ret, reason

def name_validation(url, chain):
    leaf = chain[0]
    if url == leaf["subject"]:
        ret = True
        reason = "success"
    else:
        ret = False
        reason = "invalid subject name"
    return ret, reason

def revocation_checking(chain, crl, ocsp):
    curr = int(time.time())
    curr = datetime.datetime.fromtimestamp(curr)

    # 1. checking validity period
    for cert in chain:
        not_before = datetime.datetime.strptime(cert["not before"], "%Y-%m-%d")
        not_after = datetime.datetime.strptime(cert["not after"], "%Y-%m-%d")
        if curr < not_before:
            ret = False
            reason = "invalid certificate (not before) at {}".format(cert["subject"])
            break
        elif curr > not_after:
            ret = False
            reason = "invalid certificate (not after) at {}".format(cert["subject"])
            break
        else:
            ret = True
            reason = "success"

    if not ret:
        return ret, reason

    # 2. checking revocation (crl or ocsp)
    for cert in chain:
        issuer = cert["issuer"]
        if issuer in crl:
            c = crl[issuer]
            ccert = None
            for ica in chain:
                if ica["subject"] == issuer:
                    ccert = ica
                    break
            if ccert:
                ret, reason = verify_signature(c, ccert)
                if ret:
                    revoked = c["revoked certificates"]
                    for rcert in revoked:
                        if rcert["serial"] == cert["serial"]:
                            ret = False
                            reason = "revoked certificate (crl)"
                            break
            else:
                ret = False
                reason = "invalid chain"

    if not ret:
        return ret, reason

    if ocsp == "none":
        return ret, reason

    ccert = None
    for cert in chain:
        if cert["subject"] == ocsp["issuer"]:
            ccert = cert
            break
    ret, reason = verify_signature(ocsp, ccert)

    if ret:
        if ocsp["status"] == "good":
            ret = True
            reason = "success"
        else:
            ret = False
            reason = "invalid ocsp status"
    else:
        reason = "verification failure (ocsp)"

    return ret, reason

def validate_certificate(url, chain, trusted, crl, ocsp):
    ret = False

    chain_verified, reason = chain_validation(chain, trusted)
    if chain_verified:
        name_verified, reason = name_validation(url, chain)

        if name_verified:
            revocation_verified, reason = revocation_checking(chain, crl, ocsp)

            if revocation_verified:
                ret = True

    return ret, reason

def load_crls(cdir):
    crl = {}
    clst = [f.split(".")[0] for f in os.listdir(cdir)]

    for ca in clst:
        with open("{}/{}.crl".format(cdir, ca), "r") as f:
            crl[ca] = json.loads(f.read())

    return crl

def load_trusted_root_ca(tdir):
    trusted = {}
    tlst = [f.split(".")[0] for f in os.listdir(tdir)]

    for ca in tlst:
        with open("{}/{}.crt".format(tdir, ca), "r") as f:
            trusted[ca] = json.loads(f.read())

    return trusted

def run(addr, port, rfile, cdir, tdir):
    alice = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    alice.connect((addr, port))
    logging.info("[*] Client is connected to {}:{}".format(addr, port))

    # crl: ca name -> crl
    crl = load_crls(cdir)

    # trusted: ca name -> ca's certificate
    trusted = load_trusted_root_ca(tdir)

    with open(rfile, "r") as f:
        for line in f:
            if line.strip() == '':
                break
            url = line.strip()
            alice.send(url.encode())
            logging.info("[*] Sent: {}".format(url))
            received = alice.recv(2048).decode()
            logging.debug("[*] Received: {}".format(received))
            js = json.loads(received)
            cstr = js["chain"]
            chain = []
            for cert in cstr:
                chain.append(json.loads(cert))
            ocsp = js["ocsp"]
            if ocsp != "none":
                ocsp = json.loads(ocsp)
            verified, reason = validate_certificate(url, chain, trusted, crl, ocsp)
            logging.info("[*] Result of Certificate Validation ({}): {} ({})".format(url, verified, reason))

    alice.send("finished".encode())

def command_line_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("-a", "--addr", metavar="<bob's address>", help="Bob's address", type=str, required=True)
    parser.add_argument("-p", "--port", metavar="<bob's port>", help="Bob's port", type=int, required=True)
    parser.add_argument("-r", "--request", metavar="<request file>", help="Request file name", type=str, required=True)
    parser.add_argument("-c", "--crl", metavar="<crl directory>", help="CRL directory", type=str, required=True)
    parser.add_argument("-t", "--trusted", metavar="<trusted ca directory>", help="Trusted CA directory", type=str, required=True)
    parser.add_argument("-l", "--log", metavar="<log level (DEBUG/INFO/WARNING/ERROR/CRITICAL)>", help="Log level (DEBUG/INFO/WARNING/ERROR/CRITICAL)", type=str, default="INFO")
    args = parser.parse_args()
    return args

def main():
    args = command_line_args()
    log_level = args.log
    logging.basicConfig(level=log_level)

    if not os.path.exists(args.request):
        logging.error("The request file does not exist: {}".format(args.request))
        sys.exit(1)

    if not os.path.exists(args.crl):
        logging.error("The directory specified for CRL does not exist: {}".format(args.crl))
        sys.exit(1)

    if not os.path.exists(args.trusted):
        logging.error("The directory specified for trusted root CA does not exist: {}".format(args.trusted))
        sys.exit(1)

    run(args.addr, args.port, args.request, args.crl, args.trusted)

if __name__ == "__main__":
    main()


import os
import shutil
from flask import Flask, jsonify, request
from werkzeug.utils import secure_filename

import localgpt
localgpt_object = localgpt.DocumentProcessor()

app = Flask(__name__)
localgpt_object.ingest()
localgpt_object.load_model()
localgpt_object.load_QA()

@app.route("/api/delete_source", methods=["GET"])
def delete_source_route():
    folder_name = "SOURCE_DOCUMENTS"

    if os.path.exists(folder_name):
        shutil.rmtree(folder_name)

    os.makedirs(folder_name)

    return jsonify({"message": f"Folder '{folder_name}' successfully deleted and recreated."})

@app.route("/api/save_document", methods=["GET", "POST"])
def save_document_route():
    if "document" not in request.files:
        return "No document part", 400
    file = request.files["document"]
    if file.filename == "":
        return "No selected file", 400
    if file:
        filename = secure_filename(file.filename)
        folder_path = "SOURCE_DOCUMENTS"
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
        file_path = os.path.join(folder_path, filename)
        file.save(file_path)
        return "File saved successfully", 200

@app.route("/api/run_ingest", methods=["GET"])
def run_ingest_route():
    try:
        localgpt_object.ingest()
        localgpt_object.load_QA()
        return "Script executed successfully", 200
    except Exception as e:
        return f"Error occurred: {str(e)}", 500

@app.route("/api/prompt_route", methods=["GET", "POST"])
def prompt_route():
    user_prompt = request.form.get("user_prompt")
    if user_prompt:
        res = localgpt_object.QA(user_prompt)
        answer, docs = res["result"], res["source_documents"]

        prompt_response_dict = {
            "Prompt": user_prompt,
            "Answer": answer,
        }

        prompt_response_dict["Sources"] = []
        for document in docs:
            prompt_response_dict["Sources"].append(
                (os.path.basename(str(document.metadata["source"])), str(document.page_content))
            )

        return jsonify(prompt_response_dict), 200
    else:
        return "No user prompt received", 400

if __name__ == "__main__":
    app.run(debug=False, port=5110)


import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler

def handle_missing_value(df: pd.DataFrame, method: str, freq: str):
    """
    Examine missing dates and impute missing values

    Args:
        df (dataframe): timeseries dataframe
        method (str): method used for imputation
        freq (str): time series interval length

    Returns:
        cleaned df
    """
    idx = pd.date_range(df.index.min(), df.index.max(), freq=freq)
    df = df.reindex(idx)
    df = df.interpolate(method=method)
    return df

def make_time_features(df: pd.DataFrame):

    def encode(data, col, max_val):
        data[col + '_sin'] = np.sin(2 * np.pi * data[col] / max_val)
        data[col + '_cos'] = np.cos(2 * np.pi * data[col] / max_val)
        return data

    df['hour_of_day'] = df.index.hour
    df['day_of_week'] = df.index.dayofweek
    df = encode(df, 'hour_of_day', 23)
    df.drop(columns=['hour_of_day'], inplace=True)

    return df

def make_mlp_input(df: pd.DataFrame, look_back_steps, target, forecast_steps):
    row_no = 0
    row_list = []

    for index, values in df.iterrows():
        if row_no + look_back_steps <= len(df[:-forecast_steps]):
            window_df = df[:-forecast_steps][row_no:row_no + look_back_steps]
            row_list.append(np.array(window_df))
            row_no += 1
        else:
            break

    row_no = 0
    output_list = []
    for index, values in df[look_back_steps:].iterrows():
        if row_no + forecast_steps <= len(df[look_back_steps:]):
            window_df = df[look_back_steps:][target][row_no:row_no + forecast_steps]
            output_list.append(np.array(window_df))
            row_no += 1
        else:
            break

    mlp_X = np.reshape(row_list, (len(row_list), look_back_steps, df.shape[1]))
    mlp_y = np.reshape(output_list, (len(output_list), forecast_steps))

    return mlp_X, mlp_y


from cilcdjango.core.users import LDAPConnection
from cilcdjango.core.widgets import *

from django import forms
from django.utils.translation import ugettext as _

import datetime
from lxml import etree
from lxml.etree import XMLSyntaxError
import lxml.html
from lxml.html.clean import Cleaner
import re

#-------------------------------------------------------------------------------
#  User Fields
#-------------------------------------------------------------------------------

class UserMultipleChoiceField(forms.ModelMultipleChoiceField):
	"""A multiple choice field for Users that shows a user's full name."""

	def label_from_instance(self, user):
		return user.get_full_name()

class UserMultipleChoiceField(forms.ModelMultipleChoiceField):
	"""A choice field for Users that shows a user's full name."""

	def label_from_instance(self, user):
		return user.get_full_name()

class TNumbersField(forms.CharField):
	"""
	A field that accepts a list of student T numbers and returns a dictionary of
	the user information returned for each T number.
	"""

	widget = forms.Textarea()

	def __init__(self, *args, **kwargs):

		if 'label' not in kwargs:
			kwargs['label'] = _('student T numbers')
		if 'help_text' not in kwargs:
			kwargs['help_text'] = _("separate the T numbers using commas, spaces or line breaks")

		super(TNumbersField, self).__init__(*args, **kwargs)

	def clean(self, value):
		"""
		Verify that every T number is valid and return a list of the T numbers.

		A valid T number is in the form: T12345678.
		"""

		t_list  = super(TNumbersField, self).clean(value)
		t_list  = re.sub(r'\n', '', t_list.strip())
		valid_t = re.compile(r'^T\d{8}$')

		#  Normalize the input into a list, and make sure that each number
		#  provided is a T number, which is a "T" followed by 8 digits.
		t_numbers = []
		for t_number in re.split(r'[\,\s]', t_list):
			if t_number:
				clean_t = t_number.strip().upper()
				if valid_t.search(clean_t):
					t_numbers.append(clean_t)
				else:
					raise forms.ValidationError(_("the T number %(tnumber)s is not valid") % {
						'tnumber': clean_t
					})
		self._t_numbers = t_numbers
		return t_numbers

	def verify_users(self):
		"""
		Return a dict whose keys will be a user's T number and whose values will
		be the dictionary of LDAP values returned from an LDAP lookup of the
		user.

		This is called after the field has been cleaned and a list of
		valid-format T numbers has been generated, and will raise a validation
		error if any T number does not map to a valid user.
		"""

		#  Get information on each user, and raise an error if a T number
		#  returns no information on a user
		users = {}
		if self._t_numbers:
			ldap_conn = LDAPConnection()
			for t_number in self._t_numbers:
				info = ldap_conn.get_info_from_tnumber(t_number)
				if info:
					users[t_number] = info
				else:
					raise forms.ValidationError(_("no user could be found with the T number %(tnumber)s") % {
						'tnumber': t_number
					})
		return users

#-------------------------------------------------------------------------------
#  Yes / No Boolean Field
#-------------------------------------------------------------------------------

class YesNoField(forms.ChoiceField):
	"""
	A field that transforms Django's default checkbox for a boolean type into a
	radio button with user-defined text for the labels.
	"""

	field_classes = ['yes-no']

	def __init__(self, *args, **kwargs):
		"""Create a ChoiceField as a container for boolean values."""
		choices = [(True, kwargs.pop('yes', _('yes')).title()), (False, kwargs.pop('no', _('no')).title())]
		if 'required' not in kwargs:
			kwargs['required'] = False
		super(YesNoField, self).__init__(choices, *args, **kwargs)
		self.widget = forms.RadioSelect(choices=choices, attrs={'class': "boolean-radio"})

	def clean(self, value):
		"""Return the user's choice as a boolean value or as None, if left blank."""
		if value:
			if value == 'False':
				return False
			else:
				return True
		if self.required:
			raise forms.ValidationError('You must choose yes or no')
		else:
			return None

#-------------------------------------------------------------------------------
#  Date and Date / Time Fields
#-------------------------------------------------------------------------------

class PickedDateField(forms.DateField):
	"""A date field that uses a JavaScript date picker widget."""

	def __init__(self, *args, **kwargs):
		super(PickedDateField, self).__init__(*args, **kwargs)
		self.widget = DatePickerWidget(format='%m/%d/%Y')

class PickedDateTimeField(forms.MultiValueField):
	"""A field that combines a date picker and a field for a time."""

	def __init__(self, *args, **kwargs):
		"""Initialize the two separate date and time fields."""

		#  Build our hour and minute fields
		date_field = PickedDateField()
		time_field = forms.TimeField(input_formats=['%H:%M'])
		kwargs['fields'] = (date_field, time_field)
		super(PickedDateTimeField, self).__init__(*args, **kwargs)

		#  Configure the widgets for display
		self.widget = DateTimeWidget()

	def compress(self, data_list):
		"""Combine the hours and minutes into minutes."""
		try:
			date_time = datetime.datetime.combine(data_list[0], data_list[1])
		except IndexError:
			date_time = None
		return date_time

#-------------------------------------------------------------------------------
#  Rich Text Editor Field
#-------------------------------------------------------------------------------

class RichTextCleaner(Cleaner):
	"""Custom cleaner for the rich text editor markup."""

	embedded = False

class RichTextEditorField(forms.CharField):
	"""
	A field that shows a textarea that is transformed into a rich text editor
	using CKEditor once the page has been loaded.

	The tags defined in `_STRIP_EMPTY_ELEMENTS` will be removed from the
	document tree if they contain neither child tags nor text. The
	`_REPLACE_ELEMENTS` dict is keyed by tags to replace, and has a value in the
	form of ('replace_with_tag', {'attr1': 'val1'}).
	"""

	_HAS_TEXT_SEARCH = re.compile(r'[^\s]')
	_STRIP_EMPTY_ELEMENTS = (
		'div', 'p',
		'b', 'em', 'i', 'span', 'strong'
	)
	_REPLACE_ELEMENTS = {
		'u': ('span', {'class': "underline"})
	}

	def __init__(self, *args, **kwargs):

		#  Pass through RTE widget arguments to the RTE widget
		self.must_break = True
		editor_type = kwargs.pop('editor_type', None)
		auto_focus  = kwargs.pop('auto_focus', None)
		widget_args = {}
		if editor_type:
			widget_args['editor_type'] = editor_type
		if auto_focus:
			widget_args['auto_focus'] = auto_focus

		#  Create the field and make it use the RTE widget
		super(RichTextEditorField, self).__init__(*args, **kwargs)
		self.widget = RichTextEditorWidget(**widget_args)

	def clean(self, value):
		"""Strip out needless markup and whitespace from the editor's HTML."""

		#  Strip excess markup
		value = value or u""
		value = re.sub(r'\n|\r\n|\r', '', value)  # Line breaks
		value = re.sub(r'\ ', ' ', value)    # Non-breaking spaces
		value = re.sub(r'\s+', ' ', value)        # Excess whitespace
		value = re.sub(r'\&\#\d+;', '', value)    # Numbered entities

		#  Convert the value to an element tree and remove elements on our
		#  blacklist that have no children and no text, wrapping the value in a
		#  dummy html fragment if we were unable to parse it the first time,
		#  which can happen with tagless or blank values
		try:
			tree = lxml.html.fromstring(value)
		except XMLSyntaxError:
			tree = lxml.html.fromstring("<div>%s</div>" % value)
		for tag in tree.xpath(".//*"):
			if tag.tag in self._STRIP_EMPTY_ELEMENTS and not len(tag) and not self._HAS_TEXT_SEARCH.search(tag.text_content()):
				tag.drop_tree()

		#  Replace any replaceable elements specified in our list
		for replace_tag, replace_with in self._REPLACE_ELEMENTS.iteritems():
			for tag in tree.xpath(".//%s" % replace_tag):
				tag.tag = replace_with[0]
				for attr, val in replace_with[1].iteritems():
					tag.attrib[attr] = val

		#  Run the processed tree through lxml.html's native cleaner
		cleaner = RichTextCleaner()
		cleaner.clean_html(tree)

		#  If the tree is not empty, or if the field is not required, return
		#  the user input as properly formatted XHTML, erroring out otherwise
		if not self.required or self._HAS_TEXT_SEARCH.search(tree.text_content()):
			return lxml.html.tostring(tree, pretty_print=True, method="xml").strip()
		else:
			raise forms.ValidationError(_("you must enter text in this field"))

#-------------------------------------------------------------------------------
#  Word Counter Field
#-------------------------------------------------------------------------------

class WordCounterField(forms.CharField):
	"""A field that updates the user's current word count through JavaScript."""

	def __init__(self, min_words=None, max_words=None, hard_limit=False, *args, **kwargs):
		super(WordCounterField, self).__init__(*args, **kwargs)
		self.widget = WordCounterWidget(min_words=min_words, max_words=max_words)
		self._min_words = min_words or 0
		self._max_words = max_words or 0
		self._hard_limit = hard_limit

	def clean(self, value):
		"""
		Make sure that, if a hard limit has been set on the word count, the
		user cannot submit if the word count is outside of the given bounds.
		"""

		#  Check the current word count against the bounds and raise needed errors
		if self._hard_limit:
			word_count = len(re.split(r'[^\s]\s+?[^\s]', value)) if value else 0
			if word_count < self._min_words:
				raise forms.ValidationError(_("You must write at least %(minimum)d words.  You have currently written %(current)d." % {'minimum': self._min_words, 'current': word_count}))
			if self._max_words and word_count > self._max_words:
				raise forms.ValidationError(_("You cannot write more than %(maximum)d words.  You have currently written %(current)d." % {'maximum': self._max_words, 'current': word_count}))

		return value


import numpy as np

def load_simple_data():
    data_matrix = np.matrix([[1., 2.1], [2., 1.1], [1.3, 1.], [1., 1.], [2., 1.]])
    class_labels = [1.0, 1.0, -1.0, -1.0, 1.0]
    return data_matrix, class_labels

def stump_classify(data_matrix, dimen, threshold, thresh_ineq):
    ret_array = np.ones((np.shape(data_matrix)[0], 1))
    if thresh_ineq == "lt":
        ret_array[data_matrix[:, dimen] <= threshold] = -1.0
    else:
        ret_array[data_matrix[:, dimen] > threshold] = -1.0
    return ret_array

def build_stump(data_array, class_label, D):
    data_matrix = np.mat(data_array)
    label_matrix = np.mat(class_label).T
    row, column = np.shape(data_matrix)
    num_steps = 10.0
    best_stump = {}
    best_class_est = np.mat(np.zeros((m, 1)))
    min_error = np.inf
    for i in range(column):
        range_min = data_matrix[:, i].min()
        range_max = data_matrix[:, i].max()
        step_size = (range_max - range_min) / num_steps
        for j in range(-1, int(num_steps) + 1):
            for inequal in ['lt', 'gt']:
                threshold = (range_min + float(j) * step_size)
                predict_value = stump_classify(data_matrix, i , threshold, inequal)
                error_array = np.mat(np.ones((m, 1)))
                error_array[predict_value == label_matrix] = 0
                weight_error = D.T * error_array
                print("split: dim {}, threshold {.2f}, "
                      "thresh_inequal: {}, the weight error is {.3f}".format(i, threshold, inequal, weight_error))
                if weight_error < min_error:
                    min_error = weight_error
                    best_class_est = predict_value.copy()
                    best_stump['dim'] = i
                    best_stump['threshold'] = threshold
                    best_stump['ineq'] = inequal
    return best_stump, min_error, best_class_est


import os
from dateutil.parser import parse as parse_date
import requests
from scrapy.selector import Selector

class RateFetcher:
  def __init__ (self, logger):
    self.logger = logger

  def _fetch_from_site (self, date_str):
    formated_date = parse_date(date_str).strftime("%d/%m/%Y")
    response = requests.post(
      os.environ['DOF_URL'], data={
        'idioma': "sp",
        'fechaInicial': formated_date,
        'fechaFinal': formated_date,
        'salida': 'HTML'
      }, timeout=float(os.environ.get('DOF_TIMEOUT') or 30)
    )

    if (response.status_code != 200):
      raise Exception(f"rate-provider error ({response.status_code}) from dof")

    return response.text

  def obtain_rate (self, date_str):
    html_str = self._fetch_from_site(date_str)

    ratePath = Selector(text=html_str).xpath("/html/body/table/tr[2]/td[1]/table/tr[2]/td[4]/table/tr/td/text()").get()

    if (ratePath is None):
      return 'n/a'

    return ratePath.strip()


from enum import Enum
from dataclasses import dataclass
from typing import Optional
from .sls import Sls

class OptimizerType(Enum):
    SGD = "sgd"
    ADAM = "adam"
    SLS = "sls"

@dataclass
class OptimizerParams:
    optimizer_type: OptimizerType = OptimizerType.ADAM
    lr: float = 1e-3

def create_optimizer(
    params, optimizer_params: OptimizerParams, n_batches_per_epoch: Optional[int] = None
):
    if optimizer_params.optimizer_type == OptimizerType.SGD:
        from torch.optim import SGD

        return SGD(params, lr=optimizer_params.lr)

    elif optimizer_params.optimizer_type == OptimizerType.ADAM:
        from torch.optim import Adam

        return Adam(params, lr=optimizer_params.lr)

    elif optimizer_params.optimizer_type == OptimizerType.SLS:
        if n_batches_per_epoch is None:
            return Sls(params)
        return Sls(params, n_batches_per_epoch=n_batches_per_epoch)


""" Contains URL paths for the restaurant bookings app,
forming part of the main Sushi & Sake website """
from django.urls import path
from . import views

urlpatterns = [
    path('book/', views.BookingView.as_view(), name='BookTable'),
    path('mybookings/', views.UserBookings.as_view(), name='mybookings'),
    path('editbooking/<booking_id>/', views.EditBooking.as_view(),
         name='editbooking'),
    path('confirmdelete/<booking_id>/', views.ConfirmDelete.as_view(),
         name='confirmdelete'),
]


import os
import sys
from typing import List
import yaml
import pathlib
import subprocess

from .config import FILE_NAME, DEV
from .base_manager import BaseManager
from .package_manager import PackageManager
from .env_manager import EnvironmentManager
from .command_manager import CommandManger

class ConfigManger(BaseManager):
    def __init__(
            self,
            init: bool = False,
            install: bool | List[str] = False,
            uninstall: bool | List[str] = False,
            run: bool | List[str] = False,
            upgrade=False,
            mode: str = DEV
    ):
        super().__init__("kargat", mode=mode[0])
        self._file_repr = {}
        self.pkg_mgr = PackageManager(mode=mode[0])
        self.em = EnvironmentManager(mode=mode[0])
        self.cmd_mgr = CommandManger(mode=mode[0])
        # cli flags
        self._init_project = init
        self._install = self.handle_arg_list(install)
        self._uninstall = self.handle_arg_list(uninstall)
        self._run = self.handle_arg_list(run)
        self._upgrade = upgrade

    def _load_file(self):
        with open(FILE_NAME, 'r') as f:
            self._file_repr = yaml.safe_load(f)

    def run(self) -> bool:
        if not self._init_project:
            self._load_file()
        self.cmd_mgr.file_repr = self._file_repr
        self.pkg_mgr.file_repr = self._file_repr

        if self._init_project:
            name = self.request_name()
            author = self.request_author()
            version = self.request_version()
            self.generate(name, version, author)
            return True
        elif self._install is True:
            self.pkg_mgr.install_all(self._upgrade)
            return True
        elif self._uninstall is True:
            self.pkg_mgr.uninstall_all()
        elif self._install:
            for pkg in self._install:
                self.pkg_mgr.install(pkg, self._upgrade)
            return True
        elif self._uninstall:
            for pkg in self._uninstall:
                self.pkg_mgr.uninstall(pkg)
        elif self._run:
            with EnvironmentManager(file_repr=self._file_repr, mode="dev") as em:
                self.cmd_mgr.run(self._run)
            return True

    @staticmethod
    def request_name():
        default_name = pathlib.Path(os.getcwd()).name
        name = input(f"Project name ({default_name}): ")
        return name if name else default_name

    @staticmethod
    def request_author():
        user = os.environ.get('USER', os.environ.get('USERNAME'))
        author = input(f"Author ({user}): ")
        return author if author else user

    @staticmethod
    def request_version():
        default_version = "1.0.0"
        version = input(f"Version ({default_version}): ")
        return version if version else default_version

    @staticmethod
    def request_recreate_venv():
        answer = input(f"dir .venv exist, do you want to recreate? [N/y]")
        return answer == 'y'

    @staticmethod
    def venv_create():
        subprocess.check_call([sys.executable, '-m', 'venv', '.venv'])

    @staticmethod
    def has_venv():
        working_dir = os.getcwd()
        files = os.listdir(working_dir)
        flt_iter = next(filter(lambda file: file == '.venv', files), None)
        return flt_iter is not None

    @staticmethod
    def handle_arg_list(cli_args) -> List[str] | bool:
        if isinstance(cli_args, list):
            return cli_args if cli_args else True
        return False


# Удалить все элементы с заданным значением, если они имеются в списке.
from Tasks_3.task3_for_all import numlist

n = int(input('введите значение для удаления :'))

count = 0
numlist_len = len(numlist)
for i in range(len(numlist)):
    if numlist[i] == n:
        break
    else:
        count += 1
if count == len(numlist):
    print('нет такого элемента для удаления')
while n in numlist:
    numlist.remove(n)
if numlist_len > len(numlist):
    print(f'элемент со значением {n} удален ')
    print(f'результат  {numlist}')


import time
import os
import cv2 as cv
import numpy as np
from scipy.stats import linregress
from shapely.geometry import LineString

import matplotlib.pyplot as plt

import tensorflow as tf
from tensorflow import keras
from PIL import Image

class OpticalMarkRecognitionCV:
    def __init__(self):
        """
        The __init__ function is the constructor for the class.

        :param self: Used to refer to the object itself.
        :return: None
        """
        self.inp_image = None
        self.bin_image = None
        self.bin_plus_img = None
        self.backdrop = None
        self.solved_img = None
        self.solved_compact_img = None
        self.marked_thresh = None
        self.valid_rects = []
        self.final_rows = []
        self.tf_model = self.load_tf_model()

    def start_omr_cv(self, img):
        """
        The start_omr_cv function takes in an image and starts the image evaluation process.

        :param self: Used to refer to the object itself.
        :param img: Used to pass the image to the function.
        :return: None
        """
        self.inp_image = None
        self.bin_image = None
        self.bin_plus_img = None
        self.backdrop = None
        self.valid_rects = []
        self.final_rows = []
        self.inp_image = img
        self.preprocess_image()
        self.box_finding_algorithm()
        self.find_remaining_boxes()

        self.sort_rows()
        # self.determine_checked_boxes()
        self.determine_checked_boxes_tf()
        # self.create_solution_image()

    def preprocess_image(self):
        """
        The preprocess_image function creates two binary images of the input image,
        one of the binary images has an increased contrast applied to it.

        :param self: Used to access variables that belong to the class.
        :return: None
        """
        self.backdrop = np.zeros_like(self.inp_image, np.uint8)
        gauss_img = cv.GaussianBlur(self.inp_image, (3, 3), 0)
        gray = cv.cvtColor(gauss_img, cv.COLOR_BGR2GRAY)
        self.bin_image = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]
        st_time = time.time()
        lab = cv.cvtColor(gauss_img, cv.COLOR_BGR2LAB)
        l, a, b = cv.split(lab)
        clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(4,4))
        cl = clahe.apply(l)
        limg = cv.merge((cl,a,b))
        color_contrast_image = cv.cvtColor(limg, cv.COLOR_LAB2BGR)
        gray_contrast_image = cv.cvtColor(color_contrast_image, cv.COLOR_BGR2GRAY)
        self.bin_plus_img = cv.threshold(gray_contrast_image, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)[1]

    def box_finding_algorithm(self):
        """
        The box_finding_algorithm function is used to find the coordinates of the boxes in the solution sheet.

        :param self: Used to access the class attributes.
        :return: None
        """
        y_offset = 770
        x_offset = 130
        res = 1376
        found_rects = []
        croppped_bin = self.bin_image[y_offset: y_offset+res, x_offset: x_offset+res]

        contours = cv.findContours(croppped_bin, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        contours = contours[0] if len(contours) == 2 else contours[1]

        for countour in contours:
            peri = cv.arcLength(countour, True)
            approx = cv.approxPolyDP(countour, 0.02 * peri, True)
            if len(approx) == 4:
                x, y, w, h = cv.boundingRect(approx)
                x, y = x + x_offset, y + y_offset
                if 25 < w < 33 and 25 < h < 33:
                    found_rects.append([x, y, w, h])
                    cv.rectangle(self.backdrop, (x, y), (x + w, y + h), (12, 36, 255), cv.FILLED)

        for rect in found_rects:
            self.valid_rects.append(rect)

    def find_remaining_boxes(self):
        """
        The find_remaining_boxes function finds the position of the remaining boxes
        which were not found by the box_finding_algorithm.

        :param self: Used to refer to the object itself.
        :return: None
        """
        self.valid_rects.sort(key=lambda i: i[1], reverse=False)
        last_y = self.valid_rects[0][1]
        y_split_index = 0
        final_rows = []
        for index, rect in enumerate(self.valid_rects):
            if abs(rect[1] - last_y) > 10:
                final_rows.append(self.valid_rects[y_split_index: index])
                y_split_index = index
                last_y = self.valid_rects[index + 1][1]
            else:
                last_y = rect[1]
        final_rows.append(self.valid_rects[y_split_index:])

        for index, row in enumerate(final_rows):
            row.sort(key=lambda i: i[0], reverse=False)
            final_rows[index] = row

        self.valid_rects.sort(key=lambda i: i[0], reverse=False)
        last_x = self.valid_rects[0][0]
        x_split_index = 0
        final_columns = []
        for index, rect in enumerate(self.valid_rects):
            # print(rect[1] - last_y)
            if abs(rect[0] - last_x) > 10:
                final_columns.append(self.valid_rects[x_split_index: index])
                x_split_index = index
                last_x = self.valid_rects[index + 1][0]
            else:
                last_x = rect[0]
        final_columns.append(self.valid_rects[x_split_index:])

        for index, col in enumerate(final_columns):
            col.sort(key=lambda i: i[1], reverse=False)
            final_columns[index] = col

        x = np.arange(0, 1701)
        row_line_vals = []
        row_line_shapely_vals = []
        for row in final_rows:
            x_values = []
            y_values = []
            for rect in row:
                x_values.append(rect[0])
                y_values.append(rect[1])
            line_a, line_b, _r, _p, _std = linregress(x_values, y_values)
            row_line_vals.append(x*line_a + line_b)
            row_line_shapely_vals.append(LineString(np.column_stack((x, (x*line_a + line_b)))))

        x = np.arange(0, 2308)
        col_line_vals = []
        col_line_shapely_vals = []
        for col in final_columns:
            x_values = []
            y_values = []
            for rect in col:
                x_values.append(rect[1])
                y_values.append(rect[0])
            line_a, line_b, _r, _p, _std = linregress(x_values, y_values)

            col_line_vals.append(x*line_a + line_b)
            col_line_shapely_vals.append(LineString(np.column_stack(((x*line_a + line_b), x))))

        intersections = []

        for col_line in col_line_shapely_vals:
            for row_line in row_line_shapely_vals:
                intersections.append(col_line.intersection(row_line))

        self.valid_rects = []

        # for col_line_val in col_line_vals:
        #     plt.plot(col_line_val, x, "b")

        # x = np.arange(0, 1701)
        # for row_line_val in row_line_vals:
        #     plt.plot(x, row_line_val, "m")

        for intersection in intersections:
            x_pos, y_pos = intersection.xy
            self.valid_rects.append([round(x_pos[0]), round(y_pos[0]), 29, 29])
            # plt.plot(round(x_pos[0]), round(y_pos[0]), marker="o", markersize=5, markeredgecolor="red", markerfacecolor="red")

        # plt.show()

    def sort_rows(self):
        """
        The sort_rows function first sorts the rectangles by their y-coordinate, splits them into rows,
        and then sorts the order of the rectangles in each row by their x-coordinates.

        :param self: Used to refer to the object that is calling this function.
        :return: None
        """
        final_rows = []
        y_split_index = 0
        self.valid_rects.sort(key=lambda i: i[1], reverse=False)
        last_y = self.valid_rects[0][1]
        for index, rect in enumerate(self.valid_rects):
            if abs(rect[1] - last_y) > 10:
                final_rows.append(self.valid_rects[y_split_index: index])
                y_split_index = index
                last_y = self.valid_rects[index + 1][1]
            else:
                last_y = rect[1]
        final_rows.append(self.valid_rects[y_split_index:])

        for index, row in enumerate(final_rows):
            row.sort(key=lambda i: i[0], reverse=False)
            self.final_rows.append(row)

    def determine_checked_boxes(self):
        """
        The determine_checked_boxes function accomplishes two things:
        1. Gives each rectangle a value based on how "marked" they are.
        2. Finds the threshold to split unmarked boxes into marked boxes.

        :param self: Used to access the class attributes.
        :return: None
        """
        rect_values = []
        thresh_crop_size = 0
        for row_index, row in enumerate(self.final_rows):
            for rect_index, rect in enumerate(row):
                start_x, start_y, width, height = rect[0], rect[1], rect[2], rect[3]
                while (width < 34):
                    start_x -= 0.5
                    width += 1
                while (height < 34):
                    start_y -= 0.5
                    height += 1
                start_x, start_y = int(start_x), int(start_y)
                cropped_rect = self.bin_plus_img[start_y:start_y + height, start_x:start_x + width]
                value = cv.countNonZero(cropped_rect)
                self.final_rows[row_index][rect_index].append(value)
                rect_values.append(value)

        rect_values.sort()
        max_diff = 0
        max_index = 0
        index_offset = 115
        for index in range(len(rect_values) -1 - index_offset):
            diff = rect_values[index + 1 + index_offset] - rect_values[index + index_offset]
            if diff > max_diff:
                max_diff = diff
                max_index = index

        # plt.plot(rect_values)
        # plt.plot(max_index+index_offset, rect_values[max_index + index_offset], marker="o")
        # plt.show()

        self.marked_thresh = rect_values[max_index + index_offset]

    def return_marked_boxes_dict(self):
        """
        The return_marked_boxes_dict function specifically creates a dictionary of the marked boxes in the form:
        {Task 1: ['A', 'B', 'C'], Task 2: ['D', 'F']} and so on and returns this dicionary.

        :param self: Used to access the class attributes.
        :return: A dictionary with the marked boxes for each task.
        """
        character_arr = ["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"]
        appendable_characters = []
        marked_sheet = {}

        for row_index, row in enumerate(self.final_rows):
            if row_index % 2 == 0:
                char_off = 0
            else:
                char_off = 13
            for rect_index, rect in enumerate(row):
                if rect[4] > self.marked_thresh:
                    appendable_characters.append(character_arr[rect_index+char_off])
                    cv.rectangle(self.backdrop, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (255, 0, 0), 3)

            if row_index % 2 != 0:
                marked_sheet["Task "+str(int((row_index+1)/2))] = appendable_characters
                appendable_characters = []

        return marked_sheet

    @staticmethod
    def load_tf_model():
        """
        The load_tf_model function loads our keras model for our box predicitions.

        :return: The loaded keras model.
        """
        root_dir_path = os.path.dirname(__file__)
        model_dir_path = os.path.join(root_dir_path, "classification_model")
        return keras.models.load_model(model_dir_path)

    def determine_checked_boxes_tf(self):
        """
        The determine_checked_boxes_tf function loops through all of our rectangles and uses
        our keras model to predict if the rectangle is marked or not.

        :param self: Used to access the class variables.
        :return: None
        """
        self.marked_thresh = 0.5
        for row_index, row in enumerate(self.final_rows):
            for rect_index, rect in enumerate(row):
                val = self.predict_box(rect)
                self.final_rows[row_index][rect_index].append(val)

    def predict_box(self, rect):
        """
        The predict_box function takes in a bounding box and predicts if the
        rectangle in the image is marked or not.

        :param self: Used to access the class variables.
        :param rect: Used to specify the location of the bounding box of the rectangle in the image.
        :return: bool: True if the box was marked and False if it is clear.
        """
        start_x, start_y, width, height = rect[0], rect[1], rect[2], rect[3]
        while (width < 32):
                start_x -= 0.5
                width += 1
        while (height < 32):
            start_y -= 0.5
            height += 1

        start_x = int(start_x)
        start_y = int(start_y)

        Y = keras.preprocessing.image.img_to_array(self.bin_plus_img[start_y: start_y+height, start_x: start_x+width])
        X = np.expand_dims(Y,axis=0)
        val = self.tf_model.predict(X)
        return val[0][0]

    def create_solution_image(self):
        """
        The create_solution_image function creates a two images where the marked and clear boxes are marked.
        The solved_compact_img is a compact version of the main solution image for better visibility.

        :param self: Used to access variables that belongs to the class.
        :return: None
        """
        solution_backdrop = np.zeros_like(self.inp_image, np.uint8)
        self.solved_img = self.inp_image.copy()
        for row_index, row in enumerate(self.final_rows):
            for rect_index, rect in enumerate(row):
                start_x, start_y, width, height = rect[0], rect[1], rect[2], rect[3]
                while (width < 40):
                    start_x -= 0.5
                    width += 1
                while (height < 40):
                    start_y -= 0.5
                    height += 1
                start_x, start_y = int(start_x), int(start_y)
                if rect[4] > self.marked_thresh:
                    cv.rectangle(solution_backdrop, (start_x, start_y), (start_x + width, start_y + height), (255, 0, 0), cv.FILLED)
                else:
                    cv.rectangle(solution_backdrop, (start_x, start_y), (start_x + width, start_y + height), (0, 0, 255), cv.FILLED)
        alpha = 0.5
        mask = solution_backdrop.astype(bool)
        self.solved_img[mask] = cv.addWeighted(self.inp_image, alpha, solution_backdrop, alpha, 0)[mask]

        # row_images = []
        # col_images = []
        # for row_index, row in enumerate(self.final_rows):
        #     col_images = []
        #     for rect_index, rect in enumerate(row):
        #         start_x, start_y, width, height = rect[0], rect[1], rect[2], rect[3]
        #         while (width < 34):
        #             start_x -= 0.5
        #             width += 1
        #         while (height < 34):
        #             start_y -= 0.5
        #             height += 1
        #         start_x, start_y = int(start_x), int(start_y)
        #         col_images.append(self.solved_img[start_y:start_y + height, start_x:start_x + width])
        #     row_images.append(np.concatenate((col_images[0], col_images[1], col_images[2], col_images[3], col_images[4], col_images[5], col_images[6], col_images[7], col_images[8], col_images[9], col_images[10], col_images[11], col_images[12]), axis=1))
        # self.solved_compact_img = np.concatenate((row_images[0], row_images[1], row_images[2], row_images[3], row_images[4], row_images[5], row_images[6], row_images[7], row_images[8], row_images[9], row_images[10], row_images[11], row_images[12], row_images[13], row_images[14], row_images[15], row_images[16], row_images[17], row_images[18], row_images[19]), axis=0)

if __name__ == "__main__":
    omr_cv = OpticalMarkRecognitionCV()
    image = cv.imread("modified_sheets/Sheet4_sp_LOW.jpg")
    omr_cv.start_omr_cv(image)

    image = cv.imread("modified_sheets/Sheet5_sp_LOW.jpg")
    omr_cv.start_omr_cv(image)


from django.urls import path, include
from authen.views import ResourceAPIView, GetListView
from .models import ProductCategory, Discount, Product
from .serializers import ProductCategorySerializer, DiscountSerializer, ProductSerializer
urlpatterns = [
    path('product-category/<int:pk>', ResourceAPIView.as_view(
        model = ProductCategory,
        resource_serializer = ProductCategorySerializer
    )),
    path('product-category-list/<str:page>',GetListView.as_view(
        model = ProductCategory,
        resource_serializer = ProductCategorySerializer
    )),
    path('discount/<int:pk>', ResourceAPIView.as_view(
        model = Discount,
        resource_serializer = DiscountSerializer
    )),
    path('discount-list/<str:page>',GetListView.as_view(
        model = Discount,
        resource_serializer = DiscountSerializer
    )),
    path('product/<int:pk>', ResourceAPIView.as_view(
        model = Product,
        resource_serializer = ProductSerializer
    )),
    path('product-list/<str:page>',GetListView.as_view(
        model = Product,
        resource_serializer = ProductSerializer
    ))
]


import numbers
from turtle import backward

def isPalindrome(x):

    # edge case when x is negative
    if (x < 0):
        return False

    backward_num = 0
    copy_of_x = x

    # reverse the number
    while (copy_of_x != 0):
        curr_num = copy_of_x % 10  # get the last number
        copy_of_x = copy_of_x/10  # get rid of the last number
        backward_num = (backward_num*10) + curr_num

    if (backward_num != x):
        return False

    return True

isPalindrome(121)

# NAIVE SOLUTION

# # edge case when the number is negative
# if(x < 0):
#     return False

# # reverse the integer
# str_number = str(x)
# arr_number = []
# for number in str_number:
#     arr_number.append(number)

# backwards_number = []
# for i in range(len(arr_number)-1, -1, -1):
#     backwards_number.append(arr_number[i])

# for i in range(len(arr_number)):
#     if (arr_number[i] != backwards_number[i]):
#         return False

# return True

# compare values

# edge case when the number is negative


from PIL import Image
import pytesseract
import cv2
import os

IMAGE_TO_PROCESS_PATH = 'sample/Roster1.jpg'

if __name__ == "__main__":

    img = cv2.imread(IMAGE_TO_PROCESS_PATH, cv2.IMREAD_GRAYSCALE)

    if img is None:
        print("no image")
    else:
        thresh, img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # Nhị phân hóa
        # img = cv2.medianBlur(img, 3) # Làm mờ, giảm noise

        # Ghi tạm ảnh xuống ổ cứng
        filename = "{}.jpg".format(os.getpid())
        cv2.imwrite(filename, img)

        # Tesseract OCR
        pytesseract.pytesseract.tesseract_cmd = r'D:\Tai Lieu\HUST-Study\20201\TTKT\tesseract\tesseract.exe'
        text = pytesseract.image_to_string(Image.open(filename), lang = 'jpn')
        print(text)

        # Xóa ảnh tạm
        os.remove(filename)

        # Ghi vào file
        with open('task2/output_task2.txt', "w", encoding="utf-8") as f:
            f.write(text)

        # # Thu nhỏ ảnh
        # scale_percent = 30
        # width = int(img.shape[1] * scale_percent / 100)
        # height = int(img.shape[0] * scale_percent / 100)
        # dim = (width, height)
        # img = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
        # cv2.imshow('Table Structure', img)

        cv2.waitKey(0)
        cv2.destroyAllWindows()


def DFS_ST(d, st):
    path = []
    while st:
        dep = st[-1]
        if dep not in d or len(d[dep]) == 0:
            path.append(st.pop())
        else:
            st.append(d[dep].pop(0))
    return path[::-1]

def solution(tickets):
    d = {}
    for dep,arr in tickets:
        d.setdefault(dep, set()).add(arr)

    for key in d:
        d[key] = sorted(d[key])

    return DFS_ST(d, st=["ICN"])

프로그래머스/lv3/43164. 여행경로/여행경로.py


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 17 14:20:02 2020

@author: Showi
"""

# encoding:utf-8

import requests
import base64
import os

'''
通用文字识别
'''

def p2text(imgPath):
    '''将图片转换为文字'''
    request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
    # 二进制方式打开图片文件
    f = open(imgPath, 'rb')
    img = base64.b64encode(f.read())
    f.close()
    params = {"image":img}
    ##################################################################################
    access_token = '[find the access_token on https://ai.baidu.com/tech/ocr/general]'
    ##################################################################################
    request_url = request_url + "?access_token=" + access_token
    headers = {'content-type': 'application/x-www-form-urlencoded'}
    response = requests.post(request_url, data=params, headers=headers)
    if response:
        print('||',response.json())
        recMes = (response.json())['words_result']
        recMesText = []
        for one in recMes:
            recMesText.append(one['words'])
        os.remove(imgPath)#删除垃圾
        return(recMesText)


import os
import boto3
import json

dynamodb = boto3.resource("dynamodb")
table_name = os.environ.get("DATA_TABLE")
table = dynamodb.Table(table_name)

def handler(event, context):
    placeId = event.get("pathParameters", {}).get("placeId")
    res = {}
    item = table.get_item(Key={"pk": f"p-{placeId}", "sk": "p-info"}).get("Item", {})
    if item:
        likes = item.get("likes", 0)
        res = table.update_item(
            Key={"pk": f"p-{placeId}", "sk": "p-info"},
            UpdateExpression="SET #likes = :increased",
            ExpressionAttributeValues={":increased": likes + 1},
            ExpressionAttributeNames={"#likes": "likes"},
            ReturnValues="ALL_NEW",
        )
        print(res)
    if res.get("Attributes"):
        res["Attributes"]["data"]["likes"] = int(res["Attributes"]["likes"])
        return {"statusCode": 200, "body": json.dumps(res["Attributes"]["data"])}
    else:
        return {"statusCode": 444, "body": f"Il luogo {placeId} non esiste"}


import sys

n = int(sys.stdin.readline().rstrip())

if n == 1:
    print(1)
else:
    lst = [1, 2] + [0] * (n - 2)
    t = 2
    while t < n:
        lst[t] = lst[t - 1] + lst[t - 2]
        t += 1

    print(lst[-1] % 10007)


# -*- coding: utf-8 -*-
# __author__ = 'guoquan'

"""文件基本模块"""

import os
import hashlib
from .core.exceptions import FileError
import re
import pickle
from .core.function import get_dir_size, load_class_by_path
import gzip
import gevent
import glob

class FileBase(object):
    """
    文件对象基类模块
    """

    def __init__(self):
        """
        """
        self._properties = {}
        self._is_set = False
        self.option = None
        self.parent = None

    @property
    def prop(self):
        """
        返回文件对象所有属性，dict字典 key是属性名
        """
        return self._properties

    @property
    def is_set(self):
        """
        返回文件对象是否被设置过路径
        :return:
        """
        return self._is_set

    @property
    def path(self):
        """
        返回文件路径

        :return:
        """
        if self.is_set:
            return self._properties["path"]
        else:
            return None

    @property
    def size(self):
        """
        获取文件大小
        :return:
        """
        if "size" in self._properties.keys():
            return self._properties["size"]
        else:
            return 0

    @property
    def format(self):
        """
        返回文件类的Path路径

        :return:
        """
        class_name = str(type(self))
        m = re.match(r"<class\s\'(.*)\'>", class_name)
        class_name = m.group(1)
        paths = class_name.split(".")
        paths.pop()
        paths.pop(0)
        paths.pop(0)
        return ".".join(paths)

    def set_property(self, name, value):
        """
        添加文件对象属性

        :param name: string 属性名称
        :param value: 属性值
        """
        try:
            pickle.dumps(value)
        except Exception:
            raise Exception("属性%s的值%s不能被序列化，请重新设置!" % (name, value))
        self._properties[name] = value
        return self

    def get_info(self):
        """
        获取当前文件对象的所有属性,需在扩展子类中重写此方法
        """
        if self.is_set:
            self.set_property('dirname', os.path.dirname(self.prop['path']))
            self.set_property('basename', os.path.basename(self.prop['path']))
        else:
            raise Exception("请先调用set_path方法设置文件路径!!")

    def set_path(self, path):
        """
        设置当前文件对象的路径，并获取所有属性

        :param path: 路径
        """
        if not os.path.exists(path):
            raise Exception("请先设置正确的文件或文件夹路径路径!")
        self.set_property("path", path)
        # self.get_info()
        self._is_set = True
        if self.option:
            self.option._is_set = True

    def check(self):
        """
        检测当前文件对象是否满足运行需求,需在扩展子类中重写
        """
        if not self.is_set:
            raise Exception("请先调用set_path方法设置文件路径!")
        return True

    def link(self, link_path=None):
        """
        为当前文件对象创建软连接

        :param link_path:  生成链接的目标文件夹或希望生成的链接文件路径  所在文件夹必须已经存在
        :return: string 生成的链接路径
        """
        if "path" in self.prop.keys() and os.path.exists(self.prop['path']):
            source_path = os.path.abspath(self.prop['path'])
            file_name = os.path.basename(source_path)
            if link_path:
                if os.path.isdir(link_path):   # 指定目标为文件夹
                    target_path = os.path.join(link_path, file_name)
                    os.symlink(source_path, target_path)
                    return target_path
                else:    # 指定目标为文件
                    os.symlink(source_path, link_path)
                    return link_path
            else:   # 未指定目标 默认链接到当前目录下
                os.symlink(source_path, file_name)
                return os.path.join(os.getcwd(), file_name)

    @property
    def api(self):
        """
        获取文件所属参数Workflow/Module/Agent/Tool的ApiManager对象
        :return:
        """
        parent = self
        while parent.parent is not None:
            parent = parent.parent

        if not parent.option:
            raise Exception("文件对象必须属于某个参数！")
        return parent.option.bind_obj.api

class File(FileBase):
    """
    单个文件对象
    """
    def __init__(self):
        super(File, self).__init__()
        self._is_gzip_mark = None

    def check(self):
        """
        检测文件是否正常,并可用于后续分析

        :return:
        """
        super(File, self).check()
        if not ('path' in self.prop.keys() and os.path.isfile(self.prop['path'])):
            raise FileError("文件路径不在正确或文件不存在", None, "002")
        return True

    def get_md5(self):
        """
        获取文件MD5值
        """
        md5 = hashlib.md5()
        with open(self.prop['path'], 'rb') as f:
            while 1:
                data = f.read(8096)
                if not data:
                    break
                md5.update(data)
        return md5.hexdigest()

    def get_size(self):
        """
        获取文件大小
        """
        if os.path.islink(self.path):
            path = os.path.abspath(os.path.realpath(self.path))
        else:
            path = self.path
        size = os.path.getsize(path)
        return size

    def get_reader(self):
        """
        获取文件读取句柄，只读,注意读完成后需要将句柄关闭。
        :return: 返回文件打开句柄，支持gzip压缩文件作为文本文件读取
        """
        if self.is_gzip:
            f = gzip.open(self.path, 'rb')
        else:
            f = open(self.path, "r")
        return f

    @property
    def is_gzip(self):
        """
        判断是否为压缩违建
        :return:
        """
        if self._is_gzip_mark is None:
            return self._is_gzip()
        else:
            return self._is_gzip_mark

    def _is_gzip(self):
        if self.is_set:
            try:
                with gzip.open(self.path, 'rb') as f:
                    f.readline()
            except (IOError, Exception):
                self._is_gzip_mark = False
                return False
            else:
                self._is_gzip_mark = True
                return True
        return False

    def ungzip(self):
        """
        将gzip文件解压成新的文件存储,对于大文件建议在tool中运行此方法
        :return:
        """
        if self.is_gzip:
            to_path = self._create_unzip_path()
            if os.path.exists(to_path) and os.path.isfile(to_path):
                os.remove(to_path)
            g_zip = GZipTool(1048576)
            g_zip.decompress(self.path, to_path)
            self.set_property("ungzip_path", to_path)
            return to_path

    def gzip(self):
        """
        将文件解压成gz文件存储
        :return:
        """
        if not self.is_gzip:
            to_path = "%s.gz" % self.path
            if os.path.exists(to_path) and os.path.isfile(to_path):
                os.remove(to_path)
            g_zip = GZipTool(1048576)
            g_zip.compress(self.path, to_path)
            self.set_property("gzip_path", to_path)
            return to_path

    @property
    def ungzip_path(self):
        """
        解压缩后的文件路径，只有执行ungzip方法后才有值
        :return:
        """
        if "size" in self._properties.keys():
            return self._properties["ungzip_path"]
        else:
            return None

    @property
    def gzip_path(self):
        """
        压缩后的文件路径，只有执行gzip方法后才有值
        :return:
        """
        if "size" in self._properties.keys():
            return self._properties["gzip_path"]
        else:
            return None

    def _create_unzip_path(self):
        m = re.match("^(.*)\.gz$", self.path)
        if m:
            return m.group(1)
        else:
            return "%s.ungzip" % self.path

    def get_first_lines(self, line=10):
        """
        获取文件的最开始几行，一般用于大文件格式是否正确的检测，注意不要将line值设置过大，否则可能超出内存和使运行时间过长
        :param line: 指定需要读取几行
        :return: list数组。每一行为一个数组元素，去除了最后的换行符
        """
        count = 0
        data = []
        with self.get_reader() as f:
            for l in f:  # 一行行的把数据从硬盘加载到内存里读出来
                if count < line:  # 读取前五行
                    data.append(l.strip())
                    count += 1
                else:
                    break
        return data

    def get_last_lines(self, line=10):
        """
        获取文件的最后几行，一般用于大文件格式是否正确的检测，注意不要将line值设置过大，否则可能超出内存和使运行时间过长
        :param line: 指定需要读取几行
        :return: list数组。每一行为一个数组元素，去除了最后的换行符
        """
        data = []
        line_size = -100
        with self.get_reader() as f:
            while True:
                off_set = line_size * line
                try:
                    f.seek(off_set, 2)
                except IOError:
                    f.seek(0, 0)
                    lines = f.readlines()
                    data = [l.strip() for l in lines]
                    break
                else:
                    lines = f.readlines()
                    if len(lines) >= line + 1:
                        data = [l.strip() for l in lines[-line:]]
                    else:
                        line_size *= 2
        return data

class Directory(FileBase):
    """
    文件夹对象
    """
    def __init__(self):
        super(Directory, self).__init__()
        self._file_list = []

    def check(self):
        """

        :return:
        """
        super(Directory, self).check()
        if not('path' in self.prop.keys() and os.path.isdir(self.prop['path'])):
            raise FileError("文件夹路径不正确，请设置正确的文件夹路径!", None, "002")
        for f in self._file_list:
            f.check()
            gevent.sleep(0)
        return True

    def add_files(self, file_type, path="*"):
        """
        添加文件夹下属文件

        :param file_type: 添加的文件类型自动加载路径
        :param path:  需要添加文件的路径，可以使用通配符，但是只能添加当前文件夹下的子文件或文件夹，
        不包含子文件夹迭代,默认"*"
        :return:
        """
        if not self.is_set:
            raise Exception("必须先设置路径!")
        class_module = load_class_by_path(file_type, tp="File")
        module = class_module()
        is_file = False
        is_dir = False
        if isinstance(module, File):
            is_file = True
        elif isinstance(module, Directory):
            is_dir = True
        if re.match("^/|^\.\.", path):
            raise Exception("不能使用绝对路径或切换到其他目录!")
        for f in glob.glob(os.path.join(self.path, path)):
            if (os.path.isfile(f) and is_file) or (os.path.isdir(f) and is_dir):
                    module = class_module()
                    module.set_path(f)
                    module.parent = self
                    self._file_list.append(module)

    @property
    def file_number(self):
        """
        获取下属文件对象数量,只包含直接下属，不包含间接下属
        :return:
        """
        return len(self._file_list)

    @property
    def files(self):
        """
        获取所有下属文件对象
        :return:
        """
        return self._file_list

    def get_info(self):
        super(Directory, self).get_info()
        self.set_property("file_number", self.file_number)

    def get_size(self):
        """
        获取文件大小
        """
        super(Directory, self).check()
        count, size = get_dir_size(self.path)
        return size

class GZipTool(object):
    """
    gzip文件压缩解压缩工具
    """

    def __init__(self, buf_size):
        self.buf_size = buf_size
        self.fin = None
        self.fout = None

    def compress(self, src, dst):
        self.fin = open(src, 'rb')
        self.fout = gzip.open(dst, 'wb')
        self.__in2out()

    def decompress(self, gz_file, dst):
        self.fin = gzip.open(gz_file, 'rb')
        self.fout = open(dst, 'wb')
        self.__in2out()

    def __in2out(self,):
        while True:
            buf = self.fin.read(self.buf_size)
            if len(buf) < 1:
                break
            self.fout.write(buf)
        self.fin.close()
        self.fout.close()


import Queue
#Definition for a  binary tree node

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def deserialize(self, data):
        """Decodes your encoded data to tree.

        :type data: str
        :rtype: TreeNode
        """
        node = TreeNode(0)
        root = node
        data_array = data.split(' ')
        is_root = False
        bin_constraint = 0
        node_queue = Queue.Queue()

        len_data = len(data_array)
        count = 0

        while count < len_data:
            element = data_array[count]
            if not is_root:
                if element is None:
                    return None
                else:
                    is_root = True
                    node.val = int(element)
                    node_queue.put(node)
                    count += 1
            else:
                node = node_queue.get()
                if bin_constraint == 0:
                    if element != 'null':
                        node.left = TreeNode(int(element))
                        node_queue.put(node.left)
                    bin_constraint += 1
                count += 1

                if bin_constraint == 1:
                    element = data_array[count]
                    if element != 'null':
                        node.right = TreeNode(int(element))
                        node_queue.put(node.right)
                    bin_constraint = 0
                count += 1

        return root

class BSTIterator(object):

    def __init__(self, root):
        """
        :type root: TreeNode
        """
        self.store_val = []
        self.has_next = False
        self.current_idx = -1
        self.len_store = 0
        self.stack_store = []
        self.in_order_traverse(root)

    def call_traverse(self, node):
        while True:
            if node is not None:
                self.stack_store.append(node)
                node = node.left
            else:
                if len(self.stack_store) > 0:
                    node = self.stack_store.pop()
                    self.store_val.append(node.val)
                    node = node.right
                else:
                    break
        self.len_store = len(self.store_val)

    def in_order_traverse(self, root):
        if root is None:
            return False
        if root.left is None and root.right is None:
            self.store_val.append(root.val)
            self.len_store = 1
            return True

        node = root.left
        if node is None:
            node = root.right
            self.store_val.append(root.val)

        self.call_traverse(node)

        if root.left is not None:
            self.stack_store.append(root)

    def hasNext(self):
        """
        :rtype: bool
        """
        self.current_idx += 1
        if self.current_idx < self.len_store:
            return True
        elif len(self.stack_store) > 0:
            node = self.stack_store.pop()
            self.store_val.append(node.val)
            node = node.right
            self.call_traverse(node)
            return True
        else:
            return False

    def next_v(self):
        """
        :rtype: int
        """
        val = self.store_val[self.current_idx]
        return val

def main():
    data = '8 3 10 1 6 null 14 null null 4 7 13 null'
    sol = Solution()
    deserialize_out = sol.deserialize(data)
    # Your BSTIterator will be called like this:

    i, v = BSTIterator(deserialize_out), []
    while i.hasNext():
        v.append(i.next_v())
    print(v)

if __name__ == '__main__':
    main()


import pandas as pd
import pytesseract.pytesseract
import requests as req
from bs4 import BeautifulSoup
from urllib.parse import urlparse
import urllib.request as urlreq
from pdf2image import convert_from_path
import os
import cv2
from PIL import Image
import json

'''---------------------1. READING DATA FROM EXCEL FILE-----------------------------------'''

def read_data(filename):
    # Reading Excel File
    data = pd.read_excel(filename, header=None)

    # Converting dataframe to list
    list_of_links = data.iloc[:, 0].values

    return list_of_links

'''---------------------2. FETCHING CONTENTS FROM LINKS AND STORING-----------------------'''

def pdf_download(list_of_links):
    opener = urlreq.build_opener()
    opener.addheaders = [('User-agent', 'Mozilla/5.0')]
    urlreq.install_opener(opener)

    i = 0
    for link in list_of_links:
        if '.pdf' in link:
            urlreq.urlretrieve(link, f"Downloaded_pdfs/pdf{i}.pdf")

        else:
            domain = "https://" + urlparse(link).netloc
            response = req.get(link)
            extracted_html = BeautifulSoup(response.text, 'html.parser')
            links_in_html = extracted_html.find_all('a')
            for sublink in links_in_html:
                if '.pdf' in sublink.get('href', []):
                    urlreq.urlretrieve(domain+sublink.get('href'), f"Downloaded_pdfs/pdf{i}.pdf")
                    break

        print(f"Downloaded PDF {i}")
        i += 1

'''---------------------3. CONVERTING PDFS TO IMAGES--------------------------------------'''

def pdf_to_images(path_to_pdf_directory, path_to_poppler_bin):
    for i in range(48):
        pages = convert_from_path(path_to_pdf_directory+f"\\pdf{i}.pdf", 300,
                                  poppler_path=path_to_poppler_bin)
        j = 0
        new_path = os.path.join("PDF_Images", f"Pdf{i}")
        os.mkdir(new_path)
        for page in pages:
            img_path = new_path + f"\\Pic_{j}.jpg"
            page.save(img_path, "JPEG")
            j += 1
        print(f"PDF {i} Done")

'''---------------------4. PROCESSING IMAGES-------------------------------------------'''

def process_pdf_images(list_of_pdf_links, path_to_pdf_images_dir, path_to_tesseract_exe, path_to_tessdata,
                       language="en", columns=False):
    pytesseract.pytesseract.tesseract_cmd = path_to_tesseract_exe
    tessdata_config = f'--tessdata-dir "{path_to_tessdata}" '
    if columns == True:
        tessdata_config += '--psm 3'
    else:
        tessdata_config += '--psm 6'

    json_content = []

    dirs = os.listdir(path_to_pdf_images_dir)
    dirs.sort(key=lambda x: int(x[3:]))

    for (i, dir) in enumerate(dirs):
        sub_dir = path_to_pdf_images_dir + "\\" + dir
        files = os.listdir(sub_dir)
        files.sort(key=lambda x: int(x[4:-4]))

        j, c, f = 0, 0, 0
        for file in files:
            img_path = sub_dir + "\\" + file
            img = cv2.imread(img_path)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
            tmp_file = f"{f}.png"
            f += 1
            cv2.imwrite(tmp_file, thresh)
            text = pytesseract.image_to_string(Image.open(tmp_file), lang=language, config=tessdata_config)
            os.remove(tmp_file)
            text = text.replace('\n', '')

            content = {}

            if ".pdf" in list_of_pdf_links[i]:
                content["pdf-url"] = list_of_pdf_links[i]
                content["page-url"] = content["pdf-url"]
            else:
                link = list_of_pdf_links[i]
                if "page" in link:
                    base_link = link.split("page")[0]
                else:
                    base_link = link.split("mode")[0]

                content["pdf-url"] = base_link + "mode/2up"
                if j == 0:
                    content["page-url"] = content["pdf-url"]
                    j += 1
                else:
                    content["page-url"] = base_link + f"page/n{j}/mode/2up"
                    c ^= 1
                    if c == 0:
                        j += 2

            content["pdf-content"] = text

            json_content.append(content)

        print(f"PDF {i} processed!")

    return json_content

'''---------------------5. PREPARING JSON FILE--------------------------------------------'''

def save_json_file(filename, json_content):
    with open(filename, "w") as file:
        json.dump(json_content, file, indent=2, ensure_ascii=False)

'''---------------------MAIN FUNCTION-----------------------------------------------------'''

def main():
    # ADD PATH of excel sheet
    filename = ''

    list_of_pdf_links = read_data(filename)

    pdf_download(list_of_links=list_of_pdf_links)

    # ADD PATH to "Downloaded_pdfs"
    path_to_pdf_directory = ""

    # ADD PATH to poppler bin folder
    path_to_poppler_bin = ""

    pdf_to_images(path_to_pdf_directory=path_to_pdf_directory, path_to_poppler_bin=path_to_poppler_bin)

    # ADD PATH to "PDF_Images"
    path_to_pdf_images_dir = ""

    # ADD PATH to "tesseract.exe"
    path_to_tesseract_exe = ""

    # ADD PATH to tessdata folder
    path_to_tessdata = ""

    # ADD language to be used
    language = ""

    json_content = process_pdf_images(list_of_pdf_links = list_of_pdf_links,
                                      path_to_pdf_images_dir=path_to_pdf_images_dir,
                                      path_to_tesseract_exe=path_to_tesseract_exe,
                                      path_to_tessdata=path_to_tessdata,
                                      language=language,
                                      columns=True)

    save_json_file(filename="pdf_extract.json", json_content=json_content)

if __name__ == "__main__":
    main()


import pygame
import time
import code_tic_tac_toe as tic
import sys
pygame.init()
size = width, height = 610, 410
white = (255, 255, 255)
violet = (127, 0, 255)
black = (0, 0, 0)
screen = pygame.display.set_mode(size)
mf = pygame.font.SysFont('arial', 20)
lf = pygame.font.SysFont('arial', 40)
mof = pygame.font.SysFont('arial', 60)
user = None
board = tic.initial_state()
ai_turn = False
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    screen.fill(violet)
    if user is None:
        title = lf.render("Let's Play Tic-Tac-Toe", True, white)
        titleRect = title.get_rect()
        titleRect.center = ((width / 2), 60)
        screen.blit(title, titleRect)

        title1 = mf.render("please select your character to start the game", True, black)
        title1Rect = title1.get_rect()
        title1Rect.center = ((width / 2), 95)
        screen.blit(title1, title1Rect)

        title2 = mf.render("AI - Case Study", True, black)
        title2Rect = title1.get_rect()
        title2Rect.center = ((width / 2), 370)
        screen.blit(title2, title2Rect)

        plyXbtn = pygame.Rect((width / 8), (height / 2), width / 4, 90)
        playX = mf.render("X", True, black)
        playXRect = playX.get_rect()
        playXRect.center = plyXbtn.center
        pygame.draw.rect(screen, white, plyXbtn)
        screen.blit(playX, playXRect)

        plyObtn = pygame.Rect(5 * (width / 8), (height / 2), width / 4, 90)
        playO = mf.render("O", True, black)
        playORect = playO.get_rect()
        playORect.center = plyObtn.center
        pygame.draw.rect(screen, white, plyObtn)
        screen.blit(playO, playORect)
        click, _, _ = pygame.mouse.get_pressed()
        if click == 1:
            mouse = pygame.mouse.get_pos()
            if plyXbtn.collidepoint(mouse):
                time.sleep(0.2)
                user = tic.X
            elif plyObtn.collidepoint(mouse):
                time.sleep(0.2)
                user = tic.O
    else:
        tile_size = 80
        tile_origin = (width / 2 - (1.5 * tile_size),
                       height / 2 - (1.5 * tile_size))
        tiles = []
        for i in range(3):
            row = []
            for j in range(3):
                rect = pygame.Rect(
                    tile_origin[0] + j * tile_size,
                    tile_origin[1] + i * tile_size,
                    tile_size, tile_size
                )
                pygame.draw.rect(screen, white, rect, 3)

                if board[i][j] != tic.EMPTY:
                    move = mof.render(board[i][j], True, white)
                    moveRect = move.get_rect()
                    moveRect.center = rect.center
                    screen.blit(move, moveRect)
                row.append(rect)
            tiles.append(row)

        game_over = tic.terminal(board)
        player = tic.player(board)
        if game_over:
            winner = tic.winner(board)
            if winner is None:
                title = f"DRAW!."
            else:
                title = f"Game Over: {winner} WINS!."
        elif user == player:
            title = f"Play as {user}"
        else:
            title = f""
        title = lf.render(title, True, white)
        titleRect = title.get_rect()
        titleRect.center = ((width / 2), 30)
        screen.blit(title, titleRect)
        if user != player and not game_over:
            if ai_turn:
                time.sleep(0.5)
                move = tic.mini_max(board)
                board = tic.result(board, move)
                ai_turn = False
            else:
                ai_turn = True
        click, _, _ = pygame.mouse.get_pressed()
        if click == 1 and user == player and not game_over:
            mouse = pygame.mouse.get_pos()
            for i in range(3):
                for j in range(3):
                    if (board[i][j] == tic.EMPTY and tiles[i][j].collidepoint(mouse)):
                        board = tic.result(board, (i, j))
        if game_over:
            againButton = pygame.Rect(width / 3, height - 65, width / 3, 50)
            again = mf.render("Restart Game", True, black)
            againRect = again.get_rect()
            againRect.center = againButton.center
            pygame.draw.rect(screen, white, againButton)
            screen.blit(again, againRect)
            click, _, _ = pygame.mouse.get_pressed()
            if click == 1:
                mouse = pygame.mouse.get_pos()
                if againButton.collidepoint(mouse):
                    time.sleep(0.2)
                    user = None
                    board = tic.initial_state()
                    ai_turn = False

    pygame.display.flip()


# # Lab 5 : ASTR400B

# Import modules
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from astropy import constants as const # import astropy constants
import astropy.units as u

# # Part A :  Mass to Light Ratios
#
# Wolf et al. 2010
#
# $M(<R_{half}) = \frac {4}{G}\sigma^2 R_e$
#
# Where $R_{half}$ = 3D half mass radius
# and $R_e$ is the 2D half mass radius of stars (observed)
#
# Determine which of the following two systems are galaxies:
#
# The system 47 Tuc is observed with:  $\sigma = 17.3$ km/s, $R_e = 0.5$ pc, $L_v \sim 10^5 L_\odot$
#
# The system Willman I is observed with: $\sigma = 4.3$ km/s, $R_e = 25$ pc, $L_v = 10^3 L_\odot$

# Gravitational Constant in the desired units
# kpc^3/Gyr^2/Msun
Grav = const.G.to(u.kpc**3/u.Gyr**2/u.Msun)

def WolfMass(sigma, re):
    """ Function that defines the Wolf mass estimator from Wolf+ 2010
    PARAMETERS
    ----------
        sigma: astropy quantity
            1D line of sight velocity dispersion in km/s
        re: astropy quantity
            Effective radius, 2D radius enclosing half the
            stellar mass in kpc
    OUTPUTS
    -------
        mWolf: Returns the dynamical mass within the
            half light radius in Msun
    """
    sigmaKpcGyr = sigma.to(u.kpc/u.Gyr)
    mWolf = 4/Grav*sigmaKpcGyr**2*re
    return mWolf

# 47 Tuc the globular cluster
lumTuc = 1e5*u.Lsun # luminosity
sigmaTuc = 17.3*u.km/u.s # velocity dispersion
reTuc = 0.5/1000*u.kpc # effective radius in kpc

# Determine the dynamical mass of 47 Tuc
massTuc = WolfMass(sigmaTuc, reTuc)
print(massTuc)
massTuc

print(f" Mass to Light Ratio 47 Tuc: {np.around(massTuc/lumTuc,3)}")
# this is globular cluster

# Willman I
lumWI = 1e3*u.Lsun # luminosity
sigmaWI = 4.3*u.km/u.s # velocity dispersion
reWI  =  25/1000*u.kpc  # effective radius

# Compute the dynamical mass
massWI = WolfMass(sigmaWI,reWI)
print(massWI)
massWI

print(f" Mass to Light Ratio Willman 1: {np.around(massWI/lumWI,3):}")
# this is a galaxy

# # Part B :  Stellar to Halo Mass Relation
#
# Following the work of [Moster et al. 2013 (MNRAS, 428, 3121)](https://ui.adsabs.harvard.edu/abs/2013MNRAS.428.3121M/abstract)
#
#
# `Equation 2:`                  $ \frac{m}{M} = 2N \left [ \left ( \frac{M}{M_1} \right)^{-\beta} + \left (\frac{M}{M_1} \right)^{\gamma} \right]$
#
# $m$ = stellar mass, $M$ = halo mass
#
# `Equation 11:`        log $M_1(z) = M_{10} + M_{11} \frac{z}{z+1} $
#
# `Equation 12:`        $N(z) = N_{10} + N_{11} \frac{z}{z+1} $
#
# `Equation 13:`         $\beta(z) = \beta_{10} + \beta_{11} \frac{z}{z+1} $
#
# `Equation 14:`         $\gamma(z) = \gamma_{10} + \gamma_{11} \frac{z}{z+1} $

# # Q1
#
# Modify the class below by adding a function that takes the `SHMratio` and returns the stellar mass.

class AbundanceMatching:
    """ Class to define the abundance matching relations from
    Moster et al. 2013"""

    def __init__(self, mhalo, z):
        """ Initialize the class
        PARAMETERS
        ----------
            mhalo: float
                Halo mass in Msun
            z: float
                redshift
        """

        #initializing the parameters:
        self.mhalo = mhalo # Halo Mass in Msun
        self.z = z  # Redshift

    def logM1(self):
        """eq. 11 of Moster 2013
        OUTPUT:
            M1: float
                characteristic mass in log(Msun)
        """
        M10      = 11.59
        M11      = 1.195
        return M10 + M11*(self.z/(1+self.z))

    def N(self):
        """eq. 12 of Moster 2013
        OUTPUT:
            Normalization for eq. 2
        """
        N10      = 0.0351
        N11      = -0.0247

        return N10 + N11*(self.z/(1+self.z))

    def Beta(self):
        """eq. 13 of Moster 2013
        OUTPUT:  power of the low mass slope"""
        beta10      = 1.376
        beta11      = -0.826

        return beta10 + beta11*(self.z/(1+self.z))

    def Gamma(self):
        """eq. 14 of Moster 2013
        OUTPUT: power of the high mass slope """
        gamma10      = 0.608
        gamma11      = 0.329

        return gamma10 + gamma11*(self.z/(1+self.z))

    def SHMratio(self):
        """
        eq. 2 of Moster + 2013
        OUTPUT:
            SHMratio float
                Stellar mass to halo mass ratio
        """
        M1 = 10**self.logM1() # Converting characteristic mass
        # to Msun from Log(Msun)
        A = (self.mhalo/M1)**(-self.Beta())  # Low mass end
        B = (self.mhalo/M1)**(self.Gamma())   # High mass end
        Norm = 2*self.N() # Normalization

        SHMratio = Norm*(A+B)**(-1)

        return SHMratio

 # Q1: add a function to the class that takes the SHM ratio and returns
# The stellar mass

    def StellarMass(self):
        """ Method to compute the stellar mass
        using eq. 2 of Moster + 2013

        OUTPUT: float, stellar mass in Msun"""

        return self.mhalo*self.SHMratio()

# # Part C : Plot the Moster Relation
#
# Reproduce the below figure from Moster + 2013
# Plot this for z=0, 0.5, 1, 2
#
# ![mos](./MosterFig.png)

mh = np.logspace(10,15,1000) # Logarithmically spaced array

# Define Instances of the Class for each redshift
MosterZ0 = AbundanceMatching(mh,0)
MosterZ0_5 = AbundanceMatching(mh,0.5)
MosterZ1 = AbundanceMatching(mh,1)
MosterZ2 = AbundanceMatching(mh,2)

fig,ax = plt.subplots(figsize=(10,8))

#adjust tick label font size
label_size = 22
matplotlib.rcParams['xtick.labelsize'] = label_size
matplotlib.rcParams['ytick.labelsize'] = label_size

# Plot z = 0
plt.plot(np.log10(mh), np.log10(MosterZ0.StellarMass()),
         linewidth = 5, label='z=0')
# Plot z = 0.5
plt.plot(np.log10(mh), np.log10(MosterZ0_5.StellarMass()),
         linewidth = 5, linestyle='-.', label = 'z=0.5')
# Plot z = 1
plt.plot(np.log10(mh), np.log10(MosterZ1.StellarMass()),
         linewidth = 5, linestyle='--', label = 'z=1')
# Plot z = 2
plt.plot(np.log10(mh), np.log10(MosterZ2.StellarMass()),
         linewidth = 5, linestyle=':', label='z=2')

# Axes labels
plt.xlabel('log (M$_h$/M$_\odot$)',fontsize=22)
plt.ylabel('log (m$_\star$/M$_\odot$)', fontsize=22)

# Legend
plt.legend(loc='lower right',fontsize='x-large')

# save the file
plt.savefig(AbundanceMatching_Lab5.png)

# At every halo mass, the stellar mass is lower backwards in time.
# The characteristic stellar mass is higher at higher redshift
# -- so massive things do form early, then the smaller
# systems will catch up
# Lowest stellar mass is 1e8

# # Part D
#
# # Q1
#
# In traditional models of the Magellanic Clouds (prior to 2010), the LMC is thought to have a halo mass of order $3 \times 10^{10}$ M$_\odot$.  According to LCDM theory, what should be the stellar mass of such a halo at z=0?
#
# How does this compare against the actual observed stellar mass of the LMC at the present day of $3 \times 10^9$ M$_\odot$ ?
#
# What is the $\Lambda$CDM expected halo mass? What is the origin of any discrepancy?

# LMC halo mass
haloLMC1 = 3e10 # original halo mass

# Create a class object
LMC1 = AbundanceMatching(haloLMC1,0)

# Use LMC object to determine its stellar mass
print(f"Expected M* of LMC: {np.round(LMC1.StellarMass()/1e9,3)}(1e9 Msun)")

# Compare against the real stellar mass
starLMC = 3e9
print(f"Percentage of observed M*: {np.round(LMC1.StellarMass()/starLMC,3)*100}%")

# So what should the LMC's halo mass be to give a stellar mass of 3e9?
# Start with a guess
haloLMC2 = 1.65e11

LMC2 = AbundanceMatching(haloLMC2,0)
print(f"Expected Stellar Mass of LMC {np.round(LMC2.StellarMass()/1e9,3)}  (1e9 Msun)")

# LEsson: the Halo mass relation only returns the halo mass of CENTRALS

# # Q2
#
# What is the expected stellar mass of an L* galaxy at z=0?
#
# What is the expected stellar mass of an L* galaxy at z = 2?

print(f'Log M1, characteristic halo mass at z=0: {MosterZ0.logM1()}')
MstarZ0 = AbundanceMatching(10**MosterZ0.logM1(),0)

print(f'Stellar mass of L* galaxy at z=0: {np.around(MstarZ0.StellarMass()/1e10,2)} (1e10 Msun) ')

print(f'Log M1, characteristic halo mass at z=2: {MosterZ2.logM1()}')
MstarZ2 = AbundanceMatching(10**MosterZ2.logM1(),0)

print(f'Stellar mass of L* galaxy at z=2: {np.around(MstarZ2.StellarMass()/1e10,2)} (1e10 Msun) ')


import csv
f = open("C:\\Users\\SSHS\\Desktop\\업무\\연수\\2021 AI 관련 교과 융합 연수(비대면 실시간)\\seoul.csv", "r", encoding="cp949")
data = csv.reader(f, delimiter = ",")
header = next(data)
max_temp = -999
max_date = ""

for row in data:
    if row[-1] == "":
        row[-1] = -999
    row[-1] = float(row[-1])
    if max_temp < row[-1]:
        max_date = row[0]
        max_temp = row[-1]
print(f"최고기온 : {max_temp}, 그 때의 날짜는 {max_date} 입니다.")
f.close()

AI연수 5일차_서울 최고 온도 찾기.py

AI연수 5일차_서울 최고 온도 찾기.py