import wx

from meerk40t.gui.wxutils import ScrolledPanel, StaticBoxSizer

from ...core.units import Length
from ...svgelements import Angle, Matrix
from ..wxutils import TextCtrl, set_ctrl_value
from .attributes import ColorPanel, IdPanel

_ = wx.GetTranslation

class HatchPropertyPanel(ScrolledPanel):
    def __init__(self, *args, context=None, node=None, **kwds):
        # super().__init__(parent)
        kwds["style"] = kwds.get("style", 0) | wx.TAB_TRAVERSAL
        ScrolledPanel.__init__(self, *args, **kwds)
        self.context = context
        self.context.setting(
            bool, "_auto_classify", self.context.elements.classify_on_color
        )
        self.node = node

        self._Buffer = None

        main_sizer = StaticBoxSizer(self, wx.ID_ANY, _("Hatch:"), wx.VERTICAL)

        # `Id` at top in all cases...
        panel_id = IdPanel(self, id=wx.ID_ANY, context=self.context, node=self.node)
        main_sizer.Add(panel_id, 1, wx.EXPAND, 0)

        panel_stroke = ColorPanel(
            self,
            id=wx.ID_ANY,
            context=self.context,
            label="Stroke:",
            attribute="stroke",
            callback=self.callback_color,
            node=self.node,
        )
        main_sizer.Add(panel_stroke, 1, wx.EXPAND, 0)

        # panel_fill = ColorPanel(
        #     self,
        #     id=wx.ID_ANY,
        #     context=self.context,
        #     label="Fill:",
        #     attribute="fill",
        #     callback=self.callback_color,
        #     node=self.node,
        # )
        # main_sizer.Add(panel_fill, 1, wx.EXPAND, 0)

        sizer_loops = StaticBoxSizer(self, wx.ID_ANY, _("Loops"), wx.HORIZONTAL)
        self.text_loops = TextCtrl(
            self,
            wx.ID_ANY,
            str(node.loops),
            limited=True,
            check="int",
            style=wx.TE_PROCESS_ENTER,
        )
        sizer_loops.Add(self.text_loops, 1, wx.ALIGN_CENTER_VERTICAL, 0)
        self.slider_loops = wx.Slider(self, wx.ID_ANY, 0, 0, 100)
        sizer_loops.Add(self.slider_loops, 3, wx.EXPAND, 0)
        main_sizer.Add(sizer_loops, 1, wx.EXPAND, 0)

        sizer_distance = StaticBoxSizer(
            self, wx.ID_ANY, _("Hatch Distance:"), wx.HORIZONTAL
        )
        main_sizer.Add(sizer_distance, 0, wx.EXPAND, 0)

        self.text_distance = TextCtrl(
            self,
            wx.ID_ANY,
            str(node.hatch_distance),
            limited=True,
            check="length",
            style=wx.TE_PROCESS_ENTER,
        )
        sizer_distance.Add(self.text_distance, 1, wx.ALIGN_CENTER_VERTICAL, 0)

        sizer_angle = StaticBoxSizer(self, wx.ID_ANY, _("Angle"), wx.HORIZONTAL)
        self.text_angle = TextCtrl(
            self,
            wx.ID_ANY,
            str(node.hatch_angle),
            limited=True,
            check="angle",
            style=wx.TE_PROCESS_ENTER,
        )
        sizer_angle.Add(self.text_angle, 1, wx.ALIGN_CENTER_VERTICAL, 0)
        self.slider_angle = wx.Slider(self, wx.ID_ANY, 0, 0, 360)
        sizer_angle.Add(self.slider_angle, 3, wx.EXPAND, 0)
        main_sizer.Add(sizer_angle, 1, wx.EXPAND, 0)

        sizer_angle_delta = StaticBoxSizer(
            self, wx.ID_ANY, _("Angle Delta"), wx.HORIZONTAL
        )
        self.text_angle_delta = TextCtrl(
            self,
            wx.ID_ANY,
            str(node.hatch_angle_delta),
            limited=True,
            check="angle",
            style=wx.TE_PROCESS_ENTER,
        )
        sizer_angle_delta.Add(self.text_angle_delta, 1, wx.ALIGN_CENTER_VERTICAL, 0)
        self.slider_angle_delta = wx.Slider(self, wx.ID_ANY, 0, 0, 360)
        sizer_angle_delta.Add(self.slider_angle_delta, 3, wx.EXPAND, 0)
        main_sizer.Add(sizer_angle_delta, 1, wx.EXPAND, 0)
        sizer_fill = StaticBoxSizer(self, wx.ID_ANY, _("Fill Style"), wx.VERTICAL)
        main_sizer.Add(sizer_fill, 6, wx.EXPAND, 0)

        self.fills = list(self.context.match("hatch", suffix=True))
        self.combo_fill_style = wx.ComboBox(
            self, wx.ID_ANY, choices=self.fills, style=wx.CB_DROPDOWN | wx.CB_READONLY
        )
        sizer_fill.Add(self.combo_fill_style, 0, wx.EXPAND, 0)

        self.display_panel = wx.Panel(self, wx.ID_ANY)
        sizer_fill.Add(self.display_panel, 6, wx.EXPAND, 0)

        self.check_classify = wx.CheckBox(
            self, wx.ID_ANY, _("Immediately classify after colour change")
        )
        self.check_classify.SetValue(self.context._auto_classify)
        main_sizer.Add(self.check_classify, 1, wx.EXPAND, 0)

        self.SetSizer(main_sizer)

        self.text_loops.SetActionRoutine(self.on_text_loops)
        self.text_distance.SetActionRoutine(self.on_text_distance)
        self.text_angle.SetActionRoutine(self.on_text_angle)
        self.text_angle_delta.SetActionRoutine(self.on_text_angle_delta)
        self.check_classify.Bind(wx.EVT_CHECKBOX, self.on_check_classify)
        self.Bind(wx.EVT_COMMAND_SCROLL, self.on_slider_loops, self.slider_loops)
        self.Bind(wx.EVT_COMMAND_SCROLL, self.on_slider_angle, self.slider_angle)
        self.Bind(
            wx.EVT_COMMAND_SCROLL, self.on_slider_angle_delta, self.slider_angle_delta
        )
        self.Bind(wx.EVT_COMBOBOX, self.on_combo_fill, self.combo_fill_style)
        # end wxGlade
        self.Bind(wx.EVT_SIZE, self.on_size)
        self.display_panel.Bind(wx.EVT_PAINT, self.on_display_paint)
        self.display_panel.Bind(wx.EVT_ERASE_BACKGROUND, self.on_display_erase)

        self.raster_pen = wx.Pen()
        self.raster_pen.SetColour(wx.Colour(0, 0, 0, 180))
        self.raster_pen.SetWidth(1)

        self.travel_pen = wx.Pen()
        self.travel_pen.SetColour(wx.Colour(255, 127, 255, 127))
        self.travel_pen.SetWidth(1)

        self.outline_pen = wx.Pen()
        self.outline_pen.SetColour(wx.Colour(0, 127, 255, 127))
        self.outline_pen.SetWidth(1)

        self.hatch_lines = None
        self.travel_lines = None
        self.outline_lines = None

        self.Layout()

    def pane_hide(self):
        pass

    def pane_show(self):
        pass

    @staticmethod
    def accepts(node):
        return node.type in ("effect hatch",)

    def set_widgets(self, node):
        self.node = node
        if self.node is None or not self.accepts(node):
            self.Hide()
            return
        i = 0
        for ht in self.fills:
            if ht == self.node.hatch_type:
                break
            i += 1
        if i == len(self.fills):
            i = 0
        self.combo_fill_style.SetSelection(i)
        set_ctrl_value(self.text_angle, str(self.node.hatch_angle))
        set_ctrl_value(self.text_angle_delta, str(self.node.hatch_angle_delta))
        set_ctrl_value(self.text_distance, str(self.node.hatch_distance))
        try:
            h_angle = float(Angle.parse(self.node.hatch_angle).as_degrees)
            self.slider_angle.SetValue(int(h_angle))
        except ValueError:
            pass
        try:
            h_angle = float(Angle.parse(self.node.hatch_angle_delta).as_degrees)
            self.slider_angle_delta.SetValue(int(h_angle))
        except ValueError:
            pass
        self.Show()

    def on_check_classify(self, event):
        self.context._auto_classify = self.check_classify.GetValue()

    def update_label(self):
        return

    def callback_color(self):
        self.node.altered()
        self.update_label()
        self.Refresh()
        if self.check_classify.GetValue():
            mynode = self.node
            wasemph = self.node.emphasized
            self.context("declassify\nclassify\n")
            self.context.elements.signal("tree_changed")
            self.context.elements.signal("element_property_update", self.node)
            mynode.emphasized = wasemph
            self.set_widgets(mynode)

    def on_text_loops(self):
        try:
            loops = int(self.text_loops.GetValue())
            if loops == self.node.loops:
                return
            self.node.loops = loops
            self.node.modified()
        except ValueError:
            return
        try:
            h_loops = int(self.node.loops)
            self.slider_loops.SetValue(int(h_loops))
        except ValueError:
            pass
        self.hatch_lines = None
        self.travel_lines = None
        self.refresh_display()

    def on_slider_loops(self, event):
        value = self.slider_loops.GetValue()
        self.text_loops.SetValue(str(value))
        self.on_text_loops()

    def on_text_distance(self):
        try:
            dist = Length(self.text_distance.GetValue()).length_mm
            if dist == self.node.distance:
                return
            self.node.hatch_distance = dist
            self.node.distance = dist
            self.node.modified()
            self.hatch_lines = None
            self.travel_lines = None
            self.refresh_display()
        except ValueError:
            pass

    def on_text_angle(self):
        try:
            angle = f"{Angle.parse(self.text_angle.GetValue()).as_degrees}deg"
            if angle == self.node.hatch_angle:
                return
            self.node.hatch_angle = angle
            self.node.angle = angle
            self.node.modified()

        except ValueError:
            return
        try:
            h_angle = float(Angle.parse(self.node.angle).as_degrees)
            while h_angle > self.slider_angle.GetMax():
                h_angle -= 360
            while h_angle < self.slider_angle.GetMin():
                h_angle += 360
            self.slider_angle.SetValue(int(h_angle))
        except ValueError:
            pass
        self.hatch_lines = None
        self.travel_lines = None
        self.refresh_display()

    def on_slider_angle(self, event):
        value = self.slider_angle.GetValue()
        self.text_angle.SetValue(f"{value}deg")
        self.on_text_angle()

    def on_text_angle_delta(self):
        try:
            angle = f"{Angle.parse(self.text_angle_delta.GetValue()).as_degrees}deg"
            if angle == self.node.hatch_angle_delta:
                return
            self.node.hatch_angle_delta = angle
            self.node.delta = angle
            self.node.modified()
        except ValueError:
            return
        try:
            h_angle_delta = float(Angle.parse(self.node.delta).as_degrees)
            while h_angle_delta > self.slider_angle_delta.GetMax():
                h_angle_delta -= 360
            while h_angle_delta < self.slider_angle_delta.GetMin():
                h_angle_delta += 360
            self.slider_angle_delta.SetValue(int(h_angle_delta))
        except ValueError:
            pass
        self.hatch_lines = None
        self.travel_lines = None
        self.refresh_display()

    def on_slider_angle_delta(self, event):
        value = self.slider_angle_delta.GetValue()
        self.text_angle_delta.SetValue(f"{value}deg")
        self.on_text_angle_delta()

    def on_combo_fill(self, event):  # wxGlade: HatchSettingsPanel.<event_handler>
        hatch_type = self.fills[int(self.combo_fill_style.GetSelection())]
        self.node.hatch_type = hatch_type
        self.node.modified()
        self.hatch_lines = None
        self.travel_lines = None
        self.refresh_display()

    def on_display_paint(self, event=None):
        if self._Buffer is None:
            return
        try:
            wx.BufferedPaintDC(self.display_panel, self._Buffer)
        except RuntimeError:
            pass

    def on_display_erase(self, event=None):
        pass

    def set_buffer(self):
        width, height = self.display_panel.ClientSize
        if width <= 0:
            width = 1
        if height <= 0:
            height = 1
        self._Buffer = wx.Bitmap(width, height)

    def on_size(self, event=None):
        self.Layout()
        self.set_buffer()
        self.hatch_lines = None
        self.travel_lines = None
        self.refresh_display()

    def refresh_display(self):
        # print(
        #     f"Distance={self.node.distance} / {self.node.hatch_distance} / {self.node.settings.get('hatch_distance', '')}"
        # )
        # print(
        #     f"Angle={self.node.angle} / {self.node.hatch_angle} / {self.node.settings.get('hatch_angle', '')}"
        # )
        if not wx.IsMainThread():
            wx.CallAfter(self.refresh_in_ui)
        else:
            self.refresh_in_ui()

    def calculate_hatch_lines(self):
        # from time import perf_counter

        # print(f"Calculate hatch lines {perf_counter():.3f}")
        w, h = self._Buffer.Size
        hatch_type = self.node.hatch_type
        hatch_algorithm = self.context.lookup(f"hatch/{hatch_type}")
        if hatch_algorithm is None:
            return
        paths = (
            complex(w * 0.05, h * 0.05),
            complex(w * 0.95, h * 0.05),
            complex(w * 0.95, h * 0.95),
            complex(w * 0.05, h * 0.95),
            complex(w * 0.05, h * 0.05),
            None,
            complex(w * 0.25, h * 0.25),
            complex(w * 0.75, h * 0.25),
            complex(w * 0.75, h * 0.75),
            complex(w * 0.25, h * 0.75),
            complex(w * 0.25, h * 0.25),
        )
        matrix = Matrix.scale(0.018)
        hatch = list(
            hatch_algorithm(
                settings=self.node.__dict__,
                outlines=paths,
                matrix=matrix,
                limit=1000,
            )
        )
        o_start = []
        o_end = []
        last = None
        for c in paths:
            if last is not None and c is not None:
                o_start.append((c.real, c.imag))
                o_end.append((last.real, last.imag))
            last = c
        self.outline_lines = o_start, o_end
        h_start = []
        h_end = []
        t_start = []
        t_end = []
        last_x = None
        last_y = None
        travel = True
        for p in hatch:
            if p is None:
                travel = True
                continue
            x, y = p
            if last_x is None:
                last_x = x
                last_y = y
                travel = False
                continue
            if travel:
                t_start.append((last_x, last_y))
                t_end.append((x, y))
            else:
                h_start.append((last_x, last_y))
                h_end.append((x, y))
            travel = False
            last_x = x
            last_y = y
        self.hatch_lines = h_start, h_end
        self.travel_lines = t_start, t_end

    def refresh_in_ui(self):
        """Performs redrawing of the data in the UI thread."""
        dc = wx.MemoryDC()
        dc.SelectObject(self._Buffer)
        dc.SetBackground(wx.WHITE_BRUSH)
        dc.Clear()
        gc = wx.GraphicsContext.Create(dc)
        if self.Shown:
            if self.hatch_lines is None:
                self.calculate_hatch_lines()
            if self.hatch_lines is not None:
                starts, ends = self.hatch_lines
                if len(starts):
                    gc.SetPen(self.raster_pen)
                    gc.StrokeLineSegments(starts, ends)
                else:
                    font = wx.Font(
                        14, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD
                    )
                    gc.SetFont(font, wx.BLACK)
                    gc.DrawText(_("No hatch preview..."), 0, 0)
            if self.travel_lines is not None:
                starts, ends = self.travel_lines
                if len(starts):
                    gc.SetPen(self.travel_pen)
                    gc.StrokeLineSegments(starts, ends)
            if self.outline_lines is not None:
                starts, ends = self.outline_lines
                if len(starts):
                    gc.SetPen(self.outline_pen)
                    gc.StrokeLineSegments(starts, ends)
        gc.Destroy()
        dc.SelectObject(wx.NullBitmap)
        del dc
        self.display_panel.Refresh()
        self.display_panel.Update()


