from django.db import models
from django.utils.translation import ugettext_lazy as _
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel
from shuup.core.models import ShuupModel

class GivesomeOffice(MPTTModel, ShuupModel):
    """Sub-vendor for companies with branded page"""

    supplier = models.ForeignKey("shuup.Supplier", on_delete=models.CASCADE, related_name="offices")
    name = models.CharField(max_length=64, verbose_name=_("name"))
    ordering = models.IntegerField(default=0, verbose_name=_("ordering"))
    disabled = models.BooleanField(
        default=False,
        help_text=_(
            "Disable this office. This office will not be show in the front for customers anymore. "
            "All children offices are affected as well. "
            "Any related Givecard restrictions will be left unaffected, which means that if any Batches are "
            "restricted to this Office or any child offices, it will be impossible to use any of those Givecards."
        ),
    )
    primary_project = models.ForeignKey(
        "shuup.ShopProduct",
        related_name="primary_offices",
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        verbose_name=_("Primary project"),
        help_text=_("Selected project will be prioritized when automatically reallocating expiring Givecard funds."),
    )
    parent = TreeForeignKey(
        "self",
        null=True,
        blank=True,
        related_name="children",
        verbose_name=_("Parent office"),
        on_delete=models.SET_NULL,
        help_text=_("If your office is a sub-office of another office, you can link them here."),
    )

    class Meta:
        ordering = ("supplier", "level", "ordering")

    def __str__(self):
        name = self.name
        for ancestor in self.get_ancestors(ascending=True):  # Immediate parents first
            name = f"{name} > {ancestor.name}"
        return f"{name} > {self.supplier.name}"

class SupplierOfficeTerm(models.Model):
    supplier = models.ForeignKey(
        "shuup.Supplier",
        related_name="office_terms",
        on_delete=models.CASCADE,
    )
    level = models.PositiveIntegerField(default=0)
    name = models.CharField(
        max_length=32,
        verbose_name=_("Office term"),
        help_text=_("Enter a term you want to use for your offices/chapters/locations."),
    )

    class Meta:
        unique_together = ("supplier", "level")
        ordering = ("supplier", "level")

    def __str__(self):
        return self.name


from tornado import gen, web

from jupyterhub.handlers.pages import BaseHandler
from IPython.html.utils import url_path_join
from tornado.httputil import url_concat
from tornado.escape import json_encode
from . import __version__
from .metrica import MetricaIdsMixin

class UserSpawnHandler(BaseHandler):

    @gen.coroutine
    def get(self, name, user_path):
        current_user = self.get_current_user()
        if current_user and current_user.name == name:
            # logged in, work with spawner
            is_log_request = self.get_argument('get_logs', False)
            is_failed = False
            is_up = False
            if current_user.spawner:
                spawner = current_user.spawner
                is_running = yield spawner.is_running()
                log_lines = spawner.user_log
                is_failed = spawner.is_failed
                is_up = spawner.is_up
                if spawner.is_empty and not is_failed:
                    self.redirect(url_path_join(self.hub.server.base_url, 'home'))
                    return
            else:
                log_lines = []
            if current_user.stop_pending and not is_failed:
                self.redirect(url_path_join(self.hub.server.base_url, 'home'))
                return
            if is_log_request:
                resp = {
                    'log': log_lines
                }
                if is_failed:
                    resp.update({
                        'failed': 1
                    })
                elif is_up:
                    resp.update({
                        'done': 1
                    })
                self.finish(json_encode(resp))
            else:
                if is_up:
                    self.set_login_cookie(current_user)
                    target = '/user/%s/' % (
                        current_user.name
                    )
                    self.log.info('redirecting to %s' % target)
                    self.redirect(target)
                    return
                metrica = MetricaIdsMixin()
                g_id = metrica.g_analitics_id
                ya_id = metrica.ya_metrica_id
                html = self.render_template(
                    "spawn_pending.html",
                    version=__version__,
                    g_analitics_id=g_id,
                    ya_metrica_id=ya_id
                )
                self.finish(html)
        else:
            # logged in as a different user, redirect
            target = url_path_join(self.base_url, 'login')
            self.redirect(target)


from flask import Flask, render_template, request, redirect
from database.get_connection import get_connection
from database.init_db import init_db
from database.insert_db import insert_db
import click
from flask.cli import with_appcontext
import database.user_controller as user_controller
import database.providers_controller as providers_controller
import database.movies_controller as movies_controller
import database.rentals_controller as rentals_controller
import database.ratings_controller as ratings_controller
from datetime import date

app = Flask(__name__)
app.config.from_pyfile("config/config.py")

@app.route('/usuarios')
def get_users():
    users = user_controller.get_users()
    return render_template('users.html', users=users)

@app.route('/proveedores')
def get_providers():
    providers = providers_controller.get_providers()
    return render_template('providers.html', providers=providers)

@app.route('/peliculas')
def get_movies():
    movies = movies_controller.get_movies()
    return render_template('movies.html', movies=movies)

@app.route('/alquileres')
def get_rentals():
    rentals = rentals_controller.get_rentals()
    return render_template('rentals.html', rentals=rentals)

@app.route('/valoraciones')
def get_ratings():
    ratings = ratings_controller.get_ratings()
    return render_template('ratings.html', ratings=ratings)

@app.route('/methods/crear_pelicula', methods=['POST'])
def create_movie():
    title = request.form['title']
    category = request.form['category']
    description = request.form['description']
    provider = request.form['provider']
    units = request.form['units']

    # First primary key check
    exists = movies_controller.get_movie_by_title(title)
    if exists is not None:
        return render_template('add_movie.html',
                               error='Violación de integridad de clave primaria: La película ya ha sido agregada 🔑')

    # Second foreign key check
    exists = providers_controller.get_provider_by_company(provider)
    if exists is None:
        return render_template('add_movie.html',
                               error='Violación de integridad de clave foránea: La empresa proveedora no existe 🔐')

    movies_controller.insert_movie(title, category, description, provider, units)
    return redirect('/peliculas')

@app.route('/methods/crear_alquiler', methods=['POST'])
def create_rental():
    title = request.form['title']
    owner = request.form['owner']
    start = request.form['start']
    end = request.form['end']
    type_query = request.form['type']

    # First primary key check
    exists = rentals_controller.get_rental_by_title_and_owner(title, owner)
    if exists is not None:
        return render_template('add_rental.html',
                               error='Violación de integridad de clave primaria: El alquiler ya ha sido creado 🔑')

    # Second foreign key check (with movie)
    exists = movies_controller.get_movie_by_title(title)
    if exists is None:
        return render_template('add_rental.html',
                               error='Violación de integridad de clave foránea: La película introducida no existe 🔐')

    # Third foreign key check (with user)
    exists = user_controller.get_user_by_nick(owner)
    if exists is None:
        return render_template('add_rental.html',
                               error='Violación de integridad de clave foránea: El usuario introducido no existe 🔐')

    # We must check if the movie is available with the total units
    units = movies_controller.get_movie_units(title)

    if units <= 0:
        return render_template('add_rental.html',
                               error='Restricción del dominio del problema: No hay unidades disponibles 🧿')

    # We must check if introduced date is greater than the current date
    if start < date.today().strftime("%Y-%m-%d"):
        return render_template('add_rental.html',
                               error='Restricción del dominio del problema: La fecha de alquiler no puede ser menor que la fecha actual 🧿')

    # We must check that the return date is greater than the rental date
    if start > end:
        rental = rentals_controller.get_rental_by_title_and_owner(title, owner)
        return render_template('add_rental.html',
                               error='Restricción del dominio del problema: La fecha de devolución no puede ser menor que la fecha de alquiler 🧿')

    rentals_controller.insert_rental(title, owner, start, end, type_query)

    # We must decrease the final units of the movie
    movies_controller.decrease_units(title)

    return redirect('/alquileres')

@app.route('/methods/crear_valoracion', methods=['POST'])
def create_rating():
    title = request.form['title']
    author = request.form['author']
    score = request.form['rating']
    comment = request.form['comment']

    # First primary key check
    exists = ratings_controller.get_rating_by_title_and_author(title, author)
    if exists is not None:
        return render_template('add_rating.html',
                               error='Violación de integridad de clave primaria: La valoración ya ha sido creada 🔑')

    # Second foreign key check (with movie)
    exists = movies_controller.get_movie_by_title(title)
    if exists is None:
        return render_template('add_rating.html',
                               error='Violación de integridad de clave foránea: La película introducida no existe 🔐')

    # Third foreign key check (with user)
    exists = user_controller.get_user_by_nick(author)
    if exists is None:
        return render_template('add_rating.html',
                               error='Violación de integridad de clave foránea: El usuario introducido no existe 🔐')

    # We must check if the score is between 0 and 10
    if float(score) < 0 or float(score) > 10:
        return render_template('add_rating.html',
                               error='Restricción del dominio del problema: La puntuación debe estar entre 0 y 10 🧿')

    ratings_controller.insert_rating(title, score, comment, author)

    return redirect('/valoraciones')

