# SPDX-FileCopyrightText: : 2017-2022 The PyPSA-EUR Authors, The PyPSA-Earth Authors, The PyPSA-ZA Authors
# SPDX-License-Identifier: MIT

# coding: utf-8

"""
Adds electrical generators, load and existing hydro storage units to a base network.
Relevant Settings
-----------------
.. code:: yaml
    costs:
        year:
        USD_to_ZAR:
        EUR_to_ZAR:
        marginal_cost:
        dicountrate:
        emission_prices:
        load_shedding:
    electricity:
        max_hours:
        marginal_cost:
        capital_cost:
        conventional_carriers:
        co2limit:
        extendable_carriers:
        include_renewable_capacities_from_OPSD:
        estimate_renewable_capacities_from_capacity_stats:
    load:
        scale:
        ssp:
        weather_year:
        prediction_year:
        region_load:
    renewable:
        hydro:
            carriers:
            hydro_max_hours:
            hydro_capital_cost:
    lines:
        length_factor:
.. seealso::
    Documentation of the configuration file ``config.yaml`` at :ref:`costs_cf`,
    :ref:`electricity_cf`, :ref:`load_cf`, :ref:`renewable_cf`, :ref:`lines_cf`
Inputs
------
- ``model_file.xlsx``: The database to setup different scenarios based on cost assumptions for all included technologies for specific years from various sources; e.g. discount rate, lifetime, investment (CAPEX), fixed operation and maintenance (FOM), variable operation and maintenance (VOM), fuel costs, efficiency, carbon-dioxide intensity.
- ``data/Eskom EAF data.xlsx``: Hydropower plant store/discharge power capacities, energy storage capacity, and average hourly inflow by country.  Not currently used!
- ``data/eskom_pu_profiles.csv``: alternative to capacities above; not currently used!
- ``data/bundle/SystemEnergy2009_22.csv`` Hourly country load profiles produced by GEGIS
- ``resources/regions_onshore.geojson``: confer :ref:`busregions`
- ``resources/gadm_shapes.geojson``: confer :ref:`shapes`
- ``data/bundle/supply_regions/{regions}.shp``: confer :ref:`powerplants`
- ``resources/profile_{}_{regions}_{resarea}.nc``: all technologies in ``config["renewables"].keys()``, confer :ref:`renewableprofiles`.
- ``networks/base_{model_file}_{regions}.nc``: confer :ref:`base`
Outputs
-------
- ``networks/elec_{model_file}_{regions}_{resarea}.nc``:
    .. image:: ../img/elec.png
            :scale: 33 %
Description
-----------
The rule :mod:`add_electricity` ties all the different data inputs from the preceding rules together into a detailed PyPSA network that is stored in ``networks/elec.nc``. It includes:
- today's transmission topology and transfer capacities (in future, optionally including lines which are under construction according to the config settings ``lines: under_construction`` and ``links: under_construction``),
- today's thermal and hydro power generation capacities (for the technologies listed in the config setting ``electricity: conventional_carriers``), and
- today's load time-series (upsampled in a top-down approach according to population and gross domestic product)
It further adds extendable ``generators`` with **zero** capacity for
- photovoltaic, onshore and AC- as well as DC-connected offshore wind installations with today's locational, hourly wind and solar capacity factors (but **no** current capacities),
- additional open- and combined-cycle gas turbines (if ``OCGT`` and/or ``CCGT`` is listed in the config setting ``electricity: extendable_carriers``)
"""

from email import generator
import logging
import os
import geopandas as gpd
import numpy as np
import pandas as pd
import powerplantmatching as pm
import pypsa
import xarray as xr
from _helpers import (configure_logging,
                    update_p_nom_max,
                    pdbcast,
                    map_generator_parameters,
                    clean_pu_profiles,
                    remove_leap_day)

from shapely.validation import make_valid
from shapely.geometry import Point
from vresutils import transfer as vtransfer
idx = pd.IndexSlice
logger = logging.getLogger(__name__)
from pypsa.descriptors import get_switchable_as_dense as get_as_dense

import warnings
warnings.simplefilter(action='ignore', category=FutureWarning) # Comment out for debugging and development

def normed(s):
    return s / s.sum()

def calculate_annuity(n, r):
    """
    Calculate the annuity factor for an asset with lifetime n years and
    discount rate of r, e.g. annuity(20, 0.05) * 20 = 1.6
    """
    if isinstance(r, pd.Series):
        return pd.Series(1 / n, index=r.index).where(
            r == 0, r / (1.0 - 1.0 / (1.0 + r) ** n)
        )
    elif r > 0:
        return r / (1.0 - 1.0 / (1.0 + r) ** n)
    else:
        return 1 / n

def _add_missing_carriers_from_costs(n, costs, carriers):
    missing_carriers = pd.Index(carriers).difference(n.carriers.index)
    if missing_carriers.empty: return

    emissions_cols = costs.columns.to_series()\
                           .loc[lambda s: s.str.endswith('_emissions')].values
    suptechs = missing_carriers.str.split('-').str[0]
    emissions = costs.loc[suptechs, emissions_cols].fillna(0.)
    emissions.index = missing_carriers
    n.import_components_from_dataframe(emissions, 'Carrier')

def load_costs(model_file, cost_scenario, config, elec_config, config_years):
    """
    set all asset costs and other parameters
    """
    cost_data = pd.read_excel(
        model_file,
        sheet_name='costs',
        index_col=list(range(3)
        )
    ).sort_index().loc[cost_scenario]

    cost_data.drop('source',axis=1,inplace=True)

    # Interpolate for years in config file but not in cost_data excel file
    config_years_array = np.array(config_years)
    missing_year = config_years_array[~np.isin(config_years_array,cost_data.columns)]
    if len(missing_year) > 0:
        for i in missing_year:
            cost_data.insert(0,i,np.nan) # add columns of missing year to dataframe
        cost_data_tmp = cost_data.drop('unit',axis=1).sort_index(axis=1)
        cost_data_tmp = cost_data_tmp.interpolate(axis=1)
        cost_data = pd.concat([cost_data_tmp, cost_data['unit']],ignore_index=False,axis=1)

    # correct units to MW and ZAR
    cost_data.loc[cost_data.unit.str.contains("/kW")==True, config_years] *= 1e3
    cost_data.loc[cost_data.unit.str.contains("USD")==True, config_years] *= config["USD_to_ZAR"]
    cost_data.loc[cost_data.unit.str.contains("EUR")==True, config_years] *= config["EUR_to_ZAR"]

    # Convert fuel cost from R/GJ to R/MWh
    cost_data.loc[cost_data.unit.str.contains("R/GJ")==True, config_years] *= 3.6

    # Get entries where FOM is specified as % of CAPEX
    fom_perc_capex=cost_data.loc[cost_data.unit.str.contains("%/year")==True, config_years]
    fom_perc_capex=fom_perc_capex.index.get_level_values(0)

    costs = {}
    for y in config_years:
        costs[y]=cost_data.loc[idx[:, y]].unstack(level=1).fillna(
            {
                "CO2 intensity": 0,
                "FOM": 0,
                "VOM": 0,
                "discount rate": config["discountrate"],
                "heat_rate":0,
                "efficiency": 1,
                "efficiency_store": 1,
                "efficiency_dispatch": 1,
                "fuel": 0,
                "investment": 0,
                "lifetime": 25,
            }
        )

        costs[y]['efficiency_store']=costs[y]['efficiency'].pow(1./2) #if only 1 efficiency value is given assume it is round trip efficiency
        costs[y]['efficiency_dispatch']=costs[y]['efficiency'].pow(1./2)

        costs[y].loc[fom_perc_capex,'FOM']*=costs[y].loc[fom_perc_capex,"investment"]/100.0
        costs[y]["capital_cost"] = (costs[y]["investment"]*
                                    calculate_annuity(costs[y]["lifetime"], costs[y]["discount rate"])
                                    + costs[y]["FOM"])

        costs[y].at["OCGT", "fuel"] = costs[y].at["gas", "fuel"]
        costs[y].at["CCGT", "fuel"] = costs[y].at["gas", "fuel"]

        costs[y]["marginal_cost"] = costs[y]["VOM"] + costs[y]["fuel"] / costs[y]["efficiency"]

        costs[y] = costs[y].rename(columns={"CO2 intensity": "co2_emissions"})

        costs[y].at["OCGT", "co2_emissions"] = costs[y].at["gas", "co2_emissions"]
        costs[y].at["CCGT", "co2_emissions"] = costs[y].at["gas", "co2_emissions"]

        costs[y].at["solar", "capital_cost"] = 0.5 * (
            costs[y].at["solar-rooftop", "capital_cost"]
            + costs[y].at["solar-utility", "capital_cost"]
        )

        def costs_for_storage(store, link1, link2=None, max_hours=1.0):
            capital_cost = link1["capital_cost"] + max_hours * store["capital_cost"]
            if link2 is not None:
                capital_cost += link2["capital_cost"]
            return pd.Series(
                dict(capital_cost=capital_cost, marginal_cost=0.0, co2_emissions=0.0)
            )

        max_hours = elec_config["max_hours"]
        costs[y].loc["battery"] = costs_for_storage(
            costs[y].loc["battery storage"],
            costs[y].loc["battery inverter"],
            max_hours=max_hours["battery"],
        )
        costs[y].loc['battery',:].fillna(costs[y].loc['battery inverter',:],inplace=True)

    for attr in ("marginal_cost", "capital_cost"):
        overwrites = config.get(attr)
        if overwrites is not None:
            overwrites = pd.Series(overwrites)
            costs[y].loc[overwrites.index, attr] = overwrites

    return costs

def add_generator_availability(n,generators,config_avail,eaf_projections):
    # Add plant availability based on actual Eskom data
    eskom_data  = pd.read_excel(
        snakemake.input.existing_generators_eaf,
        sheet_name='eskom_data',
        na_values=['-'],
        index_col=[1,0],
        parse_dates=True
    )
    snapshots = n.snapshots.get_level_values(1)
    years_full = range(n.investment_periods[0]-1,n.investment_periods[-1]+1)
    eaf_profiles = pd.DataFrame(1,index=snapshots,columns=[])

    # All existing generators in the Eskom fleet with available data
    for tech in n.generators.index[n.generators.plant_name.isin(eskom_data.index.get_level_values(0).unique())]:
        plant_name = n.generators.plant_name[tech]
        reference_data = eskom_data.loc[plant_name].loc[eskom_data.loc[plant_name].index.year.isin(config_avail['reference_years'])]
        base_eaf=(reference_data['EAF %']/100).groupby(reference_data['EAF %'].index.month).mean()
        carrier = n.generators.carrier[tech]
        for y in n.investment_periods:
            eaf_profiles.loc[str(y),tech]=base_eaf[eaf_profiles.loc[str(y)].index.month].values
            if carrier + '_fleet_EAF' in eaf_projections.index:
                eaf_profiles.loc[str(y),tech]=(base_eaf[eaf_profiles.loc[str(y)].index.month].values
                                *eaf_projections.loc[carrier+ '_fleet_EAF',y]
                                /(eskom_data.loc[carrier+'_total'].loc[eskom_data.loc[carrier+'_total'].index.year.isin(config_avail['reference_years']),'EAF %'].mean()/100))

    n.generators.loc[n.generators.plant_name.isna(),'plant_name']=n.generators.index[n.generators.plant_name.isna()]
    # New plants without existing data take best performing of Eskom fleet
    for carrier in ['coal', 'OCGT', 'CCGT', 'nuclear']:
        # 0 - Reference station, 1 - reference year, 2 - multiplier
        reference_data = eskom_data.loc[config_avail['new_unit_ref'][carrier][0]]
        reference_data = reference_data.loc[reference_data.index.year.isin(config_avail['new_unit_ref'][carrier][1])]
        base_eaf=(reference_data['EAF %']/100).groupby(reference_data['EAF %'].index.month).mean()* config_avail['new_unit_ref'][carrier][2]
        for gen_ext in n.generators[(n.generators.carrier==carrier) & (n.generators.p_nom_extendable)].index:
            eaf_profiles[gen_ext]=1
            for y in n.investment_periods:
                eaf_profiles.loc[str(y),gen_ext]=base_eaf[eaf_profiles.loc[str(y)].index.month].values

    eaf_profiles[eaf_profiles>1]=1
    eaf_profiles.index=n.snapshots
    n.generators_t.p_max_pu[eaf_profiles.columns]=eaf_profiles

