#!/usr/bin/env python3
#
# File: tidal_perturbation_in_circular_binary.py
# Author: Timothy Van Reeth <timothy.vanreeth@kuleuven.be>
# License: GPL-3+
# Description: Calculating the observed flux variations of a tidally
#              distorted g-mode pulsation in a circular, synchronised
#              binary system

import os
import sys
import glob
import yaml
import numpy as np
import subprocess as sp
import astropy.units as au

from progress.bar import Bar
from binary import circular_binary
from pulsations import pmode_pulsation

def distort_pulsation(star, orb_phase=0., distortion_factor=1.):
    """
        Routine to scale the g-mode visibility as a function of the location on
        the stellar surface

        Parameters:
            star:               stellar_model object
                                the star in which the pulsation is distorted
            orb_phase:          float; optional
                                current phase of the orbital cycle
                                (default = 0.)
            distortion_factor:  float; optional
                                the scaling factor of the mode visibility
                                across the stellar surface (default = 1)

        Returns:
            puls_scaling:       numpy array

    """

    basefun = 0.5 * (3.*(np.sin(star.theta)*np.cos(star.phi - 2.*np.pi*orb_phase))**2. - 1.)
    puls_scaling = ( 2. * np.ones(star.theta.shape) / ( distortion_factor + 1. ) ) + ( (basefun - np.nanmin(basefun)) / (np.nanmax(basefun) - np.nanmin(basefun)) * 2. * ( (distortion_factor - 1.) / (distortion_factor + 1.) ) )

    return puls_scaling

def calculate_flux(binary, pulsation, distortion_factor=1., puls_phase=0., orb_phase=0.):
    """
        Calculate the observed flux of a binary star with a perturbed g-mode pulsation at a
        given pulsation and orbital phase, and indicate if the data point was simulated
        during an eclipse.

        Parameters:
            binary:            circular_binary object
                               the studied circular, synchronised binary system
            pulsation:         gmode_pulsation object
                               the g-mode pulsation that will be perturbed and evaluated
            distortion_factor: float; optional
                               the scaling factor of the mode visibility
                                across the stellar surface (default = 1)
            puls_phase:         float; optional
                                current phase of the pulsation cycle (in the inertial frame)
                                (default = 0.)
            orb_phase:          float; optional
                                current phase of the orbital cycle
                                (default = 0.)

        Returns:
            bin_iflux:          float
                                the simulated flux caused by (solely) the binarity
            tot_iflux:          float
                                the total simulated flux at the provided pulsational and
                                orbital phases
            puls_iflux:         float
                                the simulated flux caused by (solely) the distorted pulsation
            ecl_iflag:          int
                                flag indicating if the calculated data point occurs during an
                                eclipse
    """

    ecl_maps = binary.eclipse_masks(orb_phase)
    primary_vissurf_bool = binary.primary.theta_incl < np.pi/2.
    secondary_vissurf_bool = binary.secondary.theta_incl < np.pi/2.

    primary_mask = np.array(ecl_maps[0] & primary_vissurf_bool, dtype=float)
    secondary_mask = np.array(ecl_maps[1] & secondary_vissurf_bool, dtype=float)

    primary_vissurf = np.array(primary_vissurf_bool, dtype=float)
    secondary_vissurf = np.array(secondary_vissurf_bool, dtype=float)

    if(binary.primary.pulsating):
        norm_puls = calculate_normalised_pulsations(binary.primary, pulsation, puls_phase)
        # puls_scaling = distort_pulsation(binary.primary, orb_phase=orb_phase, distortion_factor=distortion_factor)
        puls_scaling = 1.
        primary_puls = 10.**(-0.0004 * pulsation.amplitude * norm_puls * puls_scaling)
        secondary_puls = np.ones(binary.secondary.theta.shape)
    else:
        norm_puls = calculate_normalised_pulsations(binary.secondary, pulsation, puls_phase)
        # puls_scaling = distort_pulsation(binary.secondary, orb_phase=orb_phase, distortion_factor=distortion_factor)
        puls_scaling = 1.
        secondary_puls = 10.**(-0.0004 * pulsation.amplitude * norm_puls * puls_scaling)
        primary_puls = np.ones(binary.primary.theta.shape)

    primary_totflux   = np.nansum(2. * np.cos(binary.primary.theta_incl)   * binary.primary.cell_weight   * binary.primary.limb_darkening()   * primary_puls   * primary_mask)
    secondary_totflux = np.nansum(2. * np.cos(binary.secondary.theta_incl) * binary.secondary.cell_weight * binary.secondary.limb_darkening() * secondary_puls * secondary_mask)
    primary_binflux   = np.nansum(2. * np.cos(binary.primary.theta_incl)   * binary.primary.cell_weight   * binary.primary.limb_darkening()   * primary_mask)
    secondary_binflux = np.nansum(2. * np.cos(binary.secondary.theta_incl) * binary.secondary.cell_weight * binary.secondary.limb_darkening() * secondary_mask)
    primary_refflux   = np.nansum(2. * np.cos(binary.primary.theta_incl)   * binary.primary.cell_weight   * binary.primary.limb_darkening()   * primary_vissurf)
    secondary_refflux = np.nansum(2. * np.cos(binary.secondary.theta_incl) * binary.secondary.cell_weight * binary.secondary.limb_darkening() * secondary_vissurf)

    tot_iflux = -2500.*np.log10( (binary.light_contribution1*primary_totflux/primary_refflux) + (binary.light_contribution2*secondary_totflux/secondary_refflux))
    bin_iflux = -2500.*np.log10( (binary.light_contribution1*primary_binflux/primary_refflux) + (binary.light_contribution2*secondary_binflux/secondary_refflux))
    puls_iflux = tot_iflux - bin_iflux

    if(ecl_maps[0].all() & ecl_maps[1].all()):
        ecl_iflag = 0
    else:
        ecl_iflag = 1

    return bin_iflux, tot_iflux, puls_iflux, ecl_iflag

def calculate_normalised_pulsations(star, pulsation, puls_phase):
    if pulsation.mode_type == 'p':
        return calculate_normalised_pmode_pulsations(star, pulsation, puls_phase)
    else:
        print('g modes are currently unsupported')
        sys.exit()

def calculate_normalised_pmode_pulsations(star, pulsation, puls_phase):
    """
        Converting the geomety of the calculated g-mode pulsation to temperature
        variations, Lagrangian displacements and the associated velocity field

        Parameters:
            star:           stellar_model object
                            the pulsating star
            pulsation:      gmode_pulsation object
                            the simulated g-mode pulsation
            puls_phase:     float
                            the current phase of the studied pulsation (as seen
                            by the observer)

        Returns:
            norm_puls:      numpy array
                            normalised pulsation variability of the g-mode at the
                            stellar surface at the phase puls_phase
    """

    if(pulsation.m < 0.):
        sign = 1.
    else:
        sign = -1.

    norm_puls = (pulsation.Lr * np.cos(pulsation.m*star.phi + 2.*np.pi*sign*puls_phase)) / np.nanmax(pulsation.Lr * np.cos(pulsation.m*star.phi + 2.*np.pi*sign*puls_phase))

    return norm_puls

def read_inlist(inlist_filename='./inlist.yaml'):
    """
        Read in the required variables to calculate r-mode visibilities,
        following the methodology from Saio et al. (2018).

        Parameters:
            inlist_filename:      string; optional (default: ./inlist.dat)
                                  the path to the inlist

        Returns:
            maindir:              string
                                  main work directory
            binary:               circular binary object
                                  the circular synchronised binary system that will be simulated
            pulsation:            gmode_pulsation object
                                  the g-mode pulsation that will be simulated
            distortion_factor:    float
                                  distortion factor of the simulated pulsation
            N_forb_cycles:        int
                                  number of orbital cycles to be simulated
            Nsample_per_cycle:    int
                                  number of simulated data points per orbital cycle
    """

    with open(inlist_filename,'r') as f:
        cfg = yaml.load(f, Loader=yaml.Loader)
    f.close()

    # collecting the given parameter values within the appropriate objects
    binary = circular_binary(cfg)

    if cfg['pulsation']['mode_type'] == 'p':
        pulsation = pmode_pulsation(cfg, binary.freq_orb)
    elif cfg['pulsation']['mode_type'] == 'g':
        print('g modes are currently not supported')
        sys.exit()
    else:
        print('Mode type {} not recognised. Exiting.'.format(cfg['pulsation']['mode_type']))
        sys.exit()

    if(cfg['pulsation']['pulsating_star'] == 'primary'):
        binary.primary.pulsating = True
        pulsation.calculate_puls_geometry(binary.primary)
    elif(cfg['pulsation']['pulsating_star'] == 'secondary'):
        binary.secondary.pulsating = True
        pulsation.calculate_puls_geometry(binary.secondary)

    return cfg['general']['main_dir'], binary, pulsation, \
           cfg['pulsation']['distortion_factor'], \
           cfg['simulation']['N_forb_cycles'], \
           cfg['simulation']['Nsample_per_cycle']

def save_results(result_filename, time, orb_phases, puls_phases, total_flux, binary_flux, pulsation_flux, eclipse_flags):
    """
        Saving the calculated visibilities of the distorted g-mode pulsations

        Parameters:
            result_filename:    string
                                absolute path to the results output filename
            time:               astropy quantity array
                                the time stamps of the simulate data points
            orb_phases:         numpy array
                                orbital phases corresponding to the different time stamps
            puls_phases:        numpy array
                                pulsation phases at the different time stamps
            total_flux:         numpy array
                                the total observed flux variations at the different time stamps (unit: mmag)
            binary_flux:        numpy array
                                the flux variations from the binary motion at the different time stamps (unit: mmag)
            pulsation_flux:     numpy array
                                the flux variations from the pulsations at the different time stamps (unit: mmag)
            eclipse_flags:      numpy array of integers
                                flags indicating if the data point was taken during an eclipse (yes = 1; no = 0)

    """

    file = open(result_filename, 'w')

    headline = ' '*16 + 'time' + ' '*11 + 'orb_phase' + ' '*10 + 'puls_phase' + ' '*10 + 'total_flux' + ' '*14 + 'binary' + ' '*11 + 'pulsation' + ' '*13 + 'eclipse'
    file.write(f'{headline}\n')

    for itime, iorbphase, ipulsphase, iflux, ibin, ipuls, iflag in zip(time.to(au.d).value, orb_phases, puls_phases, total_flux, binary_flux, pulsation_flux, eclipse_flags):
        data = f'  {itime:18e}  {iorbphase:18e}  {ipulsphase:18e}  {iflux:18e}  {ibin:18e}  {ipuls:18e}                   {iflag}\n'
        file.write(data)
    file.close()

    return

