# Copyright 2022 The Nerfstudio Team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Camera transformation helper code.
"""

import math
from typing import List, Optional, Tuple

import numpy as np
import torch
from torchtyping import TensorType
from typing_extensions import Literal

_EPS = np.finfo(float).eps * 4.0

def unit_vector(data, axis: Optional[int] = None) -> np.ndarray:
    """Return ndarray normalized by length, i.e. Euclidean norm, along axis.

    Args:
        axis: the axis along which to normalize into unit vector
        out: where to write out the data to. If None, returns a new np ndarray
    """
    data = np.array(data, dtype=np.float64, copy=True)
    if data.ndim == 1:
        data /= math.sqrt(np.dot(data, data))
        return data
    length = np.atleast_1d(np.sum(data * data, axis))
    np.sqrt(length, length)
    if axis is not None:
        length = np.expand_dims(length, axis)
    data /= length
    return data

def quaternion_from_matrix(matrix, isprecise: bool = False) -> np.ndarray:
    """Return quaternion from rotation matrix.

    Args:
        matrix: rotation matrix to obtain quaternion
        isprecise: if True, input matrix is assumed to be precise rotation matrix and a faster algorithm is used.
    """
    M = np.array(matrix, dtype=np.float64, copy=False)[:4, :4]
    if isprecise:
        q = np.empty((4,))
        t = np.trace(M)
        if t > M[3, 3]:
            q[0] = t
            q[3] = M[1, 0] - M[0, 1]
            q[2] = M[0, 2] - M[2, 0]
            q[1] = M[2, 1] - M[1, 2]
        else:
            i, j, k = 1, 2, 3
            if M[1, 1] > M[0, 0]:
                i, j, k = 2, 3, 1
            if M[2, 2] > M[i, i]:
                i, j, k = 3, 1, 2
            t = M[i, i] - (M[j, j] + M[k, k]) + M[3, 3]
            q[i] = t
            q[j] = M[i, j] + M[j, i]
            q[k] = M[k, i] + M[i, k]
            q[3] = M[k, j] - M[j, k]
        q *= 0.5 / math.sqrt(t * M[3, 3])
    else:
        m00 = M[0, 0]
        m01 = M[0, 1]
        m02 = M[0, 2]
        m10 = M[1, 0]
        m11 = M[1, 1]
        m12 = M[1, 2]
        m20 = M[2, 0]
        m21 = M[2, 1]
        m22 = M[2, 2]
        # symmetric matrix K
        K = np.array(
            [
                [m00 - m11 - m22, 0.0, 0.0, 0.0],
                [m01 + m10, m11 - m00 - m22, 0.0, 0.0],
                [m02 + m20, m12 + m21, m22 - m00 - m11, 0.0],
                [m21 - m12, m02 - m20, m10 - m01, m00 + m11 + m22],
            ]
        )
        K /= 3.0
        # quaternion is eigenvector of K that corresponds to largest eigenvalue
        w, V = np.linalg.eigh(K)
        q = V[np.array([3, 0, 1, 2]), np.argmax(w)]
    if q[0] < 0.0:
        np.negative(q, q)
    return q

def quaternion_slerp(quat0, quat1, fraction: float, spin: int = 0, shortestpath: bool = True) -> np.ndarray:
    """Return spherical linear interpolation between two quaternions.
    Args:
        quat0: first quaternion
        quat1: second quaternion
        fraction: how much to interpolate between quat0 vs quat1 (if 0, closer to quat0; if 1, closer to quat1)
        spin: how much of an additional spin to place on the interpolation
        shortestpath: whether to return the short or long path to rotation
    """
    q0 = unit_vector(quat0[:4])
    q1 = unit_vector(quat1[:4])
    if q0 is None or q1 is None:
        raise ValueError("Input quaternions invalid.")
    if fraction == 0.0:
        return q0
    if fraction == 1.0:
        return q1
    d = np.dot(q0, q1)
    if abs(abs(d) - 1.0) < _EPS:
        return q0
    if shortestpath and d < 0.0:
        # invert rotation
        d = -d
        np.negative(q1, q1)
    angle = math.acos(d) + spin * math.pi
    if abs(angle) < _EPS:
        return q0
    isin = 1.0 / math.sin(angle)
    q0 *= math.sin((1.0 - fraction) * angle) * isin
    q1 *= math.sin(fraction * angle) * isin
    q0 += q1
    return q0

def quaternion_matrix(quaternion) -> np.ndarray:
    """Return homogeneous rotation matrix from quaternion.

    Args:
        quaternion: value to convert to matrix
    """
    q = np.array(quaternion, dtype=np.float64, copy=True)
    n = np.dot(q, q)
    if n < _EPS:
        return np.identity(4)
    q *= math.sqrt(2.0 / n)
    q = np.outer(q, q)
    return np.array(
        [
            [1.0 - q[2, 2] - q[3, 3], q[1, 2] - q[3, 0], q[1, 3] + q[2, 0], 0.0],
            [q[1, 2] + q[3, 0], 1.0 - q[1, 1] - q[3, 3], q[2, 3] - q[1, 0], 0.0],
            [q[1, 3] - q[2, 0], q[2, 3] + q[1, 0], 1.0 - q[1, 1] - q[2, 2], 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ]
    )

def get_interpolated_poses(pose_a, pose_b, steps: int = 10) -> List[float]:
    """Return interpolation of poses with specified number of steps.
    Args:
        poseA: first pose
        poseB: second pose
        steps: number of steps the interpolated pose path should contain
    """

    quat_a = quaternion_from_matrix(pose_a[:3, :3])
    quat_b = quaternion_from_matrix(pose_b[:3, :3])

    ts = np.linspace(0, 1, steps)
    quats = [quaternion_slerp(quat_a, quat_b, t) for t in ts]
    trans = [(1 - t) * pose_a[:3, 3] + t * pose_b[:3, 3] for t in ts]

    poses_ab = []
    for quat, tran in zip(quats, trans):
        pose = np.identity(4)
        pose[:3, :3] = quaternion_matrix(quat)[:3, :3]
        pose[:3, 3] = tran
        poses_ab.append(pose)
    return poses_ab

def get_interpolated_k(k_a, k_b, steps: int = 10) -> TensorType[3, 4]:
    """
    Returns interpolated path between two camera poses with specified number of steps.

    Args:
        KA: camera matrix 1
        KB: camera matrix 2
        steps: number of steps the interpolated pose path should contain
    """
    Ks = []
    ts = np.linspace(0, 1, steps)
    for t in ts:
        new_k = k_a * (1.0 - t) + k_b * t
        Ks.append(new_k)
    return Ks

def get_interpolated_poses_many(
    poses: TensorType["num_poses", 3, 4],
    Ks: TensorType["num_poses", 3, 3],
    steps_per_transition=10,
) -> Tuple[TensorType["num_poses", 3, 4], TensorType["num_poses", 3, 3]]:
    """Return interpolated poses for many camera poses.

    Args:
        poses: list of camera poses
        Ks: list of camera intrinsics
        steps_per_transition: number of steps per transition

    Returns:
        tuple of new poses and intrinsics
    """
    traj = []
    Ks = []
    for idx in range(poses.shape[0] - 1):
        pose_a = poses[idx]
        pose_b = poses[idx + 1]
        poses_ab = get_interpolated_poses(pose_a, pose_b, steps=steps_per_transition)
        traj += poses_ab
        Ks += get_interpolated_k(Ks[idx], Ks[idx + 1], steps_per_transition)
    return torch.stack(traj, dim=0), torch.stack(Ks, dim=0)

def normalize(x) -> TensorType[...]:
    """Returns a normalized vector."""
    return x / torch.linalg.norm(x)

def viewmatrix(lookat, up, pos) -> TensorType[...]:
    """Returns a camera transformation matrix.

    Args:
        lookat: The direction the camera is looking.
        up: The upward direction of the camera.
        pos: The position of the camera.

    Returns:
        A camera transformation matrix.
    """
    vec2 = normalize(lookat)
    vec1_avg = normalize(up)
    vec0 = normalize(torch.cross(vec1_avg, vec2))
    vec1 = normalize(torch.cross(vec2, vec0))
    m = torch.stack([vec0, vec1, vec2, pos], 1)
    return m

def get_distortion_params(
    k1: float = 0.0,
    k2: float = 0.0,
    k3: float = 0.0,
    k4: float = 0.0,
    p1: float = 0.0,
    p2: float = 0.0,
) -> TensorType[...]:
    """Returns a distortion parameters matrix.

    Args:
        k1: The first radial distortion parameter.
        k2: The second radial distortion parameter.
        k3: The third radial distortion parameter.
        k4: The fourth radial distortion parameter.
        p1: The first tangential distortion parameter.
        p2: The second tangential distortion parameter.
    Returns:
        torch.Tensor: A distortion parameters matrix.
    """
    return torch.Tensor([k1, k2, k3, k4, p1, p2])

@torch.jit.script
def _compute_residual_and_jacobian(
    x: torch.Tensor,
    y: torch.Tensor,
    xd: torch.Tensor,
    yd: torch.Tensor,
    distortion_params: torch.Tensor,
) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor,]:
    """Auxiliary function of radial_and_tangential_undistort() that computes residuals and jacobians.
    Adapted from MultiNeRF:
    https://github.com/google-research/multinerf/blob/b02228160d3179300c7d499dca28cb9ca3677f32/internal/camera_utils.py#L427-L474

    Args:
        x: The updated x coordinates.
        y: The updated y coordinates.
        xd: The distorted x coordinates.
        yd: The distorted y coordinates.
        distortion_params: The distortion parameters [k1, k2, k3, k4, p1, p2].

    Returns:
        The residuals (fx, fy) and jacobians (fx_x, fx_y, fy_x, fy_y).
    """

    k1 = distortion_params[..., 0]
    k2 = distortion_params[..., 1]
    k3 = distortion_params[..., 2]
    k4 = distortion_params[..., 3]
    p1 = distortion_params[..., 4]
    p2 = distortion_params[..., 5]

    # let r(x, y) = x^2 + y^2;
    #     d(x, y) = 1 + k1 * r(x, y) + k2 * r(x, y) ^2 + k3 * r(x, y)^3 +
    #                   k4 * r(x, y)^4;
    r = x * x + y * y
    d = 1.0 + r * (k1 + r * (k2 + r * (k3 + r * k4)))

    # The perfect projection is:
    # xd = x * d(x, y) + 2 * p1 * x * y + p2 * (r(x, y) + 2 * x^2);
    # yd = y * d(x, y) + 2 * p2 * x * y + p1 * (r(x, y) + 2 * y^2);
    #
    # Let's define
    #
    # fx(x, y) = x * d(x, y) + 2 * p1 * x * y + p2 * (r(x, y) + 2 * x^2) - xd;
    # fy(x, y) = y * d(x, y) + 2 * p2 * x * y + p1 * (r(x, y) + 2 * y^2) - yd;
    #
    # We are looking for a solution that satisfies
    # fx(x, y) = fy(x, y) = 0;
    fx = d * x + 2 * p1 * x * y + p2 * (r + 2 * x * x) - xd
    fy = d * y + 2 * p2 * x * y + p1 * (r + 2 * y * y) - yd

    # Compute derivative of d over [x, y]
    d_r = k1 + r * (2.0 * k2 + r * (3.0 * k3 + r * 4.0 * k4))
    d_x = 2.0 * x * d_r
    d_y = 2.0 * y * d_r

    # Compute derivative of fx over x and y.
    fx_x = d + d_x * x + 2.0 * p1 * y + 6.0 * p2 * x
    fx_y = d_y * x + 2.0 * p1 * x + 2.0 * p2 * y

    # Compute derivative of fy over x and y.
    fy_x = d_x * y + 2.0 * p2 * y + 2.0 * p1 * x
    fy_y = d + d_y * y + 2.0 * p2 * x + 6.0 * p1 * y

    return fx, fy, fx_x, fx_y, fy_x, fy_y

@torch.jit.script
def radial_and_tangential_undistort(
    coords: torch.Tensor,
    distortion_params: torch.Tensor,
    eps: float = 1e-3,
    max_iterations: int = 10,
) -> torch.Tensor:
    """Computes undistorted coords given opencv distortion parameters.
    Addapted from MultiNeRF
    https://github.com/google-research/multinerf/blob/b02228160d3179300c7d499dca28cb9ca3677f32/internal/camera_utils.py#L477-L509

    Args:
        coords: The distorted coordinates.
        distortion_params: The distortion parameters [k1, k2, k3, k4, p1, p2].
        eps: The epsilon for the convergence.
        max_iterations: The maximum number of iterations to perform.

    Returns:
        The undistorted coordinates.
    """

    # Initialize from the distorted point.
    x = coords[..., 0]
    y = coords[..., 1]

    for _ in range(max_iterations):
        fx, fy, fx_x, fx_y, fy_x, fy_y = _compute_residual_and_jacobian(
            x=x, y=y, xd=coords[..., 0], yd=coords[..., 1], distortion_params=distortion_params
        )
        denominator = fy_x * fx_y - fx_x * fy_y
        x_numerator = fx * fy_y - fy * fx_y
        y_numerator = fy * fx_x - fx * fy_x
        step_x = torch.where(torch.abs(denominator) > eps, x_numerator / denominator, torch.zeros_like(denominator))
        step_y = torch.where(torch.abs(denominator) > eps, y_numerator / denominator, torch.zeros_like(denominator))

        x = x + step_x
        y = y + step_y

    return torch.stack([x, y], dim=-1)

def rotation_matrix(a: TensorType[3], b: TensorType[3]) -> TensorType[3, 3]:
    """Compute the rotation matrix that rotates vector a to vector b.

    Args:
        a: The vector to rotate.
        b: The vector to rotate to.
    Returns:
        The rotation matrix.
    """
    a = a / torch.linalg.norm(a)
    b = b / torch.linalg.norm(b)
    v = torch.cross(a, b)
    c = torch.dot(a, b)
    # If vectors are exactly opposite, we add a little noise to one of them
    if c < -1 + 1e-8:
        eps = (torch.rand(3) - 0.5) * 0.01
        return rotation_matrix(a + eps, b)
    s = torch.linalg.norm(v)
    skew_sym_mat = torch.Tensor(
        [
            [0, -v[2], v[1]],
            [v[2], 0, -v[0]],
            [-v[1], v[0], 0],
        ]
    )
    return torch.eye(3) + skew_sym_mat + skew_sym_mat @ skew_sym_mat * ((1 - c) / (s**2 + 1e-8))

def auto_orient_and_center_poses(
    poses: TensorType["num_poses":..., 4, 4], method: Literal["pca", "up", "none"] = "up", center_poses: bool = True
) -> TensorType["num_poses":..., 3, 4]:
    """Orients and centers the poses. We provide two methods for orientation: pca and up.

    pca: Orient the poses so that the principal component of the points is aligned with the axes.
        This method works well when all of the cameras are in the same plane.
    up: Orient the poses so that the average up vector is aligned with the z axis.
        This method works well when images are not at arbitrary angles.

    Args:
        poses: The poses to orient.
        method: The method to use for orientation.
        center_poses: If True, the poses are centered around the origin.

    Returns:
        The oriented poses.
    """

    translation = poses[..., :3, 3]

    mean_translation = torch.mean(translation, dim=0)
    translation_diff = translation - mean_translation

    if center_poses:
        translation = mean_translation
    else:
        translation = torch.zeros_like(mean_translation)

    if method == "pca":
        _, eigvec = torch.linalg.eigh(translation_diff.T @ translation_diff)
        eigvec = torch.flip(eigvec, dims=(-1,))

        if torch.linalg.det(eigvec) < 0:
            eigvec[:, 2] = -eigvec[:, 2]

        transform = torch.cat([eigvec, eigvec @ -translation[..., None]], dim=-1)
        oriented_poses = transform @ poses

        if oriented_poses.mean(axis=0)[2, 1] < 0:
            oriented_poses[:, 1:3] = -1 * oriented_poses[:, 1:3]
    elif method == "up":
        up = torch.mean(poses[:, :3, 1], dim=0)
        up = up / torch.linalg.norm(up)

        rotation = rotation_matrix(up, torch.Tensor([0, 0, 1]))
        transform = torch.cat([rotation, rotation @ -translation[..., None]], dim=-1)
        oriented_poses = transform @ poses
    elif method == "none":
        oriented_poses = poses
        poses[:, :3, 3] -= translation

    return oriented_poses

def get_rays(H, W, K, c2w):
    i, j = torch.meshgrid(
        torch.linspace(0, W - 1, 2, device=c2w.device), torch.linspace(0, H - 1, 2, device=c2w.device)
    )  # pytorch's meshgrid has indexing='ij'
    i = i.t().float()
    j = j.t().float()

    i, j = i + 0.5, j + 0.5

    dirs = torch.stack([(i - K[0][2]) / K[0][0], -(j - K[1][2]) / K[1][1], -torch.ones_like(i)], -1)
    # Rotate ray directions from camera frame to the world frame
    rays_d = torch.sum(
        dirs[..., np.newaxis, :] * c2w[:3, :3], -1
    )  # dot product, equals to: [c2w.dot(dir) for dir in dirs]
    # Translate camera frame's origin to the world frame. It is the origin of all rays.
    rays_o = c2w[:3, 3].expand(rays_d.shape)
    return rays_o, rays_d

def get_rays_of_a_view(H, W, K, c2w, mode="center"):
    rays_o, rays_d = get_rays(H, W, K, c2w)
    viewdirs = rays_d / rays_d.norm(dim=-1, keepdim=True)
    return rays_o, rays_d, viewdirs

def _compute_bbox_by_cam_frustrm_bounded(heights, widths, Ks, poses, nears, fars):
    xyz_min = torch.Tensor([np.inf, np.inf, np.inf])
    xyz_max = -xyz_min
    for H, W, K, c2w, near, far in zip(heights, widths, Ks, poses, nears, fars):
        rays_o, rays_d, viewdirs = get_rays_of_a_view(H=H, W=W, K=K, c2w=c2w)
        pts_nf = torch.stack([rays_o + viewdirs * near, rays_o + viewdirs * far])
        xyz_min = torch.minimum(xyz_min, pts_nf.amin((0, 1, 2)))
        xyz_max = torch.maximum(xyz_max, pts_nf.amax((0, 1, 2)))
    return xyz_min, xyz_max

def center_scale_poses_and_compute_frustum(poses, bbox=None):
    transform=torch.eye(4)

    scale_factor = 1
    use_bbox = False
    if bbox is not None:
        if bbox.shape[0] == 6:
            use_bbox = True

    if use_bbox:
        sampling_xyz_min = torch.tensor(bbox[:3])
        sampling_xyz_max = torch.tensor(bbox[3:])
        Cs = poses[:, :3, 3]
        Cs_min = Cs.amin((0))
        Cs_max = Cs.amax((0))
        xyz_min = torch.minimum(sampling_xyz_min, Cs_min)
        xyz_max = torch.maximum(sampling_xyz_max, Cs_max)
        translation = torch.tensor(
            [
                (sampling_xyz_min[0] + sampling_xyz_max[0]) / 2,
                (sampling_xyz_min[1] + sampling_xyz_max[1]) / 2,
                (sampling_xyz_min[2] + sampling_xyz_max[2]) / 2,
            ]
        )
        ##center
        poses[:, :3, 3] -= translation
        sampling_xyz_min -= translation
        sampling_xyz_max -= translation
        xyz_min -= translation
        xyz_max -= translation
        ## find the radius
        r1 = torch.norm(torch.tensor([sampling_xyz_min[0], sampling_xyz_min[1], sampling_xyz_min[2]]))
        r2 = torch.norm(torch.tensor([sampling_xyz_min[0], sampling_xyz_min[1], sampling_xyz_max[2]]))
        r3 = torch.norm(torch.tensor([sampling_xyz_min[0], sampling_xyz_max[1], sampling_xyz_min[2]]))
        r4 = torch.norm(torch.tensor([sampling_xyz_min[0], sampling_xyz_max[1], sampling_xyz_max[2]]))
        r5 = torch.norm(torch.tensor([sampling_xyz_max[0], sampling_xyz_min[1], sampling_xyz_min[2]]))
        r6 = torch.norm(torch.tensor([sampling_xyz_max[0], sampling_xyz_min[1], sampling_xyz_max[2]]))
        r7 = torch.norm(torch.tensor([sampling_xyz_max[0], sampling_xyz_max[1], sampling_xyz_min[2]]))
        r8 = torch.norm(torch.tensor([sampling_xyz_max[0], sampling_xyz_max[1], sampling_xyz_max[2]]))
        radius = torch.max(torch.tensor([r1, r2, r3, r4, r5, r6, r7, r8]))

        # scale = scale_factor / max(max(xyz_max[0] - xyz_min[0], xyz_max[1] - xyz_min[1]), xyz_max[2] - xyz_min[2])
        scale = scale_factor / radius
        poses[:, :3, 3] *= scale
        sampling_xyz_min *= scale
        sampling_xyz_max *= scale
        xyz_min *= scale
        xyz_max *= scale

        #compute transoform of poses from input space to nerf space
        transform[0,3]=translation[0]
        transform[1,3]=translation[1]
        transform[2,3]=translation[2]
        transform[0,0]=scale
        transform[1,1]=scale
        transform[2,2]=scale
        # bbox = np.array(bbox).astype(np.float64)
        # # center
        # translation = poses[..., :3, 3]
        # mean_translation = torch.mean(translation, dim=0)
        # translation = mean_translation
        # poses[:, :3, 3] -= translation
        # bbox[0] -= translation[0]
        # bbox[3] -= translation[0]
        # bbox[1] -= translation[1]
        # bbox[4] -= translation[1]
        # bbox[2] -= translation[2]
        # bbox[5] -= translation[2]

        # # scale by minimal near plane
        # sc = scale_factor / nears.min()
        # poses[:, :3, 3] *= sc
        # bbox *= sc.numpy()
        # sampling_xyz_min = torch.tensor(bbox[:3])
        # sampling_xyz_max = torch.tensor(bbox[3:])
        # Cs = poses[:, :3, 3]
        # Cs_min = Cs.amin((0))
        # Cs_max = Cs.amax((0))
        # xyz_min = torch.minimum(sampling_xyz_min, Cs_min)
        # xyz_max = torch.maximum(sampling_xyz_max, Cs_max)
        return xyz_min, xyz_max, sampling_xyz_min, sampling_xyz_max, poses, -translation,scale
    else:
        assert (use_bbox == False, "please give the bbox")
        # center
        # translation = poses[..., :3, 3]
        # mean_translation = torch.mean(translation, dim=0)
        # translation = mean_translation
        # poses[:, :3, 3] -= translation
        # # scale by minimal near plane
        # sc = scale_factor / nears.min()
        # poses[:, :3, 3] *= sc
        # nears *= sc
        # fars *= sc
        # ##compute frustum
        # sampling_xyz_min, sampling_xyz_max = _compute_bbox_by_cam_frustrm_bounded(
        #     heights, widths, Ks, poses, nears, fars
        # )
        # Cs = poses[:, :3, 3]
        # Cs_min = Cs.amin((0))
        # Cs_max = Cs.amax((0))
        # xyz_min = torch.minimum(sampling_xyz_min, Cs_min)
        # xyz_max = torch.maximum(sampling_xyz_max, Cs_max)
        # return xyz_min, xyz_max, sampling_xyz_min, sampling_xyz_max, poses, nears, fars

def get_rays(H, W, K, c2w, inverse_y=False, flip_x=False, flip_y=False, mode="center"):
    i, j = torch.meshgrid(
        torch.linspace(0, W - 1, W, device=c2w.device), torch.linspace(0, H - 1, H, device=c2w.device)
    )  # pytorch's meshgrid has indexing='ij'
    i = i.t().float()
    j = j.t().float()
    if mode == "lefttop":
        pass
    elif mode == "center":
        i, j = i + 0.5, j + 0.5
    elif mode == "random":
        i = i + torch.rand_like(i)
        j = j + torch.rand_like(j)
    else:
        raise NotImplementedError

    if flip_x:
        i = i.flip((1,))
    if flip_y:
        j = j.flip((0,))
    if inverse_y:
        dirs = torch.stack([(i - K[0][2]) / K[0][0], (j - K[1][2]) / K[1][1], torch.ones_like(i)], -1)
    else:
        dirs = torch.stack([(i - K[0][2]) / K[0][0], -(j - K[1][2]) / K[1][1], -torch.ones_like(i)], -1)
    # Rotate ray directions from camera frame to the world frame
    rays_d = torch.sum(
        dirs[..., np.newaxis, :] * c2w[:3, :3], -1
    )  # dot product, equals to: [c2w.dot(dir) for dir in dirs]
    # Translate camera frame's origin to the world frame. It is the origin of all rays.
    rays_o = c2w[:3, 3].expand(rays_d.shape)
    return rays_o, rays_d

def filter_images_aoi_aabb(poses, heights, widths, fxs, fys, cxs, cys, aoi_aabb):
    from nerfstudio.data.scene_box import SceneBox
    from nerfstudio.model_components.scene_colliders import AABBBoxCollider

    aoi_aabb = torch.tensor([aoi_aabb[:3], aoi_aabb[3:]])
    scene_box = SceneBox(aoi_aabb)
    collider = AABBBoxCollider(scene_box, near_plane=0, far_plane=10000)

    valid_ids = []
    for i in range(poses.shape[0]):
        pose = poses[i, :, :]
        height = heights[i]
        width = widths[i]
        fx = fxs[i]
        fy = fys[i]
        cx = cxs[i]
        cy = cys[i]
        K = np.zeros((3, 3))
        K[0, 0] = fx
        K[0, 2] = cx
        K[1, 1] = fy
        K[1, 2] = cy
        rays_o, rays_d = get_rays(height, width, K, pose)
        rays_o = rays_o.view(-1, 3)
        rays_d = rays_d.view(-1, 3)
        select_ind = torch.range(0, rays_o.shape[0] - 1, 100).type(torch.int64)
        rays_o = rays_o[select_ind, :]
        rays_d = rays_d[select_ind, :]
        nears, fars = collider._intersect_with_aabb(rays_o, rays_d, scene_box.aabb)
        diff = fars - nears
        num_valid = torch.sum(diff > 1e-5)
        valid_ratio = float(num_valid / (rays_o.shape[0]))
        if valid_ratio > 0.3:
            valid_ids.append(i)
    return valid_ids


from rest_framework import mixins, viewsets

from core.api.permissions import IsAuthenticatedOrPostOnly

from data.wbs_user.models import WbsUser

from api.users.filters import WbsUserFilter
from api.users.serializers import WbsUserSerializer, WbsUserUpdateSerializer, WbsUserProjectSerializer

class WbsUserModelViewSet(
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.CreateModelMixin,
    mixins.UpdateModelMixin,
    viewsets.GenericViewSet,
):
    """
    ### Endpoints:

    ```[GET]		/api/users/(?(username))```

        lists all users

        PARAMS:
        - username: <String>
            filter by the users username. Note that usernames are unique.

    ```[POST]		/api/users/```

        creates a new user

        POST DATA:
        {
            /** new users username */
            username: <String>,
            /** new users password */
            password: <String>
        }

    ```[GET]		/api/users/<user_id>/```

        the user with the user id `<user_id>`.

    ```[PATCH]		/api/users/<user_id>/```

        change password of the user with the user id `<user_id>`.

        POST DATA:
        {
            /** the users new password */
            password: <String>
        }

    ```[GET]		/api/users/<user_id>/projects/```

        get all projects ot the user with the user id `<user_id>`.

    ```[POST]		/api/users/<user_id>/projects/```

        add the user to an already existing project

        POST DATA:
        {
            /** URL of the project you want the user to be added to */
            project: <URL>
        }
    """
    filter_class = WbsUserFilter
    permission_classes = (IsAuthenticatedOrPostOnly,)
    queryset = WbsUser.objects.all()

    def get_serializer_class(self):
        if self.action == 'update' or self.action == 'partial_update':
            return WbsUserUpdateSerializer
        else:
            return WbsUserSerializer

class WbsUserProjectsModelViewSet(
    mixins.ListModelMixin,
    mixins.CreateModelMixin,
    viewsets.GenericViewSet,
):
    """
    ### Endpoints:

    ```[GET]		/api/users/(?(username))```

        lists all users

        PARAMS:
        - username: <String>
            filter by the users username. Note that usernames are unique.

    ```[POST]		/api/users/```

        creates a new user

        POST DATA:
        {
            /** new users username */
            username: <String>,
            /** new users password */
            password: <String>
        }

    ```[GET]		/api/users/<user_id>/```

        the user with the user id `<user_id>`.

    ```[PATCH]		/api/users/<user_id>/```

        change password of the user with the user id `<user_id>`.

        POST DATA:
        {
            /** the users new password */
            password: <String>
        }

    ```[GET]		/api/users/<user_id>/projects/```

        get all projects ot the user with the user id `<user_id>`.

    ```[POST]		/api/users/<user_id>/projects/```

        add the user to an already existing project

        POST DATA:
        {
            /** URL of the project you want the user to be added to */
            project: <URL>
        }
    """
    serializer_class = WbsUserProjectSerializer

    def get_user_from_url(self):
        """
        retrieves the WbsUser from the url

        :return: the user
        :rtype: WbsUser
        """
        return WbsUser.objects.get(pk=self.kwargs.get('user_id'))

    def get_queryset(self):
        return self.get_user_from_url().projects.all()


import xmlrpclib
import posixpath

from trac.core import *
from tracrpc.api import IXMLRPCHandler, expose_rpc

class NikoNikoRPC(Component):
    """ Interface to NikoNiko Calendar """

    implements(IXMLRPCHandler)

    def xmlrpc_namespace(self):
        return 'nikoniko'

    def xmlrpc_methods(self):
        yield ('NIKONIKO_VIEW', ((str, ),), self.getCurrentMood)
        yield ('NIKONIKO_VIEW', ((str, ),), self.getCurrentComment)

    def page_info(self, name, time, author, version, comment=''):
        return dict(name=name,
                    lastModified=xmlrpclib.DateTime(int(time)),
                    author=author,
                    version=int(version),
                    comment=(comment or '') )

    def getCurrentMood(self, req):
        todays_mood = getField(req, 'nikoniko_mood')
        if todays_mood:
            return 'okMood'
        else:
            return todays_mood

    def getCurrentComment(self, req):
        comment = getField(req, 'nikoniko_comment')
        if comment:
            return 'Ok'
        else:
            return comment

    def getField(self, req, field):
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        now = datetime.datetime.now()
        date_time = now.strftime("%d/%m/%Y");
        username = req.authname;
        getMoodSQL = "SELECT " + field + " FROM nikoniko WHERE "\
                     "nikoniko_username = '" + username + "' AND "\
                     "nikoniko_date = '" + date_time + "'"
        cursor.execute(getMoodSQL)
        row = cursor.fetchone()
        if row:
            return row[0]
        else:
            return null


N = int(input())
A = list(map(int, input().split()))
A = [0] + A

# 答え dp[N]
dp = [0] * (N + 1)
dp[0] = float('inf')  # 0本目はないので無限コスト
dp[1] = 0

for i in range(2, N + 1):
    cost1 = abs(A[i] - A[i - 1])
    cost2 = abs(A[i] - A[i - 2])
    dp[i] = min(dp[i - 1] + cost1, dp[i - 2] + cost2)
print(dp[N])


import os
import sys
from flask import Flask,request,jsonify
import functools
import json
import logging
from pymemcache.client.base import Client
#сериализатор
def json_serializer(key, value):
    if type(value) == str:
        return value, 1
    return json.dumps(value), 2
#десериализатор
def json_deserializer(key, value, flags):
   if flags == 1:
       return value.decode("utf-8")
   if flags == 2:
       return json.loads(value.decode("utf-8"))
   raise Exception("Unknown serialization format")

MEMCACHE_HOST = os.environ.get("MEMCACHE_HOST")
MEMCACHE_PORT = int(os.environ.get("MEMCACHE_PORT", 11211))
client = Client((MEMCACHE_HOST , MEMCACHE_PORT), serializer=json_serializer,
                deserializer=json_deserializer)
#client.set('key', {'a':'b', 'c':'d'})
#result = client.get('key')
#print(result)

#функция расчета чисел фибоначи
@functools.lru_cache(maxsize=128, typed=False)
def fibo_steroids(n):
    if n in [0, 1]:
        return n
    else:
        return fibo_steroids(n-1) + fibo_steroids(n-2)
sys.setrecursionlimit(30000)

app = Flask(__name__)
port = int(os.environ.get("PORT", 5000))
@app.route('/')
def hello_world():
    return 'Программа расчета чисел Фибоначи'

@app.route("/<number>", methods=['GET'])
def get_fibonacci_api(number):
    number = int(number)
    result = client.get('{}'.format(number))
    if result:
       logging.info("For %s stored value is used" % number)
       return jsonify(number=result)
    f_number = fibo_steroids(number)
    logging.info("For %s new value is calculated" % number)
    client.set('{}'.format(number),'{}'.format(f_number))
    return jsonify(number=f_number)

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=port)


# decorator example

def my_double_args(func):
    def multiply_args_by_two(*args):
        func(args[0] * 2, args[1] * 2)
    return multiply_args_by_two

@my_double_args
def my_mult(x, y):
    print(x * y)
    return x * y

import base64
from itertools import cycle

def decrypt(encrypted_message, encryption_key):
    base64_decoded              = base64.b64decode(encrypted_message)
    decrypted_message           = [''] * len(base64_decoded)
    encryption_key_iterator     = cycle(encryption_key)
    for i, c in enumerate(base64_decoded):
        decrypted_message[i] += chr(ord(c) ^ ord(encryption_key_iterator.next()))
    return ''.join(decrypted_message)

if __name__ == '__main__':
    # encryption_key = 'chukwuemeka'
    # encrypted_message = 'HkoWHgJNCBweSERPRUoCGQRPGUhBT0MWCgEJDgBJGApKT15VQggWHwRLAAoJSEhVQggDDQ5cGRxK T15VQgQLCBNLCQYPAwFSSU1CCgJGBAobCgkQCxlCS1sOShoDAwsWDggBTE0OSh0MDQYcER5CS1sO ShwMCQFSSU1CDQ5BSk9XT0MCDANETBw='
    #
    # decrypted_message = decrypt(encrypted_message, encryption_key)
    # print(decrypted_message)

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

    import base64

    MESSAGE = '''
    HkoWHgJNCBweSERPRUoCGQRPGUhBT0MWCgEJDgBJGApKT15VQggWHwRLAAoJSEhVQggDDQ5cGRxK T15VQgQLCBNLCQYPAwFSSU1CCgJGBAobCgkQCxlCS1sOShoDAwsWDggBTE0OSh0MDQYcER5CS1sO ShwMCQFSSU1CDQ5BSk9XT0MCDANETBw=
    '''

    KEY = 'emeka.momodu'

    result = []
    for i, c in enumerate(base64.b64decode(MESSAGE)):
        result.append(chr(ord(c) ^ ord(KEY[i % len(KEY)])))

    print
    ''.join(result)

    # my_mult(1, 1)


import codecs
import datetime
import pickle
import re

from pymongo import MongoClient
from jira_service import FixVersionModel, JiraService
from config import MONGO_DB_NAME
from release_task import ReleaseTaskModel

class MongoService:
    FIX_VERSIONS_COLLECTION = 'fix_versions'
    RELEASE_TASKS_COLLECTION = 'release_tasks'

    def __init__(self):
        self.client = MongoClient('mongodb://root:example@127.0.0.1:27017/')

    def save_fix_versions(self, versions: list[FixVersionModel]):
        fv_collection = self.client[MONGO_DB_NAME][self.FIX_VERSIONS_COLLECTION]
        fv_collection.insert_many(
            [{'data': version.pickle(), 'version_id': version.id} for version in versions]
        )

    def read_fix_version_by_version_id(self, version_id) -> FixVersionModel:
        version_id = f'{version_id}'
        versions = [version for version in self.read_fix_versions() if version.id == version_id]
        if len(versions) > 0:
            return versions[0]
        else:
            return None

    def read_fix_versions(self):
        fv_collection = self.client[MONGO_DB_NAME][self.FIX_VERSIONS_COLLECTION]
        versions_pickled = [ver for ver in fv_collection.find()]
        return [pickle.loads(codecs.decode(pickled['data'].encode(), "base64")) for pickled in versions_pickled]

    def clear_versions(self):  # clear fix versions in mongo and return num of deleted rows
        return self.client[MONGO_DB_NAME][self.FIX_VERSIONS_COLLECTION].delete_many({}).deleted_count

    def read_release_tasks(self):
        rt_collection = self.client[MONGO_DB_NAME][self.RELEASE_TASKS_COLLECTION]
        rtasks_pickled = [task for task in rt_collection.find()]
        release_tasks = []
        for pickled_task in rtasks_pickled:
            rtask = pickle.loads(codecs.decode(pickled_task['data'].encode(), "base64"))
            release_tasks.append(rtask)
        return release_tasks

    def read_release_task_by_version_id(self, version_id) -> ReleaseTaskModel:
        version_id = f'{version_id}'
        versions = [task for task in self.read_release_tasks() if task.fix_version.id == version_id]
        if len(versions) > 0:
            return versions[0]
        else:
            return None

    def save_release_task(self, release_task_model: ReleaseTaskModel):
        rt_collection = self.client[MONGO_DB_NAME][self.RELEASE_TASKS_COLLECTION]
        rt_collection.insert_one({'data': release_task_model.pickle(), 'release_version_id': release_task_model.fix_version.id})

    def update_release_task(self, release_task_model):
        rt_collection = self.client[MONGO_DB_NAME][self.RELEASE_TASKS_COLLECTION]
        rt_collection.update_one(filter={'release_version_id': release_task_model.fix_version.id},
                                 update={'$set':{'data': release_task_model.pickle(),
                                         'release_version_id': release_task_model.fix_version.id}})

    def clear_tasks(self):  # clear fix versions in mongo and return num of deleted rows
        return self.client[MONGO_DB_NAME][self.RELEASE_TASKS_COLLECTION].delete_many({}).deleted_count

if __name__ == '__main__':
    # MongoService().clear_tasks()
    pass


from flask_restful import Resource, reqparse

from App.apis.UserApi import cache
from App.models import User, db

parser = reqparse.RequestParser()

parser.add_argument('u_icon',type=str)

class AccountResource(Resource):
    #需求  要修改当前数据的active状态
    #方案：通过token获取active 然后修改状态
    def get(self):
        parse = parser.parse_args()
        #获取了参数为token的值
        token = parse.get('u_icon')
        print('-------------------------')
        id = cache.get(token)
        print(id)
        if id:
        # 注意此时users是一个basequery类型的对象 那么获取basequery中的对象的方法是first（）
            users = User.query.filter(User.id.__eq__(id))
            if users.count() > 0:
                user = users.first()
                user.active = True
                db.session.add(user)
                db.session.commit()
                return {'msg': 'i am accoutn'}
        else:
            return {'msg':'i am not account'}


#!/usr/bin/env python3

from math import factorial
from math import log
from math import sqrt

second = 1e6
minute = second * 60
hour = minute * 60
day = hour * 24
month = day * 30
year = month * 12
century = year * 100

timings = {
    "second": second,
    "minute": minute,
    "hour": hour,
    "day": day,
    "month": month,
    "year": year,
    "century": century,
}

orders = {
    "lg n": lambda n: log(n, 10),
    "√n": lambda n: sqrt(int(n)),
    "n": lambda n: n,
    "n lg n": lambda n: n * log(n, 10),
    "n²": lambda n: n**2,
    "n³": lambda n: n**3,
    "2^n": lambda n: 2**n,
    "n!": lambda n: factorial(int(n)),
}

if __name__ == "__main__":
    for order, fn in orders.items():
        for timing, ms in timings.items():
            i, n = 0, 10
            while True:
                if fn(n) < ms:
                    i = n
                    n = n * 1.001
                else:
                    print(f"{order} {timing}: n={i:.3e}")
                    break


import os

def check_folder(path, required_files):
    """
    Checks if 'path' already exists as a folder and, if so, what's in it. If 'path' does not already exists,
    it gets created as an empty folder.
    BEHAVIOR:
        - If 'path' does not already exists: Creates 'path' as an empty folder and then returns False.
        - If 'path' already exists but not as a folder: Throws OSError.
        - If 'path' already exists as a folder which is empty: Returns False.
        - If 'path' already exists as a folder which is not empty but does not contain all required files:
          Throws OSError.
        - If 'path' already exists as a folder which contains all files in 'required_files': Returns True.
    """
    if not os.path.exists(path):
        os.makedirs(path)
        return False

    if not os.path.isdir(path):
        raise OSError("Given folder path already exists but is not a directory.")

    if not os.listdir(path): # Path is empty
        return False

    if not all(file in os.listdir(path) for file in required_files):
        raise OSError("Given folder already exists, but does not contain all necessarry files and is not empty.")

    return True


import runner
import traceback

dt = 1e-4
effective_rate = 0.01
subsample = int(effective_rate / dt)
if subsample is 0:
    subsample = 1

runner.run_simulation(json_file_name="replicate_neuman.json",
        json_dir = 'params',
        run_name = "traveling_wave_tests",
        # Simulation parameters here
        model_modifications = {
            'stimulus': {
                'name': 'square_pulse',
                'args': {
                    'duration': 1,
                    'strength': 2,
                    'width': 1
                    }
                },
            "w": [[16.0, -18.2],
                [27.0, -4.0]],
            "nonlinearity": {
                "name": "sigmoid_norm_rectify",
                "args": {
                    "a": [1.2, 1.0],
                    "theta": [2.6, 8.0]
                    }
            },
            'noiseless': True,
            'lattice': {
                'space_extent': 200.5, 'space_step': 0.5,
                'time_extent': 2, 'time_step': dt,
                'n_populations': 2, 'population_names': ['E', 'I']
                },
            'solver': {
                "name": "ode45"
                }
            },
        # Post-simulation parameters here
        results_params = {
            'analyses_dct': {
                    "e_i": {}
                },
            'figure_params': {
                "show": False,
                'movie_params': {
                    "show": False,
                    "subsample": subsample
                    }
                }
            }
    )


# from threading import Timer
#
# def task(name):
#     print('hello %s' %name)
#
#
# t=Timer(5,task,args=('egon',))
# t.start()

from threading import Timer
import random

class Code:
    def __init__(self):
        self.make_cache()

    def make_cache(self,interval=5):
        self.cache=self.make_code()
        print(self.cache)
        self.t=Timer(interval,self.make_cache)
        self.t.start()

    def make_code(self,n=4):
        res=''
        for i in range(n):
            s1=str(random.randint(0,9))
            s2=chr(random.randint(65,90))
            res+=random.choice([s1,s2])
        return res

    def check(self):
        while True:
            code=input('请输入你的验证码>>: ').strip()
            if code.upper() == self.cache:
                print('验证码输入正确')
                self.t.cancel()
                break

obj=Code()
obj.check()

4mysql/网络编程进阶&数据库开发/第四模块课件/01网络编程进阶/02 多线程/10 定时器.py


from django.urls import path
from . import views
urlpatterns = [
    path('', views.index, name='home'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('log_in/', views.log_in, name='log_in'),
    path('log_out/', views.log_out, name='log_out'),
    path('pasta_listing/', views.pasta, name='pasta'),
    path('cart/', views.showcart, name='showcart'),
    path('cart/delete/<int:item>/', views.delete_item, name='delete_item'),
    path('cart/delete/<int:item>/yes/', views.delete_confirm, name='delete_confirm'),
    path('checkout/', views.checkout_view, name='checkout_view'),
    path('added_to_cart/<int:pro>/', views.addtocart, name='addtocart'),
    path('order_placed/', views.order_placed, name='order_placed'),
    path('reviews/', views.review, name='review'),
    path('add_review/', views.add_review, name='add_review'),
]


# PWM Control Example
#
# This example shows how to do PWM with your OpenMV Cam.
#
# WARNING: PWM control is... not easy with MicroPython. You have to use
# the correct timer with the correct pins and channels. As for what the
# correct values are - who knows. If you need to change the pins from the
# example below please try out different timer/channel/pin configs.

import pyb, time

t2 = pyb.Timer(1, freq=1000)

ch1 = t2.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P0"))
ch2 = t2.channel(3, pyb.Timer.PWM, pin=pyb.Pin("P1"))

while(True):
    for i in range(100):
        ch1.pulse_width_percent(i)
        ch2.pulse_width_percent(100-i)
        time.sleep(5)
    for i in range(100):
        ch1.pulse_width_percent(100-i)
        ch2.pulse_width_percent(i)
        time.sleep(5)


def removeParteDiamante(linha, posicao):
    tamanho = len(linha) - 1
    linhaAux = [''] * tamanho
    for i in range(tamanho, 0, -1):
        if i != posicao:
            linhaAux[tamanho - i] = linha[i]

    tamanho = len(linhaAux)
    linha = [''] * (tamanho)
    for j in range(tamanho - 1, -1, -1):
        linha[tamanho - 1 - j] = linhaAux[j]

    return linha

def procuraDiamante():
    global linha
    global menor
    global diamante

    for j in range(0, len(linha)):
        if linha[j] == "<":
            linha = removeParteDiamante(linha, j)
            menor += 1
            return True
        elif linha[j] == ">" and menor > 0:
            linha = removeParteDiamante(linha, j)
            diamante += 1
            menor -= 1
            return True
    return False

quantidade = int(input())

for i in range(quantidade):
    linha = list(input())
    diamante = 0
    menor = 0

    while True:
        if procuraDiamante() == False:
            print(diamante)
            break


import os
from keras.callbacks import CSVLogger
from keras.preprocessing.image import ImageDataGenerator
from keras.models import load_model

def getTrain(arrayTrainX, arrayTrainY, arrayValidX, arrayValidY, DataGenerator, strProjectFolder, strOutputPath):

    intEpochs = 100
    intBatchSize = 128
    floatZoomRange = 0.2

    model = load_model(os.path.join(strProjectFolder, strOutputPath + "model.h5"))

    callbacks = []
    csvLogger = CSVLogger(os.path.join(strProjectFolder, strOutputPath + "log.csv"), separator=",", append=False)
    callbacks.append(csvLogger)

    if DataGenerator:
        genTrain = ImageDataGenerator(rotation_range=25,
                                       width_shift_range=0.1,
                                       height_shift_range=0.1,
                                       shear_range=0.1, # 水平或垂直投影變換
                                       zoom_range=[1-floatZoomRange, 1+floatZoomRange], # 按比例隨機縮放圖像尺寸
                                       horizontal_flip=True)
        genTrain.fit(arrayTrainX)
        model.fit_generator(genTrain.flow(arrayTrainX, arrayTrainY, batch_size=intBatchSize),
                            steps_per_epoch=3*arrayTrainX.shape[0]//intBatchSize, # 每次 batch 所要提取的sample數目為多少
                            verbose=2,
                            epochs=intEpochs, validation_data=(arrayValidX, arrayValidY), callbacks=callbacks, shuffle=True)
    else:
        model.fit(arrayTrainX, arrayTrainY, epochs=intEpochs, batch_size=intBatchSize, verbose=2, validation_data=(arrayValidX, arrayValidY), callbacks=callbacks, shuffle=True)

    model.save(os.path.join(strProjectFolder, strOutputPath + "model.h5"))


"""