@app.route('/methods/crear_proveedor', methods=['POST'])
def create_provider():
    company = request.form['company']
    nif = request.form['nif']
    phone = request.form['phone']

    exists = providers_controller.get_provider_by_company(company)
    if exists is not None:
        return render_template('add_provider.html',
                               error='Violación de integridad de clave primaria: La empresa ya ha sido creada 🔑')

    providers_controller.insert_provider(company, nif, phone)
    return redirect('/proveedores')

@app.route('/methods/eliminar_proveedor', methods=['POST'])
def delete_provider():
    company = request.form['company']
    providers_controller.delete_provider(company)
    return redirect('/proveedores')

@app.route('/methods/eliminar_pelicula', methods=['POST'])
def delete_movie():
    title = request.form['title']
    movies_controller.delete_movie(title)
    return redirect('/peliculas')

@app.route('/alquileres/agregar_alquiler')
def add_rental():
    return render_template('add_rental.html')

@app.route('/valoraciones/agregar_valoracion')
def add_rating():
    return render_template('add_rating.html')

@app.route('/proveedores/agregar_proveedor')
def add_provider():
    return render_template('add_provider.html')

@app.route('/usuarios/agregar_usuario')
def add_user():
    return render_template('add_user.html')

@app.route('/peliculas/agregar_pelicula')
def add_movie():
    return render_template('add_movie.html')

@app.route('/usuarios/editar_usuario/<string:id>')
def edit_user(id):
    user = user_controller.get_user_by_nick(id)
    return render_template('edit_user.html', user=user)

@app.route('/alquileres/editar_alquiler/<string:owner>/<string:title>')
def edit_rental(owner, title):
    rental = rentals_controller.get_rental_by_title_and_owner(title, owner)
    return render_template('edit_rental.html', rental=rental)

@app.route('/valoraciones/editar_valoracion/<string:author>/<string:title>')
def edit_rating(author, title):
    rating = ratings_controller.get_rating_by_title_and_author(title, author)
    return render_template('edit_rating.html', rating=rating)

@app.route('/peliculas/editar_pelicula/<string:id>')
def edit_movie(id):
    movie = movies_controller.get_movie_by_title(id)
    return render_template('edit_movie.html', movie=movie)

@app.route('/methods/editar_usuario', methods=['POST'])
def update_user():
    nick = request.form['nick']
    name = request.form['name']
    email = request.form['email']
    user_controller.update_user(nick, name, email)
    return redirect('/usuarios')

@app.route('/methods/editar_pelicula', methods=['POST'])
def update_movie():
    title = request.form['title']
    category = request.form['category']
    description = request.form['description']
    provider = request.form['provider']
    units = request.form['units']

    # Second foreign key check
    exists = providers_controller.get_provider_by_company(provider)
    if exists is None:
        movie = movies_controller.get_movie_by_title(title)

        return render_template('edit_movie.html',
                               error='Violación de integridad de clave foránea: La empresa proveedora no existe 🔐',
                               movie=movie)

    movies_controller.update_movie(title, category, description, provider, units)
    return redirect('/peliculas')

@app.route('/methods/editar_alquiler', methods=['POST'])
def update_rental():
    owner = request.form['owner']
    title = request.form['title']
    rental_date = request.form['start']
    return_date = request.form['end']
    type_query = request.form['type']

    # We must check if introduced date is greater than the current date
    if rental_date < date.today().strftime("%Y-%m-%d"):
        rental = rentals_controller.get_rental_by_title_and_owner(title, owner)
        return render_template('edit_rental.html',
                               error='Restricción del dominio del problema: La fecha de alquiler no puede ser menor que la fecha actual 🧿',
                               rental=rental)

    # We must check that the return date is greater than the rental date
    if rental_date > return_date:
        rental = rentals_controller.get_rental_by_title_and_owner(title, owner)
        return render_template('edit_rental.html',
                               error='Restricción del dominio del problema: La fecha de devolución no puede ser menor que la fecha de alquiler 🧿',
                               rental=rental)

    rentals_controller.update_rental(title, owner, rental_date, return_date, type_query)

    return redirect('/alquileres')

@app.route('/methods/editar_valoracion', methods=['POST'])
def update_rating():
    author = request.form['author']
    title = request.form['title']
    rating = request.form['rating']
    comment = request.form['comment']

    # We must check that the rating is between 0 and 10
    if float(rating) < 0 or float(rating) > 10:
        rating = ratings_controller.get_rating_by_title_and_author(title, author)

        return render_template('edit_rating.html',
                               error='Restricción del dominio del problema: La valoración debe estar entre 0 y 10 estrellas (⭐) 🧿',
                               rating=rating)

    ratings_controller.update_rating(title, rating, comment, author)

    return redirect('/valoraciones')

@app.route('/methods/crear_usuario', methods=['POST'])
def create_user():
    nick = request.form['nick']

    exists = user_controller.get_user_by_nick(nick)
    if exists is not None:
        return render_template('add_user.html', error='Violación de integridad de clave primaria: El nick ya existe 🔑')

    name = request.form['name']
    email = request.form['email']

    user_controller.insert_user(nick, name, email)
    return redirect('/usuarios')

@app.route('/methods/eliminar_usuario', methods=['POST'])
def delete_user():
    nick = request.form['nick']
    user_controller.delete_user(nick)
    return redirect('/usuarios')

@app.route('/methods/eliminar_alquiler', methods=['POST'])
def delete_rental():
    owner = request.form['owner']
    title = request.form['title']
    rentals_controller.delete_rental(title, owner)

    # We must increase the final units of the movie
    movies_controller.increase_units(title)

    return redirect('/alquileres')

@app.route('/methods/eliminar_valoracion', methods=['POST'])
def delete_rating():
    author = request.form['author']
    title = request.form['title']
    ratings_controller.delete_rating(title, author)
    return redirect('/valoraciones')

@app.route('/proveedores/editar_proveedor/<string:id>')
def edit_provider(id):
    provider = providers_controller.get_provider_by_company(id)
    return render_template('edit_provider.html', provider=provider)

@app.route('/methods/editar_proveedor', methods=['POST'])
def update_provider():
    company = request.form['company']
    nif = request.form['nif']
    phone = request.form['phone']
    providers_controller.update_provider(company, nif, phone)
    return redirect('/proveedores')

@click.command("init-db")
@with_appcontext
def init_db_command():
    """Clear the existing data and create new tables"""
    init_db()
    click.echo("Database initialized correctly! 🚀")
    insert_db()
    click.echo("All records in the database have been inserted correctly! 🔋")

app.cli.add_command(init_db_command)

@app.route('/restoreDatabaseEmpty')
def create_database():
    init_db()
    return str("The database has been successfully restored!")

@app.route('/restoreDatabaseInitialized')
def insert_records():
    # We must restore the database to its original state for insert the vanilla records
    init_db()
    insert_db()
    return str("The database has been successfully restored and initialized!")

@app.route('/')
def get_index():  # put application's code here
    return render_template('base.html')

if __name__ == '__main__':
    app.run(debug=True)


import os
import zipfile

import patoolib

from common.common_service import MyServiceException

class MyArchive(object):
    @staticmethod
    def unzip(filepath, file_name):
        zip_file = zipfile.ZipFile(file_name)
        if not os.path.isdir(filepath):
            os.mkdir(filepath)
        for names in zip_file.namelist():
            zip_file.extract(names, filepath + "/")
        zip_file.close()

    @staticmethod
    def un_archive(filename_path):
        if not filename_path:
            return
        archive_format_index = filename_path.rfind(".") + len(".")
        archive_format = filename_path[archive_format_index:]
        filepath = filename_path[:archive_format_index - 1]

        if "zip" == archive_format:
            MyArchive.unzip(filepath, filename_path)
        else:
            raise MyServiceException("解压压缩文件失败, 不支持的文件类型")
        return filepath

    @staticmethod
    def extra_file(file_path):
        file_extra_dir = file_path[0:file_path.rfind(".")]
        if not os.path.exists(file_extra_dir):
            os.mkdir(file_extra_dir)
        patoolib.extract_archive(file_path, outdir=file_extra_dir)
        return file_extra_dir


