import datetime
import time
from datetime import datetime
from typing import Optional

import holidays
import numpy as np
import pandas as pd
from gluonts.time_feature.holiday import (
    BLACK_FRIDAY,
    CHRISTMAS_DAY,
    CHRISTMAS_EVE,
    COLUMBUS_DAY,
    CYBER_MONDAY,
    EASTER_MONDAY,
    EASTER_SUNDAY,
    GOOD_FRIDAY,
    INDEPENDENCE_DAY,
    LABOR_DAY,
    MARTIN_LUTHER_KING_DAY,
    MEMORIAL_DAY,
    MOTHERS_DAY,
    NEW_YEARS_DAY,
    NEW_YEARS_EVE,
    PRESIDENTS_DAY,
    SUPERBOWL,
    THANKSGIVING,
    SpecialDateFeatureSet,
    squared_exponential_kernel,
)
from pandas.tseries.holiday import (
    AbstractHolidayCalendar,
    GoodFriday,
    Holiday,
    USFederalHolidayCalendar,
    USLaborDay,
    USMartinLutherKingJr,
    USMemorialDay,
    USPresidentsDay,
    USThanksgivingDay,
    nearest_workday,
)
from sklearn.preprocessing import MinMaxScaler

from src.transformers import DateTimeTransformer, periodic_spline_transformer

# Example use for using a squared exponential kernel:
kernel = squared_exponential_kernel(alpha=1.0)
sfs = SpecialDateFeatureSet(
    [
        NEW_YEARS_DAY,
        MARTIN_LUTHER_KING_DAY,
        PRESIDENTS_DAY,
        GOOD_FRIDAY,
        MEMORIAL_DAY,
        INDEPENDENCE_DAY,
        LABOR_DAY,
        THANKSGIVING,
        CHRISTMAS_DAY,
    ],
    squared_exponential_kernel(alpha=1.0),
)

sfs2 = SpecialDateFeatureSet(
    [
        SUPERBOWL,
        CHRISTMAS_EVE,
        EASTER_SUNDAY,
        EASTER_MONDAY,
        MOTHERS_DAY,
        COLUMBUS_DAY,
        NEW_YEARS_EVE,
        BLACK_FRIDAY,
        CYBER_MONDAY,
    ],
    squared_exponential_kernel(alpha=1.0),
)

def reindex_weekdays(
    df: pd.DataFrame,
    drop_weekends: bool = True,
    start_index: pd.Timestamp = None,
    end_index: pd.Timestamp = None,
    fill_method: str = "ffill",
    extra_fill_method: Optional[str] = "bfill",
    freq: str = "D",
) -> pd.DataFrame:
    if start_index is None:
        start_index = df.index[0]
    if end_index is None:
        end_index = df.index[-1]

    df = (
        df.reindex(pd.date_range(start=start_index, end=end_index, freq=freq))
        .fillna(method=fill_method)
        .fillna(method=extra_fill_method)
    )
    if drop_weekends:
        return df.loc[~df.index.day_name().isin(["Saturday", "Sunday"]), :]
    return df

def get_datetime_covariates(
    start_index, end_index, memory_transforms, date_time_transforms
):
    calendar = NYSECalendar()
    index = pd.date_range(start=start_index, end=end_index, freq="D")
    holiday_dates = calendar.holidays(start_index, end_index, return_name=True).index
    covariates = pd.DataFrame(index=index)
    covariates.loc[:, ["one_hot_weekends", "one_hot_holidays"]] = 0
    covariates.loc[covariates.index.isin(holiday_dates), "one_hot_holidays"] = 1
    covariates.loc[
        covariates.index.day_name().isin(["Saturday", "Sunday"]), "one_hot_weekends"
    ] = 1
    covariates.loc[:, "kernel_holidays"] = sfs(covariates.index).max(
        axis=0
    )  # np.prod(sfs(covariates.index), axis=1)
    covariates.loc[:, "kernel_other_holidays"] = sfs2(covariates.index).max(axis=0)
    covariates = covariates.round(3)

    covariates = date_time_transforms.fit_transform(covariates)
    month_splines = periodic_spline_transformer(12, n_splines=6).fit_transform(
        covariates[["month"]]
    )
    weekday_splines = periodic_spline_transformer(7, n_splines=3).fit_transform(
        covariates[["day_of_week"]]
    )
    splines = np.concatenate((month_splines, weekday_splines), axis=1)
    spline_names = [f"spline_{i}" for i in range(splines.shape[1])]
    covariates.loc[:, spline_names] = splines
    covariates = memory_transforms.fit_transform(covariates)

    scaler = MinMaxScaler()  # StandardScaler()
    covariates = pd.DataFrame(
        data=scaler.fit_transform(covariates),
        index=covariates.index,
        columns=covariates.columns,
    )

    return covariates

# https://gist.github.com/jckantor/d100a028027c5a6b8340
class NYSECalendar(AbstractHolidayCalendar):
    """
    cdr = NYSECalendar()
    non_trading_days = cdr.holidays(datetime(2022, 1, 1), datetime(2022, 12, 31))
    """

    rules = [
        Holiday("New Years Day", month=1, day=1, observance=nearest_workday),
        USMartinLutherKingJr,
        USPresidentsDay,
        GoodFriday,
        USMemorialDay,
        Holiday(
            "Juneteenth",
            month=6,
            day=19,
            start_date="2022-06-20",
            observance=nearest_workday,
        ),
        Holiday("USIndependenceDay", month=7, day=4, observance=nearest_workday),
        USLaborDay,
        USThanksgivingDay,
        Holiday("Christmas", month=12, day=25, observance=nearest_workday),
    ]

def main():

    us_holidays = holidays.UnitedStates()
    # https://www.commerce.gov/hr/employees/leave/holidays
    us_holidays.observed = False
    us_holidays["2022-01-01":"2022-12-31"]
    # markets were not closed on this day (Juneteenth National Independence Day) in 2021
    if datetime.date(2021, 6, 19) in us_holidays.keys():
        del us_holidays[datetime.date(2021, 6, 19)]
    for date, name in sorted(us_holidays.items()):
        print(date, name)
    #         Thanksgiving
    #         Black Friday
    #         Cyber Monday
    #         Giving Tuesday
    #         Green Monday
    #         Free Shipping Day
    #         Hanukkah (start/end)
    #         Christmas
    #         Kwanzaa
    #         Boxing Day
    #         New Year's Eve/Day

if __name__ == "__main__":
    main()


import json
import os

from flask import url_for
from flask_babel import _
from slugify import slugify

