"""
This module contains the implementation of a verification setup for a poromechanical
system (without fractures) using two-dimensional manufactured solutions.

The implementation considers a compressible fluid, resulting in a coupled non-linear
set of equations. The dependecy of the fluid density with the pressure is given by [1]:

.. math::

    \\rho(p) =  \\rho_0 \\exp{c_f \\left(p - p_0\\right)},

where :math:`\\rho` and :math:`p` are the density and pressure, :math:`\\rho_0`` and
:math:``p_0`` are the _reference_ density and pressure, and :math:`c_f` is the
_constant_ fluid compressibility.

We provide two different manufactured solutions, namely `parabolic` and `nordbotten2016`
[2], which can be specified as a model parameter.

Parabolic manufactured solution:

.. math::

    p(x, y, t) = t x (1 - x) y (1- y),

    u_x(x, y, t) = p(x, y, t),

    u_y(x, y, t) = p(x, y, t).

Manufactured solution based on [2]:

.. math::

    p(x, y, t) = t x (1 - x) \\sin{2 \\pi y},

    u_x(x, y, t) = p(x, y, t),

    u_y(x, y, t) = t * \\sin{2 \\pi x} \\sin{2 \\pi y}.

References:

    - [1] Garipov, T. T., & Hui, M. H. (2019). Discrete fracture modeling approach for
      simulating coupled thermo-hydro-mechanical effects in fractured reservoirs.
      International Journal of Rock Mechanics and Mining Sciences, 122, 104075.

    - [2] Nordbotten, J. M. (2016). Stable cell-centered finite volume discretization
      for Biot equations. SIAM Journal on Numerical Analysis, 54(2), 942-968.

"""
from __future__ import annotations

from dataclasses import dataclass
from typing import Callable

import numpy as np
import sympy as sym

import porepy as pp
import porepy.models.fluid_mass_balance as mass
import porepy.models.momentum_balance as momentum
import porepy.models.poromechanics as poromechanics
from porepy.applications.convergence_analysis import ConvergenceAnalysis
from porepy.applications.md_grids.domains import nd_cube_domain
from porepy.utils.examples_utils import VerificationUtils
from porepy.viz.data_saving_model_mixin import VerificationDataSaving

# PorePy typings
number = pp.number
grid = pp.GridLike

# -----> Data-saving
@dataclass
class ManuPoroMechSaveData:
    """Data class to save relevant results from the verification setup."""

    approx_displacement: np.ndarray
    """Numerical displacement."""

    approx_flux: np.ndarray
    """Numerical Darcy flux."""

    approx_force: np.ndarray
    """Numerical poroelastic force."""

    approx_pressure: np.ndarray
    """Numerical pressure."""

    error_displacement: number
    """L2-discrete relative error for the displacement."""

    error_flux: number
    """L2-discrete relative error for the Darcy flux."""

    error_force: number
    """L2-discrete relative error for the poroelastic force."""

    error_pressure: number
    """L2-discrete relative error for the pressure."""

    exact_displacement: np.ndarray
    """Exact displacement."""

    exact_flux: np.ndarray
    """Exact Darcy flux."""

    exact_force: np.ndarray
    """Exact poroelastic force."""

    exact_pressure: np.ndarray
    """Exact pressure."""

    time: number
    """Current simulation time."""

class ManuPoroMechDataSaving(VerificationDataSaving):
    """Mixin class to save relevant data."""

    darcy_flux: Callable[[list[pp.Grid]], pp.ad.Operator]
    """Method that returns the Darcy fluxes in the form of an Ad operator. Usually
    provided by the mixin class :class:`porepy.models.constitutive_laws.DarcysLaw`.

    """

    displacement: Callable[[list[pp.Grid]], pp.ad.MixedDimensionalVariable]
    """Displacement variable. Normally defined in a mixin instance of
    :class:`~porepy.models.momentum_balance.VariablesMomentumBalance`.

    """

    exact_sol: ManuPoroMechExactSolution2d
    """Exact solution object."""

    pressure: Callable[[list[pp.Grid]], pp.ad.MixedDimensionalVariable]
    """Pressure variable. Normally defined in a mixin instance of
    :class:`~porepy.models.fluid_mass_balance.VariablesSinglePhaseFlow`.

    """

    stress: Callable[[list[pp.Grid]], pp.ad.Operator]
    """Method that returns the (integrated) poroelastic stress in the form of an Ad
    operator. Usually provided by the mixin class
    :class:`porepy.models.poromechanics.ConstitutiveLawsPoromechanics`.

    """

    def collect_data(self) -> ManuPoroMechSaveData:
        """Collect data from the verification setup.

        Returns:
            ManuPoroMechSaveData object containing the results of the verification for
            the current time.

        """

        mdg: pp.MixedDimensionalGrid = self.mdg
        sd: pp.Grid = mdg.subdomains()[0]
        t: number = self.time_manager.time

        # Collect data
        exact_pressure = self.exact_sol.pressure(sd=sd, time=t)
        pressure_ad = self.pressure([sd])
        approx_pressure = pressure_ad.value(self.equation_system)
        error_pressure = ConvergenceAnalysis.l2_error(
            grid=sd,
            true_array=exact_pressure,
            approx_array=approx_pressure,
            is_scalar=True,
            is_cc=True,
            relative=True,
        )

        exact_displacement = self.exact_sol.displacement(sd=sd, time=t)
        displacement_ad = self.displacement([sd])
        approx_displacement = displacement_ad.value(self.equation_system)
        error_displacement = ConvergenceAnalysis.l2_error(
            grid=sd,
            true_array=exact_displacement,
            approx_array=approx_displacement,
            is_scalar=False,
            is_cc=True,
            relative=True,
        )

        exact_flux = self.exact_sol.darcy_flux(sd=sd, time=t)
        flux_ad = self.darcy_flux([sd])
        approx_flux = flux_ad.value(self.equation_system)
        error_flux = ConvergenceAnalysis.l2_error(
            grid=sd,
            true_array=exact_flux,
            approx_array=approx_flux,
            is_scalar=True,
            is_cc=False,
            relative=True,
        )

        exact_force = self.exact_sol.poroelastic_force(sd=sd, time=t)
        force_ad = self.stress([sd])
        approx_force = force_ad.value(self.equation_system)
        error_force = ConvergenceAnalysis.l2_error(
            grid=sd,
            true_array=exact_force,
            approx_array=approx_force,
            is_scalar=False,
            is_cc=False,
            relative=True,
        )

        # Store collected data in data class
        collected_data = ManuPoroMechSaveData(
            approx_displacement=approx_displacement,
            approx_flux=approx_flux,
            approx_force=approx_force,
            approx_pressure=approx_pressure,
            error_displacement=error_displacement,
            error_flux=error_flux,
            error_force=error_force,
            error_pressure=error_pressure,
            exact_displacement=exact_displacement,
            exact_flux=exact_flux,
            exact_force=exact_force,
            exact_pressure=exact_pressure,
            time=t,
        )

        return collected_data