import pygame
import pymunk
import OpenGL.GLU
import OpenGL.GL
#### SETUP THE PHYSICS
space = pymunk.Space()     # Create a Space which contain the simulation
space.gravity = 0, -2000     # Set its gravity
#### SETUP THE GAME OBJECTS
game_objects = pygame.sprite.Group() ## Use a pygame group for added functionality
#### SCREEN-TO-WORLD COORDINATE CONVERSION SYSTEM
def screen_to_world( pos ):
    x, y = pos
    viewport = OpenGL.GL.glGetIntegerv( OpenGL.GL.GL_VIEWPORT)
    y_max = viewport[3]
    u_x, u_y, u_z = OpenGL.GLU.gluUnProject( x, y_max-y, 1,
                                            OpenGL.GL.glGetDoublev( OpenGL.GL.GL_MODELVIEW_MATRIX),
                                            OpenGL.GL.glGetDoublev( OpenGL.GL.GL_PROJECTION_MATRIX),
                                            viewport )
    return u_x, u_y
def world_to_screen( pos ):
    x, y = pos
    viewport = OpenGL.GL.glGetIntegerv( OpenGL.GL.GL_VIEWPORT)
    y_max = viewport[3]
    p_x, p_y, p_z = OpenGL.GLU.gluProject( x, y, 1,
                                            OpenGL.GL.glGetDoublev( OpenGL.GL.GL_MODELVIEW_MATRIX),
                                            OpenGL.GL.glGetDoublev( OpenGL.GL.GL_PROJECTION_MATRIX),
                                            viewport )
    return p_x, y_max - p_y


import requests
from decouple import config
class APIHandler:
    def __init__(self) -> None:
        self.api_key = config("OPENAIKEY")
        self.url = config("VFAPI")
    def ai_request(self,message:str):
        print(message)

        message = f"Eres una humano digital, estás entrenada por The AI Humans para brindar información sobre sus servicios de automatizaciones empresariales impulsados por el uso de Inteligencia Artificial conversacional enfocada en humanos digitales, chatbots para integraciones con Whatsapp, Messenger, Web y otros así como capacitaciones, entre otras funciones tienes ayudar al usuario a agendar un demo, ver productos y responder de manera generativa a cualquier pregunta como la siguiente {message}, con una personalidad de una experta en marketing y negocios digitales, además debes responder en menos de 70 palabras y terminar la respuesta con una pregunta corta basada en el contexto de la pregunta del usuario y que incentive al usuario a conocer más sobre nosotros y poder concretar una cita o una venta de nuestros productos"
        reply = ""

        #print(user_id)
        body = {"action": {"type": "text", "payload": message}}

        # Start a conversation

        try:

            response = requests.post(url=self.url,
            json=body,
            headers={"Authorization": self.api_key},)

            print(response.text)
            for trace in response.json():
                    if trace['type'] == 'speak' or trace['type'] == 'text':
                        mensaje = trace['payload']['message']
                        # Texto que deseas eliminar
                        text_to_remove = "I'm sorry for the confusion earlier. Here are the answers: - "
                        other_text = "I apologize for the mistake earlier. Here are the answers: - "
                        # Reemplazar el texto no deseado con una cadena vacía
                        mensaje = mensaje.replace(text_to_remove, "")
                        mensaje = mensaje.replace(other_text, "")
                        print(type(mensaje))
                        if mensaje!="":
                            reply = self.message_payload = {
                            "fulfillment_response": {
                                "messages": [
                                {
                                    "text": {
                                        "text":[mensaje]
                                    }
                                }
                                ]
                            }
                        }

                            return reply
                        raise ValueError("Error conjunto vacío")
        except:
            reply = {
                "fulfillmentMessages":[
                    {
                        "text":
                        {
                            "text": [
                                "Lo sentimos, estamos mejorando la calidad de nuestro servicio de Chatbot. ¿Puedes volver a realizar la consulta?"
                            ]
                        }
                    }
                    ]
            }
            return reply


import asyncio
from argparse import Namespace
from pathlib import Path
from typing import Any, Callable, Dict, Optional, Union, ContextManager, Tuple

import pytest
from starknet_py.net.models import StarknetChainId

from protostar import TestCommand
from protostar.argument_parser import ArgumentParserFacade, CLIApp
from protostar.cli import MessengerFactory
from protostar.cli.signable_command_util import PRIVATE_KEY_ENV_VAR_NAME
from protostar.commands import (
    BuildCommand,
    CalculateAccountAddressCommand,
    CallCommand,
    DeclareCommand,
    FormatCommand,
    InitCommand,
    InvokeCommand,
    MulticallCommand,
    DeclareCairo0Command,
    TestCairo0Command,
    BuildCairo0Command,
    InitCairo0Command,
)
from protostar.commands.deploy_account_command import DeployAccountCommand
from protostar.commands.deploy_command import DeployCommand
from protostar.commands.legacy_commands.test_cairo0.test_result_formatter import (
    format_test_result,
)
from protostar.formatter.formatting_result import FormattingResult
from protostar.formatter.formatting_summary import FormattingSummary
from protostar.io import log_color_provider
from protostar.starknet_gateway import Fee, Wei
from protostar.testing import TestingSummary
from protostar.starknet import Address
from protostar.starknet.data_transformer import CairoOrPythonData
from protostar.testing.test_results import TestResult
from protostar.cairo.bindings.cairo_bindings import PackageName
from tests.conftest import DevnetAccount

from .tokenizer import tokenize
from .transaction_registry import TransactionRegistry

ContractMap = Dict[str, list[str]]

# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-public-methods
class ProtostarFixture:
    def __init__(
        self,
        project_root_path: Path,
        init_command: InitCommand,
        init_cairo0_command: InitCairo0Command,
        build_command: BuildCommand,
        build_cairo0_command: BuildCairo0Command,
        format_command: FormatCommand,
        declare_command: DeclareCommand,
        declare_cairo0_command: DeclareCairo0Command,
        deploy_command: DeployCommand,
        test_command: TestCommand,
        test_cairo0_command: TestCairo0Command,
        invoke_command: InvokeCommand,
        call_command: CallCommand,
        deploy_account_command: DeployAccountCommand,
        calculate_account_address_command: CalculateAccountAddressCommand,
        multicall_command: MulticallCommand,
        cli_app: CLIApp,
        parser: ArgumentParserFacade,
        transaction_registry: TransactionRegistry,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        self._project_root_path = project_root_path
        self._init_command = init_command
        self._init_cairo0_command = init_cairo0_command
        self._build_command = build_command
        self._build_cairo0_command = build_cairo0_command
        self._format_command = format_command
        self._declare_command = declare_command
        self._declare_cairo0_command = declare_cairo0_command
        self._deploy_command = deploy_command
        self._test_command = test_command
        self._test_cairo0_command = test_cairo0_command
        self._invoke_command = invoke_command
        self._calculate_account_address_command = calculate_account_address_command
        self._transaction_registry = transaction_registry
        self._call_command = call_command
        self._deploy_account_command = deploy_account_command
        self._multicall_command = multicall_command
        self._cli_app = cli_app
        self._parser = parser
        self._monkeypatch = monkeypatch

    @property
    def project_root_path(self) -> Path:
        return self._project_root_path

    def get_intercepted_transactions_mapping(self):
        return self._transaction_registry

    async def declare_cairo0(
        self,
        contract: Path,
        account_address: Optional[Address] = None,
        chain_id: Optional[StarknetChainId] = None,
        gateway_url: Optional[str] = None,
        wait_for_acceptance: Optional[bool] = False,
        max_fee: Optional[Fee] = None,
    ):
        args = self._declare_common_args(
            contract=contract,
            account_address=account_address,
            chain_id=chain_id,
            gateway_url=gateway_url,
            wait_for_acceptance=wait_for_acceptance,
            max_fee=max_fee,
        )

        return await self._declare_cairo0_command.run(args)

    async def declare(
        self,
        contract: Path,
        compiled_class_hash: int,
        account_address: Optional[Address] = None,
        chain_id: Optional[StarknetChainId] = None,
        gateway_url: Optional[str] = None,
        wait_for_acceptance: Optional[bool] = False,
        max_fee: Optional[Fee] = None,
    ):
        args = self._declare_common_args(
            contract=contract,
            account_address=account_address,
            chain_id=chain_id,
            gateway_url=gateway_url,
            wait_for_acceptance=wait_for_acceptance,
            max_fee=max_fee,
        )
        args.compiled_class_hash = compiled_class_hash

        return await self._declare_command.run(args)

    def _declare_common_args(
        self,
        contract: Path,
        account_address: Optional[Address] = None,
        chain_id: Optional[StarknetChainId] = None,
        gateway_url: Optional[str] = None,
        wait_for_acceptance: Optional[bool] = False,
        max_fee: Optional[Fee] = None,
    ) -> Namespace:
        args = Namespace()

        args.wait_for_acceptance = wait_for_acceptance
        args.chain_id = chain_id or StarknetChainId.TESTNET
        args.account_address = account_address
        args.contract = contract
        args.gateway_url = gateway_url
        args.max_fee = max_fee

        args.json = False
        args.signer_class = None
        args.private_key_path = None
        args.network = None
        args.token = None
        args.block_explorer = None

        return args

    async def deploy(
        self,
        class_hash: int,
        account_address: Optional[Address] = None,
        gateway_url: Optional[str] = None,
        inputs: Optional[CairoOrPythonData] = None,
        wait_for_acceptance: bool = False,
        max_fee: Optional[Fee] = None,
    ):
        args = Namespace()
        args.class_hash = class_hash
        args.gateway_url = gateway_url
        args.max_fee = max_fee
        args.inputs = inputs or []
        args.network = None
        args.token = None
        args.salt = None
        args.block_explorer = None
        args.wait_for_acceptance = wait_for_acceptance
        args.chain_id = StarknetChainId.TESTNET
        args.signer_class = None
        args.private_key_path = None
        args.account_address = int(account_address) if account_address else None
        args.json = False

        return await self._deploy_command.run(args)

    async def calculate_account_address(
        self,
        account_address_salt: int,
        account_class_hash: int,
        account_constructor_input: Optional[list[int]],
    ):
        args = self._parse(
            command_name="calculate-account-address",
            named_args={
                "account-class-hash": account_class_hash,
                "account-address-salt": account_address_salt,
                "account-constructor-input": account_constructor_input,
            },
        )
        return await self._calculate_account_address_command.run(args)

    async def deploy_account(
        self,
        account_address_salt: int,
        account_class_hash: int,
        max_fee: Wei,
        nonce: int,
        gateway_url: str,
        account_constructor_input: Optional[list[int]],
    ):
        args = self._parse(
            command_name="deploy-account",
            named_args={
                "gateway-url": gateway_url,
                "chain-id": StarknetChainId.TESTNET.value,
                "account-class-hash": account_class_hash,
                "max-fee": max_fee,
                "nonce": nonce,
                "account-address-salt": account_address_salt,
                "account-constructor-input": account_constructor_input,
            },
        )

        return await self._deploy_account_command.run(args)

    async def test_cairo0(
        self, targets: list[str], last_failed: bool = False, estimate_gas: bool = False
    ) -> TestingSummary:
        args = Namespace()
        args.target = targets
        args.ignore = []
        args.cairo_path = []
        args.disable_hint_validation = None
        args.no_progress_bar = None
        args.safe_collecting = None
        args.exit_first = None
        args.seed = None
        args.report_slowest_tests = 0
        args.last_failed = last_failed
        args.max_steps = None
        args.estimate_gas = estimate_gas

        return await self._test_cairo0_command.run(args)

    def init_cairo0_sync(self, project_name: str):
        args = Namespace()
        args.existing = False
        args.name = project_name
        result = asyncio.run(self._init_cairo0_command.run(args))
        return result

    def init_sync(self, project_name: str, minimal: bool = False):
        args = Namespace()
        args.name = project_name
        args.minimal = minimal
        result = asyncio.run(self._init_command.run(args))
        return result

    async def build_cairo0(self):
        args = self._prepare_build_cairo0_args()
        return await self._build_cairo0_command.run(args)

    def build_cairo0_sync(self):
        args = self._prepare_build_cairo0_args()
        return asyncio.run(self._build_cairo0_command.run(args))

    async def build(self):
        args = self._prepare_build_args()
        return await self._build_command.run(args)

    def build_sync(self):
        args = self._prepare_build_args()
        return asyncio.run(self._build_command.run(args))

    def _prepare_build_args(self):
        args = Namespace()
        args.compiled_contracts_dir = Path("./build")
        args.disable_hint_validation = False
        args.linked_libraries = None
        args.json = False
        args.contract_name = ""
        return args

    def _prepare_build_cairo0_args(self):
        args = self._prepare_build_args()
        delattr(args, "linked_libraries")
        args.cairo_path = None
        return args

    async def invoke(
        self,
        contract_address: Address,
        function_name: str,
        inputs: Optional[CairoOrPythonData],
        gateway_url: str,
        account_address: Optional[Address] = None,
        wait_for_acceptance: Optional[bool] = False,
        max_fee: Optional[Fee] = None,
    ):
        args = Namespace()
        args.contract_address = contract_address
        args.function = function_name
        args.inputs = inputs
        args.network = None
        args.gateway_url = gateway_url
        args.chain_id = StarknetChainId.TESTNET
        args.signer_class = None
        args.account_address = account_address
        args.private_key_path = None
        args.block_explorer = None
        args.wait_for_acceptance = wait_for_acceptance
        args.max_fee = max_fee
        args.json = False

        return await self._invoke_command.run(args)

    async def call(
        self,
        contract_address: Address,
        function_name: str,
        inputs: Optional[CairoOrPythonData],
        gateway_url: str,
        abi_path: Optional[Path] = None,
        json: bool = False,
    ):
        args = Namespace()
        args.contract_address = contract_address
        args.function = function_name
        args.inputs = inputs or []
        args.network = None
        args.gateway_url = gateway_url
        args.chain_id = StarknetChainId.TESTNET
        args.json = json
        args.abi = abi_path

        return await self._call_command.run(args)

    def format(
        self,
        targets: list[str],
        check: bool = False,
        verbose: bool = False,
        ignore_broken: bool = False,
        on_formatting_result: Optional[Callable[[FormattingResult], Any]] = None,
    ) -> FormattingSummary:
        # We can't use run because it can raise a silent exception thus not returning summary.
        return self._format_command.format(
            targets=targets,
            check=check,
            verbose=verbose,
            ignore_broken=ignore_broken,
            on_formatting_result=on_formatting_result,
        )

    async def multicall(
        self,
        file_path: Path,
        account: DevnetAccount,
        gateway_url: str,
        json: bool = False,
    ):
        self._monkeypatch.setenv(PRIVATE_KEY_ENV_VAR_NAME, account.private_key)
        result = await self._multicall_command.run(
            self._parse(
                command_name="multicall",
                positional_args=[file_path],
                named_args={
                    "account-address": account.address,
                    "gateway-url": gateway_url,
                    "chain-id": StarknetChainId.TESTNET.value,
                    "max-fee": "auto",
                    "json": json,
                },
            )
        )
        self._monkeypatch.delenv(PRIVATE_KEY_ENV_VAR_NAME)

        return result

    async def run_cairo0_test_runner_cairo0(
        self,
        target: Union[str, Path],
        cairo_path: Optional[list[Path]] = None,
    ) -> TestingSummary:
        """
        Runs test runner safely, without assertions on state of the summary and cache mechanism
        """
        if isinstance(target, Path):
            targets = [str(target)]
        else:
            targets = [target]

        def fake_indicator(_: str) -> ContextManager:
            ...

        messenger_factory = MessengerFactory(
            log_color_provider=log_color_provider,
            activity_indicator=fake_indicator,
        )

        return await self._test_cairo0_command.test(
            targets=targets,
            messenger=messenger_factory.human(),
            cairo_path=cairo_path,
        )

    async def test(
        self,
        target: Union[str, Path],
        linked_libraries: Optional[list[Tuple[Path, PackageName]]] = None,
    ) -> TestingSummary:
        """
        Runs test runner safely, without assertions on state of the summary and cache mechanism
        """
        if isinstance(target, Path):
            targets = [str(target)]
        else:
            targets = [target]

        def fake_indicator(_: str) -> ContextManager:
            ...

        messenger_factory = MessengerFactory(
            log_color_provider=log_color_provider,
            activity_indicator=fake_indicator,
        )

        return await self._test_command.test(
            targets=targets,
            messenger=messenger_factory.human(),
            linked_libraries=linked_libraries,
        )

    def _parse(
        self,
        command_name: str,
        positional_args: Optional[list[Any]] = None,
        named_args: Optional[dict[str, Any]] = None,
    ) -> Namespace:
        return self._parser.parse(
            [command_name] + tokenize(positional_args or [], named_args or {})
        )

    def format_test_result(self, test_result: TestResult) -> str:
        return format_test_result(test_result=test_result).format_human(
            log_color_provider
        )


from pyspark.sql.functions import col, explode
from pyspark.sql import functions as F
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()

input_dir = "gs://football_data_api/raw/coach/*/"

# Load the entire file as a single record
json = spark.sparkContext.wholeTextFiles(input_dir).values()
df = spark.read.json(json)

df1 = (df.select(explode(col("response")))
        .withColumn('coach_id', F.col('col.id'))
        .withColumn('career', F.col('col.career'))
        .select(col("coach_id") ,explode(col("career")))
        .withColumn('team_id', F.col('col.team.id'))
        .withColumn('start_date', F.col('col.start'))
        .withColumn('end_date', F.col('col.end'))
        .drop('col')
       )

df1.write.format("parquet").mode("overwrite").saveAsTable("football.bronze_coach")


from collections import defaultdict, deque

class Graph:
    def __init__(self):
        self.graph = defaultdict(list)

    def add_edge(self, u, v):
        self.graph[u].append(v)

    def bfs(self, start):
        visited = set()
        queue = deque([start])

        while queue:
            node = queue.popleft()
            if node not in visited:
                print(node, end=" ")
                visited.add(node)
                queue.extend(neighbor for neighbor in self.graph[node] if neighbor not in visited)

if __name__ == "__main__":

    g = Graph()
    g.add_edge(0, 1)
    g.add_edge(0, 2)
    g.add_edge(1, 2)
    g.add_edge(2, 0)
    g.add_edge(2, 3)
    g.add_edge(3, 3)

    start_node = 0
    print(f"BFS starting from node {start_node}:")
    g.bfs(start_node)


import datetime

from src.crawl import item_crawler
from src.util import suggestion
from src.util.logger import log

if __name__ == '__main__':

    # start
    start = datetime.datetime.now()
    log.info("Start Time: {}".format(start))

    table = item_crawler.crawl()

    if table is not None:
        # suggestion
        suggestion.suggest(table)
    else:
        log.error('No correct csgo items remain. Please check if conditions are to strict.')

    # end
    end = datetime.datetime.now()
    log.info("END: {}. TIME USED: {}.".format(end, end - start))


import json
from teachBot import startTraining
from typing import Match

filename = 'contenido.json'

with open(filename, "r") as file:
    contenido = json.load(file)

print(contenido['contenido'])

def newTraining(tag, patrones, respuestas):

    print(patrones)
    print(respuestas)
    data = '{"tag" : "%s","patrones":%s,"respuestas":%s}'% (tag, json.dumps(patrones),json.dumps(respuestas))

    print('DATA:')
    print(data)
    data = json.loads(data)
    contenido["contenido"].append(data)

    with open(filename, "w") as file:
        json.dump(contenido, file)

    startTraining()

    print('CONTENIDO GUARDADO:')
    print(contenido)


import requests
from pprint import pprint
import collections
import webbrowser

Result = collections.namedtuple('Result', 'category id url title description')
def main():

    print("Welcome to the search Engine!!!")
    search_name = input("What would you like to search for")
    api = "http://search.talkpython.fm/api/search?q={}".format(search_name)
    data = get_results(api)
    r,m = parse_data(data)
    display_results(r)
    response = input("Would you like to review any of these results? Y/N")
    print()
    if response == 'y':
        number = input("Please type the number you would like to review")
        url = "https://talkpython.fm{}".format(m[int(number)-1])
        webbrowser.open(url)

def get_results(api):
    request = requests.get(api)
    request.raise_for_status()
    data = request.json()
    #pprint(data)
    return data

def  parse_data(data):
    #pprint(data)
    r =[]
    w =[]
    for k,i in enumerate(data['results'],1):
        record = Result(**i)
        p = "{}. {} ".format(k,record.title)
        sites = "{}".format(record.url)
        r.append(p)
        w.append(sites)
    return r,w
def display_results(r):
    print("We have found {} results".format(len(r)))
    print()

    for i in r:
        print(i)
def view_site():
    pass

if __name__ == '__main__':
    main()


from django.shortcuts import render

# Create your views here.
import json
from datetime import datetime
from decimal import Decimal
from django.views import View
from django.http import JsonResponse
from django_redis import get_redis_connection
from django.db import transaction
from utils.views import LoginRequiredJsonMixin
from users.models import Address
from goods.models import SKU
from .models import OrderInfo, OrderGoods

"""
前端：发送请求获取地址信息和购物车选中的商品信息
后端：
    必须时登录用户才能访问订单页面
    业务逻辑：
        地址信息和购物车选中的商品信息  数据查询
    响应：json
    路由： GET orders/settlement/
"""
# 订单结算页面展示
class OrderSettlementView(LoginRequiredJsonMixin, View):
    def get(self, request):
        # 获取用户信息
        user = request.user

        # 获取redis中被选中的商品信息
        redis_cli = get_redis_connection('carts')
        redis_carts = redis_cli.hgetall('carts_%s' % user.id)
        carts_selected = redis_cli.smembers('selected_%s' % user.id)

        cart = dict()
        # 存储被选中商品的购物车信息 {sku_id: count}
        for sku_id in carts_selected:
            cart[int(sku_id)] = int(redis_carts[sku_id])

        # 组织商品信息
        sku_list = list()
        skus = SKU.objects.filter(id__in=cart.keys())
        for sku in skus:
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'count': cart.get(sku.id),
                'amount': sku.price * cart.get(sku.id)
            })

        # 运费
        from decimal import Decimal
        freight = Decimal('10.00')

        # 获取用户所有的地址信息
        addresses = Address.objects.filter(user=user, is_deleted=False)
        # 组织地址数据
        addresses_list = list()
        for address in addresses:
            addresses_list.append({
                'id': address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'receiver': address.receiver,
                'mobile': address.mobile
            })

        # 数据响应
        context = {
            'skus': sku_list,
            'freight': freight,
            'addresses': addresses_list
        }

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'context': context})

