#!/usr/bin/env python3
# vim: fenc=utf-8:ts=4:sw=4:sta:et:sts=4:ai
import os
import datetime
import glob
import logging
import nbtlib
import bedrock.leveldb as leveldb
from PIL import ImageFont, Image, ImageDraw
import math
import operator
from collections.abc import Callable
from collections import defaultdict, OrderedDict, namedtuple
from tqdm import tqdm
import argparse
import gzip
import json
import distutils.dir_util
import re
from io import BytesIO
import sys
import hashlib
import time
import struct

__author__ = "Jason Green"
__copyright__ = "Copyright 2020, Tesseract Designs"
__credits__ = ["Jason Green"]
__license__ = "MIT"
__version__ = "2.0.6"
__maintainer__ = "Jason Green"
__email__ = "jason@green.io"
__status__ = "release"

dir_path = os.path.dirname(os.path.realpath(__file__))

filenameSeparator = "."

mapPngFilenameFormat = filenameSeparator.join(["{mapId}", "{mapHash}", "{epoch}", "{dimension}", "{x}", "{z}", "{scale}.png"])

# now in epoch
now = int(time.time())

# stuff to convert the map color data to RGB values
multipliers = [180, 220, 255, 135]

# this is base pallette Minecraft uses, used with the multipliers
basecolors = [(0, 0, 0, 0),
              (127, 178, 56),
              (247, 233, 163),
              (199, 199, 199),
              (255, 0, 0),
              (160, 160, 255),
              (167, 167, 167),
              (0, 124, 0),
              (255, 255, 255),
              (164, 168, 184),
              (151, 109, 77),
              (112, 112, 112),
              (64, 64, 255),
              (143, 119, 72),
              (255, 252, 245),
              (216, 127, 51),
              (178, 76, 216),
              (102, 153, 216),
              (229, 229, 51),
              (127, 204, 25),
              (242, 127, 165),
              (76, 76, 76),
              (153, 153, 153),
              (76, 127, 153),
              (127, 63, 178),
              (51, 76, 178),
              (102, 76, 51),
              (102, 127, 51),
              (153, 51, 51),
              (25, 25, 25),
              (250, 238, 77),
              (92, 219, 213),
              (74, 128, 255),
              (0, 217, 58),
              (129, 86, 49),
              (112, 2, 0),
              (209, 177, 161),
              (159, 82, 36),
              (149, 87, 108),
              (112, 108, 138),
              (186, 133, 36),
              (103, 117, 53),
              (160, 77, 78),
              (57, 41, 35),
              (135, 107, 98),
              (87, 92, 92),
              (122, 73, 88),
              (76, 62, 92),
              (76, 50, 35),
              (76, 82, 42),
              (142, 60, 46),
              (37, 22, 16),
              (189, 48, 49),
              (148, 63, 97),
              (92, 25, 29),
              (22, 126, 134),
              (58, 142, 140),
              (86, 44, 62),
              (20, 180, 133),
              (100, 100, 100),
              (216, 175, 147),
              (127, 167, 150)]

def multiplyColor(colorTuple, multiplier):
    "calculates final color values using multiplier"
    return tuple([math.floor(a * multiplier / 255.0) for a in colorTuple])

# this a list of all possible colors a pixel can be on a map
allColors = [multiplyColor(color, multiplier)
             for color in basecolors for multiplier in multipliers]

# convert dimension names to/from human readable
dimDict = {-1: "minecraft:the_nether",
           0: "minecraft:overworld",
           1: "minecraft:the_end",
           'minecraft:overworld': 0,
           'minecraft:the_end': 1,
           'minecraft:the_nether': -1,
           'minecraft@overworld': 0,
           'minecraft@the_end': 1,
           'minecraft@the_nether': -1}

def findMapFiles(inputFolder):
    mapFiles = []

    folderTree = list(os.walk(inputFolder))

    dataFolders = [f for f in folderTree if f[0].endswith(os.sep + "data")]

    for folder in dataFolders:
        maybeMapFiles = [os.path.join(folder[0], f) for f in folder[2] if f.startswith("map_") and f.endswith(".dat")]
        if "idcounts.dat" in folder[2]:
            logging.info("Found %s maps in %s", len(maybeMapFiles), folder[0])
            mapFiles = maybeMapFiles

    if not mapFiles:
        logging.info("Didn't find any maps, did you specify the correct world location?")
        sys.exit(1)

    return mapFiles

class LastUpdatedOrderedDict(OrderedDict):
    'Store items in the order the keys were last added'
    def __setitem__(self, key, value):
        if key in self:
            del self[key]
        OrderedDict.__setitem__(self, key, value)

