# -*- coding: utf-8 -*-

from __future__ import absolute_import

import contextlib
import re
import copy
import operator
from types import MethodType
import collections

from . import mixture
from . import element
from . import compoundfromformula
from . import xrayspectrum
from . import compoundfromlist
from . import types
from ..utils import units
from ..utils import instance
from ..patch import xraylib
from ..io.mca import save as savemca
from ..utils.copyable import Copyable

import numpy as np
import scipy.interpolate
import scipy.optimize
import matplotlib.pyplot as plt
import fisx
from PyMca5.PyMcaPhysics.xrf import ClassMcaTheory
from PyMca5.PyMcaPhysics.xrf import ConcentrationsTool
from PyMca5.PyMcaIO import ConfigDict

try:
    from silx.gui import qt
    from PyMca5.PyMcaGui.physics.xrf import McaAdvancedFit
except ImportError:
    qt = None
    McaAdvancedFit = None

class PymcaBaseHandle(Copyable):
    def __init__(self):
        self.mcafit = ClassMcaTheory.McaTheory()
        self.ctool = ConcentrationsTool.ConcentrationsTool()
        self.app = None

    def loadfrompymca(self, filename=None, config=None):
        if filename is not None:
            fconfig = ConfigDict.ConfigDict()
            fconfig.read(filename)
            self.mcafit.configure(fconfig)
        if config is not None:
            self.mcafit.configure(config)

    def savepymca(self, filename):
        self.mcafit.config.write(filename)

    def configfromfitresult(self, digestedresult):
        config = copy.deepcopy(digestedresult["config"])
        # Global parameters
        parammap = {
            "Zero": ("detector", "zero"),
            "Gain": ("detector", "gain"),
            "Noise": ("detector", "noise"),
            "Fano": ("detector", "fano"),
            "Sum": ("detector", "sum"),
            "ST AreaR": ("peakshape", "st_arearatio"),
            "ST SlopeR": ("peakshape", "st_sloperatio"),
            "LT AreaR": ("peakshape", "lt_arearatio"),
            "LT SlopeR": ("peakshape", "lt_sloperatio"),
            "STEP HeightR": ("peakshape", "step_heightratio"),
            "Eta Factor": ("peakshape", "eta_factor"),
        }
        nparams = len(digestedresult["parameters"])
        ngroups = len(digestedresult["groups"])
        nglobal = nparams - ngroups
        for i in range(nglobal):
            param = digestedresult["parameters"][i]
            if param in parammap:
                key = parammap[param]
                config[key[0]][key[1]] = digestedresult["fittedpar"][i]
        return config

    @staticmethod
    def _parse_fitresult_massfractions(wfrac1, wfrac0, exclude):
        # Group per element
        wfrac2 = {}
        for zgroup, w in wfrac1.items():
            element = zgroup.element
            if element in exclude:
                continue
            group = zgroup.element.shells[0]
            if element not in wfrac2:
                wfrac2[element] = {}
            wfrac2[element][group] = w
        # Select mass fraction from most reliable group
        wfrac3 = {}
        for element, groupdict in wfrac2.items():
            w = sorted(groupdict.items(), key=operator.itemgetter(0))[0][1]
            wfrac3[element] = w
        # Modify original mass fractions
        wfracr = dict(wfrac0)
        snew = 1 - sum(w for element, w in wfrac0.items() if element not in wfrac3)
        sold = sum(wfrac3.values())
        norm = snew / sold
        for k, v in wfrac3.items():
            if v:
                wfracr[k] = v * norm
        return wfracr

    def _pymcaconfig_massfractions(self, config):
        """
        Extract elemental mass fractions from the pymca config sample
        """
        materials = collections.OrderedDict()
        enabled, name, density = config["attenuators"]["Matrix"][:3]
        if name == "MULTILAYER":
            for i in range(len(config["multilayer"])):
                enabled, name, density = config["multilayer"]["Layer{}".format(i)][:3]
                if enabled:
                    mat = self.loadfrompymca_material(config, name, density)
                    materials[name] = mat.elemental_massfractions()
        elif enabled:
            mat = self.loadfrompymca_material(config, name, density)
            materials[name] = mat.elemental_massfractions()
        return materials

    def configadjustconcentrations(self, config, lmassfractions, exclude=None):
        """
        Modify pymca config sample materials based on list of elemental concentrations
        """
        if not exclude:
            exclude = []
        materials = self._pymcaconfig_massfractions(config)
        if not materials:
            return
        if len(materials) != len(lmassfractions):
            raise RuntimeError("Number of layers in config and fitresult do not match")
        for (name, wfrac0), wfrac1 in zip(materials.items(), lmassfractions):
            wfrac2 = self._parse_fitresult_massfractions(wfrac1, wfrac0, exclude)
            CompoundList = [str(k) + "1" for k in wfrac2.keys()]
            CompoundFraction = list(wfrac2.values())
            config["materials"][name]["CompoundList"] = CompoundList
            config["materials"][name]["CompoundFraction"] = CompoundFraction

    def setdata(self, y):
        x = np.arange(len(y), dtype=np.float32)
        self.mcafit.setData(x, y)

    def fit(
        self,
        loadfromfit=False,
        concentrations=True,
        spectra=True,
        environ_elements=None,
    ):
        # Fit
        self.mcafit.estimate()
        fitresult, digestedresult = self.mcafit.startfit(digest=1)
        # Background
        yback = digestedresult.pop("continuum")  # polynomial + snip
        if self.mcafit.STRIP:
            ysnip = np.ravel(self.mcafit.zz)
        else:
            ysnip = 0
        digestedresult["yback"] = yback
        digestedresult["ysnip"] = ysnip
        # Parse result
        result = self.miscfromfitresult(digestedresult)
        if concentrations:
            self.concentrationsfromfitresult(digestedresult, out=result)
        if spectra:
            self.spectrafromfitresult(digestedresult, out=result)
        # Load parameters from fit (if you did "load from fit")
        if loadfromfit:
            config = self.configfromfitresult(digestedresult)
            if concentrations:
                self.configadjustconcentrations(
                    config, result["lmassfractions"], exclude=environ_elements
                )
            self.loadfrompymca(config=config)
        return result

    def fitgui(
        self,
        ylog=False,
        legend="data",
        loadfromfit=False,
        concentrations=True,
        spectra=True,
        environ_elements=None,
    ):
        if self.app is None:
            self.app = qt.QApplication([])
        w = McaAdvancedFit.McaAdvancedFit()

        # Copy mcafit
        x = self.mcafit.xdata0
        y = self.mcafit.ydata0
        w.setData(x, y, legend=legend, xmin=0, xmax=len(y) - 1)
        w.mcafit.configure(self.mcafit.getConfiguration())

        # GUI for fitting
        if ylog:
            w.graphWindow.yLogButton.click()
        w.graphWindow.energyButton.click()
        # w.graphWindow.setGraphYLimits(min(y[y>0]),None)
        w.refreshWidgets()
        w.show()
        result = self.app.exec_()

        # Parse result
        result = {}
        try:
            digestedresult = w.mcafit.digestresult()
        except AttributeError:
            digestedresult = None

        if digestedresult:
            # Load parameters from fit (if you did "load from fit")
            self.miscfromfitresult(digestedresult, out=result)
            if concentrations:
                self.concentrationsfromfitresult(digestedresult, out=result)
            if spectra:
                self.spectrafromfitresult(digestedresult, out=result)
            if loadfromfit:
                config = w.mcafit.getConfiguration()
                if concentrations:
                    self.configadjustconcentrations(
                        config, result["lmassfractions"], exclude=environ_elements
                    )
                self.loadfrompymca(config=config)
        else:
            if concentrations or spectra:
                result = self.fit(
                    loadfromfit=loadfromfit,
                    concentrations=concentrations,
                    spectra=spectra,
                )

        return result

    def processfitresult(self, digestedresult, originalconcentrations=False):
        ctoolcfg = self.ctool.configure()
        ctoolcfg.update(digestedresult["config"]["concentrations"])
        return self.ctool.processFitResult(
            config=ctoolcfg,
            fitresult={"result": digestedresult},
            elementsfrommatrix=originalconcentrations,
            fluorates=self.mcafit._fluoRates,
            addinfo=True,
        )

    def concentrationsfromfitresult(self, digestedresult, out=None):
        # Mass fractions:
        #
        # For a group (e.g Fe-K) and i loops over the layers:
        #  grouparea = flux.time.solidangle/(4.pi).sum_i[massfrac_i.grouprate_i]
        #
        # When Fe is present in only one layer j:
        #  massfrac_j = grouparea/(flux.time.solidangle/(4.pi).grouprate_i)
        #
        # When Fe present in multiple layers:
        #  grouparea = flux.time.solidangle/(4.pi).massfrac_avg.sum_i[b_i.grouprate_i]
        # where b_i is 1 or 0 depending on whether it is present in the matrix definition
        # When the element is not in the matrix definition b_i=1 for all layers.
        #
        #  massfrac_avg = grouparea/(flux.time.solidangle/(4.pi).sum_i[b_i.grouprate_i])
        if out is None:
            out = {}
        conresult, addinfo = self.processfitresult(
            digestedresult, originalconcentrations=False
        )

        out["massfractions"] = {
            element.Element.fluozgroup(k): v
            for k, v in conresult["mass fraction"].items()
        }

        if "layerlist" in conresult:
            nlayers = len(conresult["layerlist"])
            if nlayers > 0:
                out["lmassfractions"] = [
                    {
                        element.Element.fluozgroup(k): v
                        for k, v in conresult[k]["mass fraction"].items()
                    }
                    for k in conresult["layerlist"]
                ]
            else:
                nlayers = 1
                out["lmassfractions"] = []
        else:
            nlayers = 1
            out["lmassfractions"] = []

        if len(out["lmassfractions"]) == 0:
            out["lmassfractions"] = [out["massfractions"]]

        # Group rates:
        #   grouprate = solidangle/(4.pi).sum_i[massfrac_i.grouprate_i]   (i loops over the layers)
        out["rates"] = {}  # Ifluo / (Flux.time)
        safrac = addinfo["SolidAngle"]
        # assert(self.sample.geometry.solidangle/(4*np.pi)==addinfo["SolidAngle"])
        # assert(self.flux*self.time==addinfo["I0"])
        for zgroup in out["massfractions"]:
            ele = str(zgroup.element)
            group = str(zgroup.group)
            grouprate = 0.0
            for layer in range(1, nlayers + 1):
                if ele in self.mcafit._fluoRates[layer]:
                    massfrac_l = self.mcafit._fluoRates[layer][ele]["mass fraction"]
                    grouprate_l = self.mcafit._fluoRates[layer][ele]["rates"][
                        "{} xrays".format(group)
                    ]
                    grouprate += massfrac_l * grouprate_l
            grouprate *= safrac
            out["rates"][zgroup] = grouprate

        # Fitted areas (elements)
        out["fitareas"] = {
            element.Element.fluozgroup(k): v for k, v in conresult["fitarea"].items()
        }

        # Fitted areas (scatter)
        scatterpeaks = {
            "Compton": {"energy": [], "fitarea": []},
            "Rayleigh": {"energy": [], "fitarea": []},
        }
        nen = len(instance.asarray(digestedresult["energy"]))
        for k, v in digestedresult.items():
            if k.startswith("Scatter"):
                if "Compton" in k:
                    peak = "Compton"
                else:
                    peak = "Rayleigh"
                energy, fitarea = zip(
                    *[(v[k2]["energy"], v[k2]["fitarea"]) for k2 in v["peaks"]]
                )
                scatterpeaks[peak]["energy"] += energy
                scatterpeaks[peak]["fitarea"] += fitarea
        for peak in scatterpeaks:
            energy = np.array(scatterpeaks[peak]["energy"])
            fitarea = np.array(scatterpeaks[peak]["fitarea"])
            if peak == "Compton":
                k = xrayspectrum.ComptonLine(energy)
            else:
                k = xrayspectrum.RayleighLine(energy)
            out["fitareas"][k] = fitarea

        # Fitted rates
        out["fitrates"] = {k: v / addinfo["I0"] for k, v in out["fitareas"].items()}

        # self._print_pymcainternals_rates()
        return out

    def _pymcainternals_solidanglefrac(self):
        radius2 = self.mcafit.config["concentrations"]["area"] / np.pi
        distance = self.mcafit.config["concentrations"]["distance"]
        return 0.5 * (1.0 - (distance / np.sqrt(distance**2 + radius2)))

    def _print_pymcainternals_rates(self):
        safrac = self._pymcainternals_solidanglefrac()

        rowfmt = "{:>6}{:>8}{:>20}{:>10}{:>10}{:>20}"
        print(rowfmt.format("Layer", "Element", "MassFrac", "Line", "Energy", "Rate"))
        for i, layer in enumerate(self.mcafit._fluoRates):
            if i == 0:
                continue
            for ele in sorted(layer):
                lines = []
                for k, v in layer[ele].items():
                    if k.endswith("xrays"):
                        lines.extend(v)
                for line in lines:
                    w = layer[ele]["mass fraction"]
                    rate = layer[ele][line]["rate"] * w * safrac
                    energy = layer[ele][line]["energy"]
                    if rate > 0:
                        print(rowfmt.format(i - 1, ele, w, line, energy, rate))

    def miscfromfitresult(self, digestedresult, out=None):
        if out is None:
            out = {}
        out["chisq"] = digestedresult["chisq"]
        return out

    def spectrafromfitresult(self, digestedresult, out=None):
        conresult, addinfo = self.processfitresult(
            digestedresult, originalconcentrations=True
        )

        # Group rates:
        if False:
            # TODO: set rates of elements not in matrix to zero
            out["rates"] = {}
            for group in out["area"]:
                out["rates"][element.fluozgroup(group)] = (
                    conresult["area"][group] / addinfo["I0"]
                )

        # Matrix spectrum
        nparams = len(digestedresult["parameters"])
        ngroups = len(digestedresult["groups"])
        nglobal = nparams - ngroups
        parameters = list(digestedresult["fittedpar"])
        for i, group in enumerate(digestedresult["groups"]):
            if group in conresult["area"]:
                # Replace fitted with theoretical peak area
                parameters[nglobal + i] = conresult["area"][group]
            else:
                # Scattering peaks don't have a theoretical peak area
                parameters[nglobal + i] = 0.0
        ymatrix = self.mcafit.mcatheory(parameters, digestedresult["xdata"])

        yback = digestedresult["yback"]  # polynomial + snip
        ysnip = digestedresult["ysnip"]

        def interpol(x, spectrum):
            return scipy.interpolate.interp1d(
                x,
                spectrum,
                kind="nearest",
                bounds_error=False,
                fill_value=(spectrum[0], spectrum[-1]),
            )

        def interpol_energy(prof):
            return interpol(digestedresult["energy"], prof)

        def interpol_channel(prof):
            return interpol(digestedresult["xdata"], prof)

        if out is None:
            out = {}
        out["energy"] = digestedresult["energy"]
        out["channels"] = digestedresult["xdata"]
        out["y"] = digestedresult["ydata"]
        out["yfit"] = digestedresult["yfit"]
        out["yback"] = yback
        out["interpol_energy"] = interpol_energy
        out["interpol_channel"] = interpol_channel
        out["ypileup"] = digestedresult["pileup"]
        # polynomial is already in ymatrix, snip not
        out["ymatrix"] = ymatrix + ysnip

        def _plot(ylog=False, label="data"):
            plt.plot(out["energy"], out["y"], "+", label=label)
            plt.plot(out["energy"], out["yfit"], label=label + " fit")
            plt.plot(out["energy"], out["ymatrix"], label=label + " matrix")
            plt.plot(out["energy"], out["yback"], label=label + " background")
            if ylog:
                plt.gca().set_yscale("log", basey=10)
            plt.legend()
            plt.xlabel("MCA (keV)")
            plt.ylabel("Counts")

        out["plot"] = _plot

        return out