from abc import ABC, abstractmethod
import time
from typing import Any, Dict, NamedTuple, Optional, Tuple

from eth.exceptions import BlockNotFound
from eth_typing import Address, BlockNumber, BLSPubkey, BLSSignature, Hash32
import web3

from eth2.beacon.constants import GWEI_PER_ETH
from eth2.beacon.tools.builder.validator import (
    make_deposit_tree_and_root,
    mk_key_pair_from_seed_index,
    sign_proof_of_possession,
)
from eth2.beacon.types.deposit_data import DepositData, DepositMessage
from eth2.beacon.typing import Gwei, Timestamp

class Eth1Block(NamedTuple):
    block_hash: Hash32
    number: BlockNumber
    timestamp: Timestamp

class DepositLog(NamedTuple):
    block_hash: Hash32
    pubkey: BLSPubkey
    # NOTE: The following noqa is to avoid a bug in pycodestyle. We can remove it after upgrading
    #   `flake8`. Ref: https://github.com/PyCQA/pycodestyle/issues/635#issuecomment-411916058
    withdrawal_credentials: Hash32  # noqa: E701
    amount: Gwei
    signature: BLSSignature

    @classmethod
    def from_contract_log_dict(cls, log: Dict[Any, Any]) -> "DepositLog":
        log_args = log["args"]
        return cls(
            block_hash=log["blockHash"],
            pubkey=log_args["pubkey"],
            withdrawal_credentials=log_args["withdrawal_credentials"],
            amount=Gwei(int.from_bytes(log_args["amount"], "little")),
            signature=log_args["signature"],
        )

def convert_deposit_log_to_deposit_data(deposit_log: DepositLog) -> DepositData:
    return DepositData.create(
        pubkey=deposit_log.pubkey,
        withdrawal_credentials=deposit_log.withdrawal_credentials,
        amount=deposit_log.amount,
        signature=deposit_log.signature,
    )

class BaseEth1DataProvider(ABC):
    @abstractmethod
    def get_block(self, arg: web3.types.BlockIdentifier) -> Optional[Eth1Block]:
        ...

    @abstractmethod
    def get_logs(self, block_number: BlockNumber) -> Tuple[DepositLog, ...]:
        ...

    @abstractmethod
    def get_deposit_count(self, block_number: BlockNumber) -> bytes:
        ...

    @abstractmethod
    def get_deposit_root(self, block_number: BlockNumber) -> Hash32:
        ...

class Web3Eth1DataProvider(BaseEth1DataProvider):

    w3: web3.Web3

    _deposit_contract: web3.contract.Contract

    def __init__(
        self,
        w3: web3.Web3,
        deposit_contract_address: Address,
        deposit_contract_abi: Dict[str, Any],
    ) -> None:
        self.w3 = w3
        self._deposit_contract = self.w3.eth.contract(
            address=deposit_contract_address, abi=deposit_contract_abi
        )

    def get_block(self, arg: web3.types.BlockIdentifier) -> Optional[Eth1Block]:
        block_dict = self.w3.eth.getBlock(arg)
        if block_dict is None:
            raise BlockNotFound
        return Eth1Block(
            block_hash=Hash32(block_dict["hash"]),
            number=BlockNumber(block_dict["number"]),
            timestamp=Timestamp(block_dict["timestamp"]),
        )

    def get_logs(self, block_number: BlockNumber) -> Tuple[DepositLog, ...]:
        # NOTE: this installs/uninstalls an event filter; we could forego
        # this if we had a transaction receipt or transaction hash instead;
        # however, that only makes sense when monitoring unmined txs: it's
        # otherwise easier to process entire blocks of deposits as batches
        processed_logs = self._deposit_contract.events.DepositEvent.getLogs(
            fromBlock=block_number, toBlock=block_number
        )
        parsed_logs = tuple(
            DepositLog.from_contract_log_dict(log) for log in processed_logs
        )
        return parsed_logs

    def get_deposit_count(self, block_number: BlockNumber) -> bytes:
        return self._deposit_contract.functions.get_deposit_count().call(
            block_identifier=block_number
        )

    def get_deposit_root(self, block_number: BlockNumber) -> Hash32:
        return self._deposit_contract.functions.get_deposit_root().call(
            block_identifier=block_number
        )

# NOTE: This constant is for `FakeEth1DataProvider`
AVERAGE_BLOCK_TIME = 5