class DefaultOrderedDict(OrderedDict):
    "Source: http://stackoverflow.com/a/6190500/562769"
    def __init__(self, default_factory=None, *a, **kw):
        if (default_factory is not None and
           not isinstance(default_factory, Callable)):
            raise TypeError('first argument must be callable')
        OrderedDict.__init__(self, *a, **kw)
        self.default_factory = default_factory

    def __getitem__(self, key):
        try:
            return OrderedDict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)

    def __missing__(self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = value = self.default_factory()
        return value

    def __reduce__(self):
        if self.default_factory is None:
            args = tuple()
        else:
            args = self.default_factory,
        return type(self), args, None, None, self.items()

    def copy(self):
        return self.__copy__()

    def __copy__(self):
        return type(self)(self.default_factory, self)

    def __deepcopy__(self, memo):
        import copy
        return type(self)(self.default_factory,
                          copy.deepcopy(self.items()))

    def __repr__(self):
        return 'OrderedDefaultDict(%s, %s)' % (self.default_factory,
                                               OrderedDict.__repr__(self))

# couple of structures to keep stuff
BannerTuple = namedtuple("BannerTuple", ["X", "Y", "Z", "name", "color", "dimension"])
MapTuple = namedtuple("MapTuple", ["mapData", "bannerData", "frameData"])
MapPngTuple = namedtuple("MapPngTuple", ["mapId", "mapHash", "epoch", "x", "z", "dimension", "scale"])

def mapPngsSortedByEpoch(mapPngs):
    """Returns a list of latest map png files by their center"""

    # get all generated maps

    centerEpochs = []

    for mapPng in mapPngs:
        centerEpochs.append((mapPng.epoch, mapPng))

    # sort the whole thing by epoch
    centerEpochs.sort(key=operator.itemgetter(0))

    # for centerEpoch in centerEpochs:
    #     # this will only keep the latest map ids around for rendering
    #     [centerEpoch[0]] = centerEpoch[2]

    # latestMapPngs = list(filterDict.values())

    return [m[1] for m in centerEpochs]

def filterLatestMapPngsById(mapPngs):
    """Returns a list of latest map png files by Id"""

    # get all generated maps

    idEpochs = []
    filterDict = {}

    for mapPng in mapPngs:
        idEpochs.append((mapPng.mapId, mapPng.epoch, mapPng))

    # sort the whole thing by epoch
    idEpochs.sort(key=operator.itemgetter(1))

    for idEpoch in idEpochs:
        # this will only keep the latest map ids around for rendering
        filterDict[idEpoch[0]] = idEpoch[2]

    latestMapPngs = list(filterDict.values())

    return latestMapPngs

def makeMaps(worldFolder, outputFolder, serverType, unlimitedTracking=False):
    nbtMapData = []
    if serverType == "bds":
        # open leveldb
        db = leveldb.open(os.path.join(worldFolder, "db"))

        # iterate over all the maps
        for a in tqdm(leveldb.iterate(db), "leveldb map keys -> nbt".ljust(24), bar_format="{l_bar}{bar}"):
            key = bytearray(a[0])
            if b"map" in key:
                # get extract an nbt object
                mapNbtIo = BytesIO(a[1])
                mapNbtFile = nbtlib.File.parse(mapNbtIo, byteorder="little")
                mapNbt = mapNbtFile
                mapId = int(mapNbt["mapId"])
                epoch = 0
                nbtMapData.append({"epoch": epoch, "id": mapId, "nbt": mapNbt})

    elif serverType == "java":
        mapDatFiles = findMapFiles(worldFolder)
        for mapDatFile in tqdm(mapDatFiles, "map_*.dat -> nbt".ljust(24), bar_format="{l_bar}{bar}"):
            mapNbtFile = nbtlib.load(mapDatFile)
            mapNbt = mapNbtFile["data"]
            mapId = int(os.path.basename(mapDatFile)[4:-4])
            epoch = int(os.path.getmtime(mapDatFile))
            nbtMapData.append({"epoch": epoch, "id": mapId, "nbt": mapNbt})

    maps = []
    os.makedirs(outputFolder, exist_ok=True)
    mapPngs = getMapPngs(outputFolder)

    currentIds = {x.mapId: x for x in mapPngs}

    for nbtMap in tqdm(nbtMapData, "nbt -> png".ljust(24), bar_format="{l_bar}{bar}"):
        mapId = nbtMap["id"]
        mapNbt = nbtMap["nbt"]
        mapEpoch = nbtMap["epoch"]
        try:
            mapUnlimitedTracking = mapNbt["unlimitedTracking"]
        except KeyError:
            mapUnlimitedTracking = False

        if mapUnlimitedTracking and not unlimitedTracking:
            continue
        scale = int(mapNbt["scale"])
        x = int(mapNbt["xCenter"])
        z = int(mapNbt["zCenter"])

        dimension = mapNbt["dimension"]
        mapColors = mapNbt["colors"]

        if type(dimension) == nbtlib.tag.Int:
            dimension = dimDict[mapNbt["dimension"]]
        elif type(dimension) == nbtlib.tag.Byte:
            dimension = dimDict[mapNbt["dimension"]]
        else:
            dimension = dimension.strip('"')
        dimension = dimension.replace(":", "@")

        try:
            mapBanners = mapNbt["banners"]
        except KeyError:
            mapBanners = []

        try:
            mapFrames = mapNbt["frames"]
        except KeyError:
            mapFrames = []

        banners = set()
        for banner in mapBanners:
            X = int(banner["Pos"]["X"])
            Y = int(banner["Pos"]["Y"])
            Z = int(banner["Pos"]["Z"])
            color = banner["Color"]

            try:
                name = json.loads(banner["Name"])["text"]

            except KeyError:
                name = ""

            bannerDict = {"X": X,
                          "Y": Y,
                          "Z": Z,
                          "color": color,
                          "name": name,
                          "dimension": dimension}
            bannerTuple = BannerTuple(**bannerDict)
            banners.add(bannerTuple)
        frames = []
        for frame in mapFrames:
            X = int(frame["Pos"]["X"])
            Y = int(frame["Pos"]["Y"])
            Z = int(frame["Pos"]["Z"])
            rotation = int(frame["Rotation"])

            frameDict = {"X": X,
                        "Y": Y,
                        "Z": Z,
                        "rotation": rotation}
            frames.append(frameDict)
        # logging.debug(mapColors)

        if serverType == "bds":
            mapImage = Image.frombytes("RGBA", (128, 128),
                                       bytes([x % 256 for x in mapColors]),
                                       'raw')
        elif serverType == "java":
            colorTuples = [allColors[x % 256] for x in mapColors]
            mapImage = Image.new("RGBA", (128, 128))
            mapImage.putdata(colorTuples)

        mapHash = hashlib.md5(mapImage.tobytes()).hexdigest()

        # empty map
        if mapHash == "fcd6bcb56c1689fcef28b57c22475bad":
            continue

        if mapId not in currentIds:
            # brand new image
            logging.debug("%s is a new map", mapId)
            epoch = mapEpoch
        else:
            # changed image
            logging.debug("%s is already known", mapId)
            if mapHash != currentIds.get(mapId).mapHash:
                # map has changed based on the hash

                logging.debug("%s changed and will get an updated epoch", mapId)
                epoch = now if not mapEpoch else mapEpoch

            elif mapEpoch > currentIds.get(mapId).epoch:
                logging.debug("%s has a more recent epoch from it's dat file, updating", mapId)
                epoch = mapEpoch

            else:
                logging.debug("%s has not changed and will keep it's epoch", mapId)
                epoch = currentIds.get(mapId).epoch

        mapPng = MapPngTuple(mapId=mapId,
                             mapHash=mapHash,
                             epoch=epoch,
                             dimension=dimension,
                             x=x,
                             z=z,
                             scale=scale)

        mapImage = mapImage.resize((128 * 2 ** scale,) * 2, Image.NEAREST)
        filename = mapPngFilenameFormat.format(**mapPng._asdict())

        try:
            oldFilename = mapPngFilenameFormat.format(**currentIds.get(mapId)._asdict())
            os.remove(os.path.join(outputFolder, oldFilename))
        except:
            logging.debug("%s isn't there, didn't delete", mapId)

        mapImage.save(os.path.join(outputFolder, filename))

        mapData = MapTuple(mapData=mapPng,
                           bannerData=banners,
                           frameData=frames)
        maps.append(mapData)

    logging.debug(maps)
    logging.info("Processed %s maps", len(maps))

    return maps

def getMapPngs(mapPngFolder):
    mapPngList = []

    globString = filenameSeparator.join(6 * ["*"] + ["*.png"])
    # get all the maps
    mapPngs = glob.glob(os.path.join(mapPngFolder, globString))

    # iterate over all the maps
    for mapPng in mapPngs:
        filename = os.path.basename(mapPng)
        (mapId,
         mapHash,
         epoch,
         dimension,
         x,
         z,
         scale,
         _) = filename.split(filenameSeparator)
        # change some types
        x = int(x)
        z = int(z)
        scale = int(scale)
        mapId = int(mapId)
        if not dimension in dimDict:
            logging.info("Skipped map %s with invalid dimension.", mapId)
            continue
        epoch = int(epoch)

        mapPngList.append(MapPngTuple(mapId=mapId,
                                      mapHash=mapHash,
                                      epoch=epoch,
                                      dimension=dimension,
                                      x=x,
                                      z=z,
                                      scale=scale))

    return mapPngList

def mergeToLevel4(mapPngFolder, outputFolder, disablezoomsort):
    """pastes all maps to render onto a intermediate zoom level 4 map"""
    # what are we calling these crazy things

    filenameFormat = filenameSeparator.join(["{dimension}", "{x}", "{z}.png"])

    # make sure the output exsists
    os.makedirs(outputFolder, exist_ok=True)

    # this will hold all the maps, by dimension and associated zoom level 4 map
    level4Dict = defaultdict(lambda: defaultdict(list))

    # get all the maps
    mapPngs = getMapPngs(mapPngFolder)
    latestMapPngs = mapPngsSortedByEpoch(mapPngs)

    # iterate over all the maps
    for mapPng in latestMapPngs:
        # convert the center of the map to the top left corner
        mapTopLeft = (mapPng.x - 128 * 2 ** mapPng.scale // 2 + 64,
                      mapPng.z - 128 * 2 ** mapPng.scale // 2 + 64)

        # figure out which level 4 map it belongs to
        level4Coords = (mapTopLeft[0] // 2048 * 2048,
                        mapTopLeft[1] // 2048 * 2048)

        # throw it into a "dict"
        level4Dict[mapPng.dimension][level4Coords].append(mapPng)

    logging.debug(level4Dict)

    # iterate over the level 4 buckets
    for dim in level4Dict.items():
        d = dim[0]
        for coords in tqdm(dim[1].items(), "level 4 of dim: {}".format(d).ljust(24), bar_format="{l_bar}{bar}"):
            c = coords[0]

            mapTuples = coords[1]

            if not disablezoomsort:
            # sort them, import for the rendering order
                mapTuples.sort(key=lambda x: x.scale, reverse=True)

            # create the level 4 images
            level4MapPng = Image.new("RGBA", (2048, 2048))

            # iterate over the maps in each bucket
            for mapTuple in mapTuples:
                # get the map details
                mapPngCoords = (divmod(mapTuple.x - 128 * 2 ** mapTuple.scale // 2 + 64, 2048)[1],
                                divmod(mapTuple.z - 128 * 2 ** mapTuple.scale // 2 + 64, 2048)[1])
                mapPngFilename = mapPngFilenameFormat.format(**mapTuple._asdict())
                # paste the image into the level 4 map
                with Image.open(os.path.join(mapPngFolder, mapPngFilename)) as mapPng:
                    level4MapPng.paste(mapPng, mapPngCoords, mapPng)
            # figure out the name of the file, and save it
            fileName = filenameFormat.format(dimension=d, x=c[0], z=c[1]*-1)

            filePath = os.path.join(outputFolder, fileName)
            level4MapPng.save(filePath)
            level4MapPng.close()

def genZoom17Tiles(level4MapFolder, outputFolder):
    """generates lowest zoom level tiles from combined zoom level 4 maps"""

    # get all the level 4 maps
    globString = filenameSeparator.join(["*", "*", "*.png"])
    level4MapFilenames = glob.glob(os.path.join(level4MapFolder, globString))
    # iterate over level4 maps
    for level4MapFilename in tqdm(level4MapFilenames, "level 4 -> zoom 17 tiles", bar_format="{l_bar}{bar}"):
        # get some details
        name = os.path.basename(level4MapFilename)
        dim, x, z, _ = name.split(filenameSeparator)
        level4x = int(x)
        level4z = int(z)
        tilex = level4x // 2048
        tilez = level4z // 2048 * -1
        # open the level 4 map
        with Image.open(level4MapFilename) as level4MapPng:
            # this is pretty useless
            for zoom in range(17, 18):
                numTiles = 2 ** (zoom - 13)
                imageWidth = 2048 // numTiles
                # do math
                for numx in range(numTiles):
                    levelNumx = tilex * numTiles + numx
                    foldername = os.path.join(outputFolder, dim, str(zoom), str(levelNumx))
                    os.makedirs(foldername, exist_ok=True)
                    for numz in range(numTiles):
                        levelNumz = tilez * numTiles + numz
                        cropBox = (numx * imageWidth,
                                numz * imageWidth,
                                numx * imageWidth + imageWidth,
                                numz * imageWidth + imageWidth)
                        filename = os.path.join(foldername, str(levelNumz) + ".png")
                        tilePng = level4MapPng.crop(cropBox)
                        tilePng = tilePng.resize((256, 256), Image.NEAREST)
                        tilePng.save(filename)

def extrapolateZoom(tileFolder, level):
    zoom17Filenames = glob.glob(os.path.join(tileFolder, "*", str(level + 1), "*", "*.png"))
    newZoomDict = defaultdict(list)
    for filename in zoom17Filenames:
        tilePath = os.path.relpath(filename, tileFolder)
        dim, zoom, x, y = tilePath.strip(".png").split(os.sep)
        x = int(x)
        y = int(y)
        xnew, xq = divmod(x, 2)
        ynew, yq = divmod(y, 2)
        newZoomDict[(dim, xnew, ynew)].append((xq, yq, filename))
    for newTile in tqdm(newZoomDict.items(), "zoom {} tiles".format(level).ljust(24), bar_format="{l_bar}{bar}"):
        foldername = os.path.join(tileFolder, str(newTile[0][0]), str(level), str(newTile[0][1]))
        tilePng = Image.new("RGBA", (512,512))
        for previousTile in newTile[1]:
            topLeft = (previousTile[0] * 256, previousTile[1] * 256)
            previousTilePng = Image.open(previousTile[2])
            tilePng.paste(previousTilePng, topLeft, previousTilePng)
        tilePng = tilePng.resize((256,256), Image.NEAREST)
        os.makedirs(foldername, exist_ok=True)
        tilePng.save(os.path.join(foldername, "{}.png".format(newTile[0][2])))

def genBannerMarkers(maps, outputFolder):
    """generate the banner.json file from maps list"""
    logging.debug(maps)

    with open(os.path.join(outputFolder, "banners.json"), "+w", encoding="utf-8") as f:
        # this will also remove deplicates
        bannerList = [a._asdict() for a in {a for amap in maps for a in amap.bannerData}]
        f.write(json.dumps(list(bannerList)))

def genMapIdMarkers(maps, outputFolder):
    mapIdMarkers = []
    dimCenterScaleDict = defaultdict(list)
    for amap in maps:
        mapData = amap.mapData
        dimCenterScaleDict[(mapData.dimension, mapData.x, mapData.z, mapData.scale)].append(amap)

    for dimCenterScale in dimCenterScaleDict.items():
        logging.debug("DimCenterScale %s", dimCenterScale[0])
        dimension, x, z, scale = dimCenterScale[0]

        maps = []
        for amap in dimCenterScale[1]:
            maps.append({"id": amap.mapData.mapId,
                         "scale" : amap.mapData.scale,
                         "filename": mapPngFilenameFormat.format(**amap.mapData._asdict()),
                         "banners": list(amap.bannerData),
                         "frames": amap.frameData})

        X = x - 64 * 2 ** scale
        Z = z - 64 * 2 ** scale

        width = 128 * 2 ** scale

        TL = [X, Z]
        TR = [X, Z + width]
        BL = [X + width, Z + width]
        BR = [X + width, Z]

        coordinates = [[TL, TR, BL, BR, TL]]
        properties = {"scale": scale,
                      "dimension": dimension,
                      "maps": maps }

        geometry = {"type": "Polygon",
                    "coordinates": coordinates}

        feature = {"type": "Feature",
                   "properties": properties,
                   "geometry": geometry}

        mapIdMarkers.append(feature)

    with open(os.path.join(outputFolder, "maps.json"), "+w", encoding="utf-8") as f:
        f.write(json.dumps(mapIdMarkers))

def copyTemplate(outputFolder, copytemplate):
    if not os.path.isdir(os.path.join(outputFolder, "assets")) or copytemplate:
        logging.info("Copying template to %s", outputFolder)
        distutils.dir_util.copy_tree(os.path.join(dir_path, "template"), outputFolder)

    else:
        logging.info("Assets folder found, not copying template")

def main():
    parser = argparse.ArgumentParser(description='convert minecraft maps to the web')
    parser.add_argument('--world', help="location of your world folder or save folder", required=True)
    parser.add_argument('--type', help="server type, bedrock or java", choices=["java", "bds"], required=True)
    parser.add_argument('--includeunlimitedtracking', help="include maps that have unlimited tracking on, this includes older maps from previous Minecraft versions and treasure maps in +1.13", action="store_true")
    parser.add_argument('--disablezoomsort', help="don't sort maps by zoom level before rendering, newer maps of higher zoom level will cover lower level maps", action="store_true")
    #parser.add_argument('--overlaymca', help="generate the regionfile overlay (Java only)", action="store_true")
    parser.add_argument('--output', help="output path for web stuff", required=True)
    parser.add_argument('--copytemplate', help="copy default index.html and assets (do this if a new release changes the tempalte)", action="store_true")
    parser.add_argument('--debug', help="show debug logging", action="store_true")

    # get the args
    args = parser.parse_args()

    # setup the logger
    if args.debug:
        level = logging.DEBUG
    else:
        level = logging.INFO

    logging.basicConfig(format='%(asctime)s %(message)s', level=level)
    # where to the maps go?
    mapsOutput = os.path.join(args.output, "maps")

    # where to the tiles go?
    tileOutput = os.path.join(args.output, "tiles")

    # where to the merged zoom level 4 maps go?
    mergedMapsOutput = os.path.join(args.output, "merged-maps")

    # figure out if the input folder is java or bedrock
    latestMaps = makeMaps(args.world, mapsOutput, serverType=args.type, unlimitedTracking=args.includeunlimitedtracking)

    # make the level 4 maps
    mergeToLevel4(mapsOutput, mergedMapsOutput, disablezoomsort=args.disablezoomsort)

    # create the tiles for the lowest zoom level
    genZoom17Tiles(mergedMapsOutput, tileOutput)

    # generate the rest of the zoom levels from level 17
    for zoom in range(16, -1, -1):
        extrapolateZoom(tileOutput, zoom)

    # make the banner markers
    genBannerMarkers(latestMaps, args.output)

    # make the maps info markers
    genMapIdMarkers(latestMaps, args.output)

    # make sure the html and assets are present and copied
    copyTemplate(args.output, args.copytemplate)

    logging.info("Done")

if __name__ == "__main__":
    main()


from constants.constantsGeneral import ConstantsGeneral
from data.builder import builderCartData, builderEwallet
from data.dataGenerator import DataGenerator
from service.serviceNicepay import ServiceNicepay

class testEwallet:
    amt = 100
    itemCartData = {
        "img_url": "https://cdn.eraspace.com/pub/media/catalog/product/i/p/iphone_13_pro_max_silver_1_5.jpg",
        "goods_name": "iPhone13ProMax",
        "goods_detail": "1TB-White",
        "goods_amt": amt,
        "goods_quantity": "1"
    }

    bodyCartData = (
        builderCartData.BuildCartData()
        .setCount("1")
        .setItem(itemCartData)
        .build()
    )

    bodyEwallet = (
        builderEwallet.BuildEwallet()
        .setPayMethod(ConstantsGeneral.getPayMethodEWallet())
        .setMitraCd("DANA")
        .setUserIp(ConstantsGeneral.getUserIp())
        .setAmt(amt)
        .build()
    )

    response = ServiceNicepay.serviceRequest(DataGenerator.getTransactionBody(bodyEwallet.jsonEwallet(),
                                                                              bodyCartData.jsonCartData()))


def total_three_ints():

    int1 = int(input("Number 1: "))
    int2 = int(input("Number 2: "))
    int3 = int(input("Number 3: "))
    total = int1+int2+int3
    print(f"Total: {total}")

def average_4_ints():

    int1 = int(input("Number 1: "))
    int2 = int(input("Number 2: "))
    int3 = int(input("Number 3: "))
    int4 = int(input("Number 4: "))

    average = (int1+int2+int3+int4)/4

    print(f"Average: {average}")

def price_per_person():
    bill = float(input("Total bill: $"))
    people = int(input("How many people? "))
    _price_per_person = bill / people
    print(f"Price per person: {_price_per_person}")

def find_area_of_rect():
    width = float(input("Width of rect? "))
    height = float(input("Height of rect? "))

    area = width * height
    print(f"Area: {area} units squared")

def volume_of_box():
    width = float(input("Width of box? "))
    height = float(input("Height of box? "))
    depth = float(input("Depth of box? "))

    volume = width * height * depth
    print(f"Volume: {volume} units cubed")
    return volume

def space_remaining():
    print("Box 1")
    volume1 = volume_of_box()
    print("Box 2")
    volume2 = volume_of_box()

    space_remaining = 0
    if volume1 > volume2:
        space_remaining = volume1 - volume2
    elif volume2 > volume1:
        space_remaining = volume2-volume1
    else:
        print("2 different sizes please!")
        return

    print(f"Space remaining: {space_remaining} units")

total_three_ints()
average_4_ints()
price_per_person()
find_area_of_rect()
volume_of_box()
space_remaining()


# -*- coding: utf-8 -*-
"""
Created on Sat Jun 20 22:51:16 2020
softmax模型
@author: xiaohao
"""
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data #input_data下载用于训练和测试的MNIST数据集的源码
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# 构建Softmax 回归模型
#使用TensorFlow程序的流程是先创建一个图，然后在session中启动它。

sess = tf.InteractiveSession()
#占位
x=tf.placeholder("float",shape=[None,784]) #784是一张展平的MNIST图片的维度(28*28)
y_=tf.placeholder("float",shape=[None,10])#十分类

# 初始化变量
W=tf.Variable(tf.zeros([784,10]))#卷积核
b=tf.Variable(tf.zeros([10]))#偏置

#变量需要通过seesion初始化后，才能在session中使用
init=tf.global_variables_initializer()
sess.run(init)

# 把向量化后的图片x和卷积核W相乘，加上偏置b，然后计算每个分类的softmax概率值。
y=tf.nn.softmax(tf.matmul(x,W)+b)

#损失函数是目标类别和预测类别之间的交叉熵。
cross_entropy=-tf.reduce_sum(y_*tf.log(y))

#训练模型
train_step=tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

#返回的train_step操作对象，在运行时会使用梯度下降来更新参数。
#整个模型的训练可以通过反复地运行train_step来完成。
for i in range(1000):
    batch=mnist.train.next_batch(100)

#我们都会加载50个训练样本，然后执行一次train_step，
#并通过feed_dict将x 和 y_张量占位符用训练训练数据替代。

    train_step.run(feed_dict={x:batch[0],y_:batch[1]})

#返回一个布尔数组。为了计算分类的准确率，
#将布尔值转换为浮点数来代表对、错，然后取平均值。
#评估模型
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,"float"))

print(accuracy.eval(feed_dict={x:mnist.test.images,y_:mnist.test.labels}))


from distutils.core import setup, Extension

cLSH = Extension('cLSH',
                 sources = ['LSH.cpp', 'LSH_to_py.cpp',
                            'Element.cpp', 'ForDistance.cpp',
                            'Plain.cpp', 'Storage.cpp'])

# Compile Python module
setup (ext_modules = [cLSH],
       name = 'cLSH',
       description = 'cLSH Python module',
       version = '1.0')


def readData():
    dict = {}
    vett = []
    data = open('C:/Users/Paolo/Desktop/Tpsit/esercizi/python/grafi/covid_19/data.txt','r')
    lines = data.readlines()
    k = 0
    for line in lines:
        vett[k] = line.split(' ')
        dict[k] = vett[k][1:]
        k+=1
    data.close()
    return dict

def creaMatrixDaDict(dict):
    matrix = []
    for key,val in dict.items():
        matrix[key] = val
    return matrix

def findPatientsZero(mat, righe):
    vect = []
    k = 0
    for k in righe:
        for r in range(0,len(mat)):
            for c in range(0,len(mat[r])):
                if(mat[r][c]==k):
                    vect.append(k)
                    break
            if(mat[r][c]==k):
                break
    return vect

def stampaDict(dict): #stampo un dict
    print("\n{")
    for key, val in dict.items(): #scorro tutto dict
        print(f"\t{key}: {val},") #stampo la key e i val di quella key di dict

    print("}")

def main():
    data = readData()
    stampaDict(data)
    matrix = creaMatrixDaDict(data)
    paziente0 = findPatientsZero(matrix, len(data))
    print(paziente0)

if __name__ == "__main__":
    main()


# texto_variado = "palabra 123 +- ^*"
# print(type(texto_variado))

# # podermos utilizar comilas triples para la cadena de texto que hemos escrito
# print("""
# Funcionamiento de \
# programa: (opciones)
#     -1 para acceder a opciones
#         -2 para salir
# """)

###########################################################
# Suscripting e indexado

texto = "python"
# print(texto)
# print(texto[1])
# print(texto[3])
# print(texto[-1])
# print(texto[6]) # error no podemos ecceder a una posicion que no existe

# letra = texto[0]
# print(letra)

# # texto[0] = "P" # una cadena de texto es inmutable

# # redefinir una varriable
# letra = "P"
# print(letra)

# #sumar las partes de una cadena con otras variables
# texto_compuesto = letra + texto[1] # concatenacion
# print(texto_compuesto)

####################################################

# slicing o subtringing
texto = 'Python'

# print(texto[0:3])
# print(texto[0:-3])
# print(texto[0:-2])
# print(texto[2:])
# print(texto[:3])
# print(texto[-3::-1]) # para cambiar el orden conforme a No final que son los saltos
print(texto[::-1])


from typing import List

import numpy as np

from bayesian_network.graph import Graph
from chain.mc_mc_chain import MCMCChain
from scoring.scorer import Scorer

class MCMCMCChain:
    def __init__(self, scorer: Scorer, max_num_parents: int, graph: Graph,
                 num_chains: int,
                 first_temperature: float = 1.0,
                 temp_swap_iter_num: int = 100
                 ):
        self.scorer = scorer
        self.max_num_parents = max_num_parents
        self.num_chains = num_chains
        self.temp_swap_iter_num = temp_swap_iter_num

        self.steps = 0
        self.temp_swap_accepted = 0
        self.temps: List[float] = [first_temperature * i for i in range(1, num_chains + 1)]
        self.chains = [MCMCChain(
            scorer=scorer,
            max_num_parents=max_num_parents,
            graph=graph.copy()
        ) for i in range(num_chains)]

    @property
    def best_score(self):
        return max(chain.best_graph_score for chain in self.chains)

    @property
    def best_graph(self):
        best_score = self.chains[0].best_graph_score
        best_graph = self.chains[0].best_graph

        for i in range(1, self.num_chains):
            score, graph = self.chains[i].best_graph_score, self.chains[i].best_graph
            if score < best_score:
                best_score = score
                best_graph = graph

        return best_graph

    def wander(self):
        for i in range(self.num_chains):
            self.chains[i].temperature = self.temps[i]
            self.chains[i].wander()
        self.steps += 1

        if self.num_chains > 1 and (self.steps % self.temp_swap_iter_num) == 0:
            temp_swap_candidates = np.random.choice(self.num_chains, 2, replace=False)

            temp_0_idx, temp_1_idx = temp_swap_candidates
            temp_0_score, temp_1_score = self.chains[temp_0_idx].graph_score, self.chains[temp_1_idx].graph_score
            temp_0, temp_1 = self.temps[temp_0_idx], self.temps[temp_1_idx]

            log_prob = min(0, (temp_0 - temp_1) * (temp_1_score - temp_0_score))

            if np.log(max(1e-15, np.random.random())) < log_prob:
                self.temp_swap_accepted += 1
                self.temps[temp_0_idx], self.temps[temp_1_idx] = temp_1, temp_0

    def print_status(self):
        print(
            f"Current Score: {max(c.graph_score for c in self.chains)}\nBest Score: {max(c.best_graph_score for c in self.chains)}\nAcceptance Rate: {sum(c.steps_neighbor_accepted / c.steps_elapsed for c in self.chains) / self.num_chains}\nTemp Swap Rate:{self.temp_swap_accepted / max(1, (self.steps // self.temp_swap_iter_num))}")


import yt
import os
import sys
import numpy as np
from scipy import ndimage #, datasets

import astropy.units as u
import matplotlib.pyplot as plt
import matplotlib.colors as colors

from emission_models import uv, xrt, xray_bremsstrahlung
from visualization.colormaps import color_tables

# Importing sunpy dependencies for a synthetic map
# See creating custom maps: https://docs.sunpy.org/en/stable/how_to/create_custom_map.html
import sunpy.map
from sunpy.map.mapbase import GenericMap, SpatialPair
import textwrap
from astropy.coordinates import SkyCoord
from sunpy.coordinates import frames
from sunpy.map.header_helper import make_fitswcs_header
from sunpy.coordinates.sun import _radius_from_angular_radius

class SyntheticImage():

    """
    Template for a parent class for the Synthetic Images
    """
    # TODO: Should this be an abstract class? So that abstract methods can be explicitly defined in each of the
    #  inheriting classes

    def __init__(self):
        pass

class SyntheticFilterImage():

    """
    Load a yt readable dataset and plot synthetic image having given the instrument name and wavelength
    """

    def __init__(self, dataset, instr, channel, hint=None, units_override=None,
                 view_settings=None, plot_settings=None, **kwargs):
        """
        :param dataset: Path of the downsampled dataset or a dataset itself
        """

        self.box = None  # Importing a region within an initial dataset

        if isinstance(dataset, str):
            self.data = yt.load(dataset, units_override=units_override, hint=hint)
        elif isinstance(dataset, yt.data_objects.static_output.Dataset):
            self.data = dataset
        elif isinstance(dataset, yt.data_objects.selection_objects.region.YTRegion):
            self.data = dataset.ds
            self.box = dataset

        self.instr = instr
        self.obs = kwargs.get('obs', "DefaultInstrument")  # Name of the observatory
        self.obstime = kwargs.get('obstime', '2017-09-10')  # Observation time
        self.channel = channel
        self.view_settings = {'normal_vector': (0.0, 0.0, 1.0),  # pass vectors as mutable arguments
                              'north_vector': (-0.7, -0.3, 0.0)}
        self.__imag_field = None
        self.image = None

        if self.box:
            self.domain_width = np.abs(self.box.right_edge - self.box.left_edge).in_units('cm').to_astropy()
        else:
            self.domain_width = self.data.domain_width.in_units("cm").to_astropy() #convert unyt to astropy.units

        self.plot_settings = {'resolution': 512,
                              'vmin': 1e-15,
                              'vmax': 1e6,
                              'cmap': 'inferno',
                              'logscale': True,
                              'figpath': './prj_plt.png',
                              'frame': None,
                              'label': None}

    def make_filter_image_field(self, **kwargs):

        cmap = {}
        imaging_model = None
        instr_list = ['xrt', 'aia']

        if self.instr not in instr_list:
            raise ValueError("instr should be in the instrument list: ", instr_list)

        if self.instr == 'xrt':
            imaging_model = xrt.XRTModel("temperature", "density", self.channel)
            cmap['xrt'] = color_tables.xrt_color_table()
        if self.instr == 'aia':
            imaging_model = uv.UVModel("temperature", "density", self.channel)
            try:
                cmap['aia'] = color_tables.aia_color_table(int(self.channel) * u.angstrom)
            except ValueError:
                raise ValueError("AIA wavelength should be one of the following:"
                                 "1600, 1700, 4500, 94, 131, 171, 193, 211, 304, 335.")

        imaging_model.make_intensity_fields(self.data)

        field = str(self.instr) + '_filter_band'
        self.__imag_field = field

        if self.plot_settings:
            self.plot_settings['cmap'] = cmap[self.instr]

    def proj_and_imag(self, plot_settings=None, view_settings=None, **kwargs):

        self.make_filter_image_field()  # Create emission fields

        if plot_settings:
            self.plot_settings = plot_settings

        if view_settings:
            self.view_settings = view_settings

        if self.box:
            region = self.box
        else:
            region = self.data

        prji = yt.visualization.volume_rendering.off_axis_projection.off_axis_projection(
            region,
            [0.0, 0.5, 0.0],  # center position in code units
            normal_vector=self.view_settings['normal_vector'],  # normal vector (z axis)
            width=self.data.domain_width[0].value,  # width in code units
            resolution=self.plot_settings['resolution'],  # image resolution
            item=self.__imag_field,  # respective field that is being projected
            north_vector=self.view_settings['north_vector'])

        self.image = np.rot90(np.array(prji), k=3)

        self.image_zoom = kwargs.get('image_zoom', None)

        if self.image_zoom:
            self.image = self.zoom_out(self.image, self.image_zoom)

        # return self.image
        self.image_shift = kwargs.get('image_shift', None)  # (xshift, yshift)

        if self.image_shift:
            self.image = np.roll(self.image, (self.image_shift[0],
                                              self.image_shift[1]), axis=(1, 0))
        #if kwargs.get('shift_imag', 'EIT')

        # Fill background
        self.bkg_fill = kwargs.get('bkg_fill', None)
        if self.bkg_fill: self.image[self.image <= 0] = self.bkg_fill

    def zoom_out(self, img, scale):
        new_arr = np.ones_like(img) * img.min()
        if scale >= 1:
            raise ValueError("Scale parameter has to be lower than 1")
        zoomed_img = ndimage.zoom(img, scale)  # scale<1

        # fill the central part of the new image
        y, x = new_arr.shape
        cropx = (zoomed_img.shape[0])
        cropy = (zoomed_img.shape[1])
        startx = (x - cropx) // 2
        starty = (y - cropy) // 2
        new_arr[starty:starty + cropy, startx:startx + cropx] = zoomed_img
        return new_arr

    def make_synthetic_map(self, **kwargs):

        """
        Creates a synthetic map object that can be loaded/edited with sunpy
        :return:
        """
        data = self.image
        self.obstime = kwargs.get('obstime')

        # Define header parameters for the synthetic image

        # Coordinates can be passed from sunpy maps that comparisons are made width
        self.reference_coord = kwargs.get('reference_coord', SkyCoord(0*u.arcsec, 0*u.arcsec,
                                   obstime=self.obstime,
                                   observer='earth',  # Temporarily 1 AU away
                                   frame=frames.Helioprojective))

        self.reference_pixel = kwargs.get('reference_pixel', u.Quantity([(data.shape[1] - 1)/2.,
            (data.shape[0] - 1)/2.], u.pixel))  # Reference pixel along each axis: Defaults to the center of data array

        asec2cm = _radius_from_angular_radius(1. * u.arcsec, 1 * u.AU).to(u.cm)  # centimeters per arcsecond at 1 AU
        resolution = self.plot_settings['resolution']
        domain_size = self.domain_width.max()
        len_asec = (domain_size/asec2cm).value
        scale_ = [len_asec/resolution, len_asec/resolution]

        self.scale = kwargs.get('scale', u.Quantity(scale_, u.arcsec/u.pixel))
        self.telescope = kwargs.get('telescope', 'EIT')
        self.observatory = kwargs.get('observatory', 'SOHO')
        self.detector = kwargs.get('detector', 'Synthetic')
        self.instrument = kwargs.get('instrument', None)
        if isinstance(self.channel, int):
            self.wavelength = int(self.channel) * u.angstrom
        else:
            self.wavelength = None
        self.exposure = kwargs.get('exposure', None)
        self.unit = kwargs.get('unit', None)

        # Creating header using sunpy
        header = make_fitswcs_header(data,
                                     coordinate=self.reference_coord,
                                     reference_pixel=self.reference_pixel,
                                     scale=self.scale,
                                     telescope=self.telescope,
                                     detector=self.detector,
                                     instrument=self.instrument,
                                     observatory=self.observatory,
                                     wavelength=self.wavelength,
                                     exposure=self.exposure,
                                     unit=self.unit)

        self.synth_map = sunpy.map.Map(data, header)
        return self.synth_map

    def __str__(self):
        return f"{self._text_summary()}\n{self.data.__repr__()}"

    def __repr__(self):
        return f"{object.__repr__(self)}\n{self}"

    def _text_summary(self):
        # similarly to sunpy.map.mapbase GenericMap(NDData)
        return textwrap.dedent("""\
        Synthetic image from the yt dataset
        ---------
        Instrument:\t\t {inst}
        Wavelength:\t\t {wave}
        """).format(inst=self.instr,
                    wave=self.channel)

#TODO: Write a parent class for Synthetic images that both SyntheticBandImage and SyntheticFilterImage can inherit from,
# so you don't need to describe the same input parameters, such as *dataset*, or *view_settings* and avoid code repetition.
# Get back to this when you will start working on nonthermal emission models, and further on gyrosynchrotron.
# IMPORTANT: proj_and_imag can be inherited from this parent class as well, however exact methods are to be redefined
# Or just inherit from SyntheticFilterImage (?)

class SyntheticBandImage():

    """
    Class to store synthetic X-ray images generated in a given *energy band*, such as ones from RHESSI.
    """

    def __init__(self, dataset, emin, emax, nbins, emission_model, hint=None, units_override=None,
                 view_settings=None, plot_settings=None, **kwargs):

        """
        :param dataset: Path of the downsampled dataset or a dataset itself
        :param emin: low energy limit in keV
        :param emax: high energy limit in keV
        :param nbins: number of energy bins to compute synthetic spectra and images
        """

        self.emin = emin
        self.emax = emax
        self.nbins = nbins
        self.emission_model = emission_model  # Thermal / Non-thermal

        self.box = None  # Importing a region within an initial dataset

        if isinstance(dataset, str):
            self.data = yt.load(dataset, units_override=units_override, hint=hint)
        elif isinstance(dataset, yt.data_objects.static_output.Dataset):
            self.data = dataset
        elif isinstance(dataset, yt.data_objects.selection_objects.region.YTRegion):
            self.data = dataset.ds
            self.box = dataset

        self.obs = kwargs.get('obs', "DefaultInstrument")  # Name of the observatory
        self.instr = kwargs.get('instr', 'RHESSI')
        self.binscale = kwargs.get('binscale', 'linear')
        self.obstime = kwargs.get('obstime', '2017-09-10')  # Observation time

        self.view_settings = {'normal_vector': (0.0, 0.0, 1.0),  # pass vectors as mutable arguments
                              'north_vector': (-0.7, -0.3, 0.0)}
        self.__imag_field = None
        self.image = None

        if self.box:
            self.domain_width = np.abs(self.box.right_edge - self.box.left_edge).in_units('cm').to_astropy()
        else:
            self.domain_width = self.data.domain_width.in_units("cm").to_astropy()  # convert unyt to astropy.units

    def make_band_image_field(self, **kwargs):

        cmap = {}
        imaging_model = None

        if self.emission_model == 'Thermal':
            imaging_model = xray_bremsstrahlung.ThermalBremsstrahlungModel

        imaging_model.make_intensity_fields(self.data)
        field = 'xray_' + str(emin) + '_' + str(emax) + '_keV_band'
        self.__imag_field = field


import time
from selenium.webdriver.common.by import By

link = "http://selenium1py.pythonanywhere.com/catalogue/coders-at-work_207/"

def test_find_add_to_cart_button(browser):
    try:
        browser.get(link)
        time.sleep(5)
        button = browser.find_elements(By.CLASS_NAME, "btn-add-to-basket")

    finally:
        assert button, "No ADD-button on the link"


# -----------------------------------------------------------
# Licensed under the terms of GNU GPL 2
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# -----------------------------------------------------------
# Tim Hancock/Matthias Kuhn 2017
# Oslandia 2022

import configparser
import os

from qgis.core import Qgis, QgsExpressionContextUtils, QgsProject
from qgis.PyQt.QtCore import NULL, QObject, pyqtSignal
from qgis.PyQt.QtWidgets import QMessageBox
from qgis.utils import iface

from .core.tomsMessageLog import TOMsMessageLog

class TOMsParams(QObject):

    tomsParamsNotFound = pyqtSignal()
    """ signal will be emitted if there is a problem with opening TOMs - typically a layer missing """
    tomsParamsSet = pyqtSignal()
    """ signal will be emitted if there is a problem with opening TOMs - typically a layer missing """

    def __init__(self):
        QObject.__init__(self)

        TOMsMessageLog.logMessage("In TOMSParams.init ...", level=TOMsMessageLog.DEBUG)
        self.tomsParamsList = [
            "BayWidth",
            "BayLength",
            "BayOffsetFromKerb",
            "LineOffsetFromKerb",
            "CrossoverShapeWidth",
            "PhotoPath",
            "MinimumTextDisplayScale",
            "TOMsDebugLevel",
            "AllowZoneEditing",
        ]

        self.tomsParamsDict = {}

    def getParams(self):

        TOMsMessageLog.logMessage("In TOMsParams.getParams ...", level=TOMsMessageLog.DEBUG)
        found = True

        # Check for project being open
        currProject = QgsProject.instance()

        if len(currProject.fileName()) == 0:
            QMessageBox.information(None, "ERROR", ("Project not yet open"))
            found = False

        else:

            # TOMsMessageLog.logMessage("In TOMSLayers.getParams ... starting to get", level=logging.DEBUG)

            for param in self.tomsParamsList:
                TOMsMessageLog.logMessage(
                    "In TOMsParams.getParams ... getting " + str(param),
                    level=TOMsMessageLog.DEBUG,
                )

                currParam = None
                try:
                    currParam = QgsExpressionContextUtils.projectScope(QgsProject.instance()).variable(param)
                except Exception:
                    QMessageBox.information(
                        None,
                        "ERROR",
                        ("Property " + param + " is not present"),
                    )

                if len(str(currParam)) > 0:
                    self.tomsParamsDict[param] = currParam
                    TOMsMessageLog.logMessage(
                        "In TOMsParams.getParams ... set " + str(param) + " as " + str(currParam),
                        level=TOMsMessageLog.DEBUG,
                    )
                else:
                    QMessageBox.information(
                        None,
                        "ERROR",
                        ("Property " + param + " is not present"),
                    )
                    found = False
                    break

        if not found:
            self.tomsParamsNotFound.emit()
        else:
            self.tomsParamsSet.emit()

            # TOMsMessageLog.logMessage("In TOMSLayers.getParams ... finished ", level=logging.DEBUG)

        return found

    def setParam(self, param):
        return self.tomsParamsDict.get(param)

class TOMsConfigFile(QObject):

    tomsConfigFileNotFound = pyqtSignal()
    """ signal will be emitted if TOMs config file is not found """

    def __init__(self):
        super().__init__()

        TOMsMessageLog.logMessage("In TOMsConfigFile.init ...", level=TOMsMessageLog.DEBUG)

        self.config = configparser.ConfigParser()

    def initialiseTOMsConfigFile(self):

        # function to open file "toms.conf". Assume path is same as project file - unless environ variable is set

        # check for environ variable
        configPath = None
        try:
            configPath = os.environ.get("TOMs_CONFIG_PATH")
        except Exception:
            TOMsMessageLog.logMessage("In getTOMsConfigFile. TOMs_CONFIG_PATH not found ...", level=Qgis.Info)

        if configPath is None:
            configPath = QgsExpressionContextUtils.projectScope(QgsProject.instance()).variable("project_home")

        if configPath == NULL:
            QMessageBox.information(
                None,
                "Information",
                "Project probably not opened",
                QMessageBox.Ok,
            )
            self.tomsConfigFileNotFound.emit()
            return

        TOMsMessageLog.logMessage(
            "In getTOMsConfigFile. config_path: {}".format(configPath),
            level=TOMsMessageLog.DEBUG,
        )

        configFile = os.path.abspath(os.path.join(configPath, "TOMs.conf"))
        TOMsMessageLog.logMessage(
            "In getTOMsConfigFile. TOMs_CONFIG_PATH: {}".format(configFile),
            level=TOMsMessageLog.DEBUG,
        )

        if not os.path.isfile(configFile):
            QMessageBox.information(
                None,
                "Information",
                "TOMs configuration file not found. Stopping ...",
                QMessageBox.Ok,
            )
            self.tomsConfigFileNotFound.emit()

        # now read file
        self.readTOMsConfigFile(configFile)

    def readTOMsConfigFile(self, configFile):

        try:
            self.config.read(configFile)
        except Exception as e:
            TOMsMessageLog.logMessage(
                "In TOMsConfigFile.init. Error reading config file ... {}".format(e),
                level=Qgis.Warning,
            )
            self.tomsConfigFileNotFound.emit()

    def getTOMsConfigElement(self, section, value):
        item = None
        try:
            item = self.config[section][value]
        except KeyError:
            TOMsMessageLog.logMessage(
                "In getTOMsConfigElement. not able to find: {}:{}".format(section, value),
                level=Qgis.Info,
            )

        return item

class TOMsLayers(QObject):
    tomsLayersNotFound = pyqtSignal()
    """ signal will be emitted if there is a problem with opening TOMs - typically a layer missing """
    tomsLayersSet = pyqtSignal()
    """ signal will be emitted if everything is OK with opening TOMs """

    def __init__(self):
        QObject.__init__(self)

        TOMsMessageLog.logMessage("In TOMSLayers.init ...", level=Qgis.Info)

        self.tomsLayerDict = {}
        self.formPath = ""
        self.tomsLayerList = None
        self.configFileObject = None

    def getTOMsLayerListFromConfigFile(self, configFileObject: "TOMsConfigFile"):
        self.configFileObject = configFileObject
        layers = configFileObject.getTOMsConfigElement("TOMsLayers", "layers")
        if layers:
            self.tomsLayerList = layers.split("\n")
            return True

        self.tomsLayersNotFound.emit()
        return False

    def getTOMsFormPathFromConfigFile(self, configFileObject):
        formPath = configFileObject.getTOMsConfigElement("TOMsLayers", "form_path")
        return os.path.expandvars(formPath)  # expand env var like USERPROFILE

    def setLayers(self, configFileObject):

        TOMsMessageLog.logMessage("In TOMSLayers.getLayers ...", level=Qgis.Info)
        found = True

        # Check for project being open
        project = QgsProject.instance()

        if len(project.fileName()) == 0:
            QMessageBox.information(iface.mainWindow(), "ERROR", "Project not yet open")
            found = False

        else:

            if not self.getTOMsLayerListFromConfigFile(configFileObject):
                QMessageBox.information(
                    iface.mainWindow(),
                    "ERROR",
                    "Problem with TOMs config file ...",
                )
                self.tomsLayersNotFound.emit()
                found = False

            self.formPath = self.getTOMsFormPathFromConfigFile(configFileObject)
            TOMsMessageLog.logMessage(
                "In TOMsLayers:setLayers. formPath is {} ...".format(self.formPath),
                level=Qgis.Info,
            )

            # check that path exists
            if not os.path.isdir(self.formPath):
                QMessageBox.information(
                    iface.mainWindow(),
                    "ERROR",
                    "Form path in config file was not found ...",
                )
                self.tomsLayersNotFound.emit()
                found = False

        if found:
            for layer in self.tomsLayerList:
                if QgsProject.instance().mapLayersByName(layer):
                    self.tomsLayerDict[layer] = QgsProject.instance().mapLayersByName(layer)[0]
                    # set paths for forms
                    layerEditFormConfig = self.tomsLayerDict[layer].editFormConfig()

                    if len(layerEditFormConfig.initFilePath()) > 0:
                        TOMsMessageLog.logMessage(
                            "In TOMsLayers:setLayers. cleaning useless initFilePath for layer {}...".format(layer),
                            level=Qgis.Info,
                        )
                        layerEditFormConfig.setInitFilePath("")
                        self.tomsLayerDict[layer].setEditFormConfig(layerEditFormConfig)

                    uiPath = layerEditFormConfig.uiForm()
                    if len(uiPath) > 0:
                        TOMsMessageLog.logMessage(
                            "In TOMsLayers:setLayers. current ui_path for layer {} is {} ...".format(layer, uiPath),
                            level=Qgis.Info,
                        )
                        # try to get basename - doesn't seem to work on Linux
                        # base_ui_path = os.path.basename(ui_path)
                        pathAbsolute = os.path.abspath(os.path.join(self.formPath, os.path.basename(uiPath)))
                        if not os.path.isfile(pathAbsolute):
                            TOMsMessageLog.logMessage(
                                "In TOMsLayers:setLayers. form path not found for layer {} ...".format(layer),
                                level=Qgis.Warning,
                            )
                        else:
                            TOMsMessageLog.logMessage(
                                "In TOMsLayers:setLayers. setting new path for form {} ...".format(pathAbsolute),
                                level=Qgis.Info,
                            )
                            layerEditFormConfig.setUiForm(pathAbsolute)
                            self.tomsLayerDict[layer].setEditFormConfig(layerEditFormConfig)

                            # TODO: may need to reinstate original values here - so save them somewhere useful
                    else:
                        TOMsMessageLog.logMessage(
                            "In TOMsLayers:setLayers. no ui_path for layer {}".format(layer),
                            level=Qgis.Info,
                        )

                else:
                    QMessageBox.information(
                        iface.mainWindow(),
                        "ERROR",
                        "Table " + layer + " is not present",
                    )
                    found = False
                    break

        # TODO: need to deal with any errors arising ...

        if not found:
            self.tomsLayersNotFound.emit()

    def removePathFromLayerForms(self):

        TOMsMessageLog.logMessage("In TOMSLayers.removePathFromLayerForms ...", level=Qgis.Info)

        # Check for project being open
        project = QgsProject.instance()

        if len(project.fileName()) == 0:
            QMessageBox.information(iface.mainWindow(), "ERROR", ("Project not yet open"))

        else:

            for layer in self.tomsLayerList:
                if QgsProject.instance().mapLayersByName(layer):
                    self.tomsLayerDict[layer] = QgsProject.instance().mapLayersByName(layer)[0]
                    # set paths for forms
                    layerEditFormConfig = self.tomsLayerDict[layer].editFormConfig()
                    uiPath = layerEditFormConfig.uiForm()
                    TOMsMessageLog.logMessage(
                        "In TOMsLayers:removePathFromLayerForms. ui_path for layer {} is {} ...".format(layer, uiPath),
                        level=Qgis.Info,
                    )
                    if len(self.formPath) > 0 and len(uiPath) > 0:
                        # try to get basename - doesn't seem to work on Linux
                        # base_ui_path = os.path.basename(ui_path)
                        formName = os.path.basename(uiPath)
                        layerEditFormConfig.setUiForm(formName)
                        self.tomsLayerDict[layer].setEditFormConfig(layerEditFormConfig)

                else:
                    QMessageBox.information(
                        iface.mainWindow(),
                        "ERROR",
                        ("Table " + layer + " is not present"),
                    )
                    break

    def getLayer(self, layer):
        return self.tomsLayerDict.get(layer)

class TOMsLabelLayerNames(QObject):
    def __init__(self, currRestrictionLayer):
        QObject.__init__(self)

        TOMsMessageLog.logMessage(
            "In TOMsLabelLayerName:initialising .... {}".format(currRestrictionLayer),
            level=Qgis.Warning,
        )

        self.labelLayerName = self.setCurrLabelLayerNames(currRestrictionLayer)
        self.labelLeaderLayersNames = self.setCurrLabelLeaderLayerNames(currRestrictionLayer)

    def setCurrLabelLayerNames(self, currRestrictionLayer):
        # given a layer return the associated layer with label geometry
        # get the corresponding label layer

        if currRestrictionLayer.name() == "Bays":
            labelLayerName = ["Bays.label_pos"]
        if currRestrictionLayer.name() == "Lines":
            labelLayerName = ["Lines.label_pos", "Lines.label_loading_pos"]
        if currRestrictionLayer.name() == "Signs":
            labelLayerName = []
        if currRestrictionLayer.name() == "RestrictionPolygons":
            labelLayerName = ["RestrictionPolygons.label_pos"]
        if currRestrictionLayer.name() == "CPZs":
            labelLayerName = ["CPZs.label_pos"]
        if currRestrictionLayer.name() == "ParkingTariffAreas":
            labelLayerName = ["ParkingTariffAreas.label_pos"]

        if len(labelLayerName) == 0:
            return [""]

        return labelLayerName

    def getCurrLabelLayerNames(self):
        # given a layer return the associated layer with label geometry
        # get the corresponding label layer

        return self.labelLayerName

    def setCurrLabelLeaderLayerNames(self, currRestrictionLayer):
        # given a layer return the associated layer with label geometry
        # get the corresponding label layer

        if currRestrictionLayer.name() == "Bays":
            labelLeaderLayersNames = ["Bays.label_ldr"]
        if currRestrictionLayer.name() == "Lines":
            labelLeaderLayersNames = ["Lines.label_ldr", "Lines.label_loading_ldr"]
        if currRestrictionLayer.name() == "Signs":
            labelLeaderLayersNames = []
        if currRestrictionLayer.name() == "RestrictionPolygons":
            labelLeaderLayersNames = ["RestrictionPolygons.label_ldr"]
        if currRestrictionLayer.name() == "CPZs":
            labelLeaderLayersNames = ["CPZs.label_ldr"]
        if currRestrictionLayer.name() == "ParkingTariffAreas":
            labelLeaderLayersNames = ["ParkingTariffAreas.label_ldr"]

        if len(labelLeaderLayersNames) == 0:
            return [""]

        return labelLeaderLayersNames

    def getCurrLabelLeaderLayerNames(self):
        return self.labelLeaderLayersNames


from collections import defaultdict as dd
from bisect import bisect as bis, bisect_left as bis2

mod = 998244353
N = 1<<20
ti = 998243401 # (2^{-20} % mod)

def ri():
    return int(input())

def rl():
    return list(map(int, input().split()))

def digsum(n):
    ans = 0
    while n:
        ans += n % 10
        n //= 10
    return ans

def get_valid(L):
    masks = [0] * N
    n = len(L)
    cutoff = (n + 1) >> 1
    counts = [0] * 5
    xors   = [0] * 5

    def backtrack(i):
        if i == n:
            if max(counts) >= cutoff:
                mask = 0
                shift = 1
                for j in range(5):
                    mask += xors[j] * shift
                    shift <<= 4
                masks[mask] += 1
        else:
            for j in range(5):
                counts[j] += 1
                xors[j] ^= L[i]
                backtrack(i + 1)
                counts[j] -= 1
                xors[j] ^= L[i]

    backtrack(0)
    return masks

def fwht(a):
    """In-place Fast Walsh–Hadamard Transform of array a."""
    h = 1
    n = len(a)
    while h < n:
        for i in range(0, n, h * 2):
            for j in range(i, i + h):
                x = a[j]
                y = a[j + h]
                # a[j] = (x + y) % mod
                # a[j + h] = (x - y) % mod
                a[j] = x + y
                a[j + h] = x - y
        h *= 2
    # for i in range(n):
        # a[i] %= mod

# main
# pre-processing
n, q = rl()
ghosts = []
for _ in range(n):
    bitset = 0
    moves = set(input().split()[1:])
    if "spook" in moves:
        bitset |= 1
    if "hide" in moves:
        bitset |= 2
    if "creep" in moves:
        bitset |= 4
    if "float" in moves:
        bitset |= 8
    ghosts.append(bitset)
scores = rl()
def get_score(m):
    total_score = 0
    i = 0
    while m:
        total_score += scores[i] * (m&1)
        m >>= 1
        i = (i + 1) % 4
    return total_score

# brute force combinatorics (backtracking)
groups = dd(list)
for i in range(n):
    groups[digsum(i+1)].append(ghosts[i])
masks = [get_valid(L) for L in groups.values()]

# using walsh-hadamard in place
# storing final result in first
# array. Not using sqrt(2), so
# in the end, need to back out
# 2^20 (mod p)
for i in range(len(masks)):
    fwht(masks[i])

for i in range(1, len(masks)):
    for j in range(N):
        masks[0][j] = (masks[0][j] * masks[i][j]) % mod

fwht(masks[0])
for i in range(N):
    masks[0][i] = (masks[0][i] * ti) % mod

# filling sparse array of counts
# of possible scores
ways = dd(int)
for i in range(N):
    v = masks[0][i]
    if v != 0:
        ways[get_score(i)] += v

S = sorted(list(ways.keys()))
m = len(S)
partials = [0] * (m + 1)
for i in range(m):
    partials[i + 1] = partials[i] + ways[S[i]]

# process queries
for _ in range(q):
    a, b = rl()
    i = bis(S, a - 1)
    j = bis(S, b)
    print ((partials[j] - partials[i]) % mod)


'''
Created on Feb. 26, 2022

@author: Anmol Nagpal
'''

"""
Given the array favoriteCompanies where favoriteCompanies[i] is the list of
favorites companies for the ith person (indexed from 0).

Return the indices of people whose list of favorite companies is not a subset
of any other list of favorites companies. You must return the indices in
increasing order.
"""

# runtime = O(n^2)
# space = O(n)
class Solution:
    def peopleIndexes(self, favoriteCompanies: List[List[str]]) -> List[int]:
        index_list = []
        set_list = {sub_list: set(element) for sub_list, element in enumerate(favoriteCompanies)}
        # O(n)
        for i in range(len(set_list)):
            # O(n)
            for j in range(len(set_list)):
                is_subList = False
                if(i != j):
                    if set_list[i].intersection(set_list[j]) == set_list[i]:
                        is_subList = True
                        break
            if not is_subList:
                index_list.append(i)
        return index_list


# Jesus Carlos Martinez Gonzalez
# 05/06/2023
# collections.namedtuple (https://www.hackerrank.com/challenges/py-collections-namedtuple/problem)

"""
Dr. John Wesley has a spreadsheet containing a list of student's IDs, marks, class and names.

Your task is to help Dr. Wesley calculate the average marks of the students.

Challenge: Complete the problem within 4 LOC
"""

from collections import namedtuple

n = int(input())
Student = namedtuple('Student', input().split())

print(sum(int(Student(*input().split()).MARKS) for _ in range(n)) / n)


from flask import Flask, render_template, request, Markup
from flask_ckeditor import CKEditor, CKEditorField
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField

app = Flask(__name__)
app.config['WTF_CSRF_ENABLED'] = True
app.config['CKEDITOR_PKG_TYPE'] = 'standard'  # CKEditorのパッケージタイプを指定する（basic、standard、fullなど）
ckeditor = CKEditor(app)

class PostForm(FlaskForm):
    title = StringField('タイトル')
    content = CKEditorField('内容')
    submit = SubmitField('投稿')

@app.route('/', methods=['GET', 'POST'])
def index():
    form = PostForm()
    if form.validate_on_submit():
        # フォームが正しく送信された場合の処理
        title = request.form.get('title')
        content = request.form.get('content')
        div = Markup(content)
        return render_template('page.html', div=div)
    return render_template('index.html', form=form)

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


#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: leeyoshinari
import json
import smtplib
import shutil
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from logger import logger, cfg

def sendMsg(html, paths, failure_num=1, is_path=True, is_send=True):
    """
    发送邮件
    :param html: 邮件正文用到的html文件路径，或者html
    :param paths:
    :param failure_num: 失败的用例数
    :param is_path: bool，True表示html是一个路径，False表示html是html
    :param is_send: bool，是否发邮件，仅用于第一次发送失败后，再次发送
    :return:
    """
    flag = 0
    is_email = int(cfg.getConfig('is_email'))
    if is_email:
        if is_email == 1:
            flag = 1
        if is_email == 2:
            if failure_num > 0:
                flag = 1
            else:
                logger.info('所有用例执行成功，不发送邮件，已跳过。')
        if is_email == 3:
            if failure_num == 0:
                flag = 1
            else:
                logger.info('有执行失败的用例，不发送邮件，已跳过。')
    else:
        logger.info('设置为不自动发送邮件，已跳过。')

    if flag:
        try:
            if paths["method"] == "GET":
                shutil.copy(paths["email_file"], paths["new_email_file"])
            else:
                if paths["post_data"].get('email'):
                    replace_email(paths["email_file"], paths["post_data"]['email'], paths["new_email_file"])

            email_dict = json.load(open(paths["new_email_file"], 'r', encoding='utf-8'))
            subject = email_dict['subject']
            send_to = email_dict['receiveEmail']
            receive_name = email_dict['receiveName']
            logger.info('开始发送邮件，收件人{}'.format(send_to))
            message = MIMEMultipart()
            message['From'] = Header(cfg.getConfig('sender_name'))      # 发件人名字
            message['To'] = Header(receive_name)    # 收件人名字
            message['Subject'] = Header(subject, 'utf-8')   # 邮件主题

            if is_path:
                with open(html, 'r', encoding='utf-8') as f:
                    fail_case = f.read()
            else:
                fail_case = html

            email_text = MIMEText(fail_case, 'html', 'utf-8')
            message.attach(email_text)  # 添加邮件正文

            try:
                server = smtplib.SMTP_SSL(cfg.getConfig('smtp'), 465)
            except Exception as err:
                logger.error(err)
                server = smtplib.SMTP(cfg.getConfig('smtp'), 25)

            server.login(cfg.getConfig('sender_email'), '123456')  # 登陆邮箱
            server.sendmail(cfg.getConfig('sender_email'), send_to.split(','), message.as_string())  # 发送邮件
            server.quit()
            del fail_case, email_text, message, server
            logger.info('邮件发送成功')
        except Exception as err:
            logger.error(err)
            if is_send:
                sendMsg(html, paths, is_path=is_path, is_send=False)   # 发送失败后，重发一次

def replace_email(src, new_dict, dst):
    old_dict = json.load(open(src, 'r', encoding='utf-8'))
    for k, v in new_dict.items():
        old_dict.update({k: v})

    with open(dst, 'w', encoding='utf-8') as f:
        f.write(json.dumps(old_dict))


with open("input.txt") as f:
    monkeys = [m.split("\n") for m in f.read().split("\n\n")]

items = []
operations = []
tests = []
bigNhelper = 1

for m in monkeys:
    items.append([int(w) for w in m[1].split(": ")[1].split(", ")])

    operations.append(m[2].split(" = ")[1])

    # (divisor, idTrue, idFalse)
    tests.append((int(m[3].split(" by ")[1]), int(m[4].split(" monkey ")[1]), int(m[5].split(" monkey ")[1])))
    bigNhelper *= int(m[3].split(" by ")[1])

def worry(divide = True, rounds = 20):
    count = [0 for _ in monkeys]
    for _ in range(rounds):
        for id, mitems in enumerate(items):
            for item in mitems:
                count[id] += 1
                old = item
                item = eval(operations[id])
                if divide:
                    item //= 3
                else:
                    item %= bigNhelper

                if item % tests[id][0] == 0:
                    items[tests[id][1]].append(item)
                else:
                    items[tests[id][2]].append(item)

            items[id] = []

    count.sort(reverse = True)
    return count[0]*count[1]

backup = [[i for i in m] for m in items]
print(f"Part One: {worry()}")

items = backup
print(f"Part Two: {worry(False, 10000)}")


import matplotlib
matplotlib.use('Agg')
from matplotlib.pylab import *
from skimage.feature import greycomatrix, greycoprops
from sklearn.metrics.cluster import entropy
import numpy as np
import cv2
import csv
import math
import scipy.spatial.distance as dist
from PIL import Image
import skimage.io

root_path = '/static/content/'
UPLOAD_FOLDER = '/static/uploads/'

def colorQuantization(colorChannelImage, bins, max_color=255):
    # ubah varian warna menjadi varian bins
    quant = np.array(colorChannelImage) * (bins / max_color)
    quant = np.floor(quant)
    quant[quant >= bins] = bins - 1

    return quant

def combineColorQuantization(image, B_bins, G_bins, R_bins):
    # extrak matrix dari color channel image
    B = image[:, :, 0]
    G = image[:, :, 1]
    R = image[:, :, 2]

    # kuantisasikan tiap color channel
    B_quant = colorQuantization(B, B_bins)  # bisa coba diganti dengan K-Means
    G_quant = colorQuantization(G, G_bins)
    R_quant = colorQuantization(R, R_bins)

    # menggabungkan kuantisasi warna
    combine_quant = (B_bins * G_bins * R_quant) + (B_bins * G_quant) + B_quant

    return combine_quant

def edgeQuantization(image, binsTheta):
    # extrak matrix dari color channel image
    B = image[:, :, 0]
    G = image[:, :, 1]
    R = image[:, :, 2]

    # simplementasi sobel
    Bx = cv2.Sobel(B, cv2.CV_64F, 1, 0, ksize=3)
    By = cv2.Sobel(B, cv2.CV_64F, 0, 1, ksize=3)
    Gx = cv2.Sobel(G, cv2.CV_64F, 1, 0, ksize=3)
    Gy = cv2.Sobel(G, cv2.CV_64F, 0, 1, ksize=3)
    Rx = cv2.Sobel(R, cv2.CV_64F, 1, 0, ksize=3)
    Ry = cv2.Sobel(R, cv2.CV_64F, 0, 1, ksize=3)

    # get |a| and |b|
    a = sqrt(Bx ** 2 + Gx ** 2 + Rx ** 2)
    b = sqrt(By ** 2 + Gy ** 2 + Ry ** 2)

    # get ab
    ab = (Bx * By) + (Gx * Gy) + (Rx * Ry)

    # image orientation
    (h, w) = a.shape
    # binsTheta = 18
    theta = np.zeros((h, w))

    # edge quantization
    for i in range(0, h):
        for j in range(0, w):
            if (a[i, j] == 0 or b[i, j] == 0):
                cosab1 = 0
            else:
                cosab1 = ab[i, j] / (a[i, j] * b[i, j])
            theta1 = math.degrees(np.arccos(cosab1))
            if (math.isnan(theta1)):
                theta1 = 0
            theta[i, j] = math.floor(theta1 * (binsTheta / 180))
            if (theta[i, j] >= binsTheta - 1):
                theta[i, j] = binsTheta - 1

    return np.array(theta)

def textonSearch(colorQuant, cBins, edgeQuant, eBins):
    # tentukan bentuk dari citra
    (h, w) = colorQuant.shape

    # untuk menangani image yang dimensinya ganjil
    if (h % 2 == 1):
        a = np.zeros((h + 1, w))
        colorQuant = colorQuant[:-1, :]
        edgeQuant = edgeQuant[:-1, :]

    if (w % 2 == 1):
        a = np.zeros((h, w + 1))
        colorQuant = colorQuant[:, :-1]
        edgeQuant = edgeQuant[:, :-1]

    (h, w) = colorQuant.shape
    color_img = np.zeros((h, w))
    edge_img = np.zeros((h, w))

    # sliding window check for all color channel
    for i in range(0, h, 2):
        for j in range(0, w, 2):

            # texton search for color
            cTemp = colorQuant[i:i + 2, j:j + 2]
            if (cTemp[0, 0] == cTemp[0, 1]):  # texton type 1
                color_img[i, j] = colorQuant[i, j]
                color_img[i, j + 1] = colorQuant[i, j + 1]
            if (cTemp[0, 0] == cTemp[1, 0]):  # texton type 2
                color_img[i, j] = colorQuant[i, j]
                color_img[i + 1, j] = colorQuant[i + 1, j]
            if (cTemp[0, 0] == cTemp[1, 1]):  # texton type 3
                color_img[i, j] = colorQuant[i, j]
                color_img[i + 1, j + 1] = colorQuant[i + 1, j + 1]
            if (cTemp[1, 0] == cTemp[1, 1]):  # texton type 4
                color_img[i + 1, j] = colorQuant[i + 1, j]
                color_img[i + 1, j + 1] = colorQuant[i + 1, j + 1]
            if (cTemp[0, 1] == cTemp[1, 1]):  # texton type 5
                color_img[i, j + 1] = colorQuant[i, j + 1]
                color_img[i + 1, j + 1] = colorQuant[i + 1, j + 1]
            if (cTemp[0, 1] == cTemp[1, 0]):  # texton type 6
                color_img[i, j + 1] = colorQuant[i, j + 1]
                color_img[i + 1, j] = colorQuant[i + 1, j]

            # pencarian garis tepi menggunakan texton
            eTemp = edgeQuant[i:i + 2, j:j + 2]
            if (eTemp[0, 0] == eTemp[0, 1]):  # texton type 1
                edge_img[i, j] = edgeQuant[i, j]
                edge_img[i, j + 1] = edgeQuant[i, j + 1]
            if (eTemp[0, 0] == eTemp[1, 0]):  # texton type 2
                edge_img[i, j] = edgeQuant[i, j]
                edge_img[i + 1, j] = edgeQuant[i + 1, j]
            if (eTemp[0, 0] == eTemp[1, 1]):  # texton type 3
                edge_img[i, j] = edgeQuant[i, j]
                edge_img[i + 1, j + 1] = edgeQuant[i + 1, j + 1]
            if (eTemp[1, 0] == eTemp[1, 1]):  # texton type 4
                edge_img[i + 1, j] = edgeQuant[i + 1, j]
                edge_img[i + 1, j + 1] = edgeQuant[i + 1, j + 1]
            if (eTemp[0, 1] == eTemp[1, 1]):  # texton type 5
                edge_img[i, j + 1] = edgeQuant[i, j + 1]
                edge_img[i + 1, j + 1] = edgeQuant[i + 1, j + 1]
            if (eTemp[0, 1] == eTemp[1, 0]):  # texton type 6
                edge_img[i, j + 1] = edgeQuant[i, j + 1]
                edge_img[i + 1, j] = edgeQuant[i + 1, j]

    # make color histogram
    cF = np.histogram(color_img.ravel(), cBins, [0, 64])
    colorFeatures = (np.array(cF[0]) / 6)  # perlu dibagi dg 6 meyesuaikan dg jumlah type texton yg digunakan

    # make edge histogram
    eF = np.histogram(edge_img.ravel(), eBins, [0, 18])
    edgeFeatures = (np.array(eF[0]) / 6)

    # combine color and edge features
    features = []
    features.extend(colorFeatures)
    features.extend(edgeFeatures)

    return features

def GLCM(image):
    # convert iamge to greyscale
    grey_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # make co-occurance matrix
    gm = greycomatrix(grey_img, [1], [0, np.pi / 4, np.pi / 2, 3 * np.pi / 4], levels=256, normed=True)
    (h, w) = gm[:, :, 0, 0].shape

    glcm_features = []

    # calculate energy, contrast, correlation, entropy
    # using scikit library

    energy = greycoprops(gm, 'energy')
    contrast = greycoprops(gm, 'contrast')
    correlation = greycoprops(gm, 'correlation')
    glcm_features.extend(energy.tolist())
    glcm_features.extend(contrast.tolist())
    glcm_features.extend(correlation.tolist())

    entropy = []
    for i in range(0, 4):
        e = np.abs(gm[:, :, 0, i] * np.log2(gm[:, :, 0, i]))
        e[isnan(e)] = 0
        entropy.append(sum(e))

    return glcm_features, entropy

class Searcher:
    def __init__(self, indexPath):
        # store the index path
        self.indexPath = indexPath

    def search(self, queryFeatures, limit=12):
        # initialize our dictionary of results
        results = {}

        # open the index file for reading
        with open(self.indexPath) as f:
            # initialize the csv reader
            reader = csv.reader(f)

            # loop over the rows in the index
            for row in reader:
                # parse out the image ID and features, then compute the chi-squared
                # distance between the features in our index and our query features
                features = [float(x) for x in row[1:]]
                d = self.canberra_distance(features, queryFeatures)

                # now that we have the distance between the two feature vectors,
                # we can update the result dictionary -- the key is the current
                # image ID in the index and the value is the distance we just
                # computed, representing how 'similar' the image in the index is to our query
                results[row[0]] = d

            # close the reader
            f.close()

        # sort our results, so that the smaller distance (i.e. the more relevant images
        # are at the front of the list)
        results = sorted([(v, k) for (k, v) in results.items()])

        # return our (limited) results
        return results[:limit]

    def canberra_distance(self, histA, histB):
        # d = dist.canberra(histA, histB)

        # modified canberra
        M = len(histA)
        mA = mean(histA)
        mB = mean(histB)
        d = 0
        for i in range(0, M):
            d = d + (abs(histA[i] - histB[i]) /
                     ((abs(histA[i] + mA) + abs(histB[i] + mB))))

        return d

def process_file(path):

    # Define path of testing data and indexing file
    queryPath = path
    index_file = 'static/data/mtcd_full.csv'

    # define the bins for quantization
    colorBins = 64
    R_Bins = 4
    G_Bins = 4
    B_Bins = 4
    edgeBins = 18
    query = cv2.imread(queryPath)

    # Color Quantization
    colorQuant = combineColorQuantization(query, B_Bins, G_Bins, R_Bins)

    # Edge Quantization
    edgeQuant = edgeQuantization(query, edgeBins)

    # Texton Search
    features = textonSearch(colorQuant, colorBins, edgeQuant, edgeBins)

    # GLCM
    glcm, en = GLCM(query)
    features.extend(glcm[0])
    features.extend(glcm[1])
    features.extend(glcm[2])
    features.extend(en)

    # perform the search
    searcher = Searcher(index_file)
    results = searcher.search(features)

    # display the query
    fig = figure(figsize=(5, 5))
    title('Query Image')
    imshow(array(Image.open(queryPath)))
    axis('off')

    # loop over the results
    fig = figure(num=None, figsize=(20, 5))
    title('Result Image')
    i = 1
    result = []
    trowReslut = 'static/result/'

    for (score, resultID) in results:
        # load the result image and display it
        a = fig.add_subplot(2, 6, i)
        image = skimage.io.imread("static/"+resultID)
        imshow(image)
        result.append(cv2.imwrite(trowReslut + 'res' + str(i) + '.jpg', cv2.cvtColor(image, cv2.COLOR_BGR2RGB)))
        i += 1
        axis('off')
    return result


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Aug 11 11:15:55 2020
Compute IDW + Site Terms to compare with ShakeMap
@author: emmadevin
"""
import numpy as np
import pandas as pd

RESULTS_DIR = '/Users/emmadevin/Work/USGS Work/USGS PLUM/Data/PLUM Results/Ridgecrest/'

obs_lines = open(RESULTS_DIR+'/Ridgecrest_event_0000000000000001_plum_station_max_observation.dat').readlines()
pred_lines1 = open(RESULTS_DIR+'/Ridgecrest_event_0000000000000001_plum_station_max_prediction_with_corrections.dat').readlines()
pred_lines2 = open(RESULTS_DIR+'Ridgecrest_event_0000000000000001_plum_station_max_prediction_no_corrections.dat').readlines()

obs_stations = obs_lines[-2].strip().split(':')[1]
obs_mmis = obs_lines[-1].strip().split(':')[1]

pred_stations1 = pred_lines1[-2].strip().split(':')[1]
pred_mmis1 = pred_lines1[-1].strip().split(':')[1]

pred_stations2 = pred_lines2[-2].strip().split(':')[1]
pred_mmis2 = pred_lines2[-1].strip().split(':')[1]

observations = {}
for stat,mmi in zip(obs_stations.split(','), obs_mmis.split(',')):
    observations[stat] = float(mmi)

predictions1 = {}
for stat,mmi in zip(pred_stations1.split(','), pred_mmis1.split(',')):
    predictions1[stat] = float(mmi)

predictions2 = {}
for stat,mmi in zip(pred_stations2.split(','), pred_mmis2.split(',')):
    predictions2[stat] = float(mmi)

errors1 = []
errors2 = []
predicted1 = []
predicted2 = []
mmis = []
station = []

for stat,mmi in observations.items():
    pred1 = predictions1[stat]
    print (stat, mmi, pred1)
    errors1.append( pred1-mmi )
    predicted1.append(pred1)
    mmis.append(mmi)
    station.append(stat)

for stat,mmi in observations.items():
    pred2 = predictions2[stat]
    print (stat, mmi, pred2)
    errors2.append( pred2-mmi )
    predicted2.append(pred2)

avg1 = np.median(errors1)
stdev1 = np.std(errors1)

avg2 = np.median(errors1)
stdev2 = np.std(errors1)

d = {'observed' : mmis, 'nocorrection' : predicted1, 'withcorrection': predicted2, 'stations': station, 'errorwithout' : errors1, 'errorwith' : errors2}

df = pd.DataFrame(d)

loc = pd.read_csv('/Users/emmadevin/Work/USGS Work/USGS PLUM/Data/SiteTermsUpdated.csv')

loc['stations'] = loc['Network']+'.'+loc['StationCode']

df2 = loc.merge(df)

df2.to_csv('/Users/emmadevin/Work/USGS Work/USGS PLUM/Data/PLUM Results/Ridgecrest/dMMI/dMMI_Locations2.csv')


# Given a list of integers L, find the maximum length of a sequence of consecutive numbers that can be formed using elements from L.

# For example, given L = [5, 2, 99, 3, 4, 1, 100], return 5 as we can build a sequence [1, 2, 3, 4, 5] which has length 5.

#trivial result is achieved by sorting the array and then checking if an element is within 1 of the previous element, and incrementing a counter if so. this is O(n log n)
#the below result is O(n)

def check_sequence(arr):

    s = set()
    result = 0

    for element in arr:

        s.add(element)

    for i in range(len(arr)):

        if arr[i-1] not in s:

            temp = arr[i]
            while (temp in s):
                temp += 1

            subseq_res = temp - arr[i]
            if (subseq_res > result):
                result = subseq_res

    return result


#文本框举例
#每隔1秒取一次当前日期时间，并写入文本框中。
# 本例中调用datetime.now()获取当前日期时间，
# 用insert()方法每次从文本框txt的尾部（END）开始追加文本

from tkinter import *
import datetime
def gettime():
    s="{}\n".format(str(datetime.datetime.now()))
    txt.insert(END,s)
    root.after(1000,gettime)

root=Tk()
root.geometry('320x240')
txt=Text(root)
txt.pack()
gettime()
root.mainloop()


import os
from math import sin, cos, radians

try:
    import matplotlib.pyplot as plt
except:
    print("Matplot lib isn\'t installed - cannot plot")
    from unittest.mock import MagicMock
    plt = MagicMock()

# Test data, U,W is not phi/U0
Mm = dict()   #[Position][Y U W]
Yu = dict()   #[Position][Y U]
Yekp = dict() #[position][Y epsilon k p]

cs = {'-25' : [0,  1.3e-1],
      '025' : [10, 1.34341204e-01],
      '060' : [10, 1.40418891e-01],
      '100' : [10, 1.47364818e-01],
      '175' : [10, 1.60388431e-01],
      '250' : [10, 1.73412044e-01],
      '330' : [10, 1.87303899e-01],
      '405' : [10, 2.00327512e-01]}

def getExperimentalData():
    for filename in os.listdir('test60'):
        if 'Mm' in filename and '.dat' in filename:
            position = filename[2:5]
            print('Parsing:', filename, 'which has info for location', position, 'mm')
            file_name = os.path.join('test60', filename)
            file = open(file_name)
            text = file.read().split('\n')
            file.close()

            Mm[position] = list()

            for line_no in range(10, len(text)):
                line = text[line_no]
                line = line.split(' ')
                out_line = list()

                for item in line:
                    if 0 < len(item):
                        out_line.append(float(item))

                if len(out_line) == 3:
                    Mm[position].append(out_line)

def getCFDData():
    # Get latest folder from CFD output
    latest_folder = 0
    for folder in os.listdir('sets'):
        if latest_folder < int(folder):
            latest_folder = int(folder)
            print('Latest folder from CFD is for iteration', latest_folder)

    # Parse CFD output files
    for filename in os.listdir(os.path.join('sets', str(latest_folder))):
        position = filename[4:7]
        print('Parsing:', filename, 'which has info for location', position, 'mm')
        file = open(os.path.join('sets', str(latest_folder), filename))
        text = file.read().split('\n')
        file.close();

        if 'epsilon' in filename:
            destination = Yekp  # works as a pointer!
        else:
            destination = Yu;

        destination[position] = list()

        for line in text:
            this_line = line.split("\t")

            out_line = list()
            for item in this_line:
                try:
                    value = float(item)
                    out_line.append(value)
                except:
                    pass
            try:
                out_line[0] = out_line[0]*1000 #convert Y to meters
            except:
                next
            destination[position].append(out_line)
    print()

def calc_y(position, y):
    #($2-$$1)*1000/cos(angle)
    radius = cs[position][1]
    angle  = radians(cs[position][0])
    y_actual = (radius - y/1000)/cos(angle) * 1000
    return y_actual

def interpolate_U(position, Y_lower, Y_upper, Y_actual, Y_lower_index, Y_upper_index):
    deviation_percent = (Y_actual - Y_lower) / (Y_upper - Y_lower)
    data_lower = Yu[position][Y_lower_index]
    data_upper = Yu[position][Y_upper_index]

    data_range = list([1]*len(data_upper))
    data_interpolated = list([1]*len(data_upper))

    for i in range(0, len(data_upper)):
        data_range[i] = data_upper[i] - data_lower[i]
        data_interpolated[i] = data_lower[i] + deviation_percent * data_range[i]

    return data_interpolated

def subtract(array1, array2):
    new_array = list()
    for i in range(0, min(len(array1), len(array2))):
        new_array.append(array1[i] - array2[i])

    return new_array

def getScoreUW (plotComparison=[]):
    score = 0
    num_tests = 0

    for position in Mm:
        # We can plot a comparison if desired,
        #  just give a position you want the plot to be
        #  made
        if position in plotComparison:
            comparison_Y = list()
            comparison_Uexp = list()
            comparison_Wexp = list()
            comparison_Ucfd = list()
            comparison_Wcfd = list()

        # For each position, and for each point in the experimental data
        for data_exp in Mm[position]:
            Y_exp = data_exp[0]
            U_exp = data_exp[1]
            W_exp = data_exp[2]

            # Search through the CFD data using upper and lower bounds
            #  for the corrosponding experimental Y value. As we search
            #  upwards we break as soon as we get a Y value above the
            #  experimental Y value
            for index_Yu in range(0, len(Yu[position])-1):
                data_cfd = Yu[position][index_Yu]
                Y_cfd = calc_y(position, data_cfd[0])
                if Y_exp <= Y_cfd:
                    Y_upper = Y_cfd
                    Y_upper_index = index_Yu
                    break
                else:
                    Y_lower = Y_cfd
                    Y_lower_index = index_Yu

            # Then we interpolate between the upper and lower bounds
            if Y_upper < Y_lower:    # Unless something went wrong
                continue
            elif Y_upper != Y_lower: # And given Upper is not equal to lower
                Y_cfd = interpolate_U(position,
                                      Y_lower, Y_upper, Y_exp,
                                      Y_lower_index, Y_upper_index)
            else:                    # otherwise if we have an exact number, use that
                Y_cfd = Yu[position][Y_upper_index]

            # Now we can calculate the U and W values
            angle = radians(cs[position][0])

            # Calculate the U value
            U_cfd = Y_cfd[3] * cos(angle) + Y_cfd[2] * sin(angle)
            U_error = (U_cfd-U_exp) / U_exp

            # Calculate the W value
            W_cfd = -Y_cfd[1]
            W_error = (W_cfd - W_exp)/W_exp

            if 0.5 < max(abs(U_error), abs(W_error)):
                print('At', position, 'between', round(Y_lower,2),
                      '<' , round(Y_exp,2), '<', round(Y_upper,2))

                if 0.5 < abs(U_error):
                    print('U is about', round(U_error*100,2), '% off the actual value')
                    print('U:', round(U_cfd/11.6,4), '!=', round(U_exp/11.6,4), '\n')

                if 0.5 < abs(W_error):
                    print('W is about', round(W_error*100,2), '% off the actual value')
                    print('W:', round(W_cfd/11.6,4), '!=', round(W_exp/11.6,4), '\n')

            if position in plotComparison:
                comparison_Ucfd.append(U_cfd)
                comparison_Wcfd.append(W_cfd)
                comparison_Uexp.append(U_exp)
                comparison_Wexp.append(W_exp)
                comparison_Y.append(Y_exp)

            score = score + (1 - abs(U_error)) + (1 - abs(W_error))
            num_tests = num_tests + 2 #Max score

        if position in plotComparison:
            plt.plot(comparison_Y, subtract(comparison_Ucfd, comparison_Uexp), 'b--',
                     comparison_Y, subtract(comparison_Wcfd, comparison_Wexp), 'b--',
                     comparison_Y, comparison_Ucfd, 'r-',
                     comparison_Y, comparison_Uexp, 'g^',
                     comparison_Y, comparison_Wcfd, 'r-',
                     comparison_Y, comparison_Wexp, 'g^')
            plt.show()

    return score, num_tests

if __name__ == '__main__':
    getExperimentalData()
    getCFDData()
    score, max_score = getScoreUW(['405'])
    print(round(score/max_score,4)*100, '%')


import os
from ..modules.converter.html2pdf import Html2Pdf
from ..path import path_inicial

def test_converter_erro():
    """
    Testa a conversão do arquivo HTML para PDF quando há erro na entrada.

    Verifica se a função `convert` retorna False quando ocorre um erro na
    entrada.

    Returns:
        bool: False, se ocorreu um erro na conversão.
    """

    download_folder = os.path.join(os.path.expanduser("~"), "Downloads")
    html2pdf = Html2Pdf(html=path_inicial + "/Melissa Ribeiro Araujo.html")
    assert not html2pdf.convert(
        output_name="Melissa Ribeiro Araujo.html",
        foldername="exemplo_Melissa",
        folder_destino=download_folder,
        output_funcao="MONITOR",
    )


from django.urls import path
from blood import views

urlpatterns = [

    path('', views.home, name='home'),
    path('about/', views.about, name='about'),
    path('patient/', views.patient, name='patient'),
    path('donor/', views.donor, name='donor'),
    path('contact/', views.contact, name='contact'),
    path('register/', views.register, name='register'),
    path('forgot/', views.forgot, name='forgot'),
]


"""
    Created By: Norman Thien
    Creation Date: 15 Feb 2023
    Last Modified: 18 Feb 2023

    This file hosts the definitions for the tic-tac-toe domain model objects.
"""
#imports

import enum
import re
from dataclasses import dataclass
from functools import cached_property
from tic_tac_toe.logic.exceptions import InvalidMove
from tic_tac_toe.logic.validators import validate_game_state, validate_grid

#Var

WINNING_PATTERNS = (
    "???......",
    "...???...",
    "......???",
    "?..?..?..",
    ".?..?..?.",
    "..?..?..?",
    "?...?...?",
    "..?.?.?..",
)

#for game grid
"""
        defined as an immutable object for increased fault tolerance and code readability.
        issue is that the cells (object) cannot be altered once created.
"""
@dataclass(frozen=True)
class Grid:
    cells: str = " " * 9
    """
        Wrongly initialised cells can break the game so we only allow object to exist in
        a valid state only, otherwise the object won't be created at all
        following fail-fast and always-valid domain model principles.
        post initialization to perform cell validation. Method in validators.py
    """
    def __post_init__(self) -> None:
        validate_grid(self)

    #return number of crosses, naughts or empty cells

    @cached_property
    def x_count(self) -> int:
        return self.cells.count("X")

    @cached_property
    def o_count(self) -> int:
        return self.cells.count("O")

    @cached_property
    def empty_count(self) -> int:
        return self.cells.count(" ")

# Player Marks
"""
    Since there are only two symbols belonging to a fixed set of discrete values,
    you can define them within an enumerated type or enum.
    Using enums is preferable over constants due to their enhanced type safety, common namespace,
    and programmatic access to their members.
    sometimes be more convenient to think about the player
    marks in terms of strings instead of enum members.
    Because enums are glorified classes,
    you're free to put ordinary methods and properties into them
"""
class Mark(str, enum.Enum):
    CROSS = "X"
    NAUGHT = "O"

    @property
    def other(self) -> "Mark":
        return Mark.CROSS if self is Mark.NAUGHT else Mark.NAUGHT

@dataclass(frozen=True)
class Move:
    mark: Mark
    cell_index: int
    before_state: "GameState"
    after_state: "GameState"

@dataclass(frozen=True)
class GameState:
    grid: Grid
    starting_mark: Mark = Mark("X")

    def __post_init__(self) -> None:
        validate_game_state(self)

    #determine who's turn to move
    @cached_property
    def current_mark(self) -> Mark:
        if self.grid.x_count == self.grid.o_count:
            return self.starting_mark
        else:
            return self.starting_mark.other

    #identify empty cells that can be filled by the current player
    @cached_property
    def possible_moves(self) -> list[Move]:
        moves = []
        if not self.game_over:
            for match in re.finditer(r"\s", self.grid.cells):
                moves.append(self.make_move_to(match.start()))
        return moves

    """
        player make move (input), check valid then add the move to a new Grid
        Containing old Grid values and the new move.
    """
    def make_move_to(self, index: int) -> Move:
        if self.grid.cells[index] != " ":
            raise InvalidMove("Cell is not empty")
        return Move(
            mark=self.current_mark,
            cell_index=index,
            before_state=self,
            after_state=GameState(
                Grid(
                    self.grid.cells[:index]
                    + self.current_mark
                    + self.grid.cells[index + 1:]
                ),
                self.starting_mark,
            ),
        )

    #determine if game not started i.e. blank cells
    @cached_property
    def game_not_started(self) -> bool:
        return self.grid.empty_count == 9

    #in tie state or there is a winner
    @cached_property
    def game_over(self) -> bool:
        return self.winner is not None or self.tie

    #tie when no winner and no empty cells
    @cached_property
    def tie(self) -> bool:
        return self.winner is None and self.grid.empty_count == 0

    #Pattern match the winner
    @cached_property
    def winner(self) -> Mark | None:
        for pattern in WINNING_PATTERNS:
            for mark in Mark:
                if re.match(pattern.replace("?", mark), self.grid.cells):
                    return mark
        return None

    """
    @cached_property
    def winning_cells(self) -> list[int]:
        for pattern in WINNING_PATTERNS:
            for mark in Mark:
                if re.match(pattern.replace("?", mark), self.grid.cells):
                    return [
                        match.start()
                        for match in re.finditer(r"\?", pattern)
                    ]
        return []

    """