if __name__ == "__main__":

    # Reading the input parameters / variables
    maindir, binary, pulsation, distortion_factor, \
    N_forb_cycles, Nsample_per_cycle = read_inlist(sys.argv[1])
    print('Inlist read')

    # Setting the output directory and copying the used inlist
    mass1 = binary.primary.Mstar.to(au.Msun).value
    mass2 = binary.secondary.Mstar.to(au.Msun).value
    freq_orb = binary.freq_orb.to(1./au.d).value
    outdir = f'{maindir}binary_M{int(round(100.*mass1))}M{int(round(100.*mass2))}_forb{int(round(1000.*freq_orb))}_i{int(binary.incl_deg)}/'

    if not os.path.exists(outdir):
        os.makedirs(outdir)
        print('Directory created')
    print('Directory set')

    computation_nr = f"{len(glob.glob(f'{outdir}inlist*.yaml')) + 1}".zfill(3)
    sp.call(f'cp ./inlist.yaml {outdir}inlist{computation_nr}.yaml', shell=True)   # warning: do not forget to adapt this line if the inlist filename changes!

    # setting the time domain for tidal perturbation simulations
    time = np.linspace(0., float(N_forb_cycles), N_forb_cycles*Nsample_per_cycle+1) * binary.period.to(au.d)
    orb_phases = np.linspace(0.,float(N_forb_cycles),N_forb_cycles*Nsample_per_cycle+1) % 1.
    puls_phases = np.array(pulsation.puls_freq.to(1/au.d)*time, dtype=float) % 1.

    # time = np.loadtxt('tess_sector01_times.dat').T
    # time *= au.day
    # orb_phases = np.array( time * freq_orb, dtype=float) % 1.
    # puls_phases = np.array(pulsation.puls_freq.to(1/au.d)*time, dtype=float) % 1.

    print('Phase arrays constructed.')
    # Calculating the mode visibilities and kinetic energy
    binary_flux = []
    total_flux = []
    pulsation_flux = []
    eclipse_flags = []

    pbar = Bar('Calculating...', max=len(puls_phases))
    for iph,puls_phase,orb_phase in zip(np.arange(len(puls_phases)), puls_phases, orb_phases):

        # calculating the observed fluxes for (1) the binary + pulsation, (2) the binary, and (3) the pulsation, and provide (4) eclipse flags
        bin_iflux, tot_iflux, puls_iflux, ecl_iflag = calculate_flux(binary, pulsation, puls_phase=puls_phase, orb_phase=orb_phase, distortion_factor=distortion_factor)
        binary_flux.append(bin_iflux)
        total_flux.append(tot_iflux)
        pulsation_flux.append(puls_iflux)
        eclipse_flags.append(int(ecl_iflag))
        pbar.next()
    pbar.finish()

    binary_flux = np.array(binary_flux)
    total_flux = np.array(total_flux)
    pulsation_flux = np.array(pulsation_flux)
    eclipse_flags = np.array(eclipse_flags, dtype=int)

    # Saving the results
    save_results(f'{outdir}pmode_f{int(np.round(pulsation.puls_freq.value*1000000))}_perturbed-visibilities_{computation_nr}.dat', time, orb_phases, puls_phases, total_flux, binary_flux, pulsation_flux, eclipse_flags)


import json
import urllib.request

# read the model into a variable
with open ("../src/test/gene-filter-example-2.xml", "r") as f:
  model=f.read()

# encode the job
job = {
    "export": {
        "network_type":"en",
        "network_format":"sbml"
    },
    "filter": {
        "species": ["h2o", "atp"],
        "reactions": [],
        "enzymes": ["gene_abc"],
        "enzyme_complexes": ["a + b + c", "x + Y", "b_098 + r_abc"],
    },
    "file": model
}

# setup request
req = urllib.request.Request("https://gemtractor.bio.informatik.uni-rostock.de/api/execute")
req.add_header('Content-Type', 'application/json; charset=utf-8')
job_bytes = json.dumps(job).encode('utf-8')
req.add_header('Content-Length', len(job_bytes))

# fire the job
try:
    response = urllib.request.urlopen(req, job_bytes)
    # do whatever you want with the returned file:
    print (response.read())
except urllib.error.HTTPError  as e:
    # there was a problem...!?
    print ("bad request: " + str (getattr(e, 'code', repr(e))) +  getattr(e, 'message', repr(e)))
    print (e.readlines())


from schedule import Scheduler
from session.manager import SessionManager

class GlobalObjectClass:
    def __init__(self):
        self.text: str = ""
        self.database: str = ""
        self.session_manager: SessionManager | None = None
        self.scheduler: Scheduler | None = None

globalObject = GlobalObjectClass()


# Dictionary
capitals = {
    # "key": value,
    "Canada":  "Ottawa",
    "France": "Paris",
    "Kazakhstan": "Astana",
    "Russia": "Moscow"
}

continents = {
    "Canada": "North America",
    "France": "Europe",
    "Kazakhstan": "Asia",
    "Russia": ["Asia", "Europe"]   # Dictionary data type can contain another data type inside.
}

# Dictionaries can be differentiated from lists and tuples by them being not index-based but key-based.
# Dictionaries contain much more complex data, namely keys and values which can be updated.
# As the capital city of Kazakhstan has been renamed, let's update the particular dictionary.
capitals["Kazakhstan"] = "Nur-Sultan"

# Let's create a function to use the data provided in the dictionaries above simultaneously.
print("\nDICTIONARY DATA TYPE")
print("--------------\n")   # just for formatting the output in order to keep it clean

# But zipping the dictionaries directly is not a proper action as it zips only the key names but not the values.
# zip(capitals, countries) would return [('Canada', 'Canada'), ('France', 'France'), ... ] which is not what we want.
# What we can do is to extract the items of dictionaries to lists using items() method.

# A function below is meant for giving an information provided in the dictionaries above.

def country_information():
    global capitals
    global continents

    message = input("Do you want to get information about any country? [Type yes/no]: ").lower().strip()
    # validating the input by lower-casing the letters and shrinking the spaces

    if message == "yes":
        print("Available countries:")

        for number, country in enumerate(capitals, 1):   # looping the enumerated dict to print the keys and values
            print("", str(number) + ")", country)

        checking_country_raw = input("Insert the name of the country: ")
        checking_country = checking_country_raw[0].upper() + checking_country_raw[1:].lower()   # validating the input

        if checking_country in capitals and checking_country in continents:
            for (k1, v1), (k2, v2) in zip(capitals.items(), continents.items()):   # looping the zipped dicts
                if k1 == checking_country:
                    if isinstance(v2, str):   # if only 1 continent
                        print("\n", k1, "is situated in", v2, "and its capital city is", v1 + ".")
                    elif isinstance(v2, list):   # if two continents
                        print("\n", k1, "is situated in", v2[0], "and", v2[1] + ". Its capital city is", v1 + ".")
                    print("--------------\n")   # just for formatting the output in order to keep it clean
        else:
            print("\n!!! Please, choose an available country!\n")
        country_information()
    elif message == "no":
        print("--------------\n")   # just for formatting the output in order to keep it clean
        print(" Thank you for using this app! Good bye!")
        return
    else:
        print("\n!!! Please, answer properly!\n")
        country_information()

country_information()   # calling the function to get information about a country


import math
from abc import ABC, abstractmethod
from dataclasses import dataclass
from hvac import Quantity
from hvac.fluids import Fluid
from hvac.refrigerant_piping.copper_tubing import CopperTube
from hvac.fluid_flow import Pipe, Circular

Q_ = Quantity

@dataclass
class RefrigerantCycleData:
    rfg: Fluid
    T_eva: Quantity  # saturated suction temperature = evaporating temperature
    T_con: Quantity  # saturated condensing temperature
    ESH: Quantity    # evaporator superheat
    CSC: Quantity    # condensor subcooling
    CSH: Quantity    # compressor superheat

    def __post_init__(self):
        self.T_eva_o = self.T_eva + self.ESH
        self.T_con_i = self.T_con + self.CSH
        self.T_con_o = self.T_con - self.CSC
        self.P_eva = self.rfg(T=self.T_eva, x=Q_(0, 'frac')).P
        self.P_con = self.rfg(T=self.T_con, x=Q_(0, 'frac')).P
        self.rfg_con_i = self.rfg(P=self.P_con, T=self.T_con_i)
        self.rfg_con_o = self.rfg(P=self.P_con, T=self.T_con_o)
        self.rfg_eva_i = self.rfg(P=self.P_eva, h=self.rfg_con_o.h)
        self.rfg_eva_o = self.rfg(P=self.P_eva, T=self.T_eva_o)
        self.q_eva = self.rfg_eva_o.h - self.rfg_eva_i.h

class RefrigerantLine(ABC):
    vr_allow_max: Quantity = None
    vr_allow_min: dict[str, Quantity] | None = None

    def __init__(
        self,
        rfg_cycle_data: RefrigerantCycleData,
        Q_eva_max: Quantity,
        Q_eva_min: Quantity | None = None,
    ):
        """
        Parameters
        ----------
        rfg_cycle_data:
            Instance of dataclass RefrigerantCycleData containing the
            specifications of the refrigerant cycle.
        Q_eva_max:
            Maximum evaporator capacity. This will determine the maximum
            flow velocity of the refrigerant.
        Q_eva_min: optional, default None
            Minimum evaporator capacity. This will determine the minimum
            flow velocity of the refrigerant. Leave to default `None` in case of
            an ON/OFF-controlled compressor.
        """
        self.rcd = rfg_cycle_data
        self.Q_eva_max = Q_eva_max
        self.Q_eva_min = Q_eva_min or Q_eva_max
        # if Q_eva_min is None, set self.Q_eva_min equal to Q_eva_max
        self.mr_max = self._get_mr(self.Q_eva_max)
        self.Vr_max = self._get_Vr(self.mr_max)
        self.mr_min = self._get_mr(self.Q_eva_min)
        self.Vr_min = self._get_Vr(self.mr_min)

    def _get_mr(self, Q) -> Quantity:
        """Get mass flow rate of refrigerant in the system."""
        return Q / self.rcd.q_eva

    @abstractmethod
    def _get_Vr(self, mr) -> Quantity:
        """Get volume flow rate of refrigerant."""
        ...

    @abstractmethod
    def get_vr(self, *args, **kwargs) -> tuple:
        """Get refrigerant velocity."""
        ...

    def _check_vr_max(self, vr_max):
        if vr_max.to('feet / min') < self.vr_allow_max:
            r = 'OK'
        else:
            r = 'TOO HIGH'
        return r

    def _check_vr_min(self, vr_min, copper_tube, riser):
        ...

    @abstractmethod
    def get_dp(self, copper_tube: CopperTube, Leq: Quantity) -> Quantity:
        """Get pressure drop across refrigeration line."""
        ...

class VaporLine(RefrigerantLine):

    @abstractmethod
    def _get_Vr(self, mr) -> Quantity:
        ...

    def get_vr(self, copper_tube: CopperTube, riser: bool = True) -> tuple:
        """
        Get maximum and minimum flow velocity of refrigerant.
        This method also checks if maximum and minimum velocity are within the
        allowable upper and lower limits to avoid noise on one hand and to
        ensure proper oil return on the other hand.

        Parameters
        ----------
        copper_tube:
            Instance of dataclass CopperTube containing copper tube specs.
        riser: default True
            Indicate if the pipe is a vertical riser (True) or not (False).

        Returns
        -------
        Tuple with 4 elements:
        1. the flow velocity at maximum capacity
        2. string that indicates if maximum flow velocity is 'OK' or 'TOO HIGH'
        3. the flow velocity at minimum capacity
        4. string that indicates if minimum flow velocity is 'OK', 'TOO LOW', or
        'TOO HIGH'
        """
        A = math.pi * (copper_tube.di ** 2) / 4
        vr_max = self.Vr_max / A
        r_max = self._check_vr_max(vr_max)
        vr_min = self.Vr_min / A
        r_min = self._check_vr_min(vr_min, copper_tube, riser)
        return vr_max, r_max, vr_min, r_min

    def _check_vr_max(self, vr_max):
        if vr_max.to('feet / min') < self.vr_allow_max:
            r = 'OK'
        else:
            r = 'TOO HIGH'
        return r

    def _check_vr_min(self, vr_min, copper_tube, riser):
        vr_min = vr_min.to('feet / min')
        vr_allow_min = self.vr_allow_min[copper_tube.dn]
        # minimum allowable flow velocity to ensure oil return
        if not riser:
            vr_allow_min *= 0.75
        if vr_allow_min <= vr_min < self.vr_allow_max:
            r = 'OK'
        elif vr_min < vr_allow_min:
            r = 'TOO LOW'
        else:  # vr_min >= self.vr_allow_max:
            r = 'TOO HIGH'
        return r

    @abstractmethod
    def get_dp(self, copper_tube: CopperTube, Leq: Quantity) -> Quantity:
        ...

class SuctionLine(VaporLine):
    vr_allow_max = Q_(4000, 'ft / min')
    vr_allow_min = {
        # minimum allowable flow velocity for proper oil return in riser @
        # saturated suction temperature of 20 °F
        k: Q_(v, 'feet / min') for k, v in
        [
            ('3/8', 370), ('1/2', 460),
            ('5/8', 520), ('3/4', 560),
            ('7/8', 600), ('1 1/8', 700),
            ('1 3/8', 780), ('1 5/8', 840),
            ('2 1/8', 980), ('2 5/8', 1080),
            ('3 1/8', 1180), ('3 5/8', 1270),
            ('4 1/8', 1360)
        ]
    }

    def _get_Vr(self, mr):
        # volume flow rate of refrigerant at evaporator outlet
        return mr / self.rcd.rfg_eva_o.rho

    def get_dp(self, copper_tube: CopperTube, Leq: Quantity) -> Quantity:
        """
        Get pressure drop across suction line.

        Parameters
        ----------
        copper_tube:
            Instance of dataclass CopperTube containing copper tube specs.
        Leq:
            Equivalent length of suction line (including equivalent length
            of fittings).
        """
        pipe = Pipe.create(
            length=Leq,
            wall_roughness=Q_(0.0015, 'mm'),
            fluid=self.rcd.rfg(P=self.rcd.P_eva, x=Q_(1, 'frac')),
            cross_section=Circular.create(copper_tube.di),
            volume_flow_rate=self.Vr_max
        )
        return pipe.pressure_drop