# -----> Exact solution
class ManuPoroMechExactSolution2d:
    """Class containing the exact manufactured solution for the verification setup."""

    def __init__(self, setup):
        """Constructor of the class."""

        # Physical parameters
        lame_lmbda = setup.solid.lame_lambda()  # [Pa] Lamé parameter
        lame_mu = setup.solid.shear_modulus()  # [Pa] Lamé parameter
        alpha = setup.solid.biot_coefficient()  # [-] Biot coefficient
        rho_0 = setup.fluid.density()  # [kg / m^3] Reference density
        phi_0 = setup.solid.porosity()  # [-] Reference porosity
        p_0 = setup.fluid.pressure()  # [Pa] Reference pressure
        c_f = setup.fluid.compressibility()  # [Pa^-1] Fluid compressibility
        k = setup.solid.permeability()  # [m^2] Permeability
        mu_f = setup.fluid.viscosity()  # [Pa * s] Fluid viscosity
        K_d = lame_lmbda + (2 / 3) * lame_mu  # [Pa] Bulk modulus

        # Symbolic variables
        x, y, t = sym.symbols("x y t")
        pi = sym.pi

        # Exact pressure and displacement solutions
        manufactured_sol = setup.params.get("manufactured_solution", "parabolic")
        if manufactured_sol == "parabolic":
            p = t * x * (1 - x) * y * (1 - y)
            u = [p, p]
        elif manufactured_sol == "nordbotten_2016":
            p = t * x * (1 - x) * sym.sin(2 * pi * y)
            u = [p, t * sym.sin(2 * pi * x) * sym.sin(2 * pi * y)]
        else:
            raise NotImplementedError("Manufactured solution is not available.")

        # Exact density
        rho = rho_0 * sym.exp(c_f * (p - p_0))

        # Exact darcy flux
        q = [-1 * (k / mu_f) * sym.diff(p, x), -1 * (k / mu_f) * sym.diff(p, y)]

        # Exact mass flux
        mf = [rho * q[0], rho * q[1]]

        # Exact divergence of the mass flux
        div_mf = sym.diff(mf[0], x) + sym.diff(mf[1], y)

        # Exact divergence of the displacement
        div_u = sym.diff(u[0], x) + sym.diff(u[1], y)

        # Exact poromechanical porosity
        phi = phi_0 + ((alpha - phi_0) * (1 - alpha) / K_d) * (p - p_0) + alpha * div_u

        # Exact flow accumulation
        accum_flow = sym.diff(phi * rho, t)

        # Exact flow source
        source_flow = accum_flow + div_mf

        # Exact gradient of the displacement
        grad_u = [
            [sym.diff(u[0], x), sym.diff(u[0], y)],
            [sym.diff(u[1], x), sym.diff(u[1], y)],
        ]

        # Exact transpose of the gradient of the displacement
        trans_grad_u = [[grad_u[0][0], grad_u[1][0]], [grad_u[0][1], grad_u[1][1]]]

        # Exact strain
        epsilon = [
            [
                0.5 * (grad_u[0][0] + trans_grad_u[0][0]),
                0.5 * (grad_u[0][1] + trans_grad_u[0][1]),
            ],
            [
                0.5 * (grad_u[1][0] + trans_grad_u[1][0]),
                0.5 * (grad_u[1][1] + trans_grad_u[1][1]),
            ],
        ]

        # Exact trace (in the linear algebra sense) of the strain
        tr_epsilon = epsilon[0][0] + epsilon[1][1]

        # Exact elastic stress
        sigma_elas = [
            [
                lame_lmbda * tr_epsilon + 2 * lame_mu * epsilon[0][0],
                2 * lame_mu * epsilon[0][1],
            ],
            [
                2 * lame_mu * epsilon[1][0],
                lame_lmbda * tr_epsilon + 2 * lame_mu * epsilon[1][1],
            ],
        ]

        # Exact poroelastic stress
        sigma_total = [
            [sigma_elas[0][0] - alpha * p, sigma_elas[0][1]],
            [sigma_elas[1][0], sigma_elas[1][1] - alpha * p],
        ]

        # Mechanics source term
        source_mech = [
            sym.diff(sigma_total[0][0], x) + sym.diff(sigma_total[0][1], y),
            sym.diff(sigma_total[1][0], x) + sym.diff(sigma_total[1][1], y),
        ]

        # Public attributes
        self.p = p  # pressure
        self.u = u  # displacement
        self.sigma_elast = sigma_elas  # elastic stress
        self.sigma_total = sigma_total  # poroelastic (total) stress
        self.q = q  # Darcy flux
        self.mf = mf  # Mass flux, i.e., density * Darcy flux
        self.phi = phi  # poromechanics porosity
        self.rho = rho  # density
        self.source_mech = source_mech  # Source term entering the momentum balance
        self.source_flow = source_flow  # Source term entering the mass balance

    # -----> Primary and secondary variables
    def pressure(self, sd: pp.Grid, time: float) -> np.ndarray:
        """Evaluate exact pressure [Pa] at the cell centers.

        Parameters:
            sd: Subdomain grid.
            time: Time in seconds.

        Returns:
            Array of ``shape=(sd.num_cells, )`` containing the exact pressures at the
            cell centers at the given ``time``.

        """
        # Symbolic variables
        x, y, t = sym.symbols("x y t")

        # Get cell centers
        cc = sd.cell_centers

        # Lambdify expression
        p_fun: Callable = sym.lambdify((x, y, t), self.p, "numpy")

        # Cell-centered pressures
        p_cc: np.ndarray = p_fun(cc[0], cc[1], time)

        return p_cc

    def displacement(self, sd: pp.Grid, time: float) -> np.ndarray:
        """Evaluate exact displacement [m] at the cell centers.

        Parameters:
            sd: Subdomain grid.
            time: Time in seconds.

        Returns:
            Array of ``shape=(2 * sd.num_cells, )`` containing the exact displacements
            at the cell centers for the given ``time``.

        Notes:
            The returned displacement is given in PorePy's flattened vector format.

        """
        # Symbolic variables
        x, y, t = sym.symbols("x y t")

        # Get cell centers
        cc = sd.cell_centers

        # Lambdify expression
        u_fun: list[Callable] = [
            sym.lambdify((x, y, t), self.u[0], "numpy"),
            sym.lambdify((x, y, t), self.u[1], "numpy"),
        ]

        # Cell-centered displacements
        u_cc: list[np.ndarray] = [
            u_fun[0](cc[0], cc[1], time),
            u_fun[1](cc[0], cc[1], time),
        ]

        # Flatten array
        u_flat: np.ndarray = np.asarray(u_cc).ravel("F")

        return u_flat

    def darcy_flux(self, sd: pp.Grid, time: float) -> np.ndarray:
        """Evaluate exact Darcy flux [m^3 * s^-1] at the face centers.

        Parameters:
            sd: Subdomain grid.
            time: Time in seconds.

        Returns:
            Array of ``shape=(sd.num_faces, )`` containing the exact Darcy fluxes at
            the face centers for the given ``time``.

        Note:
            The returned fluxes are already scaled with ``sd.face_normals``.

        """
        # Symbolic variables
        x, y, t = sym.symbols("x y t")

        # Get list of face indices
        fc = sd.face_centers
        fn = sd.face_normals

        # Lambdify expression

        q_fun: list[Callable] = [
            sym.lambdify((x, y, t), self.q[0], "numpy"),
            sym.lambdify((x, y, t), self.q[1], "numpy"),
        ]

        # Face-centered Darcy fluxes
        q_fc: np.ndarray = (
            q_fun[0](fc[0], fc[1], time) * fn[0] + q_fun[1](fc[0], fc[1], time) * fn[1]
        )

        return q_fc

    def poroelastic_force(self, sd: pp.Grid, time: float) -> np.ndarray:
        """Evaluate exact poroelastic force [N] at the face centers.

        Parameters:
            sd: Subdomain grid.
            time: Time in seconds.

        Returns:
            Array of ``shape=(2 * sd.num_faces, )`` containing the exact poroealstic
            force at the face centers for the given ``time``.

        Notes:
            - The returned poroelastic force is given in PorePy's flattened vector
              format.
            - Recall that force = (stress dot_prod unit_normal) * face_area.

        """
        # Symbolic variables
        x, y, t = sym.symbols("x y t")

        # Get cell centers and face normals
        fc = sd.face_centers
        fn = sd.face_normals

        # Lambdify expression
        sigma_total_fun: list[list[Callable]] = [
            [
                sym.lambdify((x, y, t), self.sigma_total[0][0], "numpy"),
                sym.lambdify((x, y, t), self.sigma_total[0][1], "numpy"),
            ],
            [
                sym.lambdify((x, y, t), self.sigma_total[1][0], "numpy"),
                sym.lambdify((x, y, t), self.sigma_total[1][1], "numpy"),
            ],
        ]

        # Face-centered poroelastic force
        force_total_fc: list[np.ndarray] = [
            # (sigma_xx * n_x + sigma_xy * n_y) * face_area
            sigma_total_fun[0][0](fc[0], fc[1], time) * fn[0]
            + sigma_total_fun[0][1](fc[0], fc[1], time) * fn[1],
            # (sigma_yx * n_x + sigma_yy * n_y) * face_area
            sigma_total_fun[1][0](fc[0], fc[1], time) * fn[0]
            + sigma_total_fun[1][1](fc[0], fc[1], time) * fn[1],
        ]

        # Flatten array
        force_total_flat: np.ndarray = np.asarray(force_total_fc).ravel("F")

        return force_total_flat

    # -----> Sources
    def mechanics_source(self, sd: pp.Grid, time: float) -> np.ndarray:
        """Compute exact source term for the momentum balance equation.

        Parameters:
            sd: Subdomain grid.
            time: Time in seconds.

        Returns:
            Exact right hand side of the momentum balance equation with ``shape=(
            2 * sd.num_cells, )``.

        Notes:
            The returned array is given in PorePy's flattened vector format.

        """
        # Symbolic variables
        x, y, t = sym.symbols("x y t")

        # Get cell centers and cell volumes
        cc = sd.cell_centers
        vol = sd.cell_volumes

        # Lambdify expression
        source_mech_fun: list[Callable] = [
            sym.lambdify((x, y, t), self.source_mech[0], "numpy"),
            sym.lambdify((x, y, t), self.source_mech[1], "numpy"),
        ]

        # Evaluate and integrate source
        source_mech: list[np.ndarray] = [
            source_mech_fun[0](cc[0], cc[1], time) * vol,
            source_mech_fun[1](cc[0], cc[1], time) * vol,
        ]

        # Flatten array
        source_mech_flat: np.ndarray = np.asarray(source_mech).ravel("F")

        # Invert sign according to sign convention.
        return -source_mech_flat

    def flow_source(self, sd: pp.Grid, time: float) -> np.ndarray:
        """Compute exact source term for the fluid mass balance equation.

        Parameters:
            sd: Subdomain grid.
            time: Time in seconds.

        Returns:
            Exact right hand side of the fluid mass balance equation with ``shape=(
            sd.num_cells, )``.

        """
        # Symbolic variables
        x, y, t = sym.symbols("x y t")

        # Get cell centers and cell volumes
        cc = sd.cell_centers
        vol = sd.cell_volumes

        # Lambdify expression
        source_flow_fun: Callable = sym.lambdify((x, y, t), self.source_flow, "numpy")

        # Evaluate and integrate source
        source_flow: np.ndarray = source_flow_fun(cc[0], cc[1], time) * vol

        return source_flow

# -----> Utilities
class ManuPoroMechUtils(VerificationUtils):
    """Mixin class containing useful utility methods for the setup."""

    mdg: pp.MixedDimensionalGrid
    """Mixed-dimensional grid."""

    results: list[ManuPoroMechSaveData]
    """List of ManuPoroMechSaveData objects."""

    def plot_results(self) -> None:
        """Plotting results."""
        self._plot_displacement()
        self._plot_pressure()

    def _plot_pressure(self):
        """Plot exact and numerical pressures."""

        sd = self.mdg.subdomains()[0]
        p_ex = self.results[-1].exact_pressure
        p_num = self.results[-1].approx_pressure

        pp.plot_grid(sd, p_ex, plot_2d=True, linewidth=0, title="p (Exact)")
        pp.plot_grid(sd, p_num, plot_2d=True, linewidth=0, title="p (Numerical)")

    def _plot_displacement(self):
        """Plot exact and numerical displacements."""

        sd = self.mdg.subdomains()[0]
        u_ex = self.results[-1].exact_displacement
        u_num = self.results[-1].approx_displacement

        # Horizontal displacement
        pp.plot_grid(sd, u_ex[::2], plot_2d=True, linewidth=0, title="u_x (Exact)")
        pp.plot_grid(sd, u_num[::2], plot_2d=True, linewidth=0, title="u_x (Numerical)")

        # Vertical displacement
        pp.plot_grid(sd, u_ex[1::2], plot_2d=True, linewidth=0, title="u_y (Exact)")
        pp.plot_grid(
            sd, u_num[1::2], plot_2d=True, linewidth=0, title="u_y (Numerical)"
        )

# -----> Geometry
class UnitSquareGrid:
    """Class for setting up the geometry of the unit square domain."""

    params: dict
    """Simulation model parameters."""

    def set_domain(self) -> None:
        """Set domain."""
        self._domain = nd_cube_domain(2, 1.0)

    def meshing_arguments(self) -> dict[str, float]:
        """Set meshing arguments."""
        default_mesh_arguments = {"cell_size": 0.1}
        return self.params.get("meshing_arguments", default_mesh_arguments)

# -----> Balance equations
class ManuPoroMechMassBalance(mass.MassBalanceEquations):
    """Modify balance equation to account for external sources."""

    def fluid_source(self, subdomains: list[pp.Grid]) -> pp.ad.Operator:
        """Fluid source."""

        # Internal sources are inherit from parent class
        # Zero internal sources for unfractured domains, but we keep it to maintain
        # good code practice
        internal_sources: pp.ad.Operator = super().fluid_source(subdomains)

        # External sources are retrieved from pp.TIME_STEP_SOLUTIONS and wrapped as an
        # AdArray.
        external_sources = pp.ad.TimeDependentDenseArray(
            name="source_flow",
            domains=self.mdg.subdomains(),
            previous_timestep=True,
        )

        # Add up contribution of internal and external sources of fluid
        fluid_sources = internal_sources + external_sources
        fluid_sources.set_name("Fluid source")

        """
        The following is a "hack" to include cross term missing from the dt operator.
        This reduces the discretization error significantly, but we don't include it
        since the purpose of this verification setup is to be used in functional
        tests to check the correct *default* behaviour of the models.

        Add cross term missing from dt operator relative to proper application of
        the product rule.

        .. code:: python

            rho = self.fluid_density(subdomains)
            phi = self.volume_integral(self.porosity(subdomains), subdomains, dim=1)
            dt_op = pp.ad.time_derivatives.dt
            dt = pp.ad.Scalar(self.time_manager.dt, name="delta_t")
            prod = dt_op(rho, dt) * dt_op(phi, dt)

        """

        return fluid_sources  # - prod