class PymcaHandle(PymcaBaseHandle):
    """Class that converts spectrocrunch to pymca parameters
    and vice versa. Also used to call the pymca fitting
    API for single spectra.
    """

    def __init__(
        self,
        sample=None,
        emin=None,
        emax=None,
        energy=None,
        weights=None,
        scatter=None,
        flux=1e9,
        time=0.1,
        escape=True,
        pileup=False,
        ninteractions=1,
        linear=False,
        snip=True,
        continuum=0,
        SingleLayerStrategy=None,
        noisepropagation=True,
    ):
        self.sample = sample
        self.set_source(energy=energy, weights=weights, scatter=scatter)
        self.emin = emin
        self.emax = emax
        self.linear = linear
        self.escape = escape
        self.pileup = pileup
        self.snip = snip
        self.continuum = continuum
        self.noisepropagation = noisepropagation
        self.ninteractions = ninteractions
        self.SingleLayerStrategy = SingleLayerStrategy
        self.flux = flux
        self.time = time
        super(PymcaHandle, self).__init__()

    def __str__(self):
        s = zip(
            instance.asarray(self.energy),
            instance.asarray(self.weights),
            instance.asarray(self.scatter),
        )
        s = "\n ".join(
            "{} keV: {} % (Scatter: {})".format(k, v * 100, sc) for k, v, sc in s
        )
        if self.sample:
            sample = str(self.sample)
            geometry = str(self.sample.geometry)
        else:
            sample = geometry = None
        return "Flux = {:~e}\nTime = {:~}\nSource lines:\n {}\n{}\n{}".format(
            self.flux, self.time, s, sample, geometry
        )

    def set_source(self, energy=None, weights=None, scatter=None):
        if energy is None:
            return
        self.energy = units.umagnitude(energy, "keV")
        if weights is None:
            self.weights = np.ones_like(self.energy)
        else:
            self.weights = weights
        if scatter is None:
            self.scatter = np.ones_like(self.energy)
        elif isinstance(scatter, bool):
            if scatter:
                self.scatter = np.ones_like(self.energy)
            else:
                self.scatter = np.zeros_like(self.energy)
        else:
            self.scatter = scatter

    @property
    def flux(self):
        return self._flux

    @flux.setter
    def flux(self, value):
        self._flux = units.Quantity(value, "Hz").to("Hz")

    @property
    def time(self):
        return self._time

    @time.setter
    def time(self, value):
        self._time = units.Quantity(value, "s").to("s")

    @property
    def I0(self):
        return (self.flux * self.time).to("dimensionless").magnitude

    @property
    def emax_strict(self):
        return np.max(self.energy)

    @property
    def emax(self):
        if self._emax is None:
            # include elastic scattering peaks
            p = np.max(self.energy)
            if self.sample:
                s = np.sqrt(self.sample.geometry.detector.gaussianVAR(p))
            else:
                s = 0.1
            return p + 3 * s
        else:
            return self._emax

    @emax.setter
    def emax(self, value):
        self._emax = value

    @property
    def emin(self):
        if self._emin is None:
            # include Al-K lines
            p = xraylib.LineEnergy(13, xraylib.KL3_LINE)
            if self.sample:
                s = np.sqrt(self.sample.geometry.detector.gaussianVAR(p))
            else:
                s = 0.1
            return p - 3 * s
        else:
            return self._emin

    @emin.setter
    def emin(self, value):
        self._emin = value

    def addtopymca_lstsq(self, cfg):
        cfg["fit"]["maxiter"] = 500

    def addtopymca_beam(self, cfg):
        # TODO: move to source?
        cfg["fit"]["energy"] = instance.asarray(self.energy).tolist()
        cfg["fit"]["energyweight"] = instance.asarray(self.weights).tolist()
        cfg["fit"]["energyscatter"] = (
            instance.asarray(self.scatter).astype(int).tolist()
        )
        cfg["fit"]["energyflag"] = np.ones_like(
            cfg["fit"]["energy"], dtype=int
        ).tolist()
        cfg["fit"]["scatterflag"] = int(any(cfg["fit"]["energyscatter"]))

        # Not just the source:
        cfg["concentrations"]["flux"] = self.flux.to("Hz").magnitude
        cfg["concentrations"]["time"] = self.time.to("s").magnitude

    def loadfrompymca_beam(self, cfg):
        ind = np.asarray(cfg["fit"]["energyflag"], dtype=bool).tolist()

        self.energy = instance.asarray(cfg["fit"]["energy"])
        self.energy = self.energy[ind].astype(float)
        self.weights = np.asarray(cfg["fit"]["energyweight"], dtype=float)
        self.weights = self.weights[ind]
        self.scatter = np.asarray(cfg["fit"]["energyscatter"], dtype=int)
        self.scatter = self.scatter[ind]
        self.flux = cfg["concentrations"]["flux"]
        self.time = cfg["concentrations"]["time"]

    def addtopymca_background(self, cfg):
        # bmodelbkg = self.sample.geometry.detector.bstail or \
        #            self.sample.geometry.detector.bltail or \
        #            self.sample.geometry.detector.bstep
        cfg["fit"]["stripflag"] = int(self.snip)
        cfg["fit"]["stripalgorithm"] = 1
        cfg["fit"]["snipwidth"] = 100
        cfg["fit"]["continuum"] = int(self.continuum)

    def loadfrompymca_background(self, cfg):
        self.snip = bool(cfg["fit"]["stripflag"])
        self.continuum = int(cfg["fit"]["continuum"])

    def addtopymca_other(self, cfg):
        cfg["fit"]["escapeflag"] = int(self.escape)
        cfg["fit"]["sumflag"] = int(self.pileup)
        cfg["fit"]["linearfitflag"] = int(self.linear)
        cfg["concentrations"]["usemultilayersecondary"] = self.ninteractions - 1
        cfg["fit"]["fitweight"] = int(self.noisepropagation)

    def addtopymca_custom(self, cfg):
        pass

    def addcustomnpymcamethod(self, method):
        self.addtopymca_custom = MethodType(method, self)

    def addtopymca_strategy(self, cfg):
        strategy = "SingleLayerStrategy"
        dic = getattr(self, strategy)
        if dic:
            dic = dict(dic)
            cfg["fit"]["strategy"] = strategy
            cfg["fit"]["strategyflag"] = 1
            if strategy not in cfg:
                cfg[strategy] = {}
                cfg[strategy]["layer"] = "Auto"
                cfg[strategy]["iterations"] = 3

            def func(mat):
                return mat if instance.isstring(mat) else mat.pymcaname

            cfg[strategy]["completer"] = func(dic.pop("completer", "-"))
            dic2 = {}
            for el, mat in dic.items():
                if el in cfg["peaks"]:
                    k = "{} {}".format(el, sorted(cfg["peaks"][el])[0])
                    dic2[k] = func(mat)
            cfg[strategy]["peaks"] = dic2.keys()
            cfg[strategy]["materials"] = dic2.values()
            cfg[strategy]["flags"] = [1] * len(dic2)
        else:
            cfg["fit"]["strategyflag"] = 0

    def loadfrompymca_other(self, cfg):
        self.escape = bool(cfg["fit"]["escapeflag"])
        self.pileup = bool(cfg["fit"]["sumflag"])
        self.linear = bool(cfg["fit"]["linearfitflag"])
        self.ninteractions = cfg["concentrations"]["usemultilayersecondary"] + 1
        self.noisepropagation = bool(cfg["fit"]["fitweight"])

    def addtopymca_material(self, cfg, material, defaultthickness=1e-4):
        return material.topymca(cfg, defaultthickness=defaultthickness)

    def loadfrompymca_material(self, cfg, matname, density):
        formula = re.compile("^(([A-Z][a-z]?)([0-9]*))+$")
        purelement = re.compile("^(?P<element>[A-Z][a-z]?)1?$")

        # Material name is a formula:
        name = mixture.Mixture.namefrompymca(matname)
        mf = formula.match(name)
        if mf:
            me = purelement.match(name)
            if me:
                return element.Element(me.groupdict()["element"])
            else:
                return compoundfromformula.CompoundFromFormula(name, density)

        # Parse material info:
        dic = cfg["materials"][matname]
        if not instance.isarray(dic["CompoundList"]):
            dic["CompoundList"] = [dic["CompoundList"]]
        if not instance.isarray(dic["CompoundFraction"]):
            dic["CompoundFraction"] = [dic["CompoundFraction"]]
        massfractions = np.array(dic["CompoundFraction"]) / sum(dic["CompoundFraction"])
        density = dic["Density"]

        # List of materials:
        lst = [
            self.loadfrompymca_material(cfg, mat, density)
            for mat in dic["CompoundList"]
        ]

        # All elements:
        if all([isinstance(e, element.Element) for e in lst]):
            return compoundfromlist.CompoundFromList(
                lst, massfractions, types.fraction.mass, density, name=name
            )
        else:
            return mixture.Mixture(lst, massfractions, types.fraction.mass, name=name)

    def loadfrompymca(self, filename=None, config=None):
        """Update pymca parameters and convert to spectrocrunch"""
        super(PymcaHandle, self).loadfrompymca(filename=filename, config=config)
        config = self.mcafit.getConfiguration()
        self.loadfrompymca_beam(config)
        self.loadfrompymca_background(config)
        self.loadfrompymca_other(config)
        self.sample.loadfrompymca(self, config)

    def addtopymca(self, fresh=False, onlygeometry=False):
        """Convert spectrocrunch to pymca parameters"""
        if fresh:
            config = self.mcafit.getStartingConfiguration()
            config["attenuators"] = {}
            try:
                self.mcafit.useFisxEscape(True)
            except:
                pass
            self.mcafit.disableOptimizedLinearFit()
        else:
            config = self.mcafit.getConfiguration()

        if onlygeometry:
            self.sample.geometry.addtopymca(self, config)
        else:
            self.addtopymca_beam(config)
            self.addtopymca_background(config)
            self.addtopymca_lstsq(config)
            self.addtopymca_other(config)
            self.sample.addtopymca(self, config)
            self.addtopymca_strategy(config)
        self.addtopymca_custom(config)
        self.mcafit.configure(config)

    def configurepymca(self, **kwargs):
        """Convert spectrocrunch to pymca parameters"""
        self.addtopymca(**kwargs)

    def savepymca(self, filename):
        """Convert spectrocrunch to pymca parameters and then save"""
        self.configurepymca()
        super(PymcaHandle, self).savepymca(filename)

    @contextlib.contextmanager
    def fitenergy_context(self):
        # Keep original config
        self.configurepymca()
        config = self.mcafit.getConfiguration()
        keep = self.emin, self.emax, self.energy

        # Change config (extend emin and emax)
        emin = np.min(self.energy)
        line = xrayspectrum.ComptonLine(emin)
        emin = line.energy(polar=np.pi)
        s = np.sqrt(self.sample.geometry.detector.gaussianVAR(emin))
        emin = min(keep[0], emin - 5 * s)
        emin = max(emin, 0)

        emax = np.max(self.energy)
        s = np.sqrt(self.sample.geometry.detector.gaussianVAR(emax))
        emax = max(keep[1], emax + 3 * s)

        self.emin, self.emax = emin, emax
        self.configurepymca()

        yield

        # Reset config
        self.emin, self.emax, self.energy = keep
        self.mcafit.configure(config)
        self.configurepymca()

    def fitenergy(self, plot=False):
        with self.fitenergy_context():
            # Fit reduced range
            result = self.fit()
            if plot:
                plt.plot(result["energy"], result["y"], label="data")
                plt.plot(result["energy"], result["yfit"], label="pymca fit")
                plt.legend()
                plt.show()

            config = self.mcafit.getConfiguration()

            # Repeat fit
            def func(params):
                params = instance.asarray(params)
                self.energy = params[:-1]
                self.sample.geometry.angleout = params[-1]
                self.configurepymca()

                self.mcafit.configure(config)

                fitresult, digestedresult = self.mcafit.startfit(digest=1)
                return digestedresult["yfit"] - digestedresult["ydata"]

            guess = instance.asarray(self.energy).tolist()
            guess.append(self.sample.geometry.angleout)

            params, success = scipy.optimize.leastsq(func, guess)

        success = success > 0 and success < 5
        if success:
            params = instance.asarray(params)
            self.energy = params[:-1]
            self.sample.geometry.angleout = params[-1]
            self.configurepymca()

    def xrayspectrum(self, **kwargs):
        return self.sample.xrayspectrum(
            self.energy,
            emin=self.emin,
            emax=self.emax,
            weights=self.weights,
            ninteractions=self.ninteractions,
            **kwargs
        )

    def xraygrouprates(self, **kwargs):
        spectrum = self.xrayspectrum(**kwargs)
        groups = spectrum.linegroups(convert=True)
        pattern = "^(?P<element>[A-Z][a-z]?)-(?P<group>[A-Z]).?$"
        groups2 = {}
        for k in groups:
            m = re.match(pattern, k)
            if m:
                m = m.groupdict()
                g = "{}-{}".format(m["element"], m["group"])
                A = sum(groups[k].values())
                if g in groups2:
                    groups2[g] += A
                else:
                    groups2[g] = A
            else:
                groups2[k] = sum(groups[k].values())

        return groups2

    def xraygroupareas(self, **kwargs):
        return {k: v * self.I0 for k, v in self.xraygrouprates(**kwargs).items()}

    def mca(self, histogram=True, decomposed=0, energy=False, full=False, **kwargs):
        spectrum = self.xrayspectrum(**kwargs)
        if decomposed == 0:
            x, y, ylabel = spectrum.sumspectrum(fluxtime=self.I0, histogram=histogram)
        elif decomposed == 1:
            x, y, ylabel = spectrum.peakspectrum(
                fluxtime=self.I0, histogram=histogram, group=True
            )
        else:
            x, y, ylabel = spectrum.peakspectrum(
                fluxtime=self.I0, histogram=histogram, group=False
            )
        if not energy:
            a, b = spectrum.channellimits
            nchan = int(2 ** np.ceil(np.log2(b + 1)))
            mca = np.zeros(nchan, dtype=y.dtype)
            mca[a : b + 1] = y
            y = mca
            x = np.arange(nchan)
        if full:
            return x, y, ylabel
        else:
            return y

    def savemca(self, filename, mode="w", func=None, **kwargs):
        y = self.mca(**kwargs)
        if instance.iscallable(func):
            y = func(y)
        savemca(
            y,
            filename,
            mode=mode,
            zero=self.sample.geometry.detector.mcazero,
            gain=self.sample.geometry.detector.mcagain,
        )