# 提交订单
class OrderCommitView(LoginRequiredJsonMixin, View):
    def post(self, request):
        # 接收请求
        json_dict = json.loads(request.body)
        # 接收参数
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 验证参数
        if not all([address_id, pay_method]):
            return JsonResponse({'code': 400, 'errmsg': '请选择地址和支付方式'})

        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '当前地址不存在'})

        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return JsonResponse({'code': 400, 'errmsg': '参数pay_method有误'})

        """订单基本信息保存"""
        # 获取用户信息
        user = request.user

        # 生成订单编号
        from datetime import datetime
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)

        # 因为订单数据的保存会涉及多张表的修改、保存操作，为了保持数据的原子性，使用事务
        # 使用上下文管理开启数据库事务
        with transaction.atomic():
            # 创建事务起始点
            point = transaction.savepoint()

            # 暴力回滚
            try:
                order = OrderInfo.objects.create(
                    order_id = order_id,
                    user = user,
                    address = address,
                    total_count = 0,
                    total_amount = Decimal('0'),
                    freight = Decimal('10.00'),
                    pay_method = pay_method,
                    status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == 2 else OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                """保存商品信息表"""
                # 查询redis中已被勾选的商品
                redis_cli = get_redis_connection('carts')
                redis_cart = redis_cli.hgetall('carts_%s' % user.id)
                selected = redis_cli.smembers('selected_%s' % user.id)

                # 组织redis的数据结构为字典, 存储被选中的商品
                carts = dict()
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])

                # 遍历购物车中被勾选的商品信息
                sku_ids = carts.keys()
                for sku_id in sku_ids:
                    while True:
                        # 查询SKU信息
                        sku = SKU.objects.get(id=sku_id)
                        # 获取购物车对应的商品数量
                        sku_count = carts[sku.id]

                        """
                        当前代码的判断是在表数据插入之后才进行的
                        如果当前的库存数<购物车数量，那么当前就不能创建订单信息
                        如果订单信息还是创建了，那么这就是一条"垃圾数据"
                        ask:
                            如何保证库存数>购物车数量，才创建订单？
                            库存出<购物车数量，不创建订单？
                        solution: 事务
                            from django.db import transaction
                        """
                        # 商品数量>库存数量，返回错误信息，并进行数据回滚
                        if sku_count > sku.stock:
                            # 事务回滚点
                            transaction.savepoint_rollback(point)
                            return JsonResponse({'code': 400, 'errmsg': '库存不足'})

                        # 模拟延迟
                        import time
                        time.sleep(5)

                        ##### 这几段代码会带来超卖问题
                        # sku减少库存，增加销量
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()
                        ##### 这几段代码会带来超卖问题

                        # 使用乐观锁解决超卖问题
                        old_stock = sku.stock
                        new_stock = old_stock - sku_count
                        new_sales = sku.sales + sku_count

                        # 数据没有改动就进行更新
                        result = SKU.objects.filter(id=sku.id, stock=old_stock).update(stock=new_stock,sales=new_sales)
                        if not result:
                            # 如果result为0则表示数据已被修改
                            # return JsonResponse({'code': 400, 'errmsg': '下单失败'})
                            continue   # 跳出本次循环

                        # 保存商品信息
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )

                        # 更新订单基本信息中的总价和商品总数
                        order.total_count += sku_count
                        order.total_amount += (sku_count * sku.price)

                        # 如果下单成功或者失败则跳出循环
                        break

                # 添加邮费和保存订单信息
                order.total_amount += order.freight
                order.save()

                # 事务提交点[with上下文管理协议会自动提交事务，可写也可不写]
                transaction.savepoint_commit(point)
            except Exception:
                # 下单失败返回事务起始点
                transaction.savepoint_rollback(point)
                return JsonResponse({'code': 400, 'errmsg': '下单失败'})

        # 清除购物车中已结算的商品
        pl = redis_cli.pipeline()
        pl.hdel('carts_%s' % user.id, *selected)
        pl.srem('selected_%s' % user.id, *selected)
        pl.execute()

        # 响应提交订单结果
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'order_id': order.order_id})