class ManuPoroMechMomentumBalance(momentum.MomentumBalanceEquations):
    """Modify momentum balance to account for time-dependent body force."""

    def body_force(self, subdomains: list[pp.Grid]) -> pp.ad.Operator:
        """Body force."""

        external_sources = pp.ad.TimeDependentDenseArray(
            name="source_mechanics",
            domains=self.mdg.subdomains(),
            previous_timestep=True,
        )

        return external_sources

class ManuPoroMechEquations(
    ManuPoroMechMassBalance,
    ManuPoroMechMomentumBalance,
):
    """Mixer class for modified poromoechanics equations."""

    def set_equations(self):
        """Set the equations for the modified poromechanics problem.

        Call both parent classes' `set_equations` methods.

        """
        ManuPoroMechMassBalance.set_equations(self)
        ManuPoroMechMomentumBalance.set_equations(self)

# -----> Solution strategy
class ManuPoroMechSolutionStrategy2d(poromechanics.SolutionStrategyPoromechanics):
    """Solution strategy for the verification setup."""

    exact_sol: ManuPoroMechExactSolution2d
    """Exact solution object."""

    fluid: pp.FluidConstants
    """Object containing the fluid constants."""

    plot_results: Callable
    """Method for plotting results. Usually provided by the mixin class
    :class:`SetupUtilities`.

    """

    results: list[ManuPoroMechSaveData]
    """List of SaveData objects."""

    def __init__(self, params: dict):
        """Constructor for the class."""
        super().__init__(params)

        self.exact_sol: ManuPoroMechExactSolution2d
        """Exact solution object."""

        self.results: list[ManuPoroMechSaveData] = []
        """Results object that stores exact and approximated solutions and errors."""

        self.flux_variable: str = "darcy_flux"
        """Keyword to access the Darcy fluxes."""

        self.stress_variable: str = "poroelastic_force"
        """Keyword to access the poroelastic force."""

    def set_materials(self):
        """Set material parameters."""
        super().set_materials()

        # Instantiate exact solution object after materials have been set
        self.exact_sol = ManuPoroMechExactSolution2d(self)

    def before_nonlinear_loop(self) -> None:
        """Update values of external sources."""
        super().before_nonlinear_loop()

        sd = self.mdg.subdomains()[0]
        data = self.mdg.subdomain_data(sd)
        t = self.time_manager.time

        # Mechanics source
        mech_source = self.exact_sol.mechanics_source(sd=sd, time=t)
        pp.set_solution_values(
            name="source_mechanics", values=mech_source, data=data, time_step_index=0
        )

        # Flow source
        flow_source = self.exact_sol.flow_source(sd=sd, time=t)
        pp.set_solution_values(
            name="source_flow", values=flow_source, data=data, time_step_index=0
        )

    def after_simulation(self) -> None:
        """Method to be called after the simulation has finished."""
        if self.params.get("plot_results", False):
            self.plot_results()

# -----> Mixer class
class ManuPoroMechSetup2d(  # type: ignore[misc]
    UnitSquareGrid,
    ManuPoroMechEquations,
    ManuPoroMechSolutionStrategy2d,
    ManuPoroMechUtils,
    ManuPoroMechDataSaving,
    poromechanics.Poromechanics,
):
    """
    Mixer class for the two-dimensional non-linear poromechanics verification setup.

    """


import libcst as cst

def is_correct(x):
    try:
        cst.parse_module(x)
    except Exception as e:
        # print(e)
        return False
    return True

if __name__ == "__main__":
    import sys
    if sys.argv[1].endswith('.py'):
        with open(sys.argv[1], 'r') as f:
            content = f.read()
            print(is_correct(content))
    else:
        print(is_correct(sys.argv[1]))


# Ask user for a date, find the hot 100 songs on Billboard for that date
# then create a new list and all songs that could be found to it
# SKILLS: web scraping, API
# Difficulty: hard (too many bumps with Spotipy and Spotify API)

import os
import re
import requests
from bs4 import BeautifulSoup
from spotify_info import client_id, client_secret
import spotipy
from spotipy.oauth2 import SpotifyOAuth

os.environ['SPOTIPY_CLIENT_ID'] = client_id
os.environ['SPOTIPY_CLIENT_SECRET'] = client_secret
os.environ['SPOTIPY_REDIRECT_URI'] = 'https://example.org/'

# ===Get the hot 100 songs from a past point
date_regex = r"\d{4}-\d{2}-\d{2}"
format_is_ok = False
while not format_is_ok:
    date_to_go = input("What date do you want to go back to? Please input in format yyyy-mm-dd:\n")
    format_is_ok = re.search(date_regex, date_to_go)
    if format_is_ok and len(date_to_go) == 10:
        print(f'Going back to {date_to_go}')
    else:
        print("Sorry, I cannot recognise the date, please input again.")
url = f"https://www.billboard.com/charts/hot-100/{date_to_go}/"
response = requests.get(url=url)
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
# ===Extract song names and artists===
song_names_spans = soup.select("li ul li h3")
song_names = [song.getText().strip() for song in song_names_spans]
artists_uncleaned = soup.select('li ul li span')
artists_uncleaned = [artist.getText().strip() for artist in artists_uncleaned]
artists: list = []
for artist in artists_uncleaned:
    if artist.isdigit():
        continue
    elif artist == '-':
        continue
    else:
        artists.append(artist)
song_artist = []
for i in range(len(artists)):
    song_artist.append([song_names[i], artists[i]])
print(song_artist)

# Spotify authentication
scope = 'playlist-modify-private'
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))

# Find all songs' URIs
song_uris = []
for song in song_artist:
    print(f'Processing {song}')
    result = sp.search(q=f'track:{song[0]} artist:{song[1]}', type='track')
    # print(result)
    try:
        uri = result['tracks']['items'][0]['uri']
        song_uris.append(uri)
        print(f'\n{song} added\n')
    except Exception as E:
        print(f'Error: {song} {E}')
print(f'\nFound {len(song_uris)} songs in total\n')

# user_id = '314qxemcswpzo5oalmmizrzd52yi'
user_id = sp.current_user()['id']

# raise SystemExit(0)
playlist_info = sp.user_playlist_create(
    user=user_id,
    name=f'Hot 100 Songs on {date_to_go}',
    public=False,
    description=f'The top 100 songs in the week of {date_to_go} according to Billboard'
)
sp.playlist_add_items(playlist_id=playlist_info['id'], items=song_uris)
print('All found songs added to playlist!')


import torch
import torch.nn as nn
import torchvision.transforms.functional as F

class DoubleConv(nn.Module):
    def __init__(self, in_c: int, out_c: int) -> None:
        super().__init__()
        self.first = nn.Conv2d(in_c, out_c, kernel_size=3, padding=1)
        self.batch_norm_first = nn.BatchNorm2d(out_c)
        self.act_fn_first = nn.ReLU(inplace=True)

        self.second = nn.Conv2d(out_c, out_c, kernel_size=3, padding=1)
        self.batch_norm_second = nn.BatchNorm2d(out_c)
        self.act_fn_second = nn.ReLU(inplace=True)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = self.first(x)
        x = self.batch_norm_first(x)
        x = self.act_fn_first(x)
        x = self.second(x)
        x = self.batch_norm_second(x)
        return self.act_fn_second(x)