class FisxConfig:

    FISXMATERIALS = None

    def init(self):
        if self.FISXMATERIALS is None:
            self.FISXMATERIALS = fisx.Elements()
            self.FISXMATERIALS.initializeAsPyMca()

    @contextlib.contextmanager
    def init_ctx(self):
        self.init()
        yield

    def setDetector(self, setup, detector):
        with self.init_ctx():
            detector.addtofisx(setup, self.FISXMATERIALS)

    def addtofisx_material(self, material, defaultthickness=1e-4):
        with self.init_ctx():
            return material.tofisx(
                self.FISXMATERIALS, defaultthickness=defaultthickness
            )


import numpy as np
import matplotlib.pyplot as plt

from matplotlib.colors import LogNorm
from mpl_toolkits.axes_grid1 import make_axes_locatable
from psana.pop.POP import POP
import pickle
from psana import DataSource

runinfo_data = {'expt': 'amox27716', 'runnum': 101}
fnm = '/reg/d/psdm/AMO/amox27716/results/xiangli/pop_files/pop_raw_imgs.xtc2'

ds = DataSource(files = fnm)
run = next(ds.runs())
camera = run.Detector('opal')
calib_dict, _ = camera.calibconst.get('pop_rbfs')

accum_num = 30
normalizeDist = True
pop = POP(lmax=4,reg=0,alpha=4e-4,img=None,X0=512,Y0=512,Rmax=512,RBFs_dict = calib_dict,RBFs_fnm=None,edge_w=10)