Use Newton's Method
Atm it doesn't work for n=1 i think.
Because of Jacobian matrix, maybe.

Dan Krog
"""

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib import pyplot
import numpy as np
import UserInput

class funcs:
	"""
	A class containing the functions/equations, derivatives and parameters.
	Perhaps superfluous, could just have seperate functions.

	"""

	#Number of iterations. Should change to a while loop and break from some convergence measure.
	nt = 40

	#Stepping for static gradient, the same step used for all variables
	dx = 0.001

	#increments for each functon/equation added, or updates once if all equations are added at once
	nequations = 0

	flist = np.array([])

	#def __init__(self,fu,listofdf):

	def __init__(self, listoffunctions):
		"""
		A whole list of functions is initialized at once.
		You can also add one function at a time though, so it's flexible that way.
		"""
		#Number of equations
		funcs.nequations += len(listoffunctions)

		#Adding functions, we add to funcs.flist
		#Maybe, funcs.flist shouldn't be a numpy array, actually?
		#Numpy arrays are probably only faster if we do math on the items themselves.
		#In this case, we just call each element, because it's a function, not a number...
		#So, standard python list is probably faster?
		funcs.flist = np.append(funcs.flist, listoffunctions)

	def gradientf(f,x, xold = 0):
		"""
		Gradient of an n dim function, df/dx. Static gradient, constant stepping of variables, dx.
		"""
		xes1 = np.array([])
		for i in range(funcs.nequations):
			xes1 = np.append(xes1,x)

		xes1 = np.reshape(xes1, (funcs.nequations,funcs.nequations))
		for i in range(funcs.nequations):
			xes1[i,i] += funcs.dx

		dfvec = np.array([])
		for i in range(funcs.nequations):
			dfvec = np.append(dfvec, (f(xes1[i])-f(x))/funcs.dx)
		return dfvec

	def df(f,x,xold):
		"""
		Gradient of an n dim function, df/dx. Dynamic stepping of variables based on dx = x-xold

		Returns a list?

		"""

		#xes = np.array([[] for i in range(3)])
		# xes = np.array([])

		# x1 = [x[0]+dx,x[1]   ,x[2]   ]
		# x2 = [x[0]   ,x[1]+dx,x[2]   ]
		# x3 = [x[0]   ,x[1]   ,x[2]+dx]

		# d1fv = (f(x1)-f(x))/dx
		# d2fv = (f(x2)-f(x))/dx
		# d3fv = (f(x3)-f(x))/dx

		#dfvec = np.array([d1fv,d2fv,d3fv])
		#funcs.dfveclist = np.append(funcs.dfveclist, dfvec)

		dxvec = (x-xold)#np.absolute()

		#Huh? Her laver jeg jo bare en copy af x, basically?
		#Så altså jeg kan vel bare sige xes = x.copy() right?
		xes = np.array([])
		for i in range(funcs.nequations):
			xes = np.append(xes,x)

		xes = np.reshape(xes, (funcs.nequations,funcs.nequations))
		for i in range(funcs.nequations):
			xes[i,i] += dxvec[i]

		#Here, we can probably remove the append way, like i did for Jacobian
		dfvec = np.array([])
		for i in range(funcs.nequations):

			dfvec = np.append(dfvec, (f(xes[i])-f(xold))/dxvec[i])

		return dfvec

		#Doesnt look good:
		#dfvec, (f(xes1[i])-f(x))/dxvec[i]
		#dxvec = (x-xold)

		#Looks MAYBE good
		#dfvec, (f(xes1[i])-f(xold))/dxvec[i]
		#dxvec = (x-xold)

		#Det kan også være man kan lave en slags backwards step, så
		#f(x)-f(x-dx) / dx

	def ReshapeToJacobian(listofdfunc):
		return np.reshape(listofdfunc, (funcs.nequations,funcs.nequations))

#Really should also pass the guess to this class.
#Should make this as a call from a function, if possible, since then this script can be converted to a module.
# funcs([
		# lambda x: x[0]**2+x[1]**2-4+2*x[0]*x[1],
		# lambda x: 3*x[1]+x[0],
		# lambda x: 3*x[2]**2+2*x[1]*x[0]
		# ])

# #Guess arrays
# xold = np.zeros(funcs.nequations)+2
# x = np.zeros(funcs.nequations)+10 #np.zeros(funcs.nequations)+3
# xnew = np.zeros(funcs.nequations)

print("List of functions in class")
print(funcs.flist)

#I want this to be a function, actually
#We iterate the guesses using Newtons method, with Jacobi ,matrix
def NewtonMethod(xold,x,xnew):
	for n in range(funcs.nt-1):

		#This could also be called in the class
		#Jacobian = np.array([])
		#for i in range(funcs.nequations):

			#To uzywa static gradient
			#Jacobian = np.append(Jacobian, funcs.gradientf(funcs.flist[i],x,xold))

			#To uzywa dynamic gradient
			#dflist = funcs.df(funcs.flist[i],x,xold)
			#print(len(dflist))
			#Jacobian = np.append(Jacobian, dflist)

		#Jacobian = np.reshape(Jacobian, (funcs.nequations,funcs.nequations))

		#Kan man gøre det uden Numpy append?
		#Jacobian = np.zeros(funcs.nequations*funcs.nequations)

		#for i in range(funcs.nequations):
		#	Jacobian[i*funcs.nequations:(i+1)*funcs.nequations] = funcs.df(funcs.flist[i],x,xold)

		#Jacobian = np.reshape(Jacobian, (funcs.nequations,funcs.nequations))

		#Kan man gøre det uden reshape? YEs!
		Jacobian = np.zeros((funcs.nequations,funcs.nequations))

		for i in range(funcs.nequations):
			Jacobian[i,:] = funcs.df(funcs.flist[i],x,xold)

		#Need to iterate this system of LINEAR equations myself. Non sparse matrix. Non diagonal.
		Jinv = np.linalg.inv(Jacobian)

		fvec = np.zeros(funcs.nequations)
		for i in range(funcs.nequations):

			fvec[i] = funcs.flist[i](x)
		#fvec[:] = funcs.flist[:](x)

		#Newtons Method here
		xnew = x-np.dot(Jinv,fvec) #Før var det x-np.dot(np.array(Jinv)*fvec), men Jinv er vel allerede np array?
		#xnew = x-Jinv*fvec

		xold = x
		x = xnew

	PrintSolution(x)

def PrintSolution(x):
	print('Final iterated point, THE SOLUTION')
	print(x)

	print('Functions at the iterated point')

	n = 0
	for f in funcs.flist:
		print("f{} = {}".format(n,f(x)))
		n+=1

if __name__=="__main__":

	#Here i import functions
	#funcs([imported.list])
	#funcs([
	#	lambda x: x[0]**2+x[1]**2-4+2*x[0]*x[1],
	#	lambda x: 3*x[1]+x[0],
	#	lambda x: 3*x[2]**2+2*x[1]*x[0]
	#	])

	funcs(UserInput.ListOfFunctions)
	#Here i make guesses for newtons method
	#Guess arrays
	#Actually, xold need to be guessed, but, x doesn't need to be guessed?
	#Or maybe it does, because we use numerical derivatives... dunno
	xold = np.zeros(funcs.nequations)+2
	x = np.zeros(funcs.nequations)+10 #np.zeros(funcs.nequations)+3
	xnew = np.zeros(funcs.nequations)

	print("Initial guess")
	print(xold)

	# funcs([
	# lambda x: x[0]*x[1] + 3*x[0] - 20,
	# lambda x: x[0]*x[0]-10+4*x[1]
	# ])
	# xold = np.zeros(funcs.nequations)+2
	# x = np.zeros(funcs.nequations)+9 #np.zeros(funcs.nequations)+3
	# xnew = np.zeros(funcs.nequations)

	NewtonMethod(xold,x,xnew)

	#iterated point
	#PrintSolution(x)

	#function evaluated
	#print('Functions at the iterated point')

	#n = 0
	#for f in funcs.flist:
	#	print("f{} = {}".format(n,f(x)))
	#n+=1


# Django
from django.core.handlers.wsgi import WSGIRequest
from django.http.response import HttpResponse

# Python
from typing import Callable

class SecureMiddleware:
    """
    Middleware для обеспечения безопасности.

    Устанавливает заголовки безопасности, такие как X-Frame-Options и X-Content-Type-Options.
    Также управляет установкой и удалением httponly cookie с токеном обновления (refresh_token).

    Attributes:
        LOGIN_REFERER (str): Ссылка для проверки Referer при логине.
        LOGOUT_REFERER (str): Ссылка для проверки Referer при логауте.

    Methods:
        __init__(self, get_response: Callable): Конструктор middleware.

        set_refresh_token_cookie(self, response: HttpResponse, token: str):
        -> Устанавливает httponly cookie с токеном обновления.

        def delete_refresh_token_cookie(self, response: HttpResponse):
        -> Удаляет токен обновления при выходе пользователя с аккаунта.

        __call__(self, request: WSGIRequest) -> HttpResponse: Обработчик middleware.
    """

    # Ссылки для проверки Referer
    LOGIN_REFERER = 'http://127.0.0.1:8000/login/'
    LOGOUT_REFERER = 'http://127.0.0.1:8000/logout/'

    def __init__(self, get_response: Callable) -> None:
        self.get_response = get_response

    def set_refresh_token_cookie(self, response: HttpResponse, token: str) -> None:
        # Параметры для установки cookie
        params = {
            'httponly': True,
            'samesite': 'Strict',
            'path': '/'
        }

        # Определение срока действия токена
        expiration = 60 * 60 * 24 * 7  # 1 неделя
        expiration -= 60  # Вычесть одну минуту на всякий случай
        params['max_age'] = expiration

        # Установка cookie refresh_token
        response.set_cookie('refresh_token', token, **params)

    def delete_refresh_token_cookie(self, response: HttpResponse) -> None:
        """
        Удаление куки refresh_token из response.
        """
        # Параметры для удаления cookie
        params = {
            'path': '/',
        }

        # Удаление cookie refresh_token
        response.delete_cookie('refresh_token', **params)

    def __call__(self, request: WSGIRequest) -> HttpResponse:
        response = self.get_response(request)

        # Установка заголовков для защиты от XSS
        response['X-Frame-Options'] = 'SAMEORIGIN'
        response['X-Content-Type-Options'] = 'nosniff'

        # Установка httponly cookie refresh_token
        if request.META.get('HTTP_REFERER') == self.LOGIN_REFERER:
            # Если есть данные и ответ успешен (статус код 2xx)
            if hasattr(response, 'data') and 200 <= response.status_code < 300:
                refresh_token = response.data.get('refresh')
                # Если токен успешно получен
                if refresh_token:
                    self.set_refresh_token_cookie(response, refresh_token)

        # Удаление refresh_token из cookie
        elif request.META.get('HTTP_REFERER') == self.LOGOUT_REFERER:
            # Если есть данные и ответ успешен (статус код 200)
            if hasattr(response, 'data') and response.status_code == 200:
                self.delete_refresh_token_cookie(response)

        return response


"""
Swap every left node with right node.
"""

def swapLeftRight(node):
    node.left, node.right = node.right, node.left

# O(n) time O(d) space
def invertBinaryTree(tree):
    swapLeftRight(tree)
    if tree.left is not None:
        invertBinaryTree(tree.left)
    if tree.right is not None:
        invertBinaryTree(tree.right)

# O(n) time O(n) space
def invertBinaryTreeBreadthFirst(tree):
    queue = [tree]
    while queue:
        current = queue.pop(0)
        swapLeftRight(current)
        invertBinaryTreeBreadthFirst(current.left) if current.left is not None else None
        invertBinaryTreeBreadthFirst(current.right) if current.right is not None else None

# This is the class of the input binary tree.
class BinaryTree:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

import unittest

class BinaryTree:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

    def __eq__(self, other):
        return isinstance(other, type(self)) and self.__dict__ == other.__dict__

    def insert(self, values, i=0):
        if i >= len(values):
            return
        queue = [self]
        while len(queue) > 0:
            current = queue.pop(0)
            if current.left is None:
                current.left = BinaryTree(values[i])
                break
            queue.append(current.left)
            if current.right is None:
                current.right = BinaryTree(values[i])
                break
            queue.append(current.right)
        self.insert(values, i + 1)
        return self

    def invertedInsert(self, values, i=0):
        if i >= len(values):
            return
        queue = [self]
        while len(queue) > 0:
            current = queue.pop(0)
            if current.right is None:
                current.right = BinaryTree(values[i])
                break
            queue.append(current.right)
            if current.left is None:
                current.left = BinaryTree(values[i])
                break
            queue.append(current.left)
        self.invertedInsert(values, i + 1)
        return self

class TestProgram(unittest.TestCase):
    def test_case_1(self):
        tree = BinaryTree(1).insert([2, 3, 4, 5, 6, 7, 8, 9])
        invertedTree = BinaryTree(1).invertedInsert([2, 3, 4, 5, 6, 7, 8, 9])
        invertBinaryTree(tree)
        self.assertTrue(tree.__eq__(invertedTree))
        invertBinaryTreeBreadthFirst(tree)
        self.assertTrue(tree.__eq__(invertedTree))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 10 17:19:09 2019

@author: ashrey
"""