"""
有bug
当用户提交订单信息时，会发生超卖问题
线程：资源竞争问题
"""


"""Forcing related functionality for PCR-GLOBWB."""

from datetime import datetime
from pathlib import Path
from typing import Optional

from ewatercycle.base.forcing import DefaultForcing
from ewatercycle.esmvaltool.builder import RecipeBuilder
from ewatercycle.esmvaltool.schema import ClimateStatistics, Dataset, ExtractRegion
from ewatercycle.util import get_time

class PCRGlobWBForcing(DefaultForcing):
    """Container for PCR-GLOBWB forcing data.

    Args:
        directory: Directory where forcing data files are stored.
        start_time: Start time of forcing in UTC and ISO format string e.g.
            'YYYY-MM-DDTHH:MM:SSZ'.
        end_time: End time of forcing in UTC and ISO format string e.g.
            'YYYY-MM-DDTHH:MM:SSZ'.
        shape: Path to a shape file. Used for spatial selection.
        precipitationNC (optional): Input file for precipitation data. Defaults to
            'precipitation.nc'.
        temperatureNC (optional): Input file for temperature data. Defaults to
            'temperature.nc'

    Example:

        To generate forcing from ERA5 for the Rhine catchment for 2000-2001:

        .. code-block:: python

            from pathlib import Path

            from rich import print

            from ewatercycle_pcrglobwb.forcing import PCRGlobWBForcing

            shape = Path("./src/ewatercycle/testing/data/Rhine/Rhine.shp")

            forcing = PCRGlobWBForcing.generate(
                dataset='ERA5',
                start_time='2000-01-01T00:00:00Z',
                end_time='2001-01-01T00:00:00Z',
                shape=shape.absolute(),
                start_time_climatology='2000-01-01T00:00:00Z',
                end_time_climatology='2001-01-01T00:00:00Z',
            )
            print(forcing)

        Gives something like:

        .. code-block:: python

            PCRGlobWBForcing(
                model='pcrglobwb',
                start_time='2000-01-01T00:00:00Z',
                end_time='2001-01-01T00:00:00Z',
                directory=PosixPath('/home/verhoes/git/eWaterCycle/ewatercycle/esmvaltool_output/ewcrephogjj0pt_20230816_095928/work/diagnostic/script'),
                shape=PosixPath('/home/verhoes/git/eWaterCycle/ewatercycle/src/ewatercycle/testing/data/Rhine/Rhine.shp'),
                precipitationNC='pcrglobwb_OBS6_ERA5_reanaly_*_day_pr_2000-2001_Rhine.nc',
                temperatureNC='pcrglobwb_OBS6_ERA5_reanaly_*_day_tas_2000-2001_Rhine.nc'
            )
    """

    precipitationNC: Optional[str] = "precipitation.nc"
    temperatureNC: Optional[str] = "temperature.nc"

    @classmethod
    def generate(  # type: ignore
        cls,
        dataset: str | Dataset | dict,
        start_time: str,
        end_time: str,
        shape: str,
        start_time_climatology: str,  # TODO make optional, default to start_time
        end_time_climatology: str,  # TODO make optional, defaults to start_time + 1 y
        extract_region: Optional[dict] = None,
        directory: Optional[str] = None,
    ) -> "PCRGlobWBForcing":
        """Generate forcings for a model.

        The forcing is generated with help of
        `ESMValTool <https://esmvaltool.org/>`_.

        Args:
            dataset: Dataset to get forcing data from.
                When string is given a predefined dataset is looked up in
                :py:const:`ewatercycle.esmvaltool.datasets.DATASETS`.
                When dict given it is passed to
                :py:class:`ewatercycle.esmvaltool.models.Dataset` constructor.
            start_time: Start time of forcing in UTC and ISO format string e.g.
                'YYYY-MM-DDTHH:MM:SSZ'.
            end_time: nd time of forcing in UTC and ISO format string e.g.
                'YYYY-MM-DDTHH:MM:SSZ'.
            shape: Path to a shape file. Used for spatial selection.
            directory:  Directory in which forcing should be written.
                If not given will create timestamped directory.
            start_time_climatology: Start time for the climatology data
            end_time_climatology: End time for the climatology data
            extract_region: Region specification, dictionary must
                contain `start_longitude`, `end_longitude`, `start_latitude`,
                `end_latitude`
        """
        # method is replicated here to document the model specific options
        return super(PCRGlobWBForcing, cls).generate(
            dataset=dataset,
            start_time=start_time,
            end_time=end_time,
            shape=shape,
            start_time_climatology=start_time_climatology,
            end_time_climatology=end_time_climatology,
            extract_region=extract_region,
            directory=directory,
        )

    @classmethod
    def _build_recipe(
        cls,
        start_time: datetime,
        end_time: datetime,
        shape: Path,
        dataset: Dataset | str | dict = "ERA5",
        **model_specific_options,
    ):
        start_time_climatology = model_specific_options["start_time_climatology"]
        end_time_climatology = model_specific_options["end_time_climatology"]
        extract_region = model_specific_options["extract_region"]
        return build_pcrglobwb_recipe(
            start_year=start_time.year,
            end_year=end_time.year,
            shape=shape,
            dataset=dataset,
            start_year_climatology=get_time(start_time_climatology).year,
            end_year_climatology=get_time(end_time_climatology).year,
            extract_region=extract_region,
        )

    @classmethod
    def _recipe_output_to_forcing_arguments(cls, recipe_output, model_specific_options):
        # TODO dont rename recipe output, but use standard name from ESMValTool
        return {
            "precipitationNC": recipe_output["pr"],
            "temperatureNC": recipe_output["tas"],
        }