img = np.zeros((1024,1024))
fig = plt.figure(figsize=(12,15))
plt.ion()
for nevt,evt in enumerate(run.events()):
    if nevt>150:
        break
    if nevt < 2:
        continue
    img += evt._dgrams[0].opal[0].raw.img
    if (nevt%30==0):
        print('event num:',nevt,', starting peeling')
        pop.Peel(img)
        slice_img = pop.GetSlice()
        rbins,DistR = pop.GetRadialDist()
        Ebins,DistE = pop.GetEnergyDist()
        print('peeling completed at event num',nevt)
        fig.clf()

        plt.subplot(3,2,1)
        im = plt.imshow(img+1,extent=[0,1024,0,1024],norm=LogNorm(vmin=1, vmax=img.max()+1))

        ax = plt.gca()
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=0.05)
        plt.colorbar(im, cax=cax)
        ax.set_title('Raw VMI image')
        ax.set_xlabel('X (pixel)')
        ax.set_ylabel('Y (pixel)')

        plt.subplot(3,2,2)
        im = plt.imshow(slice_img,extent=[0,1024,0,1024])
        ax = plt.gca()
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=0.05)
        plt.colorbar(im, cax=cax)
        ax.set_title('3D slice (inverted image)')
        ax.set_xlabel('X (pixel)')
        ax.set_ylabel('Y (pixel)')

        plt.subplot(3,1,2)
        if normalizeDist:
            plt.plot((rbins[1:]+rbins[:-1])/2,DistR/DistR.max(),'r')
            plt.ylim([0,1])
        else:
            plt.plot((rbins[1:]+rbins[:-1])/2,DistR,'r')
        plt.xlim([0,520])

        plt.title('Radial Distribution')
        plt.xlabel('Radius (pixel)')
        plt.ylabel('Yield (arb. units)')

        plt.subplot(3,1,3)
        if normalizeDist:
            plt.plot((Ebins[1:]+Ebins[:-1])/2,DistE/DistE.max(),'r')
            plt.ylim([0,1])
        else:
            plt.plot((Ebins[1:]+Ebins[:-1])/2,DistE,'r')
        plt.title('Energy Distribution')
        plt.xlabel('Energy (eV)')
        plt.ylabel('Yield (arb. units)')
        plt.show()
        plt.pause(0.5)

        img = np.zeros((1024,1024))

fig.savefig("pop_example_xtc2_plot.pdf", bbox_inches='tight')
print('Last plots saved to "pop_example_plot.pdf".')


from solution4 import *
import unittest

class TestSolutionMethods(unittest.TestCase):

    def test_reshape_empty(self):
        cases = [('0 by * -> 0 by *', True, 0, 5, []),
                 ('1 by 0 -> 0 by *', False, 0, 6, []),
                 ('1 by 0 -> 3 by 0', False, 3, 0, [[], [], []])
                ]
        for description, orig_empty_rows, new_rows, new_cols, true_matrix in cases:
            print('Testing _reshape_empty()', description)
            computed_matrix = Solution._reshape_empty(orig_empty_rows, new_rows, new_cols)
            self.assertEqual(computed_matrix, true_matrix)

    def test_matrixReshape(self):
        cases = [('0 by * -> 3 by 0', [], 3, 0, [[], [], []]),
                 ('2 by 0 -> 0 by 2', [[], []], 0, 2, []),
                 ('2 by 3 -> 3 by 2', [[1, 2, 3], [4, 5, 6]], 3, 2, [[1, 2], [3, 4], [5, 6]]),
                 ('2 by 3 -> 1 by 4', [[1, 2, 3], [4, 5, 6]], 1, 4, [[1, 2, 3], [4, 5, 6]]),
                 ('2 by 3 -> 1 by 6', [[1, 2, 3], [4, 5, 6]], 1, 6, [[1, 2, 3, 4, 5, 6]]),
                 ('2 by 3 -> 6 by 1', [[1, 2, 3], [4, 5, 6]], 6, 1, [[1], [2], [3], [4], [5], [6]]) ]

        for description, original, new_row, new_col, true_reshape in cases:
            print('Testing matrixReshape()', description)
            computed_reshape = Solution().matrixReshape(original, new_row, new_col)
            self.assertEqual(computed_reshape, true_reshape)

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


from django import template

register = template.Library()

@register.filter(name='getByKey')
def getByKey(d, key):
    return d.get(key)

#func from https://stackoverflow.com/questions/401025/define-css-class-in-django-forms/41129192#41129192
@register.filter(name='addclass')
def addclass(field, given_class):
    existing_classes = field.field.widget.attrs.get('class', None)
    if existing_classes:
        if existing_classes.find(given_class) == -1:
            # if the given class doesn't exist in the existing classes
            classes = existing_classes + ' ' + given_class
        else:
            classes = existing_classes
    else:
        classes = given_class
    return field.as_widget(attrs={"class": classes})


import warnings
import math
import random
import scipy.optimize

def make_optimizer(config, f, save, status):
    return NelderMead(config, f, save=save, status=status)

def dumb_callback(x):
    print('-> Dumb Callback:', x)

'''
Optimization with Nelder Mead method (simplex)
'''
class NelderMead:
    def __init__(self, config, f, save=None, status=None):
        self.check_config(config)
        self.config = config
        self.save = save
        local_config = {}
        # self.n_jobs = self.config.n_jobs
        if self.config.old_type:
            self.pnames  = self.config.pnames
            self.msteps  = self.config.msteps
            self.base    = self.config.pinits
            self.in_real = self.config.in_real
            # All dimensions are integers in our case, but we can optimize in real (more noise)
            # Here we will consider the scale as the +/- range from the initial value
            dimensions = []
            x0 = []
            if type(self.config.pscale) == list:
                for pi, si in zip(self.config.pinits, self.config.pscale):
                    x0.append(pi)
                    start = pi - si
                    end   = pi + si
                    dimensions.append((start, end))
            else:
                for pi, si, ei in zip(self.config.pinits, self.config.pmin, self.config.pmax):
                    x0.append(pi)
                    dimensions.append((si, ei))
            games       = self.config.games
            simul       = self.config.simul
            texel       = self.config.texel
        else:
            self.pnames  = list(map(lambda p: p.name, self.config.optimization.params))
            self.msteps  = self.config.optimization.msteps
            self.base    = list(map(lambda p: p.ini, self.config.optimization.params))
            self.in_real = self.config.optimization.in_real
            # All dimensions are integers in our case, but we can optimize in real (more noise)
            # Here we will consider the scale as the +/- range from the initial value
            dimensions = []
            x0 = []
            for param in self.config.optimization.params:
                x0.append(param.ini)
                dimensions.append((param.min, param.max))
            games       = self.config.eval.params.games
            simul       = self.config.eval.type == 'simul'
            texel       = self.config.eval.type == 'texel'

        self.done = False
        if status is None:
            # When we start, we know that the initial point is the reference, mark it with 0
            # Unless for texel or simulation!
            if texel or simul:
                self.theta = None
                self.best = None
                self.xi = []
                self.yi = []
            else:
                self.theta = x0
                self.best = 0
                self.xi = [ x0 ]
                self.yi = [ 0 ]
                self.optimizer.tell(x0, 0)
        else:
            self.theta = status['theta']
            self.best = status['best']
            self.xi = status['xi']
            self.yi = status['yi']
            # Here: because we maximize (while the bayes optimizer minimizes), negate!
            self.optimizer.tell(self.xi, list(map(lambda y: -y, self.yi)))
        # Because we added the reference result, we have now one measurement more than steps
        self.step = len(self.xi)
        def minfun(x):
            return -f(x)
        self.func = minfun
        self.x0 = x0
        self.dimensions = dimensions
        # self.method = 'Nelder-Mead'
        self.method = 'Powell'

    '''
    Serialize (JSON) the changing parts of our optimizer.
    We save only what is needed to restore the state.
    For example we do not save the step, as this can be restored from the length of the xi.
    We also do not save the bayesian optimizer itself, but reconstruct it
    from the xi and yi that we save.
    '''
    def get_status(self):
        return {
            'theta': self.theta,
            'best': self.best,
            'xi': self.xi,
            'yi': self.yi
        }

    '''
    Maximize by gaussian process
    The callback is called after every step
    It is called with the BayesOptimizer object and it must return True
    if the optimization has to be stopped immediately
    '''
    def optimize(self, callback):
        print(f'Dimensions: {len(self.x0)}')
        if self.method == 'Nelder-Mead':
            options = { 'disp': True, 'maxfev': self.msteps, 'adaptive': True, 'xtol': 0.49 }
        else:
            options = { 'disp': True, 'maxiter': self.msteps, 'xtol': 0.49 }
        return scipy.optimize.minimize(self.func, self.x0, method=self.method, options=options, callback=dumb_callback)

    def report(self, vec, title=None, file='report.txt'):
        if title is None:
            title = 'Current best:'
        if file is None:
            print(title)
            print(vec)
            for n, v in zip(self.pnames, list(vec.x)):
                print(n, '=', v)
        else:
            with open(file, 'w', encoding='utf-8') as repf:
                print(title, file=repf)
                for n, v in zip(self.pnames, list(vec.x)):
                    print(n, '=', v, file=repf)

    '''
    We check here all entries on the config that we need, if the config is new style
    The old style checks all required values or delivers defaults for optional parameters
    '''
    def check_config(self, config):
        if config.old_type:
            assert config.check('pscale', vtype=list) \
                or config.check('pmin', vtype=list) and config.check('pmax', vtype=list)
        else:
            assert config.check('optimization.params', vtype=list, required=True)
            for param in config.optimization.params:
                assert type(param.name) == str
                assert type(param.ini) == int
                assert type(param.min) == int
                assert type(param.max) == int
            # self.n_jobs = config.n_jobs
            assert config.check('eval.type', vtype=str, required=True)
            if config.old_type and config.simul == 0.0 or not config.old_type and config.eval.type == 'selfplay':
                assert config.check('eval.params.games', vtype=int, required=True)
                assert config.check('eval.params.elo', vtype=bool, required=True)

# vim: tabstop=4 shiftwidth=4 expandtab


import matplotlib.pyplot as plt
from PIL import Image

black = (0, 0, 0)
white = (255, 255, 255)
gray = (149, 149, 149)
red = (255, 0, 0)

blue = (0, 255, 255)

def get_neighbours(grid, xy):
	x = xy[0]
	y = xy[1]
	width = grid.width
	height = grid.height
	to_return = []

	for i in [-1, 0, 1]:
		for j in [-1, 0, 1]:
			if i == 0 and j == 0:
				continue
			if x + i < 0 or x + i >= width:
				continue
			if y + j < 0 or y + j >= height:
				continue
			new_xy = (x + i, y + j)
			to_return.append((new_xy, grid.getpixel(new_xy)))
	return to_return

def print_neighbours(grid, n):
	for point in n:
		grid.putpixel(point[0], blue)

def print_path(grid, list):
	for point in list:
		grid.putpixel(point, red)


import sys
from collections import deque
sys.setrecursionlimit(10**6)
input = sys.stdin.readline

def dfs(start_node):
    dfs_results.append(start_node)
    visited[start_node] = True
    nodes = li[start_node]
    for n in nodes:
        if visited[n] == False:
            dfs(n)

n, m = map(int, input().split())
li = [[] for _ in range(n)]
visited = [False for _ in range(n)]
for _ in range(m):
    u, v = map(int, input().split())
    li[u-1].append(v-1)
    li[v-1].append(u-1)

cnt = 0
for i in range(n):
    dfs_results = []
    if visited[i] == False:
        dfs(i)
        cnt += 1
print(cnt)