import torch
import torch.nn as nn
import torchvision
import os
import torchvision.transforms as transforms
import copy

'''
mnist

'''
trans = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])

#path = os.getcwd()+'/mnist/'
train = torchvision.datasets.MNIST(root = './mnist',download=True,transform=trans)
#test = torchvision.datasets.MNIST(root='./mnist',train=False,download=True)
#print(len(test), len(train),' length of test and train')

n_epochs = 3
batch_size_train = 1
batch_size_test = 1
learning_rate = 0.01
momentum = 0.5
log_interval = 10

#random_seed = 1
torch.backends.cudnn.enabled = False
#torch.manual_seed(random_seed)

#a,b = torch.utils.data.random_split(train, [10,len(train)-10])

data_loader_train = torch.utils.data.DataLoader(train,
                                                batch_size=1,
                                                shuffle=True )

'''
to show/display the image

image,target = train[0]
image.show()
'''

'''
for cifar10
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
'''

''' for mnist
trans = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (1.0,))])'''

''' standardisation of mnist, mean = 0 and variance = 1
train_loader = torch.utils.data.DataLoader(
  torchvision.datasets.MNIST('/files/', train=True, download=True,
                             transform=torchvision.transforms.Compose([
                               torchvision.transforms.ToTensor(),
                               torchvision.transforms.Normalize(
                                 (0.1307,), (0.3081,))
                             ])),
  batch_size=batch_size_train, shuffle=True)
'''