def build_pcrglobwb_recipe(
    start_year: int,
    end_year: int,
    shape: Path,
    start_year_climatology: int,
    end_year_climatology: int,
    dataset: Dataset | str | dict,
    extract_region: ExtractRegion | None = None,
):
    """Build an ESMValTool recipe for PCR-GLOBWB forcing.

    Args:
        start_year: The start year of the recipe.
        end_year: The end year of the recipe.
        shape: The shape of the region to extract.
        start_year_climatology: The start year of the climatology.
        end_year_climatology: The end year of the climatology.
        dataset: Dataset to use for the recipe.
            When string is given a predefined dataset is looked up in
            :py:const:`ewatercycle.esmvaltool.datasets.DATASETS`.
            When dict given it is passed to
            :py:class:`ewatercycle.esmvaltool.models.Dataset` constructor.
        extract_region: The region to extract.
            When not given uses extents of shape.

    Returns:
        The recipe for PCR-GLOBWB forcing.
    """
    partial = (
        RecipeBuilder()
        .title("PCR-GLOBWB forcing recipe")
        .description("PCR-GLOBWB forcing recipe")
        .dataset(dataset)
        .start(start_year)
        .end(end_year)
    )
    if extract_region is None:
        partial = partial.region_by_shape(shape)
    else:
        partial = partial.region(
            start_longitude=extract_region["start_longitude"],
            end_longitude=extract_region["end_longitude"],
            start_latitude=extract_region["start_latitude"],
            end_latitude=extract_region["end_latitude"],
        )
    return (
        partial.add_variable("pr", units="kg m-2 d-1")
        .add_variable("tas")
        .add_variable(
            "pr_climatology",
            units="kg m-2 d-1",
            stats=ClimateStatistics(operator="mean", period="day"),
            short_name="pr",
            start_year=start_year_climatology,
            end_year=end_year_climatology,
        )
        .add_variable(
            "tas_climatology",
            stats=ClimateStatistics(operator="mean", period="day"),
            short_name="tas",
            start_year=start_year_climatology,
            end_year=end_year_climatology,
        )
        .script("hydrology/pcrglobwb.py", {"basin": shape.stem})
        .build()
    )


import calendar
import errno
import json
import locale
import optparse
import os
import re
import sys
import time
import urllib
from io import StringIO

import urllib3

DEFAULT_CONFIG_FILES = filter(os.path.isfile, ('/etc/dnsdb-query.conf', os.path.expanduser('~/.dnsdb-query.conf')))
DEFAULT_DNSDB_SERVER = 'https://api.dnsdb.info'
DEFAULT_HTTP_PROXY = ''
DEFAULT_HTTPS_PROXY = ''

cfg = None
options = None
debug = False  # set to True to print raw queries and responses

locale.setlocale(locale.LC_ALL, '')

class QueryError(Exception):
    pass

class DnsdbClient(object):
    def __init__(self, server, apikey, limit=None, http_proxy=None, https_proxy=None):
        self.server = server
        self.apikey = apikey
        self.limit = limit
        self.http_proxy = http_proxy
        self.https_proxy = https_proxy

    def query_rrset(self, oname, rrtype=None, bailiwick=None, before=None, after=None):
        if bailiwick:
            if not rrtype:
                rrtype = 'ANY'
            path = 'rrset/name/%s/%s/%s' % (quote(oname), rrtype, quote(bailiwick))
        elif rrtype:
            path = 'rrset/name/%s/%s' % (quote(oname), rrtype)
        else:
            path = 'rrset/name/%s' % quote(oname)
        return self._query(path, before, after)

    def query_rdata_name(self, rdata_name, rrtype=None, before=None, after=None):
        if rrtype:
            path = 'rdata/name/%s/%s' % (quote(rdata_name), rrtype)
        else:
            path = 'rdata/name/%s' % quote(rdata_name)
        return self._query(path, before, after)

    def query_rdata_ip(self, rdata_ip, before=None, after=None):
        path = 'rdata/ip/%s' % rdata_ip.replace('/', ',')
        return self._query(path, before, after)

    def _query(self, path, before=None, after=None):
        res = []
        url = '%s/lookup/%s' % (self.server, path)

        params = {}
        if self.limit:
            params['limit'] = self.limit
        if before and after:
            params['time_first_after'] = after
            params['time_last_before'] = before
        else:
            if before:
                params['time_first_before'] = before
            if after:
                params['time_last_after'] = after
        if params:
            url += '?{0}'.format(urllib.parse.urlencode(params))

        if self.https_proxy:
            manager = urllib3.ProxyManager(self.https_proxy)
        elif self.http_proxy:
            manager = urllib3.ProxyManager(self.http_proxy)
        else:
            manager = urllib3.PoolManager()

        headers = {
            'Accept': 'application/json',
            'X-Api-Key': self.apikey
        }

        if debug:
            sys.stderr.write(";; query URL =" + url)

        try:
            r = manager.request(method='GET', url=url, headers=headers)
            if r.status == 200:
                json_data = r.data.decode('utf-8')
                if json_data:
                    json_list = json_data.splitlines()
                    for line in json_list:
                        yield json.loads(line)
            else:
                raise QueryError(r.text)

        except (urllib3.exceptions.HTTPError) as e:
            raise QueryError(str(e))

def quote(path):
    return urllib.parse.quote(path, safe='')

def sec_to_text(ts):
    return time.strftime('%Y-%m-%d %H:%M:%S -0000', time.gmtime(ts))

def rrset_to_text(m):
    s = StringIO()

    try:
        if 'bailiwick' in m:
            s.write(';;  bailiwick: %s\n' % m['bailiwick'])

        if 'count' in m:
            s.write(';;      count: %s\n' % locale.format('%d', m['count'], True))

        if 'time_first' in m:
            s.write(';; first seen: %s\n' % sec_to_text(m['time_first']))
        if 'time_last' in m:
            s.write(';;  last seen: %s\n' % sec_to_text(m['time_last']))

        if 'zone_time_first' in m:
            s.write(';; first seen in zone file: %s\n' % sec_to_text(m['zone_time_first']))
        if 'zone_time_last' in m:
            s.write(';;  last seen in zone file: %s\n' % sec_to_text(m['zone_time_last']))

        if 'rdata' in m:
            for rdata in m['rdata']:
                s.write('%s IN %s %s\n' % (m['rrname'], m['rrtype'], rdata))

        s.seek(0)
        return s.read()
    finally:
        s.close()

def rdata_to_text(m):
    return '%s IN %s %s' % (m['rrname'], m['rrtype'], m['rdata'])

def parse_config(cfg_files):
    config = {}

    if not cfg_files:
        raise IOError(errno.ENOENT, 'dnsdb_query: No config files found')

    for fname in cfg_files:
        for line in open(fname):
            key, eq, val = line.strip().partition('=')
            val = val.strip('"')
            config[key] = val

    return config

def time_parse(s):
    try:
        epoch = int(s)
        return epoch
    except ValueError:
        pass

    try:
        epoch = int(calendar.timegm(time.strptime(s, '%Y-%m-%d')))
        return epoch
    except ValueError:
        pass

    try:
        epoch = int(calendar.timegm(time.strptime(s, '%Y-%m-%d %H:%M:%S')))
        return epoch
    except ValueError:
        pass

    m = re.match(r'^(?=\d)(?:(\d+)w)?(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?$', s, re.I)
    if m:
        return -1 * (int(m.group(1) or 0) * 604800 + \
                     int(m.group(2) or 0) * 86400 + \
                     int(m.group(3) or 0) * 3600 + \
                     int(m.group(4) or 0) * 60 + \
                     int(m.group(5) or 0))

    raise ValueError('Invalid time: "%s"' % s)