# -*- coding: utf-8 -*-
"""A setuptools based module for the NIVA tsb module/application.
"""

from setuptools import setup, find_packages
from codecs import open
from os import path

here = path.abspath(path.dirname(__file__))

# get the version from the __version__.py file
version_dict = {}
with open(path.join(here, 'src', 'qclib', '__version__.py')) as f:
    exec(f.read(), version_dict)

# Get the long description from the README.md file
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
    long_description = f.read()

setup(
    name='nivacloud-qclib',

    # Versions should comply with PEP440.  For a discussion on single-sourcing
    # the version across setup.py and the project code, see
    # https://packaging.python.org/en/latest/single_source_version.html
    version=version_dict['__version__'],
    description="Module containing QC tests",
    long_description=long_description,

    # The project's main homepage.
    url='https://github.com/NIVANorge/qclib',

    # Author details
    author='Pierre Jaccard, Elizaveta Protsenko, Zofia Rudjord',
    author_email='pja@niva.no, elizaveta.protsenko@niva.no, zofia.rudjord@niva.no',

    # Choose your license
    license='Owned by NIVA',

    # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
    classifiers=[
        # How mature is this project? Common values are
        #   0 - Alpha
        #   1 - Beta
        #   2 - Production/Stable
        'Development Status :: 4 - Beta',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        # 'Topic :: Data Access :: Time Series',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: MIT License',

        'Programming Language :: Python :: 3',
    ],

    keywords='data quality tests',
    packages=find_packages(where="src"),
    package_dir={'': 'src'},
    install_requires=[
        'pandas>=1.1,<2.0',
        'numpy>=1.16,<2.0',
        'pydantic>=1.0,<2.0',
        'matplotlib>=3.0,<4.0'
    ],
    extras_require={
      "test": [
          "pytest"
      ]
    },
    test_suite='tests',
)


# TODO: optional: add more state

import pygame as pg
from GridCell import *
from Shape import *
import random
import numpy as np
import time

MOVEMENT_PUNISHMENT = -1
INVALID_MOVEMENT_PUNISHMENT = -10
INVALID_PLACEMENT_PUNISHMENT = -10
LOSE_PUNISHMENT = 0
REWARD_PLACEMENT = 10

class Space:

    def __init__(self, n, sample):
        self.n = n
        self.sampleV = sample

    def sample(self):
        return self.sampleV

class Blockudoku:

    def __init__(self):
        self.screen = None
        self.window_size = pg.Vector2(450, 700)
        self.board_loc = pg.Vector2(1, 90)
        self.board_size = pg.Vector2(self.window_size.x - 2, self.window_size.x)
        self.cell_size = self.window_size.x // 9
        self.grid = []
        self.score = 0
        self.cleared_recently = False
        self.lost = False
        self.state = np.zeros((9, 9, 2))

        for r in range(9):
            self.grid.append([])
            for c in range(9):
                self.grid[r].append(GridCell(r, c))

        self.current_shape = Shape()
        self._calculateState()

        self.action_space = Space(5, 0)
        self.observation_space = Space(2 ** len(self.state), self.state)

        # possible states:
        # * invalid cells
        # * blocks that will be cleared if shape is placed
        # * cells' boarders

    def seed(self, seed):
        random.seed(seed)

    def setScreen(self, screen):
        self.screen = screen

    def reset(self):
        self.score = 0
        self.cleared_recently = False
        self.lost = False
        self.current_shape = Shape()
        for row in range(9):
            for col in range(9):
                self.grid[row][col].empty = True
        self.state = np.zeros(self.state.shape)
        self._calculateState()
        return self.state

    def play(self):
        running = True

        for event in pg.event.get():
            if event.type == pg.QUIT:
                running = False

            if event.type == pg.KEYDOWN:
                if event.key == pg.K_r:
                    self.reset()
                if event.key == pg.K_SPACE:
                    self.step(0)
                if event.key == pg.K_RIGHT:
                    self.step(1)
                if event.key == pg.K_DOWN:
                    self.step(2)
                if event.key == pg.K_LEFT:
                    self.step(3)
                if event.key == pg.K_UP:
                    self.step(4)

        self.screen.fill((255, 255, 255))

        self._drawCells(self.screen, self.grid, self.cell_size, self.board_loc)
        self.current_shape.draw(self.screen, self.board_loc, self.cell_size, self.grid)
        self._drawBorders(self.screen, self.cell_size, self.board_loc, self.board_size)
        self._displayScore(self.screen)

        pg.display.flip()

        return running

    def render(self, mode='human'):
        board = np.zeros((9, 9))

        for row in range(9):
            for col in range(9):
                if not self.grid[row][col].empty:
                    board[row][col] = 1

        for block in self.current_shape.blocks:
            b_row = self.current_shape.row + block[0]
            b_col = self.current_shape.col + block[1]
            if board[b_row][b_col] == 0:
                board[b_row][b_col] = 2
            else:
                board[b_row][b_col] = 3

        for row in range(9):
            if row % 3 == 0:
                print("+-----+-----+-----+")
            for col in range(9):
                if col % 3 == 0:
                    print("|", end="")
                else:
                    print(":", end="")
                if board[row][col] == 0:
                    print(" ", end="")
                elif board[row][col] == 1:
                    print("\033[0;30;44m ", end="\033[0;0m")
                elif board[row][col] == 2:
                    print("\033[0;30;42m ", end="\033[0;0m")
                else:
                    print("\033[0;30;41m ", end="\033[0;0m")
            print("|")

        print("+-----+-----+-----+")

        if self.screen is not None:
            self.drawGameHeadless()

    def drawGameHeadless(self):
        running = True

        for event in pg.event.get():
            if event.type == pg.QUIT:
                running = False

        self.screen.fill((255, 255, 255))

        self._drawCells(self.screen, self.grid, self.cell_size, self.board_loc)
        self.current_shape.draw(self.screen, self.board_loc, self.cell_size, self.grid)
        self._drawBorders(self.screen, self.cell_size, self.board_loc, self.board_size)
        self._displayScore(self.screen)

        pg.display.flip()

        return running

    def step(self, action):
        if action == 0:  # place
            valid = self.current_shape.place(self.grid)
            if valid:
                reward = self._blockPlaced() + REWARD_PLACEMENT
            else:
                reward = INVALID_PLACEMENT_PUNISHMENT

        else:
            if action == 1:
                valid = self.current_shape.moveRight()
            elif action == 2:
                valid = self.current_shape.moveDown()
            elif action == 3:
                valid = self.current_shape.moveLeft()
            else:
                valid = self.current_shape.moveUp()

            if valid:
                reward = MOVEMENT_PUNISHMENT
            else:
                reward = INVALID_MOVEMENT_PUNISHMENT

        self._calculateState()
        return self.state, reward, self.lost, {}

    def _calculateState(self):
        # layer 1: filled cells
        for row in range(9):
            for col in range(9):
                if self.grid[row][col].empty:
                    self.state[row][col][0] = 0
                else:
                    self.state[row][col][0] = 1

        # layer 2: current shape
        self.state[:, :, 1] = np.zeros(self.state[:, :, 1].shape)
        for block in self.current_shape.blocks:
            self.state[self.current_shape.row + block[0]][self.current_shape.col + block[1]][1] = 1

    def _scoreBoard(self):
        cleared_blocks = []

        # check for vertical lines
        for row in range(9):
            cleared = True
            for col in range(9):
                if self.grid[row][col].empty:
                    cleared = False
                    break

            if cleared:
                cleared_blocks += self.grid[row]

        # check for horizontal lines
        for col in range(9):
            cleared = True
            for row in range(9):
                if self.grid[row][col].empty:
                    cleared = False
                    break

            if cleared:
                cleared_blocks += [grid_row[col] for grid_row in self.grid]

        # check for cleared squares
        for square_row in range(0, 9, 3):
            for square_col in range(0, 9, 3):
                cleared = True
                for row in range(3):
                    for col in range(3):
                        if self.grid[square_row + row][square_col + col].empty:
                            cleared = False
                            break

                if cleared:

                    for row in range(3):
                        for col in range(3):
                            cleared_blocks.append(self.grid[square_row + row][square_col + col])

        # give score
        reward = 0
        if len(cleared_blocks) > 0:
            if len(cleared_blocks) <= 18:
                reward += len(cleared_blocks) * 2
            else:
                reward += len(cleared_blocks) * 4

            for cleared_block in cleared_blocks:
                cleared_block.empty = True

        return reward

    def _blockPlaced(self):
        reward = 0
        reward += self._scoreBoard()
        if reward > 0:
            if self.cleared_recently:
                reward += 9
            self.cleared_recently = True
        else:
            self.cleared_recently = False

        reward += self.current_shape.remainingBlocks(self.grid)
        self.score += reward

        self.current_shape = Shape()
        if not self.current_shape.validSpaceExists(self.grid):
            self.lost = True
            reward -= LOSE_PUNISHMENT

        return reward

    def _displayScore(self, screen):
        font = pg.font.SysFont(None, 44)
        if self.lost:
            color = (255, 0, 0)
        else:
            color = (0, 0, 0)
        img = font.render('Score: ' + str(self.score), True, color)
        screen.blit(img, (self.window_size.x / 2 - 60, 37))

    def _drawCells(self, screen, grid, cell_size, board_loc):
        for r in range(9):
            for c in range(9):
                grid[r][c].draw(screen, board_loc, cell_size)

    def _drawBorders(self, screen, cell_size, board_loc, board_size):
        color = (0, 0, 0)

        rect = pg.Rect(board_loc.x + cell_size * 3, board_loc.y, cell_size * 3, board_size.y)
        pg.draw.rect(screen, color, rect, 2)
        rect = pg.Rect(board_loc.x, board_loc.y + cell_size * 3, board_size.x, cell_size * 3)
        pg.draw.rect(screen, color, rect, 2)

        rect = pg.Rect(board_loc.x, board_loc.y, board_size.x, board_size.y)
        pg.draw.rect(screen, color, rect, 3)

# game = Blockudoku()
#
# pg.init()
#
# screen = pg.display.set_mode([game.window_size.x, game.window_size.y])
#
# game.seed(69)
# game.setScreen(screen)

# running = True
# while running:
#     running = game.renderText(screen)

# pg.quit()