class DownSampling(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.max_pool = nn.MaxPool2d(kernel_size=2)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.max_pool(x)

class UpSampling(nn.Module):
    def __init__(self, in_c: int, out_c: int) -> None:
        super().__init__()
        self.up_sampling = nn.ConvTranspose2d(in_channels=in_c, out_channels=out_c, kernel_size=2, stride=2)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.up_sampling(x)

class CropAndConcat(nn.Module):
    def forward(self, x: torch.Tensor, contracting_x: torch.Tensor) -> torch.Tensor:
        contracting_x = F.center_crop(contracting_x, [x.shape[2], x.shape[3]])
        return torch.concat((x, contracting_x), dim=1)

class UNet(nn.Module):
    def __init__(self, in_channel: int, out_channel: int) -> None:
        super().__init__()
        self.down_convs = nn.ModuleList([DoubleConv(in_c, out_c) for in_c, out_c in [(in_channel, 64), (64, 128), (128, 256), (256, 512)]])
        self.down_samples = nn.ModuleList([DownSampling() for _ in range(4)])

        self.middle_conv = nn.Conv2d(512, 1024, kernel_size=3, padding=1)

        self.up_samples = nn.ModuleList([UpSampling(in_c, out_c) for in_c, out_c in [(1024, 512), (512, 256), (256, 128), (128, 64)]])
        self.up_convs = nn.ModuleList([DoubleConv(in_c, out_c) for in_c, out_c in [(1024, 512), (512, 256), (256, 128), (128, 64)]])

        self.final_conv = nn.Conv2d(64, out_channel, kernel_size=1)

        self.crop_concat = CropAndConcat()

    def forward(self, x) -> torch.Tensor:
        skip_connection = []

        for down_conv, down_sample in zip(self.down_convs, self.down_samples):
            x = down_conv(x)
            skip_connection.append(x)
            x = down_sample(x)

        x = self.middle_conv(x)

        for up_conv, up_sample in zip(self.up_convs, self.up_samples):
            x = up_sample(x)
            y = skip_connection.pop()
            x = self.crop_concat(x, y)
            x = up_conv(x)

        return self.final_conv(x)


import sys
sys.path.append("..")
from tkinter import *
from model.Venta import Venta
from controllers.venta_controller import get_ventas,total_ventas,set_ventas,get_precio_producto

class VentanaCompra:

    def __init__(self,root) -> None:
        self.root = root
        self.set_window()

    def set_venta(self,trabajador,producto,estaus,sucursal,cliente,total_precio):
        total= total_ventas()
        trabajador = Venta(total+1,estaus,total_precio,sucursal,cliente,trabajador,producto)
        set_ventas(trabajador)
        self.display_ventas()

    #Funciones
    def display_ventas(self):
        trabajadores = get_ventas()
        listbox = Listbox(self.frame,width=100,height=5)
        listbox.grid(row=10,columnspan=4,sticky=W+E)

        for trabajador in trabajadores:
            print(trabajador)
            listbox.insert(END,trabajador)

    def set_window(self):
        canvas = Canvas(self.root,height=900,width=900)
        canvas.pack()

        self.frame = Frame()
        self.frame.place(relx=0.1,rely=0.1,relwidth=0.9,relheight=0.8,width=500)

        label_vendedor = Label(self.frame,text='Agregar Vendedor')
        label_vendedor.grid(row=2,column=0)
        entry_vendedor = Entry(self.frame)
        entry_vendedor.grid(row=2,column=1)

        label_cliente = Label(self.frame,text='Agregar Cliente')
        label_cliente.grid(row=3,column=0)
        entry_cliente = Entry(self.frame)
        entry_cliente.grid(row=3,column=1)

        label_producto = Label(self.frame,text='Agregar Producto')
        label_producto.grid(row=4,column=0)
        entry_producto = Entry(self.frame)
        entry_producto.grid(row=4,column=1)

        label_status = Label(self.frame,text='Agregar Status de compra')
        label_status.grid(row=5,column=0)
        entry_status = Entry(self.frame)
        entry_status.grid(row=5,column=1)

        label_sucursal = Label(self.frame,text='Agregar Sucursal')
        label_sucursal.grid(row=6,column=0)
        entry_sucursal = Entry(self.frame)
        entry_sucursal.grid(row=6,column=1)

        label_total = Label(self.frame,text='Agregar Total')
        label_total.grid(row=7,column=0)
        entry_total = Entry(self.frame)
        entry_total.grid(row=7,column=1)

        button = Button(self.frame,text='comprar',command=lambda: self.set_venta(
            entry_vendedor.get(),
            entry_producto.get(),
            entry_status.get(),
            entry_sucursal.get(),
            entry_cliente.get(),
            entry_total.get()
        ))
        button.grid(row=8,column=1,sticky=W+E)

        self.display_ventas()


import os
from PIL import Image

from torch.utils.data import Dataset

file_dir = os.path.dirname(__file__)  # the directory that main.py resides in

def pil_loader(path):
    # open path as file to avoid ResourceWarning
    # (https://github.com/python-pillow/Pillow/issues/835)
    with open(path, 'rb') as f:
        with Image.open(f) as img:
            return img.convert('RGB')

class KittiLoader(Dataset):
    def __init__(self, root_dir, mode, filenames, transform=None):
        self.filenames = filenames
        self.loader = pil_loader
        self.img_ext = '.jpg'
        self.root_dir = root_dir
        self.side_map = {"2": 2, "3": 3, "l": 2, "r": 3}
        self.transform = transform
        self.mode = mode

    def __len__(self):
        return len(self.filenames)

    def __getitem__(self, idx):
        line = self.filenames[idx].split()
        folder = line[0]
        if len(line) == 3:
            frame_index = int(line[1])
        else:
            frame_index = 0

        left_image = self.get_color(folder, frame_index, 'l')
        if self.mode == 'train':
            right_image = self.get_color(folder, frame_index, 'r')
            sample = {'left_image': left_image, 'right_image': right_image}
            if self.transform:
                sample = self.transform(sample)
                return sample
            else:
                return sample
        else:
            right_image = self.get_color(folder, frame_index, 'r')
            sample = {'left_image': left_image, 'right_image': right_image}
            if self.transform:
                if self.transform:
                    sample = self.transform(sample)
                    return sample
                else:
                    return sample

    def get_color(self, folder, frame_index, side):
        color = self.loader(self.get_image_path(folder, frame_index, side))
        return color

    def get_image_path(self, folder, frame_index, side):
        ''' For my Endovis split'''
        # root = os.path.join(file_dir, "Data")
        # f_str = "{:06d}{}".format(frame_index, self.img_ext)
        # image_path = os.path.join(
        #     root+folder[61:], "image_0{}".format(self.side_map[side]), f_str)
        '''For the Endovis origin split'''
        f_str = "{:06d}{}".format(frame_index, self.img_ext)
        image_path = os.path.join(
            folder, "image_0{}".format(self.side_map[side]), f_str)
        return image_path


# Tadas Orentas 9/19/2022

import cv2
import glob, os
import numpy as np
from collections import Counter
import time
import random
import difflib
import datetime
import uuid
from PIL import Image
import configparser

config = configparser.RawConfigParser()

config.read_file(open(r'/home/mari1/S_001/config.txt'))

day = str(time.strftime("%m-%d-%y"))

storage = "/run/user/1000/gvfs/smb-share:server=mari_storage_2.local,share=recordings/Flir/all_outputs/"

if os.path.exists(storage + day):
    print("path exists already")
else:
    os.mkdir(storage + day)

modelConf = config.get('ALL_DET_C', 'all_det_cfg')
modelWeights = config.get('ALL_DET_C', 'all_det_weights')

checker_modelConf = config.get('ALL_DET_CHECKER', 'checker_all_det_cfg')
checker_modelWeights = config.get('ALL_DET_CHECKER', 'checker_all_det_weights')

# modelConf = '/home/mari1/S_001/all_det/yolov4-custom_fix.cfg'
# modelWeights = '/home/mari1/S_001/all_det/yolov4-custom_best_fix2.weights'

# modelConf = '/home/mari1/Desktop/switch2/all_det/yolov4-p6_custom.cfg'
# modelWeights = '/home/mari1/Desktop/switch2/all_det/yolov4-p6_custom_best.weights'

# read pre-trained model and config file
net = cv2.dnn.readNet(modelWeights, modelConf)
checker_net = cv2.dnn.readNet(checker_modelWeights, checker_modelConf)

# net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
# net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)

net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)

classes = None

obj = config.get('ALL_DET_C','all_det_obj')

checker_obj = config.get('ALL_DET_CHECKER', 'checker_all_det_obj')

with open(obj, 'r') as f:
    classes = [line.strip() for line in f.readlines()]

with open(checker_obj, 'r') as f:
    checker_classes = [line.strip() for line in f.readlines()]

def checker(image2):
    def get_output_layers(checker_net):

        layer_names = checker_net.getLayerNames()

        output_layers = [layer_names[i - 1] for i in checker_net.getUnconnectedOutLayers()]

        return output_layers

    Width2 = image2.shape[1]
    Height2 = image2.shape[0]

    checker_scale = 0.00392

    checker_blob = cv2.dnn.blobFromImage(image2, checker_scale, (448,448), (0,0,0), True, crop=False)

    # set input blob for the network
    checker_net.setInput(checker_blob)
    checker_outs = checker_net.forward(get_output_layers(checker_net))

    # initialization
    class_ids = []
    confidences = []
    boxes = []
    conf_threshold = 0.55
    nms_threshold = 0.4

    # for each detetion from each output layer
    # get the confidence, class id, bounding box params
    # and ignore weak detections (confidence < 0.5)
    for out in checker_outs:
        for detection in out:
            scores = detection[5:]
            class_id = np.argmax(scores)
            confidence = scores[class_id]
            if confidence > 0.5:
                center_x = int(detection[0] * Width2)
                center_y = int(detection[1] * Height2)
                w = int(detection[2] * Width2)
                h = int(detection[3] * Height2)
                x = center_x - w / 2
                y = center_y - h / 2
                class_ids.append(class_id)
                confidences.append(float(confidence))
                boxes.append([x, y, w, h])

    # apply non-max suppression
    indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)

    # go through the detections remaining
    # after nms and draw bounding box
    for i in indices:
        i = i
        box = boxes[i]
        x = box[0]
        y = box[1]
        w = box[2]
        h = box[3]

        #draw_bounding_box(image2, class_ids[i], confidences[i], round(x), round(y), round(x+w), round(y+h))
        #cv2.rectangle(image2, (0,0), (60,60), 255, 4)

        #print("w",w,"h",h,"class",class_ids[i])

        if (class_ids[i] == 0) and (w>5) and (h>5): #8
            # print("ITS A BOAT")
            # print(w)
            # cv2.imwrite("all_outputs/" +str(rand)+ "_" + ".jpg", image2)
            #print("checkerid",class_ids[i])
            return(True)
#############################################################################################
def getBlurValue(image):
    canny = cv2.Canny(image, 50,250)
    return np.mean(canny)