'''
for i,data in enumerate(data_loader_train,0):
    inputs,labels = data
    print(inputs.shape,labels.shape)
    break
'''
batch_Size = 64

def data_load(data='train'):
    #trainsize = 200
    #testsize = 40

    if data == 'test':
        samples = torchvision.datasets.CIFAR10(root = './mnist',train=False,download=True,transform=trans)
        size = 64
        a,_ = torch.utils.data.random_split(samples, [size,len(samples)-size])

    else:
        samples = torchvision.datasets.CIFAR10(root = './mnist',train=True,download=True,transform=trans)
        size = 1024
        a,_ = torch.utils.data.random_split(samples,[size,len(samples)-size])

    data_loader = torch.utils.data.DataLoader(a,
                                              batch_size=batch_Size,
                                              shuffle=True )
    return data_loader

def f(): raise Exception("Found exit()")

train = data_load()
for a,b in train:
    #print(a,b)
    print(a.shape,b.shape)
    f()
    #exit()
print(train.shape,'train shape')
f()
rnn = Model([28,10,10],0.01)
fx = rnn.evaluate_proposal(train)


from flask import Flask
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy

login_manager = LoginManager()
db = SQLAlchemy()

def create_app(settings_module):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_object(settings_module)
    if app.config.get('TESTING', False):
        app.config.from_pyfile('config-testing.py', silent=True)
    else:
        app.config.from_pyfile('config.py', silent=True)

    app.config['SECRET_KEY'] = '7110c8ae51a4b5af97be6534caef90e4bb9bdcb3380af008f90b23a5d1616bf319bc298105da20fe'
    app.config['SQLALCHEMY_DATABASE_URI']='sqlite:///database.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    login_manager.init_app(app)
    login_manager.login_view = "login"

    db.init_app(app)

    #registro de los blueprinst

    from .auth import auth_bp
    app.register_blueprint(auth_bp)

    from .admin import admin_bp
    app.register_blueprint(admin_bp)

    from .public import public_bp
    app.register_blueprint(public_bp)

    return app