#Code@home4.5 Base Conversion
from time import sleep
hexcode=["1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
def dec_to_bin(dec):
    if dec==0:
        return 0
    bin=""
    while dec>0:
        remainder=dec%2
        bin=str(remainder)+bin
        dec//=2
    return bin
def bin_to_dec(bin):
    dec=0
    multiplier=1
    for i in range(len(bin)-1,-1,-1):
        if bin[i]=="1":
            dec+=1*multiplier
        multiplier*=2
    return dec

def dec_to_hex(dec):
    hex=""
    while dec>0:
        remainder = dec % 16
        if remainder<=10:
            hex=str(remainder)+hex
        elif remainder==10:
            hex="A"+hex
        elif remainder==11:
            hex="B"+hex
        elif remainder==12:
            hex="C"+hex
        elif remainder==13:
            hex="D"+hex
        elif remainder==14:
            hex="E"+hex
        elif remainder==15:
            hex="F"+hex
        dec=dec//16
    return hex
def hex_to_dec(hex_val):
    dec = 0
    multiplier = 1
    for i in range(len(hex_val)-1, -1, -1):
        hex_digit = hex_val[i]
        if hex_digit.isdigit():
            dec += int(hex_digit) * multiplier
        else:
            dec += (hexcode.index(hex_digit)+1) * multiplier
        multiplier *= 16
    return dec
def bin_to_hex(binnum):
    decnum=bin_to_dec(binnum)
    hexnum=dec_to_hex(decnum)
    return hexnum
def hex_to_bin(hexnum):
    decnum = hex_to_dec(hexnum)
    binnum = dec_to_bin(decnum)
    return binnum
def menu():print("""
1. Base 10 to Base 2
2. Base 2 to Base 10
3. Base 10 to Base 16
4. Base 16 to Base 10
5. Base 2 to Base 16
6. Base 16 to Base 2
7.Quit""")
while True:
    sleep(1)
    menu()
    choice=input("Which do you choose ")
    if choice=="1":
        decnum=int(input("Which base 10 number do you choose "))
        binnum=dec_to_bin(decnum)
        print(f"{decnum} written in base 2 is {binnum}")
    elif choice=="2":
        binnum = input("Which base 2 number do you choose ")
        decnum = bin_to_dec(binnum)
        print(f"{binnum} written in base 10 is {decnum}")
    elif choice=="3":
        decnum = int(input("Which base 10 number do you choose "))
        hexnum = dec_to_hex(decnum)
        print(f"{decnum} written in base 16 is {hexnum}")
    elif choice=="4":
        hexnum = (input("Which base 16 number do you choose "))
        decnum = hex_to_dec(hexnum)
        print(f"{hexnum} written in base 10 is {decnum}")
    elif choice=="5":
        binnum = input("Which base 2 number do you choose ")
        hexnum = bin_to_hex(binnum)
        print(f"{binnum} written in base 16 is {hexnum}")
    elif choice=="6":
        hexnum = input("Which base 16 number do you choose ")
        binnum = hex_to_bin(hexnum)
        print(f"{hexnum} written in base 2 is {binnum}")
    else:
        break


import os
import subprocess

def create_dll(filename):
    """Create DLL file from CUDA (Windows)"""
    proc = subprocess.Popen(f'nvcc -o dependencies/{filename}.dll  -lcublas -lcurand --shared kernels/{filename}.cu')
    out, err = proc.communicate()

create_dll('mat_mul')
create_dll('mat_add')
create_dll('blas_mat_mul')


# Here are all functions that an admin user or other special user should use to manage the library

from database.Database import DatabaseFunctions
from helpers.jsonHandler import jsonHandler
from functions.default.SearchFiles import SearchFiles

# Add the remove, update and insert of the jsonHandler -> Maybe I'll have to create the functions inside the class :(
class Admin:

    def __init__(self) -> None:
        self.database = DatabaseFunctions()
        self.json = jsonHandler()

    def checkAdmin(self, userID) -> int:
        user_type = self.database.getAdmType(userID)
        return user_type

    def getRole(self, role: int) -> dict:
        roles = {
            1: "Dona",
            2: "Administradora"
        }

        return roles[role]

    def getAllAdmin(self) -> dict:
        return self.database.getAllAdm()

    def getBookID(self, bookTitle):
        return self.database.getBookID(bookTitle)

    def addBook(self, bookName: str, author: str, synopsys: str) -> str:
        try:
            self.database.addBook(bookName, author, synopsys)
            return "O livro foi adicionado no banco de dados."
        except RuntimeError as e:
            return f"Não foi possível adicionar o livro no banco de dados. Erro ocorrido: {e}"

    def addBookJson(self, book_title: str, book_author: str, book_id: int, book_command: str, book_gender: str) -> None:
        try:
            value = {
                "ID": book_id,
                "Telegram": f"{book_command} - {book_title} - {book_author}",
                "Name": f"{book_command}"
            }
            self.json.add_key(book_gender, book_title, value)
            return "O livro foi adicionado no banco de dados."
        except RuntimeError as e:
            return f"Não foi possível adicionar o livro no arquivo json. Erro ocorrido: {e}"
        except TypeError as e:
            return f"Não foi possível adicionar o livro no arquivo json. Erro ocorrido: {e}"
        except ValueError as e:
            return f"Não foi possível adicionar o livro no arquivo json. Erro ocorrido: {e}"

    def addBookIMG(self, bookID: int, url: str) -> str:
        try:
            self.database.addBookIMG(bookID, url)
            return "A capa do livro foi adicionada no banco de dados."
        except RuntimeError as e:
            return f"Não foi possível adicionar a capa no banco de dados. Erro ocorrido: {e}"

    def addAdmin(self, userID: int, role: int, name: str) -> str:
        try:
            self.database.addAdm(userID, role, name)
            return "O administrador foi adicionado ao banco de dados."
        except RuntimeError as e:
            return f"Não foi possível adicionar o administrador ao banco de dados. Erro ocorrido: {e}"

    def updateBookName(self, bookID: int, newName: str) -> str:
        try:
            self.database.updateBookName(bookID, newName)
            book_name = self.json.getKeyForSubkey("ID", bookID)
            book_gender = self.json.getMasterkeyForKey(book_name)
            self.json.updateKey(book_gender, book_name, newName)
            return "O nome do livro foi atualizado no banco de dados."
        except ValueError as e:
            return f"Não foi possível atualizar o livro no banco de dados. Erro ocorrido: {e}"

    def updateBookAuthor(self, bookID: int, newAuthor: str) -> str:
        try:
            self.database.updateBookAuthor(bookID, newAuthor)
            return "O autor do livro foi atualizado no banco de dados."
        except ValueError as e:
            return f"Não foi possível atualizar o livro no banco de dados. Erro ocorrido: {e}"

    def updateBookSynopsis(self, bookID: int, newSynopsis: str) -> str:
        try:
            self.database.updateBookSynopsis(bookID, newSynopsis)
            return "A sinopse do livro foi atualizada no banco de dados."
        except ValueError as e:
            return f"Não foi possível atualizar o livro no banco de dados. Erro ocorrido: {e}"

    def updateBookIMG(self, bookID: int, newUrl: str) -> str:
        try:
            self.database.updateBookIMG(bookID, newUrl)
            return "A capa do livro foi atualizada no banco de dados."
        except ValueError as e:
            return f"Não foi possível atualizar a capa no banco de dados. Erro ocorrido: {e}"

    def updateBookJson(self, bookID: int, newValue: str) -> str:
        try:
            book_name = self.json.getKeyForSubkey("ID", bookID)
            book_gender = self.json.getMasterkeyForKey(book_name)
            self.json.updateValue(book_gender, book_name, "Name", newValue)
            return "O comando do livro foi atualizado"
        except RuntimeError as e:
            return f"Não foi possível atualizar o comando do livro no arquivo json. Erro ocorrido: {e}"
        except TypeError as e:
            return f"Não foi possível atualizar o comando do livro no arquivo json. Erro ocorrido: {e}"
        except ValueError as e:
            return f"Não foi possível atualizar o comando do livro no arquivo json. Erro ocorrido: {e}"

    def updateAdminType(self, user_id: str, newtype: int) -> str:
        try:
            self.database.updateAdmType(user_id, newtype)
            return "O cargo foi atualizado com sucesso."
        except ValueError as e:
            return f"Não foi possível atualizar o cargo no banco de dados. Erro ocorrido: {e}"

    def removeBook(self, bookID) -> str:
        try:
            self.database.removeBook(bookID)
            self.database.removeBookIMG(bookID)
            book_name = self.json.getKeyForSubkey("ID", bookID)
            book_gender = self.json.getMasterkeyForKey(book_name)
            self.json.remove(book_gender, book_name)
            SearchFiles().removeFile(book_name, "pdf")
            SearchFiles().removeFile(book_name, "mobi")
            SearchFiles().removeFile(book_name, "epub")
            return "O livro foi removido da biblioteca."
        except ValueError as e:
            return f"Não foi possível remover o livro do banco de dados. Erro ocorrido: {e}"
        except RuntimeError as e:
            return f"Não foi possível remover o livro do banco de dados. Erro ocorrido: {e}"

    def removeBookIMG(self, bookID) -> str:
        try:
            self.database.removeBookIMG(bookID)
            return "A capa foi removida do banco de dados."
        except ValueError as e:
            return f"Não foi possível remover a capa do banco de dados. Erro ocorrido: {e}"

    def removeAdmin(self, user_id: str) -> str:
        try:
            self.database.removeAdm(user_id)
            return "O cargo foi removido com sucesso."
        except ValueError as e:
            return f"Não foi possível remover o cargo no banco de dados. Erro ocorrido: {e}"


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

data = load_breast_cancer()

X = data.data
y = data.target

X = pd.DataFrame(X, columns=data.feature_names)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2)

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()

C_range_exp = np.arange(-15.0, 21.0)
C_range = 10 ** C_range_exp

from sklearn.model_selection import GridSearchCV
param = {'C' : C_range}
gs = GridSearchCV(clf, param)
gs.fit(X_train, y_train)

gs.cv_results_

gs.best_params_,
gs.best_score_,
gs.best_estimator_

clf_best = gs.best_estimator_
clf_best.fit(X_train, y_train)
clf_best.score(X_test, y_test)

plt.errorbar(gs.cv_results_['param_C'].data,
             gs.cv_results_['mean_test_score'],
             yerr=gs.cv_results_['std_test_score'],
             label='test(val)')

plt.errorbar(gs.cv_results_['param_C'].data,
             gs.cv_results_['mean_fit_time'],
             yerr=gs.cv_results_['std_fit_time'],label='train')

plt.errorbar(gs.cv_results_['param_C'].data,
             gs.cv_results_['mean_score_time'],
             yerr=gs.cv_results_['std_score_time'],
             label='test')

plt.ylim(0,)
plt.xscale('log')

from sklearn.svm import SVC

clf = SVC()

C_range_exp = np.arange(-2.0, 5.0)
C_range = 10 ** C_range_exp

params = [
    {'C': C_range, 'kernel': ['linear','rbf']},
]

gs = GridSearchCV(clf, params, n_jobs=1, verbose=2)
gs.fit(X_train, y_train)

s_linear = [gs.cv_results_['param_kernel']=='linear']

plt.plot(gs.cv_results_['param_C'][s_linear].data,
         gs.cv_results_['mean_test_score'])

# add gamma params to rbf
C_range_exp = np.arange(-2.0, 10.0)
C_range = 10 ** C_range_exp

gamma_range_exp = np.arange(-10.0, 0.0, 3)
gamma_range = 10 ** gamma_range_exp