def Base64Encode(input):
    # List of All Binary Inputs
    binary_list = [int("000000"), int("000001"), int("000010"), int("000011"), int("000100"), int("000101"), int("000110"), int("000111"), int("001000"), int("001001"), int("001010"),
                   int("001011"), int("001100"), int("001101"), int("001110"), int("001111"), int("010000"), int("010001"), int("010010"), int("010011"), int("010100"), int("010101"),
                   int("010110"), int("010111"), int("011000"), int("011101"), int("011010"), int("011011"), int("011100"), int("011101"), int("011110"), int("011111"), int("100000"),
                   int("100001"), int("100010"), int("100011"), int("100100"), int("100101"), int("100110"), int("100111"), int("101000"), int("101001"), int("101010"), int("101011"),
                   int("101100"), int("101101"), int("101110"), int("101111"), int("110000"), int("110001"), int("110010"), int("110011"), int("110100"), int("110101"), int("110110"),
                   int("110111"), int("111000"), int("111001"), int("111010"), int("111011"), int("111100"), int("111101"), int("111110"), int("111111")]
    # List of Equivalent ASCII Value
    ascii_list = ['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', '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', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-']

    # Check for Valid Input
    if input in binary_list:
        # Get Index of the Input in Binary List
        index_ = binary_list.index(input)
        # Set Output to the Equivalent Index Value in ASCII List
        output = ascii_list[index_]
    elif input not in binary_list:
        print(f"ERROR: Binary Input not Found")

    return output

# Returns Site ID String
def GetSiteIDStr():
    # Set Site ID
    # Edge Computer ID Array
    # 1 = Test
    # 2 = BBI
    # 3 = HI
    # 4 = ~
    id_arr = [1, 2, 3, 4]
    id_str = str(id_arr[0])

    return id_str

# Returns Base64 Encoded UUID String
def GenerateEncodedUUID():
    # Generating UUID
    uuid_base = uuid.uuid1().int
    time.sleep(1)

    # Shortening Generated UUID to fit VRN constraints
    uuid_str = str(uuid_base)[:5]
    print(f"New UUID String Generated: {uuid_str}")

    # Converting UUID String to Binary List
    uuid_bin = ' '.join(format(x, 'b') for x in bytearray(uuid_str, 'ascii'))
    split_uuid_bin = map(int, uuid_bin.split())

    # Encoding Each Portion of the Binary UUID List
    encoded_uuid = ''
    for i in split_uuid_bin:
        temp_encoded_uuid = Base64Encode(i)
        encoded_uuid = encoded_uuid + temp_encoded_uuid

    print(f"UUID String Encoded: {encoded_uuid}")
    return encoded_uuid

# Returns Base64 Encoded Date and Time String
def GenerateEncodedDnT():
    # Set Maritime Epoch (1/1/2022 Unix Timestamp = 1640995200)
    mt_epoch_offset = 1640995200
    # Get Time Since Default Epoch
    og_epoch_time = time.time()

    # Set Date and Time String
    dnt_str = str(int(og_epoch_time - mt_epoch_offset))

    # Convert Date and Time String to Binary
    dnt_bin = str(bin(int(dnt_str))[2:])
    # Split Date and Time Binary List Every 6 Characters
    dnt_bin_list = [dnt_bin[i:i+6] for i in range(0, len(dnt_bin), 6)]

    # Get Count of Date and Time List for Padding
    dnt_bin_list_count = len(dnt_bin_list)
    if dnt_bin_list_count == 4:
        print(f"Date and Time Binary List Count = 4, Adding 2 Zeros for Spacing")
        dnt_bin_list_padding = ('0', '0')
        dnt_bin_list.extend(dnt_bin_list_padding)
    elif dnt_bin_list_count == 5:
        print(f"Date and Time Binary List Count = 5, Adding 1 Zero for Spacing")
        dnt_bin_list_padding = ('0')
        dnt_bin_list.extend(dnt_bin_list_padding)
    elif dnt_bin_list_count == 6:
        print(f"Date and Time Binary List Count = 6, No Extra Spacing Needed")

    # Base64 Encoding Date and Time Binary
    encoded_dnt = ''
    for i in dnt_bin_list:
        temp_encoded_dnt = Base64Encode(int(i))
        encoded_dnt = encoded_dnt + temp_encoded_dnt

    print(f"Date and Time String Encoded: {encoded_dnt}")
    return encoded_dnt

# Returns a Randomly Generated Base64 Encoded UID
# CALL THIS TADAS
def GenerateUID():
    # Get Site ID
    site_id = GetSiteIDStr()
    # Get Random UUID
    uuid_ = GenerateEncodedUUID()
    # Get Date and Time
    dnt_ = GenerateEncodedDnT()

    # Combine Returned Strings
    uid_ = site_id + uuid_ + dnt_

    return uid_

path = "/home/mari1/S_001/outputs/"

while(1):

    dir = os.listdir(path)
    file_count = len(dir)

    if file_count > 0:

        base_name = []
        match = []
        dems = []
        n3 = []
        beta =[]
        sum = []
        size = []
        chars = []

        for file in glob.glob(path + "*.jpg"):
            base_name.append(os.path.basename(file))

        for item in base_name:
            if (base_name[0][0] == item[0]) & (base_name[0][1] == item[1]) & (base_name[0][2] == item[2]) & (base_name[0][3] == item[3] )& (base_name[0][4] == item[4]):
                match.append(item)

        # for item in base_name:
        #     for itemm in base_name:
        #         if (item[0] == itemm[0]):
        #             match.append(item)

        for pic in match:
            try:
                image = cv2.imread(path + pic)
                Width = image.shape[1]
                Height = image.shape[0]

                area = Width*Height
                size.append(getBlurValue(image))
            except:
                print("FAILURE")
                match.clear

        if len(size)>0:
            best = max(size)
            ibest = size.index(best)
            imagecheck = cv2.imread(path + match[ibest])

            if checker(imagecheck) == True:
                image = cv2.imread(path + match[ibest])
                image2 = np.copy(image)
                Width = image.shape[1]
                Height = image.shape[0]

                channels = image.shape[2]
                scale = 0.00392

                dems.append(Width*Height*channels)

                blob = cv2.dnn.blobFromImage(image, scale, (800,800), (0,0,0), True, crop=False)
                net.setInput(blob)

                def get_output_layers(net):

                    layer_names = net.getLayerNames()
                    output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
                    return output_layers

                def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):

                    label = str(classes[class_id]) +"_"+ str(round(confidence, 2))
                    beta.append(class_id)
                    color = 255, 255, 255

                    cv2.rectangle(img, (x,y), (x_plus_w,y_plus_h), color, 1)
                    cv2.putText(img, label, (x-10,y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.3, color, 1)

                outs = net.forward(get_output_layers(net))

                class_ids = []
                confidences = []
                boxes = []
                conf_threshold = 0.5
                nms_threshold = 0.3

                for out in outs:
                    for detection in out:
                        scores = detection[5:]
                        class_id = np.argmax(scores)
                        confidence = scores[class_id]
                        if confidence > 0.5:
                            center_x = int(detection[0] * Width)
                            center_y = int(detection[1] * Height)
                            w = int(detection[2] * Width)
                            h = int(detection[3] * Height)
                            x = center_x - w / 2
                            y = center_y - h / 2
                            class_ids.append(class_id)
                            confidences.append(float(confidence))
                            boxes.append([x, y, w, h])

                # apply non-max suppression
                indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)

                for i in indices:
                    i = i
                    box = boxes[i]
                    x = box[0]
                    y = box[1]
                    w = box[2]
                    h = box[3]

                    if class_ids[i] == 8: #8
                        #print("CHARACTERS")
                        imageRGB = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                        im = Image.fromarray(imageRGB)
                        cimg = im.crop((round(x-20), round(y-20), round(x+w+20), round(y+h+20)))
                        chars.append(cimg)

                    draw_bounding_box(image, class_ids[i], confidences[i], round(x), round(y), round(x+w), round(y+h))

                spli3 = match[ibest].split("_")
                #print(spli3[1])

                if "L" in spli3[2]:
                    direc = "O"
                else:
                    direc = "I"

                betai = []
                for u in beta:
                    if (u not in betai) & (u in beta):
                        betai.append(u)

                sum = []
                while len(beta)>0:

                    cont = 0
                    #sum = []
                    beta2 = []
                    for cl in beta:
                        if cl == beta[0]:
                            cont += 1

                    for cc in beta:
                        if cc != beta[0]:
                            beta2.append(cc)

                    beta = beta2
                    sum.append(cont)

                main = []
                for i in betai:
                    ii = betai.index(i)
                    m = classes[betai[ii]] +"_"+ str(sum[ii])
                    main.append(m)

                print(main)
                ###
                rand = int(random.uniform(000000000000, 99999999999))
                #rand = GenerateUID()
                utc_datetime = datetime.datetime.utcnow()

                tim = utc_datetime.strftime("%d-%m-%Y_%H-%M-%S")

                cv2.imwrite("/home/mari1/S_001/all_outputs/" +str(rand) + ".jpg", image)
                cv2.imwrite(storage + day + "/" + str(spli3[1])+ "_"+ direc + "_" + str(tim) +"_"+str(rand) + ".jpg", image2)

                if len(chars) > 0:
                    chars[-1].save("all_outputs/" +str(rand) +"-C" + ".jpg")
                with open("/home/mari1/S_001/all_outputs/" +str(rand) + '.txt', 'w') as f:
                    f.write(str(rand) + ".jpg" + " " + str(tim) + " " + direc + " " + str(spli3[1]) + " " + str(rand) + " " + str(main))
                    f.close()

        base_name.clear
        match.clear
        dems.clear
        n3.clear
        beta.clear
        sum.clear
        size.clear

        for filee in match:

            os.remove(path+filee)

    else:

        time.sleep(5)


#!/usr/bin/env python
# -*- coding:utf-8 -*-
import math
import sys
import re

def dps(visited, level, current, a):
    visited[current] = level
    next_p = a[current] - 1
    if visited[next_p] != 0:
        visited[current] = 0
        return level - visited[next_p] + 1
    else:
        res = dps(visited, level + 1, next_p, a)
        visited[current] = 0
        return res

def solve():
    # =list(map(int,input().split()))
    # =int(input())

    n = int(input())
    res=0

    for i in range(11,n+1):
        count = [0] * 10
        l=list(map(int,list(str(i))))
        for j in l:
            if count[j]>0:
                res+=1
                break
            count[j]+=1
    print(res)

solve()


from functools import wraps
from flask import request, jsonify, session, current_app

from models.user import User
from logic.user import get_user_by_id

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        user = None

        if current_app.config['LOGIN_DISABLED']:
            return f(user, *args, **kwargs)

        auth_header = request.headers.get('Authorization')
        if auth_header:
            if len(auth_header.split(' ')) != 2:
                return jsonify({
                    'success': False,
                    'message': 'authorization header malformed'
                }), 422

            auth_token = auth_header.split(' ')[1]
            user_id = User.decode_auth_token(auth_token)

            # decode_auth_token returns a string if there was an exception decoding the auth_token
            if isinstance(user_id, str):
                return jsonify({
                    'success': False,
                    'message': user_id
                }), 401

            user = get_user_by_id(user_id)

            return f(user, *args, **kwargs)
        else:
            return jsonify({
                'success': False,
                'message': 'no authorization header'
            }), 401

    return decorated_function


class BinaryTree:
    def __init__(self,rootObj):
        self.key = rootObj
        self.leftChild = None
        self.rightChild = None
def serch(x,k):
    if x.key==k:
        return x
    else:
        if k==x.rightChild.key and not x.rightChild==None:
            return x.rightChild
        elif k<x.rightChild.key and not x.rightChild==None:
            return serch(x.leftChild,k)
        elif not x.rightChild==None:
            return serch(x.rightChild,k)
        else:
            return serch(x.leftChild,k)
def p(x):
    if x==None:
        return None
    else:
        print(x.key)
        p(x.leftChild)
        p(x.rightChild)
a=[int(x) for x in input().split(" ")]
b=BinaryTree(a[1])
c=b
for i in range(a[0]):
    s=[int(x) for x in input().split(" ")]
    c=serch(b,s[0])
    c.leftChild=BinaryTree(s[1])
    c.rightChild=BinaryTree(s[2])
p(b)


def moveElementToEnd(array: list, to_move: int):
    collect_list = list()
    for i in array:
        if i != to_move:
            collect_list.append(i)
    collect_list.sort()
    moved_list = collect_list + [to_move] * (len(array) - len(collect_list))
    return moved_list

if __name__ == "__main__":
    arr = [2, 1, 2, 2, 2, 3, 4, 2]
    to_move = 2
    moved_list = moveElementToEnd(arr, to_move)
    print(moved_list)


class Solution(object):
    def findLadders(self, beginWord, endWord, wordlist):
        """
        :type beginWord: str
        :type endWord: str
        :type wordlist: Set[str]
        :rtype: List[List[int]]
        """
        # build the whole graph for the possible solution
        graph,res={},[]
        bwset,ewset=set([beginWord]),set([endWord])
        path=[beginWord]
        if self.buildGraph(bwset,ewset,graph,True,wordlist):
            self.searchPath(beginWord,endWord,graph,path,res)
        return res

    def searchPath(self,beginWord,endWord,graph,path,res):
        if beginWord==endWord:
            res.append(path)
            return
        # search all possible path
        if beginWord in graph:
            for node in graph[beginWord]:
                self.searchPath(node,endWord,graph,path+[node],res)

    def addPath(self,graph,word,neighor,isfw):
        # if the path is forward, adding neighor to word
        if isfw:
            graph[word]=graph.get(word,[])+[neighor]
        else:
            graph[neighor]=graph.get(neighor,[])+[word]

    def buildGraph(self,bwset,ewset,graph,isfw,wordlist):
        if not bwset:
            return False

        if len(bwset)<len(ewset):
            return self.buildGraph(ewset,bwset,graph,not isfw,wordlist)

        for w in (bwset|ewset):
            wordlist.discard(w)

        find,twset=False,set()
        while bwset:
            word=bwset.pop()
            for i in xrange(len(word)):
                for j in xrange(ord('a'),ord('z')+1):
                    cmbstr=word[:i]+chr(j)+word[i+1:]
                    if cmbstr in ewset:
                        find=True
                        self.addPath(graph,word,cmbstr,isfw)
                    if not find and cmbstr in wordlist:
                        twset.add(cmbstr)
                        self.addPath(graph,word,cmbstr,isfw)
        return find or self.buildGraph(twset,ewset,graph,isfw,wordlist)


import json
from datetime import datetime

GUESTBOOK_ENTRIES_FILE = "entries.json"
COUNTER_FILE = "count.json"
entries = []