class DischargeLine(VaporLine):
    vr_allow_max = Q_(3500, 'ft / min')
    vr_allow_min = {
        # minimum allowable flow velocity for proper oil return in riser @
        # saturated condensing temperature of 80 °F
        k: Q_(v, 'feet / min') for k, v in
        [
            ('5/16', 220), ('3/8', 250),
            ('1/2', 285), ('5/8', 315),
            ('3/4', 345), ('7/8', 375),
            ('1 1/8', 430), ('1 3/8', 480),
            ('1 5/8', 520), ('2 1/8', 600),
            ('2 5/8', 665), ('3 1/8', 730)
        ]
    }

    def _get_Vr(self, mr):
        # volume flow rate of refrigerant at condenser inlet
        return mr / self.rcd.rfg_con_i.rho

    def get_dp(self, copper_tube: CopperTube, Leq: Quantity) -> Quantity:
        """
        Get pressure drop across discharge line.

        Parameters
        ----------
        copper_tube:
            Instance of dataclass CopperTube containing copper tube specs.
        Leq:
            Equivalent length of discharge line (including equivalent length
            of fittings).
        """
        pipe = Pipe.create(
            length=Leq,
            wall_roughness=Q_(0.0015, 'mm'),
            fluid=self.rcd.rfg(P=self.rcd.P_con, x=Q_(1, 'frac')),
            cross_section=Circular.create(copper_tube.di),
            volume_flow_rate=self.Vr_max
        )
        return pipe.pressure_drop

class LiquidLine(RefrigerantLine):
    vr_allow_max = Q_(600, 'ft / min')

    def _get_Vr(self, mr) -> Quantity:
        return mr / self.rcd.rfg_con_o.rho

    def get_vr(self, copper_tube: CopperTube) -> tuple:
        A = math.pi * (copper_tube.di ** 2) / 4
        vr_max = self.Vr_max / A
        r_max = self._check_vr_max(vr_max)
        return vr_max, r_max

    def get_dp(self, copper_tube: CopperTube, Leq: Quantity) -> Quantity:
        """
        Get pressure drop across liquid line.

        Parameters
        ----------
        copper_tube:
            Instance of dataclass CopperTube containing copper tube specs.
        Leq:
            Equivalent length of discharge line (including equivalent length
            of fittings).
        """
        pipe = Pipe.create(
            length=Leq,
            wall_roughness=Q_(0.0015, 'mm'),
            fluid=self.rcd.rfg(P=self.rcd.P_con, x=Q_(0, 'frac')),
            cross_section=Circular.create(copper_tube.di),
            volume_flow_rate=self.Vr_max
        )
        return pipe.pressure_drop

    def get_dT(self, dP: Quantity, H: Quantity) -> Quantity:
        """
        Get equivalent change in saturated temperature.

        Parameters
        ----------
        dP:
            Total pressure drop across liquid line including fittings
            and accessoires.
        H:
            The elevation height between the outlet and inlet of the liquid
            line (if the outlet is below the inlet, `H` is negative).
        """
        rho = self.rcd.rfg_con_o.rho
        g = Q_(9.81, 'm / s ** 2')
        dP_elev = rho * g * H
        dP_tot = dP + dP_elev
        P_out = self.rcd.P_con - dP_tot  # pressure at liquid line outlet = TXV inlet
        T_sat = self.rcd.rfg(P=P_out, x=Q_(0, 'frac')).T  # saturation temperature @ P_out
        dT = self.rcd.T_con.to('K') - T_sat.to('K')
        return dT


import csv
from dataclasses import dataclass, field
from itertools import count

from ..configs import Configs
from ..utils import add_bytes, stringify
from .actions import MONSTER_ACTIONS, Action
from .autoabilities import AUTOABILITIES
from .characters import CHARACTERS, Character
from .constants import (
    Element,
    ElementalAffinity,
    EquipmentSlots,
    EquipmentType,
    GameVersion,
    Rarity,
    Stat,
    Status,
)
from .file_functions import get_resource_path
from .items import ITEMS, ItemDrop
from .text_characters import TEXT_CHARACTERS

@dataclass
class Monster:
    name: str
    stats: dict[Stat, int]
    elemental_affinities: dict[Element, ElementalAffinity]
    status_resistances: dict[Status, int]
    poison_tick_damage: int
    zanmato_level: int
    armored: bool
    undead: bool
    auto_statuses: list[Status]
    gil: int
    ap: dict[str, int]
    item_1: dict[str, int | dict[Rarity, ItemDrop | None]]
    item_2: dict[str, int | dict[Rarity, ItemDrop | None]]
    steal: dict[str | Rarity, int | ItemDrop | None]
    bribe: dict[str, int | ItemDrop | None]
    equipment: dict[str, int | list | dict[Character, list[int]]]
    actions: dict[str, Action]
    zones: list[str] = field(default_factory=list)

    def __str__(self) -> str:
        return self.name

def _get_prize_structs(file_path: str) -> dict[str, list[int]]:
    """Retrieves the prize structs for enemies."""
    absolute_file_path = get_resource_path(file_path)
    with open(absolute_file_path) as file_object:
        file_reader = csv.reader(file_object, delimiter=",")
        monsters_data = {}
        for line in file_reader:
            prize_struct = [int(value, 16) for value in line]
            # gets the name of the monster from the prize struct itself
            # name is null (0x00) terminated
            monster_name = ""
            for character_id in prize_struct[408:430]:
                if character_id == 0:
                    break
                monster_name += TEXT_CHARACTERS[character_id]
            monster_name = stringify(monster_name)
            # if the name is already in the dictionary
            # appends it with an underscore and a number
            # from 2 to 8
            if monster_name in monsters_data:
                for i in count(2):
                    new_name = f"{monster_name}_{i}"
                    if new_name not in monsters_data:
                        monsters_data[new_name] = prize_struct
                        break
            else:
                monsters_data[monster_name] = prize_struct
    return monsters_data

