from amaranth import *
from amaranth import tracer
from amaranth_soc import csr
from amaranth_soc.csr import wishbone

__all__ = ["Peripheral"]

class Peripheral(Elaboratable):
    def __init__(self, name=None, src_loc_at=1):
        if name is not None and not isinstance(name, str):
            raise TypeError("Name must be a string, not {!r}".format(name))
        self._name = name or tracer.get_var_name(depth=2 + src_loc_at).lstrip("_")

        self._csrs = []
        self._irqs = []

    def csr(self, width, access, *, name=None, src_loc_at=0):
        if name is not None and not isinstance(name, str):
            raise TypeError("Name must be a string, not {!r}".format(name))
        name = name or tracer.get_var_name(depth=2 + src_loc_at).lstrip("_")
        reg = csr.Element(width, access, path=(self._name, name))
        self._csrs.append((reg, name))
        return reg

    def irq(self, *, name=None, src_loc_at=0):
        if name is not None and not isinstance(name, str):
            raise TypeError("Name must be a string, not {!r}".format(name))
        name = name or tracer.get_var_name(depth=2 + src_loc_at).lstrip("_")
        sig = Signal(name=f"{name}_trigger")
        self._irqs.append(sig)
        return sig

    def bridge(self):
        return Bridge(self._csrs, self._irqs, self._name)

class Bridge(Elaboratable):
    def __init__(self, registers, irqs, base_name):
        self._csr_mux = csr_mux = csr.Multiplexer(addr_width=1, data_width=8)

        self._int = None
        if len(irqs) > 0:
            self._int = InterruptSource(irqs, base_name)
            self.irq = Signal()
            self._csr_mux.add(self._int.status, name=f"{base_name}_irq_status", extend=True, alignment=2)
            self._csr_mux.add(self._int.mask, name=f"{base_name}_irq_mask", extend=True, alignment=2)

        for register, name in registers:
            csr_mux.add(register, name=f"{base_name}_{name}", extend=True, alignment=2)

        self._csr_wb = wishbone.WishboneCSRBridge(csr_mux.bus, data_width=32)

        self.bus = self._csr_wb.wb_bus

    def elaborate(self, platform):
        m = Module()

        m.submodules.csr_mux = self._csr_mux
        m.submodules.wb_bridge = self._csr_wb
        if self._int is not None:
            m.submodules.int = self._int
            m.d.comb += self.irq.eq(self._int.irq)

        return m

class InterruptSource(Elaboratable):
    def __init__(self, events, path):
        self.irq = Signal()

        w = len(events)
        self.status = csr.Element(w, "rw", path=(path, "irq_status"))
        self.mask = csr.Element(w, "rw", path=(path, "irq_mask"))

        self._ev = events

    def elaborate(self, platform):
        m = Module()

        irq_status = Signal(len(self._ev))
        irq_mask = Signal(len(self._ev))

        m.d.comb += self.irq.eq((irq_status & irq_mask).any())

        m.d.comb += self.mask.r_data.eq(irq_mask)
        with m.If(self.mask.w_stb):
            m.d.sync += irq_mask.eq(self.mask.w_data)

        m.d.comb += self.status.r_data.eq(irq_status)
        irq_set = Cat(self._ev)
        irq_clr = Signal(len(irq_status))
        with m.If(self.status.w_stb):
            m.d.comb += irq_clr.eq(self.status.w_data)

        m.d.sync += irq_status.eq((irq_status & ~irq_clr) | irq_set)

        return m


"""MuZero Network"""
import torch
import torch.nn as nn

from titan.config import Conf
from titan.mcts.state import State
from titan.models.nets import DynamicsNet, PredictionNet, ReprNet

