import json
import os
from contextlib import suppress
from math import sqrt
from typing import Tuple

import numpy as np
import pandas as pd
from openpyxl import load_workbook, styles, utils
from PIL import Image

def to_excel(
    image: Image, path: str, lower_image_size_by: int = 10, **spreadsheet_kwargs
) -> None:
    """
    - Added on release 0.0.1;
    - Coded originally on https://github.com/Eric-Mendes/image2excel

    Saves an image as a `.xlsx` file by coloring its cells each pixel's color.

    ## Parameters
    * :param image: Your image opened using the `PIL.Image` module;
    * :param path: The path that you want to save your output file.
    Example: `/home/user/Documents/my_image.xlsx`;
    * :param lower_image_size_by: A factor that the function will divide
    your image's dimensions by. Defaults to `10`;
       * It is very important that you lower your image's dimensions because a big image might take the function a long time to process plus your spreadsheet will probably take a long time to load on any software that you use to open it;
    * :param **spreadsheet_kwargs: See below.

    ## Spreadsheet Kwargs
    Optional parameters to tweak the spreadsheet's appearance.

    * :param row_height (`float`): the rows' height. Defaults to `15`;
    * :param column_width (`float`): the columns' width. Defaults to `2.3`;
       * The default values on `row_height` and `column_width` were specifically thought out so that they make the cells squared, however - as any hardcoded value - they might not do the trick on your device. That is when you might want to tweak them a little bit.
    * :param delete_cell_value (`bool`): wheter to keep or not the text corresponding to that color. Defaults to `True`;
    * :param zoom_scale (`int`): how much to zoom in or out on the spreadsheet. Defaults to `20` which seems to be the default max zoom out on most spreadsheet softwares.

    ## Return
    * :return: `None`, but outputs a `.xlsx` file on the given `path`.
    """
    image = image.convert("RGB")

    # Resizing image
    image = image.resize(
        (image.size[0] // lower_image_size_by, image.size[1] // lower_image_size_by)
    )

    # OpenPyxl colors work in a weird way
    image_colors_processed = [
        ["%02x%02x%02x" % tuple(item) for item in row]
        for row in np.array(image).tolist()
    ]

    df = pd.DataFrame(image_colors_processed)
    image_name = os.path.splitext(os.path.split(path)[1])[0]

    # Saving a DataFrame where each cell has a text corresponding to the RGB color its background should be
    df.to_excel(path, index=False, header=False)

    # Loading the excel file, painting each cell with its color and saving the updates
    wb = load_workbook(path)

    ws = wb.active
    ws.title = image_name

    for row in range(1, df.shape[0] + 1):
        for col in range(1, df.shape[1] + 1):
            cell = ws.cell(row=row, column=col)
            # Makes cells squared
            ws.row_dimensions[row].height = spreadsheet_kwargs.get("row_height", 15)
            ws.column_dimensions[
                utils.get_column_letter(col)
            ].width = spreadsheet_kwargs.get("column_width", 2.3)

            # Painting the cell
            cell.fill = styles.PatternFill(
                start_color=cell.value, end_color=cell.value, fill_type="solid"
            )
            if spreadsheet_kwargs.get("delete_cell_value", True):
                cell.value = None  # Deletes the text from the cell

    # Saves spreadsheet already zoomed in or out
    ws.sheet_view.zoomScale = spreadsheet_kwargs.get("zoom_scale", 20)
    wb.save(path)

def to_minecraft(
    image: Image,
    path: str,
    lower_image_size_by: int = 10,
    player_pos: Tuple[int, int, int] = (0, 0, 0),
    minecraft_version: str = '1.18.2',

) -> None:
    """
    - Added on release 0.0.1;
    - Coded originally on https://github.com/Eric-Mendes/pixel-art-map

    Saves an image as a minecraft datapack that when loaded into your world will build a pixel art of it on the player's position.

    ## Parameters
    * :param image: Your image opened using the `PIL.Image` module;
    * :param path: The path that you want to save your datapack.
    Example: `/home/user/Documents/my_image_datapack`;
    * :param lower_image_size_by: A factor that the function will divide
    your image's dimensions by. Defaults to `10`;
    * :param player_pos: The player's (x, y, z) position. Defaults to `(0, 0, 0)`;
    * :param minecraft_version: The minecraft client version (x.xx.x). Default is `1.18.2`.

    ## Return
    * :return: `None`, but outputs a datapack on the given `path`.
    """
    image = image.convert("RGB")

    # Makes the commands that the datapack will run when loaded
    def script(df, **kwargs):
        player_pos = [
            kwargs.get("player_x", 0),
            kwargs.get("player_y", 0),
            kwargs.get("player_z", 0),
        ]
        z = (df != df.shift()).cumsum()
        zri = z.reset_index()
        ix_name = z.index.name
        co_name = z.columns.name
        for i in z:
            v = zri.groupby(i)[ix_name].agg(["first", "last"])
            s = {co_name: i}
            e = {co_name: i}
            for _, r in v.iterrows():
                s[ix_name] = r["first"]
                e[ix_name] = r["last"]
                material = df.loc[r["first"], i]
                yield f'fill {s["x"] + player_pos[0]} {0 + player_pos[1]} {s["z"] + player_pos[2]} {e["x"] + player_pos[0]} {0 + player_pos[1]} {e["z"] + player_pos[2]} {material.split(",")[0].strip()}'

    # Helper function. Loads the blocks an the colors they have when looked at via map,
    # and maps the pixels to the blocks
    blocks = [
        {
            "rgb": (127, 178, 56),
            "blocks": ("grass_block", "slime_block"),
        },
        {
            "rgb": (247, 233, 163),
            "blocks": ("sand", "birch_planks", "birch_log[axis=y]", "stripped_birch_log[axis=x]", "birch_wood", "stripped_birch_wood", "birch_sign", "birch_pressure_plate", "birch_trapdoor", "birch_stairs", "birch_slab", "birch_fence_gate", "birch_fence", "birch_door", "sandstone", "glowstone", "end_stone", "end_stone_brick_slab", "end_stone_brick_stairs", "end_stone_brick_wall", "bone_block", "turtle_egg", "scaffolding", "candle"),
        },
        {
            "rgb": (199, 199, 199),
            "blocks": ("mushroom_stem", "cobweb", "white_bed[part=head]", "white_candle"),
        },
        {
            "rgb": (255, 0, 0),
            "blocks": ("redstone_block", "tnt", "lava", "fire"),
        },
        {
            "rgb": (160, 160, 255),
            "blocks": ("ice", "frosted_ice", "packed_ice", "blue_ice"),
        },
        {
            "rgb": (167, 167, 167),
            "blocks": ("iron_block", "iron_door", "brewing_stand", "heavy_weighted_pressure_plate", "iron_trapdoor", "lantern", "anvil", "grindstone", "soul_lantern", "lodestone"),
        },
        {
            "rgb": (0, 124, 0),
            "blocks": ("oak_sapling", "spruce_sapling", "birch_sapling", "jungle_sapling", "acacia_sapling", "dark_oak_sapling", "dandelion", "poppy", "blue_orchid", "allium", "azure_bluet", "red_tulip", "orange_tulip", "white_tulip", "pink_tulip", "oxeye_daisy", "cornflower", "lily_of_the_valley", "wither_rose", "sunflower", "lilac", "rose_bush", "peony", "wheat[age=7]", "sugar_cane[age=9]", "pumpkin_stem[age=7]", "melon_stem[age=7]", "lily_pad", "cocoa[age=2]", "carrots[age=7]", "potatoes[age=7]", "beetroots[age=7]", "sweet_berry_bush[age=3]", "grass", "fern", "vine", "oak_leaves", "spruce_leaves", "birch_leaves", "jungle_leaves", "acacia_leaves", "dark_oak_leaves", "azalea_leaves", "flowering_azalea_leaves", "cactus[age=9]", "bamboo[age=1]", "cave_vines", "spore_blossom", "flowering_azalea", "big_dripleaf", "small_dripleaf"),
        },
        {
            "rgb": (255, 255, 255),
            "blocks": ("snow", "snow_block", "white_bed[part=foot]", "white_wool", "white_stained_glass", "white_carpet", "white_shulker_box", "white_glazed_terracotta", "white_concrete", "white_concrete_powder", "powder_snow"),
        },
        {
            "rgb": (164, 168, 184),
            "blocks": ("clay", "infested_chiseled_stone_bricks", "infested_cobblestone", "infested_cracked_stone_bricks", "infested_mossy_stone_bricks", "infested_stone", "infested_stone_bricks"),
        },
        {
            "rgb": (151, 109, 77),
            "blocks": ("coarse_dirt", "dirt", "farmland", "dirt_path", "granite_slab", "granite_stairs", "granite_wall", "polished_granite_slab", "polished_granite_stairs", "jungle_planks", "jungle_log[axis=y]", "stripped_jungle_log[axis=x]", "jungle_wood", "stripped_jungle_wood", "jungle_sign", "jungle_pressure_plate", "jungle_trapdoor", "jungle_stairs", "jungle_slab", "jungle_fence_gate", "jungle_fence", "jungle_door", "jukebox", "brown_mushroom_block", "rooted_dirt", "hanging_roots"),
        },
        {
            "rgb": (112, 112, 112),
            "blocks": ("stone", "stone_slab", "stone_stairs", "andesite_slab", "andesite_stairs", "andesite_wall", "polished_andesite_slab", "polished_andesite_stairs", "cobblestone_slab", "cobblestone_stairs", "cobblestone_wall", "bedrock", "gold_ore", "iron_ore", "coal_ore", "lapis_lazuli_ore", "dispenser", "mossy_cobblestone_slab", "mossy_cobblestone_stairs", "mossy_cobblestone_wall", "spawner", "diamond_ore", "furnace", "stone_pressure_plate", "redstone_ore", "stone_bricks", "emerald_ore", "ender_chest", "dropper", "smooth_stone_slab", "observer", "smoker", "blast_furnace", "stonecutter", "sticky_piston", "piston", "piston_head", "gravel", "acacia_log[axis=z]", "cauldron", "hopper", "copper_ore"),
        },
        {
            "rgb": (64, 64, 255),
            "blocks": ("water", "kelp", "seagrass", "bubble_column"),
        },
        {
            "rgb": (143, 119, 72),
            "blocks": ("oak_planks", "oak_log[axis=y]", "stripped_oak_log[axis=x]", "oak_wood", "stripped_oak_wood", "oak_sign", "oak_pressure_plate", "oak_trapdoor", "oak_stairs", "oak_slab", "oak_fence_gate", "oak_fence", "oak_door", "note_block", "bookshelf", "chest", "crafting_table", "trapped_chest", "daylight_detector", "loom", "barrel", "cartography_table", "fletching_table", "lectern", "smithing_table", "composter", "bamboo_sapling", "dead_bush", "petrified_oak_slab", "beehive", "white_banner"),
        },
        {
            "rgb": (255, 252, 245),
            "blocks": ("quartz_block", "diorite_stairs", "diorite_slab", "diorite_wall", "polished_diorite_stairs", "polished_diorite_slab", "birch_log[axis=x]", "sea_lantern", "target"),
        },
        {
            "rgb": (216, 127, 51),
            "blocks": ("acacia_planks", "acacia_log[axis=y]", "stripped_acacia_log[axis=x]", "acacia_wood", "stripped_acacia_wood", "acacia_sign", "acacia_pressure_plate", "acacia_trapdoor", "acacia_stairs", "acacia_slab", "acacia_fence_gate", "acacia_fence", "acacia_door", "red_sand", "orange_wool", "orange_carpet", "orange_shulker_box", "orange_bed[part=foot]", "orange_stained_glass", "orange_glazed_terracotta", "orange_concrete", "orange_concrete_powder", "orange_candle", "pumpkin", "carved_pumpkin", "jack_o_lantern", "terracotta", "red_sandstone", "honey_block", "honeycomb_block", "copper_block", "lightning_rod", "raw_copper_block"),
        },
        {
            "rgb": (178, 76, 216),
            "blocks": ("magenta_wool", "magenta_carpet", "magenta_shulker_box", "magenta_bed[part=foot]", "magenta_stained_glass", "magenta_glazed_terracotta", "magenta_concrete", "magenta_concrete_powder", "magenta_candle", "purpur_block"),
        },
        {
            "rgb": (102, 153, 216),
            "blocks": ("light_blue_wool", "light_blue_carpet", "light_blue_shulker_box", "light_blue_bed[part=foot]", "light_blue_stained_glass", "light_blue_glazed_terracotta", "light_blue_concrete", "light_blue_concrete_powder", "light_blue_candle", "soul_fire"),
        },
        {
            "rgb": (229, 229, 51),
            "blocks": ("sponge", "wet_sponge", "yellow_wool", "yellow_carpet", "yellow_shulker_box", "yellow_bed[part=foot]", "yellow_stained_glass", "yellow_glazed_terracotta", "yellow_concrete", "yellow_concrete_powder", "yellow_candle", "hay_bale", "horn_coral_block[waterlogged=true]", "bee_nest"),
        },
        {
            "rgb": (127, 204, 25),
            "blocks": ("lime_wool", "lime_carpet", "lime_shulker_box", "lime_bed[part=foot]", "lime_stained_glass", "lime_glazed_terracotta", "lime_concrete", "lime_concrete_powder", "lime_candle", "melon"),
        },
        {
            "rgb": (242, 127, 165),
            "blocks": ("pink_wool", "pink_carpet", "pink_shulker_box", "pink_bed[part=foot]", "pink_stained_glass", "pink_glazed_terracotta", "pink_concrete", "pink_concrete_powder", "pink_candle", "brain_coral_block[waterlogged=true]"),
        },
        {
            "rgb": (76, 76, 76),
            "blocks": ("acacia_wood", "gray_wool", "gray_carpet", "gray_shulker_box", "gray_bed[part=foot]", "gray_stained_glass", "gray_glazed_terracotta", "gray_concrete", "gray_concrete_powder", "gray_candle", "dead_coral_block", "tinted_glass"),
        },
        {
            "rgb": (153, 153, 153),
            "blocks": ("light_gray_wool", "light_gray_carpet", "light_gray_shulker_box", "light_gray_bed[part=foot]", "light_gray_stained_glass", "light_gray_glazed_terracotta", "light_gray_concrete", "light_gray_concrete_powder", "light_gray_candle", "structure_block", "jigsaw"),
        },
        {
            "rgb": (76, 127, 153),
            "blocks": ("cyan_wool", "cyan_carpet", "cyan_shulker_box", "cyan_bed[part=foot]", "cyan_stained_glass", "cyan_glazed_terracotta", "cyan_concrete", "cyan_concrete_powder", "cyan_candle", "prismarine_slab", "prismarine_stairs", "prismarine_wall", "warped_roots", "warped_fungus", "twisting_vines", "nether_sprouts", "sculk_sensor"),
        },
        {
            "rgb": (127, 63, 178),
            "blocks": ("shulker_box", "purple_wool", "purple_carpet", "purple_shulker_box", "purple_bed[part=foot]", "purple_stained_glass", "purple_glazed_terracotta", "purple_concrete", "purple_concrete_powder", "purple_candle", "mycelium", "chorus_plant", "chorus_flower", "repeating_command_block", "bubble_coral_block", "amethyst_block", "budding_amethyst", "amethyst_cluster"),
        },
        {
            "rgb": (51, 76, 178),
            "blocks": ("blue_wool", "blue_carpet", "blue_shulker_box", "blue_bed[part=foot]", "blue_stained_glass", "blue_glazed_terracotta", "blue_concrete", "blue_concrete_powder", "blue_candle", "tube_coral_block"),
        },
        {
            "rgb": (102, 76, 51),
            "blocks": ("dark_oak_planks", "dark_oak_log[axis=y]", "stripped_dark_oak_log[axis=x]", "dark_oak_wood", "stripped_dark_oak_wood", "dark_oak_sign", "dark_oak_pressure_plate", "dark_oak_trapdoor", "dark_oak_stairs", "dark_oak_slab", "dark_oak_fence_gate", "dark_oak_fence", "dark_oak_door", "spruce_log[axis=x]", "brown_wool", "brown_carpet", "brown_shulker_box", "brown_bed[part=foot]", "brown_stained_glass", "brown_glazed_terracotta", "brown_concrete", "brown_concrete_powder", "brown_candle", "soul_sand", "command_block", "brown_mushroom", "soul_soil"),
        },
        {
            "rgb": (102, 127, 51),
            "blocks": ("green_wool", "green_carpet", "green_shulker_box", "green_bed[part=foot]", "green_stained_glass", "green_glazed_terracotta", "green_concrete", "green_concrete_powder", "green_candle", "end_portal_frame", "chain_command_block", "sea_pickle", "moss_carpet", "moss_block", "dried_kelp_block"),
        },
        {
            "rgb": (153, 51, 51),
            "blocks": ("red_wool", "red_carpet", "red_shulker_box", "red_bed[part=foot]", "red_stained_glass", "red_glazed_terracotta", "red_concrete", "red_concrete_powder", "red_candle", "brick_slab", "brick_stairs", "brick_wall", "red_mushroom_block", "nether_wart", "enchanting_table", "nether_wart_block", "fire_coral_block", "red_mushroom", "shroomlight"),
        },
        {
            "rgb": (25, 25, 25),
            "blocks": ("black_wool", "black_carpet", "black_shulker_box", "black_bed[part=foot]", "black_stained_glass", "black_glazed_terracotta", "black_concrete", "black_concrete_powder", "black_candle", "obsidian", "end_portal", "dragon_egg", "coal_block", "end_gateway", "basalt", "polished_basalt", "smooth_basalt", "netherite_block", "crying_obsidian", "respawn_anchor", "blackstone", "gilded_blackstone"),
        },
        {
            "rgb": (250, 238, 77),
            "blocks": ("gold_block", "light_weighted_pressure_plate", "bell", "raw_gold_block"),
        },
        {
            "rgb": (92, 219, 213),
            "blocks": ("diamond_block", "beacon", "prismarine_brick_slab", "prismarine_brick_stairs", "dark_prismarine_slab", "dark_prismarine_stairs", "conduit"),
        },
        {
            "rgb": (74, 128, 255),
            "blocks": ("lapis_lazuli_block"),
        },
        {
            "rgb": (0, 217, 58),
            "blocks": ("emerald_block"),
        },
        {
            "rgb": (129, 86, 49),
            "blocks": ("podzol", "spruce_planks", "spruce_log[axis=y]", "stripped_spruce_log[axis=x]", "spruce_wood", "stripped_spruce_wood", "spruce_sign", "spruce_pressure_plate", "spruce_trapdoor", "spruce_stairs", "spruce_slab", "spruce_fence_gate", "spruce_fence", "spruce_door", "oak_log[axis=x]", "jungle_log[axis=x]", "campfire", "soul_campfire"),
        },
        {
            "rgb": (112, 2, 0),
            "blocks": ("netherrack", "nether_brick_fence", "nether_brick_slab", "nether_brick_stairs", "nether_brick_wall", "nether_brick_chiseled", "nether_brick_cracked", "nether_gold_ore", "nether_quartz_ore", "magma_block", "red_nether_brick_slab", "red_nether_brick_stairs", "red_nether_brick_wall", "crimson_roots", "crimson_fungus", "weeping_vines"),
        },
        {
            "rgb": (209, 177, 161),
            "blocks": ("white_terracotta", "calcite"),
        },
        {
            "rgb": (159, 82, 36),
            "blocks": ("orange_terracotta"),
        },
        {
            "rgb": (149, 87, 108),
            "blocks": ("magenta_terracotta"),
        },
        {
            "rgb": (112, 108, 138),
            "blocks": ("light_blue_terracotta"),
        },
        {
            "rgb": (186, 133, 36),
            "blocks": ("yellow_terracotta"),
        },
        {
            "rgb": (103, 117, 53),
            "blocks": ("lime_terracotta"),
        },
        {
            "rgb": (160, 77, 78),
            "blocks": ("pink_terracotta"),
        },
        {
            "rgb": (57, 41, 35),
            "blocks": ("gray_terracotta", "tuff"),
        },
        {
            "rgb": (135, 107, 98),
            "blocks": ("light_gray_terracotta", "exposed_copper"),
        },
        {
            "rgb": (87, 92, 92),
            "blocks": ("cyan_terracotta"),
        },
        {
            "rgb": (122, 73, 88),
            "blocks": ("purple_terracotta", "purple_shulker_box"),
        },
        {
            "rgb": (76, 62, 92),
            "blocks": ("blue_terracotta"),
        },
        {
            "rgb": (76, 50, 35),
            "blocks": ("brown_terracotta", "pointed_dripstone", "dripstone_block"),
        },
        {
            "rgb": (76, 82, 42),
            "blocks": ("green_terracotta"),
        },
        {
            "rgb": (142, 60, 46),
            "blocks": ("red_terracotta"),
        },
        {
            "rgb": (37, 22, 16),
            "blocks": ("black_terracotta"),
        },
        {
            "rgb": (189, 48, 49),
            "blocks": ("crimson_nylium"),
        },
        {
            "rgb": (148, 63, 97),
            "blocks": ("crimson_planks", "crimson_log[axis=y]", "stripped_crimson_log[axis=x]", "crimson_wood", "stripped_crimson_wood", "crimson_sign", "crimson_pressure_plate", "crimson_trapdoor", "crimson_stairs", "crimson_slab", "crimson_fence_gate", "crimson_fence", "crimson_door"),
        },
        {
            "rgb": (92, 25, 29),
            "blocks": ("crimson_hyphae", "stripped_crimson_hyphae"),
        },
        {
            "rgb": (22, 126, 134),
            "blocks": ("warped_nylium", "oxidized_copper"),
        },
        {
            "rgb": (58, 142, 140),
            "blocks": ("warped_planks", "warped_log[axis=y]", "stripped_warped_log[axis=x]", "warped_wood", "stripped_warped_wood", "warped_sign", "warped_pressure_plate", "warped_trapdoor", "warped_stairs", "warped_slab", "warped_fence_gate", "warped_fence", "warped_door", "weathered_copper"),
        },
        {
            "rgb": (86, 44, 62),
            "blocks": ("warped_hyphae", "stripped_warped_hyphae"),
        },
        {
            "rgb": (20, 180, 133),
            "blocks": ("warped_wart_block"),
        },
        {
            "rgb": (100, 100, 100),
            "blocks": ("deepslate"),
        },
        {
            "rgb": (216, 175, 147),
            "blocks": ("raw_iron_block"),
        },
        {
            "rgb": (127, 167, 150),
            "blocks": ("glow_lichen"),
        },
    ]

    def to_minecraft_color(pxl):
        color = None
        min_distance = None
        for item in blocks:
            # Calculates the "distance" between two RGB colors as if they
            # were points in a 3-dimensional space.
            # The closer they are, the more they look like each other.
            euclidean_distance = sqrt(sum([pow(p - c, 2) for p, c in zip(item["rgb"], pxl)]))

            if min_distance is None or euclidean_distance < min_distance:
                min_distance = euclidean_distance
                color = ", ".join("minecraft:"+block for block in item["blocks"])
        return color

    # Resizing the image and mapping each pixel's color to a minecraft color
    image = image.resize(
        (image.size[0] // lower_image_size_by, image.size[1] // lower_image_size_by)
    )
    image_colors_processed = [
        [to_minecraft_color(pixel) for pixel in row] for row in np.array(image)
    ]

    # Getting the name that the image should have via the given path
    image_name = os.path.splitext(os.path.split(path)[1])[0]

    df = pd.DataFrame(image_colors_processed)

    # Creates - in an error proof manner - the folder structure of the datapack
    with suppress(FileExistsError):
        os.makedirs(f"{path}/data/minecraft/tags/functions")
        os.makedirs(f"{path}/data/pixelart-map/functions")

    if minecraft_version >= '1.13.0':
        if minecraft_version >= '1.13.0' and minecraft_version <= '1.14.4':
            datapack_version = 4
        elif minecraft_version >= '1.15.0' & minecraft_version <= '1.16.1':
            datapack_version = 5
        elif minecraft_version >= '1.16.2' & minecraft_version <= '1.16.5':
            datapack_version = 6
        elif minecraft_version >= '1.17.0' & minecraft_version <= '1.17.1':
            datapack_version = 7
        elif minecraft_version >= '1.18.0' & minecraft_version <= '1.18.1':
            datapack_version = 8
        elif minecraft_version >= '1.18.2':
            datapack_version = 9
    else:
        datapack_version = 4
        raise ValueError("This versions is incompatible with datapacks (below 1.13.0) or the version is writen wrong (correct: x.xx.x | wrong: x.x, x.xx)")

    pack_mcmeta = {
        "pack": {
            "pack_format": datapack_version,
            "description": f"This datapack will generate the image ({image_name}) in your world",
        }
    }
    load_json = {"values": ["pixelart-map:load"]}
    tick_json = {"values": ["pixelart-map:tick"]}

    with open(f"{path}/pack.mcmeta", "w") as file:
        file.write(json.dumps(pack_mcmeta, indent=4))
    with open(f"{path}/data/minecraft/tags/functions/load.json", "w") as file:
        file.write(json.dumps(load_json, indent=4))
    with open(f"{path}/data/minecraft/tags/functions/tick.json", "w") as file:
        file.write(json.dumps(tick_json, indent=4))

    with open(f"{path}/data/pixelart-map/functions/tick.mcfunction", "w") as file:
        file.write("")

    # Making the commands that when ran will build the image's pixel art.
    # This part's had a huge contribution from this thread: https://stackoverflow.com/questions/70512775/how-to-group-elements-in-dataframe-by-row/70546452#70546452
    df = df.rename_axis(index="z", columns="x")

    a = list(
        script(
            df,
            player_x=player_pos[0],
            player_y=player_pos[1],
            player_z=player_pos[2],
        )
    )
    b = list(
        script(
            df.T,
            player_x=player_pos[0],
            player_y=player_pos[1],
            player_z=player_pos[2],
        )
    )
    res = min([a, b], key=len)
    with open(f"{path}/data/pixelart-map/functions/load.mcfunction", "w") as file:
        file.write("\n".join(res))


# coding=utf-8
from __future__ import absolute_import, division, print_function
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, Dataset
from util.custom_dataset import FaceLandmarksDataset, Rescale, ToTensor
import torchvision.models as models
from torchvision import transforms
import torch.nn.functional as F
import numpy as np
import matplotlib.pyplot as plt
from torchvision import transforms, utils
import torchvision

class View(nn.Module):
    def __init__(self, shape):
        super(View, self).__init__()
        self.shape = shape

    def forward(self, x):
        return x.view(*self.shape)

class InnerSum(nn.Module):
    def __init__(self):
        super(InnerSum, self).__init__()
    def forward(self, x):
        y = torch.zeros_like(x)
        for i in range(x.size(0)):
            y[i] = x[i].mul(x[i])
        if len(y.shape) == 3:
            return y.sum(2)
        else:
            return y.sum(1)

class ACNN(nn.Module):
    def __init__(self):
        super(ACNN, self).__init__()
        self.inner = InnerSum()
        self.pretrain = models.vgg16(pretrained=True).features[:28]
        self.VGG16 = self.pretrain[:21]
        self.PG_base = nn.Sequential(nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.BatchNorm2d(512), nn.ReLU(),
                                     nn.Conv2d(512, 512, kernel_size=3, padding=1), nn.BatchNorm2d(512), nn.ReLU(),)
        self.PG_attention = nn.Sequential(nn.MaxPool2d(2, stride=2), nn.Conv2d(512, 128, kernel_size=3, padding=1),
                                          nn.BatchNorm2d(128), nn.ReLU(), nn.AdaptiveAvgPool2d((1, 1)), View((-1, 128)),
                                          nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid())
        self.GG_base = self.pretrain[21:]
        self.GG_attention = nn.Sequential(nn.MaxPool2d(2, stride=2), nn.Conv2d(512, 128, kernel_size=3, padding=1),
                                          nn.BatchNorm2d(128), nn.ReLU(), nn.AdaptiveAvgPool2d((1, 1)), View((-1, 128)),
                                          nn.Linear(128, 64), nn.ReLU(), nn.Linear(64, 1), nn.Sigmoid())
        self.PG24_base = nn.ModuleList([self.PG_base for _ in range(24)])
        self.PG24_alpha = nn.ModuleList([self.PG_attention for _ in range(24)])

        self.pad = nn.ReflectionPad2d(6)
        # self.crop = batch_slice(40, 40, 6, 6)
        self.crop = torchvision.ops.roi_pool
        self.PG_fc = nn.Linear(512*6*6, 64)
        self.GG_fc = nn.Linear(512*14*14, 512)
        self.fc1 = nn.Linear(2048, 1024)
        self.dropout = nn.Dropout(0.5)
        self.fc2 = nn.Linear(1024, 7)

    # def crop_layer(self, img: '(B, C, H, W)', landmarks: '(B, 24, 2)'):
    #     # device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    #     pad = nn.ReflectionPad2d(6)  # padding for cropping
    #     img = pad(img)  # (B, 512, 36, 36)
    #     total_crop = torch.zeros((img.size(0), landmarks.size(1), 512, 6, 6), device=self.device)
    #
    #     for i in range(landmarks.size(0)):  # Batch
    #         # crop_per_batch = []
    #         for patch in range(landmarks.size(1)):  # 24 landmarks
    #             total_crop[i, patch, :, :, :] = img[i, :, (int(landmarks[i, patch, 0]) - 3): (int(
    #                 landmarks[i, patch, 0]) + 3),
    #                                             (int(landmarks[i, patch, 1]) - 3): (int(
    #                                                 landmarks[i, patch, 1]) + 3)]  # crop_img: (512, 6, 6)
    #
    #     total_crop = total_crop.permute(1, 0, 2, 3, 4)  # output: (24, B, 512, 6, 6)
    #     return total_crop

    def _branch24(self, crop_img):
        PG_out = []
        for x, base, alpha in zip(crop_img, self.PG24_base, self.PG24_alpha):
            PG_conv2 = base(x)
            PG_reshape = PG_conv2.view(-1, 512*6*6)
            PG_reshape = self.PG_fc(PG_reshape)
            PG_per = PG_reshape * alpha(PG_conv2).view(x.size(0), 1)
            PG_out.append(PG_per)
        return PG_out

    def forward(self, img, landmarks):
        img_feature = self.VGG16(img)  # (B, 512, 28, 28)
        img_pad = self.pad(img_feature)
        # landmarks = landmarks.long()
        crop_img = self.crop(img_pad, landmarks, output_size=(6, 6))
        crop_img = crop_img.view(24, -1, 512, 6, 6)

        GG_conv2 = self.GG_base(img_feature)
        GG_reshape = GG_conv2.view(-1, 512*14*14)
        GG_reshape = self.GG_fc(GG_reshape)
        GG_out = GG_reshape * self.GG_attention(GG_conv2).view(img_feature.size(0), 1)

        # crop_img = self.crop_layer(img_feature, landmarks)
        PG_out = self._branch24(crop_img)
        PG_total = torch.cat(PG_out, dim=1)
        total_out = torch.cat([GG_out, PG_total], dim=1)

        out = self.fc1(total_out)
        out = F.relu(self.dropout(out))
        out = self.fc2(out)
        return out

def landmark_resize(landmarks:'(B, 24, 2)')->'(B*24, 4)':
    bs = landmarks.size(0)
    batch = list(range(bs))
    batch = np.array(batch * 24).reshape(24, -1).T

    point = np.array(list(range(24)) * bs).reshape(bs, -1)
    insert_point = np.insert(landmarks, 0, point, 2)
    insert_batch = np.insert(insert_point, 0, batch, 2)
    new_landmark = insert_batch.reshape(-1, 4)
    return new_landmark

def data_normal(origin_data, size):  # (-1, 1)
    size = size / 2
    norm_data = origin_data.true_divide(size) - 1
    return norm_data

def grid_field(landmarks, cropsize=6):  # landmarks: (B, 24, 2)
    total_crop = []
    landmarks = landmark_resize(landmarks)  # (B*24, 4)
    lm_batch = landmarks[:, 0].long()
    landmarks_x_l = landmarks[:, 2] - (cropsize / 2)
    landmarks_x_r = landmarks[:, 2] + (cropsize / 2)
    landmarks_y_l = landmarks[:, 3] - (cropsize / 2)
    landmarks_y_r = landmarks[:, 3] + (cropsize / 2)

    for i in range(landmarks.size(0)):
        new_h = torch.linspace(landmarks_x_l[i], landmarks_x_r[i] - 1, cropsize).view(-1, 1).repeat(1, cropsize)
        new_w = torch.linspace(landmarks_y_l[i], landmarks_y_r[i] - 1, cropsize).repeat(cropsize, 1)
        grid = torch.cat((new_w.unsqueeze(2), new_h.unsqueeze(2)), dim=2)
        grid = grid.unsqueeze(0)
        grid = data_normal(grid, size=28)
        total_crop.append(grid)
    total_crop = torch.cat(total_crop, dim=0)
    return lm_batch, total_crop

def roi_select(landmarks: '(B, 4, 2)') -> '(B*24, 5)':
    landmarks = landmark_resize(landmarks)
    landmarks_right = landmarks[:, 2:] + 3
    landmarks_left = landmarks[:, 2:] - 3
    landmarks = torch.cat([landmarks[:, 0].view(-1, 1), landmarks_left, landmarks_right], dim=1)

    return landmarks

# if __name__ == '__main__':
#     model = ACNN()
#     shuffle = False
#     device = torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
#     model.to(device)
#     train_set = FaceLandmarksDataset(csv_file='train_acnn.csv', root_dir='original/',
#                                      transform=ToTensor())
#     test_set = FaceLandmarksDataset(csv_file='test_acnn.csv', root_dir='original/',
#                                     transform=ToTensor())
#     train_loader = DataLoader(dataset=train_set, shuffle=shuffle, batch_size=4, num_workers=0,
#                               pin_memory=True)
#     test_loader = DataLoader(dataset=test_set, shuffle=shuffle, batch_size=4, num_workers=8,
#                              pin_memory=True)
#     for step, batch in enumerate(train_loader):
#         imgs, landmarks, targets = batch['image'], batch['landmarks'] / 8. + 6, batch['label']
#         landmarks = roi_select(landmarks)
#
#         imgs, landmarks, targets = imgs.to(device), landmarks.to(device), targets.to(device)
#         logits = model(imgs, landmarks)
#         print(logits.size())
#         break


import sys
import socket
import platform
import psutil
import wmi
import urllib.request
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QTextEdit, QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QColor

class App(QMainWindow):
    def __init__(self, app):
        super().__init__()
        self.app = app
        self.initUI()

    def initUI(self):
        self.setWindowTitle('App')
        self.setGeometry(200, 200, 800, 600)

        central_widget = QWidget(self)
        self.setCentralWidget(central_widget)

        layout = QVBoxLayout()

        self.text_output = QTextEdit(self)
        self.text_output.setFont(QFont("Arial", 12))
        layout.addWidget(self.text_output)

        button_ipv4_info = QPushButton('Get My IPv4', self)
        button_proxy_info = QPushButton('Check Proxy Info', self)
        button_system_info = QPushButton('Retrieve System Info', self)
        button_bios_info = QPushButton('Fetch BIOS Info', self)
        button_hostname_info = QPushButton('Get Hostname', self)

        button_ipv4_info.setFont(QFont("Arial", 10))
        button_proxy_info.setFont(QFont("Arial", 10))
        button_system_info.setFont(QFont("Arial", 10))
        button_bios_info.setFont(QFont("Arial", 10))
        button_hostname_info.setFont(QFont("Arial", 10))

        button_ipv4_info.setStyleSheet("background-color: lightblue;")
        button_proxy_info.setStyleSheet("background-color: lightgreen;")
        button_system_info.setStyleSheet("background-color: lightcoral;")
        button_bios_info.setStyleSheet("background-color: lightsalmon;")
        button_hostname_info.setStyleSheet("background-color: lightyellow;")

        layout.addWidget(button_ipv4_info)
        layout.addWidget(button_proxy_info)
        layout.addWidget(button_system_info)
        layout.addWidget(button_bios_info)
        layout.addWidget(button_hostname_info)

        central_widget.setLayout(layout)

        button_ipv4_info.clicked.connect(self.fetch_ipv4_info)
        button_proxy_info.clicked.connect(self.check_proxy_info)
        button_system_info.clicked.connect(self.retrieve_system_info)
        button_bios_info.clicked.connect(self.fetch_bios_info)
        button_hostname_info.clicked.connect(self.get_host_name)

    def fetch_ipv4_info(self):
        hostname = socket.gethostname()
        ip = socket.gethostbyname(hostname)
        is_static = socket.gethostbyaddr(ip)
        interface = None
        if "Wi-Fi" in platform.platform():
            interface = "Wi-Fi"
        elif "Ethernet" in platform.platform():
            interface = "Ethernet"
        result = f"IPv4 Address: {ip}\nStatic: {is_static}\nNetwork Interface: {interface}"
        self.text_output.append(result)

    def check_proxy_info(self):
        proxy_handler = urllib.request.ProxyHandler()
        opener = urllib.request.build_opener(proxy_handler)

        try:
            opener.open("http://www.google.com", timeout=5)
            is_proxy_enabled = True
        except Exception:
            is_proxy_enabled = False

        proxy_status = "Proxy is enabled" if is_proxy_enabled else "Proxy is disabled"
        self.text_output.append(proxy_status)

    def retrieve_system_info(self):
        os_version = platform.platform()
        os_architecture = platform.architecture()
        num_cores = psutil.cpu_count(logical=False)
        ram = round(psutil.virtual_memory().total / (1024 ** 3), 2)
        result = f"Operating System Version: {os_version}\nArchitecture: {os_architecture}\nCPU Cores: {num_cores}\nRAM: {ram} GB"
        self.text_output.append(result)

    def fetch_bios_info(self):
        c = wmi.WMI()
        bios = c.Win32_BIOS()[0]
        result = f"BIOS Manufacturer: {bios.Manufacturer}\nBIOS Version: {bios.Version}\nBIOS Release Date: {bios.ReleaseDate}"
        self.text_output.append(result)

    def get_host_name(self):
        hostname = socket.gethostname()
        self.text_output.append(f"Hostname: {hostname}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = App(app)
    window.show()
    sys.exit(app.exec_())


import unittest
from pathlib import Path

from tests import CdsTestMixin
from . import CDSCase

class DumpTest(CdsTestMixin, unittest.TestCase):
    def test_trace_json(self):
        with CDSCase(self, self.NAME_LIST, self.TEST_ARCHIVE) as cds:
            cds.run_trace('import json')
            cds.verify_files(check_archive=False)

            cds.verify(lambda _: self.assertIn(
                'json',
                [line.strip() for line in Path(self.NAME_LIST).read_text().split('\n')]))

    def test_dump_archive_from_list_json(self):
        with open(self.NAME_LIST, 'w') as f:
            print('json', file=f)

        with CDSCase(self, self.NAME_LIST, self.TEST_ARCHIVE, clear_list=False) as cds:
            cds.run_dump()


import os
import re
import spotipy
from moviepy.editor import *
from urllib.parse import quote
from urllib import request as rq
from youtube_dl import YoutubeDL
from spotipy.oauth2 import SpotifyClientCredentials

## fix to skip use for PYTHONPATH
sys.path.append(os.getcwd())
sys.path.append(os.path.join(os.getcwd(),"..","common"))

from common.common import controller_common
common = controller_common()

class controller_spotify:

    def __init__(self,client_api,token_api,user):

        self.__CLIENT_ID = client_api
        self.__CLIENT_SECRET = token_api
        self.__USER_ID = user

        self.auth_manager = SpotifyClientCredentials(
            client_id=self.__CLIENT_ID, client_secret=self.__CLIENT_SECRET
        )
        self.sp = spotipy.Spotify(auth_manager=self.auth_manager)

    def get_ydl_opts(self, path):
        return {
            "format": "bestaudio/best",
            "outtmpl": f"{path}/%(id)s.%(ext)s",
            "ignoreerrors": True,
            "postprocessors": [
                {
                    "key": "FFmpegExtractAudio",
                    "preferredcodec": "mp3",
                    "preferredquality": "320",
                }
            ],
        }

    def get_user_playlists(self):
        return [
            {"value": pl.get("uri"), "name": pl.get("name")}
            for pl in self.sp.user_playlists(self.__USER_ID).get("items")
        ]

    def normalize_str(self, string):
        return string.translate(str.maketrans('\\/:*?"<>|', "__       "))

    def get_playlist_details(self, pl_uri):
        offset = 0
        fields = "items.track.track_number,items.track.name,items.track.artists.name,items.track.album.name,items.track.album.release_date,total,items.track.album.images"
        pl_name = self.sp.playlist(pl_uri)["name"]
        pl_items = self.sp.playlist_items(
            pl_uri,
            offset=offset,
            fields=fields,
            additional_types=["track"],
        )["items"]

        pl_tracks = []
        while len(pl_items) > 0:
            for item in pl_items:
                if item["track"]:
                    track_name = self.normalize_str(item["track"]["name"])
                    artist_name = self.normalize_str(
                        item["track"]["artists"][0]["name"]
                    )
                    pl_tracks.append(
                        {
                            "uri": quote(
                                f'{track_name.replace(" ", "+")}+{artist_name.replace(" ", "+")}'
                            ),
                            "file_name": f"{artist_name} - {track_name}",
                            "track_name": track_name,
                            "artist_name": artist_name,
                            "album_name": self.normalize_str(
                                item["track"]["album"]["name"]
                            ),
                            "album_date": item["track"]["album"]["release_date"],
                            "track_number": item["track"]["track_number"],
                            "album_art": item["track"]["album"]["images"][0]["url"],
                        }
                    )

            offset = offset + len(pl_items)
            pl_items = self.sp.playlist_items(
                pl_uri,
                offset=offset,
                fields=fields,
                additional_types=["track"],
            )["items"]

        return {"pl_name": pl_name, "pl_tracks": pl_tracks}

    def check_existing_tracks(self, playlist, path):
        existing_tracks = os.listdir(path)
        tracks = [
            track
            for track in playlist["pl_tracks"]
            if f"{track['file_name']}.mp3" not in existing_tracks
        ]
        return tracks

    def download_tracks(self, pl_uri):

        count = 0
        items = list()

        pl_details = self.get_playlist_details(pl_uri)
        path = common.create_download_directory(pl_details["pl_name"])
        tracks = self.check_existing_tracks(pl_details, path)
        print(
            f"\n\033[1m\033[33m[info] Downloading {len(tracks)} tracks from {pl_details['pl_name']}\033[0m"
        )
        with YoutubeDL(self.get_ydl_opts(path)) as ydl:
            for track in tracks:
                html = rq.urlopen(
                    f"https://www.youtube.com/results?search_query={track['uri']}"
                )
                video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())

                if video_ids:
                    url = "https://www.youtube.com/watch?v=" + video_ids[0]

                    print ( f"Add [{count}] - {url}" )
                    count = count + 1
                    items.append(url)

        res = common.thread_pool(items,path,"download")

        if res:
            common.converterto_mp3(pl_details["pl_name"])


#the code partial borrowed from
# "Neural Network-based Reconstruction in Compressed Sensing
#MRI Without Fully-sampled Training Data"

import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F
import util_torch as util_torch
def absval(arr):
    """
    Takes absolute value of last dimension, if complex.
    Input dims:  (N, l, w, 2)
    Output dims: (N, l, w)
    """
    # Expects input of size (N, l, w, 2)
    assert arr.shape[-1] == 2
    return torch.norm(arr, dim=3)

def scale(y, y_zf):
    """Scales inputs for numerical stability"""
    flat_yzf = torch.flatten(absval(y_zf), start_dim=1, end_dim=2)
    max_val_per_batch, _ = torch.max(flat_yzf, dim=1, keepdim=True)
    y = y / max_val_per_batch.view(len(y), 1, 1, 1)
    y_zf = y_zf / max_val_per_batch.view(len(y), 1, 1, 1)
    return y, y_zf

class Upsample(nn.Module):
    """Upsamples input multi-channel image"""
    def __init__(self, scale_factor, mode, align_corners):
        super(Upsample, self).__init__()
        self.scale_factor = scale_factor
        self.mode = mode
        self.align_corners = align_corners
    def forward(self, x):
        return F.interpolate(x, scale_factor=self.scale_factor, mode=self.mode, align_corners=self.align_corners)

class ResBlock(nn.Module):
    '''5-layer CNN with residual output'''
    def __init__(self, n_ch_in=2, n_ch_out=2, nf=64, ks=3):

        super(ResBlock, self).__init__()
        self.n_ch_out = n_ch_out

        self.conv1 = nn.Conv2d(n_ch_in, nf, ks, padding = ks//2)
        self.conv2 = nn.Conv2d(nf, nf, ks, padding = ks//2)
        self.conv3 = nn.Conv2d(nf, nf, ks, padding = ks//2)
        self.conv4 = nn.Conv2d(nf, nf, ks, padding = ks//2)
        self.conv5 = nn.Conv2d(nf, n_ch_out, ks, padding = ks//2)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        conv1_out = self.conv1(x)
        conv1_out = self.relu(conv1_out)

        conv2_out = self.conv2(conv1_out)
        conv2_out = self.relu(conv2_out)

        conv3_out = self.conv3(conv2_out)
        conv3_out = self.relu(conv3_out)

        conv4_out = self.conv4(conv3_out)
        conv4_out = self.relu(conv4_out)

        conv5_out = self.conv5(conv4_out)

        x_res = x[:,:self.n_ch_out,:,:] + conv5_out
        return x_res

class Net(nn.Module):
    def __init__(self, K, lmbda, device, n_hidden=64):
        super(Net, self).__init__()

        #self.mask = mask
        self.lmbda = lmbda
        self.resblocks = nn.ModuleList()
        self.device = device

        for i in range(K):
            resblock = ResBlock(n_ch_in=2, nf=n_hidden)
            self.resblocks.append(resblock)

        self.block_final = ResBlock(n_ch_in=2, nf=n_hidden)

    def forward(self, ksp_input, sensemap, window = 1, mask = None):

        if mask is None:
           mask=torch.not_equal(ksp_input, 0)
           dtype=torch.complex64
           mask = mask.type(dtype)
        x = util_torch.transpose_model(ksp_input * window, sensemap)
        x = util_torch.complex_to_channels(x)#;print(x.shape);quit()
        #ksp_input, x = scale(ksp_input, x)
        for i in range(len(self.resblocks)):
            # z-minimization
            x = x.permute(0, 3, 1, 2)

            z = self.resblocks[i](x)
            z = z.permute(0, 2, 3, 1)
            z = util_torch.channels_to_complex(z)
            # x-minimization
            #z_ksp = utils.fft(z)
            z_ksp = util_torch.model_forward(z, sensemap)
            #x_ksp = losslayer.data_consistency(z_ksp, y, self.mask, self.lmbda)
            x_ksp = (1 - mask) * z_ksp + mask * (self.lmbda*z_ksp + ksp_input) / (1 + self.lmbda)
            #x = utils.ifft(x_ksp)
            x = util_torch.transpose_model(x_ksp, sensemap)
            x = util_torch.complex_to_channels(x)
        x = x.permute(0, 3, 1, 2)
        x = self.block_final(x)
        return x


import json as js
import csv
import sys
import jinja2
import os
from datetime import datetime
# import smtplib

# read customers file to get information about customers
def get_customers(customers_file, error):
    TITLE = []
    FIRST_NAME = []
    LAST_NAME = []
    EMAIL = []

    with open(customers_file, mode='r') as csv_file:
        customers = csv.DictReader(csv_file, delimiter=',')
        errorData = []
        for customer in customers:
            if customer["EMAIL"] != '':
                TITLE.append(customer["TITLE"])
                FIRST_NAME.append(customer["FIRST_NAME"])
                LAST_NAME.append(customer["LAST_NAME"])
                EMAIL.append(customer["EMAIL"])
            else:
                errorData.append([customer["TITLE"], customer["FIRST_NAME"], customer["LAST_NAME"], customer["EMAIL"]])
        with open(error, mode='w', newline='') as f:
            errorCustomer = csv.writer(f)
            errorCustomer.writerow(['TITLE','FIRST_NAME','LAST_NAME','EMAIL'])
            for customer in errorData:
                errorCustomer.writerow(customer)

    return TITLE, FIRST_NAME, LAST_NAME, EMAIL

def read_template(email_template_file):
    with open(email_template_file, mode='r') as email_template:
        template = js.load(email_template)
    return template

# Can use CLI Python Library to parse agv from CMD such as argparse, getopt,...
def main(email_template, customers, path_output_emails, error):
    # how to use smtp send email
    # s = smtplib.SMTP(host='host_address', port=port)
    # s.starttls()
    # s.login(MY_ADDRESS, PASSWORD)
    TITLE, FIRST_NAME, LAST_NAME, EMAIL = get_customers(customers, error)
    template = read_template(email_template)
    if os.path.isdir(path_output_emails):
        os.chdir(path_output_emails)
    else:
        os.mkdir(path_output_emails)
        os.chdir(path_output_emails)

    now = datetime.now()
    env = jinja2.Environment()
    outputJsonFile = open("output.json", "w")
    resultData = []
    for title, first_name, last_name, email in zip(TITLE, FIRST_NAME, LAST_NAME, EMAIL):
        data = {}
        body_template = env.from_string(template["body"])
        data["from"] = template["from"]
        data["to"] = email
        data["subject"] = template["subject"]
        data["mineType"] = template["mineType"]
        data["body"] = body_template.render(TITLE=title, FIRST_NAME=first_name, LAST_NAME=last_name, TODAY=now.strftime('%d %b %Y'))
        resultData.append(data)
        # s.send_message(data)
        # del data
    output = js.dumps(resultData, indent=4)
    outputJsonFile.write(output)
    outputJsonFile.close()

if __name__ == '__main__':
    main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])


import numpy as np
import scipy.ndimage
import scipy.misc
import glob
import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

def loadPsf(psftype, fileformat):
    path='/gdata/zhoutk/Deconv/'+psftype
    files=glob.glob(path+'/'+'*'+fileformat)
    length=len(files)
    if length==0:
        print(path+'/')
        print('invalid psf file path')
        return
    im0=scipy.misc.imread(files[0])
    shape=im0.shape
    psf=np.zeros((length, shape[0], shape[1]))
    files.sort()
    for i, file in enumerate(files):
        #print(file)
        psf[i,:,:]=scipy.misc.imread(file)
        #print(type(psf))
        #print(psf.shape)
    return psf

def convolvePsf3D(volumn, psf, psnr):
    ##normalize with its largest content
    psf=psf/np.sum(psf)
    #change from int8 to float64
    volumn=volumn.astype('float64')
    #convolve psf with volumn
    #print(volumn.shape)
    #print(psf.shape)
    print('max_volumn: ', np.max(volumn))
    #volumn=scipy.ndimage.zoom(volumn, 2.0)
    if torch.cuda.is_available():
        psf=psf[:99, :, :]
        for i in range(len(psf.shape)):
            psf=np.flip(psf, i)
        psf=torch.from_numpy(psf.copy()).unsqueeze(0).unsqueeze(0).type(torch.FloatTensor).cuda()
        psf=Variable(psf, requires_grad=False)
        volumn=torch.from_numpy(volumn.copy()).unsqueeze(0).unsqueeze(0).type(torch.FloatTensor).cuda()
        volumn=Variable(volumn, requires_grad=False)
        output=F.conv3d(volumn, psf, padding=(49, 12, 12))
        output=output.squeeze().cpu().data.numpy()
    else:
        output=scipy.ndimage.filters.convolve(volumn, psf, mode='constant')
    print('convolve output shape: ', output.shape)
    print('max_output: ', np.max(output))
    #noise level --- gaussian noise
    sigma=np.max(output)/np.power(10, psnr/20)
    print('gaussian noise level:', sigma)
    noise=np.random.normal(0, sigma, output.shape)
    #add noise to the output
    output=np.clip(output+noise, 0, np.max(output))
    #output=output[0:101,0:101,0:101]
    return output


# -*- coding:utf-8 -*-
from PySide2.QtCore import Signal
from PySide2.QtWidgets import QDialog
from core.options import MultiOption
from ui.base.constants import ITEM_SEPARATORS
from ui.base.ui_add_items import Ui_AddItemsDialog
# noinspection PyTypeChecker
from utils import warn, splitItems, isEmpty

# noinspection PyTypeChecker
class AddItemsDialog(QDialog, Ui_AddItemsDialog):
    ADD_EXCLUDE_MODULES = 0
    ADD_HIDDEN_IMPORTS = 1
    COLLECT_ALL_SUBMODULES = 3
    COLLECT_ALL_DATA = 4
    COLLECT_ALL_BINARIES = 5
    COLLECT_ALL = 6
    COPY_METADATA = 7
    DEEP_COPY_METADATA = 8

    DEFAULT_ITEMS_SEP = ";"

    itemsAdded = Signal(MultiOption, list)

    def __init__(self, parent):
        super().__init__(parent)
        self._action = -1
        self._option = None
        self.setupUi()

    def setupUi(self, _=None):
        super(AddItemsDialog, self).setupUi(self)
        self.multiItemSeparatorCombo.addItems(ITEM_SEPARATORS.keys())
        self.addButton.clicked.connect(self.onAddItem)

    def onAddItem(self):
        content = self.itemsEdit.toPlainText().replace("\n", "").replace("\r", "").strip()
        if isEmpty(content):
            warn(self, self.tr(u"Warning"), self.tr("Items cannot be empty!"))
            return
        content = content.replace("；", ";").replace("，", ",")
        sepKey = self.multiItemSeparatorCombo.currentText()
        items = splitItems(content, sepKey, self.DEFAULT_ITEMS_SEP)
        self.itemsAdded.emit(self._option, items)
        self.accept()

    def display(self, action, option):
        self._action = action
        self._option = option
        self.updateTitle()
        self.show()

    def updateTitle(self):
        if self._action == self.ADD_EXCLUDE_MODULES:
            self.setWindowTitle(self.tr("Add Exclude Modules"))
        elif self._action == self.ADD_HIDDEN_IMPORTS:
            self.setWindowTitle(self.tr("Add Hidden Imports"))
        elif self._action == self.COLLECT_ALL_SUBMODULES:
            self.setWindowTitle(self.tr("Collect all submodules from:"))
        elif self._action == self.COLLECT_ALL_DATA:
            self.setWindowTitle(self.tr("Collect all data from:"))
        elif self._action == self.COLLECT_ALL_BINARIES:
            self.setWindowTitle(self.tr("Collect all binaries from:"))
        elif self._action == self.COLLECT_ALL:
            self.setWindowTitle(self.tr("Collect all(submodules,data, bin...) from:"))
        elif self._action == self.COPY_METADATA:
            self.setWindowTitle(self.tr("Copy metadata for:"))
        elif self._action == self.DEEP_COPY_METADATA:
            self.setWindowTitle(self.tr("Copy metadata for(recursively):"))
        else:
            raise ValueError("unknown action")

    def hideEvent(self, event):
        super().hideEvent(event)
        self._action = -1
        self._option = None
        self.setWindowTitle("")
        self.itemsEdit.setText("")


import numpy as np
from .utils import LinearAnnealer,ExponentialAnnealer
import tqdm
import torch
import torch.nn as nn
import wandb
from progress.bar import Bar
from array2gif import write_gif
import copy
from .utils import set_seed
from .utils import save_rewards_meanvar_plot,get_logger,MLP,ReplayMemory
import logging
import time
from torch.distributions.categorical import Categorical

# With spinning up help ;)

class VPG:
    def __init__(self, env, config):
        for k, v in config.items():
            setattr(self, k, v)
        print(config)
        self.env = env
        self.config = copy.deepcopy(config)
        self.reset(self.seed)

    def reset(self, seed):
        self.seed = seed
        set_seed(self.seed)
        self.env.seed(self.seed)
        self.env.action_space.seed(self.seed)
        obs_size = self.env.observation_space.n if 'n' in self.env.observation_space.__dict__ else self.env.observation_space._shape[0]
        self.policy = MLP(self.nUnits, obs_size,self.env.action_space.n).to(self.device)

        self.optimizer = torch.optim.Adam(self.policy.parameters(), lr=self.lr)

    def get_policy(self,s):
        return Categorical(logits=self.policy(s))

    def get_action(self,s):
        return self.get_policy(s).sample()

    def update_net(self,ep_mem):

        def r_to_go(rewards):
            return torch.cumsum(rewards.flip(dims=[0]),dim=0).flip(dims=[0])

        s = torch.stack([exp.s for exp in ep_mem.memory])
        a = torch.stack([exp.a for exp in ep_mem.memory])
        r = torch.stack([exp.r for exp in ep_mem.memory])
        r = r_to_go(r)
        self.optimizer.zero_grad()
        ep_loss = -(self.get_policy(s).log_prob(a) * r).mean()
        ep_loss.backward()
        self.optimizer.step()
        return ep_loss

    def train(self):
        bar = Bar('{}'.format('Training'), max=self.nepisodes)
        self.logger = get_logger("VPG",self.env.spec.name)

        episode_rewards = []
        eval_rewards = []

        n_experience = 0
        last_eval_mean = 0
        last_eval_std = 0
        step = 0

        for ep in (range(self.nepisodes)):
            self.policy.train()
            replaymem = ReplayMemory(10000,1)
            state = self.env.reset(seed=self.seed)
            ep_reward = 0
            for t in range(1,self.max_steps):

                action = self.get_action(torch.tensor(state).unsqueeze(0).float())
                new_state, reward, done, info = self.env.step(action.item())

                ep_reward += reward
                replaymem.add_exp(torch.tensor(state).unsqueeze(0).float(),action,reward,torch.tensor(new_state).unsqueeze(0).float(),int(done))

                state = new_state

                step += 1
                if done:
                    break

            self.update_net(replaymem)

            if self.num_eval_episodes > 0 and ((ep % self.eval_freq )==0):
                temp_eval_rewards = []
                for _ in range(self.num_eval_episodes):
                    temp_eval_rewards.append(self.evaluate())
                last_eval_mean = np.mean(temp_eval_rewards)
                last_eval_std = np.std(temp_eval_rewards)
                eval_rewards.append(temp_eval_rewards)

            if self.use_wandb:
                wandb.log({"episode_reward": ep_reward,'eval_reward_mean':last_eval_mean,'eval_reward_std':last_eval_std})

            episode_rewards.append(ep_reward)
            ep_info =  ('Episode '+str(ep)+' reward: ' + str(ep_reward) + ' Mean r over last 20 episodes :' + str(np.mean(episode_rewards[-20:]).item())+' last eval mean,std  ' +str(last_eval_mean)+' '+str(last_eval_std))

            if "cart" in self.env.spec.name.lower() and np.mean(episode_rewards[-20:]).item() > 480:
                print("Solved cartpole exiting early")
                bar.finish()
                self.logger.info(ep_info)
                return eval_rewards, np.mean(episode_rewards[-30:]).item()

            self.logger.info( ep_info)
            Bar.suffix = ep_info
            bar.next()

        bar.finish()

        return eval_rewards, np.mean(episode_rewards[-30:]).item()

    def show_results(self):
        self.evaluate(save_gif=True)

    def evaluate(self,save_gif = False):
        self.policy.eval()
        state = self.env.reset(seed=self.seed)
        total_reward = 0
        frames = []
        for t in range(1,self.max_steps):

            action = self.get_action(torch.tensor(state).unsqueeze(0).float())
            new_state, reward, done, info = self.env.step(action.item())
            if save_gif:
                img = self.env.render(mode="rgb_array")
                frames.append(img)

            total_reward += reward
            state = new_state
            if done :
                break

        if save_gif:
            write_gif([np.transpose(f, axes=[2,0, 1]) for f in frames], 'gifs/vpg_'+self.env.spec.name+'.gif', fps=30)
        if self.use_wandb:
            wandb.log({"loss": total_reward})
        return total_reward


# -*- coding: utf-8 -*-
"""
Created on Sat Nov 10 17:30:55 2018

@author: Wioletta
"""
import cv2
from localbinarypatterns import LocalBinaryPatterns

img = cv2.imread('yaleB01_P00A+000E+00.pgm')

cv2.imshow('Image',img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

desc = LocalBinaryPatterns(24, 8)

hist = desc.describe(gray)

cv2.imshow('Histogram', hist)


from flask import Response
import json

from presentation.contracts import HttpController, HttpRequest

def adapt_route(flask_request, controller: HttpController):
    request = HttpRequest(
        params=flask_request.args,
        body=flask_request.json
    )
    data = controller.handle(request)
    return Response(
        json.dumps(data.body),
        status=data.status,
        mimetype='application/json'
    )
    try:
        request = HttpRequest(
            params=flask_request.args,
            body=flask_request.json
        )
        data = controller.handle(request)
        return Response(
            json.dumps(data.body),
            status=data.status,
            mimetype='application/json'
        )
    except Exception as e:
        return Response(
            json.dumps({"error": "Internal server error"}),
            status=500,
            mimetype='application/json'
        )


# -*- coding: utf-8 -*-
import time, functools

def metric(fn):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args,**kw):
            print(fn) if fn.__str__()==fn else print('no metric args')
            start_time=time.time()
            return (func(*args,**kw),print('%s executed in %s ms' % (func.__name__, time.time()-start_time)))[0]
        return wrapper
    return decorator if fn.__str__()==fn else decorator(fn)

@metric
def fast(x, y):
    time.sleep(0.0012)
    return x + y;

@metric('test')
def slow(x, y, z):
    time.sleep(0.1234)
    return x * y * z;

f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
    print('测试失败!')
elif s != 7986:
    print('测试失败!')
else:
    print('测试成功!')


import sys, json
from urllib.request import urlopen
from collections import OrderedDict

list_host = 'http://localhost:5000'
list_url = list_host + '/api/3/action/organization_list'
get_url = list_host + '/api/3/action/organization_show'

contents = urlopen(list_url)
org_list =  json.load(contents)['result']

for org_name in org_list:

    org_url = get_url + "?id=" + org_name
    print("=== Loading " +org_name + " from " + org_url)

    org_content = urlopen(org_url)
    org_obj = json.load(org_content)['result']

    org = OrderedDict()
    for key in ('name', 'title', 'description', 'site', 'email', 'region', 'identifier'):
        if key in org_obj and org_obj[key]:
            org[key] = org_obj[key]

    org_filename = "orgs/"+org_name+".json"
    with open(org_filename,"w+") as f:
        f.write(json.dumps(org, indent=4))

    print("=== Saved in "+org_filename+"\n")


# https://leetcode.com/problems/rotting-oranges/
"""
Time complexity:- O(N)
Space Complexity:- O(N)
"""

"""
Intuition:

The algorithm uses Breadth-First Search (BFS) to simulate the rotting process, starting from initially rotten oranges.
The queue (q) is used to keep track of the rotten oranges and their coordinates.
The process continues until either all fresh oranges are rotten or there are no more rotten oranges.
The time variable keeps track of the minutes passed during the rotting process.
If there are still fresh oranges after the simulation, it means some oranges cannot be rotten, and -1 is returned.
The algorithm follows a simple and intuitive approach of simulating the rotting process through BFS traversal.
"""
import collections
from typing import List

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        q = collections.deque()  # Using deque for efficient pop and append operations
        fresh = 0  # Counter for fresh oranges
        time = 0  # Variable to track time (minutes)

        # Iterate through the grid to identify fresh and rotten oranges
        for r in range(len(grid)):
            for c in range(len(grid[0])):
                if grid[r][c] == 1:
                    fresh += 1
                if grid[r][c] == 2:
                    q.append((r, c))  # Add coordinates of rotten oranges to the queue

        # Directions to check neighboring cells (up, down, left, right)
        directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]

        # BFS traversal to simulate rotting process
        while fresh > 0 and q:
            length = len(q)
            for i in range(length):
                r, c = q.popleft()  # Pop the front of the queue

                for dr, dc in directions:
                    row, col = r + dr, c + dc
                    # Check if the neighboring cell is in bounds and contains a fresh orange
                    if (
                        row in range(len(grid))
                        and col in range(len(grid[0]))
                        and grid[row][col] == 1
                    ):
                        grid[row][col] = 2  # Mark the orange as rotten
                        q.append((row, col))  # Add the coordinates to the queue
                        fresh -= 1  # Decrease the count of fresh oranges

            time += 1  # Increment time after processing each minute

        # Return the time required if all fresh oranges are rotten, otherwise return -1
        return time if fresh == 0 else -1


import copy
import functools
import os
import random
import torch
import torch.nn.functional as F
import blobfile as bf
import torchvision.utils as vutils
import numpy as np
import torch as th
import torch.distributed as dist
from torch.nn.parallel.distributed import DistributedDataParallel as DDP
from torch.optim import Adam
from ..models.unet.fp16_util import zero_grad
from tqdm  import tqdm
from ..utils import dist_util
import matplotlib.pyplot as plt
from .plotters import ImPlotter
from .config_getters import get_model

class IPFStepBase(th.nn.Module):
    def __init__(
        self,
        model,
        forward_diffusion,
        backward_diffusion,
        data_loader,
        prior_loader,
        cache_data_loader = None,
        args = None,
        forward_model = None,
        cache_loader = False,
        resume_checkpoint = 0,
        checkpoint_directory = './',
        plot_directory = './',
    ):

        super().__init__()

        self.set_seed(dist.get_rank()+0)
        ema_rate = args.ema_rate
        save_interval=args.save_interval
        lr_anneal_steps = 0
        self.args = args
        self.model = model
        self.forward_diffusion = forward_diffusion
        self.backward_diffusion = backward_diffusion

        self.forward_model = forward_model
        self.prior_loader = prior_loader
        self.data_loader = data_loader
        self.cache_data_loader = cache_data_loader

        self.num_steps = self.args.nit
        self.num_iter = self.args.num_iter
        self.lr_anneal_steps = lr_anneal_steps
        self.batch_size = self.args.batch_size
        self.cache_loader = cache_loader
        self.cache_refresh = self.args.cache_refresh_stride
        self.lr = self.args.lr
        self.classes = self.args.num_data_classes > 0
        self.weight_decay = self.args.weight_decay
        self.ema_rate = (
            [ema_rate]
            if isinstance(ema_rate, float)
            else [float(x) for x in ema_rate.split(",")]
        )
        self.save_interval = save_interval
        self.checkpoint_dir = checkpoint_directory
        self.plot_dir = plot_directory
        self.plotter = ImPlotter(im_dir=self.plot_dir, plot_level=1)

        self.step = 0
        self.resume_step = resume_checkpoint
        self.resume_checkpoint = resume_checkpoint
        self.global_batch = self.batch_size * dist.get_world_size()

        self.model_params = list(self.model.parameters())
        self.master_params = self.model_params
        self.sync_cuda = th.cuda.is_available()

        self._load_and_sync_parameters()

        # Optimizers
        self.opt = Adam(self.master_params, lr=self.lr)
        if self.resume_step:
            self._load_optimizer_state()
            # Model was resumed, either due to a restart or a checkpoint
            # being specified at the command line.
            self.ema_params = [
                self._load_ema_parameters(rate) for rate in self.ema_rate
            ]
        else:
            self.ema_params = [
                copy.deepcopy(self.master_params) for _ in range(len(self.ema_rate))
            ]

        if th.cuda.is_available():
            self.use_ddp = True
            self.ddp_model = DDP(
                self.model,
                device_ids=[dist_util.dev()],
                output_device=dist_util.dev(),
                broadcast_buffers=False,
                bucket_cap_mb=128,
                find_unused_parameters=False,
            )
        else:
            if dist.get_world_size() > 1:
                self.use_ddp = False
                self.ddp_model = self.model

    def _load_and_sync_parameters(self):
        resume_checkpoint = find_resume_checkpoint() or self.resume_checkpoint

        if resume_checkpoint:
            self.resume_step = parse_resume_step_from_filename(resume_checkpoint)
            if dist.get_rank() == 0:
                self.model.load_state_dict(
                    dist_util.load_state_dict(
                        resume_checkpoint, map_location=dist_util.dev()
                    )
                )

        dist_util.sync_params(self.model.parameters())

    def _load_ema_parameters(self, rate):
        ema_params = copy.deepcopy(self.master_params)

        main_checkpoint = find_resume_checkpoint() or self.resume_checkpoint
        ema_checkpoint = find_ema_checkpoint(main_checkpoint, self.resume_step, rate)
        if ema_checkpoint:
            if dist.get_rank() == 0:
                state_dict = dist_util.load_state_dict(
                    ema_checkpoint, map_location=dist_util.dev()
                )
                ema_params = self._state_dict_to_master_params(state_dict)

        dist_util.sync_params(ema_params)
        return ema_params

    def _load_optimizer_state(self):
        main_checkpoint = find_resume_checkpoint() or self.resume_checkpoint
        opt_checkpoint = bf.join(
            bf.dirname(main_checkpoint), f"opt{self.resume_step:06}.pt"
        )
        if bf.exists(opt_checkpoint):
            state_dict = dist_util.load_state_dict(
                opt_checkpoint, map_location=dist_util.dev()
            )
            self.opt.load_state_dict(state_dict)

    def optimize_step(self):
        #self._anneal_lr()
        # if self.args.grad_clipping:
        #     clipping_param = self.args.grad_clip
        #     total_norm = torch.nn.utils.clip_grad_norm_(self.model.parameters(), clipping_param)
        self.opt.step()
        for rate, params in zip(self.ema_rate, self.ema_params):
            update_ema(params, self.master_params, rate=rate)

    def _anneal_lr(self):
        if not self.lr_anneal_steps:
            return
        frac_done = (self.step + self.resume_step) / self.lr_anneal_steps
        lr = self.lr * (1 - frac_done)
        for param_group in self.opt.param_groups:
            param_group["lr"] = lr

    def save(self):
        if dist.get_rank() == 0:
            self.set_seed(0)
            init_samples, labels = next(self.prior_loader)
            init_samples = init_samples.to(dist_util.dev())
            labels = labels.to(dist_util.dev()) if labels is not None else None

            sample_model = get_model(self.args)
            for rate, params in zip(self.ema_rate, self.ema_params):
                state_dict = self._master_params_to_state_dict(params)
                sample_model.load_state_dict(state_dict)
                sample_model = sample_model.to(dist_util.dev())
                x_tot_plot = self.backward_diffusion.sample(init_samples, labels, t_batch=None, net=sample_model)
                filename = 'ema{0}_step{1}.png'.format(rate, self.step)
                self.plotter.plot(init_samples, x_tot_plot, filename)
            sample_model = None
            torch.cuda.empty_cache()

            # init_samples, labels = next(self.data_loader)
            # init_samples = init_samples.to(dist_util.dev())
            # labels = labels.to(dist_util.dev()) if labels is not None else None
            # x_tot_plot = self.forward_diffusion.sample(init_samples, labels, t_batch=None, net=self.forward_model)
            # filename = 'sample{0}_step{1}.png'.format(rate, self.step)
            # self.plotter.plot(init_samples, x_tot_plot, filename)

        def save_checkpoint(rate, params):

            state_dict = self._master_params_to_state_dict(params)
            if dist.get_rank() == 0:
                if not rate:
                    filename = f"model{(self.step+self.resume_step):06d}.pt"
                else:
                    filename = f"ema_{rate}_{(self.step+self.resume_step):06d}.pt"
                with bf.BlobFile(bf.join(self.checkpoint_dir, filename), "wb") as f:
                    th.save(state_dict, f)

        save_checkpoint(0, self.master_params)
        for rate, params in zip(self.ema_rate, self.ema_params):
            save_checkpoint(rate, params)

        if dist.get_rank() == 0:
            with bf.BlobFile(
                bf.join(self.checkpoint_dir, f"opt{(self.step+self.resume_step):06d}.pt"),
                "wb",
            ) as f:
                th.save(self.opt.state_dict(), f)

        dist.barrier()

    def _master_params_to_state_dict(self, master_params):
        state_dict = self.model.state_dict()
        for i, (name, _value) in enumerate(self.model.named_parameters()):
            assert name in state_dict
            state_dict[name] = master_params[i]
        return state_dict

    def _state_dict_to_master_params(self, state_dict):
        params = [state_dict[name] for name, _ in self.model.named_parameters()]
        return params

    def log_step(self):
        return

    def get_blob_logdir(self):
        return self.plot_dir

    def set_seed(self, seed=0):
        torch.manual_seed(seed)
        random.seed(seed)
        np.random.seed(seed)
        torch.cuda.manual_seed_all(seed)

def parse_resume_step_from_filename(filename):
    """
    Parse filenames of the form path/to/modelNNNNNN.pt, where NNNNNN is the
    checkpoint's number of steps.
    """
    split = filename.split("model")
    if len(split) < 2:
        return 0
    split1 = split[-1].split(".")[0]
    try:
        return int(split1)
    except ValueError:
        return 0

def find_resume_checkpoint():
    # On your infrastructure, you may want to override this to automatically
    # discover the latest checkpoint on your blob storage, etc.
    return None

def find_ema_checkpoint(main_checkpoint, step, rate):
    if main_checkpoint is None:
        return None
    filename = f"ema_{rate}_{(step):06d}.pt"
    path = bf.join(bf.dirname(main_checkpoint), filename)
    if bf.exists(path):
        return path
    return None

def update_ema(target_params, source_params, rate=0.99):
    """
    Update target parameters to be closer to those of source parameters using
    an exponential moving average.

    :param target_params: the target parameter sequence.
    :param source_params: the source parameter sequence.
    :param rate: the EMA rate (closer to 1 means slower).
    """
    for targ, src in zip(target_params, source_params):
        targ.detach().mul_(rate).add_(src, alpha=1 - rate)


import fileinput
import sys
from collections import deque, defaultdict, Counter
from functools import lru_cache
from itertools import permutations, combinations, combinations_with_replacement, product
sys.setrecursionlimit(10000000)
dd = defaultdict(lambda: 0)
dx = [0, 0, -1, 1]  # NSWE
dy = [-1, 1, 0, 0]  # NSWE

p1 = 6
p2 = 10

def part1(p1, p2):
    die = 1
    score1 = score2 = 0
    turn = True
    rolled = 0
    while (score1 < 1000 and score2 < 1000):

        d1 = die
        die = die % 100 + 1
        d2 = die
        die = die % 100 + 1
        d3 = die
        die = die % 100 + 1
        rolled += 3
        roll = d1+d2+d3
        if turn:
            p1 = (p1 - 1 + roll) % 10 + 1
            score1 += p1
        else:
            p2 = (p2 - 1 + roll) % 10 + 1
            score2 += p2
        turn = not turn
    return min(score1, score2) * rolled

@lru_cache(maxsize=None)
def old_dp(p1, p2, score1, score2, turn):
    if score1 >= 21:
        return Counter({"p1": 1})
    elif score2 >= 21:
        return Counter({"p2": 1})
    s = Counter()
    for i, j, k in product([1, 2, 3], repeat=3):
        if turn:
            z = (p1 - 1 + i+j+k) % 10 + 1
            s += old_dp(z, p2, score1 + z, score2, not turn)
        else:
            z = (p2 - 1 + i+j+k) % 10 + 1
            s += old_dp(p1, z, score1, score2+z, not turn)
    return s

dices = []
for i, j, k in product([1, 2, 3], repeat=3):
    dices.append(i+j+k)
dices = Counter(dices)

@lru_cache(maxsize=None)
def dp(p1, p2, score1, score2):
    if score1 >= 21:
        return (1,0)
    elif score2 >= 21:
        return (0,1)
    a = b = 0
    for k,times in dices.items():
        z = (p1 - 1 + k) % 10 + 1
        x,y = dp(p2, z, score2, score1 + z)
        a+=times * x
        b+=times * y
    return (b,a)

# print(part1(p1, p2), max(old_dp(p1, p2, 0, 0, True)))
print(part1(p1, p2), max(dp(p1, p2, 0, 0)))


# Establish the Python Logger
import logging # built in python library that does not need to be installed
import time
from datetime import datetime
import os
import talking_code as tc
speaking_log = False
speaking_steps = False

def set_speaking_log(on_off_setting = False):
    global speaking_log
    speaking_log = on_off_setting

def get_speaking_log():
    return speaking_log

def set_speaking_steps(on_off_setting = False):
    global speaking_steps
    speaking_steps = on_off_setting

def get_speaking_steps():
    return speaking_steps

def talk(speech):
    tc.say(speech)
    return

def set_start_time():
    start_time = time.time()
    return(start_time)

def create_logger_Start(solution_name, start_time):
    logging.basicConfig(level=logging.INFO, filename=solution_name + '.log',
                    filemode='w', format='%(asctime)s - %(levelname)s - %(message)s')
    process_start_time_stamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'[:-3])
    logging.info(f'START {solution_name} ' + ('=' * 45) )
    logging.info(f'START {solution_name} Start Time = {process_start_time_stamp}')
    logging.info(f'{solution_name} Step 0 - Initialize the configuration file parser')
#     return f'logger_started for {solution_name} at {process_start_time_stamp}'
    return logging

def create_logger_start(solution_name, start_time):
    logging.basicConfig(level=logging.INFO, filename=solution_name + '.log',
                    filemode='w', format='%(asctime)s - %(levelname)s - %(message)s')
    process_start_time_stamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'[:-3])
    logging.info(f'START {solution_name} ' + ('=' * 45) )
    logging.info(f'START {solution_name} Start Time = {process_start_time_stamp}')
    logging.info(f'{solution_name} Step 0 - Initialize the configuration file parser')
#     return f'logger_started for {solution_name} at {process_start_time_stamp}'
    return logging

def append_log_file(solution_name):
    log_filename=solution_name + '.log'
    historical_log_filename=solution_name + '_history.log'

    with open(log_filename) as log_file:
        log_content = log_file.read()

    with open(historical_log_filename,'a') as historical_log_file:
        print(120*' ', file=historical_log_file)
        print(120*'>', file=historical_log_file)
        print(log_content, file=historical_log_file)
        print(120*'<', file=historical_log_file)
        print(120*' ', file=historical_log_file)
    return(log_content)

def calculate_process_performance(solution_name, process_start_time):
    import time
    stop_time = time.time() # establish the stop time of the overall process.
    process_duration = stop_time - process_start_time
    process_stop_time_stamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f'[:-3])

    logging.info(f'PERFORMANCE {solution_name} The total process duration was:{process_duration:.2f}')
    logging.info(f'PERFORMANCE {solution_name} Stop Time = {process_stop_time_stamp}')
    status = f'END   {solution_name} Duration Classification Error - Process Duration UNKNOWN'
    if process_duration > 600.0:
        logging.info(f'PERFORMANCE {solution_name} LONG process duration greater than 10 Minutes:{process_duration:.2f}')
        logging.info(f'PERFORMANCE {solution_name} Performance optimization is required')
    elif process_duration > 120.0:
        logging.info(f'PERFORMANCE {solution_name} Medium process duration greater than 3 minutes:{process_duration:.2f}')
        logging.info(f'PERFORMANCE {solution_name} Performance optimization is optional')
    elif process_duration > 3.0:
        logging.info(f'PERFORMANCE {solution_name} Low process duration less than 3 minutes:{process_duration:.2f}')
        logging.info(f'PERFORMANCE {solution_name} Performance optimization is optional')
    elif process_duration < 3.0:
        logging.info(f'PERFORMANCE {solution_name} Short process duration less than 3 Seconds:{process_duration:.2f}')
        logging.info(f'PERFORMANCE {solution_name} Performance optimization is not reccomended')
    else:
        status = f'PERFORMANCE {solution_name} Duration Classification Error - Process Duration UNKNOWN'

    logging.info(f'END {solution_name} ' + ('=' * 45) )
    return(status)

def set_start_time():
    start_time = time.time()
    return(start_time)

def pvlog(log_level, log_string):
    global speaking_log
    global speaking_steps

    print(log_string)
    if speaking_log:
        tc.say(log_string)

    if speaking_steps:
        if log_string.find("Step") > -1:
            tc.say(log_string)

    if log_level == 'debug':
        logging.debug(log_string)
    if log_level == 'info':
        logging.info(log_string)
    if log_level == 'warn':
        logging.warn(log_string)
    if log_level == 'error':
        logging.error(log_string)
    if log_level == 'critical':
        logging.critical(log_string)


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import NoSuchElementException
import logging

def has_booking_started(url: str) -> bool:
    options = webdriver.ChromeOptions()
    options.add_argument("--headless=new")
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    options.add_experimental_option('excludeSwitches', ['enable-logging'])
    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
    driver.implicitly_wait(0.5)
    driver.get(url)
    try:
        if driver.find_elements(By.XPATH, '//button[@data-name="get-tickets"]'):
            logging.info("Ticket booking has started")
            return True
        else:
            logging.info("Ticket booking hasn't started yet")
            return False
    except NoSuchElementException:
        logging.info("Ticket booking hasn't started yet")
        return False
    finally:
        driver.close()


# -*- coding: utf-8 -*-
"""
Created on Wed Sep  6 11:55:47 2023

@author: Gilberto
"""

import pandas as pd
from datetime import datetime, timedelta

class StraightLineAmortization:
    def __init__(self, settlement_date, maturity_date, first_payment_date, notional_amount, rate, basis_numerator, basis_denominator, amortization_years, payment_frequency):
        self.settlement_date = datetime.strptime(settlement_date, "%m/%d/%Y") if isinstance(settlement_date, str) else settlement_date
        self.maturity_date = datetime.strptime(maturity_date, "%m/%d/%Y") if isinstance(maturity_date, str) else maturity_date
        self.first_payment_date = datetime.strptime(first_payment_date, "%m/%d/%Y") if isinstance(first_payment_date, str) else first_payment_date
        self.notional_amount = notional_amount
        self.rate = rate/100
        self.basis_numerator = basis_numerator
        self.basis_denominator = basis_denominator
        self.amortization_years = amortization_years
        # Add the payment_frequency variable
        self.payment_frequency = payment_frequency
        # Adjust the num_periods and monthly_principal_payment based on payment_frequency
        if self.payment_frequency == "1M":
            self.num_periods = self.amortization_years * 12
        elif self.payment_frequency == "3M":
            self.num_periods = self.amortization_years * 4
        elif self.payment_frequency == "6M":
            self.num_periods = self.amortization_years * 2
        self.period_principal_payment = self.notional_amount / self.num_periods

    def compute_days(self, start_date, end_date):
        if self.basis_numerator == "ACT":
            days = (end_date - start_date).days
        else:
            days = 30  # assuming each month has 30 days
        if self.basis_denominator == 360:
            return days
        else:
            return days / 365.0 * 360.0

    def get_next_dates(self, current_date):
        if current_date == self.settlement_date:
            return self.first_payment_date, self.first_payment_date

        # Calculate next_month and next_year based on payment_frequency
        if self.payment_frequency == "1M":
            months_increment = 1
        elif self.payment_frequency == "3M":
            months_increment = 3
        elif self.payment_frequency == "6M":
            months_increment = 6

        next_month = (current_date.month + months_increment - 1) % 12 + 1
        next_year = current_date.year + (current_date.month - 1 + months_increment) // 12

        period_end_date = current_date.replace(year=next_year, month=next_month, day=self.first_payment_date.day)

        payment_date = period_end_date
        # If it's a weekend, move to the next business day for payment date
        while payment_date.weekday() >= 5:
            payment_date += timedelta(days=1)

        return period_end_date, payment_date

    def generate_schedule(self):
        data = []
        current_date = self.settlement_date
        payment_number = 1
        notional_amount = self.notional_amount

        while current_date < self.maturity_date and payment_number <= self.num_periods:
            period_start_date = current_date
            period_end_date, payment_date = self.get_next_dates(current_date)
            days_in_period = self.compute_days(period_start_date, period_end_date)
            actual_days_in_period = (period_end_date - period_start_date).days
            interest_for_period = (notional_amount * self.rate * days_in_period) / self.basis_denominator
            period_payment = round(interest_for_period + self.period_principal_payment,2)
            notional_amount -= self.period_principal_payment

            data.append([period_start_date, period_end_date, payment_date, payment_number, notional_amount + self.period_principal_payment, period_payment, self.period_principal_payment, actual_days_in_period])

            current_date = period_end_date # Start next period the same day as the previous period's end date
            payment_number += 1

        df = pd.DataFrame(data, columns=['Period Start Date', 'Period End Date', 'Payment Date', 'Payment Number', 'Outstanding Balance', 'Period Payment', 'Principal Payment', 'Actual Days in Period'])
        return df

# Usage
sla = StraightLineAmortization("8/1/2022", "8/1/2032", "9/1/2022", 600000, 7.03, "ACT", 360, 25, "3M")
amortization_schedule = sla.generate_schedule()
print(amortization_schedule)


"""
 Problem Statement

 A zero-indexed array A of length N contains all integers from 0 to N-1.
 Find and return the longest length of set S,
 where S[i] = {A[i], A[A[i]], A[A[A[i]]], ... } subjected to the rule below.

 Suppose the first element in S starts with the selection of element A[i]
 of index = i, the next element in S should be A[A[i]], and then A[A[A[i]]]…
 By that analogy, we stop adding right before a duplicate element occurs in S.

 Example:
 Input: A = [5,4,0,3,1,6,2]
 Output: 4
 Explanation:
 A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2.

 One of the longest S[K]:
 S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0}

"""
from typing import List

def was_visited(value):
    return value < 0

def was_not_visited(value):
    return value >= 0

class Solution:
    @classmethod
    def array_nesting(cls, nums: List[int]) -> int:
        result = 0
        for index, _ in enumerate(nums):
            if was_visited(nums[index]):
                continue
            else:
                next_pos = nums[index]
                count = 0

                while was_not_visited(nums[next_pos]):
                    actual_pos = next_pos
                    next_pos = nums[next_pos]
                    count += 1
                    nums[actual_pos] = -1
                result = count if count > result else result

        return result


import numpy as np
import matplotlib.pyplot as plt

def linear_LS(xi, yi):
    a = np.empty(2)
    n = xi.shape[0]
    c0 = np.sum(xi)
    c1 = np.sum(xi ** 2)
    c2 = np.sum(yi)
    c3 = np.sum(xi * yi)
    a[0] = (c0*c3 - c1*c2) / (c0*c0 - n*c1)
    a[1] = (c0*c2 - n*c3) / (c0*c0 - n*c1)
    return a

def parabolic_LS(xi, yi):
    n = xi.shape[0]
    x1 = np.sum(xi)
    x2 = np.sum(xi ** 2)
    x3 = np.sum(xi ** 3)
    x4 = np.sum(xi ** 4)
    y1 = np.sum(yi)
    x1y1 = np.sum(xi * yi)
    x2y1 = np.sum(xi**2 * yi)
    A_mat = np.array([[n, x1, x2], [x1, x2, x3], [x2, x3, x4]])
    b_vec = np.array([y1, x1y1, x2y1])
    a_vec = np.linalg.solve(A_mat, b_vec)
    return a_vec

def sketch(x, y, flag):
    if flag == 1:
        name = "linear"
    else:
        name = "parabolic"
    plt.plot(x, y, label=name)
    plt.xlabel("x")
    plt.ylabel("T")
    plt.grid()
    plt.legend()

def scatter(x, y):
    plt.scatter(x, y, label="data", color="black")
    plt.xlabel("x")
    plt.ylabel("T")
    plt.grid()
    plt.legend()

def main():
    distance = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0])
    temperature = np.array([14.6, 18.5, 36.6, 30.8, 59.2, 60.1, 62.2, 79.4, 99.9])
    scatter(distance, temperature)

    x_plot = np.linspace(0, 10, 100)
    coef = linear_LS(distance, temperature)
    y_plot = coef[0] + coef[1]*x_plot
    print(coef)
    sketch(x_plot, y_plot, 1)

    x_plot = np.linspace(0, 10, 100)
    coef = parabolic_LS(distance, temperature)
    y_plot = coef[0] + coef[1]*x_plot + coef[2]*x_plot**2
    print(coef)
    sketch(x_plot, y_plot, 2)

    plt.show()

if __name__ == '__main__':
    main()
    input("请按任意键以继续......")


import boto3
import logging
import os
import json
import time
from datetime import datetime
from jsonpath_ng.ext import parse
import helpers

logger = logging.getLogger()
logger.setLevel(logging.INFO)

utl = helpers.Utils()
dyn = helpers.Dyn()

ssm = boto3.client('ssm')
ec2 = boto3.client('ec2')
appValue = os.getenv('TAG_APP_VALUE')
appName = os.getenv('APP_NAME')

def getNicInformation(instance):
    logger.info(instance + "- getNicInformation")

    ssm_rsp = ssm.send_command(
            InstanceIds=[instance],
            DocumentName='AWS-RunShellScript',
            TimeoutSeconds=30,
            Parameters={
                'commands':[
                     "NIC=$(ifconfig -a | grep UP,BROADCAST | awk '{print substr($1, 1, length($1)-1)}');aws ssm put-parameter --name '/amplify/minecraftserverdashboard/" + instance + "/nic' --type 'String' --value $NIC"
                ]
            },
        )
    resp = checkExecutionLoop(instance,ssm_rsp["Command"]["CommandId"])
    logger.info(resp)

def minecraftInit(instance):
    logger.info(instance + " - minecraftInit")
    instanceInfo = dyn.GetInstanceAttr(instance)
    logger.info(instanceInfo)

    if instanceInfo['code'] != 200:
        logger.warning("Instance data does not exist")
        return False

    if 'runCommand' in instanceInfo['msg'] and 'workingDir' in instanceInfo['msg']:
        script = os.path.join(instanceInfo['msg']['workingDir'],instanceInfo['msg']['runCommand'])
        #script = instanceInfo['msg']['runCommand']

        ssm_rsp = ssm.send_command(
            InstanceIds=[instance],
            DocumentName='AWS-RunShellScript',
            TimeoutSeconds=30,
            Parameters={
                'commands':[
                     script
                ],
                'workingDirectory':[
                    instanceInfo['msg']['workingDir']
                ],
            },
        )
        logger.info(ssm_rsp)

    else:
        logger.warning("RunCommand or Working Directories are not defined")
        return False

def cwAgentStatusCheck(instance):
    logger.info(instance + " - cwAgentStatusCheck")
    ssmAgentStatus = ssmExecCommands(instance,"AmazonCloudWatch-ManageAgent",{"action": ["status"],"mode": ["ec2"]})
    #logger.info(ssmAgentStatus)

    # Checking Agent Status if Success. Failed messages occurs when the CloudWatch Agent is not installed.
    if ssmAgentStatus["Status"] == "Success":
        agentDetails=""
        jpexpr = parse("$.pluginsDetails[?(@.Name[:] == 'ControlCloudWatchAgentLinux')].Output")
        for i in jpexpr.find(ssmAgentStatus):
            agentDetails = i.value

        if len(agentDetails) > 5:
            agentDetailsJson = json.loads(agentDetails)
            if agentDetailsJson["status"] == "running":
                logger.info("Agent is already running. Version :" + agentDetailsJson["version"])
                # AmazonCloudWatch Agent configuration
                logger.info("Configuring agent")
                ssmAgentConfig = ssmExecCommands(instance,"AmazonCloudWatch-ManageAgent",{"action": ["configure"],"mode": ["ec2"],"optionalConfigurationLocation": ["/amplify/minecraftserverdashboard/amazoncloudwatch-linux"],"optionalConfigurationSource": ["ssm"],"optionalRestart": ["yes"]})
                logger.info(ssmAgentConfig)
                return { "code": 200, "msg": "Agent is already running. Version :" + agentDetailsJson["version"] }
            else:
                logger.info("Agent Status: " + agentDetailsJson["status"] + " - configuration Status: " + agentDetailsJson["configstatus"])
                return { "code": 400, "msg":"Agent Status: " + agentDetailsJson["status"] + " - configuration Status: " + agentDetailsJson["configstatus"] }
        else:
            logger.warning(agentDetailsJson)
            return { "code": 500, "msg": "Detailed information not available"}
    else:
        return { "code": 500, "msg": "Failed" }

def cwAgentInstall(instance):
    ssmInstallAgent = ssmExecCommands(instance,"AWS-ConfigureAWSPackage",{"action": ["Install"],"name": ["AmazonCloudWatchAgent"]})
    #logger.info(ssmInstallAgent)

    # Checking Agent Status if Success. Failed messages occurs when the CloudWatch Agent is not installed.
    if ssmInstallAgent["Status"] == "Success":
        # AmazonCloudWatch Agent installation
        jpexpr = parse("$.pluginsDetails[?(@.Name[:] == 'configurePackage')].Output")
        for i in jpexpr.find(ssmInstallAgent):
            agentDetails = i.value
            logger.info(agentDetails)
        # AmazonCloudWatch Agent configuration
        logger.info("Configuring agent")
        ssmAgentConfig = ssmExecCommands(instance,"AmazonCloudWatch-ManageAgent",{"action": ["configure"],"mode": ["ec2"],"optionalConfigurationLocation": ["/amplify/minecraftserverdashboard/amazoncloudwatch-linux"],"optionalConfigurationSource": ["ssm"],"optionalRestart": ["yes"]})
        logger.info(ssmAgentConfig)

def scriptExec(instance):
    ssmRunScript = ssmExecCommands(instance,"AWS-RunRemoteScript",{"sourceType": ["GitHub"],"sourceInfo": ["{\"owner\":\"arturlr\", \"repository\": \"minecraft-server-dashboard\", \"path\": \"scripts/adding_cron.sh\", \"getOptions\": \"branch:dev\" }"],"commandLine": ["bash adding_cron.sh"]})
    logger.info(ssmRunScript)

def sendCommand(instance, param, docName):
    ssm_rsp = ssm.send_command(
                InstanceIds=[instance],
                DocumentName=docName,
                TimeoutSeconds=30,
                Parameters=param
            )

    # logger.info("sendCommand " + instance + " - " + ssm_rsp["Command"]["Status"])
    return { "CommandId": ssm_rsp["Command"]["CommandId"], "Status": ssm_rsp["Command"]["Status"] }

def listCommand(instance, commandId):
    ssm_rsp = ssm.list_commands(
            CommandId=commandId,
            InstanceId=instance,
    )

    logger.info("listCommand " + instance + " - " + ssm_rsp["Commands"][0]["Status"])
    return { "Status": ssm_rsp["Commands"][0]["Status"] }

def getCommandDetails(instance, commandId):
    ssm_rsp = ssm.list_command_invocations(
            CommandId=commandId,
            InstanceId=instance,
            Details=True
    )

    if 'CommandPlugins' in  ssm_rsp["CommandInvocations"][0]:
        pluginsDetails = ssm_rsp["CommandInvocations"][0]["CommandPlugins"]

    logger.info("getCommandDetails " + instance + " - " + ssm_rsp["CommandInvocations"][0]["Status"])
    return { "Status": ssm_rsp["CommandInvocations"][0]["Status"], "pluginsDetails": pluginsDetails }

def checkExecutionLoop(instanceId, commandId, sleepTime=5):

    loopCount = 0

    while True:
        checkStatusCommand = listCommand(instanceId, commandId)
        logger.info(instanceId + " - " + commandId + " - " + checkStatusCommand["Status"])
        if checkStatusCommand["Status"] == "Success":
            getStatusDetails = getCommandDetails(instanceId, commandId)
            return getStatusDetails
        elif checkStatusCommand["Status"] == "Failed":
            return "Failed"
        elif loopCount > 5:
            logger.error("Timeout - Cancelling the Command")
            logger.error(checkStatusCommand)
            ssm.cancel_command(
                CommandId=commandId,
                InstanceIds=[instanceId]
            )
            return "Cancelled"
        else:
            loopCount = loopCount + 1
            time.sleep(sleepTime)

def ssmExecCommands(instanceId, docName, params):
    logger.info("ssmExecCommands " + instanceId + " - " + docName)

    command = sendCommand(instanceId, params, docName)
    response = checkExecutionLoop(instanceId,command["CommandId"])

    return response

def handler(event, context):
    try:
        instanceId = event["instanceId"]

        # Execute minecraft initialization
        minecraftInit(instanceId)

        # Nic Value
        getNicInformation(instanceId)

        ## CloudWatch Agent Steps
        cwAgentStatus = cwAgentStatusCheck(instanceId)
        if cwAgentStatus['code'] != 200:
            cwAgentInstall(instanceId)
            scriptExec(instanceId)
            return { "code": 200, "msg": "CW Agent installed and Script executed"}
        else:
            return cwAgentStatus

    except Exception as e:
        logger.error('Something went wrong: ' + str(e))
        return { "code": 500, "msg": str(e) }