def add_min_stable_levels(n, generators, config_min_stable):
    # Existing generators
    for gen in generators.index:
        if ((generators.loc[gen, "min_stable"] != 0) & (gen in n.generators.index)):
            p_min_pu = n.generators_t.p_min_pu.get(gen, n.generators.p_max_pu[gen])
            n.generators_t.p_min_pu[gen] = p_min_pu * generators.loc[gen, "min_stable"]

            p_max_pu = n.generators_t.p_max_pu.get(gen, n.generators.p_max_pu[gen])
            if isinstance(p_max_pu, (pd.DataFrame, pd.Series)):
                n.generators_t.p_max_pu[gen] = p_max_pu.where(p_max_pu >= generators.loc[gen, "min_stable"], generators.loc[gen, "min_stable"])
            else:
                n.generators_t.p_max_pu[gen] = max(p_max_pu, generators.loc[gen, "min_stable"])

    # New conventional generators take defined pu_min from config_file
    for carrier in ["coal", "OCGT", "CCGT", "nuclear","biomass"]:
        for gen_ext in n.generators[(n.generators.carrier == carrier) & (~n.generators.index.isin(generators.index))].index:
            n.generators_t.p_min_pu[gen_ext] = n.generators_t.p_max_pu[gen_ext] * config_min_stable[carrier]

    n.generators_t.p_min_pu = n.generators_t.p_min_pu.fillna(0)

 ## Attach components
# ### Load

def attach_load(n, annual_demand):
    load = pd.read_csv(snakemake.input.load,index_col=[0],parse_dates=True)

    annual_demand = annual_demand.drop('unit')*1e6

    # load = load.set_index(
    #     pd.to_datetime(load['date'] + ' ' +
    #                    load['PERIOD'].astype(str) + ':00')
    #     .rename('t'))['SYSTEMENERGY']

    demand=pd.Series(0,index=n.snapshots)

    profile_demand = normed(remove_leap_day(load.loc[str(snakemake.config['years']['reference_demand_year']),'system_energy']))

    # if isinstance(n.snapshots, pd.MultiIndex):
    for y in n.investment_periods:
            demand.loc[y]=profile_demand.values*annual_demand[y]

    n.madd("Load", n.buses.index,
           bus=n.buses.index,
           p_set=pdbcast(demand, normed(n.buses.population)))

### Generate pu profiles for other_re based on Eskom data
def generate_eskom_profiles(n,config_carriers,ref_years):
    carriers= config_carriers
    if snakemake.config["enable"]["use_excel_wind_solar"][0]:
        carriers = [ elem for elem in carriers if elem not in ['onwind','solar']]

    eskom_data = (
        pd.read_csv(
            snakemake.input.eskom_profiles,skiprows=[1],
            index_col=0,parse_dates=True
        )
        .resample('1h').mean()
    )

    eskom_data  = remove_leap_day(eskom_data)
    eskom_profiles=pd.DataFrame(0,index=n.snapshots,columns=carriers)

    for carrier in carriers:
        weather_years=ref_years[carrier]
        for i in range(0,int(np.ceil(len(n.investment_periods)/len(weather_years))-1)):
            weather_years+=weather_years

        cnt=0
        # Use the default RSA hourly data (from Eskom) and extend to multiple weather years
        for y in n.investment_periods:
            eskom_profiles.loc[y,carrier] = (eskom_data.loc[str(weather_years[cnt]),carrier]
                                        .clip(lower=0., upper=1.)).values
            cnt+=1
    return eskom_profiles

def generate_excel_wind_solar_profiles(n,ref_years):
    profiles={}
    profiles['onwind'] = pd.DataFrame(0,index=n.snapshots,columns=n.buses.index)
    profiles['solar'] = pd.DataFrame(0,index=n.snapshots,columns=n.buses.index)
    # wind and solar resources can be explicitly specified in excel format
    for carrier in ['onwind','solar']:
        raw_profiles= (pd.read_excel(snakemake.config["enable"]["use_excel_wind_solar"][1],
                                    sheet_name=carrier+'_pu',
                                    skiprows=[1],
                                    index_col=0,parse_dates=True)
                                    .resample('1h').mean()
        )
        raw_profiles = remove_leap_day(raw_profiles)

        weather_years=ref_years[carrier]
        for i in range(0,int(np.ceil(len(n.investment_periods)/len(weather_years))-1)):
            weather_years+=weather_years

        cnt=0
        # Use the default RSA hourly data (from Eskom) and extend to multiple weather years
        for y in n.investment_periods:
            profiles[carrier].loc[y,n.buses.index] = (
                raw_profiles.loc[str(weather_years[cnt]),n.buses.index]
                .clip(lower=0., upper=1.)
            ).values
            cnt+=1

    return profiles

### Set line costs

def update_transmission_costs(n, costs, length_factor=1.0, simple_hvdc_costs=False):
    for y in n.investment_periods:
        n.lines["capital_cost"] = (
            n.lines["length"] * length_factor * costs[y].at["HVAC overhead", "capital_cost"]
        )

        if n.links.empty:
            return

        dc_b = n.links.carrier == "DC"
        # If there are no "DC" links, then the 'underwater_fraction' column
        # may be missing. Therefore we have to return here.
        # TODO: Require fix
        if n.links.loc[n.links.carrier == "DC"].empty:
            return

        if simple_hvdc_costs:
            costs = (
                n.links.loc[dc_b, "length"]
                * length_factor
                * costs[y].at["HVDC overhead", "capital_cost"]
            )
        else:
            costs = (
                n.links.loc[dc_b, "length"]
                * length_factor
                * (
                    (1.0 - n.links.loc[dc_b, "underwater_fraction"])
                    * costs[y].at["HVDC overhead", "capital_cost"]
                    + n.links.loc[dc_b, "underwater_fraction"]
                    * costs[y].at["HVDC submarine", "capital_cost"]
                )
                + costs[y].at["HVDC inverter pair", "capital_cost"]
            )
        n.links.loc[dc_b, "capital_cost"] = costs

# ### Generators - TODO Update from pypa-eur
def attach_wind_and_solar(n, costs,input_profiles, model_setup, eskom_profiles):

    # Aggregate existing REIPPPP plants per region
    eskom_gens = pd.read_excel(
        snakemake.input.model_file,
        sheet_name='existing_eskom',
        na_values=['-'],
        index_col=[0,1]
    ).loc[model_setup.existing_eskom]
    eskom_gens = eskom_gens[eskom_gens['Carrier'].isin(['solar','onwind'])] # Currently only Sere wind farm

    ipp_gens = pd.read_excel(
        snakemake.input.model_file,
        sheet_name='existing_non_eskom',
        na_values=['-'],
        index_col=[0,1]
    ).loc[model_setup.existing_non_eskom]
    ipp_gens=ipp_gens[ipp_gens['Carrier'].isin(['solar','onwind'])] # add existing wind and PV IPP generators

    gens = pd.concat([eskom_gens,ipp_gens])
    gens['bus']=np.nan
    # Calculate fields where pypsa uses different conventions
    gens = map_generator_parameters(gens,n.investment_periods[0])

    # Associate every generator with the bus of the region it is in or closest to
    pos = gpd.GeoSeries([Point(o.x, o.y) for o in gens[['x', 'y']].itertuples()], index=gens.index)
    regions = gpd.read_file(
        snakemake.input.supply_regions,
        layer = snakemake.wildcards.regions
    ).to_crs(snakemake.config["crs"]["geo_crs"]).set_index('name')

    for bus, region in regions.geometry.items():
        pos_at_bus_b = pos.within(region)
        if pos_at_bus_b.any():
            gens.loc[pos_at_bus_b, "bus"] = bus
    gens.loc[gens.bus.isnull(), "bus"] = pos[gens.bus.isnull()].map(lambda p: regions.distance(p).idxmin())
    gens.loc['Sere','Grouping'] = 'REIPPPP_BW1' #add Sere wind farm to BW1 for simplification #TODO fix this to be general

    # Aggregate REIPPPP bid window generators at each bus #TODO use capacity weighted average for lifetime, costs
    for carrier in ['solar','onwind']:
        plant_data = gens.loc[gens['carrier']==carrier,['Grouping','bus','p_nom']].groupby(['Grouping','bus']).sum()
        for param in ['lifetime','capital_cost','marginal_cost']:
            plant_data[param]=gens.loc[gens['carrier']==carrier,['Grouping','bus',param]].groupby(['Grouping','bus']).mean()

        resource_carrier=pd.DataFrame(0,index=n.snapshots,columns=n.buses.index)
        if ((snakemake.config["enable"]["use_eskom_wind_solar"]==False) &
            (snakemake.config["enable"]["use_excel_wind_solar"][0]==False)):
            ds = xr.open_dataset(getattr(input_profiles, "profile_" + carrier))
            for y in n.investment_periods:
                    atlite_data = ds["profile"].transpose("time", "bus").to_pandas()
                     #TODO remove hard coding only use 1yr from atlite at present
                    #resource_carrier.loc[y] = (atlite_data.loc[str(weather_years[cnt])].clip(lower=0., upper=1.)).values
                    resource_carrier.loc[y] = atlite_data.clip(lower=0., upper=1.).values[0:8760]
        elif (snakemake.config["enable"]["use_excel_wind_solar"][0]):
            excel_wind_solar_profiles = generate_excel_wind_solar_profiles(n,
                                snakemake.config['years']['reference_weather_years'])
            resource_carrier[n.buses.index] = excel_wind_solar_profiles[carrier][n.buses.index]
        else:
            for bus in n.buses.index:
                resource_carrier[bus] = eskom_profiles[carrier].values # duplicate aggregate Eskom profile if specified

        for group in plant_data.index.levels[0]:
            n.madd("Generator", plant_data.loc[group].index, suffix=" "+group+"_"+carrier,
                bus=plant_data.loc[group].index,
                carrier=carrier,
                build_year=n.investment_periods[0],
                lifetime=plant_data.loc[group,'lifetime'],
                p_nom = plant_data.loc[group,'p_nom'],
                p_nom_extendable=False,
                marginal_cost = plant_data.loc[group,'marginal_cost'],
                p_max_pu=resource_carrier[plant_data.loc[group].index],
                p_min_pu=resource_carrier[plant_data.loc[group].index]*0.95, # for existing PPAs force to buy all energy produced
                )

    # Add new generators
        for y in n.investment_periods:
            #TODO add check here to exclude buses where p_nom_max = 0
            n.madd("Generator", n.buses.index, suffix=" "+carrier+"_"+str(y),
                bus=n.buses.index,
                carrier=carrier,
                build_year=y,
                lifetime=costs[y].at[carrier,'lifetime'],
                p_nom_extendable=True,
                #p_nom_max=ds["p_nom_max"].to_pandas(), # For multiple years a further constraint is applied in prepare_network.py
                #weight=ds["weight"].to_pandas(),
                marginal_cost=costs[y].at[carrier, 'marginal_cost'],
                capital_cost=costs[y].at[carrier, 'capital_cost'],
                efficiency=costs[y].at[carrier, 'efficiency'],
                p_max_pu=resource_carrier[n.buses.index])
    return gens