with open(
    os.path.join(os.path.dirname(__file__), "countries.json"), encoding="utf8"
) as a:
    COUNTRIES = sorted(json.load(a)["countries"], key=lambda k: k["name"])
    COUNTRIES = [c for c in COUNTRIES if c["iso"] != "GBR"]

def get_country_groups(as_dict=False):
    continents = set()
    undp = set()
    dac = set()
    for c in COUNTRIES:
        continents.add(c["continent"])
        if c["undp"]:
            undp.add(c["undp"])
        if c["dac_status"]:
            dac.add(c["dac_status"])

    if as_dict:
        areas = {}
        areas["all"] = {"name": _("all countries"), "countries": COUNTRIES}
        for c in COUNTRIES:
            areas[slugify(c["iso"])] = {"name": c["name"], "countries": [c]}

        for con in continents:
            areas[("continent", slugify(con))] = {
                "name": con,
                "countries": [c for c in COUNTRIES if c["continent"] == con],
            }

        for i in [
            ("undp", "undp", _("all UNDP countries"), undp),
            ("dac", "dac_status", _("all DAC countries"), dac),
        ]:
            areas[(i[0], "all")] = {
                "name": i[2],
                "countries": [c for c in COUNTRIES if c[i[1]]],
            }
            for con in i[3]:
                areas[(i[0], slugify(con))] = {
                    "name": con,
                    "countries": [c for c in COUNTRIES if c[i[1]] == con],
                }
        return areas

    return [
        (
            None,
            [{"id": url_for("data.country", countryid="all"), "name": "all countries"}],
            True,
        ),
        (
            "Continents",
            [
                {
                    "id": url_for(
                        "data.region", regiontype="continent", regionid=slugify(c)
                    ),
                    "name": c,
                }
                for c in continents
            ],
            True,
        ),
        (
            _('UNDP regions'),
            [
                {
                    "id": url_for("data.region", regiontype="undp", regionid="all"),
                    "name": _("all UNDP regions"),
                }
            ]
            + [
                {
                    "id": url_for(
                        "data.region", regiontype="undp", regionid=slugify(c)
                    ),
                    "name": c,
                }
                for c in undp
                if c
            ],
            True,
        ),
        (
            _('DAC groups'),
            [
                {
                    "id": url_for("data.region", regiontype="dac", regionid="all"),
                    "name": _("all DAC groups"),
                }
            ]
            + [
                {
                    "id": url_for("data.region", regiontype="dac", regionid=slugify(c)),
                    "name": c,
                }
                for c in dac
                if c
            ],
            True,
        ),
    ] + [
        (
            con,
            [
                {
                    "id": url_for("data.country", countryid=slugify(c["iso"])),
                    "name": c["name"],
                }
                for c in COUNTRIES
                if c["continent"] == con
            ],
            False,
        )
        for con in sorted(continents)
    ]

def get_multiple_countries(countryid):
    countryids = countryid.lower().split("+")
    area = {"name": [], "countries": []}
    for i in countryids:
        this_area = get_country_groups(as_dict=True).get(i)
        if this_area:
            area["name"].append(this_area["name"])
            area["countries"].extend(this_area["countries"])
    if not area["countries"]:
        return None

    area["name"] = ", ".join(area["name"])
    return area

def get_country_by_id(id):
    for c in COUNTRIES:
        if c["id"] == id or c["iso"] == id or c["iso2"] == id:
            return c
    return None