class FakeEth1DataProvider(BaseEth1DataProvider):

    start_block_number: BlockNumber
    start_block_timestamp: Timestamp

    num_deposits_per_block: int

    deposits: Tuple[DepositData, ...]
    num_initial_deposits: int
    latest_processed_block_number: BlockNumber

    def __init__(
        self,
        start_block_number: BlockNumber,
        start_block_timestamp: Timestamp,
        num_deposits_per_block: int,
        initial_deposits: Tuple[DepositData, ...],
    ) -> None:
        self.start_block_number = start_block_number
        self.start_block_timestamp = start_block_timestamp
        self.num_deposits_per_block = num_deposits_per_block
        self.deposits = initial_deposits
        self.num_initial_deposits = len(initial_deposits)
        self.latest_processed_block_number = start_block_number

    def _get_latest_block_number(self) -> BlockNumber:
        current_time = int(time.time())
        distance = (current_time - self.start_block_timestamp) // AVERAGE_BLOCK_TIME
        return BlockNumber(self.start_block_number + distance)

    def _get_block_time(self, block_number: BlockNumber) -> Timestamp:
        return Timestamp(
            self.start_block_timestamp
            + (block_number - self.start_block_number) * AVERAGE_BLOCK_TIME
        )

    def get_block(self, arg: web3.types.BlockIdentifier) -> Optional[Eth1Block]:
        # If `arg` is block number
        if isinstance(arg, int):
            block_time = self._get_block_time(BlockNumber(arg))
            return Eth1Block(
                block_hash=Hash32(int(arg).to_bytes(32, byteorder="big")),
                number=BlockNumber(arg),
                timestamp=Timestamp(block_time),
            )
        # If `arg` is block hash
        elif isinstance(arg, bytes):
            block_hash = Hash32(arg)
            # Why are we interpreting the block hash as a block number here?
            block_number = int.from_bytes(block_hash, byteorder="big")
            latest_block_number = self._get_latest_block_number()
            # Block that's way in the future is presumed to be fake eth1 block in genesis state.
            # Return the block at `start_block_number` in this case.
            # The magic number `100` here stands for distance that's way in the future.
            if block_number > latest_block_number + 100:
                return Eth1Block(
                    block_hash=Hash32(
                        self.start_block_number.to_bytes(32, byteorder="big")
                    ),
                    number=BlockNumber(self.start_block_number),
                    timestamp=Timestamp(self.start_block_timestamp),
                )
            block_time = self._get_block_time(BlockNumber(block_number))
            return Eth1Block(
                block_hash=block_hash,
                number=BlockNumber(block_number),
                timestamp=Timestamp(block_time),
            )
        elif arg == "latest":
            latest_block_number = self._get_latest_block_number()
            block_time = self._get_block_time(latest_block_number)
            return Eth1Block(
                block_hash=Hash32(latest_block_number.to_bytes(32, byteorder="big")),
                number=BlockNumber(latest_block_number),
                timestamp=block_time,
            )
        elif isinstance(arg, str):
            raise NotImplementedError(f"get_block({arg!r}) is not implemented")
        else:
            raise TypeError(
                f"Argument {arg!r} to get_block was an unexpected type: {type(arg)}"
            )

    def get_logs(self, block_number: BlockNumber) -> Tuple[DepositLog, ...]:
        block_hash = block_number.to_bytes(32, byteorder="big")
        logs: Tuple[DepositLog, ...] = tuple()
        if block_number < self.start_block_number:
            return logs
        elif block_number == self.start_block_number:
            logs = tuple(
                DepositLog(
                    block_hash=Hash32(block_hash),
                    pubkey=deposit.pubkey,
                    withdrawal_credentials=deposit.withdrawal_credentials,
                    signature=deposit.signature,
                    amount=deposit.amount,
                )
                for deposit in self.deposits
            )
            return logs
        else:
            amount: Gwei = Gwei(32 * GWEI_PER_ETH)
            for seed in range(self.num_deposits_per_block):
                # Multiply `block_number` by 10 to shift it one digit to the left so
                # the input to the function is generated deterministically but does not
                # conflict with blocks in the future.
                pubkey, privkey = mk_key_pair_from_seed_index(block_number * 10 + seed)
                withdrawal_credentials = Hash32(b"\x12" * 32)
                deposit_data_message = DepositMessage.create(
                    pubkey=pubkey,
                    withdrawal_credentials=withdrawal_credentials,
                    amount=amount,
                )
                signature = sign_proof_of_possession(
                    deposit_message=deposit_data_message, privkey=privkey
                )
                logs = logs + (
                    DepositLog(
                        block_hash=Hash32(block_hash),
                        pubkey=pubkey,
                        withdrawal_credentials=withdrawal_credentials,
                        signature=signature,
                        amount=amount,
                    ),
                )
            return logs

    def get_deposit_count(self, block_number: BlockNumber) -> bytes:
        if block_number <= self.start_block_number:
            return self.num_initial_deposits.to_bytes(32, byteorder="little")
        deposit_count = (
            self.num_initial_deposits
            + (block_number - self.start_block_number) * self.num_deposits_per_block
        )
        return deposit_count.to_bytes(32, byteorder="little")

    def get_deposit_root(self, block_number: BlockNumber) -> Hash32:
        # Check and update deposit data when deposit root is requested
        if self.latest_processed_block_number < block_number:
            for blk_number in range(
                self.latest_processed_block_number + 1, block_number + 1
            ):
                deposit_logs = self.get_logs(BlockNumber(blk_number))
                self.deposits += tuple(
                    convert_deposit_log_to_deposit_data(deposit_log)
                    for deposit_log in deposit_logs
                )
            self.latest_processed_block_number = block_number
        deposit_count_bytes = self.get_deposit_count(block_number)
        deposit_count = int.from_bytes(deposit_count_bytes, byteorder="little")
        deposits = self.deposits[:deposit_count]
        _, deposit_root = make_deposit_tree_and_root(deposits)
        return deposit_root


from flask import Flask,render_template,request
import os
import random

app = Flask(__name__)#Flaskクラスのインスタンス生成

num_list=[0,1,2,3,4,5,6,7,8,9]
target_num = random.sample(num_list,3)
num_log=[]
eat_log=[]
bite_log=[]
length=0

@app.route('/',methods=['GET','POST'])
def start():
   if request.method=="GET":
      global target_num
      target_num= random.sample(num_list,3)
      global num_log
      num_log=[]
      global eat_log
      eat_log=[]
      global bite_log
      bite_log=[]
      global length
      length=0
   return render_template('start.html')
@app.route('/first_declare/',methods=['GET','POST'])
def first_declare():
   return render_template('first_declare.html',title='コンピュータが数字を設定しました。',target_num=target_num)

@app.route('/main_declare',methods=['GET','POST'])
def main_declare():
   user_num=request.form['user']
   eat=0
   bite=0
   if not user_num.isdecimal():
      return render_template('main_declare.html',title='整数を入力してよ',num_log='/',eat_log='/',bite_log='/',eat=0,length=0)
   elif len(user_num) !=3:
      return render_template('main_declare.html',title='3桁の数字で入力してよ',num_log='/',eat_log='/',bite_log='/',eat=0,length=0)
   elif user_num.count(user_num[0])!=1 or user_num.count(user_num[1])!=1 or user_num.count(user_num[2])!=1:
      return render_template('main_declare.html',title='重複は論外だよ！しっかりやってね',num_log='/',eat_log='/',bite_log='/',eat=0,length=0)
   num_log.append(user_num)
   length=len(num_log)
   for index,i_tar in enumerate(target_num):
      for cnt in range(3):
         if str(target_num[index])==user_num[index]:
            eat+=1
            break
         elif str(i_tar) in user_num:
            bite+=1
            break
   eat_log.append(eat)
   bite_log.append(bite)

   if eat!=3:
      return render_template('main_declare.html',title='残念！　ハズレだドン！！！',num_log=num_log,eat_log=eat_log,bite_log=bite_log,eat=eat,length=length)
   elif eat==3:
      return render_template('main_declare.html',title='クリア！！おめでとドン！！！！',num_log=num_log,eat_log=eat_log,bite_log=bite_log,eat=eat,length=length)

app.run(debug=True,host='0.0.0.0',port=8888,threaded=True)#Webアプリの起動（Flaskサーバの起動）


from typing import Optional

from buffett.adapter.pandas import DataFrame
from buffett.common import Code
from buffett.common.tools import create_meta, dataframe_not_valid
from buffett.common.constants.col import FREQ, FUQUAN, SOURCE, START_DATE, END_DATE
from buffett.common.constants.col.stock import CODE
from buffett.common.constants.table import DL_RCD
from buffett.download import Para
from buffett.download.mysql import Operator
from buffett.download.mysql.types import ColType, AddReqType
from buffett.download.types import FreqType, FuquanType, SourceType

_META = create_meta(meta_list=[
    [CODE, ColType.CODE, AddReqType.KEY],
    [FREQ, ColType.ENUM_BOOL, AddReqType.KEY],
    [FUQUAN, ColType.ENUM_BOOL, AddReqType.KEY],
    [SOURCE, ColType.ENUM_BOOL, AddReqType.KEY],
    [START_DATE, ColType.DATETIME, AddReqType.NONE],
    [END_DATE, ColType.DATETIME, AddReqType.NONE]])

class DownloadRecorder:
    def __init__(self, operator: Operator):
        self._operator = operator
        self._exist = False

    def save(self, para: Para) -> None:
        ls = [[para.stock.code, para.comb.freq, para.comb.fuquan, para.comb.source, para.span.start, para.span.end]]
        cols = [CODE, FREQ, FUQUAN, SOURCE, START_DATE, END_DATE]
        data = DataFrame(data=ls, columns=cols)
        self.save_to_database(data=data)

    def save_to_database(self,
                         data: DataFrame) -> None:
        if not self._exist:
            self._operator.create_table(DL_RCD, _META, if_not_exist=True)
            self._exist = True

        self._operator.try_insert_data(DL_RCD, data, _META, update=True)  # 如果原纪录已存在，则更新

    def select_data(self) -> Optional[DataFrame]:
        df = self._operator.select_data(DL_RCD)
        if dataframe_not_valid(df):
            return

        df[CODE] = df[CODE].apply(lambda x: Code(x))
        df[FREQ] = df[FREQ].apply(lambda x: FreqType(x))
        df[FUQUAN] = df[FUQUAN].apply(lambda x: FuquanType(x))
        df[SOURCE] = df[SOURCE].apply(lambda x: SourceType(x))
        return df


from collections import defaultdict
import json
import logging

from jose import (
    jwk,
    jwt,
)
import tornado.ioloop
from tornado.web import (
    Application,
    HTTPError,
    RequestHandler,
)

logger = logging.getLogger()
logger.setLevel("DEBUG")

with open("./data/iam-prod-keys.json") as kf:
    KEYS = json.load(kf)
ISSUER = "https://iam.humanbrainproject.eu/auth/realms/hbp"

def bearer_authtenticated(fn: callable) -> callable:
    def wrapped(self: RequestHandler, *args, **kwargs):
        try:
            bearer = self.request.headers["authorization"].split(" ")[1]
        except Exception:
            self.write("Requires authorization with a Bearer token")
            raise HTTPError(401, f"Authorization failed, no header")
        try:
            payload = jwt.decode(
                bearer,
                KEYS,
                algorithms=["RS256"],
                issuer=ISSUER,
                options={"verify_aud": False},
            )
        except jwt.JWTError as e:
            raise HTTPError(401, f"Authorization failed {e}")
        user = payload["preferred_username"]
        return fn(self, user, *args, **kwargs)

    return wrapped

class InvalidVoteException(Exception):
    pass

class VotesHandler(RequestHandler):
    _options = ['A', 'B', 'C']

    @bearer_authtenticated
    def get(self, user: str) -> None:
        self.write({'vote': self.application.context['votes'][user]})

    @bearer_authtenticated
    def post(self, user: str) -> None:
        logging.info("Posting vote")
        try:
            vote = json.loads(self.request.body)['vote']
            self._validate(vote)
        except KeyError:
            self.write({"Error": f"Vote is required."})
            raise HTTPError(400, "Invalid option for vote.")
        except InvalidVoteException:
            self.write({"Error": f"Vote should be one of {self._options}"})
            raise HTTPError(400, "Invalid option for vote.")
        except json.JSONDecodeError:
            self.write({"error": "Invalid JSON"})
            raise HTTPError(400, "Invalid json")
        old = self.application.context['votes'][user]
        if old and not (old == vote):
            self.application.context['tally'][old] -= 1
        changed = not old == vote
        if changed:
            self.application.context['tally'][vote] += 1
            self.application.context['votes'][user] = vote
        logging.info(f"voted for: {vote}, new: {not old}, changed: {changed}")
        self.write(f"hello {user}")

    def _validate(self, vote):
        if vote not in self._options:
            raise InvalidVoteException

class ResultsHandler(RequestHandler):
    def get(self):
        self.write(self.application.context['tally'])

def main():
    import os
    try:
        port = int(os.environ.get('SVC_PORT'), 8080)
    except Exception:
        port = 8080
    app = Application([
        ("/votes", VotesHandler),
        ("/results", ResultsHandler),
    ])
    app.context = {
        "votes": defaultdict(lambda: None),
        "version": 0,
        "tally": defaultdict(int),
    }
    app.listen(port)
    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()


#!/usr/bin/env python
#
# Visualize image with numpy and matplotlib.
#
# Last revision: 24/01/2022
from __future__ import print_function, division

import os, sys, numpy as np
import matplotlib.pyplot as plt

imgfile = sys.argv[1]

# Read info file
info = np.genfromtxt(imgfile+'.info',comments='#')
ch   = int(info[0]) # Number of channels
w    = int(info[1]) # Width
h    = int(info[2]) # Heigth

# Load image data - double array
data = np.fromfile(imgfile+'.bin').reshape(h,w,ch)

# Convert to image (uint8)
img = np.clip(data*(1<<8-1),0,1<<8-1).astype(np.uint8)