import torch
import torch.nn as nn
import torch.nn.functional as F

class DecoderAttention(nn.Module):
    def __init__(self, hidden_size, weighted=False):
        super(DecoderAttention, self).__init__()
        self.weighted = weighted
        self.hidden_size = hidden_size
        if self.weighted:
            self.attn_weight = nn.Linear(hidden_size, hidden_size, bias=False)
        self.linear_output = nn.Linear(2 * hidden_size, hidden_size)

    def forward(self, decoder_out, encoder_out):
        # decoder_out BxOxH
        # encoder_out BxIxH
        B, _, H = decoder_out.shape
        assert H == self.hidden_size, "Size mismatch"

        output = decoder_out

        if self.weighted:
            output = self.attn_weight(output)

        attn = torch.bmm(output, encoder_out.transpose(1, 2))   # OxH x HxI
        attn = F.softmax(attn, dim=2)

        context = torch.bmm(attn, encoder_out)
        combined = torch.cat((context, output), dim=2)
        output = torch.tanh(
            self.linear_output(combined)
        )

        return output, attn


def problem_1289():
    global result

    for i in range(len(arr)):

        # * 만약 i번째 위치가 서로 다르면 바꿔준다.
        if arr[i] != arr2[i]:
            result += 1
            change = arr[i]

            # * i ~ 배열길이 만큼 바꿔줌
            for j in range(i, len(arr)):
                arr2[j] = change