# # Generators
def attach_existing_generators(n, costs, eskom_profiles, model_setup):
    # Coal, gas, diesel, biomass, hydro, pumped storage

    # Add existing conventional generators that are active
    eskom_gens = pd.read_excel(
        snakemake.input.model_file,
        sheet_name='existing_eskom',
        na_values=['-'],
        index_col=[0,1]
    ).loc[model_setup.existing_eskom]

    eskom_gens = eskom_gens[~eskom_gens['Carrier'].isin(['solar','onwind'])]

    ipp_gens = pd.read_excel(
        snakemake.input.model_file,
        sheet_name='existing_non_eskom',
        na_values=['-'],
        index_col=[0,1]
    ).loc[model_setup.existing_non_eskom]

    ipp_gens=ipp_gens[~ipp_gens['Carrier'].isin(['solar','onwind'])] # add existing non eskom generators (excluding solar, onwind)

    gens = pd.concat([eskom_gens,ipp_gens])
    gens = map_generator_parameters(gens,n.investment_periods[0])

    # CahoraBassa will be added later, even though we don't have coordinates
    CahoraBassa  = pd.DataFrame(gens.loc["CahoraBassa"]).T
    # Drop power plants where we don't have coordinates or capacity
    gens = pd.DataFrame(gens.loc[lambda df: (df.p_nom>0.) & df.x.notnull() & df.y.notnull()])

    # Associate every generator with the bus of the region it is in or closest to
    pos = gpd.GeoSeries([Point(o.x, o.y) for o in gens[['x', 'y']].itertuples()], index=gens.index)
    regions = gpd.read_file(
        snakemake.input.supply_regions,
        layer = snakemake.wildcards.regions
    ).to_crs(snakemake.config["crs"]["geo_crs"]).set_index('name')

    for bus, region in regions.geometry.items():
        pos_at_bus_b = pos.within(region)
        if pos_at_bus_b.any():
            gens.loc[pos_at_bus_b, "bus"] = bus
    gens.loc[gens.bus.isnull(), "bus"] = pos[gens.bus.isnull()].map(lambda p: regions.distance(p).idxmin())

    if snakemake.wildcards.regions=='1-supply':
        CahoraBassa['bus'] = "RSA"
    elif snakemake.wildcards.regions=='27-supply':
        CahoraBassa['bus'] = "POLOKWANE"
    else:
        CahoraBassa['bus'] = "LIMPOPO"
    gens = pd.concat([gens,CahoraBassa])

    gen_index=gens[gens.carrier.isin(['coal','nuclear','gas','diesel','hydro','hydro-import'])].index
    n.madd("Generator", gen_index,
        bus=gens.loc[gen_index,'bus'],
        carrier=gens.loc[gen_index,'carrier'],
        build_year=n.investment_periods[0],
        lifetime=gens.loc[gen_index,'lifetime'],
        p_nom = gens.loc[gen_index,'p_nom'],
        p_nom_extendable=False,
        efficiency = gens.loc[gen_index,'efficiency'],
        ramp_limit_up = gens.loc[gen_index,'ramp_limit_up'],
        ramp_limit_down = gens.loc[gen_index,'ramp_limit_down'],
        marginal_cost=gens.loc[gen_index,'marginal_cost'],
        capital_cost=gens.loc[gen_index,'capital_cost'],
        #p_max_pu - added later under generator availability function
        )
    n.generators['plant_name'] = n.generators.index.str.split('*').str[0]

    for carrier in ['CSP','biomass']:
        n.add("Carrier", name=carrier)
        plant_data = gens.loc[gens['carrier']==carrier,['Grouping','bus','p_nom']].groupby(['Grouping','bus']).sum()
        for param in ['lifetime','efficiency','capital_cost','marginal_cost']:
            plant_data[param]=gens.loc[gens['carrier']==carrier,['Grouping','bus',param]].groupby(['Grouping','bus']).mean()

        for group in plant_data.index.levels[0]:
            # Duplicate Aggregate Eskom Data across the regions
            eskom_data = pd.concat([eskom_profiles[carrier]] * (len(plant_data.loc[group].index)), axis=1, ignore_index=True)
            eskom_data.columns = plant_data.loc[group].index
            capacity_factor = (eskom_data[plant_data.loc[group].index]).mean()[0]
            annual_cost = capacity_factor * 8760 * plant_data.loc[group,'marginal_cost']

            n.madd("Generator", plant_data.loc[group].index, suffix=" "+group+"_"+carrier,
                bus=plant_data.loc[group].index,
                carrier=carrier,
                build_year=n.investment_periods[0],
                lifetime=plant_data.loc[group,'lifetime'],
                p_nom = plant_data.loc[group,'p_nom'],
                p_nom_extendable=False,
                efficiency = plant_data.loc[group,'efficiency'],
                capital_cost=annual_cost,
                p_max_pu=eskom_data.values,
                p_min_pu=eskom_data.values*0.95, #purchase at least 95% of power under existing PPAs despite higher cost
                )

    # ## HYDRO and PHS
    # # Cohora Bassa imports to South Africa - based on Actual Eskom data from 2017-2022
    n.generators_t.p_max_pu['CahoraBassa'] = eskom_profiles['hydro-import'].values
    # Hydro power generation - based on actual Eskom data from 2017-2022
    for tech in n.generators[n.generators.carrier=='hydro'].index:
        n.generators_t.p_max_pu[tech] = eskom_profiles['hydro'].values

    for tech in n.generators[n.generators.carrier=='hydro-import'].index:
        n.generators_t.p_max_pu[tech] = eskom_profiles['hydro-import'].values

    # PHS
    phs = gens[gens.carrier=='PHS']
    n.madd('StorageUnit', phs.index, carrier='PHS',
            bus=phs['bus'],
            p_nom=phs['p_nom'],
            max_hours=phs['PHS_max_hours'],
            capital_cost=phs['capital_cost'],
            marginal_cost=phs['marginal_cost'],
            efficiency_dispatch=phs['PHS_efficiency']**(0.5),
            efficiency_store=phs['PHS_efficiency']**(0.5),
            cyclic_state_of_charge=True
            #inflow=inflow_t.loc[:, hydro.index]) #TODO add in
            )

    _add_missing_carriers_from_costs(n, costs[n.investment_periods[0]], gens.carrier.unique())

    return gens

def attach_extendable_generators(n, costs):
    elec_opts = snakemake.config['electricity']
    carriers = elec_opts['extendable_carriers']['Generator']
    if snakemake.wildcards.regions=='1-supply':
        buses = dict(zip(carriers,['RSA']*len(carriers)))
    elif snakemake.wildcards.regions=='27-supply':
        buses = elec_opts['buses']['27-supply']
    else:
        buses = elec_opts['buses']['11-supply']

    _add_missing_carriers_from_costs(n, costs[n.investment_periods[0]], carriers)

    for y in n.investment_periods:
        for carrier in carriers:
            buses_i = buses.get(carrier, n.buses.index.to_list())
            if buses_i=='RSA':
                    n.add("Generator", buses_i + " " + carrier + "_"+str(y),
                        bus=buses_i,
                        p_nom_extendable=True,
                        carrier=carrier,
                        build_year=y,
                        lifetime=costs[y].at[carrier, 'lifetime'],
                        capital_cost=costs[y].at[carrier, 'capital_cost'],
                        marginal_cost=costs[y].at[carrier, 'marginal_cost'],
                        efficiency=costs[y].at[carrier, 'efficiency'])
            else:
                n.madd("Generator", buses_i, suffix=" " + carrier + "_"+str(y),
                    bus=buses_i,
                    p_nom_extendable=True,
                    carrier=carrier,
                    build_year=y,
                    lifetime=costs[y].at[carrier, 'lifetime'],
                    capital_cost=costs[y].at[carrier, 'capital_cost'],
                    marginal_cost=costs[y].at[carrier, 'marginal_cost'],
                    efficiency=costs[y].at[carrier, 'efficiency'])

def attach_storage(n, costs):
    elec_opts = snakemake.config['electricity']
    carriers = elec_opts['extendable_carriers']['StorageUnit']
    max_hours = elec_opts['max_hours']
    buses = elec_opts['buses']

    _add_missing_carriers_from_costs(n, costs[n.investment_periods[0]], carriers)

    for y in n.investment_periods:
        for carrier in carriers:
            buses_i = buses.get(carrier, n.buses.index)
            n.madd("StorageUnit", buses_i, " " + carrier + "_" + str(y),
                bus=buses_i,
                p_nom_extendable=True,
                carrier=carrier,
                build_year=y,
                capital_cost=costs[y].at[carrier, 'capital_cost'],
                marginal_cost=costs[y].at[carrier, 'marginal_cost'],
                efficiency_store=costs[y].at[carrier, 'efficiency_store'],
                efficiency_dispatch=costs[y].at[carrier, 'efficiency_dispatch'],
                max_hours=max_hours[carrier],
                cyclic_state_of_charge=True)

def add_co2limit(n):
    n.add("GlobalConstraint", "CO2Limit",
          carrier_attribute="co2_emissions", sense="<=",
          constant=snakemake.config['electricity']['co2limit'])

# already in prepare_network
    # def add_emission_prices(n, emission_prices=None, exclude_co2=False):
    #     if emission_prices is None:
    #         emission_prices = snakemake.config['costs']['emission_prices']
    #     if exclude_co2: emission_prices.pop('co2')
    #     ep = (pd.Series(emission_prices).rename(lambda x: x+'_emissions') * n.carriers).sum(axis=1)
    #     n.generators['marginal_cost'] += n.generators.carrier.map(ep)
    #     n.storage_units['marginal_cost'] += n.storage_units.carrier.map(ep)