def _patch_prize_structs_for_hd(
    prize_structs: dict[str, list[int]],
) -> dict[str, list[int]]:
    """Apply changes made in the HD version to the prize structs."""

    def patch_abilities(
        monster_name: str,
        abilities: tuple[int, int, int, int, int, int, int],
        equipment_type: EquipmentType = EquipmentType.WEAPON,
    ) -> None:
        """Modifies ability values 1-7 of every character's weapon
        or armor ability array.
        """
        # base address for abilities in the prize struct
        base_address = 178
        type_offset = 0 if equipment_type == EquipmentType.WEAPON else 1
        # place the abilities values at the correct offsets
        for owner_index in range(7):
            offset = (type_offset + (owner_index * 2)) * 16
            for slot in range(7):
                slot_offset = (slot + 1) * 2
                address = base_address + offset + slot_offset
                prize_structs[monster_name][address] = abilities[slot]

    # in the HD version equipment droprates were modified
    # from 8/255 to 12/255 for these enemies
    monster_names = (
        "condor",
        "dingo",
        "water_flan",
        "condor_2",
        "dingo_2",
        "water_flan_2",
        "dinonix",
        "killer_bee",
        "yellow_element",
        "worker",
        "vouivre_2",
        "raldo_2",
        "floating_eye",
        "ipiria",
        "mi'ihen_fang",
        "raldo",
        "vouivre",
        "white_element",
        "funguar",
        "gandarewa",
        "lamashtu",
        "raptor",
        "red_element",
        "thunder_flan",
        "bite_bug",
        "bunyip",
        "garm",
        "simurgh",
        "snow_flan",
        "bunyip_2",
        "aerouge",
        "buer",
        "gold_element",
        "kusariqqu",
        "melusine",
        "blue_element",
        "iguion",
        "murussu",
        "wasp",
        "evil_eye",
        "ice_flan",
        "mafdet",
        "snow_wolf",
        "guado_guardian_2",
        "alcyone",
        "mech_guard",
        "mushussu",
        "sand_wolf",
        "bomb_2",
        "evil_eye_2",
        "guado_guardian_3",
        "warrior_monk",
        "warrior_monk_2",
        "aqua_flan",
        "bat_eye",
        "cave_iguion",
        "sahagin_2",
        "swamp_mafdet",
        "sahagin_3",
        "flame_flan",
        "mech_scouter",
        "mech_scouter_2",
        "nebiros",
        "shred",
        "skoll",
        "flame_flan",
        "nebiros",
        "shred",
        "skoll",
        "dark_element",
        "imp",
        "nidhogg",
        "yowie",
    )
    for monster_name in monster_names:
        prize_structs[monster_name][139] = 12

    # all the enemies that have ability arrays modified in the HD version
    # besaid
    patch_abilities("dingo", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("condor", (0, 0, 0, 0, 126, 126, 126))
    patch_abilities("water_flan", (42, 42, 42, 42, 125, 125, 125))
    patch_abilities("dingo_2", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("condor_2", (0, 0, 0, 0, 126, 126, 126))
    patch_abilities("water_flan_2", (42, 42, 42, 42, 125, 125, 125))

    # kilika
    patch_abilities("dinonix", (38, 42, 38, 30, 126, 126, 126))
    patch_abilities("killer_bee", (38, 42, 34, 30, 126, 126, 126))
    patch_abilities("yellow_element", (38, 38, 38, 38, 125, 125, 125))

    # luca
    patch_abilities("vouivre_2", (38, 42, 34, 30, 124, 124, 124))

    # mi'ihen
    patch_abilities("raldo_2", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("bomb", (30, 30, 30, 30, 30, 30, 125))
    patch_abilities("dual_horn", (67, 30, 30, 30, 30, 127, 127))
    patch_abilities("floating_eye", (38, 42, 34, 30, 99, 126, 126))
    patch_abilities("ipiria", (38, 42, 38, 30, 126, 126, 126))
    patch_abilities("mi'ihen_fang", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("raldo", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("vouivre", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("white_element", (34, 34, 34, 34, 125, 125, 125))

    # mushroom rock road
    patch_abilities("gandarewa", (38, 38, 38, 38, 125, 125, 125))
    patch_abilities("lamashtu", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("raptor", (38, 42, 38, 30, 126, 126, 126))
    patch_abilities("red_element", (30, 30, 30, 30, 125, 125, 125))
    patch_abilities("thunder_flan", (38, 38, 38, 38, 125, 125, 125))

    # djose highroad
    patch_abilities("bite_bug", (38, 42, 34, 30, 126, 126, 126))
    patch_abilities("bunyip", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("garm", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("simurgh", (0, 0, 0, 0, 126, 126, 126))
    patch_abilities("snow_flan", (34, 34, 34, 34, 125, 125, 125))

    # moonflow
    patch_abilities("bunyip_2", (38, 42, 34, 30, 124, 124, 124))

    # thunder plains
    patch_abilities("aerouge", (38, 38, 38, 38, 125, 125, 125))
    patch_abilities("buer", (38, 42, 34, 30, 99, 126, 126))
    patch_abilities("gold_element", (38, 38, 38, 38, 125, 125, 125))
    patch_abilities("kusariqqu", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("melusine", (38, 42, 38, 30, 126, 126, 126))

    # macalania woods
    patch_abilities("blue_element", (42, 42, 42, 42, 125, 125, 125))
    patch_abilities("chimera", (104, 104, 103, 103, 103, 103, 125))
    patch_abilities("iguion", (38, 42, 38, 30, 126, 126, 126))
    patch_abilities("murussu", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("wasp", (38, 42, 34, 30, 126, 126, 126))

    # lake macalania
    patch_abilities("evil_eye", (38, 42, 34, 30, 99, 126, 126))
    patch_abilities("ice_flan", (34, 34, 34, 34, 125, 125, 125))
    patch_abilities("mafdet", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("snow_wolf", (38, 42, 34, 30, 124, 124, 124))

    # bikanel
    patch_abilities("alcyone", (0, 0, 0, 0, 126, 126, 126))
    patch_abilities("mushussu", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("sand_wolf", (38, 42, 34, 30, 124, 124, 124))

    # home
    patch_abilities("bomb_2", (30, 30, 30, 30, 30, 30, 125))
    patch_abilities("chimera_2", (104, 104, 103, 103, 103, 103, 125))
    patch_abilities("dual_horn_2", (67, 67, 67, 30, 30, 127, 127))
    patch_abilities("evil_eye_2", (38, 42, 34, 30, 99, 126, 126))

    # via purifico
    patch_abilities("aqua_flan", (42, 42, 42, 42, 125, 125, 125))
    patch_abilities("bat_eye", (38, 42, 34, 30, 99, 126, 126))
    patch_abilities("cave_iguion", (38, 42, 38, 30, 126, 126, 126))
    patch_abilities("swamp_mafdet", (38, 42, 34, 30, 124, 124, 124))

    # calm lands
    patch_abilities("chimera_brain", (104, 104, 104, 104, 103, 103, 125))
    patch_abilities("flame_flan", (30, 30, 30, 30, 125, 125, 125))
    patch_abilities("nebiros", (38, 42, 34, 30, 126, 126, 126))
    patch_abilities("shred", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("skoll", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("defender_x", (100, 99, 99, 99, 99, 99, 124))

    # cavern of the stolen fayth
    patch_abilities("dark_element", (42, 30, 30, 34, 125, 125, 125))
    patch_abilities("defender", (99, 99, 99, 99, 98, 98, 124))
    patch_abilities("ghost", (104, 104, 104, 103, 103, 103, 125))
    patch_abilities("imp", (38, 38, 38, 38, 125, 125, 125))
    patch_abilities("nidhogg", (38, 42, 34, 30, 124, 124, 124))
    patch_abilities("valaha", (67, 67, 67, 30, 30, 127, 127))
    patch_abilities("yowie", (38, 42, 38, 30, 126, 126, 126))
    return prize_structs

def get_raw_data_string(prize_struct: list[str]) -> str:
    string = ""
    for index, byte in enumerate(prize_struct):
        # every 16 bytes make a new line
        if index % 16 == 0:
            string += "\n"
            string += " ".join([f"[{hex(index + i)[2:]:>3}]" for i in range(16)])
            string += "\n"
        # print the bytes' value
        # string += f' {hex(byte)[2:]:>3}  '
        string += f" {byte:>3}  "
        # string += f' {byte:08b}  '
    return string

def _get_monster_data(monster_id: str, prize_struct: list[int]) -> Monster:
    """Get a Monster from his prize struct."""

    def get_elements() -> dict[str, str]:
        elements = {
            Element.FIRE: 0b00001,
            Element.ICE: 0b00010,
            Element.THUNDER: 0b00100,
            Element.WATER: 0b01000,
            Element.HOLY: 0b10000,
        }
        affinities = {}
        for element, value in elements.items():
            if prize_struct[43] & value:
                affinities[element] = ElementalAffinity.ABSORBS
            elif prize_struct[44] & value:
                affinities[element] = ElementalAffinity.IMMUNE
            elif prize_struct[45] & value:
                affinities[element] = ElementalAffinity.RESISTS
            elif prize_struct[46] & value:
                affinities[element] = ElementalAffinity.WEAK
            else:
                affinities[element] = ElementalAffinity.NEUTRAL
        return affinities

    def get_abilities(address: int) -> dict[str, list[str | None]]:
        abilities = {}
        equipment_types = (EquipmentType.WEAPON, 0), (EquipmentType.ARMOR, 16)
        for equipment_type, offset in equipment_types:
            abilities[equipment_type] = []
            for i in range(address + offset, address + 16 + offset, 2):
                if prize_struct[i + 1] == 128:
                    ability_name = AUTOABILITIES[prize_struct[i]]
                else:
                    ability_name = None
                abilities[equipment_type].append(ability_name)
        return abilities

    monster_name = ""
    for character_id in prize_struct[408:430]:
        if character_id == 0:
            break
        monster_name += TEXT_CHARACTERS[character_id]
    for i in range(16):
        if monster_id.endswith(f"_{i}"):
            monster_name += f"#{i}"
            break

    stats = {
        Stat.HP: add_bytes(*prize_struct[20:24]),
        Stat.MP: add_bytes(*prize_struct[24:28]),
        "overkill_threshold": add_bytes(*prize_struct[28:32]),
        Stat.STRENGTH: prize_struct[32],
        Stat.DEFENSE: prize_struct[33],
        Stat.MAGIC: prize_struct[34],
        Stat.MAGIC_DEFENSE: prize_struct[35],
        Stat.AGILITY: prize_struct[36],
        Stat.LUCK: prize_struct[37],
        Stat.EVASION: prize_struct[38],
        Stat.ACCURACY: prize_struct[39],
    }

    gil = add_bytes(*prize_struct[128:130])
    ap = {
        "normal": add_bytes(*prize_struct[130:132]),
        "overkill": add_bytes(*prize_struct[132:134]),
    }
    item_1 = {
        "drop_chance": prize_struct[136],
        "normal": {Rarity.COMMON: None, Rarity.RARE: None},
        "overkill": {Rarity.COMMON: None, Rarity.RARE: None},
    }
    if prize_struct[141] == 32:
        item_1["normal"][Rarity.COMMON] = ItemDrop(
            ITEMS[prize_struct[140]], prize_struct[148], False
        )
    if prize_struct[143] == 32:
        item_1["normal"][Rarity.RARE] = ItemDrop(
            ITEMS[prize_struct[142]], prize_struct[149], True
        )
    if prize_struct[153] == 32:
        item_1["overkill"][Rarity.COMMON] = ItemDrop(
            ITEMS[prize_struct[152]], prize_struct[160], False
        )
    if prize_struct[155] == 32:
        item_1["overkill"][Rarity.RARE] = ItemDrop(
            ITEMS[prize_struct[154]], prize_struct[161], True
        )

    item_2 = {
        "drop_chance": prize_struct[137],
        "normal": {Rarity.COMMON: None, Rarity.RARE: None},
        "overkill": {Rarity.COMMON: None, Rarity.RARE: None},
    }
    if prize_struct[145] == 32:
        item_2["normal"][Rarity.COMMON] = ItemDrop(
            ITEMS[prize_struct[144]], prize_struct[150], False
        )
    if prize_struct[147] == 32:
        item_2["normal"][Rarity.RARE] = ItemDrop(
            ITEMS[prize_struct[146]], prize_struct[151], True
        )
    if prize_struct[157] == 32:
        item_2["overkill"][Rarity.COMMON] = ItemDrop(
            ITEMS[prize_struct[156]], prize_struct[162], False
        )
    if prize_struct[159] == 32:
        item_2["overkill"][Rarity.RARE] = ItemDrop(
            ITEMS[prize_struct[158]], prize_struct[163], True
        )

    steal = {
        "base_chance": prize_struct[138],
        Rarity.COMMON: None,
        Rarity.RARE: None,
    }
    if prize_struct[165] == 32:
        steal[Rarity.COMMON] = ItemDrop(
            ITEMS[prize_struct[164]], prize_struct[168], False
        )
    if prize_struct[167] == 32:
        steal[Rarity.RARE] = ItemDrop(ITEMS[prize_struct[166]], prize_struct[169], True)
    bribe = {
        "cost": float("nan"),
        "item": None,
    }
    if prize_struct[171] == 32:
        bribe["item"] = ItemDrop(ITEMS[prize_struct[170]], prize_struct[172], False)

    elemental_affinities = get_elements()

    status_resistances = {
        Status.DEATH: prize_struct[47],
        Status.ZOMBIE: prize_struct[48],
        Status.PETRIFY: prize_struct[49],
        Status.POISON: prize_struct[50],
        Status.POWER_BREAK: prize_struct[51],
        Status.MAGIC_BREAK: prize_struct[52],
        Status.ARMOR_BREAK: prize_struct[53],
        Status.MENTAL_BREAK: prize_struct[54],
        Status.CONFUSE: prize_struct[55],
        Status.BERSERK: prize_struct[56],
        Status.PROVOKE: prize_struct[57],
        Status.THREATEN: prize_struct[58],
        Status.SLEEP: prize_struct[59],
        Status.SILENCE: prize_struct[60],
        Status.DARK: prize_struct[61],
        Status.PROTECT: prize_struct[62],
        Status.SHELL: prize_struct[63],
        Status.REFLECT: prize_struct[64],
        Status.NULBLAZE: prize_struct[65],
        Status.NULFROST: prize_struct[66],
        Status.NULSHOCK: prize_struct[67],
        Status.NULTIDE: prize_struct[68],
        Status.REGEN: prize_struct[69],
        Status.HASTE: prize_struct[70],
        Status.SLOW: prize_struct[71],
    }
    poison_tick_damage = stats[Stat.HP] * prize_struct[42] // 100
    undead = prize_struct[72] == 2
    auto_statuses = []
    if prize_struct[74] & 0b00100000:
        auto_statuses.append(Status.REFLECT)
    if prize_struct[75] & 0b00000011 and prize_struct[74] & 0b11000000:
        auto_statuses.append(Status.NULALL)
    if prize_struct[75] & 0b00000100:
        auto_statuses.append(Status.REGEN)

    equipment = {
        "drop_chance": prize_struct[139],
        "bonus_critical_chance": prize_struct[175],
        "base_weapon_damage": prize_struct[176],
        "slots_modifier": prize_struct[173],
        "slots_range": [],
        "max_ability_rolls_modifier": prize_struct[177],
        "max_ability_rolls_range": [],
        "added_to_inventory": bool(prize_struct[174]),
    }

    for i in range(8):
        slots_mod = equipment["slots_modifier"] + i - 4
        slots = (slots_mod + ((slots_mod >> 31) & 3)) >> 2
        if slots < EquipmentSlots.MIN:
            slots = EquipmentSlots.MIN.value
        elif slots > EquipmentSlots.MAX:
            slots = EquipmentSlots.MAX.value
        equipment["slots_range"].append(slots)
        ab_mod = equipment["max_ability_rolls_modifier"] + i - 4
        ab_rolls = (ab_mod + ((ab_mod >> 31) & 7)) >> 3
        equipment["max_ability_rolls_range"].append(ab_rolls)

    equipment["ability_arrays"] = {}
    for c, i in zip(CHARACTERS.values(), range(178, 371, 32)):
        equipment["ability_arrays"][c.name] = get_abilities(i)

    armored = bool(prize_struct[40] & 0b00000001)
    zanmato_level = prize_struct[402]
    actions = MONSTER_ACTIONS[monster_id]
    if not actions:
        actions.update(MONSTER_ACTIONS["generic_actions"])
    monster = Monster(
        name=monster_name,
        stats=stats,
        elemental_affinities=elemental_affinities,
        status_resistances=status_resistances,
        poison_tick_damage=poison_tick_damage,
        zanmato_level=zanmato_level,
        armored=armored,
        undead=undead,
        auto_statuses=auto_statuses,
        gil=gil,
        ap=ap,
        item_1=item_1,
        item_2=item_2,
        steal=steal,
        bribe=bribe,
        equipment=equipment,
        actions=actions,
    )
    return monster

PRIZE_STRUCTS = _get_prize_structs("tracker\\data\\ffx_mon_data.csv")
if Configs.game_version is GameVersion.HD:
    PRIZE_STRUCTS = _patch_prize_structs_for_hd(PRIZE_STRUCTS)

MONSTERS = {k: _get_monster_data(k, v) for k, v in PRIZE_STRUCTS.items()}


# Django初期化
import os, django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
django.setup()

# views.py
from datetime import date
from django.db.models import Count, Q
from app.models import Staff
today = date(2023, 2, 14)  # 動作検証用
qs = (
    Staff.objects
    .values("pk", "name")  # group byのキー
    .annotate(
        delivery_num=Count(
            "delivery",
            filter=Q(
                delivery__date=today,
                delivery__receiver__isnull=False,
            ),
        ),
        unknown_num=Count(
            "delivery",
            filter=Q(
                delivery__date=today,
                delivery__receiver__isnull=True,
            ),
        ),
    )
).values("pk", "name", "delivery_num", "unknown_num")

## クエリーセットを辞書のリストに展開。データの詰め替えは不要
values = list(qs)

# index.html
## todayは各行に持たせず別で渡せばよい
print(today)
for staff in values:
    print(staff)

# ----------------------------

# SQL確認
print("### valuesに変更したSQL")
def printsql(query):
    from sqlparse import format as sfmt
    print(sfmt(str(query), reindent_aligned=True))

printsql(qs.query)

# ----------------------------

print("### SQLを観察してORMを組みなおした改善版")
from django.db.models import FilteredRelation, F

# ORMクエリの実装
qs = (
    Staff.objects
    .values("pk", "name")  # group byのキー
    .annotate(
        dlist=FilteredRelation("delivery", condition=Q(delivery__date=today)),
        delivery_num=Count("dlist__receiver"),
        unknown_num=Count(
            "dlist",
            filter=Q(dlist__receiver__isnull=True),
        ),
    ).values("pk", "name", "delivery_num", "unknown_num")
)

printsql(qs.query)


def main():
	dim = int(input("Enter odd number of rows/columns: "))
	while dim % 2 != 1:
		dim = int(input("Enter odd number of rows/columns: "))

	# create rows
	grid = []
	for i in range(dim):
		row = []
		for j in range(dim):
			row.append(0)
		grid.append(row)

	count = dim ** 2
	grid[dim // 2][dim // 2] = 1

	for i in range(dim // 2 + 1):
		# starting index
		x = i
		y = dim - 1 - i
		for j in range(dim - 1 - i * 2):
			grid[x][y - j] = count
			count -= 1

		# x = i
		y = i
		for j in range(dim - 1 - i * 2):
			grid[x + j][y] = count
			count -= 1

		x = dim - 1 - i
		# y = i
		for j in range(dim - 1 - i * 2):
			grid[x][y + j] = count
			count -= 1

		# x = dim - 1 = i
		y = dim - 1 - i
		for j in range(dim - 1 - i * 2):
			grid[x - j][y] = count
			count -= 1

	# print the result
	for row in grid:
		for i in row:
			print('%02d' % i, end=" ")
		print()
main()


import pygame
import sys

#define bird class
class Bird(object):
    def __init__(self):
        self.birdRect = pygame.Rect(65,50,50,50)
        self.birdStatus = [pygame.image.load("flappybirdassets/assets/1.png"),
                           pygame.image.load("flappybirdassets/assets/2.png"),
                           pygame.image.load("flappybirdassets/assets/dead.png")]
        self.status = 0
        self.birdX = 120
        self.birdY = 350
        self.jump = False
        self.jumpSpeed = 10
        self.gravity = 5
        self.dead = False

    def birdUpdate(self):
        #movement
        if self.jump:
           self.jumpSpeed -= 1
           self.birdY -= self.jumpSpeed
        else:
           self.gravity += 0.2
           self.birdY += self.gravity
        self.birdRect[1] = self.birdY

def createMap():
        screen.blit(background,(0,0))
        #display pine
        screen.blit(Pipeline.pineUp,(Pipeline.wallx, -300))
        screen.blit(Pipeline.pineUp,(Pipeline.wallx, 500))
        Pipeline.PipelineUpdate()
        #display bird
        if Bird.dead :
            Bird.status = 2
        elif Bird.jump :
            Bird.status = 1
        screen.blit(Bird.birdStatus[Bird.status], (Bird.birdX,Bird.birdY))
        Bird.birdUpdate()

        screen.blit(font.render('Score:'+ str(score),1,(255,255,255)),(100,50))
        pygame.display.update()

#define pipeline class
class Pipeline(object):
    def __init__(self):
        self.wallx = 400
        self.pineUp = pygame.image.load("flappybirdassets/assets/top.png")
        self.pineDown = pygame.image.load("flappybirdassets/assets/bottom.png")

    def PipelineUpdate(self):
        #movement
        self.wallx -= 5
        if self.wallx < -80:
            global score
            score += 1
            self.wallx = 400

def checkDead():
    upRect = pygame.Rect(Pipeline.wallx,-300,Pipeline.pineUp.get_width(),Pipeline.pineUp.get_height())
    downRect = pygame.Rect(Pipeline.wallx,500,Pipeline.pineDown.get_width(),Pipeline.pineDown.get_height())

    if upRect.colliderect(Bird.birdRect) or downRect.colliderect(Bird.birdRect):
        Bird.dead = True
    if not Bird.birdRect[1] < height:
        Bird.dead = True
        return True
    else:
        return False

def getResult():
    final_text1 = "GAME OVER"
    final_text2 = "Your final score is :" + str(score)
    ft1_font = fit1_font = pygame.font.SysFont("Arial",70)
    ft1_surf = font.render(final_text1,1,(242,3,36))
    ft2_font = fit2_font = pygame.font.SysFont("Arial",50)
    ft2_surf = font.render(final_text2,1,(253,177,6))

    screen.blit(ft1_surf,[screen.get_width()/2-ft1_surf.get_width()/2,100])
    screen.blit(ft2_surf,[screen.get_width()/2-ft2_surf.get_width()/2,200])
    pygame.display.update()

if __name__ == '__main__':
    pygame.init()
    font = pygame.font.SysFont(None,50)

    size = width, height = 400,650
    screen = pygame.display.set_mode(size) #setting windows sieze
    clock = pygame.time.Clock()# setting delay time
    color = (255,255,255)

    Bird = Bird()
    Pipeline = Pipeline()
    score = 0

    while True:
        clock.tick(60)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
               sys.exit()
            if (event.type == pygame.MOUSEBUTTONDOWN or event.type == pygame.KEYDOWN) and not Bird.dead :
                Bird.jump = True
                Bird.gravity = 5
                Bird.jumpSpeed = 10

        # screen.fill(color)
        background = pygame.image.load("flappybirdassets/assets/background.png")
        if checkDead():
            getResult()
        else:
            createMap()

pygame.quit()


# Write Text command, sends one or multiple text field
class WriteSpecialFunctions:
    code = b"E"

    def __init__(self):
        self.label = b""
        self.data = b""

        # Memory configs
        self.memory_configs = []

        # Checksum?
        self.checksum = False

    # Each special function has it's own function here
    def set_time_of_day(self, hours, minutes):
        self.label = b"\x20"

    def set_speaker(self, enabled):
        self.label = b"\x21"
        self.data = b"00" if enabled else b"FF"

    def clear_memory(self):
        self.label = b"\x24"
        self.data = b""

    def add_memory_config(self, label, type, ir, size, conf):
        self.label = b"\x24"

        # Label of file to configure
        config = label.encode()

        # Type of file to configure
        types = { "text": b"\x41", "string": b"\x42", "dots": b"\x43" }
        config += types.get(type, "\x41")

        # IR Keyboard protection status
        key = { "unlocked": b"\x55", "locked": b"\x4C" }
        config += key.get(ir, "\x4C")

        # Size (in bytes or in image size. WARN: image size is inverted, it's y*x natively)
        config += f"{size[1]:02X}{size[0]:02X}".encode() if isinstance(size, tuple) else f"{size:04X}".encode()

        # Type-specific config
        if type == "text":
            config += f"{conf['start']}{conf['stop']}".encode()
        elif type == "string":
            config += b"0000"
        elif type == "dots":
            colors = { "monochrome": b"1000", "3color": b"2000", "8color": b"8000" }
            config += colors.get(conf, "\x8000")
        else:
            print("ERROR: unknown type")

        self.memory_configs.append(config)

    def set_day_of_week(self, day):
        self.label = b"\x26"
        days = {
            "sunday": b"\x31",
            "monday": b"\x32",
            "tuesday": b"\x33",
            "wednesday": b"\x34",
            "thurdsay": b"\x35",
            "friday": b"\x36",
            "saturday": b"\x37",
        }
        self.data = days.get(day, b"\x32")

    def set_time_format(self, format):
        self.label = b"\x27"
        self.data = "M" if format == "military" else "S"

    def generate_tone(self, type, freq=0, duration=5, repeat=0):
        self.label = b"\x28"
        self.data = type
        if type == b"\x32":
            self.data += f"{freq:02X}{duration:1X}{repeat:1X}".encode()

    def set_run_time_table(self, label, start, stop):
        self.label = b"\x29"
        self.data = label + start + stop

    def display_text_at_xy(self, enabled, x, y, text):
        self.label = b"\x2B"
        status = "\x2B" if enabled else "\x2D"
        file = "\x2B" # Apparently mandatory?
        self.data = f"{status}{file}{x:02}{y:02}{text}".encode()

    def soft_reset(self):
        self.label = b"\x2C"

    def set_run_sequence(self, sequence):
        self.label = b"\x2E"
        self.data = sequence

    def set_dimming_reg(self, dim, brightness):
        self.label = b"\x2F"

        # Get index level closest to brightness
        level = min([100, 86, 72, 58, 44], key=lambda x:abs(x-brightness))
        index = [100, 86, 72, 58, 44].index(level)

        self.data = f"{dim:02X}{index:02}".encode()

    def set_dimming_time(self, start, stop):
        self.label = b"\x2F"
        self.data = f"{start:02X}{stop:02X}".encode()

    def to_bytes(self):
        # Do not return anything if there's no command
        if not self.label:
            return

        # This one is simple: label (function) and it's data (parameters)
        if self.label == "\x24" and self.memory_configs:
            bytes = self.label + self.data
        else:
            bytes = self.label
            for config in self.memory_configs:
                bytes += config

        return bytes


import argparse
import os
import shutil
import socket
import time

import torch
import torch.backends.cudnn as cudnn
import torch.nn as nn
import torch.nn.parallel
import torch.optim as optim
import torch.utils.data
import torchvision.utils as vutils
import torchvision.transforms as transforms

from tensorboardX import SummaryWriter
from torch.autograd import Variable
from torch.optim.lr_scheduler import ReduceLROnPlateau
from torch.utils.data import DataLoader

from data import MyImageFolder
from model import UnetGenerator
from model import RevealNet
from text_data import *
from utils import *
import nltk

DATA_DIR = '/media/changmin/mini_hard/ImageNet/'
TEXT_DATA_DIR = "/home/changmin/research/steganography/data/"

parser = argparse.ArgumentParser()
parser.add_argument('--dataset', default="train",
                    help='train | val | test')
parser.add_argument('--workers', type=int, default=8,
                    help='number of data loading workers')
parser.add_argument('--batchsize', type=int, default=4,
                    help='input batch size')
parser.add_argument('--imagesize', type=int, default=256,
                    help='the number of frames')
parser.add_argument('--epochs', type=int, default=100,
                    help='number of epochs to train for')
parser.add_argument('--lr', type=float, default=0.001,
                    help='learning rate, default=0.001')
parser.add_argument('--decay_round', type=int, default=10,
                    help='learning rate decay 0.5 each decay_round')
parser.add_argument('--beta1', type=float, default=0.5,
                    help='beta1 for adam. default=0.5')
parser.add_argument('--cuda', type=bool, default=True,
                    help='enables cuda')
parser.add_argument('--ngpu', type=int, default=1,
                    help='number of GPUs to use')
parser.add_argument('--Hnet', default='',
                    help="path to Hidingnet (to continue training)")
parser.add_argument('--Rnet', default='',
                    help="path to Revealnet (to continue training)")
parser.add_argument('--embedding', default='',
                    help="path to embedding (to continue training)")
parser.add_argument('--trainpics', default='./training/',
                    help='folder to output training images')
parser.add_argument('--validationpics', default='./training/',
                    help='folder to output validation images')
parser.add_argument('--testpics', default='./training/',
                    help='folder to output test images')
parser.add_argument('--outckpts', default='./training/',
                    help='folder to output checkpoints')
parser.add_argument('--traintexts', default='./training/',
                    help='folder to output training texts')
parser.add_argument('--outlogs', default='./training/',
                    help='folder to output images')
parser.add_argument('--outcodes', default='./training/',
                    help='folder to save the experiment codes')
parser.add_argument('--beta', type=float, default=0.01,
                    help='hyper parameter of beta')
parser.add_argument('--remark', default='', help='comment')
parser.add_argument('--test', default='', help='test mode, you need give the test pics dirs in this param')

parser.add_argument('--hostname', default=socket.gethostname(), help='the host name of the running server')
parser.add_argument('--debug', type=bool, default=False, help='debug mode do not create folders')
parser.add_argument('--logfrequency', type=int, default=10, help='the frequency of print the log on the console')
parser.add_argument('--resultpicfrequency', type=int, default=100, help='the frequency of save the resultpic')
parser.add_argument('--savefrequency', type=int, default=1000, help='the frequency of save the checkpoint')

def main():
    global writer, smallestLoss, optimizerH, optimizerR, schedulerH, schedulerR

    opt = parser.parse_args()

    if torch.cuda.is_available() and not opt.cuda:
        print("WARNING: You have a CUDA device, "
              "so you should porbably run with --cuda")

    cudnn.benchmark = True

    create_dir_to_save_result(opt)

    logpath = opt.outlogs + '%s_%d_log.txt' % (opt.dataset, opt.batchsize)

    print_log(opt, str(opt), logpath)

    save_current_codes(opt.outcodes)

    if opt.test == '':
        voc, _ = loadPrepareData(None, "all", os.path.join(TEXT_DATA_DIR, "dialogues_text.txt"), 768)
        # tensorboardX writer
        writer = SummaryWriter(comment='**' + opt.remark)
        # Get the dataset
        #traindir = os.path.join(DATA_DIR, 'train')
        texttraindir = os.path.join(TEXT_DATA_DIR, "train/dialogues_train.txt")
        valdir = os.path.join(DATA_DIR, 'val')
        textvaldir = os.path.join(TEXT_DATA_DIR, "validation/dialogues_validation.txt")
        """
        train_dataset = MyImageFolder(
            traindir, # Preprocessing the data
            transforms.Compose([
                transforms.Resize([opt.imagesize, opt.imagesize]), # Randomly cut and resize the data to a given size
                transforms.ToTensor(),
                # Convert a numpy.ndarray with a value range of [0,255] or a shape of (H,W,C) to
                # a torch.FloatTensor with a shape of [C,H,W] and a value of [0, 1.0] torch.FloatTensor
            ]),
            True)
        """
        _, text_train_dataset = loadPrepareData(None, "train", texttraindir, 768)
        val_dataset = MyImageFolder(
            valdir, # Preprocessing the data
            transforms.Compose([ # Combine several transforms together
                transforms.Resize([opt.imagesize, opt.imagesize]), # Randomly cut and resize the data to a given size
                transforms.ToTensor(),
                # Convert a numpy.ndarray with a value range of [0, 255] or a shpae of (H,W,C) to
                # a torch.FloatTensor with a shape of [C,H,W] and a value of [0, 1.0] torch.FloatTensor
            ]))
        _, text_val_dataset = loadPrepareData(None, "val", textvaldir, 768)
        #assert train_dataset
        assert val_dataset
        assert text_train_dataset
        assert text_val_dataset
    else:
        testdir = opt.test
        texttestdir =  os.path.join(TEXT_DATA_DIR, "test/dialogues_test.txt")
        test_dataset = MyImageFolder(
            testdir, # Preprocessing the data
            transforms.Compose([ # Combine several transfroms together
                transforms.Resize([opt.imagesize, opt.imagesize]),
                transforms.ToTensor(),
            ]))
        _, text_test_dataset = loadPrepareData(None, "test", texttestdir, 768)
        assert test_dataset
        assert text_test_dataset
    # Create word embedding layer
    embedding = nn.Embedding(voc.num_words, 256)
    embedding.cuda()
    embedding.weight.data.uniform_(-1, 1)
    if opt.embedding != '':
        embedding.load_state_dict(torch.load(opt.embedding))
    if opt.ngpu > 1:
        embedding = torch.nn.DataParallel(embedding).cuda()

    # Create Hiding network objects
    Hnet = UnetGenerator(input_nc=6, output_nc=3, num_downs=7, output_function=nn.Sigmoid)
    Hnet.cuda()
    Hnet.apply(weights_init)
    # Determine whether to continue the previous training
    if opt.Hnet != "":
        Hnet.load_state_dict(torch.load(opt.Hnet))
    if opt.ngpu > 1:
        Hnet = torch.nn.DataParallel(Hnet).cuda()
    print_network(opt, Hnet, logpath)

    # Create Reveal network objects
    Rnet = RevealNet(output_function=nn.Sigmoid)
    Rnet.cuda()
    Rnet.apply(weights_init)
    if opt.Rnet != '':
        Rnet.load_state_dict(torch.load(opt.Rnet))
    if opt.ngpu > 1:
        Rnet = torch.nn.DataParallel(Rnet).cuda()
    print_network(opt, Rnet, logpath)

    # LogSoftmax
    logsoftmax = nn.LogSoftmax(dim=-1).cuda()

    # Mean Square Error loss
    criterion = nn.MSELoss().cuda()
    # training mode
    if opt.test == '':
        # setup optimizer
        optimizerH = optim.Adam(Hnet.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
        schedulerH = ReduceLROnPlateau(optimizerH, mode='min', factor=0.2, patience=5, verbose=True)

        optimizerR = optim.Adam(Rnet.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
        schedulerR = ReduceLROnPlateau(optimizerR, mode='min', factor=0.2, patience=8, verbose=True)

        #train_loader = DataLoader(train_dataset, batch_size=opt.batchsize,
        #                          shuffle=True, num_workers=int(opt.workers))
        val_loader = DataLoader(val_dataset, batch_size=opt.batchsize,
                                shuffle=True, num_workers=int(opt.workers))
        smallestLoss = 10000
        print_log(opt, "-------------------Starts Training----------------------", logpath)

        for epoch in range(opt.epochs):
            # train
            train(opt, val_loader, epoch, voc, embedding, text_train_dataset, Hnet=Hnet, Rnet=Rnet,
                  criterion=criterion, logsoftmax=logsoftmax, logpath=logpath)

            # validation
            val_hloss, val_rloss, val_sumloss = validation(opt, val_loader, epoch, voc, text_val_dataset,
                                                           Hnet=Hnet, Rnet=Rnet, criterion=criterion, logsoftmax=logsoftmax, logpath=logpath)

            # adjust learning rate
            schedulerH.step(val_sumloss)
            schedulerR.step(val_rloss)

            # save the best model parameters
            if val_sumloss < globals()["smallestLoss"]:
                globals()["smallestLoss"] = val_sumloss
                # do check pointing
                torch.save(Hnet.state_dict(),
                           '%s/netH_epoch_%d,sumloss=%.f,Hloss=%.6f.pth' % (
                           opt.outckpts, epoch, val_sumloss, val_hloss))
                torch.save(Rnet.state_dict(),
                           '%s/netR_epoch_%d,sumloss=%.6f,Rloss=%.6f.pth' % (
                           opt.outckpts, epoch, val_sumloss, val_rloss))

        writer.close()

    # test mode
    else:
        test_loader = DataLoader(test_dataset, batch_size=opt.batchsize,
                                 shuffle=False, num_workers=int(opt.workers))
        test(opt, test_loader, 0, Hnet=Hnet, Rnet=Rnet, criterion=criterion, logpath=logpath)
        print("-------------------Test is completed-------------------")

def train(opt, train_loader, epoch, voc, embedding, text_train_dataset, Hnet, Rnet, criterion, logsoftmax, logpath):
    batch_time = AverageMeter()
    data_time = AverageMeter()
    Hlosses = AverageMeter() # record the loss of each epoch Hnet
    Rlosses = AverageMeter() # record the loss of each epoch Rnet
    SumLosses = AverageMeter() # record the each epoch Hloss + β*Rloss

    # switch to train mode
    Hnet.train()
    Rnet.train()

    start_time = time.time()
    for i, data in enumerate(train_loader, 0):
        data_time.update(time.time() - start_time)

        Hnet.zero_grad()
        Rnet.zero_grad()

        all_pics = data # all pics contains coverImg and secretImg, no label needed
        this_batch_size = int(all_pics.size()[0])

        #--------------------------------------------------------------------------------------------------------------------------------
        # The first half of the picture is used as coverImg, and the second half of the picture is used as secretImg
        #cover_img = all_pics[0:this_batch_size, :, :, :] # batch_size, 3, ,256, 256
        cover_img = all_pics
        #--------------------------------------------------------------------------------------------------------------------------------
        # should change secret_img -> secret_text and secret_text has the same size with cover_img
        #secret_img = all_pics[this_batch_size:this_batch_size * 2, :, :, :]
        text_batches = batch2TrainData(voc, [random.choice(text_train_dataset) for _ in range(this_batch_size)])
        secret_text, text_lengths, target_text, mask, max_target_len = text_batches
        org_text = secret_text
        secret_text = secret_text.cuda()
        secret_text = embedding(secret_text)
        secret_text = secret_text.view(this_batch_size, 3, 256, 256)
        #--------------------------------------------------------------------------------------------------------------------------------

        # Concat the pictures together to get six-channel pictures as input to the Hnet
        concat_img_text = torch.cat([cover_img.cuda(), secret_text], dim=1)

        # Data into gpu
        if opt.cuda:
            cover_img = cover_img.cuda()
            #secret_img = secret_img.cuda()
            #concat_img = concat_img.cuda()
            secret_text = secret_text.cuda()
            concat_img_text = concat_img_text.cuda()

        #concat_imgv = Variable(concat_img) # concat_img as input to the Hnet
        concat_img_textv = Variable(concat_img_text)
        cover_imgv = Variable(cover_img) # cover_img as label of Hnet

        #container_img = Hnet(concat_imgv) # Get container_img with secret_img
        container_img = Hnet(concat_img_textv)
        errH = criterion(container_img, cover_imgv) # Hnet reconstruction error
        Hlosses.update(errH, this_batch_size) # record H_loss value

        rev_secret_img = Rnet(container_img) # container_img is used as input to the Rnet to get rev_secret_img
        #import pdb
        #pdb.set_trace()
        #secret_imgv = Variable(secret_img) # secret_img as the label of the Rnet
        secret_textv = Variable(secret_text)

        #errR = criterion(rev_secret_img, secret_imgv) # Rnet reconstruction error
        #errR = criterion(rev_secret_img, secret_textv)
        #-----------------------------------------------------------------------------------------------------------------------------
        #import pdb
        #pdb.set_trace()
        rec_text = rev_secret_img.view(this_batch_size, 768, 256)

        rec_text_norm = normalizing(rec_text, 2)

        W_norm = normalizing(embedding.weight, 1)

        text_org = org_text.view(-1)

        prob_logits = torch.tensordot(torch.squeeze(rec_text_norm), W_norm, dims=[[2], [1]])

        prob = logsoftmax(prob_logits * 100)
        rec_sent = torch.squeeze(torch.argmax(prob, dim=2))
        prob = prob.view(-1, voc.num_words)

        idx = torch.arange(this_batch_size * 768)

        all_idx = torch.t(torch.stack([idx, text_org]))

        all_prob = gather_nd(prob, all_idx)

        gen_temp = rec_sent.view(-1)
        gen_idx = torch.t(torch.stack([idx, gen_temp.cpu()]))
        gen_prob = gather_nd(prob, gen_idx)

        errR = -torch.mean(all_prob)
        #-----------------------------------------------------------------------------------------------------------------------------
        Rlosses.update(errR, this_batch_size) # record R_loss value

        betaerrR_secret = opt.beta * errR
        err_sum = errH + betaerrR_secret
        SumLosses.update(err_sum, this_batch_size)

        # Calculate the gradient
        err_sum.backward()

        # Optimize the parameters of both networks
        optimizerH.step()
        optimizerR.step()

        # Update the time of a batch
        batch_time.update(time.time() - start_time)
        start_time = time.time()

        # log information
        log = '[%d/%d][%d/%d]\tLoss_H: %.4f Loss_R: %.4f Loss_sum: %.4f \tdatatime: %.4f \tbatchtime: %.4f' % (
                epoch, opt.epochs, i, len(train_loader),
                Hlosses.val, Rlosses.val, SumLosses.val, data_time.val, batch_time.val)

        # print log information
        if i % opt.logfrequency == 0:
            print_log(opt, log, logpath)
        else:
            print_log(opt, log, logpath, console=False)

        # Related operations such as storing records
        # Generate a picture in 100 steps

        if epoch % 1 == 0 and i % opt.resultpicfrequency == 0:

            APD = save_result_pic(opt, this_batch_size, cover_img, container_img.data, epoch, i, opt.trainpics)
            save_text_path = opt.traintexts + '/ResultTexts_epoch%03d_batch%04d.txt' % (epoch, i)
            #import pdb
            #pdb.set_trace()
            avg_bleu = 0
            with open(save_text_path, 'a') as text_file:

                for b in range(this_batch_size):
                    ori = [voc.index2word[x] for x in org_text[b].tolist() if x != 0]
                    recon = [voc.index2word[x] for x in rec_sent[b].tolist() if x != 0]
                    original_text = "{}_Original     :".format(b) + " ".join([voc.index2word[x] for x in org_text[b].tolist() if x != 0])
                    recons_text = "{}_Reconstructed:".format(b) + " ".join([voc.index2word[x] for x in rec_sent[b].tolist() if x != 0])
                    text_file.write(original_text + "\n")
                    text_file.write(recons_text + "\n")
                    bleu_score = nltk.translate.bleu_score.sentence_bleu([ori], recon)
                    text_file.write(str(bleu_score) + "\n")
                    avg_bleu += bleu_score
                apd_text = "APD: {}".format(APD) + "\n"
                text_file.write(apd_text)
            avg_bleu = avg_bleu / float(this_batch_size)
            print("Original     :" + " ".join([voc.index2word[x] for x in org_text[0].tolist() if x != 0]))
            print()
            print("Reconstructed:" + " ".join([voc.index2word[x] for x in rec_sent[0].tolist() if x != 0]))
            print("Bleu score   :{}".format(avg_bleu))

        if i % opt.savefrequency == 0 and i != 0:
            torch.save({
                'epoch': epoch,
                'iteration': i,
                'Hnet': Hnet.state_dict(),
                'Rnet': Rnet.state_dict(),
                'optimizerH': optimizerH.state_dict(),
                'optimizerR': optimizerR.state_dict(),
                'sum_loss': err_sum,
                'H_loss': errH,
                'R_loss': errR,
                'voc_dict': voc.__dict__,
                'embedding': embedding.state_dict()
            }, opt.outckpts + '/{}_{}_{}.tar'.format(epoch, i, 'checkpoint'))

    # Time taken to output an epoch
    """
    epoch_log = "one epoch time is %.4f==================================================" % (
        batch_time.sum) + "\n"
    epoch_log = epoch_log + "epoch learning rate: optimizerH_lr = %.8f    optimizerR_lr = %.8f" % (
        Hlosses.avg, Rlosses.avg, SumLosses.avg)
    print_log(opt, epoch_log, logpath)
    """
    if not opt.debug:
        # record learning rate
        writer.add_scalar("lr/H_lr", optimizerH.param_groups[0]['lr'], epoch)
        writer.add_scalar("lr/R_lr", optimizerR.param_groups[0]['lr'], epoch)
        writer.add_scalar("lr/beta", opt.beta, epoch)
        # Every epoch records an average loss on tensorboard display
        writer.add_scalar("train/R_loss", Rlosses.avg, epoch)
        writer.add_scalar("train/H_loss", Hlosses.avg, epoch)
        writer.add_scalar("train/sum_loss", SumLosses.avg, epoch)

def validation(opt, val_loader, epoch, voc, text_val_dataset, Hnet, Rnet, criterion, logsoftmax, logpath):
    print("--------------------------------------------------validation begin--------------------------------------------------")
    start_time = time.time()
    Hnet.eval()
    Rnet.eval()
    Hlosses = AverageMeter() # record the loss of each epoch Hnet
    Rlosses = AverageMeter() # record the loss of each epoch Rnet
    count = 0
    for i, data in enumerate(val_loader, 0):
        if count >= 100:
            break
        Hnet.zero_grad()
        Rnet.zero_grad()
        with torch.no_grad():
            all_pics = data # allpics contains coverImg and secretImg, no label needed
            this_batch_size = int(all_pics.size()[0]) # Processing the last batch of each epoch may be insufficient for opt.batchsize

            # The first half of the picture is used as coverImg, and the second half of the picture is used as secretImg
            cover_img = all_pics # batchsize, 3, 256, 256
            #secret_img = all_pics[this_batch_size:this_batch_size * 2, :, :, :]
            text_batches = batch2TrainData(voc, [random.choice(text_val_dataset) for _ in range(this_batch_size)])
            secret_text, text_lengths, target_text, mask, max_target_len = text_batches
            org_text = secret_text
            secret_text = secret_text.cuda()
            secret_text = embedding(secret_text)
            secret_text = secret_text.view(this_batch_size, 3, 256, 256)

            # Concat the pictures together to get six-channel pictures as input to the Hnet
            #concat_img = torch.cat([cover_img, secret_img], dim=1)
            concat_img_text = torch.cat([cover_img.cuda(), secret_text], dim=1)

            # Data into gpu
            if opt.cuda:
                cover_img = cover_img.cuda()
                #secret_img = secret_img.cuda()
                #concat_img = concat_img.cuda()
                concat_img_text = concat_img_text.cuda()

            #concat_imgv = Variable(concat_img) # concat_img as input to the Hnet
            concat_img_textv = Variable(concat_img_text)
            cover_imgv = Variable(cover_img) # cover_img as label of Hnet

            container_img = Hnet(concat_img_textv) # Get container_img with secret_img
            errH = criterion(container_img, cover_imgv) # Hnet reconstruction error
            Hlosses.update(errH, this_batch_size) # record H_loss value

            rev_secret_img = Rnet(container_img) # container_img is used as input to the Rnet to get rev_secret_img

            secret_textv = Variable(secret_text)

            rec_text = rev_secret_img.view(this_batch_size, 768, 256)

            rec_text_norm = normalizing(rec_text, 2)

            W_norm = normalizing(embedding.weight, 1)

            text_org = org_text.view(-1)

            prob_logits = torch.tensordot(torch.squeeze(rec_text_norm), W_norm, dims=[[2], [1]])

            prob = logsoftmax(prob_logits * 100)
            prob = prob.view(-1, voc.num_words)

            idx = torch.arange(this_batch_size * 768)

            all_idx = torch.t(torch.stack([idx, text_org]))

            all_prob = gather_nd(prob, all_idx)

            errR = -torch.mean(all_prob) # Rnet reconstruction error
            Rlosses.update(errR, this_batch_size) # record R_loss value
            """
            if i % 50 == 0:
                save_result_pic(opt, this_batch_size, cover_img, container_img.data, secret_img, rev_secret_img.data, epoch, i,
                                opt.validationpics)
            """
            count += 1
    val_hloss = Hlosses.avg
    val_rloss = Rlosses.avg
    val_sumloss = val_hloss + opt.beta * val_rloss

    val_time = time.time() - start_time
    val_log = "validation[%d] val_Hloss = %.6f\t val_Rloss = %.6f\t val_Sumloss = %.6f\t validation time=%.2f" % (
        epoch, val_hloss, val_rloss, val_sumloss, val_time)
    print_log(opt, val_log, logpath)

    if not opt.debug:
        writer.add_scalar('validation/H_loss_avg', Hlosses.avg, epoch)
        writer.add_scalar('validation/R_loss_avg', Rlosses.avg, epoch)
        writer.add_scalar('validation/sum_loss_avg', val_sumloss, epoch)

    print("--------------------------------------------------validation end--------------------------------------------------")
    return val_hloss, val_rloss, val_sumloss

def test(opt, test_loader, epoch, Hnet, Rnet, criterion, logpath):
    print("--------------------------------------------------test begin--------------------------------------------------")
    start_time = time.time()
    Hnet.eval()
    Rnet.eval()
    Hlosses = AverageMeter() # to record the Hloss in one epoch
    Rlosses = AverageMeter() # to record the Rloss in one epoch
    for i, data in enumerate(test_loader, 0):
        Hnet.zero_grad()
        Rnet.zero_grad()
        with torch.no_grad():
            all_pics = data # all_pics contain cover_img and secret_img, label is not needed
            this_batch_size = int(all_pics.size()[0] / 2) # in order to handle the final batch which may not have opt.size

            # half of the front is as cover_img, half of the end is as secret_img
            cover_img = all_pics[0:this_batch_size, :, :, :] # batchsize,3,256,256
            secret_img = all_pics[this_batch_size:this_batch_size * 2, :, :, :]

            # concat cover and original secret get the concat_img with  channels
            concat_img = torch.cat([cover_img, secret_img], dim=1)

            # data into gpu
            if opt.cuda:
                cover_img = cover_img.cuda()
                secret_img = secret_img.cuda()
                concat_img = concat_img.cuda()

            concat_imgv = Variable(concat_img) # concat_img is the input of Hnet
            cover_imgv = Variable(cover_img) # Hnet reconstruction error

            container_img = Hnet(concat_imgv) #  concat_img as the input of Hnet and get the container_img
            errH = criterion(container_img, cover_imgv) # Hnet reconstruction error
            Hlosses.update(errH, this_batch_size) # record the H loss value

            rev_secret_img = Rnet(container_img) # container_img is the input of the Rnet and get the output "rev_secret_img"
            secret_imgv = Variable(secret_img) # secret_imgv is the label of Rnet
            errR = criterion(rev_secret_img, secret_imgv) # Rnet reconstructed error
            Rlosses.update(errR, this_batch_size) # record the R_loss value
            save_result_pic(opt, this_batch_size, cover_img, container_img.data, secret_img, rev_secret_img.data, epoch, i,
                            opt.testpics)

    val_hloss = Hlosses.avg
    val_rloss = Rlosses.avg
    val_sumloss = val_hloss + opt.beta * val_rloss

    val_time = time.time() - start_time
    val_log = "validation[%d] val_Hloss = %.6f\t val_Rloss = %.6f\t val_Sumloss = %.6f\t validation time=%.2f" % (
        epoch, val_hloss, val_rloss, val_sumloss, val_time)
    print_log(opt, val_log, logpath)

    print("--------------------------------------------------test end--------------------------------------------------")
    return val_hloss, val_rloss, val_sumloss

if __name__ == '__main__':
    main()


# class Solution: # 作弊解法
#     def permute(self, nums):
#         import itertools
#         return list(itertools.permutations(nums))

class Solution:
    def permute(self, nums):

        res = []
        if len(nums) == 1:  # 结束条件
            return [nums]
        if len(nums) == 2:  # 结束条件
            return [nums, nums[::-1]]
        for i in range(len(nums)):
            num = nums[i]
            newnums = nums[:i] + nums[i+1:]
            for item in self.permute(newnums):  # 递归调用
                res.append([num] + item)
        return res

if __name__ == '__main__':

    s = Solution()
    ans = s.permute([1,2,3,5,6,8])
    print(ans)


import numpy as np
import matplotlib.pyplot as plt

def optimum_cf (gamma, P_exit_pa, mean_Pc_pa, ):
    cf = lambda p2_p3, p3_p1: np.sqrt((2 * (gamma ** 2) / (gamma - 1)) * ((2 / (gamma + 1)) ** ((gamma + 1) / (gamma - 1))) * (1 - (p2_p3 * p3_p1) ** ((gamma - 1) / gamma))) + (p2_p3 * p3_p1 - p3_p1) \
                                / ((((gamma + 1) / 2) ** (1 / (gamma - 1))) * ((p2_p3 * p3_p1) ** (1 / gamma)) * np.sqrt(((gamma + 1) / (gamma - 1)) * (1 - ((p2_p3 * p3_p1) ** ((gamma - 1) / gamma)))))
    # pe_pa = np.linspace(0.1, 3, 1000000)
    #
    # plt.plot(pe_pa, [cf(i, P_exit_pa / mean_Pc_pa) for i in pe_pa], 1, cf(1, P_exit_pa / mean_Pc_pa), '*')
    # plt.legend(['Thrust coefficient', 'Maximum Thrust Coefficient'])
    # plt.xlabel('Pe/Pa')
    # plt.ylabel(r'$C_{f}$')
    # plt.title('Thrust coefficient VS Exit to ambient pressure ratio')
    # plt.show()
    #
    # max_cf = cf(1,P_exit_pa / mean_Pc_pa)
    Cf = cf()
    return cf

Rocket Nozzle Optimization in Python/optimum_cf.py


from SlackClient import SlackClient

class SlackFiles(SlackClient):

    def __init__(self):
        self.file = None
        self.id = None

        self.count = None
        self.cursor = None
        self.limit = None
        self.page = None

        self.channel = None
        self.show_files_hidden_by_limit = None
        self.ts_from = None
        self.ts_to = None
        self.types = None
        self.user = None

        self.content = None
        self.filename = None
        self.filetype = None
        self.initial_comment = None
        self.thread_ts = None
        self.title = None
        self.channels = []

        self.external_id = None
        self.external_url = None
        self.filetype = None
        self.indexable_file_contents = None
        self.preview_image = None

        self.highlight = None
        self.sort = None
        self.sort_dir = None
        self.team_id = None

    def generate_queries(self):

        body = {}

        if self.highlight != None:
            body['highlight'] = self.highlight
        if self.sort != None:
            body['sort'] = self.sort
        if self.sort_dir != None:
            body['sort_dir'] = self.sort_dir
        if self.team_id != None:
            body['team_id'] = self.team_id
        if self.external_id != None:
            body['external_id'] = self.external_id
        if self.external_url != None:
            body['external_url'] = self.external_url
        if self.title != None:
            body['title'] = self.title
        if self.indexable_file_contents != None:
            body['indexable_file_contents'] = self.indexable_file_contents
        if self.preview_image != None:
            body['preview_image'] = self.preview_image
        if self.filename != None:
            body['filename'] = self.filename
        if self.filetype != None:
            body['filetype'] = self.filetype
        if self.initial_comment != None:
            body['initial_comment'] = self.initial_comment
        if self.tread_ts != None:
            body['thread_ts'] = self.thread_ts
        if self.title != None:
            body['title'] = self.title
        if len(self.channels) > 0:
            body['channels'] = ','.join(self.channels)
        if self.content != None:
            body['content'] = self.content
        if self.channel != None:
            body['channel'] = self.channel
        if self.show_files_hidden_by_limit != None:
            body['show_files_hidden_by_limit'] = self.show_files_hidden_by_limit
        if self.ts_from != None:
            body['ts_from'] = self.ts_from
        if self.ts_to != None:
            body['ts_to'] = self.ts_to
        if self.types != None:
            body['types'] = self.types
        if self.user != None:
            body['user'] = self.user
        if self.file != None:
            body['file'] = self.file
        if self.id != None:
            body['id'] = self.id
        if self.count != None:
            body['count'] = self.count
        if self.cursor != None:
            body['cursor'] = self.cursor
        if self.limit != None:
            body['limit'] = self.limit
        if self.page != None:
            body['page'] = self.page
        return body

    def clear_queries(self):
        self.file = None
        self.id = None
        self.count = None
        self.cursor = None
        self.limit = None
        self.page = None
        self.channel = None
        self.show_files_hidden_by_limit = None
        self.ts_from = None
        self.ts_to = None
        self.types = None
        self.user = None
        self.channels = []
        self.content = None
        self.file = None
        self.filename = None
        self.filetype = None
        self.initial_comment = None
        self.thread_ts = None
        self.title = None
        self.external_id = None
        self.external_url = None
        self.indexable_file_contents = None
        self.preview_image = None
        self.highlight = None
        self.sort = None
        self.sort_dir = None
        self.team_id = None


from uuid import uuid4
from typing import Tuple, List
from asendia_us_lib.shipping_request import ShippingRequest, Item
from asendia_us_lib.shipping_response import PackageLabel
from purplship.core.units import CustomsInfo, Packages, Options, Weight
from purplship.core.utils import Serializable, DP
from purplship.core.models import (
    Documents,
    ShipmentRequest,
    ShipmentDetails,
    Message,
    Customs,
)

from purplship.providers.asendia_us.units import (
    Service,
    Option,
    LabelType,
    ProcessingLocation,
)
from purplship.providers.asendia_us.error import parse_error_response
from purplship.providers.asendia_us.utils import Settings

def parse_shipment_response(
    responses: Tuple[str, dict], settings: Settings
) -> Tuple[ShipmentDetails, List[Message]]:
    _, response = responses
    errors = parse_error_response(response, settings)
    details = (
        _extract_details(responses, settings)
        if response.get("packageLabel") is not None
        else None
    )

    return details, errors

def _extract_details(response: Tuple[str, dict], settings: Settings) -> ShipmentDetails:
    label, details = response
    shipment = DP.to_object(PackageLabel, details)

    return ShipmentDetails(
        carrier_name=settings.carrier_name,
        carrier_id=settings.carrier_id,
        tracking_number=shipment.trackingNumber,
        shipment_identifier=shipment.packageId,
        docs=Documents(label=label),
    )

def shipment_request(
    payload: ShipmentRequest, settings: Settings
) -> Serializable[ShippingRequest]:
    package = Packages(payload.parcels).single
    options = Options(payload.options, Option)
    product_code = Service.map(payload.service).value_or_key
    unique_id = getattr(payload, "id", uuid4().hex)
    customs = CustomsInfo(payload.customs or Customs(commodities=[]))

    request = ShippingRequest(
        accountNumber=settings.account_number,
        subAccountNumber=options.asendia_sub_account_number,
        processingLocation=ProcessingLocation.map(
            options.asendia_processing_location or "SFO"
        ).name,
        includeRate=True,
        labelType=LabelType.map(payload.label_type or "PDF").name_or_key,
        orderNumber=unique_id,
        dispatchNumber=unique_id,
        packageID=unique_id,
        recipientTaxID=payload.recipient.state_tax_id,
        returnFirstName=payload.shipper.person_name,
        returnLastName=payload.shipper.person_name,
        returnCompanyName=payload.shipper.company_name,
        returnAddressLine1=payload.shipper.address_line1,
        returnAddressLine2=payload.shipper.address_line2,
        returnAddressLine3=None,
        returnProvince=payload.shipper.state_code,
        returnPostalCode=payload.shipper.postal_code,
        returnCountryCode=payload.shipper.country_code,
        returnPhone=payload.shipper.phone_number,
        returnEmail=payload.shipper.email,
        recipientFirstName=payload.recipient.person_name,
        recipientLastName=payload.recipient.person_name,
        recipientBusinessName=payload.recipient.company_name,
        recipientAddressLine1=payload.recipient.address_line1,
        recipientAddressLine2=payload.recipient.address_line2,
        recipientAddressLine3=None,
        recipientCity=payload.recipient.city,
        recipientProvince=payload.recipient.state_code,
        recipientPostalCode=payload.recipient.postal_code,
        recipientPhone=payload.recipient.phone_number,
        recipientEmail=payload.recipient.email,
        totalPackageWeight=package.weight.value,
        weightUnit=package.weight_unit.value.lower(),
        dimLength=package.length.value,
        dimWidth=package.width.value,
        dimHeight=package.height.value,
        dimUnit=package.dimension_unit.value,
        totalPackageValue=options.declared_value,
        currencyType=options.currency,
        productCode=product_code,
        customerReferenceNumber1=payload.reference,
        customerReferenceNumber2=None,
        customerReferenceNumber3=None,
        contentType=("D" if package.parcel.is_document else "M"),
        packageContentDescription=package.parcel.description,
        vatNumber=None,
        sellerName=payload.shipper.person_name,
        sellerAddressLine1=payload.shipper.address_line1,
        sellerAddressLine2=payload.shipper.address_line2,
        sellerAddressLine3=None,
        sellerProvince=payload.shipper.state_code,
        sellerPostalCode=payload.shipper.postal_code,
        sellerPhone=payload.shipper.phone_number,
        sellerEmail=payload.shipper.email,
        items=[
            Item(
                sku=item.sku,
                itemDescription=item.description,
                unitPrice=item.value_amount,
                quantity=item.quantity,
                unitWeight=Weight(item.weight, package.weight_unit).value,
                countryOfOrigin=item.origin_country,
                htsNumber=None,
            )
            for item in customs.commodities
        ],
    )

    return Serializable(request)


import collections
from typing import Any, List

import torch
from executorch.exir.dialects.edge.arg.model import BaseArg

from executorch.exir.dialects.edge.arg.type import ArgType

def extract_return_dtype(
    returns: Any, sample_returns: List[BaseArg]
) -> List[torch.dtype]:
    """Extract the dtype from a return value."""
    if not isinstance(returns, collections.abc.Sequence):
        returns = [returns]
    result = []
    for ret, sample in zip(returns, sample_returns):
        if sample.type == ArgType.TensorList or sample.type == ArgType.TensorOptList:
            # Assuming all tensors in tensor list has the same dtype, and we only add 1 dtype to result.
            assert (
                ret is not None
            ), f"Expecting non-None return value for {sample} but got None"
            result.append(ret.dtype)
            break
        elif sample.type == ArgType.Tensor or sample.type == ArgType.TensorOpt:
            assert (
                ret is not None
            ), f"Expecting non-None return value for {sample} but got None"
            result.append(ret.dtype)
    return result


from pandas import read_csv
from sklearn.metrics import mean_absolute_percentage_error
from math import sqrt
from matplotlib import pyplot as plt
from pandas import concat
import numpy as np
import scipy.stats as stats
import pandas as pd

def persistence_one_step_ln(train_log, teste_log,
    show_results=False, plot_result=False):
    # Prepare data
    teste_log = teste_log.values
    train_log = [x for x in train_log]

    # Walk-forward validation
    predictions = list()

    for i in range(len(teste_log)):
        # Predict
        yhat = train_log[-1]
        # Store forecast in list of predictions
        predictions.append(yhat)
        # Add actual observation to train for the next loop
        obs = teste_log[i]
        train_log.append(obs)

        if show_results:
            print('>Predicted=%.3f, Expected=%.3f' % (yhat, obs))

    # Report performance
    mape = mean_absolute_percentage_error(np.exp(teste_log), np.exp(predictions))
    print('MAPE: %.3f' % mape)
    # Plot predicted vs expected values
    if plot_result:
        plt.plot(np.exp(teste_log))
        plt.plot(np.exp(predictions), color='red')
        plt.show()

# Load data
train_log = pd.read_csv('../timeserie_log_train.csv',
                     header=0, index_col=0, parse_dates=True, squeeze=True)
teste_log = pd.read_csv('../timeserie_log_test.csv',
                     header=0, index_col=0, parse_dates=True, squeeze=True)

persistence_one_step_ln(train_log, teste_log, plot_result=True)


import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

import plotly.graph_objects as go
import pandas as pd

import plotly.express as px

# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')

fig = go.Figure(data=[go.Surface(z=z_data.values)])
fig.update_traces(contours_z=dict(show=True, usecolormap=True,
                                  highlightcolor="limegreen", project_z=True))
fig.update_layout(title='Mt Bruno Elevation', autosize=False,
                  scene_camera_eye=dict(x=1.87, y=0.88, z=-0.64),
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90))

cont = go.Figure(go.Surface(
    contours = {
        "x": {"show": True, "start": 1.5, "end": 2, "size": 0.04, "color":"white"},
        "z": {"show": True, "start": 0.5, "end": 0.8, "size": 0.05}
    },
    x = [1,2,3,4,5],
    y = [1,2,3,4,5],
    z = [
        [0, 1, 0, 1, 0],
        [1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0],
        [1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0]
    ]))
cont.update_layout(
        scene = {
            "xaxis": {"nticks": 20},
            "zaxis": {"nticks": 4},
            'camera_eye': {"x": 0, "y": -1, "z": 0.5},
            "aspectratio": {"x": 1, "y": 1, "z": 0.2}
        })

df = px.data.iris()
sepal = px.scatter_3d(df, x='sepal_length', y='sepal_width', z='petal_width',color='species')

app = dash.Dash(__name__)

app.layout = html.Div(
    children = [
        html.Div([
            dcc.Graph(id="3d-surface-plot", figure=fig),
            dcc.Graph(id="contour-surface-plot", figure=cont)
        ],style={'columnCount': 2}),
        html.Div([
            dcc.Graph(id="3d-scatter-plot", figure=sepal)
            ], style={'columnCount': 1})
            ])