for tnt in range(1, int(input()) +1):
    arr = list(input())
    arr2 = ['0'] * len(arr)
    result = 0
    problem_1289()
    print(f'#{tnt} {result}')

SSAFY 대비 스터디/SSAFY 코테대비(Vscode)/SSAFY 코테스터디/3일차/1289.py


import json
from datetime import datetime
from uuid import UUID
from decimal import Decimal
from inspect import isgenerator

from flask import Response, request

class JSONEncoder(json.JSONEncoder):
    """ This encoder will serialize all entities that have a to_dict
    method by calling that method and serializing the result. """

    def __init__(self, index=False):
        self.index = index
        super(JSONEncoder, self).__init__()

    def default(self, obj):
        if self.index and hasattr(obj, 'to_dict_index'):
            return obj.to_dict_index()
        if hasattr(obj, 'to_dict'):
            return obj.to_dict()
        if isinstance(obj, datetime):
            return obj.isoformat() + 'Z'
        if isinstance(obj, UUID):
            return str(obj)
        if isinstance(obj, Decimal):
            return float(obj)
        if isgenerator(obj):
            return [o for o in obj]
        return json.JSONEncoder.default(self, obj)

def jsonify(obj, status=200, headers=None, index=False, encoder=JSONEncoder):
    """ Custom JSONificaton to support obj.to_dict protocol. """
    if encoder is JSONEncoder:
        data = encoder(index=index).encode(obj)
    else:
        data = encoder().encode(obj)
    if 'callback' in request.args:
        cb = request.args.get('callback')
        data = '%s && %s(%s)' % (cb, cb, data)
    return Response(data, headers=headers,
                    status=status,
                    mimetype='application/json')


class GiveawayMessage:
    def __init__(self):
        self.platform = None
        self.title = None
        self.description = None
        self.price = None
        self.image = None
        self.link = None

def parse_template(template: str, msg: GiveawayMessage) -> str:
    with open(template, "r", encoding="utf-8") as f:
        content = f.read()
    return content \
        .replace("{BOLDON}", "") \
        .replace("{BOLDOFF}", "") \
        .replace("{SOURCE}", str(msg.platform)) \
        .replace("{TITLE}", str(msg.title)) \
        .replace("{DESCRIPTION}", str(msg.description)) \
        .replace("{PRICE}", str(msg.price)) \
        .replace("{LINK}", " " + str(msg.link) + "" if msg.link is not None else "") \
        .replace("{IMAGE}", "" if msg.image is not None else "")


"""
SystemLab-Design 20.01.r1
Configuration file
Version: 1.0 (27-Feb-2019)
Version: 2.0 (25_Oct-2019)
"""
import os
import sys # MV 20.01.r2.custom 27-May-20

from PyQt5 import QtGui # MV 20.01.r2.custom 27-May-20

#test = os.getcwd()
#root_path = os.path.dirname(__file__)
root_path = os.getcwd()
sys.path.insert(0, root_path) # MV 20.01.r2.custom 27-May-20

app = None #Used for app.processEvents (called with main application & fb scripts)
status = None #Info/Status box (called with main application & fb scripts)
text_source = ''

'''Simulator default settings=============================================================
'''
sampling_rate_default = 1.00E+11 #Hz
sample_period_default = 1.00E-11 #sec
simulation_time_default = 1.00E-08 #sec
num_samples_default = 1.000E+03 #samples number: n

'''Simulator global initializations (flags/windows)=======================================
The simulation status GUI instance 'sim_status_win' is shared between the main
application and the script modules used for each functional block calculation
'''
sim_status_win = None # Simulation status panel (global instance)
sim_status_win_enabled = True # When True, status window is active
sim_data_view = None # Data viewer panel (global instance)
sim_data_activate = False # When True, data window will be displayed/active
sim_graph_view = None # Graph viewer (global instance) MV 20.01.r2 2 Feb 20
sim_pause_flag = False # Boolean flag for pausing simulation
stop_sim_flag = False # Boolean flag for stopping simulation

'''Data panel global initializations======================================================
Data table dictionaries (for exporting to data boxes in a scene)
IMPORTANT: Each data box must be linked to a unique data_source_file name. It is
recommended to link the ID to the project name followed by a number. For example,
project "Laser" may have two data panels. Set these to laser_1 and laser_2.
'''
data_box_dict = {} # Containing dictionary for all data panel objects, holds data_tables
                   # and data_tables_iterations

data_tables = {} # Dictionary for tracking data results lists for each data panel

data_tables_iterations = {} # Nested dictionary that saves/tracks data_tables over multiple
                            # iterations

'''Graph initializations==================================================================
Initialization of graphing objects that have been integrated into fb library
'''
import importlib
custom_viewers_path = str('syslab_config_files.systemlab_viewers')
# 20.01.r2.custom 27-May-20
# Added try/except to import module procedure----------------------------------
try:
    view = importlib.import_module(custom_viewers_path)
except:
    view = None
#------------------------------------------------------------------------------
fbg_graph = None # Graph object for FBG functional block
analog_filter_graph = None # Graph object for Analog filter functional block
mzm_graph = None # Graph object for Mach-Zhender modulator functional block
dist_graph = {} # Graph object for mapping receiver signal distibution
demux_filter_graph = None

# New feature 20.01.r2 17-Feb-20 (quick view of arbitrary x-y data points)
xy_graph_dict = {}

def set_new_key(object_list):
    i = 1
    while (i in object_list): #Set new key for object dictionary
        i += 1
    return i

def display_xy_data(title, x_data, x_units, y_data, y_units):
    if view is not None: #MV 20.01.r2.custom 27-May-20
        i = set_new_key(xy_graph_dict)
        xy_graph_dict[i] = view.X_Y_Analyzer(title, x_data, x_units, y_data, y_units)
        xy_graph_dict[i].show()

'''def display_xy_data(title, x_data, y_data):
    xy_graph_dict = view.X_Y_Analyzer(title, x_data, y_data)
    return graph_xy'''

'''Functions==============================================================================
'''
def display_data(text, data, new_line, header):
    if sim_data_activate:
        # MV 20.01.r2.custom Added check for header
        font = QtGui.QFont()
        if header:
            font.setBold(True)
            sim_data_view.dataEdit.setCurrentFont(font)
        else:
            font.setBold(False)
            sim_data_view.dataEdit.setCurrentFont(font)
        if new_line:
            sim_data_view.dataEdit.append(text)
            sim_data_view.dataEdit.append(str(data))
        else:
            sim_data_view.dataEdit.append(text + str(data))

def status_message(text):
    if sim_status_win_enabled:
        sim_status_win.textEdit.append(text)
    status.setText(text)
    app.processEvents()


import os
from flask import render_template
from hetzner_dns_tools.zone_list import zone_list
from flask import Flask, redirect, url_for, request
from hetzner_dns_tools.record_create import record_create
from hetzner_dns_tools.zone_get import zone_get
app = Flask(__name__)

@app.route('/success')
def success():
  return 'success!'

@app.route('/index', methods=['POST', 'GET'])
def index():
  def zone_names():
    zones = []
    zone_dict = zone_list()
    for i in zone_dict['zones']:
      zones.append(i['name'])
    return zones
  zones = zone_names()
  if request.method == 'POST':
    hetznerdnstoken = request.args.get('page')
    zone = request.form.get('zone_select')
    handle = request.form.get('handle')
    didvalue = request.form.get('didvalue')
    zone_id = zone_get(hetzner_dns_token=hetznerdnstoken,
                    zone_name=zone,
                    id_only=True)
    record = record_create(hetzner_dns_token=hetznerdnstoken,
                           zone_id=zone_id,
                           record_type='TXT',
                           name='_atproto.%s' % (handle),
                           value=didvalue,
                           ttl=60)
    print(record)
    return redirect(url_for('success'))
  else:
    handle = request.args.get('handle')
    didvalue = request.args.get('didvalue')
    zone = request.args.get('zone_select')
    return render_template('index.html', zones=zones)

@app.route('/login', methods=['POST', 'GET'])
def login():
  if request.method == 'POST':
    hetznerdnstoken = request.form['hetznerdnstoken']
    os.environ["HETZNER_DNS_TOKEN"] = hetznerdnstoken
    return redirect(url_for('index', token=hetznerdnstoken))
  else:
    hetznerdnstoken = request.args.get('hetznerdnstoken')
    return render_template('login.html')

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


##
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
 # http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##

'''
running test case
we test following operations:
    set_difference
    set_union
    set_intersection
    concat
    drop_duplicates

>>  mpirun --mca opal_cuda_support 1 -n 4 -quiet python -m pytest --with-mpi -q python/pygcylon/test/test_setops.py
'''

import pytest
import cudf
import pycylon as cy
import pygcylon as gcy

@pytest.mark.mpi
def test_diff():
    env: cy.CylonEnv = cy.CylonEnv(config=cy.MPIConfig(), distributed=True)
    print("CylonEnv Initialized: My rank: ", env.rank)

    inputFile1 = "data/input/cities_a_" + str(env.rank) + ".csv"
    inputFile2 = "data/input/cities_b_" + str(env.rank) + ".csv"
    diffFile1 = "data/output/diff_df1-df2_" + str(env.rank) + ".csv"
    diffFile2 = "data/output/diff_df2-df1_" + str(env.rank) + ".csv"

    df1 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile1))
    df2 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile2))

    diff1 = df1.set_difference(other=df2, env=env)
    diff2 = df2.set_difference(other=df1, env=env)

    #  sort difference dataframes
    diff1_sorted = diff1.to_cudf().sort_values(by=["city", "state_id"], ignore_index=True)
    diff2_sorted = diff2.to_cudf().sort_values(by=["city", "state_id"], ignore_index=True)

    saved_diff1 = cudf.read_csv(diffFile1).sort_values(by=["city", "state_id"], ignore_index=True)
    saved_diff2 = cudf.read_csv(diffFile2).sort_values(by=["city", "state_id"], ignore_index=True)

    assert diff1_sorted.equals(saved_diff1), \
        "First Difference DataFrame and the DataFrame from file are not equal"
    assert diff2_sorted.equals(saved_diff2), \
        "Second Difference DataFrame and the DataFrame from file are not equal"