class M0Net(nn.Module):
    """MuZero Network Architecture."""

    def __init__(self, cfg: Conf):
        super(M0Net, self).__init__()
        self.cfg = cfg

        downsample = False
        self.full_support_size = 2 * self.cfg.SUPPORT_SIZE + 1
        self.block_output_size_reward = (
            (
                self.cfg.REDUCED_C_REWARD
                * math.ceil(self.cfg.OBSERVATION_SHAPE[1] / 16)
                * math.ceil(self.cfg.OBSERVATION_SHAPE[2] / 16)
            )
            if downsample
            else (
                self.cfg.REDUCED_C_REWARD
                * self.cfg.OBSERVATION_SHAPE[1]
                * self.cfg.OBSERVATION_SHAPE[2]
            )
        )

        self.block_output_size_value = (
            (
                self.cfg.REDUCED_C_VALUE
                * math.ceil(self.cfg.OBSERVATION_SHAPE[1] / 16)
                * math.ceil(self.cfg.OBSERVATION_SHAPE[2] / 16)
            )
            if downsample
            else (
                self.cfg.REDUCED_C_VALUE
                * self.cfg.OBSERVATION_SHAPE[1]
                * self.cfg.OBSERVATION_SHAPE[2]
            )
        )

        self.block_output_size_policy = (
            (
                self.cfg.REDUCED_C_POLICY
                * math.ceil(self.cfg.OBSERVATION_SHAPE[1] / 16)
                * math.ceil(self.cfg.OBSERVATION_SHAPE[2] / 16)
            )
            if downsample
            else (
                self.cfg.REDUCED_C_POLICY
                * self.cfg.OBSERVATION_SHAPE[1]
                * self.cfg.OBSERVATION_SHAPE[2]
            )
        )
        # Representation function that encodes past observations.
        self.repr_network = ReprNet(
            self.cfg.OBSERVATION_SHAPE[0], self.cfg.CHANNELS, self.cfg.DEPTH
        )
        #
        self.dyn_network = DynamicsNet(
            (self.cfg.CHANNELS + self.cfg.ACTION_SHAPE[0]),
            self.cfg.CHANNELS,
            self.cfg.DEPTH,
            self.cfg.REDUCED_C_REWARD,
            self.cfg.RESNET_FC_REWARD_LAYERS,
            self.full_support_size,
            self.block_output_size_reward,
        )
        #
        self.prediction_network = PredictionNet(
            self.cfg.CHANNELS,
            self.cfg.DEPTH,
            len(self.cfg.ACTION_SPACE),
            self.cfg.REDUCED_C_VALUE,
            self.cfg.REDUCED_C_POLICY,
            self.cfg.RESNET_FC_VALUE_LAYERS,
            self.cfg.RESNET_FC_POLICY_LAYERS,
            self.full_support_size,
            self.block_output_size_value,
            self.block_output_size_policy,
        )

    def representation(self, obs):
        """."""
        s = self.repr_network(obs)

        # Scale encoded state between [0, 1] (See appendix paper Training)
        min_s = (
            s.view(-1, s.shape[1], s.shape[2] * s.shape[3])
            .min(2, keepdim=True)[0]
            .unsqueeze(-1)
        )
        max_s = (
            s.view(-1, s.shape[1], s.shape[2] * s.shape[3])
            .max(2, keepdim=True)[0]
            .unsqueeze(-1)
        )

        scale_s = max_s - min_s
        scale_s[scale_s < 1e-5] += 1e-5
        s_norm = (s - min_s) / scale_s
        return s_norm

    def prediction(self, hidden_state: torch.Tensor):
        """Prediction function computes the policy and value function."""
        policy, value = self.prediction_network(hidden_state)
        return policy, value

    def dynamics(self, hidden_state, action):
        """."""
        if len(action.shape) == 3:
            action = action.unsqueeze(0)
        if len(hidden_state.shape) == 3:
            hidden_state = hidden_state.unsqueeze(0)

        # Stack encoded_state with a game specific one hot encoded action.
        # (See paper appendix Network Architecture)
        x = torch.cat((hidden_state, action), 1)

        s, reward = self.dyn_network(x)

        # Scale encoded state between [0, 1] (See appendix paper Training)
        min_s = (
            s.view(-1, s.shape[1], s.shape[2] * s.shape[3])
            .min(2, keepdim=True)[0]
            .unsqueeze(-1)
        )
        max_s = (
            s.view(-1, s.shape[1], s.shape[2] * s.shape[3])
            .max(2, keepdim=True)[0]
            .unsqueeze(-1)
        )
        scale_s = max_s - min_s
        scale_s[scale_s < 1e-5] += 1e-5
        next_s_norm = (s - min_s) / scale_s

        return next_s_norm, reward

    def initial_inference(self, obs):
        s = self.representation(obs)
        policy_logits, value = self.prediction(s)

        # reward equal to 0 for consistency
        reward = torch.log(
            (
                torch.zeros(1, self.full_support_size)
                .scatter(1, torch.tensor([[self.full_support_size // 2]]).long(), 1.0)
                .repeat(len(obs), 1)
                .to(obs.device)
            )
        )
        return (
            value,
            reward,
            policy_logits,
            s,
        )

    def recurrent_inference(self, hidden_state, action):
        """."""
        next_s, reward = self.dynamics(hidden_state, action)
        policy_logits, value = self.prediction(next_s)

        return value, reward, policy_logits, next_s

def transform_to_scalar(config, x) -> float:
    """Transform a categorical representation to a scalar."""
    probs = torch.softmax(x, dim=1)
    support = (
        torch.tensor([x for x in range(-config.SUPPORT_SIZE, config.SUPPORT_SIZE + 1)])
        .expand(probs.shape)
        .float()
        .to(device=probs.device)
    )
    x = torch.sum(support * probs, dim=1, keepdim=True)

    # Invert the scaling (defined in https://arxiv.org/abs/1805.11593)
    x = torch.sign(x) * (
        (
            (
                torch.sqrt(1 + 4 * config.EPSILON * (torch.abs(x) + 1 + config.EPSILON))
                - 1
            )
            / (2 * config.EPSILON)
        )
        ** 2
        - 1
    )
    return x

def transform_from_scalar(config, x: int):
    sx = math.sign(x) * (math.sqrt(math.abs(x) + 1) - 1 + config.EPSILON * x)

def build_model(config: Conf) -> M0Net:
    """Returns model."""
    model = M0Net(config)
    # Load pretrained model from path.
    if config.MODEL_PATH:
        model.load_state_dict(torch.load(config.MODEL_PATH))
    return model


import copy
from typing import List, Tuple

import settings

class PlotData:
    """
    Хранение данных графиков (math)
    """

    def __init__(self):
        self.current_plot_index: int = 0  # текущий график
        self.row_count: int = settings.DEFAULT_ROW_COUNT  # D(X) - кол-во строк
        self.plot_count: int = settings.DEFAULT_PLOT_COUNT  # кол-во графиков
        self.data: List[List[List[float, float]]] = [settings.DEFAULT_DATA]  # список точек

    @property
    def avg_data(self) -> Tuple[List[float], List[float]]:
        """Данные для среднего графика"""

        all_x = set()

        for i in range(self.plot_count):
            all_x = all_x.union(set(self.x_data(i)))

        all_x = sorted(all_x)
        all_y = []

        for x in all_x:
            sum_y = 0
            count_y = 0
            for plot in self.data:
                for temp_x, temp_y in plot:
                    if temp_x == x:
                        sum_y += temp_y
                        count_y += 1
            all_y.append(sum_y / count_y)
        return all_x, all_y

    def fill_rows(self, new_count: int) -> None:
        """Дополняет(обрезает) каждый график до нового кол-ва строк"""

        dist = new_count - self.row_count
        for ind_plot, _ in enumerate(self.data):
            for _ in range(abs(dist)):
                if dist > 0:
                    self.data[ind_plot].append(copy.copy(settings.DEFAULT_VECTOR))
                else:
                    self.data[ind_plot].pop()

    def fill_plot(self, new_count: int) -> None:
        """Дополняет кол-во графиков"""

        dist = new_count - self.plot_count
        for _ in range(abs(dist)):
            if dist > 0:
                self.data.append([copy.copy(settings.DEFAULT_VECTOR) for _ in range(self.row_count)])
            else:
                self.data.pop()

    @property
    def current_plot(self) -> List[List[float]]:
        return self.data[self.current_plot_index]

    @current_plot.setter
    def current_plot(self, value):
        self.data[self.current_plot_index] = list(value)

    def x_data(self, ind) -> List[float]:
        return [vector[0] for vector in self.data[ind]]

    def y_data(self, ind) -> List[float]:
        return [vector[1] for vector in self.data[ind]]


import math
# Practice for methods described in Python: Beyond the Basics - Pluralsight

# --- Classes ---

# Example of a complex number class
class ComplexNumber:
    def __init__(self, r=0, i=0):
        self.real = r
        self.imag = i

    def __str__(self):
        # Note the use of a conditional expression
        # Note the distinction between a cond. expression and a cond. statement
        opp = '+' if self.imag >= 0 else ''
        return "{0}{1}{2}i".format(self.real,opp,self.imag)

    def __add__(self, rhs):
        return ComplexNumber(self.real + rhs.real, self.imag + rhs.imag)

    def __sub__(self, rhs):
        return ComplexNumber(self.real - rhs.real, self.imag - rhs.imag)

    def __mul__(self, rhs):
        return ComplexNumber(self.real * rhs.real - self.imag * rhs.imag, self.real * rhs.imag + self.imag * rhs.real)

    def __abs__(self):
        return ComplexNumber(math.sqrt(self.real**2 + self.imag**2),0)

c1 = ComplexNumber(2,-3)
c2 = ComplexNumber(3, 4)
print(c1)
print(c1 + c2)
print(c1 * c2)
print(abs(c1))

# --- Callable instances ---

# Defines what is callable and what is not
print(callable(print))
print(callable(1))

# --- *args and **kwargs ---

# HYPERVOLUME: Computes the hypervolume of a hyperbox with at least one dimension
# INPUT:    n>0 int lengths where n is the number of inputted lengths
# OUTPUT:   The volume of the hyperbox with given dimensions

def hypervolume(length, *lengths):
    v = length
    for item in lengths:
        v *= item
    return v

# We can pass as many lengths as we like, as long as there is at least occurences
print(hypervolume(1))
print(hypervolume(1,2))
print(hypervolume(1,2,3))
# Using the * operator in the call, we can unpack a list as arguments
print(hypervolume(*list(range(1,10))))

# --- Zip ---
n = 5

a = list(range(n))
b = list(range(n,2*n))
c = list(range(2*n,3*n))

list_of_lists = [a,b,c]

# Print each row as is
for i in list_of_lists:
    print(i)

# Print the transpose of the list of lists
for item in zip(*list_of_lists):
    print(list(item))


from json import load
from pathlib import Path

from nonebot import get_driver
from nonebot.log import logger

from nonebot_plugin_setu_now.config import Config
from nonebot_plugin_setu_now.models import SetuMessage

plugin_config = Config.parse_obj(get_driver().config.dict())
if plugin_config.setu_send_custom_message_path:
    MSG_PATH = Path(str(plugin_config.setu_send_custom_message_path)).absolute()
else:
    MSG_PATH = None

DEFAULT_MSG = {
    "send": [
        "哦呀~这个大叔居然要色图哦？好变态哦~",
        "嚯嚯嚯，臭大叔又来色图了哦，好恶心",
        "有什么好色图有给发出来让大伙看看！",
        "咱没有色图（骗你的~）",
        "哈？你的脑子一天都在想些什么呢，咱才没有这种东西啦♡~",
        "Hen....Hentai！。",
        "哈？？？就这？？大叔根本都忍不住呢~",
        "变态baka死宅？",
        "已经可以了，现在很多死宅也都没你这么恶心了",
        "噫…你这个死变态想干嘛！居然想叫咱做这种事，死宅真恶心！快离我远点，我怕你污染到周围空气了（嫌弃脸）",
        "这么喜欢看色图哦？变态？",
        "eee，死肥宅不要啦！恶心心！",
        "又忍不住来看色图了吗？果然根~~~~本没有忍耐力呢♡~你这白痴臭大叔~",
        "啊啦？有来看这种东西哦~我看啊，你根本就不行嘛~♡",
        "哎呀，废材大叔又在要色图哦~！别人都自己画的~~你不会画不来吧~~",
        "看这些东西，会变成笨蛋的哦~诶，不过大叔本来就是大笨蛋吧~",
    ],
    "cd": [
        "注意身体，色图看太多对身体不好 (╯‵□′)╯︵┻━┻ 你还需要 {cd_msg} 才能再次发送哦",
        "憋再冲了！{cd_msg}",
        "呃...好像冲了好多次...感觉不太好呢...{cd_msg}后再冲吧",
        "你这么喜欢色图，{cd_msg}后再给你看哦",
        "被我玩弄了吧♡~",
        "不给你看色图 {cd_msg} 不会真的生气的，对吧？✧(≖ ◡ ≖✿)",
        "不是把，不给你看就要哭出来吗？快哭一个出来给我看看~",
        "再看的话，就会变成淫~~~~~虫的哦~这样下去可是找不到女朋友的哦。",
        "你还真是可怜恶心哦~就 {cd_msg} 没看这种东西就忍不住了吗？",
    ],
}

def load_setu_message():
    if MSG_PATH:
        logger.info(f"加载自定义色图消息 路径: {MSG_PATH}")
        with MSG_PATH.open("r") as f:
            msg = load(f)
        return SetuMessage(**msg)
    else:
        return SetuMessage(**DEFAULT_MSG)

SETU_MSG: SetuMessage = load_setu_message()


from django.urls import path, include
from rest_framework import routers
from core.views.feedbacks_view import *
from core.views.products_view import *
from core.views.order_view import *

router = routers.SimpleRouter()
router.register('products', ProductViewSet, basename='products')
router.register('categories', CategoryViewSet, basename='categories')
router.register('orders', OrderViewSet, basename='orders')
router.register('deliverer-tasks', DelivererAndOrderViewSet, basename='set-order-deliverer')

urlpatterns = [
    path('category-products/<int:pk>/', CategoryProductsApi.as_view()),

    path('shopfeedbacks/', ShopFeedbackViewSet.as_view({'get': 'list'})),
    path('shopfeedbacks/create/', ShopFeedbackViewSet.as_view({'post': 'create'})),

    path('productfeedbacks/<int:pk>/', ProductFeedbackViewSet.as_view({'get': 'retrieve'})),
    path('productfeedbacks/create/', ProductFeedbackViewSet.as_view({'post': 'create'})),

    path("", include(router.urls)),
]

urlpatterns += router.urls


from database.database import SQLALCHEMY_DATABASE_URL, engine, SessionLocal
from database.schemas import Parent_Base, Child_Base
import database.models as models
from random_data_generator import RDG

import os
import sqlite3 as s
from sqlalchemy.orm import Session
from typing import List, Generator

class TestInstance:
    """
    docstring for TestInstance
    """

    def __init__(self,
                 URL: str = None,
                 SETUP: bool = False,
                 RESET: bool = False):
        self.url = URL
        self.fname = "sql_app.db"
        SETUP and self.setup_database()
        RESET and self.reset_database()
        # assume drop means just empty out tables

    @staticmethod
    def get_db() -> Generator:
        try:
            db = SessionLocal()
            yield db
        finally:
            db.close()

    def reset_database(self):
        conn = self.make_connection()
        with conn:
            cur = conn.cursor()
            tables = list(cur.execute(
                "SELECT name FROM sqlite_master WHERE type = 'table'"
            ))
            for table in tables:
                cur.execute("DELETE FROM %s;" %table)

    def setup_database(self):
        try:
            os.remove(self.fname)
            models.Base.metadata.create_all(bind=engine)
            conn = self.make_connection()
            with conn:
                cur = conn.cursor()
                resp = cur.execute("SELECT name FROM sqlite_master" +
                                   " WHERE type ='table'" +
                                   " AND name NOT LIKE 'sqlite_%';").fetchall()
                print(resp)
        except Exception as e:
            print(e)
        finally:
            print('done creating')

    def make_connection(self):
        try:
            conn = s.connect(self.fname)
            return conn
        except Exception as e:
            print(e)

    def insert_all_one_by_one(
        self,
        db: Session = None,
        parents: List[Parent_Base] = None,
        childrens: List[Child_Base] = None
    ):
        """
        ONE to MANY
        assuming we are inserting parents WITHOUT childrens
        p1, c1, c2
        """
        for parent in parents:
            db_parent = models.Parent(**parent)
            db.add(db_parent)
            db.commit()
            db.refresh(db_parent)
            print(db_parent)
            # return the p_id here will help
            # else hard code it for this example...
        for child in childrens:
            db_child = models.Child(**child)
            db.add(db_child)
            db.commit()
            db.refresh(db_child)
            print(db_child)
        try:
            p1 = db.query(models.Parent).first()
            print(p1.children)
        except Exception as e:
            print(e)
        return

    def insert_all_by_once(
        self,
        db: Session = None,
        parents: List[Parent_Base] = None,
    ):
        """
        ONE to MANY
        assuming we are inserting parents WITH childrens
        p1 will have c1 and c2
        if (p2 will also have c1 and c2) this is not one to many relation
        """
        for parent in parents:
            db_parent = models.Parent(
                name=parent['name'],
                children=[models.Child(**c) for c in parent['children']]
            )
            db.add(db_parent)
            db.commit()
            db.refresh(db_parent)
            print(db_parent)
        try:
            parent_list = db.query(models.Parent).all()
            for parent in parent_list:
                print(parent.children)
            ass = db.query(models.association_table).all()
            print(ass)
        except Exception as e:
            print(e)
        return

    def insert_additional_child(self, child: Child_Base):
        """
        expected behavior
        insert additional child with both parents
        """
        pass

    def delete_parent(self):
        """
        expected behavior
        delete one parent all child also be deleted
        """
        pass

    def delete_child(self):
        """
        expected behavior
        delete one child all parent remains
        """
        pass

def obj_creator():
    r = RDG(["name"])
    p1 = r()
    p2 = r()
    c1 = r()
    c2 = r()
    c3 = r()

    p1['children'] = [c1, c2]
    p2['children'] = [c1, c2]
    c3['parent'] = [p1, p2]
    # c1['p_id'] = 1
    # c2['p_id'] = 1
    return p1, p2, c1, c2, c3

p1, p2, c1, c2, c3 = obj_creator()
t = TestInstance(URL=SQLALCHEMY_DATABASE_URL, SETUP=True)
t.insert_all_by_once(db=SessionLocal(), parents=[p1, p2])


class Solution(object):
    # 方法1:
    def copyRandomList(self, head):
        """
        :type head: RandomListNode
        :rtype: RandomListNode
        """
        if head is None:
            return None

        # 1. copy nodes
        self.copy_nodes(head)
        # 2. copy random
        self.copy_random(head)

        return self.split_list(head)

    # 邊掃描 1->2->3->4 邊拷貝節點建立成 1->1'->2->2'->3->3'->4->4'
    def copy_nodes(self, head):
        while head is not None:
            # 拷貝節點
            node = RandomListNode(head.label)
            node.next = head.next
            node.random = head.random # 這時候 node 的 random 並不是我要的結果

            # 把拷貝的節點接上原本的 list
            head.next = node
            # 再把 head 移動到原本 list 中的下一個節點
            head = head.next.next

    def copy_random(self, head):
        while head != None:
            if head.next.random != None: # head.next 就是指向新拷貝的節點
                head.next.random = head.random.next
            head = head.next.next

    def split_list(self, head):
        new_head = head.next
        while head != None:
            curr = head.next
            head.next = curr.next # 把原先 list 中的下一個接回來
            head = head.next # 移動到下一個原先 list 中的節點

            if curr.next != None: # curr 有可能是在原先加上拷貝過後的 list 中的最後一個
                curr.next = curr.next.next
        return new_head

class Solution(object):
    # 方法2: 用 hash map
    def copyRandomList(self, head):
        self.dummy = RandomListNode(0)
        self.curr = self.dummy
        self.hash_map = {}

        while head != None:
            if head in self.hash_map:
                new_node = self.hash_map[head] # 因為第 65 行也可能把節點的關係放到 hash_map 中，所以可能 hash_map 中已經存在了
            else:
                new_node = RandomListNode(head.label)
                self.hash_map[head] = new_node
            self.curr.next = new_node

            if head.random is not None:
                if head.random in self.hash_map:
                    new_node.random = self.hash_map[head.random]
                else:
                    new_node.random = RandomListNode(head.random.label)
                    self.hash_map[head.random] = new_node.random

            # curr 和 head 個往下移動一格
            self.curr = new_node
            head = head.next

        return self.dummy.next

class Solution(object):
    # 方法3:
    def copyRandomList(self, head):
        # write your code here
        if head == None:
            return None

        myMap = {}
        nHead = RandomListNode(head.label) # 新節點的頭
        myMap[head] = nHead
        p = head
        q = nHead
        while p != None:
            q.random = p.random # 先把原先節點的 random 暫時分配給新節點，等一下再修改
            if p.next != None:
                q.next = RandomListNode(p.next.label)
                myMap[p.next] = q.next
            else:
                q.next = None
            p = p.next
            q = q.next

        p = nHead # 這時後 p 是指向新的 linked list 的元素
        while p!= None:
            if p.random != None:
                p.random = myMap[p.random] # 把新節點的 random 修改成正確的
            p = p.next
        return nHead

# lintcode 105
class Solution:
    # @param head: A RandomListNode
    # @return: A RandomListNode
    def copyRandomList(self, head):
        # write your code here
        if head is None:
            return head
        # 先複製節點，插入到原本的節點後面
        curr = head
        while curr:
            node = RandomListNode(curr.label)
            temp = curr.next
            curr.next = node
            node.next = temp
            curr = curr.next.next

        # 複製 random 指標指的東西
        curr = head
        while curr:
            new_node = curr.next
            if curr.random is not None:
                new_node.random = curr.random.next
            curr = curr.next.next

        new_head = head.next
        curr = head.next
        while curr.next:
            curr.next = curr.next.next
            curr = curr.next

        return new_head

    def copyRandomList(self, head):
        # 用 hash map 來記錄新舊節點
        hash_map = {}
        curr = head
        while curr:
            node = RandomListNode(curr.label)
            node.next = curr.next
            node.random = curr.random
            hash_map[curr] = node # key 是舊的節點，val 是新的節點
            curr = curr.next

        curr = head
        while curr:
            new_node = hash_map[curr]
            if curr.next is not None:
                new_node.next = hash_map[curr.next]
            if curr.random is not None:
                new_node.random = hash_map[curr.random]
            curr = curr.next

        return hash_map[head]


#!/usr/bin/python3
import math
import rclpy
import atexit
from rclpy.node import Node
from nav_msgs.msg import Odometry
from os.path import expanduser

class WaypointLogger(Node):
    def __init__(self):
        super().__init__("waypoint_logger")
        self.get_logger().info("Created waypoint_logger node")

        self.declare_parameter("wp_file_path", expanduser("~") + "/pp_waypoints.csv")
        self.declare_parameter("odom_topic", "/ego_racecar/odom")
        self.declare_parameter("save_waypoint_threshold", 0.1)
        self.odom_topic = (
            self.get_parameter("odom_topic").get_parameter_value().string_value
        )
        self.wp_file_path = (
            self.get_parameter("wp_file_path").get_parameter_value().string_value
        )
        self.save_waypoint_threshold = (
            self.get_parameter("save_waypoint_threshold")
            .get_parameter_value()
            .double_value
        )

        self.create_subscription(Odometry, self.odom_topic, self.save_waypoint, 100)

        self.wp_file = open(self.wp_file_path, "w")
        self.prev_waypoint = {"x": 0, "y": 0}

    def save_waypoint(self, data):
        dist = 0.0
        dx = data.pose.pose.position.x - self.prev_waypoint["x"]
        dy = data.pose.pose.position.y - self.prev_waypoint["y"]
        dist = math.pow(dx, 2) + math.pow(dy, 2)
        if dist > self.save_waypoint_threshold:
            self.wp_file.write(
                f"{data.pose.pose.position.x}, {data.pose.pose.position.y}\n"
            )
            self.prev_waypoint["x"] = data.pose.pose.position.x
            self.prev_waypoint["y"] = data.pose.pose.position.y

    def shutdown(self):
        self.wp_file.close()
        self.get_logger().info("Goodbye")

def main(args=None):
    rclpy.init(args=args)
    wl = WaypointLogger()
    atexit.register(
        wl.shutdown
    )  # run the shutdown method of our class before the program ends
    wl.get_logger().info("Saving waypoints...")
    rclpy.spin(wl)

if __name__ == "__main__":
    main()


#!/usr/bin/env python

import os
import rpyc.utils.authenticators
import socket
import sys

sys.path.append(os.path.normpath(os.path.join(sys.path[0], '..', 'lib')))

import pytis.remote  # noqa: E402

def report(message):
    sys.stderr.write(message + '\n')

def main():
    session_id = pytis.remote.x2go_session_id()
    if not session_id:
        report("X2GO_SESSION environment variable not set.")
        return
    info_file = pytis.remote.pytis_x2go_info_file(session_id)
    if not os.path.exists(info_file):
        report("P2Go info file not present: %s" % (info_file,))
        return
    if not os.access(info_file, os.R_OK):
        report("P2Go info file not readable: %s" % (info_file,))
        return
    try:
        access_data = pytis.remote.parse_x2go_info_file(info_file)
    except pytis.remote.X2GoInfoException as e:
        report("Exception when parsing P2Go info file: %s" % (e.args,))
        return
    connector = pytis.remote.Connector(access_data['password'])
    try:
        connection = connector.connect('localhost', access_data['port'])
    except rpyc.utils.authenticators.AuthenticationError:
        report("Authentication failed")
        return
    except socket.error as e:
        report("Connection error -- tunnel not available? %s" % (e,))
        return
    except EOFError as e:
        report("Connection error -- RPyC server not connected or invalid password? %s" % (e,))
        return
    message = "hello client"
    echoed_message = connection.root.echo(message)
    if echoed_message != message:
        report("Invalid echo result: %s" % (echoed_message,))
        return
    report("Connection OK!")

if __name__ == '__main__':
    main()


from flask import render_template, redirect, flash, url_for, current_app
from flask_login import login_required, current_user

from app.models.base import db
from app.models.gift import Gift
from app.spider.yushu_book import YuShuBook
from app.view_models.drift import MyDrift
from . import web

@web.route("/my/gifts")
@login_required
def my_gifts():
    uid = current_user.id
    # 用于找出当前用户的所有礼物
    gift_of_mine = Gift.get_uer_gifts(uid)
    # 从礼物中获取isbn号
    isbn_list = [gift.isbn for gift in gift_of_mine]
    # 获取到愿望清单对象数组
    wish_count_list = Gift.get_wishs_count(isbn_list)
    # 转换成视图模型
    my_gifts = MyDrift(gift_of_mine, wish_count_list)
    return render_template('my_gifts.html', gifts=my_gifts.drifts)

@web.route("/gifts/book/<isbn>")
@login_required
def save_to_gifts(isbn):
    yushu = YuShuBook()
    yushu.search_by_isbn(isbn)

    if current_user.can_save_to_list(isbn):
        with db.auto_commit():
            gift = Gift()
            gift.isbn = isbn
            gift.uid = current_user.id
            db.session.add(gift)
            current_user.beans += current_app.config["BEANS_UPLOAD_ONE_BOOK"]
    else:
        flash("请勿重复添加已赠送或者正在索要的书籍")
    return redirect(url_for('web.detail', isbn=isbn))

@web.route("/gift/<gid>/redraw")
@login_required
def redraw_from_gifts():
    pass


"""
超市发清洗逻辑
销售，成本，库存，商品， 分类

"""
from datetime import datetime
import pandas as pd
import boto3
import tempfile
import pytz
import time
import numpy as np
_TZINFO = pytz.timezone("Asia/Shanghai")

S3_BUCKET = "ext-etl-data"
S3 = boto3.resource("s3")

CLEANED_PATH = "clean_data/source_id={source_id}/clean_date={date}/target_table={target_table}/dump={timestamp}&rowcount={rowcount}.csv.gz"

def clean_fujirongtong(source_id, date, target_table, data_frames):
    if target_table == "goodsflow":
        return clean_goodsflow(source_id, date, target_table, data_frames)
    elif target_table == "cost":
        return clean_cost(source_id, date, target_table, data_frames)
    elif target_table == "store":
        return clean_store(source_id, date, target_table, data_frames)
    elif target_table == "goods":
        return clean_goods(source_id, date, target_table, data_frames)
    elif target_table == "category":
        return clean_category(source_id, date, target_table, data_frames)
    else:
        pass

def clean_goodsflow(source_id, date, target_table, data_frames):
    """
    清洗销售流水
    :param source_id:
    :param date:
    :param target_table:
    :param data_frames:
    :return:
    """

    cmid = source_id.split("Y")[0]
    flow_frames = data_frames["sale_j"]
    pay_frames = data_frames["pay_j"]
    pay_frames = pay_frames[pay_frames["paytype"] == "h"].drop_duplicates()

    if len(flow_frames) == 0:
        goodsflow_frames = pd.DataFrame(columns=[
            'source_id', 'cmid', 'foreign_store_id', 'store_name', 'receipt_id', 'consumer_id', 'saletime', 'last_updated',
            'foreign_item_id', 'barcode', 'item_name', 'item_unit', 'saleprice', 'quantity', 'subtotal',
            'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2', 'foreign_category_lv2_name',
            'foreign_category_lv3', 'foreign_category_lv3_name', 'foreign_category_lv4', 'foreign_category_lv4_name',
            'foreign_category_lv5', 'foreign_category_lv5_name', 'pos_id'])
    else:
        goodsflow_frames = pd.merge(flow_frames, pay_frames, how="left", on=["listno", "posid", "sdate", "shopid", "stime"])
        goodsflow_frames = goodsflow_frames.merge(data_frames["goods"], how="left", on="goodsid")
        goodsflow_frames = goodsflow_frames.merge(data_frames["shop"], how="left", left_on="shopid", right_on="id", suffixes=("", ".store"))

        sgroup_frames = data_frames["sgroup"]
        lv3 = sgroup_frames[sgroup_frames["deptlevelid"] == "3"]
        lv2 = sgroup_frames[sgroup_frames["deptlevelid"] == "2"]
        lv1 = sgroup_frames[sgroup_frames["deptlevelid"] == "1"]
        sgroup_frames["id_1"] = sgroup_frames.apply(lambda row: row["id"][:1], axis=1)
        sgroup_frames["id_2"] = sgroup_frames.apply(lambda row: row["id"][:3], axis=1)
        sgroup_frames["id_3"] = sgroup_frames.apply(lambda row: row["id"][:5], axis=1)
        sgroup_frames = sgroup_frames.merge(lv3, how="left", left_on="id_3", right_on="id", suffixes=("", "_lv3"))
        sgroup_frames = sgroup_frames.merge(lv2, how="left", left_on="id_2", right_on="id", suffixes=("", "_lv2"))
        sgroup_frames = sgroup_frames.merge(lv1, how="left", left_on="id_1", right_on="id", suffixes=("", "_lv1"))
        sgroup_frames = sgroup_frames[sgroup_frames["deptlevelid"] == "4"]
        sgroup_frames = sgroup_frames[["id", "name", "id_lv3", "name_lv3", "id_lv2", "name_lv2", "id_lv1", "name_lv1"]]
        sgroup_frames = sgroup_frames.rename(columns={
            "id": "foreign_category_lv4",
            "name": "foreign_category_lv4_name",
            "id_lv3": "foreign_category_lv3",
            "name_lv3": "foreign_category_lv3_name",
            "id_lv2": "foreign_category_lv2",
            "name_lv2": "foreign_category_lv2_name",
            "id_lv1": "foreign_category_lv1",
            "name_lv1": "foreign_category_lv1_name",
        })

        goodsflow_frames["deptid1"] = goodsflow_frames.apply(lambda row: row["deptid"][:7], axis=1)
        goodsflow_frames = goodsflow_frames.merge(sgroup_frames, how="left", left_on="deptid1", right_on="foreign_category_lv4")
        goodsflow_frames = goodsflow_frames.merge(data_frames["dept"], how="left", left_on="deptid", right_on="id", suffixes=("", "_lv5"))
        goodsflow_frames = goodsflow_frames[(goodsflow_frames["id"].notna()) & (goodsflow_frames["goodsid"].notna())]

        goodsflow_frames["source_id"] = source_id
        goodsflow_frames["cmid"] = cmid
        goodsflow_frames["last_updated"] = datetime.now(_TZINFO)

        def quatity(row):

            x = row["amount"]/row["x"] if row["x"] != 0 else 0
            return x
        goodsflow_frames["quantity"] = goodsflow_frames.apply(quatity, axis=1)

        def subtotal(row):
            x = row["salevalue"] - row["discvalue"]
            return x
        goodsflow_frames["subtotal"] = goodsflow_frames.apply(subtotal, axis=1)

        def saletime(row):
            date = row["sdate"].split(" ")[0]
            hour = row["stime"][0:2]
            minute = row["stime"][2:4]
            secend = row["stime"][4:6]
            time = f"{date} {hour}:{minute}:{secend}"
            return time

        goodsflow_frames["saletime"] = goodsflow_frames.apply(saletime, axis=1)
        goodsflow_frames = goodsflow_frames.rename(columns={
            "id": "foreign_store_id",
            "name.store": "store_name",
            "listno": "receipt_id",
            "cardno": "consumer_id",
            "goodsid": "foreign_item_id",
            "usebarcodeid": "barcode",
            "name": "item_name",
            "unitname": "item_unit",
            "price": "saleprice",
            "id_lv5": "foreign_category_lv5",
            "name_lv5": "foreign_category_lv5_name",
            "posid": "pos_id"
        })

        goodsflow_frames = goodsflow_frames[[
            'source_id', 'cmid', 'foreign_store_id', 'store_name', 'receipt_id', 'consumer_id', 'saletime', 'last_updated',
            'foreign_item_id', 'barcode', 'item_name', 'item_unit', 'saleprice', 'quantity', 'subtotal',
            'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2', 'foreign_category_lv2_name',
            'foreign_category_lv3', 'foreign_category_lv3_name', 'foreign_category_lv4', 'foreign_category_lv4_name',
            'foreign_category_lv5', 'foreign_category_lv5_name', 'pos_id'
        ]]

    return upload_to_s3(goodsflow_frames, source_id, date, target_table)

def clean_cost(source_id, date, target_table, data_frames):
    """
    清洗成本
    :param source_id:
    :param date:
    :param target_table:
    :param frames:
    :return:
    """
    cmid = source_id.split("Y")[0]
    cost_frames = data_frames["salecost"]
    cost_frames = cost_frames.merge(data_frames["goods"], on="goodsid")
    if len(cost_frames) == 0:
        cost_frames = pd.DataFrame(columns=[
            "source_id", "foreign_store_id", "foreign_item_id", "date", "cost_type", "total_quantity", "total_sale",
            "total_cost", "foreign_category_lv1", "foreign_category_lv2", "foreign_category_lv3", "foreign_category_lv4",
            "foreign_category_lv5", "cmid"])
    else:
        sgroup_frames = data_frames["sgroup"]
        lv3 = sgroup_frames[sgroup_frames["deptlevelid"] == "3"]
        lv2 = sgroup_frames[sgroup_frames["deptlevelid"] == "2"]
        lv1 = sgroup_frames[sgroup_frames["deptlevelid"] == "1"]
        sgroup_frames["id_1"] = sgroup_frames.apply(lambda row: row["id"][:1], axis=1)
        sgroup_frames["id_2"] = sgroup_frames.apply(lambda row: row["id"][:3], axis=1)
        sgroup_frames["id_3"] = sgroup_frames.apply(lambda row: row["id"][:5], axis=1)

        sgroup_frames = sgroup_frames.merge(lv3, how="left", left_on="id_3", right_on="id", suffixes=("", "_lv3"))
        sgroup_frames = sgroup_frames.merge(lv2, how="left", left_on="id_2", right_on="id", suffixes=("", "_lv2"))
        sgroup_frames = sgroup_frames.merge(lv1, how="left", left_on="id_1", right_on="id", suffixes=("", "_lv1"))
        sgroup_frames = sgroup_frames[sgroup_frames["deptlevelid"] == "4"]
        sgroup_frames = sgroup_frames[["id", "id_lv3", "id_lv2", "id_lv1"]]
        sgroup_frames = sgroup_frames.rename(columns={
            "id": "foreign_category_lv4",
            "id_lv3": "foreign_category_lv3",
            "id_lv2": "foreign_category_lv2",
            "id_lv1": "foreign_category_lv1",
        })

        cost_frames["deptid1"] = cost_frames.apply(lambda row: row["deptid"][:7], axis=1)
        cost_frames = cost_frames.merge(sgroup_frames, how="left", left_on="deptid1", right_on="foreign_category_lv4")
        cost_frames = cost_frames.merge(data_frames["dept"], how="left", left_on="deptid", right_on="id", suffixes=("", "_lv5"))

        def generate_total_sale(row):
            res = row["salevalue"] - row["discvalue"]
            return res
        cost_frames["total_sale"] = cost_frames.apply(generate_total_sale, axis=1)
        cost_frames = cost_frames.groupby([
            "shopid", "goodsid", "sdate", "foreign_category_lv1", "foreign_category_lv2", "foreign_category_lv3", "foreign_category_lv4", "id"], as_index=False).\
            agg({"qty": np.sum, "costvalue": np.sum, "total_sale": np.sum})
        cost_frames["source_id"] = source_id
        cost_frames["cmid"] = cmid
        cost_frames["cost_type"] = ""
        cost_frames = cost_frames.rename(columns={
            "shopid": "foreign_store_id",
            "goodsid": "foreign_item_id",
            "sdate": "date",
            "qty": "total_quantity",
            "costvalue": "total_cost",
            "id": "foreign_category_lv5",
        })

        cost_frames = cost_frames[[
            "source_id", "foreign_store_id", "foreign_item_id", "date", "cost_type", "total_quantity", "total_sale",
            "total_cost", "foreign_category_lv1", "foreign_category_lv2", "foreign_category_lv3", "foreign_category_lv4",
            "foreign_category_lv5", "cmid"
        ]]

    return upload_to_s3(cost_frames, source_id, date, target_table)

def clean_goods(source_id, date, target_table, data_frames):
    """
    清洗商品
    :param source_id:
    :param date:
    :param target_table:
    :param frames:
    :return:
    """
    """
    origin_table_columns = {
        "goods": ['barcodeid', 'goodsid', 'name', 'unitname', 'flag', 'deptid', 'keepdays'],
        "cost": ['cost', 'goodsid', 'shopid', 'flag'],
        "goodsshop": ['price', 'goodsid', 'shopid'],
    }

    coverts = {"goods": {"barcodeid": str, "goodsid": str, "deptid": str, "goodsid": str},
               "cost": {"goodsid": str, "shopid": str},
               "goodsshop": {"goodsid": str}}
    """
    cmid = source_id.split("Y")[0]

    goods_frames = data_frames["goods"]
    goods_frames = goods_frames.merge(data_frames["cost"], on="goodsid", suffixes=("", ".b"))
    goods_frames = goods_frames[(goods_frames["shopid"] == "A00A") & (goods_frames["flag.b"] == "0")]
    goods_frames = goods_frames.merge(data_frames["goodsshop"], on="goodsid", suffixes=("", ".c"))
    goods_frames = goods_frames[goods_frames["shopid.c"] == 'A00A']

    def item_status(x):
        if x == "0":
            res = "正常"
        elif x == "8":
            res = "新品"
        elif x == "1":
            res = "暂停订货"
        elif x == "2":
            res = "暂停销售"
        elif x == "3":
            res = "清理"
        elif x == "4":
            res = "暂停经营"
        else:
            res = ""
        return res
    goods_frames['item_status'] = goods_frames.flag.apply(lambda x: item_status(x))
    goods_frames["cmid"] = cmid
    goods_frames['foreign_category_lv1'] = goods_frames.deptid.apply(lambda x: str(x)[:1])
    goods_frames['foreign_category_lv2'] = goods_frames.deptid.apply(lambda x: str(x)[:3])
    goods_frames['foreign_category_lv3'] = goods_frames.deptid.apply(lambda x: str(x)[:5])
    goods_frames['foreign_category_lv4'] = goods_frames.deptid.apply(lambda x: str(x)[:7])
    goods_frames["storage_time"] = datetime.now(_TZINFO)
    goods_frames["last_updated"] = datetime.now(_TZINFO)
    goods_frames["isvalid"] = "1"
    goods_frames["allot_method"] = ""
    goods_frames["supplier_name"] = ""
    goods_frames["supplier_code"] = ""
    goods_frames["brand_name"] = ""
    goods_frames["show_code"] = goods_frames["goodsid"]
    goods_frames = goods_frames.rename(columns={
        "barcodeid": "barcode",
        "goodsid": "foreign_item_id",
        "name": "item_name",
        "cost": "lastin_price",
        "price": "sale_price",
        "unitname": "item_unit",
        "deptid": "foreign_category_lv5",
        "keepdays": "warranty",
    })

    goods_frames = goods_frames[[
        "cmid",
        "barcode",
        "foreign_item_id",
        "item_name",
        "lastin_price",
        "sale_price",
        "item_unit",
        "item_status",
        "foreign_category_lv1",
        "foreign_category_lv2",
        "foreign_category_lv3",
        "foreign_category_lv4",
        "storage_time",
        "last_updated",
        "isvalid",
        "warranty",
        "show_code",
        "foreign_category_lv5",
        "allot_method",
        "supplier_name",
        "supplier_code",
        "brand_name",
    ]]

    return upload_to_s3(goods_frames, source_id, date, target_table)

def clean_category(source_id, date, target_table, data_frames):
    """
    分类清洗
    :param source_id:
    :param date:
    :param target_table:
    :param frames:
    :return:
    """
    cmid = source_id.split("Y")[0]
    sgroup_frames = data_frames["sgroup"]
    lv1 = sgroup_frames[sgroup_frames["id"].str.len() == 1].rename(columns=lambda x: f"lv1_{x}")
    lv2 = sgroup_frames[sgroup_frames["deptlevelid"] == "2"].rename(columns=lambda x: f"lv2_{x}")
    lv3 = sgroup_frames[sgroup_frames["deptlevelid"] == "3"].rename(columns=lambda x: f"lv3_{x}")
    lv4 = sgroup_frames[sgroup_frames["deptlevelid"] == "4"].rename(columns=lambda x: f"lv4_{x}")
    lv2["lv1_id"] = sgroup_frames.id.map(lambda x: x[:1])
    lv3["lv2_id"] = sgroup_frames.id.map(lambda x: x[:3])
    lv4["lv3_id"] = sgroup_frames.id.map(lambda x: x[:5])

    category1 = lv1.copy()
    category1 = category1[category1["lv1_deptlevelid"] == "1"]
    category1 = category1.rename(columns={
        "lv1_deptlevelid": "level",
        "lv1_id": "foreign_category_lv1",
        "lv1_name": "foreign_category_lv1_name"
    })
    category1["foreign_category_lv2"] = ""
    category1["foreign_category_lv2_name"] = ""
    category1["foreign_category_lv3"] = ""
    category1["foreign_category_lv3_name"] = ""
    category1["foreign_category_lv4"] = ""
    category1["foreign_category_lv4_name"] = ""
    category1["foreign_category_lv5"] = ""
    category1["foreign_category_lv5_name"] = ""
    category1["cmid"] = cmid
    category1["last_updated"] = datetime.now(_TZINFO)
    category1 = category1[[
        'cmid', 'level', 'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2',
        'foreign_category_lv2_name', 'foreign_category_lv3', 'foreign_category_lv3_name',
        'last_updated', 'foreign_category_lv4', 'foreign_category_lv4_name', 'foreign_category_lv5',
        'foreign_category_lv5_name'
    ]]

    category2 = pd.merge(lv2.copy(), lv1.copy(), how="left", on="lv1_id")
    category2 = category2.rename(columns={
        "lv2_deptlevelid": "level",
        "lv1_id": "foreign_category_lv1",
        "lv1_name": "foreign_category_lv1_name",
        "lv2_id": "foreign_category_lv2",
        "lv2_name": "foreign_category_lv2_name"
    })
    category2["foreign_category_lv3"] = ""
    category2["foreign_category_lv3_name"] = ""
    category2["foreign_category_lv4"] = ""
    category2["foreign_category_lv4_name"] = ""
    category2["foreign_category_lv5"] = ""
    category2["foreign_category_lv5_name"] = ""
    category2["cmid"] = cmid
    category2["last_updated"] = datetime.now(_TZINFO)
    category2 = category2[[
        'cmid', 'level', 'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2',
        'foreign_category_lv2_name', 'foreign_category_lv3', 'foreign_category_lv3_name',
        'last_updated', 'foreign_category_lv4', 'foreign_category_lv4_name', 'foreign_category_lv5',
        'foreign_category_lv5_name'
    ]]

    category3 = pd.merge(lv3.copy(), lv2.copy(), how="left", on="lv2_id").merge(lv1.copy(), how="left", on="lv1_id")
    category3 = category3.rename(columns={
        "lv3_deptlevelid": "level",
        "lv1_id": "foreign_category_lv1",
        "lv1_name": "foreign_category_lv1_name",
        "lv2_id": "foreign_category_lv2",
        "lv2_name": "foreign_category_lv2_name",
        "lv3_id": "foreign_category_lv3",
        "lv3_name": "foreign_category_lv3_name",
    })
    category3["foreign_category_lv4"] = ""
    category3["foreign_category_lv4_name"] = ""
    category3["foreign_category_lv5"] = ""
    category3["foreign_category_lv5_name"] = ""
    category3["cmid"] = cmid
    category3["last_updated"] = datetime.now(_TZINFO)
    category3 = category3[[
        'cmid', 'level', 'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2',
        'foreign_category_lv2_name', 'foreign_category_lv3', 'foreign_category_lv3_name',
        'last_updated', 'foreign_category_lv4', 'foreign_category_lv4_name', 'foreign_category_lv5',
        'foreign_category_lv5_name'
    ]]

    category4 = pd.merge(lv4.copy(), lv3.copy(), how="left", on="lv3_id").merge(lv2.copy(), how="left", on="lv2_id").\
        merge(lv1.copy(), how="left", on="lv1_id")
    category4 = category4.rename(columns={
        "lv4_deptlevelid": "level",
        "lv1_id": "foreign_category_lv1",
        "lv1_name": "foreign_category_lv1_name",
        "lv2_id": "foreign_category_lv2",
        "lv2_name": "foreign_category_lv2_name",
        "lv3_id": "foreign_category_lv3",
        "lv3_name": "foreign_category_lv3_name",
        "lv4_id": "foreign_category_lv4",
        "lv4_name": "foreign_category_lv4_name"
    })
    category4["foreign_category_lv5"] = ""
    category4["foreign_category_lv5_name"] = ""
    category4["cmid"] = cmid
    category4["last_updated"] = datetime.now(_TZINFO)
    category4 = category4[[
        'cmid', 'level', 'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2',
        'foreign_category_lv2_name', 'foreign_category_lv3', 'foreign_category_lv3_name',
        'last_updated', 'foreign_category_lv4', 'foreign_category_lv4_name', 'foreign_category_lv5',
        'foreign_category_lv5_name'
    ]]

    category5 = data_frames["dept"]
    category5["lv4_id"] = category5.id.apply(lambda x: x[:7])
    category5 = category5.merge(lv4.copy(), how="left", on="lv4_id").merge(lv3.copy(), how="left", on="lv3_id").\
        merge(lv2.copy(), how="left", on="lv2_id").merge(lv1.copy(), how="left", on="lv1_id")
    category5 = category5.rename(columns={
        "lv1_id": "foreign_category_lv1",
        "lv1_name": "foreign_category_lv1_name",
        "lv2_id": "foreign_category_lv2",
        "lv2_name": "foreign_category_lv2_name",
        "lv3_id": "foreign_category_lv3",
        "lv3_name": "foreign_category_lv3_name",
        "lv4_id": "foreign_category_lv4",
        "lv4_name": "foreign_category_lv4_name",
        "id": "foreign_category_lv5",
        "name": "foreign_category_lv5_name",
    })
    category5["cmid"] = cmid
    category5["last_updated"] = datetime.now(_TZINFO)
    category5["level"] = "5"
    category5 = category5[[
        'cmid', 'level', 'foreign_category_lv1', 'foreign_category_lv1_name', 'foreign_category_lv2',
        'foreign_category_lv2_name', 'foreign_category_lv3', 'foreign_category_lv3_name',
        'last_updated', 'foreign_category_lv4', 'foreign_category_lv4_name', 'foreign_category_lv5',
        'foreign_category_lv5_name'
    ]]

    category = pd.concat([category1, category2, category3, category4, category5])

    return upload_to_s3(category, source_id, date, target_table)

def clean_store(source_id, date, target_table, data_frames):
    """
    门店清洗
    :param source_id:
    :param date:
    :param target_table:
    :param frames:
    :return:
    """
    cmid = source_id.split("Y")[0]
    store_frames = data_frames["shop"]
    store_frames["cmid"] = cmid
    store_frames["address_code"] = ""
    store_frames["device_id"] = ""

    def generate_stor_status(x):
        if x == 11:
            res = "正常营业"
        elif x == 98:
            res = "闭店"
        else:
            res = "其它"
        return res
    store_frames["store_status"] = store_frames.shoptype.apply(generate_stor_status)
    store_frames["create_date"] = datetime.now(_TZINFO)
    store_frames["lat"] = None
    store_frames["lng"] = None
    store_frames["contacts"] = None
    store_frames["area_code"] = None
    store_frames["area_name"] = None
    store_frames["business_area"] = None
    store_frames["property_id"] = None
    store_frames["property"] = "直营店"
    store_frames["source_id"] = source_id
    store_frames["last_updated"] = datetime.now(_TZINFO)
    store_frames["show_code"] = store_frames["id"]
    store_frames = store_frames.rename(columns={
        "id": "foreign_store_id",
        "name": "store_name",
        "address": "store_address",
        "linktele": "phone_number"
    })
    store_frames = store_frames[
        ['cmid', 'foreign_store_id', 'store_name', 'store_address', 'address_code', 'device_id', 'store_status',
         'create_date', 'lat', 'lng', 'show_code', 'phone_number', 'contacts', 'area_code', 'area_name',
         'business_area', 'property_id', 'property', 'source_id', 'last_updated']]

    return upload_to_s3(store_frames, source_id, date, target_table)

def upload_to_s3(frame, source_id, date, target_table):
    filename = tempfile.NamedTemporaryFile(mode="w", encoding="utf-8")
    count = len(frame)
    frame.to_csv(filename.name, index=False, compression="gzip", float_format='%.4f')
    filename.seek(0)
    key = CLEANED_PATH.format(
        source_id=source_id,
        target_table=target_table,
        date=date,
        timestamp=now_timestamp(),
        rowcount=count,
    )
    S3.Bucket(S3_BUCKET).upload_file(filename.name, key)
    return key

def now_timestamp():
    _timestamp = datetime.fromtimestamp(time.time(), tz=_TZINFO)
    return _timestamp


import setuptools

with open("./README.rst","r") as f:
    long_description = f.read()

setuptools.setup(
  name="DataProTool",
  version="1.2.0-Beta",
  author="Zhang Jiexi",
  author_email="zhangjiexi66696@outlook.com",
  description="It is a library that support advance tools in feature engineering",
  url="https://github.com/Zhang-Jiexi/DataProTool",
  long_description=long_description,
  packages=setuptools.find_packages(),
  install_requires=["numpy >= 1.23.3","pandas >=1.5.0","scikit-learn >= 1.0.2","tqdm >=4.64.1"],
  license='MIT License',
  classifiers=[
  "Programming Language :: Python :: 3.9",
  "License :: OSI Approved :: MIT License",
  "Operating System :: Microsoft",
  "Natural Language :: English",
  "Natural Language :: Chinese (Simplified)",
  "Development Status :: 4 - Beta",
  ],
)


from util import Bot
from collections import defaultdict

example_input_file = "./input/14-example.txt"
challenge_input_file = "./input/14.txt"
bot = Bot(example_input_file, challenge_input_file)

def parse_input(filename):
    with open(filename) as f:
        polymer_template = f.readline().strip()
        _ = f.readline()
        rules = {}
        ends = [polymer_template[0], polymer_template[-1]]
        for line in f:
            pair, insertion = line.strip().split(" -> ")
            rules[pair] = [pair[0]+insertion, insertion+pair[1]]
        polymer_pairs = defaultdict(int)
        for i in range(len(polymer_template) - 1):
            pair = polymer_template[i:i+2]
            polymer_pairs[pair] += 1
    return polymer_pairs, rules, ends

def polymerise(polymer_pairs, rules):
    new_polymer_pairs = defaultdict(int)
    for pair, count in polymer_pairs.items():
        p1, p2 = rules[pair]
        new_polymer_pairs[p1] += count
        new_polymer_pairs[p2] += count
    return new_polymer_pairs

def difference_after_n_steps(filename, n):
    polymer_pairs, rules, ends = parse_input(filename)
    for _ in range(n):
        polymer_pairs = polymerise(polymer_pairs, rules)
    element_counts = defaultdict(int)
    element_counts[ends[0]] += 1
    element_counts[ends[1]] += 1
    for pair, count in polymer_pairs.items():
        element_counts[pair[0]] += count
        element_counts[pair[1]] += count
    counts = [count for count in element_counts.values()]
    return (max(counts) - min(counts)) // 2

expected_difference_1 = 1749 - 161
expected_difference_2 = 2192039569602 - 3849876073

bot.check(expected_difference_1, difference_after_n_steps, [10])
bot.check(expected_difference_2, difference_after_n_steps, [40])


# -*- coding: utf-8 -*-
from datetime import datetime
from typing import Dict

import PyPDF2
import re
import pytz
import io
import requests
import lxml.html

from . import MenuParser

class HofliParser(MenuParser):

    TIMEZONE = pytz.timezone('Europe/Zurich')
    MENSA_NAME = '*Bärenhöfli*'

    def get_menu_string(self, timestamp):
        try:
            html_body = requests.get("http://baerenhoefli.ch/").text
            root = lxml.html.fromstring(html_body)
            # find the link to the menu

            menu_link = root.xpath('//div[@id="daily-menu"]/a')[0].attrib['href']
            pdf = requests.get(menu_link)
            input_fp = io.BytesIO(pdf.content)
            pdf_reader = PyPDF2.PdfFileReader(input_fp)

            page = pdf_reader.getPage(0)
            text = page.extractText()
            text = text[19:]
            text = re.sub(r'(?=[^\s\)])([A-Z][a-z])', ' \g<1>', text)
            text = text.replace(',', '')
            menus = parse_first_page(text)

            menu = self.MENSA_NAME + '\n' + self.get_menu_for_weekday(timestamp, menus)

            return menu
        except Exception as e:
            print(e)
        return self.MENSA_NAME + ": exception occurred"

    def get_menu_for_weekday(self, timestamp: datetime, menus: Dict[str, Dict]):
        weekday = timestamp.weekday()
        menu = None
        if weekday == 0:
            menu = menus['Montag']
        elif weekday == 1:
            menu = menus['Donnerstag']
        elif weekday == 2:
            menu = menus['Dienstag']
        elif weekday == 3:
            menu = menus['Mittwoch']

        if menu is None:
            return 'No menu for today!'

        menu['daily'] = self.emojify_menu(menu['daily'])
        menu['menu'] = self.emojify_menu(menu['menu'])
        menu_string = 'Daily: {}, {} CHF\nBusinesslunch: {}, {} CHF'.format(menu['daily'], menu['daily_price'],
                                                                            menu['menu'], menu['price'])
        return menu_string

def parse_first_page(text: str):
    menu_queue = []

    menu_started = False
    next_price = False

    menus = {}

    days = {'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag'}
    for word in text.split():
        if word.endswith("CHF") and menu_started:
            menu_queue[0]['menu'].append(word[:-3])
            next_price = True
            continue

        if word in days:
            menu_queue.append({"day": word, "menu": []})
            continue

        if word.startswith("Businesslunch"):
            menu_queue[0]['daily'] = ' '.join(menu_queue[0]['menu'])
            menu_queue[0]['daily_price'] = menu_queue[0]['price']
            menu_queue[0]['menu'] = [word[len("Businesslunch"):]]
            continue

        if word.endswith("***"):
            menu_queue[0]['menu'].append(word[:-3] + ',')
            menu_started = True
            continue

        if next_price:
            menu_queue[0]['price'] = word
            next_price = False
            continue

        if word == "Businessdessert":
            menu_started = False
            menu_queue[0]['menu'] = ' '.join(menu_queue[0]['menu'])
            day = menu_queue[0]['day']
            menus[day] = menu_queue.pop(0)
            continue

        if menu_started:
            menu_queue[0]['menu'].append(word)
    return menus

if __name__ == "__main__":

    print(HofliParser().get_menu_string(datetime.now()))


#!usr/bin/python3
import socket
import sys
import binascii

def send_udp_message(message, address, port):
    message = message.replace(" ", "").replace("\n", "")
    server_address = (address, port)

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        sock.sendto(binascii.unhexlify(message), server_address)
        data, _ = sock.recvfrom(4096)
    finally:
        sock.close()

    return binascii.hexlify(data).decode("utf-8")

def createQueryMessage(userInput):
    urlArr=userInput.split(".")

    hexQuery=""
    for i in urlArr:
        curr="0"+str(len(i)) if len(str(len(i)))==1 else str(len(i))

        hexQuery=hexQuery+curr+" "
        for j in i:
            hexQuery=hexQuery+str(hex(ord(j)))[2:]+" "
    return hexQuery

def getName(url):
    headerJunkInitial="AA AA 01 00 00 01 00 00 00 00 00 00 "
    headerJunkFinal=" 00 00 01 00 01"

    message=headerJunkInitial+createQueryMessage(url)+headerJunkFinal

    response = send_udp_message(message, "8.8.8.8", 53)

    answerCount=int(response[14:16])

    ipRough=[]
    for i in range(answerCount):
        curridx=i*32
        ipAsHex=(response[(len(response)-8-curridx):(len(response)-curridx)])
        ipRough.append([int(ipAsHex[0:2],16),int(ipAsHex[2:4],16),int(ipAsHex[4:6],16),int(ipAsHex[6:8],16)])

    ip=""

    for i in ipRough:
        address=""

        for j in i:
            address=address+str(j)+"."

        ip=ip+(address[:-1])+","

    ip=ip[:-1]

    return ip

port=int(sys.argv[1])

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((socket.gethostname(), port))
    s.listen()
    connectionsocket, address = s.accept()
    with connectionsocket:
        print(f"Client connected: {address}")
        while True:
            data = connectionsocket.recv(1024)
            if not data:
                break

            data=getName(data.decode('utf-8'))

            # data=' '.join(getName(data.decode('utf-8')))
            connectionsocket.sendall(data.encode('utf-8'))

connectionsocket.close()


# Cellular Automata: Rule 90, 7 Sep 2015, https://www.reddit.com/r/dailyprogrammer/comments/3jz8tt/20150907_challenge_213_easy_cellular_automata/
def automata(input, steps):
    length = len(input)
    if length<=1:
        print("input must be longer than 1 character")
    row=input
    tempRow=""
    for c in row:
        tempRow+="x" if c=="1" else " "
    print(tempRow)
    for i in range(steps):
        newRow=""
        for x in range(length):
            if x==0:
                newRow+="x" if int(row[1]) else " "
            elif x==length-1:
                newRow+="x" if int(row[length-2]) else " "
            else:
                newRow+="x" if int(row[x-1])^int(row[x+1]) else " "
        print(newRow)
        row=""
        for c in newRow:
            row+="1" if c=="x" else "0"


"""
Django settings for students_portal project.

For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os

BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'a7ipc^72h1-wu78sn5@@tk+ea49iwn9atar!0*b3)2%%17(tge'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = True

ALLOWED_HOSTS = ['students-portal.net', 'www.students-portal.net', '127.0.0.1']

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'account',
    'forum',
    'hallway',
    'films',
    'library',
    'chat',
    'mixins',
    'ckeditor',
    'research_work',
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'students_portal.urls'

WSGI_APPLICATION = 'students_portal.wsgi.application'

# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'database/main_db.sqlite3'),
    },
    'research_db': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'database/research_db.sqlite3'),
    }
}
DATABASE_ROUTERS = [
    'students_portal.database_routers.ResearchWorkRouter',
    'students_portal.database_routers.MainDataBaseRouter',
]

# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/

LANGUAGE_CODE = 'ru-ru'

TIME_ZONE = 'Europe/Chisinau'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static/'),
)

MEDIA_URL = '/media/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

CKEDITOR_UPLOAD_PATH = "uploads/"

CKEDITOR_IMAGE_BACKEND = 'pillow'

TEMPLATE_DIRS = (
    os.path.join(BASE_DIR, 'templates/'),
)

LOGIN_URL = '/account/login/'

CKEDITOR_JQUERY_URL = '/static/scripts/jquery.min.js'

CKEDITOR_CONFIGS = {
    "default": {
        'toolbar': [
            ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-',
             'TextColor', 'BGColor', '-',
             'NumberedList', 'BulletedList', '-',
             'Smiley', 'SpecialChar', '-',
             'Undo', 'Redo', '-',
             'Maximize']
        ],
        'forcePasteAsPlainText': True,
        'allowedContent': True,
        'height': 150,
        'width': 500,
        'undoStackSize': 50,
        'toolbarLocation': 'top',
        'tabSpaces': 4,
        'smiley_columns': 7,
        'enterMode': 2,  # br
        'shiftEnterMode': 1,  # p
        'autoParagraph': False,

        # 'toolbar_Full': [
        #   ['Styles', 'Format', 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ],
        #   ['Image', 'Flash', 'Table', 'HorizontalRule'],
        #   ['TextColor', 'BGColor'],
        #   ['Smiley','sourcearea', 'SpecialChar'],
        #   [ 'Link', 'Unlink', 'Anchor' ],
        #   [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl', 'Language' ],
        #   [ 'Source', '-', 'Save', 'NewPage', 'Preview', 'Print', '-', 'Templates' ],
        #   [ 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ],
        #   [ 'Find', 'Replace', '-', 'SelectAll', '-', 'Scayt' ],
        #   [ 'Maximize', 'ShowBlocks' ]
        #],
    }
}


"""

import socket

#建立TCP套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print("tcp socket建立成功")

#建立UDP套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
print("udp socket建立成功")

"""

#UDP socket简单实例

"""
from socket import *
#创建套接字
udpsocket=socket(AF_INET,SOCK_DGRAM)

#准备接收方的地址
sendAddr=('127.0.0.1',8080)

#从键盘获取数据
while True:
    sendData = bytes(input("请输入你要发送的数据："),encoding="GBK")

#发送数据到指定的电脑上

    udpsocket.sendto(sendData,sendAddr)

#关闭套接字

udpsocket.close()

"""

from socket import *
udpsocket=socket(AF_INET,SOCK_DGRAM)
#str=bytes("我是张伟",encoding='UTF-8')  #转换编码
while True:
    str = input(":")

    udpsocket.sendto(str.encode("GBK"),('192.168.100.73',8081))    #

udpsocket.close()