# Show image
plt.imshow(img)
plt.show()


# This code process the data according to logistic regression
import sklearn.linear_model

class Lr:
    def __init__(self,prob = 0.5):
        self.trainingData = []
        self.testingData = []
        self.prob = prob

    def setTrainingData(self,trainingData):
        self.trainingData = trainingData

    def setTestingData(self,testingData):
        self.testingData = testingData

    def buildModel(self):
        """Building sklearn linear model from training data"""
        featureVecs, labels = [],[]
        for p in self.trainingData:
            featureVecs.append(p.getFeatureVec())
            labels.append(p.getOutcome())
        LogisticRegression = sklearn.linear_model.LogisticRegression
        model = LogisticRegression().fit(featureVecs, labels)
        return model

    def applyModel(self,model,label):
        """Applying model to test data"""
        testFeatureVecs = [e.getFeatureVec() for e in self.testingData]
        probs = model.predict_proba(testFeatureVecs)
        truePos, falsePos, trueNeg, falseNeg = 0, 0, 0, 0
        for i in range(len(probs)):
            if probs[i][1] > self.prob:
                if self.testingData[i].getOutcome() == label:
                    truePos += 1
                else:
                    falsePos += 1
            else:
                if self.testingData[i].getOutcome() != label:
                    trueNeg += 1
                else:
                    falseNeg += 1
        return truePos, falsePos, trueNeg, falseNeg

    def getResult(self,lable):
        model = self.buildModel()
        return self.applyModel(model,lable)


import logging
import mmap
import shutil
import tempfile
import os

from fastapi import HTTPException
from turbinia import config as turbinia_config

log = logging.getLogger('turbinia:api_server:utils')

def create_zip(request_id: str, task_id: str):
  """Compress a Turbinia request or task's output directories into a zip file.

  Args:
    request_id (str): Turbinia request identifier.
    task_id (str): Turbinia task identifier.

  Returns:
    A zip compressed bytes stream

  Raises:
    HTTPException if the request/task output paths could not be found
        on the file system.
  """
  log_path = turbinia_config.toDict().get('OUTPUT_DIR')

  request_output_path = os.path.join(log_path, request_id)

  if task_id:
    try:
      request_dirs = os.listdir(request_output_path)
    except FileNotFoundError as exception:
      message = 'Output path {0:s} for task {1:s} could not be found.'.format(
          request_output_path, task_id)
      log.error(message)
      raise HTTPException(status_code=404, detail=message) from exception

    for request_dir in request_dirs:
      if task_id in request_dir:
        request_output_path = os.path.join(request_output_path, request_dir)
        break

  if not os.path.exists(request_output_path):
    message = 'Output path {0:s} for request {1:s} could not be found.'.format(
        request_output_path, request_id)
    log.error(message)
    raise HTTPException(status_code=404, detail=message)

  # Create a temporary directory to store the zip file
  # containing the request result files.
  # Directory and its contents deleted upon context exit.
  temp_directory = tempfile.TemporaryDirectory()
  with temp_directory as directory_name:
    if task_id:
      zip_path = os.path.join(directory_name, task_id)
    else:
      zip_path = os.path.join(directory_name, request_id)

    # Create the zip file
    zip_filename = shutil.make_archive(zip_path, 'zip', request_output_path)
    data = None

    # Read the zip using a memory-mapped file and return it
    with open(zip_filename, 'rb') as zip_obj:
      mm = mmap.mmap(zip_obj.fileno(), 0, access=mmap.ACCESS_READ)
      data = mm.read()

    return data


import torch
import esm
import gc
from typing import List, Dict

class ESM2_Embeddings:
    def __init__(self, model_variant: str):

        if model_variant == 't36':
            embedding_model, alphabet = esm.pretrained.esm2_t36_3B_UR50D()
        elif model_variant == 't33':
            embedding_model, alphabet = esm.pretrained.esm2_t33_650M_UR50D()
        elif model_variant == 't30':
            embedding_model, alphabet = esm.pretrained.esm2_t30_150M_UR50D()
        elif model_variant == 't12':
            embedding_model, alphabet = esm.pretrained.esm2_t12_35M_UR50D()
        else:
            embedding_model, alphabet = esm.pretrained.esm2_t6_8M_UR50D()

        self.embedding_model = embedding_model
        self.alphabet = alphabet
        self.n_layers = int(model_variant[1:])

    def generate_embeddings(self, sequences: List[str], ids: List[str]) -> Dict[str, torch.tensor]:

        tokenizer = self.alphabet.get_batch_converter()
        device = torch.device("cpu")

        self.embedding_model.to(device)
        self.embedding_model.eval()

        sequence_ids = list(zip(ids, sequences))

        ind = 0
        batch_size = 16
        n_seqs = len(sequence_ids)
        embedding_ids = {}

        while ind < n_seqs:
            if ind + batch_size > n_seqs:
                batch_size = n_seqs - ind
            _, _, batch_tokens = tokenizer(sequence_ids[ind:ind + batch_size])
            batch_lens = (batch_tokens != self.alphabet.padding_idx).sum(1)
            with torch.no_grad():
                batch_tokens = batch_tokens.to(device)
                results = self.embedding_model(batch_tokens, repr_layers=[self.n_layers])
            token_representations = results["representations"][self.n_layers].to(device)

            for i, tokens_len in enumerate(batch_lens):
                embedding_ids[sequence_ids[ind + i][0]] = token_representations[i, 1:tokens_len - 1].cpu()
            ind += batch_size

        del self.embedding_model
        del tokenizer
        gc.collect()

        return embedding_ids


from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import Post
from .forms import PostForm
from django.shortcuts import redirect

#postのlistを見せる
def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

#postの内容を見る
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

#新しい内容を書く
def post_new(request):
    #htmlのformからPOSTなら
    if request.method == "POST":
        #formのデータを減数formに入れる
        form = PostForm(request.POST)
        #validation後データを保存
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

def post_delete(request, pk):
    if pk  is not None:
        Post.objects.filter(pk=pk).delete()

    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})


import unittest
import requests
from unittest.mock import patch, Mock
from morphosource.search import search_media, get_media, Media, Endpoints, ItemNotFound, \
    get_object, ObjectTypes, search_objects, MetadataMissingError
from morphosource.download import DownloadVisibility
from morphosource.search import Media

MS_MEDIA = [
    {
        'id': ['000390223'],
        'title': ['Dentary Teeth [Mesh] [CT]'],
        'media_type': ['Mesh'],
        "visibility": ["Open Download"],
        "physical_object_id": ["000577960"],
        'file_thumbnail_url': ['/downloads/000390223?file=thumbnail&t=1604144137'],
    },
    {
        'id': ['000390218'],
        'title': ['Maxillary Teeth [Mesh] [CT]'],
        'media_type': ['Mesh'],
        "visibility": ["Restricted Download"],
        "physical_object_id": ["000577960"]
    },
]
MS_FACETS = [{'name': 'generic_type_sim', 'items': [], 'label': 'Generic Type Sim'}]
MS_PAGES = {
    'current_page': 1,
    'next_page': None,
    'prev_page': None,
    'total_pages': 1,
    'limit_value': 10,
    'offset_value': 0,
    'total_count': 2,
    'first_page?': True,
    'last_page?': True,
}
MS_SPECIMEN = [{
    'id': ['000577960'],
    'title': ['MCZ:SC:4041'],
    'type': ['Biological Specimen'],
    'taxonomy': ['Lithobates catesbeiana'],
}]
MS_CULTURAL_OBJECT = [{
    'id': ['000545101'],
    'title': ['YPM:ANT:131819 Spindle Whorl'],
    'type': ['Cultural Heritage Object'],
}]
MS_FILE_METADATA = {
    'file_name': ['AMNH-196405-Macaca-tonkeana-hecki-teeth-DICOM.zip'],
    'file_size': [1784225321],
    'mime_type': ['application/zip'],
    'contents_mime_type': ['application/dicom'],
    'date_uploaded': ['2020-10-21T00:48:47Z'],
    'date_modified': ['2020-10-21T00:48:47Z']
}