def init():
    global entries
    try:
        f = open(GUESTBOOK_ENTRIES_FILE)
        entries = json.loads(f.read())
        f.close()
    except:
        entries = []

    return entries

def get_entries():
    global entries
    global counter
    return entries

def count():
    global entries
    counter={}
    try:
        with open(COUNTER_FILE, encoding = 'utf-8') as g:
            counter = json.load(g)
    except:
        counter['count'] = 0

    return str(counter['count'])

def add_entry(name, text):
    global entries, GUESTBOOK_ENTRIES_FILE, counter, COUNTER_FILE
    now = datetime.now()
    counter={}
    #time_string = now.strftime("%b %d, %Y %-I:%M %p")
    # if you have an error using this format, just use
    time_string = str(now)
    entry = {"author": name, "text": text, "timestamp": time_string, "id": count()}
    entries.insert(0, entry) ## add to front of list
    try:
        g = open(COUNTER_FILE)
        counter = json.loads(g.read())
        g.close()
    except:
        counter['count'] = 0

    counter['count']+= 1
    try:
        f = open(GUESTBOOK_ENTRIES_FILE, "w")
        dump_string = json.dumps(entries)
        f.write(dump_string)
        f.close()
    except:
        print("ERROR! Could not write entries to file.")

    try:
        f = open(COUNTER_FILE, "w")
        dump_counter = json.dumps(counter)
        f.write(dump_counter)
        f.close()
    except:
        print("ERROR! Could not write entries to file.")

def delete_entry(counter):
    global entries
    entry1 = []
    try:
        with open(GUESTBOOK_ENTRIES_FILE, encoding = 'utf-8') as g:
            jsonReader = json.load(g)
            for i in jsonReader:
                if str(counter)!=i['id']:
                    entry1.append(i)
                else:
                    pass
    except:
        entry1 = []
    try:
        f = open(GUESTBOOK_ENTRIES_FILE, "w")
        dump_string = json.dumps(entry1)
        f.write(dump_string)
        f.close()
    except:
        print("ERROR! Could not write entries to file.")


import requests

class PayarcError(Exception):
    pass

class PayarcRequest(object):

    access_token: str

    def __init__(self, payarc_info):
        credentials = self.extract_credentials(payarc_info)
        for k, v in credentials.items():
            setattr(self, k, v)
        self.batch_url = 'https://api.payarc.net/v1/deposit/summary'

    @classmethod
    def extract_credentials(cls, payarc_info):
        return {
            'access_token': payarc_info['payarc_access_token']
        }

    def _generate_header(self):
        return {
            'Accept': 'application/json',
            'Content-Type': 'application/x-www-form-urlencoded',
            'Authorization': 'Bearer %s' % self.access_token
        }

    def parse_payarc_batch_report_reponse_data(self, raw_datas):
        res = []
        datas = raw_datas['rows_data']

        for date, row in datas.items():
            if 'row_totals' in row:
                for deposit in row['row_data']:
                    if 'transType' in deposit and deposit['transType'] == 'DEPOSIT':
                        res.append({
                            'amount': deposit['amount'],
                            'batch_ref': deposit['batch_reference_number'],
                            'transaction_qty': deposit['transaction_count'],
                            'date': row['row_totals']['Settlement_Date']
                        })
        return res

    def get_batch_from_payarc(self, from_date, to_date):
        headers = self._generate_header()
        params = {
            'from_date': from_date,
            'to_date': to_date
        }

        response = requests.get(url=self.batch_url, headers=headers, params=params)
        if response.ok:
            return self.parse_payarc_batch_report_reponse_data(response.json()['data'])
        else:
            error_message = response.json().get('error_description')
            raise PayarcError("Something went wrong while getting Batch Report!\n%s" % error_message)


import inspect
import time
from threading import Thread, Lock

count = 0
lock = Lock()

def incre():
    global count
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
    print("Inside %s()" % caller)
    print("Acquiring lock")
    with lock:
        print("Lock Acquired")
        count += 1
        time.sleep(2)

def bye():
    while count < 5:
        incre()

def hello_there():
    while count < 5:
        incre()

hello = Thread(target=hello_there)
hello.start()
goodbye = Thread(target=bye)
goodbye.start()


import pika
import time
import random

class SensorPresenca:
    def __init__(self) -> None:
        pass

    def verificaPresenca(self):
        presenca = random.randint(0, 1)
        return str(presenca)

# Configurar a conexão RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# Declarar uma fila chamada 'presenca_queue'
channel.queue_declare(queue='presenca_queue')

while True:
    sensor = SensorPresenca()
    presenca = sensor.verificaPresenca()
    print('Presença:', presenca)

    # Publicar a mensagem no RabbitMQ
    channel.basic_publish(exchange='', routing_key='presenca_queue', body=presenca)
    print(f'Mensagem {presenca} publicada na fila')
    time.sleep(5)

# Fechar a conexão com o RabbitMQ
connection.close()


from io import StringIO
import os
import sys
import csv
from tracemalloc import start
import numpy as np
import pandas as pd
import urllib.request
import urllib.error
import json
import datetime
import re
import zipfile
import shutil
from preprocess_data import *

datadir = './data/raw/'
droughtDir = f'{datadir}drought/'
weatherDir = f'{datadir}weather/'
featuresDir = f'{datadir}features/'
outputDir = './data/processed/'
order = ['min', 'avg', 'max', 'precip']
months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']

weatherFileName = 'weather.csv'
droughtFileName = 'drought.csv'
countyCodesName = 'county_codes.csv'
countyCoordsName = 'county_coords.csv'
populationName = 'population.csv'
featuresName = 'features.csv'

outputFileNames = [
  weatherFileName,
  droughtFileName,
  countyCodesName,
  countyCoordsName,
  populationName,
  featuresName,
]

#
def download(url, save_path, skip_download_if_save_file_exists = False, read = True):

  delete_file = False
  download_contents = None

  # construct friendly name from path filename
  if save_path is not None:
    data_name = os.path.splitext(os.path.basename(save_path))[0]
    friendly_name = data_name.replace("-", " ") \
                            .replace("_", " ")
  else:
    friendly_name = 'data'
    delete_file = True
    save_path = 'download.temp'

  def report_hook(count, block_size, total_size):
    percent = int(count * block_size * 100 / total_size)
    print(f'downloading {friendly_name}.... {(count * block_size)/1024} KB', end='\r')

  if not skip_download_if_save_file_exists or not os.path.exists(save_path):
    print(f'downloading {friendly_name}....', end='\r')
    urllib.request.urlretrieve(url, save_path, reporthook=report_hook)
    print('')

  # read contents from file
  if read:
    with open(save_path, 'r') as f:
      download_contents = f.read()

  # delete file
  if delete_file:
    os.remove(save_path)

  return download_contents

def convert_countycodes(skip_download_if_save_file_exists):
  global allStatesCounties
  id = 1

  with open(f'{outputDir}{countyCodesName}', 'w') as w:
    # header
    w.write('id INTEGER PRIMARY KEY,county_code INTEGER,fips_code INTEGER,county_name VARCHAR(50),state VARCHAR(2),country VARCHAR(3)\n')

    for state_abbr in allStatesCounties:
      state = allStatesCounties[state_abbr]
      counties = state['Counties']
      for county in counties:

        fips_code = county['Fips']
        ncdc_code = county['Ncdc']
        state_name = state['FullName']
        county_name = county['Name']

        # prepend '01' to code, indicating county is from united states
        # add 'US' value for country column
        w.write(f'{id},01{ncdc_code},{fips_code},{county_name},{state_abbr},US\n')
        id += 1

def convert_county_coords(skip_download_if_save_file_exists):
  global allStatesCounties

  # download coordinate data
  county_boundaries = download('https://public.opendatasoft.com/explore/dataset/us-county-boundaries/download/?format=csv&timezone=America/Los_Angeles&lang=en&use_labels_for_header=true&csv_separator=%3B', f'{weatherDir}us-county-boundaries.csv', skip_download_if_save_file_exists)

  # converts county coords csv
  with open(f'{outputDir}{countyCoordsName}', 'w') as w:
    # this csv contains very large fields so
    # we must increase the field size limit to something larger
    csv.field_size_limit(0x1000000)
    reader = csv.reader(county_boundaries.split('\n'), delimiter=';')
    columns = next(reader)

    # header
    w.write('county_code INTEGER PRIMARY KEY,geo_point VARCHAR(50),geo_shape TEXT[][]\n')

    # iterate lines
    id = 1
    for row in reader:
      if len(row) > 8:
        geo_point = row[0]
        geo_shape = row[1]
        state = row[8]
        county_code = row[3]
        skip = False

        if state in allStatesCounties:
          county_code = f'{allStatesCounties[state]["StateCode"]}{county_code}'
        else:
          skip = True
          print(f'skipping county coord {row[2:]}')

        if not skip:
          # process geo shape into our db format
          shape_json = json.loads(geo_shape)
          shape_processed = '"{'
          for coord in shape_json["coordinates"][0]:
            shape_processed += f'{{""{coord[0]}"",""{coord[1]}""}},'
          shape_processed = shape_processed.strip(',') + '}"'

          # prepend '01' to code, indicating county is from united states
          w.write(f'01{county_code},"{geo_point}",{shape_processed}\n')
          id += 1

def build_weather_table(skip_download_if_save_file_exists):
    filesToStrip = ['avgtmp', 'maxtmp', 'mintmp', 'precip']
    urlPaths = ['climdiv-tmpccy', 'climdiv-tmaxcy', 'climdiv-tmincy', 'climdiv-pcpncy']
    colsPrefix = ['tmp_avg', 'tmp_max', 'tmp_min', 'precip']
    dataFiles = {}

    icols = [i for i in range(len(months) + 1)]
    dtypes = [str] + [str] * len(months)
    d = pd.DataFrame(np.vstack([icols, dtypes])).to_dict(orient='records')[1]
    dff = pd.DataFrame()

    # download weather data directory listing
    weather_directory = download('https://www1.ncdc.noaa.gov/pub/data/cirs/climdiv/', None)

    # download weather data
    for filename, url_path in zip(filesToStrip, urlPaths):
      url_path_idx = weather_directory.index(url_path)
      url_path_end_idx = weather_directory.index('"', url_path_idx)
      path = weather_directory[url_path_idx:url_path_end_idx]
      dataFiles[filename] = download(f'https://www1.ncdc.noaa.gov/pub/data/cirs/climdiv/{path}', f'{weatherDir}climdiv-{filename}.txt', skip_download_if_save_file_exists)

    for filename, prefix, i in zip(filesToStrip, colsPrefix, range(len(colsPrefix))):

        # Build column names
        cols = ['id INTEGER PRIMARY KEY']
        for m in months:
            cols.append(f'{prefix}_{m} FLOAT')

        s = re.sub('( |\t)+', ' ', dataFiles[filename])
        strio = StringIO(s)
        df = pd.read_csv(strio, delimiter=' ', header=None, index_col=False, usecols=icols, dtype=d)

        # Remove datatype field, since it's the same throughout the entirity of each file
        s = df.iloc[:,0]
        s = s.str[0:5] + s.str[7:]
        df.iloc[:,0] = s

        if i == 0:
            # Add USA Country code
            cc = pd.DataFrame(['01']*len(df), dtype=(str))
            df.iloc[:,0] = cc.iloc[:,0].str[:] + df.iloc[:,0].str[:]

            # Add columns (along with id column this first time)
            df.columns = cols
            dff = pd.DataFrame(df, columns=cols)
        else:
            # Add columns
            df.columns = cols
            # Insure id parity here!
            for v1, v2 in zip(dff.iloc[:,0], df.iloc[:,0]):
                # Don't compare country code as it hasn't been added to anything but the primary id
                if v1[2:] != v2:
                    raise RuntimeError('Invalid Data Join')

            df = df.iloc[:,1:]
            dff = dff.join(df)

        print(dff)

        # Create individual files
        #df.to_csv(f'{datadir}{filename}.csv', header=False, index=False)

    # WARNING: If you open this file in Excel without specifying the first
    # column is a string, it will remove all the first zeros in the ID column
    dff.to_csv(f'{outputDir}{weatherFileName}', index=False)
    print('Succesful merge!')