#    env.finalize()

@pytest.mark.mpi
def test_union():
    env: cy.CylonEnv = cy.CylonEnv(config=cy.MPIConfig(), distributed=True)
    print("CylonEnv Initialized: My rank: ", env.rank)

    inputFile1 = "data/input/cities_a_" + str(env.rank) + ".csv"
    inputFile2 = "data/input/cities_b_" + str(env.rank) + ".csv"
    unionFile = "data/output/union_cities_" + str(env.rank) + ".csv"

    df1 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile1))
    df2 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile2))

    unionDf = df1.set_union(other=df2, env=env)
    union_sorted = unionDf.to_cudf().sort_values(by=["city", "state_id"], ignore_index=True)

    saved_union = cudf.read_csv(unionFile).sort_values(by=["city", "state_id"], ignore_index=True)

    assert union_sorted.equals(saved_union), \
        "Union DataFrame and the DataFrame from file are not equal"
#    env.finalize()

@pytest.mark.mpi
def test_intersect():
    env: cy.CylonEnv = cy.CylonEnv(config=cy.MPIConfig(), distributed=True)
    print("CylonEnv Initialized: My rank: ", env.rank)

    inputFile1 = "data/input/cities_a_" + str(env.rank) + ".csv"
    inputFile2 = "data/input/cities_b_" + str(env.rank) + ".csv"
    intersectFile = "data/output/intersect_cities_" + str(env.rank) + ".csv"

    df1 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile1))
    df2 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile2))

    intersectDf = df1.set_intersect(other=df2, env=env)
    intersect_sorted = intersectDf.to_cudf().sort_values(by=["city", "state_id"], ignore_index=True)

    saved_intersect = cudf.read_csv(intersectFile).sort_values(by=["city", "state_id"], ignore_index=True)

    assert intersect_sorted.equals(saved_intersect), \
        "Intersect DataFrame and the DataFrame from file are not equal"
#    env.finalize()

@pytest.mark.mpi
def test_concat():
    env: cy.CylonEnv = cy.CylonEnv(config=cy.MPIConfig(), distributed=True)
    print("CylonEnv Initialized: My rank: ", env.rank)

    inputFile1 = "data/input/cities_a_" + str(env.rank) + ".csv"
    inputFile2 = "data/input/cities_b_" + str(env.rank) + ".csv"
    concatFile = "data/output/concat_cities_" + str(env.rank) + ".csv"

    df1 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile1))
    df2 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile2))

    concatedDf = gcy.concat([df1, df2], env=env)
    concated_sorted = concatedDf.to_cudf().sort_values(by=["city", "state_id"], ignore_index=True)

    saved_concated = cudf.read_csv(concatFile).sort_values(by=["city", "state_id"], ignore_index=True)

    assert concated_sorted.equals(saved_concated), \
        "Concatanated DataFrame and the DataFrame from file are not equal"
#    env.finalize()

@pytest.mark.mpi
def test_drop_duplicates():
    """
    We first perform concatenation of two dataframes,
    then drop duplicates.
    Resulting dataframe must be equal to the union of the two original dataframe
    """

    env: cy.CylonEnv = cy.CylonEnv(config=cy.MPIConfig(), distributed=True)
    print("CylonEnv Initialized: My rank: ", env.rank)

    inputFile1 = "data/input/cities_a_" + str(env.rank) + ".csv"
    inputFile2 = "data/input/cities_b_" + str(env.rank) + ".csv"
    unionFile = "data/output/union_cities_" + str(env.rank) + ".csv"

    df1 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile1))
    df2 = gcy.DataFrame.from_cudf(cudf.read_csv(inputFile2))

    concatedDf = gcy.concat([df1, df2], env=env)
    duplicates_dropped = concatedDf.drop_duplicates(ignore_index=True, env=env)
    d_dropped_sorted = duplicates_dropped.to_cudf().sort_values(by=["city", "state_id"], ignore_index=True)

    saved_union = cudf.read_csv(unionFile).sort_values(by=["city", "state_id"], ignore_index=True)

    assert d_dropped_sorted.equals(saved_union), \
        "Duplicates dropped DataFrame and the DataFrame from file are not equal"
#    env.finalize()


from ..models.jags.jag import Jag

def handle_victim_evacuated(jag_instance: Jag, data):
    victim_id = data['victim_id']
    if victim_id != jag_instance.inputs.get('victim-id'):
        return

    # print(f"at_proper_triage_area::handle_victim_evacuated {jag_instance.short_string()}")  # {data}")
    player_id = data['participant_id']
    elapsed_ms = data['elapsed_milliseconds']
    success = data['success']
    if success:
        jag_instance.update_preparing(player_id, player_id, 1.0, elapsed_ms)
        jag_instance.update_preparing(player_id, player_id, 0.0, elapsed_ms)
        jag_instance.update_addressing(player_id, player_id, 1.0, elapsed_ms)
        jag_instance.update_addressing(player_id, player_id, 0.0, elapsed_ms)
        jag_instance.update_completion_status(player_id, success, elapsed_ms)


from cProfile import label
import os
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

print(*[filename.split(".")[0] for filename in os.listdir("./opinions")], sep="\n")
item_id = input(str("Input your item id from the site link (numbers between .pl/ and #tab): "))

opinions = pd.read_json("opinions/"+item_id+".json")
opinions["stars"] = opinions["stars"].map(lambda x: float(x.split("/")[0].replace(",",".")))

opinions_count = len(opinions)
pros_count = opinions["pros"].map(bool).sum()
cons_count = opinions["cons"].map(bool).sum()
average_score = opinions["stars"].mean().round(2)

recommendation = opinions["recommendation"].value_counts(dropna=False).sort_index().reindex(["Nie polecam", "Polecam", None], fill_value=0)
recommendation.plot.pie(
    label="",
    autopct = lambda p: '{:.1f}%'.format(round(p)) if p > 0 else '',
    colors = ["crimson", "forestgreen", "lightskyblue"],
    labels = ["Polecam", "Nie polecam","Nie mam zdania"]
)
plt.title("Rekomendacje")
plt.savefig(f"plots/{item_id}_recommendations.png")
plt.close()

stars = opinions["stars"].value_counts().sort_index().reindex(list(np.arange(0,5.5,0.5)), fill_value=0)
stars.plot.bar(
    color = "pink"
)
plt.xlabel("Liczba gwiazdek")
plt.ylabel("Liczba opinii")
plt.grid(True, axis="y")
plt.xticks(rotation=0)
plt.savefig(f"plots/{item_id}_stars.png")
plt.close()


import os
import time
import numpy as np
import cv2
# from matplotlib import pyplot as plt
from rice_detection import rice_detection
from uuid import uuid4

from flask import Flask, request, render_template, send_from_directory

__author__ = 'Imbalance'

# app = Flask(__name__)
app = Flask(__name__, static_folder="static")
app.config.from_object(os.environ['APP_SETTINGS'])

APP_ROOT = os.path.dirname(os.path.abspath(__file__))
APP_STATIC = os.path.join(APP_ROOT, 'static/')

@app.route("/")
def index():
    return render_template("upload.html")

@app.route("/upload", methods=["POST"])
def upload():
    result = request.form
    crop_detail = [int(e) for e in result['info'].split(',')]
    print(crop_detail)
    target = os.path.join(APP_ROOT, 'static')
    print(target)
    if not os.path.isdir(target):
            os.mkdir(target)
    else:
        print("Couldn't create upload directory: {}".format(target))
    upload = request.files.getlist("file")[0]
    # print(upload.read()[:100])
    print("{} is the file name".format(upload.filename))
    filename = upload.filename
    destination = "/".join([target, filename])
    print ("Accept incoming file:", filename)
    print ("Save it to:", destination)
    upload.save(destination)

    test_rice_name = rice_detection(destination, filename, crop_detail)

    # return send_from_directory("static", filename)
    return render_template("complete.html", image_name=test_rice_name)

@app.route('/upload/<filename>', methods=["GET"])
def send_image(filename):
    return send_from_directory("static", filename)

if __name__ == "__main__":
    app.run(port=4555, debug=True)


from tkinter import *
import sys
from Navigation import Navigate
from User import *
import random as r

sys.path.append("/path/to/script/file/directory/")
RoomData = open('text_files/Data.txt', 'r')
EnemyData = open('text_files/enemies.txt', 'r')
game = Navigate(RoomData,EnemyData)
User = User()
class UserInterface():
    def __init__(self):
        self.window = Tk()
        self.window.title("Adventure Game")
        self.window.geometry('650x400')
        self.moveButton1 = Button(self.window,text = 'North',command = lambda: self.move('north'))
        self.moveButton2 = Button(self.window, text='South ', command= lambda: self.move('south'))
        self.moveButton3 = Button(self.window, text='West', command= lambda: self.move('west'))
        self.moveButton4 = Button(self.window, text='East ', command= lambda: self.move('east'))
        self.moveButton5 = Button(self.window, text='Up ', command= lambda: self.move('up'))
        self.moveButton6 = Button(self.window, text='Down ', command= lambda: self.move('down'))
        self.lookButton = Button(self.window, text = "Look", command = lambda: self.look())
        self.text1 = Text(self.window)
        self.user_health = Label(self.window,text = "Health")
        self.user_health1 = Label(self.window,text = User.health)
        self.useButton = Button(self.window,text = "Use Item",command = lambda: self.use())

        global item
        item = StringVar(self.window)
        item.set("Pick an item")
        try:
            self.pickUpTab = OptionMenu(self.window,item,*game.current.contents).place(x=00, y=225, width = 200,height = 25)
        except TypeError:
            item.set("Pick an item")

        self.executePickUp = Button(self.window,text="Pick Up",command = lambda: self.get())

        global inventory
        inventory = StringVar(self.window)
        inventory.set("Inventory")
        self.listInventoryButton = Button(self.window,text="Show Inventory",command = lambda: self.inventory())
        try:
            self.dropTab = OptionMenu(self.window,inventory, *User.inventory).place(x = 00 , y = 250, width = 200,height = 25)
        except TypeError:
            pass
        self.executeDrop= Button(self.window,text = "Drop Item",command =lambda: self.dropp())

#Layout

        self.moveButton1.place(x = 500, y = 200,width = 75,height = 25)
        self.moveButton2.place(x = 500, y = 250,width = 75,height = 25)
        self.moveButton3.place(x = 450, y = 225,width = 75,height = 25)
        self.moveButton4.place(x = 550, y = 225,width = 75,height = 25)
        self.moveButton5.place(x = 500, y = 275,width = 75,height = 25)
        self.moveButton6.place(x = 500, y = 300,width = 75,height = 25)
        self.lookButton.place(x = 475, y = 165,width = 125,height = 25)
        self.text1.place(x = 125,y = 000, width = 400, height = 150)
        self.user_health.place(x = 125, y = 175, width = 50)
        self.user_health1.place(x = 175,y = 175)
        self.useButton.place(x = 275, y = 225,width = 125,height = 25)
        self.executePickUp.place(x = 200, y = 225,width = 75,height = 25)

        self.executeDrop.place(x = 200, y =250,width = 75,height = 25)
        self.listInventoryButton.place(x = 275, y = 250,width = 125,height = 25)
#Display Console
        self.add_timestamp()
    def refresh_health(self):
        self.user_health = Label(self.window,text = "Health")
        self.user_health1 = Label(self.window,text = User.health)
        self.user_health.place(x = 125, y = 175, width = 50)
        self.user_health1.place(x = 175,y = 175)
    def add_timestamp(self):
        self.text1.see("end")
        self.text1.after(1000, self.add_timestamp)
    def run_script(self):
        sys.stdout = self
        try:
            del (sys.modules["Navigation"])
        except:
            pass
        import Navigation
        return Navigation
        sys.stdout = sys.__stdout__
    def write(self, txt):
        self.text1.insert(INSERT, txt)
    def flush(self):
        pass