class TestSearch(unittest.TestCase):
    @patch("morphosource.search.fetch_items")
    def test_search_media(self, mock_fetch_items):
        mock_fetch_items.return_value = MS_MEDIA, MS_FACETS, MS_PAGES
        results = search_media("Fruitadens")
        self.assertEqual(len(results.items), 2)
        self.assertEqual(results.items[0].id, "000390223")
        self.assertEqual(results.items[0].title, "Dentary Teeth [Mesh] [CT]")
        self.assertEqual(results.items[0].media_type, "Mesh")
        self.assertEqual(results.items[0].visibility, "Open Download")
        self.assertEqual(results.items[0].data, MS_MEDIA[0])
        self.assertEqual(len(results.facets), 1)
        self.assertEqual(results.pages['total_count'], 2)
        mock_fetch_items.assert_called_with(
            url=Endpoints.MEDIA, query="Fruitadens", params={}, per_page=None, page=None, items_name="media"
        )

    @patch("morphosource.search.fetch_items")
    def test_search_media_advanced(self, mock_fetch_items):
        mock_fetch_items.return_value = MS_MEDIA, MS_FACETS, MS_PAGES
        results = search_media(
            "Fruitadens", media_type="Mesh", visibility=DownloadVisibility.OPEN, media_tag="pelvis", per_page=8, page=2
        )
        expected_params = {
            'f.media_type': 'Mesh',
            'f.publication_status': 'Open Download',
            'f.tag': 'pelvis',
        }
        mock_fetch_items.assert_called_with(
            url=Endpoints.MEDIA, query="Fruitadens", params=expected_params, per_page=8, page=2, items_name="media"
        )

    @patch("morphosource.search.fetch_item")
    def test_get_media(self, mock_fetch_item):
        mock_fetch_item.return_value = {"media": MS_MEDIA[0]}
        media = get_media(media_id="123")
        self.assertEqual(media.id, "000390223")
        self.assertEqual(media.title, "Dentary Teeth [Mesh] [CT]")
        self.assertEqual(media.media_type, "Mesh")
        self.assertEqual(media.visibility, "Open Download")
        self.assertEqual(media.data, MS_MEDIA[0])
        mock_fetch_item.assert_called_with(f"{Endpoints.MEDIA}/123")

    @patch("morphosource.search.fetch_item")
    def test_get_media_not_found(self, mock_fetch_item):
        error = requests.exceptions.HTTPError()
        error.response = Mock(status_code=404)
        mock_fetch_item.side_effect = error
        with self.assertRaises(ItemNotFound) as raised_exception:
            media = get_media(media_id="123")
        self.assertEqual(str(raised_exception.exception), "No media found with id 123")

    @patch("morphosource.search.fetch_items")
    def test_search_biological_specimen(self, mock_fetch_items):
        mock_fetch_items.return_value = MS_SPECIMEN, MS_FACETS, MS_PAGES
        results = search_objects("Fruitadens", object_type=ObjectTypes.BIOLOGICAL_SPECIMEN)
        self.assertEqual(len(results.items), 1)
        self.assertEqual(results.items[0].id, "000577960")
        self.assertEqual(results.items[0].title, "MCZ:SC:4041")
        self.assertEqual(results.items[0].type, ObjectTypes.BIOLOGICAL_SPECIMEN)
        self.assertEqual(results.items[0].data, MS_SPECIMEN[0])
        self.assertEqual(len(results.facets), 1)
        self.assertEqual(results.pages['total_count'], 2)
        expected_params = {'f.object_type': 'Biological Specimen'}
        mock_fetch_items.assert_called_with(
            url=Endpoints.PHYSICAL_OBJECTS, query="Fruitadens", params=expected_params,
            per_page=None, page=None, items_name="physical_objects"
        )

    @patch("morphosource.search.fetch_items")
    def test_biological_specimen_advanced(self, mock_fetch_items):
        mock_fetch_items.return_value = MS_SPECIMEN, MS_FACETS, MS_PAGES
        results = search_objects("Fruita", object_type=ObjectTypes.BIOLOGICAL_SPECIMEN,
                                 taxonomy_gbif="Ornithischia", media_type="Mesh", media_tag="pelvis",
                                 per_page=8, page=2)
        expected_params = {
            'f.object_type': 'Biological Specimen',
            'f.taxonomy_gbif': 'Ornithischia',
            'f.media_type': 'Mesh',
            'f.media_tag': 'pelvis'
        }
        mock_fetch_items.assert_called_with(
            url=Endpoints.PHYSICAL_OBJECTS, query="Fruita", params=expected_params,
            per_page=8, page=2, items_name="physical_objects"
        )

    @patch("morphosource.search.fetch_items")
    def test_search_artifact(self, mock_fetch_items):
        mock_fetch_items.return_value = MS_CULTURAL_OBJECT, MS_FACETS, MS_PAGES
        results = search_objects("Spindle", object_type=ObjectTypes.CULTURAL_HERITAGE)
        self.assertEqual(len(results.items), 1)
        self.assertEqual(results.items[0].id, "000545101")
        self.assertEqual(results.items[0].title, "YPM:ANT:131819 Spindle Whorl")
        self.assertEqual(results.items[0].type, ObjectTypes.CULTURAL_HERITAGE)
        self.assertEqual(results.items[0].data, MS_CULTURAL_OBJECT[0])
        self.assertEqual(len(results.facets), 1)
        self.assertEqual(results.pages['total_count'], 2)
        expected_params = {'f.object_type': 'Cultural Heritage Object'}
        mock_fetch_items.assert_called_with(
            url=Endpoints.PHYSICAL_OBJECTS, query="Spindle", params=expected_params,
            per_page=None, page=None, items_name="physical_objects"
        )

    @patch("morphosource.search.fetch_items")
    def test_artifact_advanced(self, mock_fetch_items):
        mock_fetch_items.return_value = MS_SPECIMEN, MS_FACETS, MS_PAGES
        results = search_objects("Spindle", object_type=ObjectTypes.CULTURAL_HERITAGE,
                                 media_type="Mesh", media_tag="ceramic", per_page=8, page=2)
        expected_params = {
            'f.object_type': 'Cultural Heritage Object',
            'f.media_type': 'Mesh',
            'f.media_tag': 'ceramic'
        }
        mock_fetch_items.assert_called_with(
            url=Endpoints.PHYSICAL_OBJECTS, query="Spindle", params=expected_params,
            per_page=8, page=2, items_name="physical_objects"
        )

    @patch("morphosource.search.fetch_item")
    def test_get_biological_specimen(self, mock_fetch_item):
        mock_fetch_item.return_value = {"biological_specimen": MS_SPECIMEN[0]}
        obj = get_object(object_id="123")
        self.assertEqual(obj.id, "000577960")
        self.assertEqual(obj.title, "MCZ:SC:4041")
        self.assertEqual(obj.taxonomy, "Lithobates catesbeiana")
        self.assertEqual(obj.type, ObjectTypes.BIOLOGICAL_SPECIMEN)
        self.assertEqual(obj.data, MS_SPECIMEN[0])
        mock_fetch_item.assert_called_with(f"{Endpoints.PHYSICAL_OBJECTS}/123")

    @patch("morphosource.search.fetch_item")
    def test_get_cultural_heritage_object(self, mock_fetch_item):
        mock_fetch_item.return_value = {"cultural_heritage_object": MS_CULTURAL_OBJECT[0]}
        obj = get_object(object_id="123")
        self.assertEqual(obj.id, "000545101")
        self.assertEqual(obj.title, "YPM:ANT:131819 Spindle Whorl")
        self.assertEqual(obj.type, ObjectTypes.CULTURAL_HERITAGE)
        self.assertEqual(obj.taxonomy, None)
        self.assertEqual(obj.data, MS_CULTURAL_OBJECT[0])
        mock_fetch_item.assert_called_with(f"{Endpoints.PHYSICAL_OBJECTS}/123")

    @patch("morphosource.search.fetch_item")
    def test_get_biological_specimen_not_found(self, mock_fetch_item):
        error = requests.exceptions.HTTPError()
        error.response = Mock(status_code=404)
        mock_fetch_item.side_effect = error
        with self.assertRaises(ItemNotFound) as raised_exception:
            obj = get_object(object_id="123")
        self.assertEqual(str(raised_exception.exception), "No object found with id 123")

    @patch("morphosource.search.fetch_item")
    @patch("morphosource.search.search_media")
    def test_physicial_object_get_media_ary(self, mock_search_media, mock_fetch_item):
        mock_fetch_item.return_value = {"biological_specimen": MS_SPECIMEN[0]}
        media1 = Media(MS_MEDIA[0])
        media2 = Media(MS_MEDIA[1])
        mock_search_media.return_value = Mock(items=[media1, media2])
        obj = get_object(object_id="123")

        ary = obj.get_media_ary()
        self.assertEqual(ary, [media1, media2])
        mock_search_media.assert_called_with(query='000577960', visibility=None)

        ary = obj.get_media_ary(visibility=DownloadVisibility.OPEN)
        mock_search_media.assert_called_with(query='000577960', visibility=DownloadVisibility.OPEN)

        ary = obj.get_media_ary(visibility=DownloadVisibility.RESTRICTED)
        mock_search_media.assert_called_with(query='000577960', visibility=DownloadVisibility.RESTRICTED)

    def test_get_website_url(self):
        media = Media(MS_MEDIA[0])
        url = media.get_website_url()
        self.assertEqual(url, "https://www.morphosource.org/concern/media/000390223")

    def test_get_thumbnail_url(self):
        media = Media(MS_MEDIA[0])
        url = media.get_thumbnail_url()
        self.assertEqual(url, "https://www.morphosource.org/downloads/000390223?file=thumbnail&t=1604144137")

        media = Media(MS_MEDIA[1])
        url = media.get_thumbnail_url()
        self.assertEqual(url, None)

    @patch("morphosource.search.fetch_item")
    def test_get_file_metadata(self, mock_fetch_item):
        mock_fetch_item.return_value = {"file_set": MS_FILE_METADATA}
        media = Media(MS_MEDIA[0])
        metadata = media.get_file_metadata()
        self.assertEqual(metadata.file_name, "AMNH-196405-Macaca-tonkeana-hecki-teeth-DICOM.zip")
        self.assertEqual(metadata.file_size, 1784225321)
        self.assertEqual(metadata.mime_type, "application/zip")
        self.assertEqual(metadata.contents_mime_type, "application/dicom")
        self.assertEqual(metadata.data, MS_FILE_METADATA)

    @patch("morphosource.search.fetch_item")
    def test_get_file_metadata_empty_metadata(self, mock_fetch_item):
        mock_fetch_item.return_value = {}
        media = Media(MS_MEDIA[0])
        with self.assertRaises(MetadataMissingError) as raised_exception:
            media.get_file_metadata()
        self.assertEqual(str(raised_exception.exception),
                         "No metadata returned by MorphoSource for id: 000390223")


from keras import backend as K
import numpy as np
import cv2

def balanced_binary_crossentropy(y_true, y_pred):
    """Binary crossentropy loss function with automatic class balancing"""
    y_true_f = K.cast(y_true,K.floatx())
    num_pos = K.sum(y_true_f)+1
    num_neg = K.sum(1-y_true_f)+1
    #weights = 1/(2*num_pos)*y_true + 1/(2*num_neg)*(1-y_true)
    weights = (num_neg)/(num_pos)*y_true_f + (1-y_true_f)
    score_array = K.binary_crossentropy(y_pred,y_true_f)
    score_array *= weights
    score_array /= K.mean(K.cast(K.not_equal(weights, 0), K.floatx()))
    return K.mean(score_array)

def pad_images(imgs,pad):
    """Pad images with reflection padding"""
    imgs_p = np.ndarray((imgs.shape[0], imgs.shape[1]+pad*2, imgs.shape[2]+pad*2, imgs.shape[3]), dtype=imgs.dtype)
    for i in xrange(imgs.shape[0]):
        imgs_p[i,:,:,:] = cv2.copyMakeBorder(imgs[i,:,:,:],pad,pad,pad,pad,cv2.BORDER_REFLECT)
    return imgs_p

def remove_mean(imgs):
    """Subtract per-channel mean from each image"""
    for i in xrange(imgs.shape[0]):
        for j in xrange(imgs.shape[3]):
            imgs[i,:,:,j] -= np.mean(imgs[i,:,:,j])
    return imgs


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 05:10:10 2020

@author: coyote

This is to test overlapping nodes in TntaAt with the other databases
"""

import logging
from neo4j import GraphDatabase
from neo4j.exceptions import ServiceUnavailable
import create_mysql_db
from create_mysql_db import *
import pandas as pd
import numpy as np
import requests
import re
import json

############################################################################
"""
This script also loads data into the MySQL data warehouse
based on the issue that there was not gene name data for
the MEROPS substrates for the 'name' or label of the nodes
in Neo4j
"""
############################################################################

userMySQL='dummy'
passwordMySQL='password'
hostMySQL='127.0.0.1'
dbMySQL = 'protTest'

cnx = connect(userMySQL, passwordMySQL, hostMySQL)
cursor = cnx.cursor(dictionary=True)
use_database(cnx, cursor, dbMySQL)

## testing data and queries for loading into neo4j
from queries import query_merops
cursor.execute(query_merops)
merops_sel = cursor.fetchall()
merops = pd.DataFrame([[i['interactorA'], i['interactorB'],
                        i["interactionID"], i['uniProtID'],
                        i['cleavageID']] for i in merops_sel])
merops
merops.columns = ['interactorA','interactorB',"interactionID", 'uniProtID', 'cleavageID']
merops_IDs = np.unique(merops['cleavageID'])

from queries import query_psp
cursor.execute(query_psp)
psp_sel = cursor.fetchall()
psp = pd.DataFrame([[i['interactorA'], i['interactorB'],
                     i["interactionID"], i['uniProtID']] for i in psp_sel])
psp
psp.columns = ['interactorA','interactorB',"interactionID", 'uniProtID']

from queries import query_ppase
cursor.execute(query_ppase)
ppase_sel = cursor.fetchall()
ppase = pd.DataFrame([[i['interactorA'], i['interactorB'],
                       i["interactionID"], i['uniProtID']] for i in ppase_sel])
ppase
ppase.columns = ['interactorA','interactorB',"interactionID", 'uniProtID']

np.unique([merops['interactorA'], merops['interactorB']])
np.unique([psp['interactorA'], psp['interactorB']])
np.unique(psp['interactorB'])
np.unique([ppase['interactorA'], ppase['interactorB']])
np.unique(ppase['interactorB'])

get_uniprot = np.unique((merops['interactorA'].tolist() +
                         merops['interactorB'].tolist() +
                         psp['interactorA'].tolist() +
                         psp['interactorB'].tolist() +
                         ppase['interactorA'].tolist() +
                         ppase['interactorB'].tolist() +
                         merops['uniProtID'].tolist() +
                         psp['uniProtID'].tolist() +
                         ppase['uniProtID'].tolist()))

get_intact = np.unique((merops['interactionID'].tolist() +
                         psp['interactionID'].tolist() +
                         ppase['interactionID'].tolist()))

len(get_uniprot)
len(get_intact)

###############################################################################
## Not getting good data for gene names for merops substrates
## Need to get merops substrate genes names from UniProt
## Merops only had a description column which was hard to
## get gene names for nodes. Do this with batch request

query_merops3 = """
SELECT DISTINCT s.Uniprot AS substrateUniprot
FROM protTest.Substrate_search s
INNER JOIN
	protTest.proteinsUniprot p
    ON p.meropsID = s.`code` AND s.organism LIKE CONCAT('%%', p.organism, '%%')