def add_peak_demand_hour_without_variable_feedin(n):
    new_hour = n.snapshots[-1] + pd.Timedelta(hours=1)
    n.set_snapshots(n.snapshots.append(pd.Index([new_hour])))

    # Don't value new hour for energy totals
    n.snapshot_weightings[new_hour] = 0.

    # Don't allow variable feed-in in this hour
    n.generators_t.p_max_pu.loc[new_hour] = 0.

    n.loads_t.p_set.loc[new_hour] = (
        n.loads_t.p_set.loc[n.loads_t.p_set.sum(axis=1).idxmax()]
        * (1.+snakemake.config['electricity']['SAFE_reservemargin'])
    )

def add_nice_carrier_names(n, config):
    carrier_i = n.carriers.index
    nice_names = (
        pd.Series(config["plotting"]["nice_names"])
        .reindex(carrier_i)
        .fillna(carrier_i.to_series().str.title())
    )
    n.carriers["nice_name"] = nice_names
    colors = pd.Series(config["plotting"]["tech_colors"]).reindex(carrier_i)
    if colors.isna().any():
        missing_i = list(colors.index[colors.isna()])
        logger.warning(
            f"tech_colors for carriers {missing_i} not defined " "in config."
        )
    n.carriers["color"] = colors

#%%
if __name__ == "__main__":
    if 'snakemake' not in globals():
        from _helpers import mock_snakemake
        snakemake = mock_snakemake(
            'add_electricity',
            **{
                'model_file':'val-LC-UNC',
                'regions':'27-supply',
                'resarea':'redz',
                'll':'copt',
                'attr':'p_nom'
            }
        )

    model_setup = (
        pd.read_excel(snakemake.input.model_file,
                                sheet_name='model_setup',
                                index_col=[0])
                                .loc[snakemake.wildcards.model_file]
                                )

    projections = (pd.read_excel(snakemake.input.model_file,
                            sheet_name='projected_parameters',
                            index_col=[0,1])
                            .loc[model_setup['projected_parameters']])

    #opts = snakemake.wildcards.opts.split('-')
    n = pypsa.Network(snakemake.input.base_network)
    costs = load_costs(
        snakemake.input.model_file,
        model_setup.costs,
        snakemake.config["costs"],
        snakemake.config["electricity"],
        n.investment_periods,
    )

    #wind_solar_profiles = xr.open_dataset(snakemake.input.wind_solar_profiles).to_dataframe()
    eskom_profiles = generate_eskom_profiles(
        n,
        snakemake.config['electricity']['renewable_carriers'],
        snakemake.config['years']['reference_weather_years']
    )

    attach_load(n, projections.loc['annual_demand',:])
    if snakemake.wildcards.regions!='1-supply':
        update_transmission_costs(n, costs)
    gens = attach_existing_generators(n, costs, eskom_profiles, model_setup)
    attach_wind_and_solar(n, costs, snakemake.input, model_setup, eskom_profiles)
    attach_extendable_generators(n, costs)
    attach_storage(n, costs)
    if snakemake.config['electricity']['generator_availability']['implement_availability']==True:
        add_generator_availability(n,
            gens[gens.Type == 'Generator'],
            snakemake.config['electricity']['generator_availability'],
            projections
        )
        add_min_stable_levels(
            n,gens[gens.Type == 'Generator'],
            snakemake.config['electricity']['min_stable_levels']
        )
    add_nice_carrier_names(n, snakemake.config)
    n.export_to_netcdf(snakemake.output[0])


#!/usr/bin/python

from random import shuffle,seed
from os import urandom
seed(urandom(512))

conditions=['Placebo','Oxytocin']

for subject in range(1,41):
    subjstr=str(subject)
    shuffle(conditions)
    print (subjstr+"A"),conditions[0]
    print (subjstr+"B"),conditions[1]


import cv2
import numpy as np
from matplotlib import pyplot as plt
from imutils import perspective
from imutils import contours
import imutils
from imutils.video import VideoStream, FPS
import time
import random as rng
from scipy.spatial import distance as dist
from centroidTracker import CentroidTracker
from imutils.video import FileVideoStream
## Read
#"C:/Users/israe/Downloads/frames_ml_trim7s/frame%d.jpg" % count, image)
#stream = cv2.VideoCapture('C:/Users/israe/Downloads/tracking/trim7s.mp4')
#success,image = vidcap.read()
#fvs = FileVideoStream('C:/Users/israe/detectVideo_Output.avi').start()

ct = CentroidTracker()
fvs = FileVideoStream('C:/Users/israe/detectVideo_Output.avi').start()
time.sleep(2.0)
H,W = None, None
fps = FPS().start()
#cv2.destroyAllWindows()
#imgNew = fvs.read()
#img = cv2.imread("C:/Users/israe/Downloads/frames_ml_trim7s/frame200.jpg")
#fourcc = cv2.VideoWriter_fourcc('M','J','P','G')
#name = '/CountdetectVideo_Output_' + args.method + '.avi'
#videoOut = cv2.VideoWriter('CountdetectVideo_Output.mp4',fourcc, 20.0, (imgNew.shape[1], imgNew.shape[0]))
counter = 1
totalObjects = []
lastNumberItem = []
frameText = []
while fvs.more():
    """
    (grabbed, frame) = stream.read()

    if not grabbed:
        print("[INFO]: End of video frames")
        break

    if frame.all()==None:
        assert grabbed==None, "Video is in invalid directory or name is invalid"
    """
    img =fvs.read()
    ## convert to hsv
    #img = frame
    if img is None:
        break

    img = img[:,:1000]
    #second and first img = img[100:,:960]

    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    ## mask of green (36,25,25) ~ (86, 255,255)
    # mask = cv2.inRange(hsv, (36, 25, 25), (86, 255,255))
    mask = cv2.inRange(hsv, (36, 40, 40), (77, 255,255))
    #thresh , im_bw = cv2.threshold(hsv,(36, 40, 40), (77, 255,255),0)
    ## slice the green
    imask = mask>0
    green = np.zeros_like(img, np.uint8)
    green[imask] = img[imask]

    ## save
    #cv2.imwrite("green.png", green)

    new_green = cv2.cvtColor(green, cv2.COLOR_RGB2GRAY)
    #cv2.imshow("green", cv2.resize(new_green,None,fx=0.75, fy=0.75))
    #cv2.waitKey(0)

    thresh, im_bw = cv2.threshold(new_green,180,255, 0)
    #cv2.imshow("white", cv2.resize(im_bw,None,fx=0.75, fy=0.75))
    #cv2.waitKey(0)

    kernel = np.ones((5,5),np.uint8)
    erode = cv2.dilate(im_bw,kernel,iterations = 2)

    erode = cv2.erode(erode,None,iterations = 1)
    #cv2.imshow("eroded", cv2.resize(erode,None,fx=0.75, fy=0.75))
    #cv2.waitKey(0)

    kernel = np.ones((45,45),np.uint8)
    close = cv2.morphologyEx(erode, cv2.MORPH_CLOSE, kernel)

    contours, hierarchy = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    minArea = 20 * 20
    # draw the contours with area bigger than a minimum and that is almost rectangular

    rects = []
    for cnt in contours:
        x,y,w,h = cv2.boundingRect(cnt)
        area = cv2.contourArea(cnt)
        if area > (w*h*.60) and area > minArea:
            #original = cv2.rectangle(img, (x,y),(x+w,y+h), (0,0,255), 3)
            bbox = (x,y,x+w,y+h)
            #cv2.circle(img, (int(x), int(y)), 9, (255,0,0), -1)
            rects.append(bbox)
            #cv2.circle(img, (int(x+w), int(y+h)), 9, (255,0,0), -1)
            cv2.circle(img, (int(x+(w/2)), int(y+(h/2) )   ), 9, (255,0,0), -1)
            #print("bbox: ",x,y,x+w,y+h)
            #counter = counter +1

                #rects = listOfbboxes
    #print("boundingBoxes: ", rects)
    rects = np.array(rects)
    objects = ct.update(rects)
	# loop over the tracked objects
    #if frameText != []:
    #    del frameText
    for (objectID, centroid) in objects.items():
        # draw both the ID of the object and the centroid of the
        # object on the output frame
        text = "{}".format(objectID+1)
        centroidText = cv2.putText(img, text, (centroid[0] - 10, centroid[1] - 10),
            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 2)
        #frameText = cv2.putText(img, text, (100, 100),
        #    cv2.FONT_HERSHEY_SIMPLEX, 2.5, (0, 255, 0), 2)
        lastNumberItem.append(int(text))
    #print(lastNumberItem)
    if len(lastNumberItem) != 0 :
    # choose to display only the first class
            cv2.putText(img, str(max(lastNumberItem)), (150,150) ,cv2.FONT_HERSHEY_SIMPLEX, 2, [255, 255,
            0], thickness=3)

    img = imutils.resize(img, width=800)
    cv2.imshow("Frame", img)
    #cv2.imwrite("Frame{}".format(counter)+".jpg",img)
    cv2.waitKey(1)

    key = cv2.waitKey(1) & 0xFF
    fps.update()
    counter = counter + 1
    # if the `q` key was pressed, break from the loop
    if key == ord("q"):
        break

    fps.update()

# eam.stop()
fps.stop()
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
cv2.destroyAllWindows()

fvs.stop()
#videoOut.release()


import numpy as np
import matplotlib.pyplot as plt
import scipy.special as ss
import sys

def dist(n):
    a = np.arange(n)
    a = np.where(a<np.float(n)/2.,a,np.abs(a-np.float(n)))**2
    array=np.zeros((n,n))
    for i in range(np.int(n/2)+1):
        y=np.sqrt(a+i**2)
        array[:,i]=y
        if i!=0:
            array[:,n-i]=y
    return np.fft.fftshift(array)

def cal_zp(diameter_m,finest_zone_width_m,energy_kev,defocal_distance_m,pixel_size_m,array_size,disp_flag=False):

    wavelength_m = (12.4 / energy_kev) * 1.e-10
    focal_length_m = diameter_m * finest_zone_width_m / wavelength_m

    n = 1024
    dr_m = diameter_m / 2 / n

    z_defocal_m = focal_length_m + defocal_distance_m

    array_size_new = np.int(array_size * 1.6)
    line_m = (np.arange(array_size_new) - array_size_new/2) * pixel_size_m
    k = 2 * np.pi / wavelength_m

    line = np.zeros(array_size_new).astype(complex)

    for ii in range(array_size_new):
        s = 0.
        for jj in range(n):
            r = jj * dr_m
            s += np.exp(1j * 0.5 * k * (1/z_defocal_m - 1/focal_length_m) * r**2) * \
              ss.j0(k * line_m[ii] * r / z_defocal_m) * r * dr_m
        line[ii] = s * np.exp(1j * 0.5 * k * line_m[ii]**2 / z_defocal_m)

    if disp_flag:
        plt.close('all')
        plt.figure()
        plt.subplot(221)
        plt.plot(np.abs(line))
        plt.title('Diameter: '+np.str(diameter_m/1e-6)+'um')
        plt.subplot(222)
        plt.plot(np.angle(line))
        plt.title('Outmost zone: '+np.str(finest_zone_width_m/1e-9)+'nm')

    zp_array = np.zeros((array_size,array_size)).astype(complex)
    dummy = dist(array_size)
    n_max = np.int(np.max(dummy))
    for i in range(n_max):
        tmp = line[np.int(array_size_new/2)+i]
        r_in = i
        r_out = i + 1
        index = np.where((dummy >= r_in) & (dummy < r_out))
        zp_array[index] = tmp

    if disp_flag:
        plt.subplot(223)
        plt.imshow(np.abs(zp_array))
        plt.title('Energy: '+np.str(energy_kev)+'keV')
        plt.subplot(224)
        plt.imshow(np.angle(zp_array))
        plt.title('Pixel size: '+np.str(pixel_size_m/1e-9)+'nm')
        plt.show()

    zp_array /= np.max(np.abs(zp_array))
    return zp_array