SIMILAR_INITIATIVE = {
    "sen": [
        {
            "homepage": "https://pfongue.org/",
            "title": _("Platform of European NGOs in Senegal"),
            "directlink": "https://pfongue.org/-Cartographie-.html",
            "directlinktext": _("Map of projects"),
        },
        {
            "title": "CONGAD - Conseil des ONG d’Appui au Développement",
            "homepage": "http://www.congad.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        },
    ],
    "uga": [
        {
            "homepage": "https://ugandanetworks.org/",
            "title": "Uganda Networks",
            "directlink": "https://ugandanetworks.org/groups/250421/directory_search.aspx",
            "directlinktext": _("Directory search"),
        },
        {
            "homepage": "http://www.uwasnet.org/Elgg/",
            "title": "Uganda Water and Sanitation NGO Network",
            "directlink": "http://www.uwasnet.org/Elgg/network/",
            "directlinktext": _("Members directory"),
        },
        {
            "title": "UNNGOF - Uganda National NGO Forum",
            "homepage": "http://ngoforum.or.ug/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        },
    ],
    "bra": [
        {
            "homepage": "http://www.abong.org.br",
            "title": "Abong - Associaçao Brasileira de ONGs",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "hti": [
        {"homepage": "http://coeh.eu/members/", "title": "Coordination Europe-Haiti"}
    ],
    "chl": [
        {
            "title": "ACCIÓN - Asociación Chilena de ONG",
            "homepage": "http://www.accionag.cl",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "bdi": [
        {
            "title": "ADIR - Action Développement et Intégration Régionale",
            "homepage": "https://adirplateform.wordpress.com/adir/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "dom": [
        {
            "title": "Alianza ONG",
            "homepage": "http://alianzaong.org.do",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "per": [
        {
            "title": "ANC - Asociación Nacional de Centros",
            "homepage": "http://www.anc.org.pe",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "ury": [
        {
            "title": "ANONG - Asociación Nacional de ONG",
            "homepage": "http://www.anong.org.uy",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "hnd": [
        {
            "title": "ASONOG - Asociacion De Organismos No Gubernamentales",
            "homepage": "http://www.asonog.hn/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "bwa": [
        {
            "title": "Bocongo - Botswana Council of Non-Governmental Organisations",
            "homepage": "http://www.bocongo.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "gbr": [
        {
            "title": "Bond - British Overseas NGOs for Development",
            "homepage": "http://www.bond.org.uk",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "chn": [
        {
            "title": "CANGO - China Association for NGO Cooperation",
            "homepage": "http://www.cango.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "khm": [
        {
            "title": "CCC - Cooperation Committee for Cambodia",
            "homepage": "http://www.ccc-cambodia.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "can": [
        {
            "title": "CCIC - Canadian council for international co-operation",
            "homepage": "http://www.ccic.ca",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "rwa": [
        {
            "title": "CCOAIB - Conseil de Concertation des Organisations d’Appui aux Initiatives de Base",
            "homepage": "http://www.ccoaib.org.rw",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "cog": [
        {
            "title": "CCOD - Conseil de Concertation des ONG de développement",
            "homepage": "https://pcpacongo.org/ccod/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "col": [
        {
            "title": "CCONG - Confederación Colombiana de ONG",
            "homepage": "http://www.ccong.org.co",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "syc": [
        {
            "title": "CEPS - Citizens Engagement Platform Seychelles",
            "homepage": "http://www.civilsociety.sc",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "ben": [
        {
            "title": "CFRONG - Collectif des Fédérations et Réseaux d’ONG du Bénin",
            "homepage": "http://www.cfrong.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "cok": [
        {
            "title": "CICSO - Cook Islands Association of NGOs",
            "homepage": "",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "nzl": [
        {
            "title": "CID - Council for International Development",
            "homepage": "http://www.cid.org.nz",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "tcd": [
        {
            "title": "CILONG - Centre d’information et de Liaison des ONG",
            "homepage": "",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "caf": [
        {
            "title": "CIONGCA - Conseil Inter ONG de Centrafrique",
            "homepage": "https://www.facebook.com/ciongcarca/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "cod": [
        {
            "title": "CNONGD - Conseil National des ONGD de Développement",
            "homepage": "http://www.cnongdrdc.org/cnongd.php",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "phl": [
        {
            "title": "CODE - Caucus of Development NGO Networks",
            "homepage": "http://www.code-ngo.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "cmr": [
        {
            "title": "CONGAC - Collectif des ONG Agréées du Cameroun",
            "homepage": "",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "gtm": [
        {
            "title": "CONGCOOP - Coordinación de ONG y Cooperativas",
            "homepage": "http://www.congcoop.org.gt",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "esp": [
        {
            "title": "Coordinadora - NGO Coordinator for Development",
            "homepage": "http://www.coordinadoraongd.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "fra": [
        {
            "title": "Coordination SUD - Coordination SUD – Solidarité Urgence Développement",
            "homepage": "http://www.coordinationsud.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    # "civ": [{'title': 'CSCI - Convention de la Société Civile Ivoirienne',
    #          'homepage': 'http://www.cs-ci.com/',
    #          'source': 'Forus',
    #          'source_link': 'http://forus-international.org/en/about-us/who-we-are'}],
    "irl": [
        {
            "title": "Dochas",
            "homepage": "https://dochas.ie/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "arg": [
        {
            "title": "EENGD - Red Encuentro",
            "homepage": "http://www.encuentrodeongs.org.ar",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "mar": [
        {
            "title": "Espace Associatif",
            "homepage": "http://www.espace-associatif.ma",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "fji": [
        {
            "title": "FCOSS - Fiji Council of Social Services",
            "homepage": "",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "mli": [
        {
            "title": "FECONG - Fédération des Collectif d’ONG du Mali",
            "homepage": "http://www.fecong.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "fin": [
        {
            "title": "FINGO - Finnish NGO Platform",
            "homepage": "https://www.fingo.fi/english",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "rou": [
        {
            "title": "FOND - Romanian NGDOs Platform",
            "homepage": "http://www.fondromania.org/pagini/index.php",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "ago": [
        {
            "title": "FONGA - Foro das ONGs Angolanas",
            "homepage": "https://www.facebook.com/plateformeFonga",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "gin": [
        {
            "title": "FONGDD - Forum des ONG pour le Développement Durable",
            "homepage": "",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "stp": [
        {
            "title": "FONG-STP - Federaçao das ONGs de Sao Tomé e Principe",
            "homepage": "http://fong-stp.net",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "tgo": [
        {
            "title": "FONGTO - Fédération des Organisations Non Gouvernementales au Togo",
            "homepage": "http://fongto.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "cze": [
        {
            "title": "FoRS - Czech Forum for Development Co-operation",
            "homepage": "http://www.fors.cz",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "dnk": [
        {
            "title": "Global Focus",
            "homepage": "http://www.globaltfokus.dk/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "hun": [
        {
            "title": "HAND - Hungarian Association of NGOs for Development and Humanitarian Aid",
            "homepage": "http://hand.org.hu/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "idn": [
        {
            "title": "INFID - International NGO Forum on Indonesian Development",
            "homepage": "http://www.infid.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "usa": [
        {
            "title": "InterAction",
            "homepage": "http://www.interaction.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "jpn": [
        {
            "title": "JANIC - Japan NGO Center for International Cooperation",
            "homepage": "http://www.janic.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "moz": [
        {
            "title": "Joint - League For NGOs in Mozambique",
            "homepage": "http://www.joint.org.mz/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "kir": [
        {
            "title": "KANGO - Kiribati Association of NGOs",
            "homepage": "http://www.kango.org.ki",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "kor": [
        {
            "title": "KCOC - Korea NGO Council for Overseas Development Cooperations",
            "homepage": "http://www.ngokcoc.or.kr",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "lva": [
        {
            "title": "LAPAS - Latvijas Platforma attīstības sadarbībai",
            "homepage": "http://lapas.lv/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "ltu": [
        {
            "title": "Lithuanian National Non-Governmental Development Cooperation Organisations’ Platform",
            "homepage": "http://www.vbplatforma.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "mus": [
        {
            "title": "MACOSS - Mauritius Council of Social Service",
            "homepage": "http://www.macoss.intnet.mu/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "npl": [
        {
            "title": "NFN - NGO Federation of Nepal",
            "homepage": "http://www.ngofederation.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        },
        {
            "title": "British and Nepal NGO Network (BRANNGO)",
            "homepage": "https://www.branngo.org/",
        },
    ],
    "nga": [
        {
            "title": "NNNGO - Nigeria Network of NGOs",
            "homepage": "http://www.nnngo.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "mdg": [
        {
            "title": "PFNOSCM - Plateforme Nationale des Organisations de la Société Civile de Madagascar",
            "homepage": "http://societecivilemalgache.com/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "prt": [
        {
            "title": "Plataforma ONGD - Portuguese Platform NGOD",
            "homepage": "http://www.plataformaongd.pt/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "bel": [
        {
            "title": "Plateforme belge des ONG de développement et d’urgence",
            "homepage": "",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "cpv": [
        {
            "title": "PLATONG - Plataforma das ONGs de Cabo Verde",
            "homepage": "http://www.platongs.org.cv/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "pry": [
        {
            "title": "POJOAJU - Asociación de ONGs del Paraguay",
            "homepage": "http://www.pojoaju.org.py",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "mlt": [
        {
            "title": "SKOP - National Platform of Maltese NGDOs",
            "homepage": "http://www.skopmalta.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "svn": [
        {
            "title": "SLOGA - Slovenian Global Action",
            "homepage": "http://www.sloga-platform.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "bfa": [
        {
            "title": "SPONG - Secrétariat Permanent des ONG du Burkina Faso",
            "homepage": "http://www.spong.bf/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "twn": [
        {
            "title": "Taiwan Alliance in International Development",
            "homepage": "http://www.taiwanaid.org/en",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "gmb": [
        {
            "title": "TANGO - The Association of Non-Governmental Organizations",
            "homepage": "http://www.tangogambia.org/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "bol": [
        {
            "title": "UNITAS - Red Unitas",
            "homepage": "http://www.redunitas.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "ind": [
        {
            "title": "VANI - Voluntary Action Network India",
            "homepage": "http://www.vaniindia.org",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
    "zmb": [
        {
            "title": "ZCSD - Zambia Council for Social Development",
            "homepage": "http://www.zcsdev.org.zm/",
            "source": "Forus",
            "source_link": "http://forus-international.org/en/about-us/who-we-are",
        }
    ],
}


import heapq
from collections import defaultdict

class HuffmanNode:
    def __init__(self, symbol, freq):
        self.symbol = symbol
        self.freq = freq
        self.left = None
        self.right = None

    def __lt__(self, other):
        return self.freq < other.freq

def build_huffman_tree(frequencies):
    heap = []
    for symbol, freq in frequencies.items():
        heapq.heappush(heap, HuffmanNode(symbol, freq))

    while len(heap) > 1:
        node1 = heapq.heappop(heap)
        node2 = heapq.heappop(heap)
        merged = HuffmanNode(None, node1.freq + node2.freq)
        merged.left = node1
        merged.right = node2
        heapq.heappush(heap, merged)

    return heap[0]

def traverse_huffman_tree(node, code, code_dict):
    if node.symbol is not None:
        code_dict[node.symbol] = code
        return

    traverse_huffman_tree(node.left, code + '0', code_dict)
    traverse_huffman_tree(node.right, code + '1', code_dict)

def huffman_encoding(text):
    text = text.replace(" ", "")  # Usunięcie spacji z tekstu
    frequencies = defaultdict(int)
    for symbol in text:
        frequencies[symbol] += 1

    huffman_tree = build_huffman_tree(frequencies)
    code_dict = {}
    traverse_huffman_tree(huffman_tree, '', code_dict)

    encoded_text = [(symbol, code_dict[symbol]) for symbol in text]

    return encoded_text, frequencies, code_dict

def main():
    text = input("Podaj tekst do zakodowania: ")
    encoded_text, frequencies, code_dict = huffman_encoding(text)
    print("Znak\t| Liczba wystąpień\t| Kodowanie")
    print("------------------------------------------")
    for symbol, count in sorted(frequencies.items(), key=lambda x: x[1]):
        code = code_dict[symbol]
        print(f"{symbol}\t| {count}\t\t| {code}")
    encoded_string = ''.join(code for symbol, code in encoded_text)
    print("Zakodowany tekst:", encoded_string)

main()


#!/usr/bin/python3
import discord
from discord.ext import commands
from spam_modules import meme

class MemeBot(commands.Cog):

    def __init__(self,client):
        self.client=client

    @commands.command(name='help')
    async def help(self,ctx):
        h=discord.Embed(title='Help',description='Help for Disco Meme')
        h.add_field(name='help',value='Displays this message',inline=False)
        memecommand="""
        Shows a random meme.
        Syntax: ```>meme```
        """
        h.add_field(name='meme',value=memecommand,inline=False)
        await ctx.send(embed=h)

    @commands.command(name='meme',help='Show a random meme')
    async def memes(self,ctx):
        link=meme.getmeme(1)
        emb=discord.Embed()
        emb.set_image(url=link[0])
        await ctx.send(embed=emb)

def setup(client):
    client.add_cog(MemeBot(client))


import unittest
from datetime import datetime

from batteries.nubbin_battery import NubbinBattery
from batteries.spindler_battery import SpindlerBattery

class TestNubbin(unittest.TestCase):
    def setUp(self) -> None:
        self.current_date: datetime = datetime.today().date()
        self.last_service_date: datetime = datetime.today().date()
        self.nubbin: NubbinBattery = None

    def create_nubbin_battery(self):
        self.nubbin = NubbinBattery(self.current_date, self.last_service_date)

    def test_battery_should_be_serviced(self):
        self.last_service_date = self.current_date.replace(
            year=self.current_date.year - 5
        )

        self.create_nubbin_battery()
        self.assertTrue(self.nubbin.needs_service())

    def test_battery_should_not_be_serviced(self):
        self.last_service_date = self.current_date.replace(
            year=self.current_date.year - 3
        )

        self.create_nubbin_battery()
        self.assertFalse(self.nubbin.needs_service())

class TestSpindler(unittest.TestCase):
    def setUp(self) -> None:
        self.current_date: datetime = datetime.today().date()
        self.last_service_date: datetime = datetime.today().date()
        self.spindler: SpindlerBattery = None

    def create_spindler_battery(self):
        self.spindler = SpindlerBattery(self.current_date, self.last_service_date)

    def test_battery_should_be_serviced(self):
        self.last_service_date = self.current_date.replace(
            year=self.current_date.year - 4
        )

        self.create_spindler_battery()
        self.assertTrue(self.spindler.needs_service())

    def test_battery_should_not_be_serviced(self):
        self.last_service_date = self.current_date.replace(
            year=self.current_date.year - 2
        )

        self.create_spindler_battery()
        self.assertFalse(self.spindler.needs_service())

if __name__ == "__main__":
    unittest.main()


# %%
import os
import glob
import numpy as np
import torch
from PIL import Image, ImageDraw
from skimage import draw
from skimage.io import imread
from matplotlib import pyplot as plt
from scipy.ndimage.filters import gaussian_filter
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms as T
import import_ipynb
import transforms as my_T
import dataset
from dataset import Microscopy_dataset

def get_transforms(train=False, rescale_size=(256, 256)):
    #transformation definition
    transforms = []
    if train:
        transforms.append(my_T.Rescale(rescale_size))
        transforms.append(my_T.Normalize())
        transforms.append(my_T.ToTensor())
    return my_T.Compose(transforms)

def get_loaders(
    train_dir,
    train_maskdir,
    val_dir,
    val_maskdir,
    batch_size,
    num_workers=1,
    pin_memory=True):

    #loader for Microscopy dataset - training and validation dataset

    train_ds = Microscopy_dataset(
        image_dir=train_dir,
        mask_dir=train_maskdir,
    )

    train_loader = DataLoader(
        train_ds,
        batch_size=batch_size,
        num_workers=num_workers,
        pin_memory=pin_memory,
        shuffle=True,
    )

    val_ds = Microscopy_dataset(
        image_dir=val_dir,
        mask_dir=val_maskdir,
    )

    val_loader = DataLoader(
        val_ds,
        batch_size=batch_size,
        num_workers=num_workers,
        pin_memory=pin_memory,
        shuffle=False,
    )

    return train_loader, val_loader

def get_loaders_test(
    # loader fo testing dataset
    val_dir,
    val_maskdir,
    batch_size,
    num_workers=1,
    pin_memory=True):
    print("test get loaders test")
    #loader for Microscopy dataset - training and validation dataset

    val_ds = Microscopy_dataset(
        image_dir=val_dir,
        mask_dir=val_maskdir,
    )

    val_loader = DataLoader(
        val_ds,
        batch_size=batch_size,
        num_workers=num_workers,
        pin_memory=pin_memory,
        shuffle=True,
    )
    return val_loader

def check_acc(loader, model, device="cuda"):
    #check accuracy and dice score deffinition

    num_correct = 0
    num_pixels = 0
    dice_score = 0
    model.eval()

    print(type(loader))
    print("Breakpoint!")

    with torch.no_grad():
        for x, y in loader:
            x = x.to(device)
            y = y.to(device).unsqueeze(1)
            preds = torch.sigmoid(model(x))
            preds = (preds > 0.5).float()
            num_correct += (preds == y).sum()
            num_pixels += torch.numel(preds)
            dice_score += (2 * (preds * y).sum()) / (
                (preds + y).sum() + 1e-8
            )

    print(
        f"Got {num_correct}/{num_pixels} with acc {num_correct/num_pixels*100:.2f}"
    )

    print(f"Dice score: {dice_score/len(loader)}")

    model.train()


#----------------------------------------------------------------------
#   A dataset wrapper for pluto simulations
#
#   Author  : Thomas Rometsch (thomas.rometsch@uni-tuebingen.de)
#   Date    : 2018-07-12
#----------------------------------------------------------------------

from cast.dataset import *
from . import units
from . import grid
from .units import Dimension as Dim
import re
import os
import numpy as np
import astropy.units as u
from .pluload import pload
from .particles import Planet

""" Datafiles produced by pluto.
Filenames are given as regex expression to extract from file list."""
datafile_pattern = ".*\.dat"

outputdir_indicators = ["grid.out", "dbl.out"]

scalar_files = []

collections = ["analysis_values.dat"]

# Look for planet related files and extract the planet number
# from the filename using (\d+) group in regex pattern
particle_file_pattern = ['nbody_coordinates.dat', 'nbody_orbital_elements.dat']

known_units = {
    "niter"    : Dim(),
    "M_DISK"   : Dim(M=1),
    "KE_R"     : Dim(M=1, L=2, T=-2),
    "KE_TH"    : Dim(M=1, L=2, T=-2),
    "KE_PHI"   : Dim(M=1, L=2, T=-2),
    "RHO_MIN"  : Dim(M=1, L=-3),
    "RHO_MAX"  : Dim(M=1, L=-3),
    "J_DISK_." : Dim(M=1, L=2, T=-1),
    "F_."      : Dim(M=1, L=1, T=-2),
    "ACC_."    : Dim(L=1, T=-2),
    "P_1_A_."  : Dim(L=1, T=-2),
    "rho"      : Dim(M=1, L=-3),
    "prs"      : Dim(M=1, L=-1, T=-2),
    "vx."      : Dim(L=1, T=-1)
}

def find_pluto_log(rootdir):
    try:
        rv = os.path.join(find_dir_containing("pluto.log", rootdir), "pluto.log")
    except FileNotFoundError:
        #rv = None
        raise
    return rv

def extract_pluto_log_units(datadir):
    fpath = find_pluto_log(datadir)
    if fpath is None:
        rv = units.UnitSystem()
    else:
        foundUnits = {}
        with open(fpath, 'r') as f:
            for l in f:
                # match to lines like: [Density]:      4.249e-09 (gr/cm^3), 2.540e+15 (1/cm^3)
                rs = re.match("\s*\[(\w+)\]\:\s*([0-9\.e\-\+]+).*\((.+)\)",l.split(',')[0].strip())
                if rs:
                    rs = rs.groups()
                    name = rs[0]
                    value = rs[1]
                    unitstring = rs[2].replace('^', '').replace('gr','g').replace('sec', 's')
                    foundUnits[rs[0]] = float(value)*u.Unit(unitstring)
        baseunits = {
            "L" : foundUnits['Length'],
            "T" : foundUnits['Time'],
            "Th" : foundUnits['Temperature'],
            "M" : foundUnits['Density']*foundUnits['Length']**3
            }
        rv = units.UnitSystem(baseunits)
    return rv

def parse_text_header(fpath):
    with open(fpath, 'r') as f:
        header = []
        for l in f:
            l = l.strip()
            if l[0] != '#':
                break
            header.append(l)
    return parse_text_header_pluto(header)

def parse_text_header_pluto(header):
    names = []
    for l in header:
        l = l.strip('#').strip()
        if l[:4] == "vars":
            l = l[4:].lstrip().lstrip(":")
            names = [s.strip() for s in l.split('\t')]
    timecol = None
    for n, name in enumerate(names):
        if name in ['time', 'simulation time']:
            timecol = n
    return names, timecol

def pload_to_grid(pl, unitSys = {'L' : 1}):
    if pl.geometry == "SPHERICAL":
        return grid.SphericalRegularGrid(r=pl.x1*unitSys['L'], dr=pl.dx1*unitSys['L'],
                                         theta=pl.x2, dtheta=pl.dx2,
                                         phi=pl.x3, dphi=pl.dx3 )
    elif pl.geometry == "POLAR":
        return grid.PolarRegularGrid(r=pl.x1*unitSys['L'], dr=pl.dx1*unitSys['L'],
                                         phi=pl.x3, dphi=pl.dx3 )
    else:
        raise NotImplementedError("No grid implemented for '{}' geometry.".format(pl.geometry))

def createPlutoParticles(datadir, unitSys, extraData):
    # return a list of PlutoParticle objects for all present nbody particles
    particleIds = plutoParticlesIds(datadir)
    particles = []
    for i in particleIds:
        particles.append(Planet(name = i, unitSys=unitSys, data={}))

    # register the common load function
    loadFunction = lambda : loadPlutoParticles(datadir, particles, unitSys, extraData)
    for p in particles:
        p.load = loadFunction

    return particles

def plutoParticlesIds(datadir):
    with open(os.path.join(datadir, 'nbody_coordinates.dat'), 'r') as f:
        # first, find the number of particles
        ids = []
        for l in f:
            if l[0] == "#":
                continue
            pid = l.strip().split()[0]
            if not pid in ids:
                ids.append(pid)
            else:
                break
    return ids

def loadPlutoParticles(datadir, particles, unitSys, extraData):
    pids = [p.name for p in particles]
    Nparticles = len(particles)

    # load cartesian positions and velocities
    data = np.genfromtxt(os.path.join(datadir, 'nbody_coordinates.dat'))
    varNames = ['id', 'time', 'x1', 'x2', 'x3', 'v1', 'v2', 'v3']
    units = { 'id'   : 1,
              'time' : unitSys['T'],
              'x1'    : unitSys['L'],
              'x2'    : unitSys['L'],
              'x3'    : unitSys['L'],
              'v1'   : unitSys['L']/unitSys['T'],
              'v2'   : unitSys['L']/unitSys['T'],
              'v3'   : unitSys['L']/unitSys['T'] }

    for n, p in enumerate(particles):
        time = data[n::Nparticles, 1]*unitSys['T']
        for k, name in enumerate(varNames):
            p.data[name] = TimeSeries(name = name, data = data[n::Nparticles, k]*units[name], time=p.data['time'])

    # load orbital elements
    data = np.genfromtxt(os.path.join(datadir, 'nbody_orbital_elements.dat'))
    varNames = ['id', 'time', 'a', 'e', 'i',
                'AscendingNode', 'Periastron', 'TrueAnomaly',
                'PeriodInCodeUnits', 'EccentricAnomaly', 'MeanAnomaly']
    units = { 'id'   : 1,
              'time' : unitSys['T'],
              'a'    : unitSys['L'],
              'e'    : 1,
              'i'    : u.rad,
              'AscendingNode'     : u.rad,
              'Periastron'        : u.rad,
              'TrueAnomaly'       : u.rad,
              'PeriodInCodeUnits' : unitSys['T'],
              'EccentricAnomaly'  : u.rad,
              'MeanAnomaly'       : u.rad }

    # orbital elements are not printed for the primary object
    # load it for all others
    for n, p in enumerate(particles[1:]):
        time = data[n::Nparticles-1, 1]*unitSys['T']
        for k, name in enumerate(varNames):
            if k <= 1:
                continue
            p.data[name] = TimeSeries(name = name, data = data[n::Nparticles-1, k]*units[name], time=time)

    # get the mass from the restart file, assume its constant!
    with open(os.path.join(datadir, 'nbody.out'), 'r') as df:
        for n,line in zip(range(Nparticles) ,df):
            parts = line.strip().split()
            if int(parts[1]) != n:
                raise ValueError("line {} does not correspond to planet {} but to {}".format(n,n,parts[1]))
            mass = float(parts[2])*np.ones(len(particles[n]['time']))*unitSys['M']
            particles[n].data['mass'] = TimeSeries(name = 'mass', data = mass, time=particles[n].data['time'])

    # get accelerations which are written to the analysisValue file
    for n, p in enumerate(particles):
        for i in range(1,4):
            varname = 'P_{}_A_{}'.format(n, i-1)
            if varname in extraData:
                p.data['a{}'.format(i)] = extraData[varname]
                p.data['a{}'.format(i)].name = 'a{}'.format(i)

class ScalarTimeSeries(TimeSeries):
    def __init__(self, time=None, data=None, datafile=None, name = None, unitSys = None):
        self.time = time
        self.data = data
        self.datafile = datafile
        self.name = name
        self.unitSys = unitSys

    def load(self, *args, **kwargs):
        pass

class PlutoField(Field):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def load(self):
        if self.data is None:
            if self.resource[1] is None:
                self.resource[1] = self.pload()
            self.data = self.resource[1].__dict__[self.name]
            if self.unitSys is not None and self.name is not None:
                self.data *= self.unitSys.find(self.name)
            if self.unitSys is not None and self.name == 'rho' and self.grid.dim == 2:
                self.data *= self.unitSys['L']

    def pload(self):
        output_number = int(re.match("data\.(\d+)\.dbl", os.path.basename(self.resource[0])).groups()[0])
        return pload(output_number, os.path.dirname(self.resource[0]))

class PlutoDataset(AbstractDataset):
    def __init__(self, rootdir):
        super().__init__()
        self.rootdir = rootdir
        self.find_datadir()
        self.units = extract_pluto_log_units(self.rootdir)
        for key in known_units:
            self.units.register(key, known_units[key])
        self.find_datafiles()
        self.find_scalars()
        self.find_collections()
        self.find_particles()
        self.find_fields()

    def find_datadir(self):
        # Look for an output dir inside the rootdir
        self.datadir = find_dir_containing(outputdir_indicators, self.rootdir)

    def find_datafiles(self):
        """ Search the datadir for datafiles."""
        matches = (re.match(datafile_pattern, s) for s in os.listdir(self.datadir))
        self.datafiles = [m.string for m in matches if m is not None]

    def find_scalars(self):
        """ Find all time info."""
        for s in scalar_files:
            if s in self.datafiles:
                name = s[:-4]
                self.timeSeries[name] = ScalarTimeSeries(os.path.join(self.datadir, s)
                                                         , name=name, unitSys=self.units)

    def find_collections(self):
        """ Find files containing multiple time series and parse them. """
        for c in collections:
            if c in self.datafiles:
                self.add_collection(c)

    def add_collection(self, collection):
        fpath = os.path.join(self.datadir, collection)
        names, timecol = parse_text_header(fpath)
        if timecol is None:
            raise TypeError("Could not find time info for constructing time series in '{}' with names '{}'.".format(fpath, names))
        data = np.genfromtxt(fpath)
        time = data[:,timecol]*self.units['time']
        for n, name in enumerate(names):
            if n == timecol:
                continue
            vardata = data[:,n]*self.units.find(name)
            self.timeSeries[name] = ScalarTimeSeries(time = time, data = vardata, name = name)

    def find_particles(self):
        if all([f in self.datafiles for f in particle_file_pattern]):
            particles = createPlutoParticles(self.datadir, self.units, self.timeSeries)
            self.particles = {p.name : p for p in particles}
            self.planets = PlanetSystem( planets= particles[1:])

    def find_fields(self):
        output_numbers = []
        time = []
        with open(os.path.join(self.datadir, 'dbl.out')) as f:
            got_names = False
            for l in f:
                parts = l.strip().split()
                if not got_names:
                    var_names = parts[6:]
                    got_names = True
                output_numbers.append(int(parts[0]))
                time.append(float(parts[1]))

        self.times['coarse'] = Time(data = time*self.units['T'])
        datafiles = [[int(m.groups()[0]), m.string]
                      for m in (re.match("data\.(\d*)\.dbl", s)
                                for s in os.listdir(self.datadir)) if m is not None]
        datafiles = sorted( datafiles, key=lambda item: item[0])
        # Get grid data from first output
        pl = pload(datafiles[0][0], self.datadir)
        self.grids['full'] = pload_to_grid(pl, self.units)
        self._field_resource = [ [f, None] for f in (os.path.join(self.datadir, s) for s in (l[1] for l in datafiles))]
        self._field_resource[0][1] = pl
        for name in var_names:
            self.fields[name] = FieldTimeSeries(name, self._field_resource, self.times['coarse'],
                                                self.grids['full'], unitSys=self.units,
                                                Field = PlutoField)


from fastapi.testclient import TestClient
import pytest
from app.main import app
from app.db import Base, engine
from app.cache import Cache

cache = Cache()

client = TestClient(app)

@pytest.fixture(autouse=True)
def cleanup_db():
    Base.metadata.drop_all(bind=engine)
    Base.metadata.create_all(bind=engine)
    yield

def create_url():
    payload = {"url": "https://www.example.com"}
    response = client.post("/shorten", json=payload, follow_redirects=False)
    assert response.status_code == 201
    location_url = response.json()["location"]
    shortcode = location_url.split("/")[2]
    assert len(shortcode) == 6
    return shortcode

def test_home():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello world"}

def test_shorten_url_no_url():
    body = {}
    response = client.post("/shorten", json=body)
    assert response.status_code == 400
    assert response.json() == {"detail": "URL is required"}

def test_shorten_url_create_url():
    payload = {"url": "https://www.example.com"}
    response = client.post("/shorten", json=payload, follow_redirects=False)
    assert response.status_code == 201
    location_url = response.json()["location"]
    shortcode = location_url.split("/")[2]
    assert len(shortcode) == 6

def test_shorten_url_existing_url():
    shortcode = create_url()

    response = client.post("/shorten", json={"url": "https://www.example.com"}, follow_redirects=False)
    assert response.status_code == 303
    assert response.headers["location"] == f"/urls/{shortcode}"

def test_redirect_url_no_url():
    response = client.get("/urls/abc123", follow_redirects=False)
    assert response.status_code == 404
    assert response.json() == {"detail": "There is no url with this shortcode"}

def test_redirect_url_cache():
    shortcode = create_url()

    assert cache.retrieve_url(shortcode) == "https://www.example.com"

    response = client.get(f"/urls/{shortcode}", follow_redirects=False)
    assert response.status_code == 307
    assert response.headers["location"] == "https://www.example.com"

def test_redirect_url_db():
    shortcode = create_url()

    cache.client.delete(shortcode)

    assert cache.retrieve_url(shortcode) == None

    response = client.get(f"/urls/{shortcode}", follow_redirects=False)
    assert response.status_code == 307
    assert response.headers["location"] == "https://www.example.com"

def test_redirect_url_recache_url():
    shortcode = create_url()

    cache.client.delete(shortcode)

    assert cache.retrieve_url(shortcode) == None

    response = client.get(f"/urls/{shortcode}", follow_redirects=False)

    assert cache.retrieve_url(shortcode) == "https://www.example.com"

def test_redirect_url_extend_url_ttl():
    shortcode = create_url()

    client.get(f"/urls/{shortcode}", follow_redirects=False)

    assert cache.retrieve_url(shortcode) == "https://www.example.com"

    assert cache.client.ttl(shortcode) >= 24 * 60 * 60

def test_url_stats_no_url():
    response = client.get("/urls/abc123/stats", follow_redirects=False)
    assert response.status_code == 404
    assert response.json() == {"detail": "There is no url with this shortcode"}

def test_url_stats_no_hits():
    shortcode = create_url()

    response = client.get(f"/urls/{shortcode}/stats")
    assert response.status_code == 200
    data = response.json()
    assert data["hits"] == 0
    assert data["url"] == "https://www.example.com"

def test_url_stats_with_hits():
    shortcode = create_url()

    for _ in range(10):
        response = client.get(f"/urls/{shortcode}")

    response = client.get(f"/urls/{shortcode}/stats")
    assert response.status_code == 200
    data = response.json()
    assert data["hits"] == 10
    assert data["url"] == "https://www.example.com"

# Unfortunately, I'm not using Python on a daily basis and the mocking proven to be more complicated than I thought.
# Here is an attempt to mock the database to return an integrity error when adding a new URL.
""" def test_shorten_url_existing_url():
    db_mock = MagicMock()

    db_mock.add.side_effect = IntegrityError("statement", "params", "orig", "detail")

    db_mock.query.return_value.filter.return_value.first.return_value = {
        "id": 1,
        "url": "https://www.example.com",
        "shortcode": "abc123",
    }

    app.dependency_overrides["get_db"] = lambda: db_mock

    payload = {"url": "https://www.example.com"}

    response = client.post("/shorten", json=payload, follow_redirects=False)

    assert response.status_code == 303
    assert response.headers["location"] == "/urls/abc123"
"""


import logging

import hydra
from omegaconf import DictConfig

logger = logging.getLogger(__name__)

class BiencoderDatasetsCfg(object):
    def __init__(self, cfg: DictConfig):
        datasets = cfg.datasets
        self.train_datasets_names = cfg.train_datasets
        logger.info("train_datasets: %s", self.train_datasets_names)
        # print(datasets)
        if self.train_datasets_names:
            self.train_datasets = [
                hydra.utils.instantiate(datasets[ds_name])
                for ds_name in self.train_datasets_names
            ]
        else:
            self.train_datasets = []
        if cfg.dev_datasets:
            self.dev_datasets_names = cfg.dev_datasets
            logger.info("dev_datasets: %s", self.dev_datasets_names)
            self.dev_datasets = [
                hydra.utils.instantiate(datasets[ds_name])
                for ds_name in self.dev_datasets_names
            ]
        self.sampling_rates = cfg.train_sampling_rates


from models.calendar_model import CalendarItem
from dotenv import load_dotenv
import os

# id: int
# subject: str
# location: str
# starttime: str
# endtime: str
# categorycolor: str

# Load Secret Items
load_dotenv()
connection_string = os.getenv("ConnectionString")

# MongoDB Driver
import motor.motor_asyncio
client = motor.motor_asyncio.AsyncIOMotorClient(connection_string)

# Create Database & Collection
database = client.DashboardFARM
collection = database.CalendarItems

# Create a Calendar item
async def create_calendar_item(item):
    document = item
    result = await collection.insert_one(document)
    return document

# Read 1 Calendar item
async def read_one_calendar_item(id):
    document = await collection.find_one({"id":id})
    return document

# Read All Calendar items
async def read_all_calendar_items():
    calendar_items = []
    cursor = collection.find({})
    async for document in cursor:
        calendar_items.append(CalendarItem(**document))
    return calendar_items

# Update a Calendar item
async def update_calendar_item(id, subject, location, starttime, endtime, categorycolor):
    await collection.update_one(
        {"id":id},
        {"set": {"subject": subject}},
        {"set": {"location": location}},
        {"set": {"starttime": starttime}},
        {"set": {"endtime": endtime}},
        {"set": {"categorycolor": categorycolor}}
    )
    document = await collection.find_one({"id": id})
    return document

# Delete a Calendar item
async def remove_calendar_item(id):
    await collection.delete_one({"id": id})
    return True


# Released under the MIT License. See LICENSE for details.
#
"""Defines AppDelegate class for handling high level app functionality."""
from __future__ import annotations

from typing import TYPE_CHECKING

import babase

if TYPE_CHECKING:
    from typing import Callable
    import bascenev1

class AppDelegate:
    """Defines handlers for high level app functionality.

    Category: App Classes
    """

    def create_default_game_settings_ui(
        self,
        gameclass: type[bascenev1.GameActivity],
        sessiontype: type[bascenev1.Session],
        settings: dict | None,
        completion_call: Callable[[dict | None], None],
    ) -> None:
        """Launch a UI to configure the given game config.

        It should manipulate the contents of config and call completion_call
        when done.
        """
        # Replace the main window once we come up successfully.
        from bauiv1lib.playlist.editgame import PlaylistEditGameWindow

        assert babase.app.classic is not None
        babase.app.ui_v1.clear_main_menu_window(transition='out_left')
        babase.app.ui_v1.set_main_menu_window(
            PlaylistEditGameWindow(
                gameclass,
                sessiontype,
                settings,
                completion_call=completion_call,
            ).get_root_widget()
        )


#!/usr/bin/env python

# HOUSE ROBBER
#
# - given list of values
# - return highest total value you can get by adding values - but none of the indexes can be touching
#
# NOTES
#
# - introduces RECURRANCE RELATIONSHIP which is a way to break up DYNAMIC PROGRAMMING problems
# - trick is to break the problem into subsets, calculate the highest totals from those groups and store those values somewhere (so that you don't need to recalculate over and over)
#
# example:
#
# 1 2 3 4  # input array
# 1        # highest total from first col
# 2      # highest total from first 2 cols
# 4    # highest total from first 3 cols
# 4  # highest total from first 4 cols # note that is going to be max value from col3 or col2 + col4
#
# aka: col4 = max(col3, col2+col4)

import argparse
from typing import List

class Solution:
    def rob(self, nums: List[int]) -> int:
        rob1, rob2 = 0, 0

        for n in nums:
            temp = max(n + rob1, rob2)
            rob1 = rob2
            rob2 = temp
        return rob2

def main():
    # Use argparse to handle command line arguments
    parser = argparse.ArgumentParser(description='A basic Python script template.')
    parser.add_argument('-a', '--arg1', type=str, help='An example argument')
    args = parser.parse_args()

    # call here
    solution = Solution()
    answer = solution.rob([1,2,3,1])    # 4
    print(answer)

if __name__ == '__main__':
    main()


#!/usr/bin/env python
# coding=utf-8

import rospy
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import cv2
import numpy as np
from geometry_msgs.msg import Twist

rospy.init_node('line_follower')

cmd_vel_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)

cv_bridge = CvBridge()

def image_callback(msg):
    try:
        img = cv_bridge.imgmsg_to_cv2(msg, "bgr8")
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img_filtree = color_filter(img_rgb)
        img_roi = roi(img_filtree)

        controle_suivi_ligne(img_roi)
    except CvBridgeError as e:
        rospy.logerr(e)

# Filtrer l'image pour ne conserver que les pixels rouges
def color_filter(image):
    hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
    lower_red = np.array([0, 100, 100])  # Plage de valeurs pour le rouge (vous pouvez ajuster ces valeurs si nécessaire)
    upper_red = np.array([10, 255, 255])  # Plage de valeurs pour le rouge
    red_mask = cv2.inRange(hsv, lower_red, upper_red)
    masked_image = np.zeros_like(image)
    masked_image[red_mask != 0] = [255, 255, 255]  # Remplacez le rouge par du blanc
    return masked_image

def roi(im):
    x = int(im.shape[1])
    y = int(im.shape[0])

    # Définir les coordonnées de la région d'intérêt en pourcentage de la largeur et de la hauteur de l'image
    shape = np.array([[int(0.003 * x), int(0.7651 * y)],
                      [int(0.995 * x), int(0.735 * y)],
                      [int(0.552 * x), int(0.514 * y)],
                      [int(0.445 * x), int(0.52 * y)]])

    mask = np.zeros_like(im)

    if len(im.shape) > 2:
        channel_count = im.shape[2]
        ignore_mask_color = (255,) * channel_count
    else:
        ignore_mask_color = 255
    cv2.fillPoly(mask, np.int32([shape]), ignore_mask_color)
    masked_image = cv2.bitwise_and(im, mask)
    return masked_image

# Contrôler le robot en fonction de l'image de la région d'intérêt
def controle_suivi_ligne(image_roi):

   # touuuuuuuuut le code pour que ça suit la ligne

    # Exemple de commande de vitesse :
    cmd_vel = Twist()
    cmd_vel.linear.x = 0.2
    cmd_vel.angular.z = 0.0  # Pas de rotation (rad/s)
    cmd_vel_pub.publish(cmd_vel)

rospy.Subscriber('/camera/image', Image, image_callback)
rospy.spin()


from tkinter import Tk, filedialog
import json
import os

Tk().withdraw()  # prevents extra window

with filedialog.askopenfile(initialdir='~') as input_file:
    base_name = os.path.basename(input_file.name)
    if base_name.split('.')[-1] != 'ipynb':
        raise ValueError("Expected file extension '.ipynb'")
    input_obj = json.load(input_file)

output_obj = {key: val for key, val in input_obj.items() if key != 'cells'}
output_obj['cells'] = []

for cell in input_obj['cells']:
    if cell['cell_type'] == 'code':
        output_obj['cells'].append({key: val for key, val in cell.items() if key != 'outputs'})

OUTPUT_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'notebooks')
with open(os.path.join(OUTPUT_DIR, base_name), 'w') as output_file:
    json.dump(output_obj, output_file )