def build_drought_table(skip_download_if_save_file_exists):

    urlPaths = ['climdiv-pdsist', 'climdiv-phdist', 'climdiv-pmdist', 'climdiv-sp01st', 'climdiv-sp02st', 'climdiv-sp03st', 'climdiv-sp06st', 'climdiv-sp09st', 'climdiv-sp12st', 'climdiv-sp24st']
    dataFiles = {}

    icols = [i for i in range(len(months) + 1)]
    dtypes = [str] + [str] * len(months)
    d = pd.DataFrame(np.vstack([icols, dtypes])).to_dict(orient='records')[1]
    dff = pd.DataFrame()

    # download weather data directory listing
    weather_directory = download('https://www1.ncdc.noaa.gov/pub/data/cirs/climdiv/', None)

    # download weather data
    for url_path in urlPaths:
      url_path_idx = weather_directory.index(url_path)
      url_path_end_idx = weather_directory.index('"', url_path_idx)
      path = weather_directory[url_path_idx:url_path_end_idx]
      dataFiles[url_path] = download(f'https://www1.ncdc.noaa.gov/pub/data/cirs/climdiv/{path}', f'{droughtDir}{url_path}.txt', skip_download_if_save_file_exists)

    for i, path in enumerate(urlPaths):
        datatype = path[8:]
        cols = ['id INTEGER PRIMARY KEY']
        for m in months:
            cols.append(f'{datatype}_{m} FLOAT')

        newLines = []
        lines = dataFiles[path].split('\n')
        for line in lines:
            parts = line.split()
            if len(parts) > 0:

                # TODO: Add the years of 1895 & 1896 back in. It looks like the bad
                # data comes from the rolling averages of 12 & 24 months respectively
                # (which makes sense) - but we'd need to handle this in the ui/db and
                # not allow the user to select these two values for that date range
                if int(parts[0][0:3]) > 48 or int(parts[0][-4:]) < 1897:
                    continue
                parts[0] = parts[0][1:3] + parts[0][6:]
                newLines.append(parts)

        df = pd.DataFrame(newLines, columns=cols)

        if i == 0:
            # Add USA Country code
            cc = pd.DataFrame(['01']*len(df), dtype=(str))
            df.iloc[:,0] = cc.iloc[:,0].str[:] + df.iloc[:,0].str[:]

            # Add columns (along with id column this first time)
            df.columns = cols
            dff = pd.DataFrame(df, columns=cols)
        else:
            # Add columns
            df.columns = cols
            # Insure id parity here!
            for v1, v2 in zip(dff.iloc[:,0], df.iloc[:,0]):
                # Don't compare country code as it hasn't been added to anything but the primary id
                if v1[2:] != v2:
                    raise RuntimeError('Invalid Data Join')

            df = df.iloc[:,1:]
            dff = dff.join(df)
        print(dff)
    dff.to_csv(f'{outputDir}{droughtFileName}', index=False)
    print('Succesful merge!')

def build_population_table(skip_download_if_save_file_exists):
  global allStatesCounties

  # https://data.nber.org/census/pop/cencounts.csv 1900-1990
  # https://api.census.gov/data/2000/dec/sf1?get=P001001,NAME&for=county:*

  # get historical data
  pop_1900_to_1990 = download("https://data.nber.org/census/pop/cencounts.csv", f'{datadir}pop-1900-1990.csv', skip_download_if_save_file_exists= skip_download_if_save_file_exists)

  # generates population csv
  with open(f'{outputDir}{populationName}', 'w') as w:
    reader = csv.reader(pop_1900_to_1990.split('\n'), delimiter=',')
    columns = next(reader)
    us_total_pop = next(reader)
    id = 1

    # header
    w.write('id INTEGER PRIMARY KEY,county_code INTEGER,year INTEGER,population INTEGER\n')

    # iterate historical data
    for row in reader:
      if len(row) == 12:

        # name is state code then name
        # some rows are aggregate state data
        # valid county name is "AL Autauga County"
        # agg state name is "AL Alabama"
        name = row[11]
        state_code = name[:2]
        name = name[3:]
        fips = row[10]
        county = None
        skip = False

        if fips[2:] == '000':
          # fips code of 000 means its the state/country
          # not the county
          skip = True
        elif state_code in allStatesCounties:
          counties = allStatesCounties[state_code]["Counties"]
          filtered_counties = list(filter(lambda x: x["Fips"] == fips, counties))
          if len(filtered_counties) == 1:
            county = filtered_counties[0]
          else:
            skip = True
            print(f'skipping 1900-1990 population for {state_code} {name} {fips}')
        else:
          skip = True
          print(f'skipping 1900-1990 population for {state_code} {name} {fips}')

        if not skip:

          for i in range(10):
            # prepend '01' to code, indicating county is from united states
            value = row[i]
            if value == '.':
              value = '-1'
            w.write(f'{id},01{county["Ncdc"]},{1900 + (i * 10)},{value}\n')
            id += 1

    # iterate new data until we can't
    year = 2000
    while True:

      # try and download data
      # download will throw exception on 404
      # which happens when we reach the end of the available data
      pop_data = None
      try:
        pop_data_json = download(f"https://api.census.gov/data/{year}/dec/sf1?get=P001001,NAME&for=county:*", f'{datadir}pop-{year}.csv', skip_download_if_save_file_exists= skip_download_if_save_file_exists)
        pop_data = json.loads(pop_data_json)
      except:
        break

      # first row is header
      for row in pop_data[1:]:
        population = row[0]
        name = row[1] # "county name, state name"
        state_id = row[2]
        county_fips = row[3] # just county fips, no state id
        fips = f'{state_id}{county_fips}'
        state_name = name.split(',')[1].strip()
        skip = False
        county = None

        state_code = next((s for s in allStatesCounties if allStatesCounties[s]["FullName"] == state_name), None)
        if state_code is None:
          skip = True
          print(f'skipping {year} population for {name} {state_id} {county_fips}')
        else:
          state = allStatesCounties[state_code]
          county = next((c for c in state["Counties"] if c["Fips"] == fips), None)
          if county is None:
            skip = True
            print(f'skipping {year} population for {name} {state_id} {county_fips}')

        if not skip:

          # prepend '01' to code, indicating county is from united states
          w.write(f'{id},01{county["Ncdc"]},{year},{population}\n')
          id += 1

      year += 10

def build_features_table(skip_download_if_save_file_exists):
  # https://geonames.usgs.gov/docs/stategaz/NationalFile.zip

  # get dataset
  download("https://geonames.usgs.gov/docs/stategaz/NationalFile.zip", f'{datadir}features.zip', read= False, skip_download_if_save_file_exists= skip_download_if_save_file_exists)

  # delete existing zip extraction
  if os.path.exists(featuresDir):
    shutil.rmtree(featuresDir)

  # unzip dataset
  with zipfile.ZipFile(f'{datadir}features.zip', 'r') as zip_ref:
    zip_ref.extractall(featuresDir)

  # get extracted filename
  dataset_file = os.listdir(featuresDir)[0]

  # converts features csv
  with open(f'{featuresDir}{dataset_file}', 'r', encoding='utf-8') as r:
    lines = r.readlines()

    with open(f'{outputDir}{featuresName}', 'w', encoding='utf-8') as w:
      # this csv contains very large fields so
      # we must increase the field size limit to something larger
      csv.field_size_limit(0x1000000)
      reader = csv.reader(lines, delimiter='|')
      columns = next(reader)

      # header
      w.write('id INTEGER PRIMARY KEY,county_code INTEGER,feature_type VARCHAR(50),feature_name VARCHAR(200),elevation_ft INTEGER\n')

      # iterate lines
      id = 1

      for row in reader:
        if len(row) == 20:
          name = row[1]
          name = name.replace(",","")
          feature_type = row[2]
          state_code = row[3]
          fips = f'{row[4]}{row[6]}'
          elevation = row[16]
          ncdc = None
          skip = False

          if state_code in allStatesCounties:
            ncdc = f'{allStatesCounties[state_code]["StateCode"]}{row[6]}'
          else:
            skip = True
            print(f'skipping feature {name} {feature_type} {state_code} {fips}')

          if not elevation:
            skip = True
            print(f'skipping feature {name} {feature_type} {state_code} {fips} FOR MISSING ELEVATION')

          if not skip:
            # prepend '01' to code, indicating county is from united states
            w.write(f'{id},01{ncdc},{feature_type},{name},{elevation}\n')

def has_processed_files():
  for outputFileName in outputFileNames:
    if not os.path.exists(f'{outputDir}{outputFileName}'):
      return False

  return True

def process_files(force_data_redownload = True):
  # if not forced redownload and we've already processed everything
  # exit
  if not force_data_redownload:
    if has_processed_files():
      return

  # process county codes and test the output
  try:
    build_drought_table(not force_data_redownload)
  except Exception as error:
    print(error)

  try:
    build_weather_table(not force_data_redownload)
  except Exception as error:
    print(error)

  try:
    convert_countycodes(not force_data_redownload)
  except Exception as error:
    print(error)

  try:
    convert_county_coords(not force_data_redownload)
  except Exception as error:
    print(error)

  try:
    build_population_table(not force_data_redownload)
  except Exception as error:
    print(error)

  try:
    build_features_table(not force_data_redownload)
  except Exception as error:
    print(error)

def create_working_directory():
  if not os.path.exists(outputDir):
    os.makedirs(outputDir)
  if not os.path.exists(droughtDir):
    os.makedirs(droughtDir)
  if not os.path.exists(weatherDir):
    os.makedirs(weatherDir)

if __name__ == '__main__':
  create_working_directory()
  process_files()


import os
import numpy

yearrange=[1985,2018]
longitude=[291,360]
latitude=[-9,71]