if __name__ == '__main__':
    diameter_m = np.float(sys.argv[1])
    finest_zone_width_m = np.float(sys.argv[2])
    energy_kev = np.float(sys.argv[3])
    defocal_distance_m = np.float(sys.argv[4])
    pixel_size_m = np.float(sys.argv[5])
    array_size = np.int(sys.argv[6])
    disp_flag = np.int(sys.argv[7])
    cal_zp(diameter_m,finest_zone_width_m,energy_kev,defocal_distance_m,pixel_size_m,array_size,disp_flag)


'''
Utilizando estrutura de repetição com FOR
'''

def main():
    for i in (0,1,2,3,4,5,6,7,8,9,10):
        print("Executando o valor de i: %d " % (i))

if __name__ == '__main__':
    main()


from odysseus import log
from odysseus.taskbox import *
import random

# Usage:  python3 example.py --id myid --mock-server

# Simulating backend value change:  echo '{"number":5}' > backend-mock-myid.json

def logic(state, backend_change):
    if backend_change:
        print(state)
        print("Backend changed to: number=" + str(state.get("number", None)))
    else:
        if random.random() > 0.5:
            state["number"] = state["number"] + 1
            print("number=" + str(state.get("number", None)))
    return state

def box_init():
    print("Init called")

options = {
    "init": box_init,
    "callback": logic,
    "run_interval": 0.3,
    "initial_state": {"number": 0},
    # "write_interval": 2
    # "mock_init":box_init
}

TaskBoxRunner(options).run()


from models.order import *
from datetime import datetime

now = datetime.now()

order1 = Order("Mar", now, 1, "MARgherita", "Olives", "Deep Pan")
order2 = Order("Colette", now, 2, "Hawaiian", "Cheese", "Romana")
order3 = Order("Keith", now, 5, "Pepperoni", "Sausage", "Stuffed Crust")
orders = [order1, order2, order3]


import asyncio
from dataclasses import fields
from datetime import datetime
import time

from discord import FFmpegPCMAudio

from discord import member, Embed
from discord.ext.commands import Cog

image = ['https://static-cdn.jtvnw.net/jtv_user_pictures/cfd5e66a-f247-4158-be16-5aa5068f13a0-profile_image-70x70.png'
         'https://static-cdn.jtvnw.net/jtv_user_pictures/d05c03ad-4e70-4734-9159-51fc1477d564-profile_image-70x70.png'
         'https://static-cdn.jtvnw.net/jtv_user_pictures/6b4441ff-a6bf-4609-bc1d-32cba5b51c61-profile_image-70x70.png']

class Info(Cog):
    def __init__(self, bot):
        self.bot = bot

from discord.ext import commands

client = commands.Bot(command_prefix='t?')

status = ['Tocando Musica', 'Run Turtle Run!!', 'Dormindo']

frasesproanbu = ['Deve ta dando o cu é a cara dele...','Resolvendo os bugs dele','Ta dormindo','Porque eu iria saber?','Tomara que tenham hackeado o codigo dele :D']

import discord
from discord.ext import tasks
import youtube_dl

from random import choice

youtube_dl.utils.bug_reports_message = lambda: ''

ytdl_format_options = {
    'format': 'bestaudio/best',
    'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s',
    'restrictfilenames': True,
    'noplaylist': True,
    'nocheckcertificate': True,
    'ignoreerrors': False,
    'logtostderr': False,
    'quiet': True,
    'no_warnings': True,
    'default_search': 'auto',
    'source_address': '0.0.0.0'  # bind to ipv4 since ipv6 addresses cause issues sometimes
}

ffmpeg_options = {
    'options': '-vn'
}

ytdl = youtube_dl.YoutubeDL(ytdl_format_options)

class YTDLSource(discord.PCMVolumeTransformer):
    def __init__(self, source, *, data, volume=0.5):
        super().__init__(source, volume)

        self.data = data

        self.title = data.get('title')
        self.url = data.get('url')

    @classmethod
    async def from_url(cls, url, *, loop=None, stream=False):
        loop = loop or asyncio.get_event_loop()
        data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream))

        if 'entries' in data:
            # take first item from a playlist
            data = data['entries'][0]

        filename = data['url'] if stream else ytdl.prepare_filename(data)
        return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)

#####INICIAR#####
@client.event
async def on_ready():
    change_status.start()
    print('Turtle Is Online!')

@client.event
async def on_member_join(member):
    channel = discord.utils.get(member.guild.channels, name='general')
    await channel.send(
        f'**Bem Vindo** {member.mention}! Pronto pra correr? Fale ?commands para mostrar minhas habilidades!!')

#######PING#######

@client.command(name='ping')
async def ping(ctx):
    await ctx.send(f'**BUM!** Latencia: {round(client.latency * 1000)}ms')

#######OLA#######

@client.command(name='ola')
async def ola(ctx):
    respostas = ['Oi seu gostoso(a)', 'Olha onde????', 'Olaa! Tudo bem com você?', 'To com sono',
                 'Oi Amigo! Tava com saudade']
    await ctx.send(choice(respostas))

#######RUNTURTLE#######

@client.command(name='run')
async def run(ctx):
    respostas = ['To Correeendo!!', 'RUN TURTLE RUNNN!!!', 'No.', 'Pisquei te passei o pau e tu nao viu']
    await ctx.send(choice(respostas))

#######CREDITS#######

@client.command(name='credits')
async def run(ctx):
    await ctx.send('Made By: **DuxX**')
    await ctx.send('Obrigado **Sr DuxX** por ter me trazido a vida')
    await ctx.send('**ANBU** Chupa meu CU! Voce sempre sera inferior a minha presença')

#######MUSICAS#######

@client.command(name='play')
async def play(ctx, url):
    if not ctx.message.author.voice:
        await ctx.send('Voce não esta em um canal de voz.')
        return

    else:
        channel = ctx.message.author.voice.channel

    await channel.connect()

    server = ctx.message.guild
    voice_channel = server.voice_client

    async with ctx.typing():
        if url == 'calaboca':
            player = await YTDLSource.from_url('https://www.youtube.com/watch?v=cMTrUCasbss', loop=client.loop)
        elif url == 'ola':
            player = await YTDLSource.from_url('https://www.youtube.com/watch?v=cMTrUCasbss', loop=client.loop)
        else:
            player = await YTDLSource.from_url(url, loop=client.loop)
        voice_channel.play(player, after=lambda e: print('Player error: %s' % e) if e else None)

    await ctx.send(f'**Tocando Agora:** {player.title}')

@client.command(name='stop')
async def stop(ctx):
    voice_client = ctx.message.guild.voice_client
    await voice_client.disconnect()

    server = ctx.message.guild
    voice_channel = server.voice_client
    voice_channel.stop()

#######STREAMERS#######

@client.command(name='streamers')
async def stremers(ctx):
    embed = discord.Embed(title='Stremer#1', color=discord.Colour.blue())
    embed.set_image(
        url='https://static-cdn.jtvnw.net/jtv_user_pictures/cfd5e66a-f247-4158-be16-5aa5068f13a0-profile_image-70x70.png')
    embed.add_field(name='ID:', value='@Dux')
    embed.add_field(name='URL:', value='https://www.twitch.tv/igdux')

    await ctx.send(embed=embed)

    embed = discord.Embed(title='Streamer#2', color=discord.Colour.blue())
    embed.set_image(
        url='https://static-cdn.jtvnw.net/jtv_user_pictures/6b4441ff-a6bf-4609-bc1d-32cba5b51c61-profile_image-70x70.png')
    embed.add_field(name='ID:', value='@F4')
    embed.add_field(name='URL:', value='https://www.twitch.tv/f4_zzz')

    await ctx.send(embed=embed)
    embed = discord.Embed(title='Streamer#3', color=discord.Colour.blue())
    embed.set_image(
        url='https://static-cdn.jtvnw.net/jtv_user_pictures/d05c03ad-4e70-4734-9159-51fc1477d564-profile_image-70x70.png')
    embed.add_field(name='ID:', value='@Héset')
    embed.add_field(name='URL:', value='https://www.twitch.tv/1heset')

    await ctx.send(embed=embed)
    embed = discord.Embed(title='Streamer#4', color=discord.Colour.blue())
    embed.set_image(
        url='https://static-cdn.jtvnw.net/jtv_user_pictures/216fb513-c711-4d1e-abd6-0503b9744c18-profile_image-70x70.png')
    embed.add_field(name='ID:', value='@Japoleca')
    embed.add_field(name='URL:', value='https://www.twitch.tv/japoleca')

    await ctx.send(embed=embed)

#######COMANDOS#######

@client.command(name='comandos')
async def comandos(ctx):
    embed = discord.Embed(title='Comandos', color=discord.Colour.blue())
    embed.add_field(name='**#1**:?ping', value='(Mostra Seu Ping!)')
    embed.add_field(name='**#2**:?play', value='(Da Play Na Sua Musica!)')
    embed.add_field(name='**#3**:?streamers', value='(Todos Os Streamers Do Servidor!)')
    embed.add_field(name='**#4**:?stop', value='(Para A Musica Atual!)')
    embed.add_field(name='**#5**:?ola', value='(Voce Fala Com O Turtle!)')
    embed.add_field(name='**#6**:?run', value='(Faz O Turtle Correr!)')
    embed.add_field(name='**#7**:?credits', value='(As Dedicações Do Meu DNA!)')
    embed.add_field(name='**#8**:?falaeai', value='(Eu Falo Eai No Voice!)')
    embed.add_field(name='**#9**:?xinganois', value='(Xingo Voces No Voice!)')

    await ctx.send(embed=embed)

#######MEMBROS#######

@client.command(name='membros')
async def membros(ctx):
    guild = member.guild
    await ctx.edit(name='---Quantidade De Membros--- **{}**'.format(guild.member_count))

@client.command(name="serverinfo")
async def serverinfo(ctx, statuses=None):
    embed = Embed(title="Informação Do Server",
                  colour=discord.Colour.blue(),
                  timestamp=datetime.utcnow())

    await ctx.send(embed=embed)

#######FALAS DO TURTLE#######

@client.command(name='falaeai')
async def falaeai(ctx):
    if (ctx.author.voice):
        channel = ctx.message.author.voice.channel
        voice = await channel.connect()
        source = FFmpegPCMAudio('eai.wav')
        player = voice.play(source)

        time.sleep(6)
        voice_client = ctx.message.guild.voice_client
        await voice_client.disconnect()

        server = ctx.message.guild
        voice_channel = server.voice_client
        voice_channel.stop()