WHERE s.Uniprot IS NOT NULL
"""
## non dict cursor
cursor = cnx.cursor()
cursor.execute(query_merops3)
merops_subs = cursor.fetchall()
arr = [i[0] for i in merops_subs]
len(merops_subs)
merops_subs2 = [i[0][0:6] for i in merops_subs]
up_tbl_cols = ["id", "reviewed", "entry name", "genes(PREFERRED)",
               "genes(ALTERNATIVE)", "organism-id", "organism"]
up_tbl_cols = ["accession", "reviewed", "id", "gene_primary",
               "gene_synonym", "organism_id", "organism_name"]

up_tbl_cols = ["accession", "id", "reviewed", "protein_name", "gene_primary",
               "gene_synonym", "gene_names" , "cc_interaction", "organism_id", "organism_name",
               "protein_families", "length", "xref_merops"]
up_tbl_cols = ["id", "entry name", "reviewed", "protein names", "genes(PREFERRED)",
               "genes(ALTERNATIVE)", "genes" , "interactor", "organism-id", "organism",
               "families", "length", "database(MEROPS)"]

# Uniprot batch request docs!
#https://www.biostars.org/p/304247/
#https://www.ebi.ac.uk/training/online/sites/ebi.ac.uk.training.online/files/UniProt_programmatically_py3.pdf
BASE = "http://www.uniprot.org"
TOOL_ENDPOINT = "/uploadlists/"

from requests.adapters import HTTPAdapter, Retry
from urllib.parse import urlparse, parse_qs, urlencode
import zlib
POLLING_INTERVAL = 3

API_URL = "https://rest.uniprot.org"

retries = Retry(total=5, backoff_factor=0.25, status_forcelist=[500, 502, 503, 504])
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=retries))

def check_response(response):
    try:
        response.raise_for_status()
    except requests.HTTPError:
        print(response.json())
        raise

def submit_id_mapping(from_db, to_db, ids):
    request = requests.post(
        f"{API_URL}/idmapping/run",
        data={"from": from_db, "to": to_db, "ids": ",".join(ids)},
    )
    check_response(request)
    return request.json()["jobId"]

def get_next_link(headers):
    re_next_link = re.compile(r'<(.+)>; rel="next"')
    if "Link" in headers:
        match = re_next_link.match(headers["Link"])
        if match:
            return match.group(1)

def check_id_mapping_results_ready(job_id):
    while True:
        request = session.get(f"{API_URL}/idmapping/status/{job_id}")
        check_response(request)
        j = request.json()
        if "jobStatus" in j:
            if j["jobStatus"] == "RUNNING":
                print(f"Retrying in {POLLING_INTERVAL}s")
                time.sleep(POLLING_INTERVAL)
            else:
                raise Exception(j["jobStatus"])
        else:
            return bool(j["results"] or j["failedIds"])

def get_batch(batch_response, file_format, compressed):
    batch_url = get_next_link(batch_response.headers)
    while batch_url:
        batch_response = session.get(batch_url)
        batch_response.raise_for_status()
        yield decode_results(batch_response, file_format, compressed)
        batch_url = get_next_link(batch_response.headers)

def combine_batches(all_results, batch_results, file_format="tsv"):
    if file_format == "json":
        for key in ("results", "failedIds"):
            if key in batch_results and batch_results[key]:
                all_results[key] += batch_results[key]
    elif file_format == "tsv":
        return all_results + batch_results[1:]
    else:
        return all_results + batch_results
    return all_results

def get_id_mapping_results_link(job_id):
    url = f"{API_URL}/idmapping/details/{job_id}"
    request = session.get(url)
    check_response(request)
    return request.json()["redirectURL"]

def decode_results(response, file_format, compressed):
    if compressed:
        decompressed = zlib.decompress(response.content, 16 + zlib.MAX_WBITS)
        if file_format == "json":
            j = json.loads(decompressed.decode("utf-8"))
            return j
        elif file_format == "tsv":
            return [line for line in decompressed.decode("utf-8").split("\n") if line]
        elif file_format == "xlsx":
            return [decompressed]
        elif file_format == "xml":
            return [decompressed.decode("utf-8")]
        else:
            return decompressed.decode("utf-8")
    elif file_format == "json":
        return response.json()
    elif file_format == "tsv":
        return [line for line in response.text.split("\n") if line]
    elif file_format == "xlsx":
        return [response.content]
    elif file_format == "xml":
        return [response.text]
    return response.text

def get_xml_namespace(element):
    m = re.match(r"\{(.*)\}", element.tag)
    return m.groups()[0] if m else ""

def merge_xml_results(xml_results):
    merged_root = ElementTree.fromstring(xml_results[0])
    for result in xml_results[1:]:
        root = ElementTree.fromstring(result)
        for child in root.findall("{http://uniprot.org/uniprot}entry"):
            merged_root.insert(-1, child)
    ElementTree.register_namespace("", get_xml_namespace(merged_root[0]))
    return ElementTree.tostring(merged_root, encoding="utf-8", xml_declaration=True)

def print_progress_batches(batch_index, size, total):
    n_fetched = min((batch_index + 1) * size, total)
    print(f"Fetched: {n_fetched} / {total}")

def get_id_mapping_results_search(url):
    parsed = urlparse(url)
    query = parse_qs(parsed.query)
    file_format = query["format"][0] if "format" in query else "json"
    if "size" in query:
        size = int(query["size"][0])
    else:
        size = 500
        query["size"] = size
    compressed = (
        query["compressed"][0].lower() == "true" if "compressed" in query else False
    )
    parsed = parsed._replace(query=urlencode(query, doseq=True))
    url = parsed.geturl()
    request = session.get(url)
    check_response(request)
    results = decode_results(request, file_format, compressed)
    total = int(request.headers["x-total-results"])
    print_progress_batches(0, size, total)
    for i, batch in enumerate(get_batch(request, file_format, compressed), 1):
        results = combine_batches(results, batch, file_format)
        print_progress_batches(i, size, total)
    if file_format == "xml":
        return merge_xml_results(results)
    return results

def get_id_mapping_results_stream(url):
    if "/stream/" not in url:
        url = url.replace("/results/", "/results/stream/")
    request = session.get(url)
    check_response(request)
    parsed = urlparse(url)
    query = parse_qs(parsed.query)
    file_format = query["format"][0] if "format" in query else "json"
    compressed = (
        query["compressed"][0].lower() == "true" if "compressed" in query else False
    )
    return decode_results(request, file_format, compressed)

job_id = submit_id_mapping(
    from_db="UniProtKB_AC-ID", to_db="ChEMBL", ids=["P05067", "P12345"]
)
if check_id_mapping_results_ready(job_id):
    link = get_id_mapping_results_link(job_id)
    results = get_id_mapping_results_search(link)
    # Equivalently using the stream endpoint which is more demanding
    # on the API and so is less stable:
    # results = get_id_mapping_results_stream(link)
    results = get_id_mapping_results_stream(link + '?compressed=true&fields=' + \
                                             ','.join(up_tbl_cols) + \
                                             '&format=tsv')

merops_up_sub_tbl = pd.DataFrame([x.split("\t") for x in results[1:]],
                                 columns=results[0].split("\t"))
job_id='4e69c039e10625d01d2bb20341684fb127220125'  # 6587 results
#job_id='61a46976682a51e5910ae26363a869b98e1342f1'
if check_id_mapping_results_ready(job_id):
    link = get_id_mapping_results_link(job_id)
    results = get_id_mapping_results_search(link)

def map_retrieve(ids2map, source_fmt='ACC+ID', target_fmt='ACC', output_fmt='tab'):
    if hasattr(list(ids2map), 'pop'):
        pass #ids2map = ','.join(ids2map)

    payload = {'ids': ids2map,
               'format': output_fmt,
               'columns': ','.join(up_tbl_cols),
               'from': source_fmt,
               'to': target_fmt}

    response = requests.get("https://rest.uniprot.org/idmapping/run", params=payload)
    response = requests.post("https://rest.uniprot.org/idmapping/run", params=payload)
    response.raise_for_status()

    request = requests.post(
        "https://rest.uniprot.org/idmapping/run",
        data={"from": "UniProtKB_AC-ID", "to": "UniProtKB", "ids": merops_subs2,
              "fields": ','.join(up_tbl_cols)}
    )
    request.raise_for_status()
    request.text

    if response.ok:
        protein_df = pd.read_csv(StringIO(response.text), sep="\t")
        ## pandas is good but need to pass None to MySQL
        df_final = protein_df.replace({np.nan: None})
        df_final2 = df_final.iloc[:, :-1]
        df_final2.columns
        return df_final2
    else:
        print(response.raise_for_status())

chunks = np.array_split(merops_subs2, 20)
len(chunks)
ids2map = chunks[0]
one = map_retrieve(chunks[0])
two
three
frames = [map_retrieve(i) for i in chunks]

merops_up_sub_tbl = pd.concat(frames)
reviewed = merops_up_sub_tbl[merops_up_sub_tbl['Reviewed'] == 'reviewed']

## add new table to database for merops substrate gene names
TABLES = {}
TABLES['meropsSubsUniprot'] = """
CREATE TABLE meropsSubsUniprot (
    uniProtID CHAR(15) NOT NULL PRIMARY KEY,
    entryName VARCHAR(45) NOT NULL,
    geneNamePreferred VARCHAR(45),
    geneNamesAlternative JSON DEFAULT NULL,
    taxid INT,
    organism VARCHAR(100)
    ) ENGINE=InnoDB