pathsource="C:\\Users\\lenovo\\Desktop\\data2"
pathres="C:\\Users\\lenovo\\Desktop\\data2mean"
shape=(latitude[1]-latitude[0]+1,longitude[1]-longitude[0]+1)

for year in range(yearrange[0],yearrange[1]+1):
    newpath=os.path.join(pathsource,str(year)+".csv")
    data=numpy.zeros(shape,dtype=float)

    with open(newpath) as path1:
        content=path1.readlines()
        for cont in content:
            line=cont.split(",")
            latituderead=int(line[1])-latitude[0]
            longituderead=int(line[2])-longitude[0]
            if line[3]=="NaN":
                value=1000000
            else:
                value=float(line[3].strip())
            data[latituderead][longituderead]+=value

    savepath=os.path.join(pathres,str(year)+".csv")
    with open(savepath,"w") as file:
        for i in range(shape[0]):
            for j in range(shape[1]):
                value=data[i][j]/12
                if value>10000:
                    res="NaN"
                else:
                    res= str(round(value,3))
                line=str(i+latitude[0])+","+str(j+longitude[0])+","+res+"\n"
                file.write(line)

3 大三/数学建模程序/数学建模数据平均.py


import sqlite3
import threading
import json

class Database:
    _instance = None
    _lock = threading.Lock()

    @staticmethod
    def getInstance():
        """ Static access method. """
        if Database._instance == None:
            Database()
        return Database._instance

    def __init__(self):
        """ Virtually private constructor. """
        if Database._instance != None:
            raise Exception("The class 'Database' is a singleton!")
        else:
            Database._instance = self

    def write_ping(self, tracker_id, time, data):
        # print(tracker_id, time, data)
        with self._lock:
            con = sqlite3.connect("database.db")
            cur = con.cursor()
            cur.execute(
                "INSERT INTO pings VALUES (?, ?, ?)",
                (tracker_id, time, json.dumps(data))
            )
            con.commit()
            con.close()

    def fetch_pings(self, tracker_id=None, limit=None, clean=True):
        with self._lock:
            con = sqlite3.connect("database.db")
            cur = con.cursor()
            cur.execute(
                "SELECT * FROM pings " +
                ("WHERE tracker_id = ?" if tracker_id !=
                 None else "") +
                "ORDER BY time DESC " +
                ("LIMIT ?" if limit != None else ""),
                tuple(
                    filter(
                        lambda x: x != None,
                        [tracker_id, limit]
                    )
                )
            )
            pings = cur.fetchall()
            con.close()

            return [
                {
                    "tracker_id": p[0],
                    "time": p[1],
                    "data": json.loads(p[2])["DATA"]
                }
                for p in pings
            ]

    def create_db(self):
        with self._lock:
            con = sqlite3.connect("database.db")
            cur = con.cursor()
            cur.execute(
                '''CREATE TABLE pings
                (tracker_id text, time integer, data text)'''
            )
            con.commit()
            con.close()

if __name__ == "__main__":
    if input("Would you like to create the database? (y/N)") == "y":
        input("Please delete database.db then press ENTER")
        print("Creating database")
        db = Database.getInstance()
        db.create_db()
        print("Done!")


"""
This will connect the Sickchill platform to Homeassistant, showing stats and switches from Sickchill.
"""
import logging
import time
import re
from datetime import timedelta
import requests
import urllib

#import newznab
from newznab import wrapper

COMPONENT_NAME = "sabnzbd"

class sabnzbd:
	def __init__(self,config,_LOGGER):
		"""Set up the component."""
		self._LOGGER = _LOGGER
		self.category = config['sab_category']
		self.sab_url = config['sab_host']
		self.sab_api_key = config['sab_api_key']

		_LOGGER.warning(' %s is starting', COMPONENT_NAME)

	def addnzb(self,url,name=None):
		'''
		Send a NZB url to SABNZBD

		:param url: The NZBSearchResult object to send to SAB
		'''

		self._LOGGER.debug("Adding url to SABNZBD: %s",url)

		# set up a dict with the URL params in it
		params = {'output': 'json'}
		params['apikey'] = self.sab_api_key

		# Set the sab catgory for sickchill
		params['cat'] = self.category

		self._LOGGER.info('Sending NZB to SABnzbd')
		submiturl = urllib.parse.urljoin(self.sab_url, 'api')

		params['mode'] = 'addurl'
		params['name'] = url

		if name is not None:
			params['nzbname'] = name

		result = requests.post(url=submiturl,data=params)

		self._LOGGER.debug("REturned result form sab: %s",result.status_code)


import pandas as pd
import requests
import os
from datetime import datetime
from dateutil.relativedelta import relativedelta

class FSC:
    BASE_URL = 'http://apis.data.go.kr/1160100/service'
    PRICE_INFO = 'GetBondSecuritiesInfoService/getBondPriceInfo'
    BASE_INFO= 'GetBondIssuInfoService/getBondBasiInfo'

    @classmethod
    def get_data(cls, entrypoint, base_date, num_of_rows):
        fsc_api_key = os.getenv('fsc_api_key')
        if not fsc_api_key:
            raise Exception('NO FSC API KEY')
        print(fsc_api_key)
        params = dict(
            serviceKey=fsc_api_key,
            resultType='json',
            basDt=base_date,
            numOfRows=num_of_rows,
        )
        res = requests.get(f'{cls.BASE_URL}/{entrypoint}', params=params)
        json : dict = res.json()
        data : {} = json.get('response', {}).get('body', {})\
                          .get('items', {}).get('item', {})
        if not len(data):
            raise Exception('NO DATA')
        df = pd.DataFrame(data)
        return df

    @classmethod
    def get_price_info(cls):
        최근일자 = datetime.utcnow()
        for _ in range(14):
            print(최근일자.date())
            try:
                return cls.get_data(FSC.PRICE_INFO,
                                    최근일자.strftime('%Y%m%d'), 1000)
            except Exception as e:
                print(e)
                최근일자 -= relativedelta(days=1)

    @classmethod
    def get_price_info(cls):
        # 금융위원회_채권시세정보
        # https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15094784
        최근일자 = datetime.utcnow()
        for _ in range(14):
            print(최근일자.date())
            try:
                info = cls.get_data(FSC.PRICE_INFO,
                                    최근일자.strftime('%Y%m%d'), 1000)
                print('OK')
                return info
            except Exception as e:
                print(e)
                최근일자 -= relativedelta(days=1)

    @classmethod
    def get_base_info(cls):
        # 금융위원회_채권기본정보
        # https://www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15059592
        최근일자 = datetime.utcnow()
        for _ in range(14):
            print(최근일자.date())
            try:
                info = cls.get_data(FSC.BASE_INFO,
                                    최근일자.strftime('%Y%m%d'), 30000)
                print('OK')
                return info
            except Exception as e:
                print(e)
                최근일자 -= relativedelta(days=1)

    @classmethod
    def get_bond_info(cls):
        price_info = cls.get_price_info()
        base_info = cls.get_base_info()
        bond_info = pd.merge(price_info, base_info, on='isinCd', suffixes=['x', 'y'])
        bond_info = bond_info.loc[:, [
            # 채권명, 거래일, 거래량,
            'itmsNm', 'basDtx', 'trqu',
            # 가격, 수익률, 표면이율, 만기일
            'clprPrc', 'clprBnfRt', 'bondSrfcInrt', 'bondExprDt',
            # 신뢰도
            'kisScrsItmsKcdNm', 'kbpScrsItmsKcdNm', 'niceScrsItmsKcdNm']]
        # 'bondIsurNm' : 발행자명, 'intPayCyclCtt' : 이자주기
        # 'scrsItmsKcdNm' : 분류
        bond_info.rename(columns=dict(
            basDtx= 'DATE', itmsNm = 'NAME', trqu = 'VOLUME', clprPrc = 'PRICE',
            clprBnfRt = 'BENEFIT', bondSrfcInrt = 'INTEREST', bondExprDt = 'EXPIRE',
            kisScrsItmsKcdNm = 'KIS', kbpScrsItmsKcdNm = 'KBP', niceScrsItmsKcdNm = 'NICE',
        ), inplace=True)
        bond_info.DATE = pd.to_datetime(bond_info.DATE, format='%Y%m%d')
        bond_info.EXPIRE = pd.to_datetime(bond_info.EXPIRE, format='%Y%m%d', errors='coerce')
        bond_info.VOLUME = bond_info.VOLUME.astype(int)
        bond_info.PRICE = bond_info.PRICE.astype(float)
        bond_info.BENEFIT = bond_info.BENEFIT.astype(float)
        bond_info.INTEREST = bond_info.INTEREST.astype(float)
        bond_info.KIS = bond_info.KIS.map({
            '': True, 'AAA': True,
            'AA+': True, 'AA0': True, 'AA-': True,
            'A+': True, 'A0': True, 'A-': True,
            'BBB+': True, 'BBB0': True, 'BBB-': True}).fillna(False)
        bond_info.KBP = bond_info.KBP.map({
            '': True, 'AAA': True,
            'AA+': True, 'AA': True, 'AA-': True,
            'A+': True, 'A': True, 'A-': True,
            'BBB+': True, 'BBB': True, 'BBB-': True}).fillna(False)
        bond_info.NICE = bond_info.NICE.map({
            '': True, 'AAA': True,
            'AA+': True, 'AA0': True, 'AA-': True,
            'A+': True, 'A0': True, 'A-': True,
            'BBB+': True, 'BBB0': True, 'BBB-': True}).fillna(False)
        return bond_info


import time

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By

ser_obj = Service("/home/prashant/Documents/Browser_Driver/chrome_102/chromedriver")
driver = webdriver.Chrome(service=ser_obj)

driver.get("https://admin-demo.nopcommerce.com/login")
driver.maximize_window()

email_box = driver.find_element(By.XPATH, "//input[@id='Email']")
email_box.clear()
email_box.send_keys("abc@gmail.com")

# text - returns inner text of the web_element
print("Result od text: ", email_box.text)  # prints nothing

# get_attributes() - returns values of any attributes of the web_element
print("Result of get_attributes: ", email_box.get_property('value'))  # print abc@gmail.com

button = driver.find_element(By.XPATH, "//button[normalize-space()='Log in']")
print("Result of text: ", button.text)  # LOG IN
print("Result of get-attributes: ", button.get_attribute('value'))  # prints nothing
print("Result of get-attributes: ", button.get_attribute('type'))  # prints submit
time.sleep(2)
driver.quit()


import turtle

wn = turtle.Screen()
wn.bgcolor('lightgreen')

mosca = turtle.Turtle()
mosca.shape('turtle')

larg = turtle.Turtle()
larg.shape('turtle')
larg.color('red')
def desenhaQuadrado(t,tam):

    for i in range(4):
        t.forward(tam)
        t.left(90)

tamanho = 20

for i in range(10):
    desenhaQuadrado(mosca,tamanho)
    desenhaQuadrado(larg, (tamanho + 6))
    mosca.goto (-(tamanho / 2), -(tamanho / 2))
    larg.goto (-((tamanho + 6) / 2), -((tamanho + 6 )/ 2))
    tamanho = tamanho + 20