@client.command(name='xinganois')
async def xinganois(ctx):
    if (ctx.author.voice):
        channel = ctx.message.author.voice.channel
        voice = await channel.connect()
        source = FFmpegPCMAudio('xingando.wav')
        player = voice.play(source)

        time.sleep(6)
        voice_client = ctx.message.guild.voice_client
        await voice_client.disconnect()

        server = ctx.message.guild
        voice_channel = server.voice_client
        voice_channel.stop()

@client.command(name='anbusheat')
async def anbusheat(ctx):
    if (ctx.author.voice):
        channel = ctx.message.author.voice.channel
        voice = await channel.connect()
        source = FFmpegPCMAudio('anbu1.wav')
        player = voice.play(source)

        time.sleep(6)
        voice_client = ctx.message.guild.voice_client
        await voice_client.disconnect()

        server = ctx.message.guild
        voice_channel = server.voice_client
        voice_channel.stop()

@client.command(name='anbusheat2')
async def anbusheat(ctx):
    if (ctx.author.voice):
        channel = ctx.message.author.voice.channel
        voice = await channel.connect()
        source = FFmpegPCMAudio('anbu2.wav')
        player = voice.play(source)

        time.sleep(6)
        voice_client = ctx.message.guild.voice_client
        await voice_client.disconnect()

        server = ctx.message.guild
        voice_channel = server.voice_client
        voice_channel.stop()

@client.command(name='turtle_cade_o_anbu')
async def turtle_cade_o_anbu(ctx):
    await ctx.send((choice(frasesproanbu)))

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

@Cog.listener()
async def on_ready(self):
    if not self.bot.ready:
        self.bot.cogs_ready.ready_up("info")

@tasks.loop(seconds=20)
async def change_status():
    await client.change_presence(activity=discord.Game(choice(status)))

def setup(bot):
    bot.add_cog(Info(bot))

client.run('')


nomre = int(input())

final_list = []
for _ in range(nomre):
    items = input().split()
    name = items[0]

    ali = 0
    for idx in range(1, len(items)):
        ali += int(items[idx])
    final_list.append([name, ali / (len(items) - 1)])

list_end = []
for item in final_list:
    name, avg = item
    if avg > 10:
        list_end.append(item)
print(list_end)


file = open("input")
halak_strings = file.readline().split(",")
print(halak_strings)
halak = []
for i in halak_strings:
    halak.append(int(i))
print(halak)
kov_halak = []
for i in range(1, 257):
    for hal in halak:
        if hal > 0:
            kov_halak.append(hal - 1)
        else:
            kov_halak.append(6)
            kov_halak.append(8)
    halak = kov_halak.copy()
    print(str(i) + " nap: ")
    kov_halak = []

print(len(halak))


from omegaconf import OmegaConf
from typing import Tuple, Union, List, Any

import clip
import torch
import torch.nn as nn
from torchvision import transforms as T
from PIL import Image, ImageDraw, ImageFont

from .dummycond import DummyCond
from ...utils.general import initialize_from_config

class ClipTextCond(DummyCond):
    def __init__(self, image_size: Union[Tuple[int, int], int],
                 clip_model: str, tokenizer: OmegaConf) -> None:
        super().__init__()
        self.image_size = image_size
        self.clip_model, _ = clip.load(clip_model, device=device)
        self.tokenizer = initialize_from_config(tokenizer)

    def encode_codes(self, text: torch.LongTensor) -> torch.FloatTensor:
        with torch.no_grad():
            text_features = model.encode_text(text)

        return text_features

    def to_img(self, texts: torch.LongTensor) -> torch.FloatTensor:
        W, H = self.image_size if isinstance(self.image_size, tuple) else (self.image_size, self.image_size)
        font = ImageFont.truetype("arial.ttf", 12)

        imgs = []
        for text in texts:
            text = self.tokenizer.decode(text)
            words = text.split()
            length = 0

            for idx, word in enumerate(words):
                if length > 27:
                    length = 0
                    word[idx-int(idx>0)] += '\n'

                length += len(word)

            img = Image.new("RGBA", (W, H), "white")
            draw = ImageDraw.Draw(img)

            w, h = draw.textsize(text, font)
            draw.text(((W-w)/2,(H-h)/2), text, font=font, fill="black", align="center")

            img = img.convert('RGB')
            img = T.ToTensor()(img)
            imgs.append(img)

        return torch.stack(imgs, dim=0)

class ClipImageCond(DummyCond):
    def __init__(self, clip_model: str) -> None:
        super().__init__()
        self.clip_model, _ = clip.load(clip_model, device=device)

    def encode_codes(self, image: torch.FloatTensor) -> torch.FloatTensor:
        with torch.no_grad():
            image_features = model.encode_image(image)

        return image_features

    def to_img(self, image: torch.FloatTensor) -> torch.FloatTensor:
        return image.clamp(0, 1)


import random
from typing import Dict, Tuple
from collections import OrderedDict

DEFAULT_RANGES: int = 1000000
MAXIMUM_RANGE_ENDPOINT: int = 1000000000

def prompt() -> int:
    """Ask the user for a number of range."""
    msg: str = "How many ranges to generate - (default={}) \n".format(
        str(DEFAULT_RANGES)
    )
    while True:
        try:
            return int(input(msg) or DEFAULT_RANGES)
        except ValueError:
            raise ValueError("I only accept decimal numbers")

def create_random_range() -> Tuple[int, int]:
    """Create a random range.

    (start, end) where start < end, 0 <= start, end <= MAXIMUM_RANGE_ENDPOINT
    """
    start = random.randrange(0, MAXIMUM_RANGE_ENDPOINT + 1)
    end = 0
    exit = False

    while exit is not True:
        end = random.randrange(0, MAXIMUM_RANGE_ENDPOINT + 1)
        if start < end:
            exit = True

    return start, end

def create_ranges(nb_ranges: int) -> Dict[int, int]:
    """Create a given number of ranges."""
    ranges: Dict[int, int] = {}

    print(
        "Generating {} ranges... (it can take a few seconds)".format(nb_ranges)
    )

    for n in range(nb_ranges):
        start, end = create_random_range()
        ranges[start] = end

    return ranges

def get_nb_enclosures(value: int, ranges: Dict[int, int]) -> int:
    """Get the number of enclosures for a value in a list of ranges.

    Example:
        We want to search for 54 in the below
        ranges = {23: 55, 70: 101, 10: 60, 31: 52, 53: 90, 95: 102}

        Steps:
        1. filtered_dict = {23: 55, 10: 60, 31: 52, 53: 90}
        2. ordered_filtered_dict = {10: 60, 23: 55, 31: 52, 53: 90}
        3. enclosures = [60, 55, 90]
        4. result = 3
    """

    # Remove all entries where key (aka start point of a range) > value
    filtered_dict = {
        k: v for k, v in filter(lambda t: t[0] <= value, ranges.items())
    }

    # Create a new dict ordered by key ascending
    ordered_filtered_dict = OrderedDict(sorted(filtered_dict.items()))

    # Create an array of the end points of ranges where value < dict val
    enclosures = [
        v
        for _, v in filter(
            lambda t: t[1] >= value, ordered_filtered_dict.items()
        )
    ]

    return len(enclosures)

"""Main program."""
if __name__ == "__main__":
    try:
        # 1. Ask for a number of range
        input_ranges = prompt()

        # 2. Create random ranges
        ranges = create_ranges(input_ranges)

        # 3. Generate random numbers and find enclosures
        while True:
            random_int = random.randint(0, MAXIMUM_RANGE_ENDPOINT)

            result = get_nb_enclosures(random_int, ranges)

            print("{} => Enclosed by {} range(s)".format(random_int, result))
    except KeyboardInterrupt:
        pass


from rest_framework.test import APITestCase,RequestsClient
from django.urls import reverse
from rest_framework import status
from users.models import CustomUser,CustomUserToken

class UserTestAPI(APITestCase):
    def setUp(self): #create user and token
        user1=CustomUser.objects.create(phone='09121112233')
        user1.username='amir shiri'
        user1.save()
        token=CustomUserToken.objects.create(user_id=1,deviceId='sample',deviceType=1,validToken='sample',token='sample')
    def test_post_getphone(self):
        url=reverse('get phone')
        data={'phone':'09303331122'}
        response=self.client.post(url,data) # create second user
        self.assertEqual(response.status_code,status.HTTP_201_CREATED) #201:user created
        self.assertEqual(CustomUser.objects.count(),2) # count should be 2
        self.assertEqual(CustomUser.objects.get(phone='09303331122').username,None) #username new user is none

    def test_post_signup(self):
        url=reverse('sign up')
        data={'phone':'09121112233', #prepare data
            'deviceId':'sample',
            'validToken':'sample',
            'deviceType':'1'}
        response=self.client.post(url,data) #create user token and signup
        self.assertEqual(response.status_code,200) #token is update or create
        print(CustomUserToken.objects.get(user_id=1).token) # show new token

    def test_put_updateprofile(self):
        self.client=RequestsClient() # set APIclient to request client(because set headers)
        data={'username':'amir amir','phone':'09121112233'} #set data
        headers={"userId":"1","token":"sample"} # set headers
        response=self.client.put('http://localhost:8000/user/api/updateprofile',data=data,headers=headers)
        self.assertEqual(response.status_code,status.HTTP_204_NO_CONTENT) #update done
        self.assertEqual(CustomUser.objects.get(pk=1).username,'amir amir') # check updated username
        t=CustomUserToken.objects.get(user_id=1)
        self.assertEqual(t.token,'sample') #check token

    def test_put_setNotify(self):
        self.client=RequestsClient()
        data={'notification_status':'true','phone':'09121112233'} #set data
        headers={'userId':'1','token':'sample'} #set headers
        self.client.head=headers
        response=self.client.put('http://localhost:8000/user/api/setNotificationStatus',data,headers=headers)
        self.assertEqual(response.status_code,status.HTTP_204_NO_CONTENT) #update done
        self.assertEqual(CustomUser.objects.get(pk=1).notification_status,True) #check new notification status

    def test_logout(self):
        self.client=RequestsClient()
        headers={'userId':'1','token':'sample'}
        response=self.client.get('http://localhost:8000/user/api/logout',headers=headers)
        self.assertEqual(response.status_code,status.HTTP_200_OK) #get the record
        response=self.client.put('http://localhost:8000/user/api/logout',headers=headers)
        self.assertEqual(response.status_code,status.HTTP_200_OK) #update(log out) Done
        self.assertEqual(CustomUserToken.objects.get(pk=1).token,'None') # check updated token


input_str = input()
digits_str, letters_str, take_list, skip_list = "", "", [], []
hidden_message = ""
total_chars_checked = 0

#Create two strings(we can do the same with lists) - 1st - for the digits and 2nd - for all other chars
for i in range(len(input_str)):
    if input_str[i].isdigit():
        digits_str += input_str[i]
    else:
        letters_str += input_str[i]