"""
for table_name in TABLES:
    table_description = TABLES[table_name]
    try:
        print("Creating table: {}".format(table_name))
        cursor.execute(table_description)
    except mysql.connector.Error as err:
        if err.errno == errorcode.ER_TABLE_EXISTS_ERROR:
            print("Table already exists")
        else:
            print(err.msg)

log_file = "uniprot_merops_subs_not_entered.log"
open(log_file, 'w').close()

for idx, row in reviewed.iterrows():
#for idx, row in row.iterrows():
    print("*****************************",  row['Entry'])
    uniProtID = row['Entry']
    entryName = row['Entry Name']

    if row['Gene Names (primary)']:
        geneNamePreferred = row['Gene Names (primary)'].split(";")[0]
    else:
        geneNamePreferred = None

    ## can be None
    if row['Gene Names (synonym)']==None:
        geneNamesAlternative=None
    else:
        geneNamesAlternative = row['Gene Names (synonym)'].split(' ')

    organismID = row['Organism (ID)']
    organism = row['Organism'].split(" (")[0]
    geneNamesAlternative_ = None if geneNamesAlternative==None else json.dumps(geneNamesAlternative)

    try:
        cursor.execute(
            "INSERT IGNORE INTO meropsSubsUniprot VALUES (%s,%s,%s,%s,%s,%s)",
            (uniProtID, entryName, geneNamePreferred, geneNamesAlternative_,
             organismID, organism))
        cnx.commit()
    except mysql.connector.Error as err:
        print("Something went wrong: {}".format(err))
        with open(log_file, 'a') as f:
            f.write(f"{row['Entry']}\n")

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

# Test filling neo4j

# mostly need this host
uri = 'neo4j://localhost:7687'
user = 'neo4j'
# you'll need a password after you start
password = '**'
db = 'protTest'

from fill_neo4j import ProteinExample
prot_db = ProteinExample(uri, user, password)
#prot_db.create_db(db)
#prot_db._drop(db)
prot_db.use_database(db)
prot_db.database

# query MySQL database to get node and edge infromation
# Need to remove comments in queries.py if testing again
from queries import query_up, query_intact, query_merops2, query_psp2, query_ppase2

#https://stackoverflow.com/questions/589284/imploding-a-list-for-use-in-a-python-mysqldb-in-clause
format_strings = ','.join(['%s'] * len(get_uniprot))
cursor.execute(query_up % format_strings, tuple(get_uniprot))
uniprot_data = cursor.fetchall()
len(uniprot_data)

# get query for fill intact neo4j
format_strings_intact = ','.join(['%s'] * len(get_intact))
cursor.execute(query_intact % format_strings_intact, tuple(get_intact))
intact_data = cursor.fetchall()
len(intact_data)

# get query for fill merops neo4j
format_strings_merops = ','.join(['%s'] * len(merops_IDs))
cursor.execute(query_merops2 % format_strings_merops, tuple(merops_IDs))
merops_data = cursor.fetchall()
len(merops_data)

# get query for fill psp neo4j
format_strings_psp = ','.join(['%s'] * len(np.unique(psp['interactorB'])))
cursor.execute(query_psp2 % format_strings_psp, tuple(np.unique(psp['interactorB'])))
psp_data = cursor.fetchall()
len(psp_data)

# get query for fill ppase neo4j
format_strings_ppase = ','.join(['%s'] * len(np.unique(ppase['interactorB'])))
cursor.execute(query_ppase2 % format_strings_ppase, tuple(np.unique(ppase['interactorB'])))
ppase_data = cursor.fetchall()
len(ppase_data)

"""
Tests
prot_db.create_proteins(uniprot_data)
prot_db.create_intact_interactions(intact_data)
prot_db.create_merops_interactions(merops_data)
prot_db.create_psp_interactions(psp_data)
prot_db.create_depod_interactions(ppase_data)
"""


"""Ingestor.

A Class that manages all ingestors.
"""
from .csv import CSVIngestor
from .docx import DocxIngestor
from .pdf import PDFIngestor
from .text import TextIngestor

class Ingestor:
    """Ingestor.

    A class that manages all ingestors
    """

    @classmethod
    def parse(cls, infile: str):
        """Parse a file.

        pass the file to the right ingestor.

        :param infile: a fully qualified path to the infile.
        """
        ext = infile.split(".")[-1].lower()

        if ext == "csv":
            return CSVIngestor.parse(infile)
        elif ext == "docx":
            return DocxIngestor.parse(infile)
        elif ext == "txt":
            return TextIngestor.parse(infile)
        elif ext == "pdf":
            return PDFIngestor.parse(infile)
        else:
            raise ValueError(
                "Invalid file! Please, provide a txt, docx, csv or pdf file!"
            )


from os import path

from PyQt5 import QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import unsplash
import wall
import win_darkmode
import utils

class UnsplashWindow:
    def __init__(self, main_window):
        self.ui = main_window
        self.screenSize = QDesktopWidget().screenGeometry(0)
        self.image_path = None
        self.unsplash_instance = unsplash.Unsplash(
            self.screenSize.width(), self.screenSize.height()
        )
        self.ui.unsplashPhoto.setMaximumHeight(int(0.7 * self.screenSize.height()))
        self.ui.unsplashPhoto.setMaximumWidth(int(0.99 * self.screenSize.width()))
        self.ui.unsplashSearchTextEdit.setMaximumWidth(
            int(0.15 * self.screenSize.width())
        )
        self.ui.unsplashNextWallButton.clicked.connect(self.next_wallpaper)
        self.ui.unsplashWallpaperButton.clicked.connect(self.set_wallpaper)
        self.ui.unsplashSaveButton.clicked.connect(self.save_wallpaper)

    def next_wallpaper(self):
        self.enable_wall_buttons(False)
        query = self.ui.unsplashSearchTextEdit.toPlainText()
        if self.ui.unsplashFeaturedCheck.isChecked():
            is_featured = True
        else:
            is_featured = False

        self.download_thread = UnsplashDownloadThread(
            self.unsplash_instance, is_featured, query
        )
        self.download_thread.signal.connect(self.display_wallpaper)
        self.download_thread.start()

    def save_wallpaper(self):
        if self.image_path is None:
            messagebox = QMessageBox()
            messagebox.setWindowTitle("Wallpaper not found!")
            messagebox.setText("Choose a wallpaper to set")
            messagebox.setIcon(QMessageBox.Critical)
            messagebox.exec_()
        else:
            wall.saveWall(
                self.image_path,
                utils.Helpers.saved_wall_path(
                    self.image_path,
                    self.unsplash_instance.get_image_extension()
                    )
            )
            messagebox = QMessageBox()
            messagebox.setWindowTitle("Wallpaper saved!")
            messagebox.setText("Wallpaper saved in User's Pictures folder")
            messagebox.setIcon(QMessageBox.Information)
            messagebox.exec_()

    def set_wallpaper(self):
        if self.image_path is None:
            messagebox = QMessageBox()
            messagebox.setWindowTitle("Wallpaper not found!")
            messagebox.setText("Choose a wallpaper to set")
            messagebox.setIcon(QMessageBox.Critical)
            messagebox.exec_()
        else:
            self.toggle_dark_mode()
            wall.changeBG(self.image_path)
            if not utils.Helpers.insert_history(self.unsplash_instance.wallpaper_url, "unsplash"):
                QMessageBox.warning(QMessageBox(), 'Error', 'Could not add wall to the history.')

    def display_wallpaper(self, image_path):
        self.image_path = image_path
        self.ui.unsplashPhoto.setPixmap(QtGui.QPixmap(self.image_path))
        self.ui.unsplashPhoto.setScaledContents(True)
        self.enable_wall_buttons(True)

    def toggle_dark_mode(self):
        if self.ui.unsplashDarkModeCheck.isChecked():
            win_darkmode.setDarkMode()
        else:
            win_darkmode.setLightMode()

    def enable_wall_buttons(self, state):
        self.ui.unsplashNextWallButton.setEnabled(state)
        self.ui.unsplashSaveButton.setEnabled(state)
        self.ui.unsplashWallpaperButton.setEnabled(state)

class UnsplashDownloadThread(QThread):
    signal = pyqtSignal(str)

    def __init__(self, unsplash_instance,is_featured, query):
        QThread.__init__(self)
        self.unsplash_instance = unsplash_instance
        self.unsplash_instance.set_featured(is_featured)
        if query and not query.isspace():
            self.unsplash_instance.set_query(query)

    def run(self):
        self.unsplash_instance.get_unsplash_pic()
        print(self.unsplash_instance.wallpaper_url)
        self.image_path = self.unsplash_instance.get_download_path()
        utils.Helpers.download_wall(self.image_path,self.unsplash_instance.wallpaper_url)
        self.signal.emit(self.image_path)


from flask_app.config.mysqlconnection import connectToMySQL
from flask_app import DATABASE
from flask import flash
from flask_app.models import user_model

class Roads:
    def __init__(self, data):
        self.id = data['id']
        self.date = data['date']
        self.origin = data['origin']
        self.destination = data['destination']
        self.created_at = data['created_at']
        self.updated_at = data['updated_at']
        self.user_id = data['user_id']
        self.post_by = None

#?=========create a classmethod========
    @classmethod
    def roads_utv(cls,data):
        query = """
            INSERT INTO off_roads (origin,destination,user_id,date)
            VALUES (%(origin)s,%(destination)s,%(user_id)s,%(date)s);
        """
        return connectToMySQL(DATABASE).query_db(query,data)

#?===========read all==========
    @classmethod
    def get_all(cls):
        query = """
            SELECT * FROM off_roads
            JOIN users
            ON off_roads.user_id = users.id;

        """
        results = connectToMySQL(DATABASE).query_db(query)
        print (results)

        all_roads = []
        if results:
            for row in results:
                the_roads = cls(row)
                user_data = {
                    'id' : row['user_id'],
                    'created_at' : row['users.created_at'],
                    'updated_at' : row['users.updated_at'],
                    **row
                }
                this_user = user_model.User(user_data)
                the_roads.create_by = this_user
                all_roads.append(the_roads)
        return all_roads

#?=======read one========
#
    @classmethod
    def get_by_id(cls,data):
        query = """
            SELECT * FROM off_roads
            JOIN users
            ON off_roads.user_id = users.id
            WHERE off_roads.id = %(id)s;
        """
        results = connectToMySQL(DATABASE).query_db(query,data)
        print (results)
        this_roads = cls(results[0])
        for row in results:
            user_data = {
                **row,
                'id' : row['user_id'],
                'created_at' : row['users.created_at'],
                'updated_at' : row['users.updated_at']
            }
            this_user = user_model.User(user_data)
            this_roads.post_by = this_user
            return this_roads
        return False

#?=======update========
    # @classmethod
    # def update_roads(cls,data):
    #     query = """
    #         UPDATE off_roads
    #         SET origin = %(origin)s,
    #         destination = %(destination)s,
    #         date = %(date)s
    #         WHERE id = %(id)s;
    #     """
    #     return connectToMySQL(DATABASE).query_db(query,data)

#?=======delete========

    @classmethod
    def delete(cls,data):
        query = """
            DELETE FROM off_roads
            WHERE id = %(id)s;
        """
        return connectToMySQL(DATABASE).query_db(query,data)

#?=======validator=======

    @staticmethod
    def validator(data):
        is_valid =True
        print(data)
        # if len(data['name']) < 1:
        #     is_valid = False
        #     flash("Must have a Name")
        # if len(data['place']) < 1:
        #     is_valid = False
        #     flash("Must have a Place")
        if len(data['date']) < 1:
            is_valid = False
            flash("Must type a Date")
        if len(data['origin']) < 1:
            is_valid = False
            flash("Must create a Origin")
        if len(data['destination']) < 1:
            is_valid = False
            flash("Must type a Destination")

        return is_valid


from typing import Tuple, Type, TypeVar

from ssz.hashable_container import HashableContainer
from ssz.sedes import Bitvector, uint64

ATTESTATION_SUBNET_COUNT = 64

TMetaData = TypeVar("TMetaData", bound="MetaData")

default_attnets_tuple = (False,) * ATTESTATION_SUBNET_COUNT

class SeqNumber(int):
    pass

default_seq_number = SeqNumber(0)

class MetaData(HashableContainer):
    fields = [("seq_number", uint64), ("attnets", Bitvector(ATTESTATION_SUBNET_COUNT))]

    @classmethod
    def create(
        cls: Type[TMetaData],
        *,
        seq_number: SeqNumber = default_seq_number,
        attnets: Tuple[bool, ...] = default_attnets_tuple,
    ) -> TMetaData:
        return super().create(seq_number=seq_number, attnets=attnets)

    def __str__(self) -> str:
        attnets = map(lambda elem: "1" if elem else "0", self.attnets)
        return f"seq_number={self.seq_number}, attnets=0b{''.join(attnets)}"


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Apr  9 16:47:25 2021