params = [
    {'C': C_range,
     'kernel': ['linear']},
    {'C': C_range,
     'gamma': gamma_range,
     'kernel': ['rbf']}
]

gs = GridSearchCV(clf, params, n_jobs=-1, verbose=2)
gs.fit(X_train, y_train)


from collections import deque

def solution(maps):

    answer = 0

    startPosX, startPosY = 0, 0
    leverPosX, leverPosY = 0, 0
    endPosX, endPosY = 0, 0

    for i in range(len(maps)):
        for j in range(len(maps[i])):
            if maps[i][j] == 'S':
                startPosX, startPosY = i, j
            elif maps[i][j] == 'L':
                leverPosX, leverPosY = i, j
            elif maps[i][j] == 'E':
                endPosX, endPosY = i, j

    BPS_this(maps, startPosX, startPosY, leverPosX, leverPosY)

    return answer

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

def BPS_this(graph, startX, startY, targetX, targetY):
    n = len(graph)
    m = len(graph[0])

    queue = deque()
    queue.append((startX, startY))

    answer = {}

    while queue:
        x, y = queue.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx < 0 or ny < 0 or nx >= n or ny >= m:
                continue
            if graph[nx][ny] == 'X':
                continue
            if graph[nx][ny] == 'O' or 'S' or 'E':
                queue.append((nx, ny))
                print(queue)

maps = ["SOOOL", "XXXXO", "OOOOO", "OXXXX", "OOOOE"]

print(solution(maps))


#usr/bin/env python3

print("19. 複雑な割引")

items = [["apple",	200,	38],
		["kiwi",	130,	40],
		["orange",	90,		20],
		["grape",	380,	30],
		["peach",	400,	10],
		["cherry",	300,	5],
		["banana",	80,		36],
		["lemon",	150,	20] ]

sales = {}
for i in range(0, len(items)):
	sales[items[i][0]] = (items[i][1], items[i][2])

for each_key in sales.keys():
	price = sales[each_key][0] * sales[each_key][1]
	if sales[each_key][1]>= 30:
		price *= 0.9
	if sales[each_key][1]>= 10 and (each_key == "peach" or each_key == "cherry"):
		price *= 0.9
	price *= 1.08
	print(each_key.ljust(8)+" "+"{0:5d}".format(int(price)))


#! /usr/bin/env python

'''
Author: Eric Kwok
Email: mpeknt@nus.edu.sg
Instruction:
    To use these functions, make sure that the EK_robotiq3f_gripper_node.py is
    running. Start roscore and use rosrun to run the script to initialize the
    node, which starts the ros action server, publisher to publish the gripper
    status and a listener to listen to command for the gripper.
'''

import rospy
import actionlib
import iiwa_msgs.msg
import time
import numpy as np

class Gripper_API(object):
    node_no = 0

    def __init__(self,init_node=False):
        self.node_no += 1
        self.node_name = 'Gripper_node_' + str(self.node_no)
        self.result = iiwa_msgs.msg.GripperControl()
        self.client = self._init_client(self.node_name,init_node)
        self.action_done = False    # For eval() in cognitive architecture
        self._goal_msg = iiwa_msgs.msg.GripperControlGoal()
        self._time0 = time.time()
        self._pos0 = None

# Method: To initialize action clent with or wihtout init_node
# Input: name - name of the node
#        init_node - True (start node upon initialization)
# Output: Returns action client object
    def _init_client(self,name,init_node=False):
        try:
            if init_node:
                rospy.init_node(name)
            client = actionlib.SimpleActionClient('/Robotiq3f_gripper/action',\
             iiwa_msgs.msg.GripperControlAction)
            return client
        except rospy.ROSInterruptException:
            rospy.logwarn(self.node_name + " initialization interrupted...")
            raise rospy.ROSInterruptException
        except Exception:
            # rospy.logerr(self.node_name)
            rospy.logerr(sys.exc_info()[0])
            rospy.logerr(sys.exc_info()[2])

# Method: To open or close gripper
# Input: val [0 ,1] - open or close (Either input val or exact_val, not both)
#        actreq (optional)
#        spd - grippping speed (optional)
#        force - gripping force (optional)
#        exact_val [0,255] - exact gripping pos (optional)
#        blocking [True,False] - If True, it will block until action is finish
# Output: goal_achieved - The achieved goal (only ouput if blocking), in the
#         format goal_achieved.gripper_result.actreq
    def open_close_gripper(self,val=None,actreq=11,spd=100,force=10,exact_val=None,\
     blocking=False):
        self.action_done = False
        try:
            if (self.client == False):
                rospy.logerr("Action client not setup.")
                return False

            elif (val != 0 and val != 1 and exact_val == None):
                rospy.logerr("Wrong input value. Please input 0 (open) or 1 (close).")
                return False

            elif (val == None and exact_val == None):
                rospy.logerr("Please input val or exact_val")
                return False

            elif (val != None and exact_val != None):
                rospy.logerr("Please input either val or exact_val")
                return False

            else:
                rospy.loginfo("Waiting for action client")
                self.client.wait_for_server()

                self._goal_msg.gripper_goal.actreq = int(actreq)
                self._goal_msg.gripper_goal.grip_force = int(force)
                self._goal_msg.gripper_goal.grip_spd = int(spd)

                if (exact_val != None):
                    self._goal_msg.gripper_goal.grip_pos = exact_val
                elif val:
                    self._goal_msg.gripper_goal.grip_pos = 255
                else:
                    self._goal_msg.gripper_goal.grip_pos = 0

                if int(actreq) != self.gripper_status()[1]:
                    wait_time = 2
                    rospy.loginfo("Sending target and waiting for %.1fs to change actreq"\
                    %wait_time)
                    self.client.send_goal(self._goal_msg)
                    rospy.Rate(1./wait_time).sleep()
                else:
                    rospy.loginfo("sending")
                    self.client.send_goal(self._goal_msg)

                if blocking:
                    goal_achieved = self.client.wait_for_result()
                    self.result = self.client.get_result()
                    self.action_done = True
                    return goal_achieved

        except rospy.ROSInterruptException:
            rospy.logwarn(self.node_name + " interrupted...")
            pass
        except Exception:
            # rospy.logerr(self.node_name)
            rospy.logerr(sys.exc_info()[0])
            rospy.logerr(sys.exc_info()[2])

# Method: Evaluate gripper whether it has stopped moving
# Input: watch_time - the length of time to check whether the gripper is stationary
#                     before confirming it has gripped something (optional)
#        watch_time_ub - the upper bound for the watch time (optional)
#        grip_pos_uncertainty - The uncertainty in the grip pos (optional)
# Output: [True,False] - True if it has stopped moving
    def eval_gripper_motion(self,watch_time=1.5,watch_time_ub=2.5,\
     grip_pos_uncertainty=1):
        if self.action_done:
            return True
        elif self._pos0 == None:
            self._pos0 = self.gripper_status()[0]
            self._time0 = time.time()
            if self._pos0 == False:
                rospy.logerr("Unable to get status from gripper_status method")
            return False
        elif time.time()-self._time0 > watch_time_ub:
            self._pos0 = self.gripper_status()[0]
            self._time0 = time.time()
            return False
        elif time.time()-self._time0 < watch_time:
            return False
        elif np.abs(self.gripper_status()[0]-self._pos0) > grip_pos_uncertainty:
            self._time0 = time.time()
            self._pos0 = self.gripper_status()[0]
            if self._pos0 == False:
                rospy.logerr("Unable to get status from gripper_status method")
            return False
        else:
            self.action_done = True
            return True

    # # TODO: Change to other method to stop gripper
    # def stop_action(self):
    #     try:
    #         msg = iiwa_msgs.msg.GripperControl()
    #         msg = Gripper_control.get_gripper(msg)
    #         self.open_close_gripper(exact_val=msg.grip_pos)
    #         # status = self.gripper_status()
    #         # self.open_close_gripper(exact_val=status[0])
    #     except rospy.ROSInterruptException:
    #         rospy.logwarn(self.node_name + " interrupted...")
    #         raise rospy.ROSInterruptException
    #     except:
    #         rospy.logerr(self.node_name + " unexpected error...")
    #         raise

# Method: To check the status of the gripper
# Input: timeout [s] - No. of seconds to wait for publisher before giving up (optional)
# Output: (grip_pos, actreq, grip_force, grip_spd) tuple
    def gripper_status(self,timeout=5):
        try:
            topic_name = '/Robotiq3f_gripper/status_publisher'
            _gripper_status = rospy.wait_for_message(topic_name,\
             iiwa_msgs.msg.GripperControl,timeout)
            if (_gripper_status == False):
                rospy.logwarn("Timeout after waiting for %is for the message from "\
                 %(timeout) + topic_name)
                return False
            return _gripper_status.grip_pos, _gripper_status.actreq,\
             _gripper_status.grip_force, _gripper_status.grip_spd

        except rospy.ROSInterruptException:
            rospy.logwarn(self.node_name + " interrupted...")
            pass
        except Exception:
            # rospy.logerr(self.node_name)
            rospy.logerr(sys.exc_info()[0])
            rospy.logerr(sys.exc_info()[2])

if __name__ == "__main__":
    G = Gripper_API(init_node=True)
    while True:
        val = int(input("Enter gripper val: "))
        G.open_close_gripper(val,actreq=11)
        while True:
            print(G.eval_gripper_motion())


def acronym(phrase):
    phrase_split = phrase.split(" ")
    acronym = ''
    print(phrase_split)
    for word in phrase_split:
        letter = word[0]
        acronym = acronym + letter.capitalize()
    return acronym

def main():
    phrase = input("Please input phrase to be acronymed: ")
    print("Acronym is: {0}".format(acronym(phrase)))

main()


'''
Created on 2014-11-12

@author: hongye
'''

import psutil

from core import regist_monitor_source
from core.MetricValue import MultiMetricValue, BatchMultiMetricValue, \
    KeyedMultiMetricValue
from core.MonitorSource import SampleMonitorSource

class NetIoCountersMonitorSource(SampleMonitorSource):
    _pernic = False

    def pernic(self, pernic=False):
        self._pernic = pernic
        return self

    def sample(self, parms):
        nic = psutil.net_io_counters(pernic=self._pernic)
        if self._pernic == True:
            metricValue = KeyedMultiMetricValue(self.getMonitorSourceName())
            for (k, v) in nic.items():
                value = dict()
                value["bytes_sent"] = v.bytes_sent
                value["bytes_recv"] = v.bytes_recv
                value["packets_sent"] = v.packets_sent
                value["packets_recv"] = v.packets_recv
                value["errin"] = v.errin
                value["errout"] = v.errout
                value["dropin"] = v.dropin
                value["dropout"] = v.dropout
                metricValue.addMetricValue(k, value)
            return metricValue
        else:
            metricValue = MultiMetricValue(self.getMonitorSourceName())
            metricValue.addMetricValue("bytes_sent", nic.bytes_sent)
            metricValue.addMetricValue("bytes_recv", nic.bytes_recv)
            metricValue.addMetricValue("packets_sent", nic.packets_sent)
            metricValue.addMetricValue("packets_recv", nic.packets_recv)
            metricValue.addMetricValue("errin", nic.errin)
            metricValue.addMetricValue("errout", nic.errout)
            metricValue.addMetricValue("dropin", nic.dropin)
            metricValue.addMetricValue("dropout", nic.dropout)
            return metricValue