#Divide the digits string into 2 new lists - take_list and skip_list
for i in range(len(digits_str)):
    if i % 2 == 0:
        take_list.append(int(digits_str[i]))
    else:
        skip_list.append(int(digits_str[i]))

#Until we have any chars to add in the secret message "range(len(take_list))" we add chars and count the checked characters -> taken + skipped
for i in range(len(take_list)):
    hidden_message += letters_str[total_chars_checked : total_chars_checked + take_list[i]]
    total_chars_checked += take_list[i] + skip_list[i]

print(hidden_message)

Python-Fundamentals/Lists Advanced - More Exercises/02. Take-Skip Rope.py


from django.urls import path
from listaPrecio.views import listaPrecio,listap_crear,editar

urlpatterns = [
  path('',listaPrecio,name="listaPrecio"),
  path('crear/',listap_crear,name="listap-crear"),
  path('editar/<int:id>', editar, name="editar-LP"),
]


from classes import Cliente

cliente1 = Cliente('Luiz', 32)
cliente1.inserirEndereco('Belo Horizonte', 'MG')
print(cliente1.nome)
cliente1.listaEnderecos()
del cliente1
print()

cliente2 = Cliente('Maria', 42)
cliente2.inserirEndereco('Salvador', 'BA')
cliente2.inserirEndereco('Porto Alegre', 'RS')
print(cliente2.nome)
cliente2.listaEnderecos()
del cliente2
print()

cliente3 = Cliente('Otavio', 55)
cliente3.inserirEndereco('Brasilia', 'DF')
print(cliente3.nome)
cliente3.listaEnderecos()
del cliente3
print()


import httplib
from stat_sender.common import logger_helper
from stat_sender.endpoint.endpoint import Endpoint

class HttpEndpoint(Endpoint):

    # spec (None -> HttpConnection), str, Logger -> HttpEndpoint
    def __init__(self, connection_factory, path, logger):
        self._connection_factory = connection_factory
        self._path = path
        self._logger = logger

    # spec: str -> bool
    def send(self, data):
        self._logger.info('send(data) enter')
        conn = self._connection_factory()
        try:
            headers = {"Content-Type": "application/xml", "Accept": "text/plain"}
            conn.request('POST', self._path, data, headers)
            response = conn.getresponse()
            result = response.status == httplib.OK
            str_result = logger_helper.bool_result_to_str(result)
            self._logger.info('send(data) exit with result {0:s}'.format(str_result))
            return result
        except BaseException:
            self._logger.exception('exception in send(data)')
            return False
        finally:
            conn.close()

__author__ = 'andrey.ushakov'


import numpy as np
import cv2
import math

filename = "3.jpg"
image = cv2.imread(filename)
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

row = len(img)
column = len(img[0])

E = np.zeros((row, column))
F = np.zeros((row, column))
G = np.zeros((row, column))
e = np.zeros((row, column))
f = np.zeros((row, column))
g = np.zeros((row, column))
N = np.zeros((row, column))
H = np.zeros((row, column))
K1 = np.zeros((row, column))
K2 = np.zeros((row, column))
K = np.zeros((row, column))

IS = cv2.GaussianBlur(img,(3,3),0)
#first division
X = cv2.Sobel(IS, cv2.CV_64F, 1, 0)
Y = cv2.Sobel(IS, cv2.CV_64F, 0, 1)
XY = cv2.Laplacian(IS, cv2.CV_64F)
#second division
X2 = cv2.Sobel(X, cv2.CV_64F, 1, 0)
Y2 = cv2.Sobel(Y, cv2.CV_64F, 0, 1)
XY2 = cv2.Laplacian(XY, cv2.CV_64F)

for x in range(row):
    for y in range(column):
        E[x,y] = 1+X[x,y]**2

for x in range(row):
    for y in range(column):
        G[x,y] = 1+Y[x,y]**2

for x in range(row):
    for y in range(column):
        F[x,y] = Y[x,y]*X[x,y]

for x in range(row):
    for y in range(column):
        N[x,y] = E[x,y]+G[x,y]

for x in range(row):
    for y in range(column):
        N[x,y] = math.sqrt(N[x,y])

for x in range(row):
    for y in range(column):
        e[x,y] = X2[x,y]/N[x,y]

for x in range(row):
    for y in range(column):
        f[x,y] = Y2[x,y]/N[x,y]

for x in range(row):
    for y in range(column):
        g[x,y] = XY2[x,y]/N[x,y]

for x in range(row):
    for y in range(column):
        H[x,y] = -(e[x,y]*G[x,y]-2*f[x,y]*F[x,y]+g[x,y]*E[x,y])

for x in range(row):
    for y in range(column):
        K1[x,y] = (e[x,y]*g[x,y]-f[x,y]**2)
for x in range(row):
    for y in range(column):
        K2[x,y] = (E[x,y]*G[x,y]-F[x,y]**2)
for x in range(row):
    for y in range(column):
        K[x,y] = K1[x,y]/K2[x,y]

for x in range(row):
    for y in range(column):
        if H[x,y] == 0 and K[x,y] == 0:
            image [x,y] = [0,0,0]
        elif H[x,y] == 0 and K[x,y] > 0:
            image [x,y] = [255,255,0]
        elif H[x,y] == 0 and K[x,y] < 0:
            image [x,y] = [0,255,0]
        elif H[x,y] > 0 and K[x,y] > 0:
            image [x,y] = [255,0,255]
        elif H[x,y] > 0 and K[x,y] < 0:
            image [x,y] = [255,0,0]
        elif H[x,y] < 0:
            image [x,y] = [0,0,255]

cv2.imshow("img",img)
cv2.imshow("image",image)

cv2.waitKey(0)
cv2.destroyAllWindows()


# Fireplace Analysis
# Script: 002_preprocess_data.py
# Author: Becca Kuss
# Date 2021-02-18

# A - Clean Up Log Data ===========================================================

# For fires that span more than one day, add as two entries
is_spanning = log_data['fire_end_hour'] < log_data['fire_start_hour']

# Create two new rows to replace the single row
new_entry_early = log_data[is_spanning]
new_entry_late = log_data[is_spanning]

# For the early row, set the end hour to midnight
new_entry_early['fire_end_hour'] = np.array([23] * new_entry_early.shape[0])
new_entry_early['fire_end_min'] = np.array([55] * new_entry_early.shape[0])

# For the late row, set the start hour to midnight, and add a day
new_entry_late['fire_start_hour'] = np.array([0] * new_entry_late.shape[0])
new_entry_late['fire_start_min'] = np.array([0] * new_entry_late.shape[0])
new_entry_late['date'] = new_entry_late['date'] + pd.DateOffset(days=1)

# Concatenate the data into the final log data
log_data_list = [log_data[-is_spanning]] + [new_entry_early] + [new_entry_late]
log_data = pd.concat(log_data_list, axis=0, ignore_index=True)

# B - Join Log Data and Ecobee Data ================================================


import base64

from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage
from django.db.models import Q
from rest_framework import status
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from .serializers import *

# Create your views here.

#### Appointments

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def getAppointments(request, professor_id):
    professor = User.objects.get(id=professor_id)
    appointments = Appointment.objects.filter(student=request.user).filter(professor=professor)
    sr = AppointmentSerializer(appointments, many=True)
    return Response(sr.data)

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getAllUserAppointments(request):
    appointments = Appointment.objects.filter(student=request.user).order_by('-time')
    sr = AppointmentSerializer(appointments, many=True)
    return Response(sr.data)

@api_view(['GET'])
def getAppointment(request, id):
    appointment = Appointment.objects.get(id=id)
    sr = AppointmentSerializer(appointment, many=False)
    return Response(sr.data)

@api_view(['GET'])
def getAppointmentForUser(request):
    appointments = Appointment.objects.filter(student=request.user).order_by('-id')
    sr = AppointmentSerializer(appointments, many=True)
    return Response(sr.data)

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def addAppointment(request):
    appointment = Appointment.objects.create(
        title=request.data['title'],
        description=request.data['description'],
        professor_id=request.data['professor_id'],
        time=0,
        student=request.user
    )
    """
    context = {
        'subject': appointment.title,
        'content': f
    #                روز بخیر  {appointment.professor.name} \n
     #               دانشجو {appointment.student.name} درخواست قرار ملاقات  دارد.
      #              لطفا در اپلیکیشن برسی کنید.

    }
    message = get_template('layouts/mail/email_layout.html').render(context)
    msg = EmailMessage(
        appointment.title,
        message,
        'notification@gethermes.ir',
        [appointment.professor.email],
    )
    msg.content_subtype = "html"  # Main content is now text/html
    msg.send()"""

    return Response(AppointmentSerializer(appointment).data, status=status.HTTP_200_OK)

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def deleteAppointment(request, id):
    appointment = Appointment.objects.get(id=id)
    appointment.delete()
    return Response(status=status.HTTP_200_OK)

#### professor profile

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def updateProfile(request):
    user = request.user
    user.stud_code = request.data['stud_code']
    user.id_code = request.data['id_code']
    if request.data['email'] != '' and len(request.data['email']) > 0:
        user.email = request.data['email']
    user.bio = request.data['bio'][:200]
    user.phone = request.data['phone']
    user.name = request.data['name']
    user.family = request.data['family']
    user.save()
    return Response(UserSerializerSelf(user, many=False).data, status=status.HTTP_200_OK)

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def updatePassword(request):
    success = request.user.check_password(request.data['previous_pass'])
    if not success:
        return Response(status=status.HTTP_403_FORBIDDEN)

    request.user.set_password(request.data['new_pass'])
    return Response(status=status.HTTP_202_ACCEPTED)

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def updateAvatar(request):
    cover_data = request.data['avatar']

    format, imgstr = cover_data.split(';base64,')
    ext = format.split('/')[-1]
    data = ContentFile(base64.b64decode(imgstr))

    file_name = f'{time.time()}' + ext
    request.user.avatar.save(file_name, data, save=True)  # image is User's model field

    return Response(UserSerializerSelf(request.user, many=False).data, status=status.HTTP_200_OK)

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def updateAvatarFile(request):
    print(request.FILES)

    myfile = request.data.get('image')

    fs = FileSystemStorage()
    filename = fs.save(myfile.name, myfile)
    uploaded_file_url = fs.url(filename)
    request.user.avatar = uploaded_file_url

    return Response(UserSerializerSelf(request.user, many=False).data, status=status.HTTP_200_OK)

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getProfessorProfile(request, id):
    professor = User.objects.get(id=id)
    if professor.mode != User.MODES[2][0]:
        return Response(status=status.HTTP_409_CONFLICT)
    appointments = Appointment.objects.filter(student=request.user).filter(professor=professor).order_by('-id')
    appointments_sr = AppointmentSerializer(appointments, many=True)
    professor_sr = UserSerializerProfile(professor, many=False)
    return Response({
        'professor': professor_sr.data,
        'appointments': appointments_sr.data
    })

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def getProfessors(request):
    professors = User.objects.filter(mode=2)
    return Response(
        UserSerializerListItem(professors, many=True).data
    )

### Main page