@author: suee
"""
#plot distribution for wate usage and time for usage

# =============================================================================
# import numpy as np
# import matplotlib.pyplot as plt
# import pandas as pd
# import math
#
# # water usa
# # =============================================================================
# mu, sigma, num_bins = 8, 0.5, 50
# mu1, sigma1 , num_bins1 = 10, 0.5, 50
# mu2, sigma2 , num_bins2 = 12, 0.5, 50
# mu3, sigma3 , num_bins3 = 3, 0.5, 50
# x = mu + sigma * np.random.randn(1000)
# x1 = mu1 + sigma1 * np.random.randn(1000)
# x2 = mu2 + sigma2 * np.random.randn(1000)
# x3 = mu3 + sigma3 * np.random.randn(1000)
# #
# n, bins, patches = plt.hist(x, num_bins, normed=True, facecolor = 'blue', alpha = 0.5)
# n1, bins1, patches = plt.hist(x1, num_bins1, normed=True, facecolor = 'blue', alpha = 0.5)
# n2, bins2, patches = plt.hist(x2, num_bins2, normed=True, facecolor = 'blue', alpha = 0.5)
# n3, bins3, patches = plt.hist(x3, num_bins3, normed=True, facecolor = 'blue', alpha = 0.5)
# #
# y = norm.pdf(bins, mu, sigma)
# y1 = norm.pdf(bins1, mu1, sigma1)
# y2 = norm.pdf(bins2, mu2, sigma2)
# y3 = norm.pdf(bins3, mu3, sigma3)
# plt.xlabel('water usage L/person*day')
# plt.ylabel('frequency of every X')
# plt.title('normal distribution of water usage: $\mu = 2$, $\sigma=0.5$')
# plt.plot(bins, y, 'r--')
# plt.plot(bins1, y1, 'r--')
# plt.plot(bins2, y2, 'r--')
# plt.plot(bins3, y3, 'r--')
# =============================================================================
import pandas as pd

import numpy as np

import matplotlib.pyplot as plt
from matplotlib import cm

# 根据均值、标准差,求指定范围的正态分布概率值

def normfun(x, mu, sigma):

    pdf = np.exp(-((x - mu)**2)/(2*sigma**2)) / (sigma * np.sqrt(2*np.pi))

    return pdf

left,width=0.14,0.77
bottom,height=0.11,0.5
bottom_h=bottom+height+0.04

rect_line1=[left,bottom,width,height]

axbelow=plt.axes(rect_line1)

# result = np.random.randint(-65, 80, size=100) # 最小值,最大值,数量

result = np.random.normal(8, 0.5, 100) # 均值为0.5,方差为1
result1 = np.random.normal(8.2, 0.5, 100)
result2 = np.random.normal(8.3, 0.5, 100)
result3 = np.random.normal(8.4, 0.5, 100)

x = np.arange(min(result), max(result), 0.1)
x1 = np.arange(min(result1), max(result1), 0.1)
x2 = np.arange(min(result2), max(result2), 0.1)
x3 = np.arange(min(result3), max(result3), 0.1)
# 设定 y 轴，载入刚才的正态分布函数

y = normfun(x, result.mean(), result.std())
y1 = normfun(x1, result1.mean(), result1.std())
y2 = normfun(x2, result2.mean(), result2.std())
y3 = normfun(x3, result3.mean(), result3.std())
# axbelow.plot(x, y,label='person A at 8:00am') # 这里画出理论的正态分布概率曲线
# plt.plot(x1, y1,label='person B at 8:12am')
# plt.plot(x2, y2,label='person C at 8:18am')
# plt.plot(x3, y3,label='person D at 8:24am')

result7 = np.random.normal(18, 0.5, 100) # 均值为0.5,方差为1
result4 = np.random.normal(18.2, 0.5, 100)
result5 = np.random.normal(18.3, 0.5, 100)
result6 = np.random.normal(18.4, 0.5, 100)

x7 = np.arange(min(result7), max(result7), 0.1)
x4 = np.arange(min(result4), max(result4), 0.1)
x5 = np.arange(min(result5), max(result5), 0.1)
x6 = np.arange(min(result6), max(result6), 0.1)
# 设定 y 轴，载入刚才的正态分布函数

y7 = normfun(x7, result7.mean(), result7.std())
y4 = normfun(x4, result4.mean(), result4.std())
y5 = normfun(x5, result5.mean(), result5.std())
y6 = normfun(x6, result6.mean(), result6.std())
plt.plot(x7, y7,label='person A at 6:00pm') #
plt.plot(x4, y4,label='person B at 6:12pm')
plt.plot(x5, y5,label='person C at 6:18pm')
plt.plot(x6, y6,label='person D at 6:24pm')

# 这里画出实际的参数概率与取值关系

plt.hist(result, bins=10, rwidth=0.8, density=True) # bins个柱状图,宽度是rwidth(0~1),=1没有缝隙
plt.hist(result1, bins=10, rwidth=0.8, density=True)
plt.hist(result2, bins=10, rwidth=0.8, density=True)
plt.hist(result3, bins=10, rwidth=0.8, density=True)
plt.hist(result4, bins=10, rwidth=0.8, density=True) # bins个柱状图,宽度是rwidth(0~1),=1没有缝隙
plt.hist(result5, bins=10, rwidth=0.8, density=True)
plt.hist(result6, bins=10, rwidth=0.8, density=True)
plt.hist(result7, bins=10, rwidth=0.8, density=True)
plt.title('Probablity of water usage from one family during one day')

plt.xlabel('time in one day')

plt.ylabel('probability of using the filter')
plt.legend(loc='upper center', numpoints=1)

leg = plt.gca().get_legend()

ltext = leg.get_texts()

plt.setp(ltext, fontsize='small')

# 输出

plt.show()

# =============================================================
# ====================== Plots ================================
# =============================================================
colorIdx = np.linspace(0, 256, num = 20).astype('int')
xTick = np.arange(6, 20 + 1, step = 1)
xTickLabel = [str(item) + ':00' for item in xTick]

fig, ax = plt.subplots(dpi = 150)

ax.set_title('Probability of Water Usage\nfrom One Family during One Day', fontsize = 18, weight = 'bold')
ax.set_xlabel('Time of the Day', fontsize = 14, weight = 'normal')
ax.set_ylabel('Probability of Using Filter', fontsize = 14, weight = 'normal')
ax.set_xticks(xTick)
ax.set_xticklabels(xTickLabel, rotation = 30)

ax.plot(x, y, linestyle = '-', color = cm.turbo(colorIdx[3]))
ax.plot(x1, y1, linestyle = '-', color = cm.turbo(colorIdx[5]))
ax.plot(x2, y2, linestyle = '-', color = cm.turbo(colorIdx[7]))
ax.plot(x3, y3, linestyle = '-', color = cm.turbo(colorIdx[9]))

ax.plot(x4, y4, linestyle = '-', color = cm.turbo(colorIdx[11]))
ax.plot(x5, y5, linestyle = '-', color = cm.turbo(colorIdx[13]))
ax.plot(x6, y6, linestyle = '-', color = cm.turbo(colorIdx[15]))
ax.plot(x7, y7, linestyle = '-', color = cm.turbo(colorIdx[17]))
legend = ['person A at 8:00am', 'person B at 8:12am', 'person C at 8:18am', 'person D at 8:24am',
          'person B at 6:12pm', 'person C at 6:18pm', 'person D at 6:24pm', 'person A at 6:00pm']
ax.legend(legend, loc = 'best', frameon = False)

ax.hist(result, bins=10, rwidth=0.8, density=True)
ax.hist(result1, bins=10, rwidth=0.8, density=True)
ax.hist(result2, bins=10, rwidth=0.8, density=True)
ax.hist(result3, bins=10, rwidth=0.8, density=True)
ax.hist(result4, bins=10, rwidth=0.8, density=True)
ax.hist(result5, bins=10, rwidth=0.8, density=True)
ax.hist(result6, bins=10, rwidth=0.8, density=True)
ax.hist(result7, bins=10, rwidth=0.8, density=True)


import threading
import time
import random
import sys
import socket

from collections import OrderedDict

def TS2_server():
    try:
        ts2_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        print("[S]: Server socket created")
    except socket.error as err:
        print('socket open error: {}\n'.format(err))
        exit()

    port_from_command_line_TS = int(sys.argv[1])
    ser_bind = ('', port_from_command_line_TS)
    ts2_sock.bind(ser_bind)
    ts2_sock.listen(1)
    # ts2_ls_conn: connection with ls server over socket
    ts2_ls_conn, addr = ts2_sock.accept()
    print("[S]: Got a connection request from a client at {}".format(addr))

    host = socket.gethostname()
    print("[S]: Server host name is {}".format(host))
    localhost_ip = (socket.gethostbyname(host))
    print("[S]: Server IP address is {}".format(localhost_ip))

    raw_file = open('PROJ2-DNSTS2.txt', 'r')
    DNS_TSTable = OrderedDict()
    for line_num, data_line in enumerate(raw_file, 0):
        temp_split = data_line.split(' ')
        if not temp_split[0] in DNS_TSTable:
            DNS_TSTable[temp_split[0]] = line_num
    raw_file.close()
    return_msg = ''

    while True:
        data_from_client = ts2_ls_conn.recv(1024).decode('utf-8')
        if len(data_from_client) == 0:
            break
        if data_from_client.strip() in DNS_TSTable:
            p = DNS_TSTable.get(data_from_client.strip())
            raw = open('PROJ2-DNSTS2.txt', 'r')
            return_line = raw.readlines()[p].strip()
            return_msg = return_line
            ts2_ls_conn.send(return_msg.encode('utf-8'))
            raw.close()

thread4 = threading.Thread(name='TS2_server', target=TS2_server)
thread4.start()
time.sleep(random.random() * 5)


from dataclasses import dataclass
from typing import Any, Dict

import inflect

# See the K8s Python API's client.CustomObjectsApi() and
# create_namespaced_custom_object for examples.  The namespace field will
# be supplied at object creation time and therefore is not present in the
# CRDParser class

CRDBody = Dict[str, Any]
# This represents the body of a K8s custom object.

_p = inflect.engine()

@dataclass(frozen=True)
class CRDParser:
    group: str
    """Group is the K8s API group for the custom resource.
    e.g. 'ricoberger.de'"""

    version: str
    """Version is the API version.  e.g. 'v1alpha1'"""

    name: str
    """Name is the name of this CRD object.  e.g. 'butler-secret'"""

    plural: str
    """The plural of this object Kind.  We just defer to the 'inflect'
    package for this."""

    @classmethod
    def from_crd_body(cls, body: CRDBody) -> "CRDParser":
        """Ingest a Python Dict representation of a Custom Resource, and
        return a CRDParser with the properties filled out.  Raises KeyError
        if required fields are not present.  Required fields are currently:
        'apiVersion', 'kind', and 'metadata.name'.  The 'apiVersion' field
        must contain a slash, with the group before the slash and the version
        after it; raises IndexError if that isn't true."""
        (group, version) = body["apiVersion"].split("/")
        return cls(
            group=group,
            version=version,
            name=body["metadata"]["name"],
            plural=_p.plural(body["kind"].lower()),
        )