#Button Commands
    def use(self):
        User.use(inventory.get())
        self.refresh_health()
        self.refreshOptionMenus()
    def look(self):
        game.look()
    def move(self,direction):
        self.refresh_health()
        User.unlock(game.current,game.floorPlan, direction)

        if game.detectEnemyNextRoom(direction) != None:
            if User.battleReady == True:
                game.move(direction)
                if game.detectEnemy() != None:
                    self.battleon()
                else:
                    pass
            else:
                print("You cannot go in there! You are not equipped for battle!")
        else:
            game.move(direction)

        item = StringVar(self.window)
        item.set("Pick an item")
        self.refreshOptionMenus()
    def battleon(self):
        BattleTime = Battle()
        BattleTime.window.mainloop
        self.refresh_health()
    def refreshOptionMenus(self):
        try:
            self.pickUpTab = OptionMenu(self.window,item,*game.current.contents).place(x = 00 , y = 225 ,width = 200,height = 25)
            item.set("Pick an item")
        except TypeError:
            item.set("Pick an item")
        try:
            self.dropTab= OptionMenu(self.window,inventory, *User.inventory).place(x = 00 , y = 250, width = 200,height = 25)
            inventory.set("Inventory")
        except TypeError:
            inventory.set("Inventory")
    def inventory(self):
        User.listInventory()
    def get(self):
        User.pickup(game.current,item.get())
        self.refreshOptionMenus()

    def dropp(self):
        User.drop(game.current,inventory.get())
        self.refreshOptionMenus()
class Battle():

    def __init__(self):
        Enemy = game.detectEnemy()
        self.battlestatus = True
        self.window = Tk()
        self.window.title('Battle')
        self.window.geometry('300x300')
        self.listbox = Listbox(self.window)
        self.attackButton = Button(self.window,text = 'Attack', command = self.attack)
        self.user_health = Label(self.window,text = "Health")
        self.user_health1 = Label(self.window,text = User.health)
        self.enemy_health = Label(self.window, text="Enemy Health")
        self.enemy_health1 = Label(self.window, text=int(Enemy.health))
        self.listbox.place(x=0,y=0,width=300,height=150)
        self.attackButton.place(x=0,y=175,width=100,height=25)
        self.user_health.place(x=50, y=150, width=50)
        self.user_health1.place(x=100, y=150)
        self.enemy_health.place(x=150, y=150, width=75)
        self.enemy_health1.place(x=225, y=150)
        self.add_timestamp()
        self.listbox_insert('A '+Enemy.name+' appears')
        if "Bow and Arrow" in User.inventory:
            self.bowButton = Button(self.window,text = 'Bow and Arrow', command = lambda : self.bowandarrow())
            self.bowButton.place(x=200,y=175,width =100,height = 25)
        if "Boomerang" in User.inventory:
            self.boomerangButton = Button(self.window,text = "Boomerang",command = lambda: self.boomerang())
            self.boomerangButton.place(x=0,y =200,width = 100,height =20)
    def update_healthbar(self):
        Enemy = game.detectEnemy()
        self.user_health = Label(self.window,text = "Health")
        self.user_health1 = Label(self.window,text = User.health)
        self.enemy_health = Label(self.window, text="Enemy Health")
        self.enemy_health1 = Label(self.window, text=int(Enemy.health))
        self.attackButton.place(x=0,y=175,width=100,height=25)
        self.user_health.place(x=50, y=150, width=50)
        self.user_health1.place(x=100, y=150)
        self.enemy_health.place(x=150, y=150, width=75)
        self.enemy_health1.place(x=225, y=150)
    def endBattle(self):
        self.window.destroy()
    def add_timestamp(self):
        self.listbox.see("end")
        self.listbox.after(500, self.add_timestamp)
    def listbox_insert(self, item):
        self.listbox.insert(END, item)
    def checkEndGame(self):
        Enemy = game.detectEnemy()
        if User.health <= 0:
            gui.window.destroy()
            self.window.destroy()

        if Enemy.health <= 0:
            self.window.destroy()
            print('You won the battle!')
            Enemy.health = Enemy.original_health
            if game.current.enemy == "Dragon":
                print("You've saved princess Sofia from the wrath of the evil dragon")
                print("An era of peace has been restored to the kingdom")
            game.current.enemy = None
        gui.refresh_health()
    def attack(self):
        Enemy = game.detectEnemy()
        if Enemy.awake == "Awake":
            y = Enemy.attack()
            self.listbox_insert('You took ' + str(y) + ' damage!')
            User.health -= y
            if "Shield" in User.inventory:
                p = r.randint(1, 5)
                if p == 3:
                    y = 0
                    self.listbox_insert("Your shield blocked the hit!")
                else:
                    pass
        else:
            pass
        if Enemy.awake == "Asleep":
            self.listbox_insert('The enemy is stunned it cannot attack!')
        x = User.attack(Enemy.health)
        Enemy.awake = "Awake"
        self.listbox_insert('The enemy took '+str(x)+' damage!')
        Enemy.health -= x
        self.update_healthbar()
        self.checkEndGame()
    def boomerang(self):
        Enemy = game.detectEnemy()
        p = r.randint(1,7)
        if p in [1,4,7]:
            self.listbox_insert("The boomerang missed!")
            y = Enemy.attack()
            if "Shield" in User.inventory:
                b = r.randint(1, 5)
                if b == 3:
                    y = 0
                    self.listbox_insert("Your shield blocked the hit!")
                else:
                    pass
            self.listbox_insert('You took ' + str(y) + ' damage!')
            User.health -= y
        else:
            Enemy.awake = "Asleep"
            self.listbox_insert("The Enemy has been stunned")
        self.update_healthbar()
        self.checkEndGame()
    def bowandarrow(self):
        Enemy = game.detectEnemy()
        p = r.randint(1,8)
        if p in [1,2,3]:
            self.listbox_insert('Your arrow missed')
            pass
        else:
            y = 20
            Enemy.health -= y
            self.listbox_insert('The enemy took ' + str(y) + ' damage!')
        y = Enemy.attack()
        self.listbox_insert('You took ' + str(y) + ' damage!')
        User.health -= y
        self.update_healthbar()
        self.checkEndGame()

gui = UserInterface()
gui.run_script()

game.look()
gui.window.mainloop()
if User.health <= 0:
    root = Tk()
    photo = PhotoImage(file ="images/gameover.gif")
    label = Label(image = photo)
    label.pack()
    root.mainloop()


'''
Write a Python program to delete file by specified path.
Before deleting check for access and whether a given path exists or not.
'''

import os

path = r'C:\\Users\\Lenovo\\Desktop\\pp2\\forlab6\\b.txt'
if os.path.exists(path)==True:
    os.remove(path)


from ...base import DBSession
from ...system.models.user import User
from ..models import APIKey, APIHandler
from sqlalchemy import and_
from random import choice
import string

_handlers = {}

def auth(key):
    the_key = DBSession.query(APIKey).filter(APIKey.key == key).first()
    return the_key

_chars = string.ascii_letters + string.digits
def grant(user_id):
    key_str = "".join(map(lambda i: choice(_chars), range(24)))

    the_key = APIKey(
        user = user_id,
        key = key_str,
    )

    DBSession.add(the_key)
    return the_key.key

def revoke(key_id):
    DBSession.query(APIKey).filter(APIKey.id == key_id).delete()

def get_key_list():
    return DBSession.query(
        User, APIKey
    ).join(
        (APIKey, and_(APIKey.user == User.id)),
    ).order_by(User.username)

def get_user_by_key(key_id):
    return DBSession.query(
        User
    ).join(
        (APIKey, and_(APIKey.user == User.id)),
    ).filter(
        APIKey.key == key_id,
    ).first()

def collect_handlers():
    for h in APIHandler.__subclasses__():
        _handlers[h.name] = h

def get_key_by_user(user_id):
    return DBSession.query(
        APIKey
    ).filter(
        APIKey.user == user_id,
    ).first()

def test_response(result, msg=""):
    """
    Utility function for unit testing, checks for errors.
    """
    body = result.body.decode("utf-8")

    if body == "Key not found":
        return "No API key supplied{}".format(msg)

    if body[:17] == "Request mode of '" and body[-14:] == "' is not valid":
        return "Invalid mode{}".format(msg)

    return False


from nodo import Nodo, Nodo_ll

class Lista_listas:
    def __init__(self) -> None:
        self.inicio = None

    def insertarAlInicio(self, dato):
        nuevo = Nodo_ll(dato)
        if self.inicio == None:
            self.inicio = nuevo
        else:
            nuevo.siguiente = self.inicio
            self.inicio = nuevo

    def insertarHijo(self, encabezado, informacion_hijo):
        actual = self.inicio
        while actual is not None:
            if actual.info == encabezado:
                break
            actual = actual.siguiente

        if actual is not None:
            nuevo = Nodo(informacion_hijo)
            if actual.hijo == None:
                actual.hijo = nuevo
            else:
                nuevo.siguiente = actual.hijo
                actual.hijo = nuevo

    def imprimirHijos(self, nodo_encabezado):
        rep = "["
        actual = nodo_encabezado.hijo
        while actual is not None:
            rep += f'{actual},' if actual.siguiente != None else f'{actual}'
            actual = actual.siguiente
        rep += "]"
        return rep

    def imprimir(self):
        actual = self.inicio
        rep = "{"
        while actual is not None:
            rep += f'{actual}:'
            rep += f'{self.imprimirHijos(actual)}, '
            actual = actual.siguiente
        rep += "}"
        return rep

    def graficarHijos(self, nodo_encabezado):
        rep = ""
        enlaces = ""

        actual = nodo_encabezado.hijo
        while actual is not None:
            rep += f'{hash(actual)}[ label= "{actual}"]\n'
            enlaces += f'{hash(actual)} ->{hash(actual.siguiente)}\n' if actual.siguiente != None else ""
            actual = actual.siguiente

        return f'{rep}{enlaces}'

    def graficar(self):
        # variable para almacenar el codigo de graphviz de la estructura de datos
        rep = "digraph G { \nnode [shape=box]\n"
        # variables para almacenar el codigo que relaciona los nodos encabezados
        enlaces = ""
        # establece los nodos encabezados en la misma direccion (horizontal)
        direccion = "\n{ rank = same;"

        # recorrido de la estructura
        actual = self.inicio
        while actual is not None:
            rep += '\n# ---- encabezado e hijos -----\n'
            rep += f'{hash(actual)}[ label= "{actual}"]'
            # retorna el codigo de los nodos hijos y sus enlaces
            rep += f'\n{self.graficarHijos(actual)}'
            # se vincula a un nodo encabezado con su siguiente en la lista
            enlaces += f'{hash(actual)} ->{hash(actual.siguiente)}\n' if actual.siguiente != None else ""
            # enlace del encabezado con el primero de la sublista
            rep += f'\n{hash(actual)} ->{hash(actual.hijo)}\n' if actual.hijo != None else ""
            direccion += f'{hash(actual)};'
            actual = actual.siguiente
        direccion += "}"
        rep += '\n# ---- enlazando los encabezados -----\n'
        rep += f'{enlaces}'
        rep += '\n# ---- estableciendo la misma direccion para los nodos encabezados -----'
        rep += f'{direccion}'
        # final del gráfico
        rep += "\n}"
        return rep


from typing import List

class CountVectorizer():
    '''Создали класс'''

    def __init__(self):
        pass

    def fit_transform(self, raw_documents: List[str]) -> List[List[int]]:
        '''Возвращает терм-документную матрицу https://ru.wikipedia.org/wiki/Терм-документная_матрица '''
        words = set()
        for sentence in raw_documents:
            sentence_words = sentence.split()
            for word in sentence_words:
                words.add(word.lower())
        self.words = list(words)  # self.words - это атрибут

        index_words = {}
        for index in range(len(self.words)):
            index_words[self.words[index]] = index  # дикт из ключей-слов и валью-индексов

        count_matrix = []
        for sentence in raw_documents:
            sentence_words = sentence.split()
            count_vector = [0] * len(self.words)
            for word in sentence_words:
                word = word.lower()
                index = index_words[word]
                count_vector[index] += 1
            count_matrix.append(count_vector)
        return count_matrix

    def get_feature_names(self) -> List[str]:
        '''Возвращет все уникальные слова'''
        return self.words

def main():
    corpus = [
        'Crock Pot Pasta Never boil pasta again',
        'Pasta Pomodoro Fresh ingredients Parmesan to taste'
    ]
    vectorizer = CountVectorizer()  # инициализируем объект
    count_matrix = vectorizer.fit_transform(corpus)  # метод fit transform вернул count matrix
    print(vectorizer.get_feature_names())
    # Out: ['crock', 'pot', 'pasta', 'never', 'boil', 'again', 'pomodoro',
    #       'fresh', 'ingredients', 'parmesan', 'to', 'taste']
    print(count_matrix)
    # Out: [[1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0],
    #       [0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1]]

if __name__ == '__main__':
    main()