@api_view(['GET'])
def mainPage(request):
    main_page = Setting.objects.get(key=settings.MAIN_PAGE_PROFS_DISPLAY_LOCATION)
    location = Location.objects.get(id=main_page.value)
    profs = User.objects.filter(mode=User.MODES[2][0])
    sr = UserSerializerListItem(profs, many=True)
    return Response(
        {
            'profs': sr.data
        }
    )

#### posts

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getPostDetails(request, id):
    post = Post.objects.get(id=id)
    return Response(
        PostSerializerDetailed(post, many=False).data, status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def allPosts(request):
    post = Post.objects.order_by('-id')
    return Response(
        PostSerializerDetailed(post, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def allPostsFilterByGroup(request):
    groups = request.POST['groups'].split(',')
    expertise = request.POST['expertise'].split(',')
    professors = request.POST['professors'].split(',')
    print(request.POST)
    print(groups)
    print(expertise)
    if groups == ['']:
        groups = []

    if expertise == ['']:
        print(expertise)
        expertise = []

    if professors == ['']:
        professors = []

    print((professors))
    posts = Post.objects.filter(Q(user__group__in=groups) | Q(user__expertise__in=expertise) | Q(user__in=professors))
    print(len(posts))
    # posts = Post.objects.all()

    return Response(
        PostSerializerDetailed(posts, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def allProfessorsFiltered(request):
    print(request.data['expertise'])
    groups = list(map(lambda x: x['id'], request.data['groups']))
    expertise = list(map(lambda x: x['id'], request.data['expertise']))
    locations = list(map(lambda x: x['id'], request.data['locations']))
    print(request.POST)
    print(groups)
    print(locations)
    if groups == ['']:
        groups = []

    if expertise == ['']:
        print(expertise)
        expertise = []

    if locations == ['']:
        locations = []

    profs = User.objects.filter(Q(group__in=groups) | Q(expertise__in=expertise) | Q(location__in=locations)).filter(
        mode=2)
    posts = Post.objects.all()

    return Response(
        UserSerializerListItem(profs, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def allAnnouncesFiltered(request):
    skills = request.POST['skills'].split(',')
    expertise = request.POST['expertise'].split(',')
    professors = request.POST['professors'].split(',')
    print(request.POST)
    if skills == ['']:
        skills = []

    if expertise == ['']:
        expertise = []

    if professors == ['']:
        professors = []

    announces = Announce.objects.filter(
        Q(user__expertise__in=expertise) | Q(skills__in=skills) | Q(user__in=professors))
    # posts = Post.objects.all()

    return Response(
        AnnounceSerializerList(announces, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def allAnnounces(request):
    announce = Announce.objects.order_by('-id')
    return Response(
        AnnounceSerializerList(announce, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def getAnnounceDetails(request, id):
    announce = Announce.objects.get(id=id)
    return Response(
        AnnounceSerializerList(announce, many=False).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def addAnnounceRequest(request):
    announce, created = AnnounceRequest.objects.get_or_create(
        student=request.user,
        announce_id=request.data['announce_id'],
        description=request.data['description']
    )
    if created:
        return Response(
            status=status.HTTP_201_CREATED
        )
    else:
        return Response(
            status=status.HTTP_200_OK
        )

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def getMyAnnounceRequests(request):
    reqs = AnnounceRequest.objects.filter(student=request.user)

    return Response(AnnounceRequestSerializer(reqs, many=True).data,
                    status=status.HTTP_200_OK
                    )

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def deleteAnnounceRequest(request, id):
    announce = AnnounceRequest.objects.get(id=id)
    announce.delete()
    return Response(
        status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def getPostFilters(request):
    groups = ProfessorGroup.objects.all()
    expertise = Expertise.objects.all()
    professors = User.objects.filter(mode=2)
    return Response(
        {
            'groups':
                GroupSerializer(groups, many=True).data,
            'expertise': ExpertiseSerializer(expertise, many=True).data,
            'professors': UserSerializerListItem(professors, many=True).data
        }
    )

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def getProfessorFilters(request):
    groups = ProfessorGroup.objects.all()
    expertise = Expertise.objects.all()
    locations = Location.objects.all()
    return Response(
        {
            'groups':
                GroupSerializer(groups, many=True).data,
            'expertise': ExpertiseSerializer(expertise, many=True).data,
            'locations': LocationSerializer(locations, many=True).data
        }
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def getAnnounceFilters(request):
    skills = Skill.objects.all()
    expertise = Expertise.objects.all()
    professors = User.objects.filter(mode=2)
    return Response(
        {
            'skills':
                SkillSerializer(skills, many=True).data,
            'expertise': ExpertiseSerializer(expertise, many=True).data,
            'professors': UserSerializerListItem(professors, many=True).data
        }
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def filterPostsByText(request):
    search_term = request.POST['search_term']
    posts = Post.objects.filter(Q(title__contains=search_term) | Q(body__contains=search_term))
    return Response(
        PostSerializerDetailed(posts, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def filterProfessorsByText(request):
    search_term = request.POST['search_term']
    profs = User.objects.filter(name__contains=search_term).filter(mode=2)
    return Response(
        UserSerializerListItem(profs, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
def fullTextSearchProfessor(request):
    search_term = request.data['search_term']
    profs = User.objects.filter(
        Q(name__contains=search_term) | Q(family__contains=search_term) | Q(expertise__name__contains=search_term) | Q(
            location__name__contains=search_term)).filter(mode=2)
    return Response(
        UserSerializerListItem(profs, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def filterAnnouncesByText(request):
    search_term = request.POST['search_term']
    announces = Announce.objects.filter(Q(title__contains=search_term) | Q(body__contains=search_term))
    return Response(
        AnnounceSerializerList(announces, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def getCircles(request):
    circles = Circle.objects.all()
    return Response(
        CircleSerializer(circles, many=True).data, status=status.HTTP_200_OK
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def addCircleToProfile(request):
    print(request.POST)
    user = User.objects.get(id=request.user.id)
    circle = Circle.objects.get(id=request.POST['circle_id'])
    if circle not in user.circles.all():
        circle.user_set.add(user)
    else:
        pass
    return Response(
        status=status.HTTP_200_OK
    )

@api_view(['POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def deleteMyCircle(request):
    print(request.POST)
    user = User.objects.get(id=request.user.id)
    circle = Circle.objects.get(id=request.POST['circle_id'])
    user.circles.remove(circle)
    return Response(
        status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def getMyCircles(request):
    user = User.objects.get(id=request.user.id)
    return Response(
        CircleSerializer(
            user.circles.all(), many=True
        ).data, status=status.HTTP_200_OK
    )

@api_view(['GET'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
def userData(request):
    user = User.objects.get(id=request.user.id)
    sr = UserSerializerSelf(user)
    return Response(
        sr.data, status=status.HTTP_200_OK
    )


import csv, os, copy, subprocess

PMi_MSConvert_exe_location = r"C:\Users\sam\dev\builds\qt_common-build\bin\Release"
cmd_for_comparison = [PMi_MSConvert_exe_location + r"\PMi-MSConvert.exe", "--command", "6"]

def compare_one_pair(file, file_partner, args, n_value):
	tmp_cmd = copy.deepcopy(cmd_for_comparison)
	tmp_cmd.extend([os.path.abspath(file), os.path.abspath(file_partner), "-o", os.path.abspath(args.output_path_for_comparisons + "\\" + (n_value if n_value != '7' else "pwiz_pico"))])
	print(tmp_cmd)
	process = subprocess.Popen(tmp_cmd, cwd=PMi_MSConvert_exe_location)
	process.wait()

def find_matching_file(file, file_list, args, n_value):
	for file_partner in file_list:
		if n_value == '7':
			if "pico" in file_partner:
				if file[:file.index("pwiz")] == file_partner[:file_partner.index("pico")]:
					return file_partner
		else:
			if file[len(args.first_prefix):] == file_partner[len(args.second_prefix):] and file != file_partner:
				return file_partner

def compare_files(args, n_value):
	true_output_path = args.output_path_for_comparisons + "\\" + (n_value if n_value != '7' else "pwiz_pico")
	true_byspec_path = args.output_path_for_byspecs + "\\" + (n_value if n_value != '7' else "pwiz_pico")
	if not os.path.exists(true_output_path):
		os.makedirs(true_output_path)
	file_list = os.listdir(true_byspec_path)
	for file in file_list:
		if n_value == '7':
			if "pwiz" in file:
				file_partner = find_matching_file(file, file_list, args, n_value)
				compare_one_pair(true_byspec_path + "\\" + file,
					true_byspec_path + "\\" + file_partner, args, n_value)
		else:
			if file.startswith(args.first_prefix):
				file_partner = find_matching_file(file, file_list, args, n_value)
				compare_one_pair(true_byspec_path + "\\" + file,
					true_byspec_path + "\\" + file_partner, args, n_value)

def print_greatest_diff_in_files(args, n_value):
	true_output_path = args.output_path_for_comparisons + "\\" + (n_value if n_value != '7' else "pwiz_pico")
	file_list = os.listdir(true_output_path)
	with open(true_output_path + "\\file_level_summary.csv", 'w', newline='') as csvfile:
		writer = csv.writer(csvfile)
		if n_value == "2" or n_value == "6":
			writer.writerow(["filename:", "native id of scan with biggest y-diff", "x/ycoordinate of greatest diff", "difference in x at point", "difference in y at point"])
		else:
			writer.writerow(["filename:", "native id of scan with biggest x-diff", "x/ycoordinate of greatest diff", "difference in x at point", "difference in y at point"])
		for file in file_list:
			if file.startswith("XY_SUMMARY"):
				with open(true_output_path + "\\" + file) as f:
					reader = csv.reader(f)
					for row, line_contents in enumerate(reader):
						if row == 2:
							writer.writerow([file,
								line_contents[0] if line_contents[0] else "NULL",
								line_contents[1],
								line_contents[2],
								line_contents[3]])
							break
		writer.writerow([""])
		writer.writerow(["Meta-data differences:"])
		for file in file_list:
			if file.startswith("META_DATA_SUMMARY"):
				with open(true_output_path + "\\" + file) as f:
					reader = csv.reader(f)
					writer.writerow([file + ":"])
					for row, line_contents in enumerate(reader):
						if row == 0:
							continue
						if (line_contents):
							writer.writerow(["",
							line_contents[0] if line_contents[0] else "NULL",
							line_contents[1] if line_contents[1] else "NULL",
							line_contents[2] if line_contents[2] else "NULL"])
						if row == 9:
							break


n=int(input())
arr=list(map(int,input().split()))
arr.reverse()
arr=list(set(arr))
print(len(arr))
for i in range(len(arr)):
    if(i==len(arr)-1):
        print(i)
    else:
        print(i,'',end='')


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        def extractList(node, arr):
            if node:
                arr.append(node)
                extractList(node.next, arr)
        listA = []
        listB = []
        extractList(headA, listA)
        extractList(headB, listB)
        if listA[-1] != listB[-1]:
            return None
        cap = min(len(listA), len(listB))
        for i in range(1, cap + 1):
            if listA[-i] != listB[-i]:
                return listA[-i + 1]
        return listA[-cap]