def epipe_wrapper(func):
    def f(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except IOError as e:
            if e.errno == errno.EPIPE:
                sys.exit(e.errno)
            raise

    return f

@epipe_wrapper
def main():
    global cfg
    global options
    global debug

    parser = optparse.OptionParser(
        epilog='Time formats are: "%Y-%m-%d", "%Y-%m-%d %H:%M:%S", "%d" (UNIX timestamp), "-%d" (Relative time in seconds), BIND format (e.g. 1w1h, (w)eek, (d)ay, (h)our, (m)inute, (s)econd)')
    parser.add_option('-c', '--config', dest='config',
                      help='config file', action='append')
    parser.add_option('-r', '--rrset', dest='rrset', type='string',
                      help='rrset <ONAME>[/<RRTYPE>[/BAILIWICK]]')
    parser.add_option('-n', '--rdataname', dest='rdata_name', type='string',
                      help='rdata name <NAME>[/<RRTYPE>]')
    parser.add_option('-i', '--rdataip', dest='rdata_ip', type='string',
                      help='rdata ip <IPADDRESS|IPRANGE|IPNETWORK>')
    parser.add_option('-t', '--rrtype', dest='rrtype', type='string',
                      help='rrset or rdata rrtype')
    parser.add_option('-b', '--bailiwick', dest='bailiwick', type='string',
                      help='rrset bailiwick')
    parser.add_option('-s', '--sort', dest='sort', type='string', help='sort key')
    parser.add_option('-R', '--reverse', dest='reverse', action='store_true', default=False,
                      help='reverse sort')
    parser.add_option('-j', '--json', dest='json', action='store_true', default=False,
                      help='output in JSON format')
    parser.add_option('-l', '--limit', dest='limit', type='int', default=0,
                      help='limit number of results')
    parser.add_option('-d', '--debug', dest='debug', action='store_true', default=False,
                      help='print debug output')

    parser.add_option('', '--before', dest='before', type='string', help='only output results seen before this time')
    parser.add_option('', '--after', dest='after', type='string', help='only output results seen after this time')

    options, args = parser.parse_args()
    if args:
        parser.print_help()
        sys.exit(1)

    debug = options.debug

    try:
        if options.before:
            options.before = time_parse(options.before)
    except ValueError as e:
        print('Could not parse before: {}'.format(options.before))

    try:
        if options.after:
            options.after = time_parse(options.after)
    except ValueError as e:
        print('Could not parse after: {}'.format(options.after))

    try:
        cfg = parse_config(options.config or DEFAULT_CONFIG_FILES)
    except IOError as e:
        sys.stderr.writable(str(e))
        sys.exit(1)

    if not 'DNSDB_SERVER' in cfg:
        cfg['DNSDB_SERVER'] = DEFAULT_DNSDB_SERVER
    if not 'HTTP_PROXY' in cfg:
        cfg['HTTP_PROXY'] = DEFAULT_HTTP_PROXY
    if not 'HTTPS_PROXY' in cfg:
        cfg['HTTPS_PROXY'] = DEFAULT_HTTPS_PROXY
    if not 'APIKEY' in cfg:
        sys.stderr.write('dnsdb_query: APIKEY not defined in config file\n')
        sys.exit(1)

    client = DnsdbClient(cfg['DNSDB_SERVER'], cfg['APIKEY'],
                         limit=options.limit,
                         http_proxy=cfg['HTTP_PROXY'],
                         https_proxy=cfg['HTTPS_PROXY'])
    if options.rrset:
        if options.rrtype or options.bailiwick:
            qargs = (options.rrset, options.rrtype, options.bailiwick)
        else:
            qargs = (options.rrset.split('/', 2))

        results = client.query_rrset(*qargs, before=options.before, after=options.after)
        fmt_func = rrset_to_text
    elif options.rdata_name:
        if options.rrtype:
            qargs = (options.rdata_name, options.rrtype)
        else:
            qargs = (options.rdata_name.split('/', 1))

        results = client.query_rdata_name(*qargs, before=options.before, after=options.after)
        fmt_func = rdata_to_text
    elif options.rdata_ip:
        results = client.query_rdata_ip(options.rdata_ip, before=options.before, after=options.after)
        fmt_func = rdata_to_text
    else:
        parser.print_help()
        sys.exit(1)

    if options.json:
        fmt_func = json.dumps

    try:
        if options.sort:
            results = list(results)
            if len(results) > 0:
                if not options.sort in results[0]:
                    sort_keys = results[0].keys()
                    sort_keys.sort()
                    sys.stderr.write('dnsdb_query: invalid sort key "%s". valid sort keys are %s\n' % (
                        options.sort, ', '.join(sort_keys)))
                    sys.exit(1)
                results.sort(key=lambda r: r[options.sort], reverse=options.reverse)
        for res in results:
            sys.stdout.write('%s\n' % fmt_func(res))
    except QueryError as e:
        sys.stderr.write(e)
        sys.exit(1)

if __name__ == '__main__':
    main()


#%% P154 zero coupon bond
def zero_coupon_bond(par, y, t):
    """
    Price a zero coupon bond.

    :param par: face value of the bond.
    :param y: annual yield or rate of the bond.
    :param t: time to maturity, in years.
    """
    return par/(1+y)**t

print(zero_coupon_bond(100, 0.05, 5))

#%% P162 Calculating the yield to maturity

import scipy.optimize as optimize

def bond_ytm(price, par, T, coup, freq=2, guess=0.05):
    freq = float(freq)
    periods = T*2
    coupon = coup/100.*par
    dt = [(i+1)/freq for i in range(int(periods))]
    ytm_func = lambda y:sum([coupon/freq/(1+y/freq)**(freq*t) for t in dt])
    +  par/(1+y/freq)**(freq*T) - price

    return optimize.newton(ytm_func, guess)

ytm = bond_ytm(95.0428, 100, 1.5, 5.75, 2)
print(ytm)

#%% P163 Calculating the price of a bond

def bond_price(par, T, ytm, coup, freq=2):
    freq = float(freq)
    periods = T*2
    coupon = coup/100.*par
    dt = [(i+1)/freq for i in range(int(periods))]
    price = sum([coupon/freq/(1+ytm/freq)**(freq*t) for t in dt]) +  \
       par/(1+ytm/freq)**(freq*T)
    return price

price = bond_price(100, 1.5, ytm, 5.75, 2)
print(price)

#%% Bond duration
#percentage change in bond price with respect to a
#percentage change in yield , 1%)

def bond_mod_duration(price, par, T, coup, freq, dy=0.01):
    ytm = bond_ytm(price, par, T, coup, freq)

    ytm_minus = ytm - dy
    price_minus = bond_price(par, T, ytm_minus, coup, freq)

    ytm_plus = ytm + dy
    price_plus = bond_price(par, T, ytm_plus, coup, freq)

    mduration = (price_minus-price_plus)/(2*price*dy)
    return mduration

mod_duration = bond_mod_duration(95.0428, 100, 1.5, 5.75, 2)
print(mod_duration)

#%% P165 Bond convexity

#Higher-convexity portfolios are less
#affected by interest-rate volatilities than lower-convexity portfolios, given the
#same bond duration and yield. As such, higher-convexity bonds are more
#expensive than lower-convexity ones, everything else being equal.

def bond_convexity(price, par, T, coup, freq, dy=0.01):
    ytm = bond_ytm(price, par, T, coup, freq)

    ytm_minus = ytm - dy
    price_minus = bond_price(par, T, ytm_minus, coup, freq)

    ytm_plus = ytm + dy
    price_plus = bond_price(par, T, ytm_plus, coup, freq)

    convexity = (price_minus + price_plus - 2*price)/(price*dy**2)
    return convexity

#%% P167 Short-rate modeling - The Vasicek model
# rates CAN become negative
import math
import numpy as np

def vasicek(r0, K, theta, sigma, T=1., N=10, seed=777):
    np.random.seed(seed) #to produce same results each time run
    dt = T/float(N)
    rates = [r0]
    for i in range(N):
        dr = K*(theta-rates[-1])* dt + sigma*math.sqrt(dt)*np.random.normal()
        rates.append(rates[-1]+dr)

    return range(N+1), rates

#

# In[13]:
get_ipython().run_line_magic('pylab', 'inline')
fig = plt.figure(figsize=(12, 8))

for K in [0.002, 0.02, 0.2]:
    x, y = vasicek(0.005, K, 0.15, 0.05, T=10, N=200)
    plot(x,y, label='K=%s'%K)
    pylab.legend(loc='upper left');

pylab.legend(loc='upper left')
pylab.xlabel('Vasicek model');


import gi
import json

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

def get_menu_from_config(accel_group, action_router):
    # get our own menubar
    with open("./data/menus.json", "r") as read_file:
        menu_data = json.load(read_file)
    menu_bar = Gtk.MenuBar()
    for menu_item in menu_data:
        new_menu = Gtk.Menu()
        menu_top = Gtk.MenuItem(menu_item['text'])
        menu_top.set_submenu(new_menu)
        for menu_choice in menu_item['items']:
            if menu_choice['text'] == '-':
                new_menu.append(Gtk.SeparatorMenuItem())
                continue
            else:
                if 'icon' in menu_choice:
                    menu_item = Gtk.ImageMenuItem(label=menu_choice['text'])
                    image = Gtk.Image()
                    image.set_from_file(f'./gfx/icons/{menu_choice["icon"]}.png')
                    menu_item.set_image(image)
                else:
                    menu_item = Gtk.MenuItem(label=menu_choice['text'])
                if 'shortcut' in menu_choice:
                    key, mod = Gtk.accelerator_parse(menu_choice['shortcut'])
                    menu_item.add_accelerator('activate', accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
                if 'action' in menu_choice:
                    if 'data' in menu_choice:
                        menu_item.connect('activate', action_router, menu_choice['action'], menu_choice['data'])
                    else:
                        menu_item.connect('activate', action_router, menu_choice['action'])
                else:
                    menu_item.connect('activate', action_router, 'messagebox', 'Not yet coded')
                new_menu.append(menu_item)
        menu_bar.append(menu_top)
    return menu_bar