NET_CONNECTION_KIND_INET = "inet"
NET_CONNECTION_KIND_INET4 = "inet4"
NET_CONNECTION_KIND_INET6 = "inet6"
NET_CONNECTION_KIND_TCP = "tcp"
NET_CONNECTION_KIND_TCP4 = "tcp4"
NET_CONNECTION_KIND_TCP6 = "tcp6"
NET_CONNECTION_KIND_UDP = "udp"
NET_CONNECTION_KIND_UDP4 = "udp4"
NET_CONNECTION_KIND_UDP6 = "udp6"
NET_CONNECTION_KIND_UNIX = "unix"
NET_CONNECTION_KIND_ALL = "all"

class NetConnectionsMonitorSource(SampleMonitorSource):
    _kind = NET_CONNECTION_KIND_INET
    def kind(self, kind=NET_CONNECTION_KIND_INET):
        self._kind = kind
        return self

    def sample(self, parms):
        conns = psutil.net_connections(self._kind)
        metricValue = BatchMultiMetricValue(self.getMonitorSourceName())
        for conn in conns:
            value = dict()
            value["fd"] = conn.fd
            value["family"] = conn.family
            value["type"] = conn.type
#             value["laddr"] = conn.laddr
#             value["raddr"] = conn.raddr
            value["status"] = conn.status
            value["pid"] = conn.pid
            metricValue.addMetricValue(value)
        return metricValue

def net_io_counters(monitorSourceName, pernic=False):
    monitorSource = NetIoCountersMonitorSource().monitorSourceName(monitorSourceName).pernic(pernic)
    regist_monitor_source(monitorSource)
    return monitorSource

def net_connections(monitorSourceName, kind=NET_CONNECTION_KIND_INET):
    monitorSource = NetConnectionsMonitorSource().monitorSourceName(monitorSourceName).kind(kind)
    regist_monitor_source(monitorSource)
    return monitorSource


def solution(polynomial):
    answer = ''
    xsum = 0
    nsum = 0
    for p in polynomial.split(' + '):
        if 'x' in p:
            if len(p) == 1:
                xsum += 1
            else:
                xsum += int(p.replace('x', ''))
        else:
            nsum += int(p)

    if xsum > 0 and nsum > 0:
        if xsum == 1:
            answer = 'x + {}'.format(nsum)
        else:
            answer = '{}x + {}'.format(xsum, nsum)

    elif xsum > 0 and nsum == 0:
        if xsum == 1:
            answer = 'x'
        else:
            answer = '{}x'.format(xsum)

    elif nsum > 0 and xsum == 0:
        answer = '{}'.format(nsum)

    print(answer)

    return answer

프로그래머스/다항식 더하기.py


import pickle
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import colors

paths = ["trajectories_td_prog.zarr", "trajectories_raceline.zarr", "trajectories_min_act.zarr"]
# preppend plots to paths
paths = ["plots2/" + path for path in paths]
discounts = [0.95, 0.99]

keys = ['DR', 'MB', 'FQE']
for path in paths:

    # Prepare an empty matrix for the results
    data_matrix = []

    for discount in discounts:
        # Construct the full path to the .pkl file
        full_path = f"{path}/{discount}/spearman_per_model.pkl"

        with open(full_path, 'rb') as f:
            spearman_data = pickle.load(f)

        # Extract values for models 0-3
        model_values = [spearman_data[key] for key in keys]
        data_matrix.append(model_values)

    data_matrix = np.array(data_matrix)

    # Plotting
    fig, ax = plt.subplots()

    cmap = colors.ListedColormap(['red', 'green'])
    bounds = [-1.0, 0.6, 1.1]  # Adjusting upper bound to include all values >0.5
    norm = colors.BoundaryNorm(bounds, cmap.N)

    cax = ax.matshow(data_matrix, cmap=cmap, norm=norm)

    # Annotating the actual values
    for i in range(len(discounts)):
        for j in range(len(spearman_data.keys())):
            ax.text(j, i, f"{data_matrix[i, j]:.2f}", va='center', ha='center', color='black' if data_matrix[i, j] < 0.7 else 'white')

    ax.set_xticks(np.arange(len(spearman_data.keys())))
    ax.set_yticks(np.arange(len(discounts)))

    ax.set_xticklabels([str(key) for key in keys])
    ax.set_yticklabels(discounts)

    ax.set_xlabel('Models')
    ax.set_ylabel('Discounts')

    plt.colorbar(cax, ticks=[0, 0.5, 1.5])

    plt.show()
    plt.savefig(f"{path}/spearman.png")
    # clear figure
    plt.clf()


from django.urls import path

from . import views

app_name = 'moderation'

urlpatterns = [
     path('shops/', views.moderation_shop, name='moderation_shop'),
     path('accept_shop/<int:shop_id>/', views.accept_shop, name='accept_shop'),
     path('reject_shop/<int:shop_id>/', views.reject_shop, name='reject_shop'),
     path('products/', views.moderation_product, name='moderation_product'),
     path('accept_product/<int:product_id>/', views.accept_product,
          name='accept_product'),
     path('reject_product/<int:product_id>/', views.reject_product,
          name='reject_product'),
     path('moderation_history/', views.moderation_history,
          name='moderation_history'),
     path('change_moderator_status/', views.change_moderator_status,
          name='change_moderator_status'),
]


from http import HTTPStatus

from django.core.cache import cache
from django.test import TestCase, Client
from django.urls import reverse

from posts.models import Post, Group, User

class PostURLTests(TestCase):
    REDIRECT_WAY = '/auth/login/?next='

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.author_post = User.objects.create(username='Test_author')
        cls.group = Group.objects.create(
            title='тестовая группа',
            slug='test_group'
        )
        cls.post = Post.objects.create(
            text='Содержание поста',
            author=PostURLTests.author_post,
            group=PostURLTests.group
        )

    def setUp(self):
        cache.clear()
        self.user = User.objects.create_user(username='TestUser')
        self.not_author = Client()
        self.not_author.force_login(self.user)
        self.author = Client()
        self.author.force_login(PostURLTests.author_post)
        self.reverse_names = (
            ('posts:index', None, '/'),
            (
                'posts:group_list',
                (self.group.slug,),
                f'/group/{self.group.slug}/'
            ),
            (
                'posts:profile',
                (self.post.author.username,),
                f'/profile/{self.post.author.username}/'
            ),
            (
                'posts:post_detail',
                (self.post.pk,),
                f'/posts/{self.post.pk}/'
            ),
            ('posts:post_create', None, '/create/'),
            (
                'posts:post_edit',
                (self.post.pk,),
                f'/posts/{self.post.pk}/edit/'
            ),
            (
                'posts:add_comment',
                (self.post.pk,),
                f'/posts/{self.post.pk}/comment/'
            ),
            (
                'posts:follow_index',
                None,
                '/follow/'
            ),
            (
                'posts:profile_follow',
                (self.post.author.username,),
                f'/profile/{self.post.author.username}/follow/'
            ),
            (
                'posts:profile_unfollow',
                (self.post.author.username,),
                f'/profile/{self.post.author.username}/unfollow/'
            ),
        )

    def test_reverse_name_url(self):
        """Тест реверсов."""
        for name, args, hardurl in self.reverse_names:
            with self.subTest(name=name):
                self.assertEqual(reverse(name, args=args), hardurl)

    def test_unexisting_urls(self):
        """Проверяем запрос к несуществующей странице 404 и шаблон"""
        response = self.client.get('/unexisting_page/')
        self.assertEqual(response.status_code, HTTPStatus.NOT_FOUND)
        self.assertTemplateUsed(response, 'core/404.html')

    def test_urls_uses_correct_template_guest(self):
        """URL-адрес использует соответствующий шаблон. """
        cache.clear()
        url_names = (
            ('posts:index', None, 'posts/index.html'),
            ('posts:follow_index', None, 'posts/follow.html'),
            (
                'posts:group_list',
                (self.group.slug,),
                'posts/group_list.html'
            ),
            (
                'posts:profile',
                (self.post.author.username,),
                'posts/profile.html'
            ),
            (
                'posts:post_detail',
                (self.post.pk,),
                'posts/post_detail.html'
            ),
            ('posts:post_create', None, 'posts/post_create.html'),
            (
                'posts:post_edit',
                (self.post.pk,),
                'posts/post_create.html'
            ),
        )
        for name, args, template in url_names:
            with self.subTest(name=name):
                response = self.author.get(reverse(name, args=args))
                self.assertTemplateUsed(response, template)

    def test_urls_author(self):
        """Проверяем доступность страниц для автора"""
        for name, args, url in self.reverse_names:
            with self.subTest(name=name):
                response = self.author.get(reverse(name, args=args))
                if name == 'posts:add_comment':
                    self.assertRedirects(response, reverse(
                        'posts:post_detail', args=(self.post.pk,)
                    ))
                elif name == 'posts:profile_follow':
                    self.assertRedirects(response, reverse(
                        'posts:profile', args=(self.post.author.username,)
                    ))
                elif name == 'posts:profile_unfollow':
                    self.assertEqual(
                        response.status_code, HTTPStatus.NOT_FOUND
                    )
                else:
                    self.assertEqual(response.status_code, HTTPStatus.OK)

    def test_urls_not_author(self):
        """Проверяем доступность страниц для неавтора"""
        for name, args, x in self.reverse_names:
            with self.subTest(name=name):
                response = self.not_author.get(reverse(name, args=args))
                if name in ('posts:post_edit', 'posts:add_comment'):
                    self.assertRedirects(response, reverse(
                        'posts:post_detail', args=(self.post.pk,)
                    ))
                elif name in (
                        'posts:profile_follow',
                        'posts:profile_unfollow'
                ):
                    self.assertRedirects(response, reverse(
                        'posts:profile', args=(self.post.author.username,)
                    ))
                else:
                    self.assertEqual(response.status_code, HTTPStatus.OK)

    def test_urls_guest(self):
        """Проверяем доступность страниц для гостя"""
        for_redirect = (
            'posts:post_edit',
            'posts:post_create',
            'posts:add_comment',
            'posts:profile_follow',
            'posts:profile_unfollow',
            'posts:follow_index',
        )
        for name, args, url in self.reverse_names:
            with self.subTest(name=name):
                response = self.client.get(reverse(name, args=args))
                if name in for_redirect:
                    self.assertRedirects(
                        response,
                        self.REDIRECT_WAY + reverse(name, args=args)
                    )
                else:
                    self.assertEqual(response.status_code, HTTPStatus.OK)