"""交易机器人相关的逻辑 """
import asyncio
import json
import time
from concurrent.futures.thread import ThreadPoolExecutor
from datetime import timedelta, datetime
from functools import partial
from typing import Dict, Tuple, List

import grpc
import pandas as pd
import websockets

from api.basis import Basis
from api.exchange import SimpleExchangeAPI
from backtesting._util import _Data
from base.config import logger
from base.consts import ExecutionConfig, BinanceWebsocketUri
from base.consts import RobotRedisConfig, RobotStatus, RobotConfig
from db.cache import RedisHelper
from db.model import SymbolModel, StrategyModel
from execution import execution_pb2, execution_pb2_grpc
from util.strategy_import import get_strategy_class

class RobotException(Exception):
    pass

class TradingStrategy(object):

    def __init__(self):
        self.channel = None
        self.robot_id = None
        self.info = None
        self.kline = None
        self.basis = Tuple

    def __str__(self):
        return f"Trading Strategy of :{self.__class__}"

    def init(self):
        pass

    @property
    def balance_available(self):
        # TODO: implement me
        logger.info("调用远程的查询余额")
        raise NotImplementedError

    def update_kline(self, newest_kline: pd.DataFrame) -> bool:
        """更新策略的K线

        Args:
            newest_kline: 最新的K线

        Returns:
            True 表示更新K线成功
            False 表示更新K线失败

        """
        self.kline = self.kline.combine_first(newest_kline).iloc[-RobotConfig.KLINE_LENGTH - 1:]

        # check there is not err in kline cost performance but worth it !
        # 1. check if there is missing data
        index_reference = pd.date_range(start=self.kline.index[0], end=self.kline.index[-1], freq='min')
        gaps = index_reference[~index_reference.isin(self.kline.index)]
        assert gaps.shape[0] == 0
        # 2. check if time is current minute
        now = datetime.utcnow()
        end = self.kline.index[-1].to_pydatetime().replace(tzinfo=None)

        if gaps.shape[0] != 0:
            logger.error(f"K线中间的有空值:{gaps}")
            return False

        if (now - end).total_seconds() > 70:
            logger.warning(f"生成K线的时间超过10s,用时:{(now - end).total_seconds()}")
            return False

        return True

    def check_basis(self) -> Tuple[float, float, float, float]:
        """查看基差的接口

        Returns:
            long : float
            short : float
            best_long_qty : float
            best_short_qty : float

        """
        return self.basis

    def multiple_order(self, target_amounts: List[float], symbol_ids: List[int]) -> int:
        """

        Args:
            directions: 各自的下单方向
            target_amounts: 各自的下单的目标百分比
            symbol_ids: 各自的symbol_id

        Returns:
            交易的执行结果: int (1是成功，0是失败)

        """
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.MultipleOrder(
            execution_pb2.MultipleOrderInfo(
                target_amounts=target_amounts,
                symbol_ids=symbol_ids,
                api_key=self.info["api"]["api_key"],
                secret_key=self.info["api"]["secret_key"],
                passphrase=self.info["api"]["passphrase"]
            )
        )
        return result.code

    def order_basis(self, direction_1: str, direction_2: str, amount_1: float, amount_2: float) -> int:
        """基差下单的接口

        Args:
            direction_1:  第一个交易对的方向
            direction_2:  第二个交易对的方向
            amount_1: 第一个交易对的下单数量
            amount_2: 第二个交易对的下单数量

        Returns:
            执行结果

        """
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.OrderBasis(
            execution_pb2.OrderBasisInfo(
                symbol_id_1=self.info["symbol_id"],
                symbol_id_2=self.info["symbol2_id"],
                direction_1=direction_1,
                direction_2=direction_2,
                amount_1=amount_1,
                amount_2=amount_2,
                api_key=self.info["api"]["api_key"],
                secret_key=self.info["api"]["secret_key"], passphrase=self.info["api"]["passphrase"]
            )
        )
        return result.code

    def two_order(self, direction_1: str, direction_2: str, amount_1: float, amount_2: float) -> int:

        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.TwoOrder(
            execution_pb2.TwoOrderInfo(
                symbol_id_1=self.info["symbol_id"],
                symbol_id_2=self.info["symbol2_id"],
                direction_1=direction_1,
                direction_2=direction_2,
                amount_1=amount_1,
                amount_2=amount_2,
                api_key_1=self.info["api"]["api_key"],
                secret_key_1=self.info["api"]["secret_key"],
                passphrase_1=self.info["api"]["passphrase"],
                api_key_2=self.info["api2"]["api_key"],
                secret_key_2=self.info["api2"]["secret_key"],
                passphrase_2=self.info["api2"]["passphrase"]
            )
        )
        return result.code

    def check_two_position(self):
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.CheckBasisPosition(
            execution_pb2.CheckTwoOrderPositionInfo(
                symbol_id_1=self.info["symbol_id"], symbol_id_2=self.info["symbol2_id"],
                api_key_1=self.info["api"]["api_key"], secret_key_1=self.info["api"]["secret_key"], passphrase_1=self.info["api"]["passphrase"],
                api_key_2=self.info["api2"]["api_key"], secret_key_2=self.info["api2"]["secret_key"], passphrase_2=self.info["api2"]["passphrase"],
            )
        )
        return result.long_amount_1, result.short_amount_1, result.long_amount_2, result.short_amount_2

    def check_basis_position(self) -> (int, int, int, int):
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.CheckBasisPosition(
            execution_pb2.CheckBasisPositionInfo(symbol_id_1=self.info["symbol_id"], symbol_id_2=self.info["symbol2_id"], api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"],
                                                 passphrase=self.info["api"]["passphrase"])
        )
        return result.long_amount_1, result.short_amount_1, result.long_amount_2, result.short_amount_2

    def check_basis_position_equity(self) -> (float, float, int, int, int, int, int):
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.CheckBasisPositionEquity(
            execution_pb2.CheckBasisPositionInfo(symbol_id_1=self.info["symbol_id"], symbol_id_2=self.info["symbol2_id"], api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"],
                                                 passphrase=self.info["api"]["passphrase"])
        )
        return round(result.equity, 4), round(result.available, 4), result.cont, result.long_amount_1, result.short_amount_1, result.long_amount_2, result.short_amount_2

    def check_equity(self) -> (float, float, float):
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.CheckEquity(
            execution_pb2.CheckEquityInfo(symbol_id=self.info["symbol_id"], api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"],
                                          passphrase=self.info["api"]["passphrase"])
        )
        return round(result.equity, 4), round(result.available, 4), round(result.cont, 4)

    def check_position(self) -> (int, int):
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        result = stub.CheckPosition(execution_pb2.CheckPositionInfo(symbol_id=self.info["symbol_id"], api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"], passphrase=self.info["api"]["passphrase"]))
        return result.long_amount, result.short_amount

    def order(self, direction: int, amount: int) -> int:
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        return stub.Order(execution_pb2.OrderInfo(symbol_id=self.info["symbol_id"], api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"], passphrase=self.info["api"]["passphrase"], direction=direction,
                                                  amount=amount)).code

    def target_position(self, direction: int, target_percent: float):
        stub = execution_pb2_grpc.ExecutionStub(self.channel)
        return stub.TargetPosition(
            execution_pb2.TargetInfo(symbol_id=self.info["symbol_id"], api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"], passphrase=self.info["api"]["passphrase"], direction=direction,
                                     target_percent=target_percent)).code

class RobotManager(object):
    """生成/运行交易机器人的服务
    """

    def __init__(self):
        self.redis = RedisHelper()

    def run_robot_by_id(self, robot_id: str):
        info = self.redis.hget(RobotRedisConfig.ROBOT_REDIS_INFO_KEY, robot_id)
        param = self.redis.hget(RobotRedisConfig.ROBOT_REDIS_PARAMETER_KEY, robot_id)
        if not info:
            raise RobotException(f"没有找到对应的机器人信息,id={robot_id}")
        status = info.get("status")
        if info and status == RobotStatus.RUNNING:
            robot = Robot(
                robot_id=robot_id,
                info=info,
                param=param,
            )
            robot.run()
        elif status == RobotStatus.STOPPED:
            raise RobotException(f"机器人没有开启,id={robot_id}")
        else:
            raise RobotException(f"没有找到对应的机器人或者机器人信息不全,id={robot_id}")

class Robot(object):
    def __init__(self, robot_id: str, info: Dict, param: Dict):
        self.redis = RedisHelper()
        self.robot_id = robot_id
        self.info = info
        self.strategy_class = self.generate_strategy()
        self.symbol: SymbolModel = SymbolModel.get_by_id(id=self.info.get("symbol_id"))
        self.symbol2: SymbolModel = SymbolModel.get_by_id(id=self.info.get("symbol2_id"))
        if not self.symbol2:
            self.symbol2 = self.symbol
        self.api = SimpleExchangeAPI(api_key=self.info["api"]["api_key"], secret_key=self.info["api"]["secret_key"], passphrase=self.info["api"]["passphrase"], exchange=self.symbol.exchange, symbol=self.symbol)
        if self.info.get("api2"):
            self.api2 = SimpleExchangeAPI(api_key=self.info["api2"]["api_key"], secret_key=self.info["api2"]["secret_key"], passphrase=self.info["api2"]["passphrase"], exchange=self.symbol2.exchange, symbol=self.symbol2)
        else:
            self.api2 = None

    @staticmethod
    def kline_to_df(kline: list) -> pd.DataFrame:
        assert len(kline) > 0
        # 最后一根K线是没有完成的，只有当下一根K线开始的时候才算是上一根K线结束了

        # TODO: figure out why it doesn't work
        # df = pd.DataFrame(kline[:-1]).loc[:, 0:5]
        df = pd.DataFrame(kline[:-1])
        # okex接口给的数据是str类型
        df.columns = ["candle_begin_time", "Open", "High", "Low", "Close", "Volume"]
        df["candle_begin_time"] = pd.to_datetime(df["candle_begin_time"])
        df.set_index('candle_begin_time', inplace=True)
        df = df.apply(pd.to_numeric)
        if not df.index.is_monotonic_increasing:
            df.sort_index(inplace=True)
        return df

    async def get_binance_recent_kline(self) -> pd.DataFrame:
        start_time = datetime.utcnow() - timedelta(minutes=RobotConfig.KLINE_LENGTH)
        kline = await self.api.get_kline(start_date=datetime.strftime(start_time, "%Y-%m-%d %H:%M:%S"), timeframe="1m")
        return self.kline_to_df(kline)

    def get_recent_kline(self) -> pd.DataFrame:
        start_time = datetime.utcnow() - timedelta(minutes=RobotConfig.KLINE_LENGTH)
        kline = asyncio.run(self.api.get_kline(start_date=datetime.strftime(start_time, "%Y-%m-%d %H:%M:%S"), timeframe="1m"))
        return self.kline_to_df(kline)

    def get_newest_kline(self) -> pd.DataFrame:
        start_time = datetime.utcnow() - timedelta(minutes=5)
        kline = asyncio.run(self.api.get_kline(start_date=datetime.strftime(start_time, "%Y-%m-%d %H:%M:%S"), timeframe="1m"))
        return self.kline_to_df(kline)

    async def get_all_depth(self):
        """获取两个交易对的深度数据
        """
        tasks = [self.api.get_depth(), self.api2.get_depth()]
        symbol_1_depth, symbol_2_depth = await asyncio.gather(*tasks)
        return symbol_1_depth, symbol_2_depth

    def get_newest_basis(self) -> (int, int, int, int):
        """计算基差
        """
        symbol_1_depth, symbol_2_depth = asyncio.run(self.get_all_depth())
        return Basis.depth_to_basis(symbol_1_depth, symbol_2_depth)

    def get_binance_newest_kline(self, data) -> pd.DataFrame:
        """

        Args:
            data: data from binance websocket

        """
        if not data.get("k"):
            logger.error(f"行情数据错误:{data}", exc_info=True)
            raise RobotException(f"行情数据错误:{data}")
        df = pd.DataFrame({
            "Open": data["k"]["o"],
            "Close": data["k"]["c"],
            "High": data["k"]["h"],
            "Low": data["k"]["l"],
            "Volume": data["k"]["v"]
        }, index=[pd.to_datetime(data["k"]["t"], unit='ms')])
        return df

    def generate_strategy(self):
        """通过redis中的策略名称找到对应的策略类，读入内存
        """
        try:
            strategy_name = self.info["strategy"]["file_name"]

            if strategy_name:
                strategy_class = get_strategy_class(strategy_name)
                TradingStrategy.init = strategy_class.init
                strategy_class.__init__ = TradingStrategy.__init__
                strategy_class.__str__ = TradingStrategy.__str__
                strategy_class.balance_available = TradingStrategy.balance_available
                strategy_class.two_order = TradingStrategy.two_order
                strategy_class.check_two_position = TradingStrategy.check_two_position
                strategy_class.order_basis = TradingStrategy.order_basis
                strategy_class.check_basis = TradingStrategy.check_basis
                strategy_class.check_equity = TradingStrategy.check_equity
                strategy_class.check_basis_position = TradingStrategy.check_basis_position
                strategy_class.check_basis_position_equity = TradingStrategy.check_basis_position_equity
                strategy_class.check_position = TradingStrategy.check_position
                strategy_class.get_amount = TradingStrategy.order
                strategy_class.target_position = TradingStrategy.target_position
                strategy_class.update_kline = TradingStrategy.update_kline
                strategy_class.multiple_order = TradingStrategy.multiple_order
                return strategy_class
            else:
                raise RobotException(f"机器人策略信息缺少")
        except Exception as e:
            raise RobotException(f"读取机器人策略失败:{e}")

    def get_param(self):
        try:
            return self.redis.hget(RobotRedisConfig.ROBOT_REDIS_PARAMETER_KEY, self.robot_id)
        except Exception as e:
            raise RobotException(f"读取机器人{self.robot_id}参数失败:{e}")

    def get_info(self):
        try:
            return self.redis.hget(RobotRedisConfig.ROBOT_REDIS_INFO_KEY, self.robot_id)
        except Exception as e:
            raise RobotException(f"读取机器人{self.robot_id}参数失败:{e}")

    def run_robot_basis(self):
        strategy = self.strategy_class()
        strategy.info = self.info
        while 1:
            with grpc.insecure_channel(f"{ExecutionConfig.HOST}:{ExecutionConfig.PORT}") as channel:
                try:
                    while 1:
                        # 在每一次调用next之前都获取基差
                        strategy.basis = self.get_newest_basis()
                        # 在每一次调用next之前都读取参数,然后生成策略
                        strategy.param = self.get_param()
                        strategy.robot_id = self.robot_id
                        strategy.channel = channel
                        strategy.init()
                        strategy.next()
                        # TODO: 使用 websocket 来更新
                        time.sleep(RobotConfig.BASIS_STRATEGY_INTERVAL)
                except Exception as e:
                    logger.error(f"{e}", exc_info=True)
                    time.sleep(RobotConfig.ERROR_INTERVAL)
                time.sleep(RobotConfig.BASIS_STRATEGY_INTERVAL)
            time.sleep(RobotConfig.BASIS_STRATEGY_INTERVAL)

    def run_robot(self):
        strategy = self.strategy_class()
        strategy.info = self.info
        strategy.kline = self.get_recent_kline()
        strategy.robot_id = self.robot_id
        newest_kline = self.get_newest_kline()
        strategy.update_kline(newest_kline)
        while 1:
            with grpc.insecure_channel(f"{ExecutionConfig.HOST}:{ExecutionConfig.PORT}") as channel:
                try:
                    while 1:
                        # TODO: 使用 websocket 来更新
                        newest_kline = self.get_newest_kline()
                        # 如果策略kline里面的最后一条数据和最新kline不一样，则更新Kline并运行策略
                        # TODO: replace me!
                        # if newest_kline.index[-1] != strategy.kline.index[-1] and strategy.update_kline(newest_kline):
                        if True:
                            # 替换策略的_data变量为kline,用于和回测的接口保持一致
                            strategy._data = _Data(strategy.kline)
                            # 在每一次调用next之前,先对策略init，然后再给策略设置参数
                            strategy.init()
                            # 把参数设置给策略
                            strategy.param = self.get_param()
                            # 在每一次调用next之前都获取基差
                            strategy.basis = self.get_newest_basis()
                            strategy.channel = channel
                            strategy.next()
                        time.sleep(RobotConfig.KLINE_STRATEGY_INTERVAL)
                except Exception as e:
                    logger.error(f"策略机器人运行异常{e}", exc_info=True)
                    time.sleep(RobotConfig.ERROR_INTERVAL * RobotConfig.ROBOT_EXCEPTION_WAIT_FACTOR)
            time.sleep(RobotConfig.BASIS_STRATEGY_INTERVAL * RobotConfig.ROBOT_EXCEPTION_WAIT_FACTOR)

    def run(self):
        logger.info(f"开始运行机器人,id:{self.robot_id},name:{self.strategy_class}")
        # logger.info(f"基差机器人的详细信息:{self.info}")
        strategy = StrategyModel.get_by_id(self.info.get("strategy_id"))
        if strategy.data_type == "periodic":
            self.run_hourly()
        elif self.symbol.exchange == "binance":
            self.run_websocket()
        elif self.symbol.exchange == "ccfox":
            self.run_ccfox_websocket()
        elif strategy.data_type == "index":
            self.run_websocket()
        elif strategy.data_type == "kline":
            self.run_robot()
        elif strategy.data_type == "basis":
            self.run_robot_basis()
        else:
            raise RobotException(f"策略的data_type设置错误:{strategy.data_type}")

    def run_next(self, strategy, channel, data, basis):
        """根据data运行策略的next方法,websocket模式专用

        Args:
            data: 某条kline 或者某个ticker数据

        """
        try:
            strategy.current_data = data
            strategy.basis = basis
            strategy.init()
            strategy.param = self.get_param()
            strategy.info = self.get_info()
            strategy.channel = channel
            strategy.next()
        except Exception as e:
            logger.error(f"策略执行失败 {e}", stack_info=True)

    async def run_websocket_aync(self):
        # TODO: split into two function basis and kline
        # 读取策略
        strategy = self.strategy_class()
        strategy.info = self.info
        strategy.robot_id = self.robot_id

        # 判断策略类型
        strategy_data = StrategyModel.get_by_id(self.info.get("strategy_id"))
        if strategy_data.data_type == "kline":
            if self.symbol.symbol == self.symbol2.symbol:
                strategy.is_pair = False
                stream_names = [self.symbol.symbol.lower() + "@kline_1m"]
            else:
                strategy.is_pair = True
                stream_names = [self.symbol.symbol.lower() + "@kline_1m", self.symbol2.symbol.lower() + "@kline_1m"]
            #
            # 如果是K线策略，给策略设置好初始的K线
            strategy.kline = await self.get_binance_recent_kline()
            uri = BinanceWebsocketUri.__dict__[self.symbol.market_type] + f"/stream?streams={'/'.join(stream_names)}"

        # 组合投资策略
        elif strategy_data.data_type == "index":
            stream_names = ["btcusdt" + "@kline_1m"]
            uri = BinanceWebsocketUri.usdt_future + f"/stream?streams={'/'.join(stream_names)}"
        # 基差策略
        else:
            stream_names = [self.symbol.symbol.lower() + "@depth5@100ms", self.symbol2.symbol.lower() + "@depth5@100ms"]
            uri = BinanceWebsocketUri.__dict__[self.symbol.market_type] + f"/stream?streams={'/'.join(stream_names)}"

        subscribe = {
            "method": "SUBSCRIBE",
            "params": stream_names,
            "id": 1
        }
        loop = asyncio.get_running_loop()
        future = loop.create_future()
        future.set_result("Done")

        # variable for basis
        symbol_1_depth = None
        symbol_2_depth = None
        basis = None

        # variable for pair kline
        symbol_1_info = None
        symbol_2_info = None

        while 1:
            with grpc.insecure_channel(f"{ExecutionConfig.HOST}:{ExecutionConfig.PORT}") as channel:
                try:
                    while 1:
                        try:
                            async with websockets.connect(uri) as websocket:
                                logger.info(f"订阅数据:{subscribe}")
                                await websocket.send(json.dumps(subscribe))
                                while 1:
                                    r = await asyncio.wait_for(websocket.recv(), timeout=5)
                                    # r = await websocket.recv()
                                    data = json.loads(r)
                                    # 给数据解包
                                    if data.get("stream"):
                                        data = data.get("data")

                                    # 处理基差策略
                                    if strategy_data.data_type == "basis":
                                        if data.get("s"):
                                            depth = {
                                                "asks": data.get("a"),
                                                "bids": data.get("b")
                                            }
                                            if data.get("s") == self.symbol.symbol:
                                                symbol_1_depth = depth

                                            if data.get("s") == self.symbol2.symbol:
                                                symbol_2_depth = depth

                                            if not symbol_1_depth or not symbol_2_depth:
                                                logger.warning(f"基差两边的depth没有准备好")
                                                # 基差准备好之前不启动策略
                                                continue
                                            else:
                                                basis = Basis.depth_to_basis(symbol_1_depth, symbol_2_depth)
                                        else:
                                            logger.warning(f"发现非行情的数据:{data}")
                                            continue

                                        # 如果基差准备好了,而且之前的next已经结束了，则再执行一次next
                                        if future.done():
                                            future = loop.run_in_executor(
                                                self.executor,
                                                partial(self.run_next, data=data, channel=channel, strategy=strategy, basis=basis),
                                            )

                                    elif strategy_data.data_type == "index":
                                        if data.get("k") and data["k"].get("x") and future.done():
                                            # if data.get("k") and future.done():
                                            future = loop.run_in_executor(
                                                self.executor,
                                                partial(self.run_next, data=data, channel=channel, strategy=strategy, basis=basis),
                                            )

                                    # K线策略
                                    elif strategy_data.data_type == "kline":
                                        if data.get("k"):
                                            # x means 这根K线是否完结(是否已经开始下一根K线)
                                            if data["k"].get("x") and future.done():
                                                # 如果是配对策略的话，使用基差作为diff
                                                if strategy.is_pair:
                                                    if data.get("s") == self.symbol.symbol:
                                                        symbol_1_info = (float(data.get("k").get("c")), data.get("k").get("t"))

                                                    if data.get("s") == self.symbol2.symbol:
                                                        symbol_2_info = (float(data.get("k").get("c")), data.get("k").get("t"))

                                                    if not symbol_1_info or not symbol_2_info or symbol_1_info[1] != symbol_2_info[1]:
                                                        logger.warning(f"两边的数据没有准备好")
                                                        # diff准备好之前不启动策略
                                                        continue
                                                    else:
                                                        basis = (symbol_1_info[0], symbol_2_info[0])

                                                    # 如果K线已经结束了,而且之前的next已经结束了，则再执行一次next
                                                    # remind of my debug time
                                                    self.run_next(data=data, channel=channel, strategy=strategy, basis=basis)

                                                    # to do use treading executor

                                                    # future = loop.run_in_executor(
                                                    #     self.executor,
                                                    #     partial(self.run_next, data=data, channel=channel, strategy=strategy, basis=basis),
                                                    # )

                                                # 不是配对的K线策略
                                                else:
                                                    future = loop.run_in_executor(
                                                        self.executor,
                                                        partial(self.run_next, data=data, channel=channel, strategy=strategy, basis=basis),
                                                    )

                                            elif not data["k"].get("x"):
                                                logger.info("K线还没有结束")
                                            else:
                                                logger.warning("上一次next还没有执行完")
                                        else:
                                            logger.warning(f"发现非行情的数据:{data}")
                                            continue
                                    else:
                                        logger.error(f"策略类型错误:{strategy_data.data_type}", exc_info=True)
                                        raise RobotException(f"策略类型错误:{strategy_data.data_type}")
                        except Exception as e:
                            logger.error(f"连接币安Websocket错误:{e}")
                except Exception as e:
                    logger.error(f"连接到RPC错误:{e}", stack_info=True)

    def run_websocket(self):
        """运行通过websocket获取数据的策略机器人
        """
        logger.info(f"开始在websocket模式下运行机器人,id:{self.robot_id},name:{self.strategy_class}")
        # self.executor = ProcessPoolExecutor(max_workers=1)
        self.executor = ThreadPoolExecutor(max_workers=1)
        asyncio.run(self.run_websocket_aync())

    def run_ccfox_websocket(self):
        pass

    def run_hourly(self):
        logger.info(f"运行一小时执行一次的策略机器人,id:{self.robot_id},name:{self.strategy_class}")
        while 1:
            try:
                with grpc.insecure_channel(f"{ExecutionConfig.HOST}:{ExecutionConfig.PORT}") as channel:
                    # 读取策略
                    strategy = self.strategy_class()
                    strategy.info = self.info
                    strategy.robot_id = self.robot_id
                    self.run_next(strategy=strategy, channel=channel, data=None, basis=None)
            except Exception as e:
                logger.error(f"按小时的策略执行异常{e}")
            # time.sleep(60 * 30)
            time.sleep(60 * 60)


"""계좌 잔고내역 조회 예제
"""
import pyexpertplus as ep

#  데이터 수신 이벤트
class RequestDataEvent:
    def OnStatus(self, status, trCode, msgCode, msgName):
        print("OnStatus: status={}, trCode={}, msgCode={}, msgName={}".format(status, trCode, msgCode, msgName))

    def OnReceiveData(self, trCode, value, valueList, nextFlag, selectCount, msgCode, msgName):
        #print("OnReceiveData: trCode={}, value={}, valueList={}, nextFlag={}, selectCount={}, msgCode={}, msgName={}"
        #.format(trCode, value, valueList, nextFlag, selectCount, msgCode, msgName))

        values = ep.YFValues()
        values.SetValueData(self.GetKorValueHeader(trCode), value)

        print("예수금:" + str(int(values.GetNameValue("예수금"))))
        print("출금가능금액:" + str(int(values.GetNameValue("출금가능금액"))))
        print("손익금액:" + str(int(values.GetNameValue("손익금액합계"))))

        valuelist = ep.YFValueList()
        valuelist.SetListData(self.GetKorValueListHeader(trCode), valueList, selectCount-1)

        # 헤더 출력
        header = ""
        for i in range(valuelist.ColCount()):
            header += valuelist.GetColName(i) + "\t"

        print(header)

        # 값 출력
        valuelist.RowFirst()
        for row in range(valuelist.RowCount()):
            rowVal = ""
            for col in range(valuelist.ColCount()):
                rowVal += str(valuelist.GetRowDataCell(col)) + "\t"

            print(rowVal)
            valuelist.RowNext()

def main():
    # ExpertPlus 초기화
    if ep.initialize()== False:
        return

    accountData = ep.YFRequestData(RequestDataEvent)
    accountData.ComInit()

    accountData.RequestInit()
    accNo = "00000000000"   # 계좌번호
    accPwd = "0000"         # 계좌비밀번호
    accountData.SetData("Account", accNo)
    accountData.SetData("Password", accPwd)
    accountData.RequestData("TA1001", 0)

    # 프로그램 종료 방지 루프
    ep.loop()

main()


import numpy as np
from windsaloft.jetstream import jet_streams

def test_raster_base_coordinates_ne():
    w = 30
    Y, X = np.mgrid[-w:w:91j, -w:w:180j]
    u = -1 - X**2 + Y
    v = 1 + X - Y**2

    feature_collection = jet_streams(
        u, v, pixel_dist=30, min_value=10, smooth=0, zigzag_degrees=45)
    x, y = feature_collection.features[0].geometry.coordinates[0][0]
    assert x == -178.0
    assert y == 87.830286


# -*- coding: utf-8 -*-
import numpy as np
import spacy
import pandas as pd
from nltk import Tree
import nltk
from nltk.tokenize import sent_tokenize
from nltk.util import ngrams
from nltk.tokenize import word_tokenize
from datetime import datetime
import pickle
from collections import OrderedDict
from lib.ctbcfxSQL import ctbcfxSQL

def get_ngrams(text, n):
    n_grams = ngrams(word_tokenize(text), n)
    phrase = [' '.join(grams) for grams in n_grams]
    return phrase

def sentence_tokenize(article):
    sent_tokenize_list = sent_tokenize(article)
    sent_list = [x.lower() for x in sent_tokenize_list]
    return sent_list

def entity_dict(df):
    # entity dataframe to dictionary
    e = df.dropna()
    e['word'] = e['word'].str.lower()
    edict = e.set_index('word')['entity'].to_dict()
    return edict

def merge_phrases(matcher, doc, i, matches):
    # custom named entity
    '''
    Merge a phrase. We have to be careful here because we'll change the token indices.
    To avoid problems, merge all the phrases once we're called on the last match.
    '''
    if i != len(matches)-1:
        return None
    spans = [(ent_id, label, doc[start : end]) for ent_id, label, start, end in matches]
    for ent_id, label, span in spans:
        span.merge('NNP' if label else span.root.tag_, span.text, nlp.vocab.strings[label])

def tok_format(tok):
    return "_".join([tok.orth_,tok.ent_type_]) # tok.lemma_,

def to_nltk_tree(node):
    # get nltk tree
    if node.n_lefts + node.n_rights > 0:
        return Tree(tok_format(node), [to_nltk_tree(child) for child in node.children])
    else:
        return tok_format(node)

def traverseTree(tree):
    # get dependency tree
    global dfs_list
    if type(tree) == nltk.tree.Tree:
        dfs_list.append(tree.label())
    else:
        dfs_list.append(tree)
        #print("tree:", tree)
    for subtree in tree:
        if type(subtree) == nltk.tree.Tree:
            traverseTree(subtree)
        else:
            dfs_list.append(subtree)

now = datetime.now()
# load spacy model
nlp = spacy.load('en')

# load entity & sentiment dictionary
entity_cb = pd.read_csv(r'C:\Users\z00013855\Desktop\treemodel\ctbc1026.csv',encoding = 'utf-8') #CTBC_mod5
en_dict = entity_dict(entity_cb)

negterm = ["n't",'no','not','never','none','nothing','nobody','noone','nowhere','without','hardly',
               'barely','rarely','seldom','against','minus']
#negaux = ['should','could','would','might','ought']
neg_dep_list = ['det','prt','advmmod','dobj','nsubj','dep']

DBconn = ctbcfxSQL()
# preprocess of news data
with open(r'C:\Users\z00013855\Desktop\JU_try\start.txt', "rb") as fp:   # Unpickling
    start = pickle.load(fp)

with open(r'C:\Users\z00013855\Desktop\JU_try\end.txt', "rb") as fs:   # Unpickling
    end = pickle.load(fs)

raw_data = DBconn.query(cols='*',table='zerohedge',condition_str='(time > "2013-01-14 00:00:00") and (time < "2017-06-26 00:00:00")') #time >= "start_time" and (time < end_time)
fomc_news = pd.DataFrame(raw_data)
fomc_news['content'] = fomc_news['content'].apply(lambda x: x.lower())
'''
fomc_news['jpy_word']= fomc_news['content'].apply(lambda x:1 if 'jpy' in x else 0)
fomc_news = fomc_news.query(jpy_word>0)
'''
info_list = []
info_list2 = []

count = 0
for index in range(len(start)):
    sen_dict = {}
    word_dict ={}

    start_time = pd.to_datetime(start[index])
    end_time = pd.to_datetime(end[index])

    limit_news = fomc_news[(fomc_news.time > start_time) & (fomc_news.time < end_time)]

    for each in limit_news['content']:
        temp_list = []
        subsent_list = []
        # nltk斷句
        sent_list = sent_tokenize(each)

        # 更詳細的斷句
        for sent in sent_list:
            for subsent in sent.split(','):
                if len(subsent.split(' ')) > 1: #3
                    for smaller_sent in subsent.split(':'):
                        subsent_list.append(smaller_sent)

        entity_list = list(en_dict.keys())

        for each in subsent_list:
            big_list = []
            remove_list = []
            en_sent_dict = en_dict.copy()

            # remove overlap
            for i in range(2,5):
                 temp = get_ngrams(each,i)
                 for phrase in temp:
                     if phrase in entity_list:
                         big_list.append(phrase)

            uni_gram = get_ngrams(each,1)
            for word in uni_gram:
                for phrase in big_list:
                    if word in phrase:
                        remove_list.append(word)

            for removal in remove_list:
                if removal in entity_list:
                    try:
                        en_sent_dict.pop(removal)
                    except:
                        #print('check whether',removal,'is removed.')
                        continue

            #named entity recongition
            try:
                matcher = spacy.matcher.Matcher(nlp.vocab)
                for key, value in en_sent_dict.items():
                    key_len = len(key.split(' '))
                    if key_len == 1:
                        matcher.add(entity_key=value, label=value, attrs={}, specs=[[{spacy.attrs.ORTH:key}]], on_match=merge_phrases) #merge_phrases
                    else:
                        specs_list = []
                        for k in range(key_len):
                            specs_list.append({spacy.attrs.ORTH:key.split(' ')[k]})
                        matcher.add(entity_key=value, label=value, attrs={}, specs=[specs_list], on_match=merge_phrases)

            except:
                continue

            doc = nlp(each)
            try:
                matcher(doc)
            except:
                #print(each,'is unavalible.')
                continue

            dfs_list = []
            for sent in doc.sents:
                #sent = nlp('interesting hedgeing against the chance of a "no rate hike" was "aggressive" today in fed funds futures.')

                rot = [w for w in sent if w.head is w][0] #root
                gg_list = []
                neg_type1 = False
                # get typed dependency
                for wordss in sent:
                    typed_d = ''.join([str(wordss.dep_),'(',str(wordss.head),',',str(wordss),')'])
                    Td = typed_d.split('(')[0]
                    gov = typed_d.split('(')[1].split(',')[0]
                    dep = typed_d.split(',')[1].split(')')[0]

                    # negation rules
                    if (Td == 'neg') & (gov in entity_list):
                        neg_type1 = True

                    if (Td in neg_dep_list) & (dep in negterm) & (gov in entity_list):
                        neg_type1 = True

                    if (Td == 'neg') & (gov == str(rot)) & (rot.pos_ == 'VERB'):
                        neg_type1 = True

                    if (Td in neg_dep_list) & (dep in negterm) &(gov == str(rot)) & (rot.pos_ == 'VERB'):
                        neg_type1 = True

                    gg_list.append(typed_d)

                dfs_list = []

                #to_nltk_tree(sent.root).pretty_print()

                # build dependency tree
                traverseTree(to_nltk_tree(sent.root))
                #nltk_tree_list.append(to_tp_tree(sent.root))

                # get index of entity & sentiment
                for word in dfs_list:
                    indice = [j for j,x in enumerate(dfs_list) if '##' in x] #entity-aspect signal
                    indice_sent = [j for j,x in enumerate(dfs_list) if '@#' in x] #sentiment signal

                length = len(sent) / 5 + 1
                # calculate distance between entity &sentiment
                k = 0
                m = 0
                for i in range(len(indice_sent)):
                    ta = [abs(x-indice_sent[i]) for x in indice if abs(x-indice_sent[i] <= length)]
                    try:
                        min(ta)
                    except:
                        continue
                    for z in indice:
                        if indice_sent[i] - min(ta) <= z <= indice_sent[i]+min(ta):
                            a_index = z
                            b_index = indice_sent[i]
                            word = str(dfs_list[a_index].split('_')[0])
                            EA = str(dfs_list[a_index].split('_')[1].split('##')[1])
                            sen_word = str(dfs_list[b_index].split('_')[0])
                            sen_type = str(dfs_list[b_index].split('_')[1].split('@#')[1])

                            #info_dict = OrderedDict()
                            if (m == 0):
                                m+=1
                            if neg_type1 == False:
                                if sen_word in sen_dict.keys():
                                    sen_dict['%s' %sen_word] += 1
                                    sen_dict['period'] = index
                                else:
                                    sen_dict['%s' %sen_word] = 1
                                    sen_dict['period'] = index

                                if word in word_dict.keys():
                                    word_dict['%s' %word] += 1
                                else:
                                    word_dict['%s' %word] = 1

    info_list.append(sen_dict)
    info_list2.append(word_dict)

sent = pd.DataFrame(info_list)
word = pd.DataFrame(info_list2)
#del word['period']

result = pd.concat([sent,word],axis = 1)

result['time'] = 0
for index in range(len(start)):
    result['time'][result.period == index] = end[index]

jpy = pd.read_csv(r'C:\Users\z00013855\Desktop\fx_data\jpyday_return.csv',encoding = 'utf-8')
jpy = jpy.rename(columns={'Time': 'time'})

df2 = result.merge(jpy,on = 'time',how = 'inner')
df2['move_direction'] = np.sign(df2['DailyReturn'])

df3 = df2.groupby('move_direction').mean()
df3.to_csv(r'C:\Users\z00013855\Desktop\treemodel\JU_result.csv',encoding = 'utf-8')


#Ejercicio Nº 1: Implementar el TAD Pila con sus operaciones abstractas en Representación secuencial y encadenada.

from nodo import Nodo

class Pila: #Lifo
    __first=None
    __size=0

    def __init__(self):
        self.__first=None
        self.__size=0

    def getTamaño(self):
        return print(self.__size)

    def append(self,value):
        mynode=Nodo(value)
        if self.__size==0:
            self.__first=mynode

        else:
            mynode.setNext(self.__first)
            self.__first=mynode

        self.__size+=1

    def remove(self):
        if self.__first is None:
            raise Exception("Lista vacia")
        else:
            self.__first=self.__first.getNext()
            self.__size-=1

    def watch(self):
        current=self.__first
        while current!=None:
            current.getValue()
            current=current.getNext()

if __name__=="__main__":
    pila=Pila()
    print("\n #Cargo(1,2,3,4,5)")
    pila.append(1)
    pila.append(2)
    pila.append(3)
    pila.append(4)
    pila.append(5)
    print("\n #Muestro(1,2,3,4,5)")
    pila.watch()
    print("\n #Elimino el primer elemento de Pila")
    pila.remove()
    print("\n #Muestro(1,2,3,4)")
    pila.watch()


from django.conf.urls import url, include
from django.contrib import admin
from main.views import ImageBatchView
from django.shortcuts import render

#####################################################
############### Project Url Configuration ###########
#####################################################

urlpatterns = [
    url(r'^', include('main.urls')),
    url(r'^grappelli/', include('grappelli.urls')),
    url(r'^admin/', admin.site.urls),
    url(r'^ckeditor/', include('ckeditor_uploader.urls')),
    url( r'admin/media/images/batch/$', ImageBatchView.as_view(), name="admin_image_batch_view"),
]

#####################################################
############### Custom Error Handling ###############
#####################################################

def custom_handler404(request):
    response = render(request, 'main/404.html')
    response.status_code = 404
    return response
handler404 = custom_handler404

def custom_handler500(request):
    response = render(request, 'main/500.html')
    response.status_code = 500
    return response

handler500 = custom_handler500


# John McDonough
# github - movinalot
# Advent of Code 2017

testing = 0
debug = 0
day = "04"
year = "2017"
part = "2"
answer = None

if testing:
    puzzle_data = ["abcde fghij",
                   "abcde xyz ecdab",
                   "a ab abc abd abf abj",
                   "iiii oiii ooii oooi oooo",
                   "oiii ioii iioi iiio"]
else:
    with open("puzzle_data_" + day + "_" + year + ".txt") as f:
        puzzle_data = f.readlines()

if debug:
    print(len(puzzle_data))

import collections
invalid_phrases = 0

for line in puzzle_data:

    str_values = line.strip().split(' ')

    sorted_str_values = []
    for str_value in str_values:
        sorted_str_values.append(''.join(sorted((str_value))))

    tmp = [item for item, count in collections.Counter(sorted_str_values).items() if count > 1]

    if debug:
        print(sorted_str_values, tmp, len(tmp))

    if len(tmp) > 0:
        invalid_phrases += 1

answer = len(puzzle_data) - invalid_phrases
print("AoC Day: " + day + " Year: " + year + " part " + part + ", this is the answer:", answer)


import datetime
import matplotlib.pyplot as plt
import pandas.io.sql as sqlio
from nyc_taxi_trips_load_tasks.common.aws import upload_file_to_s3
import pandas as pd
from airflow.contrib.hooks.aws_hook import AwsHook
from airflow.hooks.postgres_hook import PostgresHook
import os
import logging

def build_query_for(year, month):
    return """
        SELECT
            pickup_date,
            tip_amount_sum
        FROM
            bi_daily_tip_amount
        WHERE
            TO_CHAR(pickup_date, 'YYYY-MM') = '{}-{}'
    """.format(year, '0' + str(month) if month < 10 else month)

def build_graphic_for(execution_date, conn, credentials):
    sql_query = build_query_for(execution_date.year, execution_date.month)
    logging.info(sql_query)
    df = sqlio.read_sql_query(sql_query, conn).sort_values(by='pickup_date')

    if df.empty:
        logging.info('Query returned empty results set')
        return

    df.plot(y='tip_amount_sum', x='pickup_date')
    x_or_labels = df['pickup_date'].tolist()
    plt.xticks(x_or_labels, x_or_labels, rotation='vertical')
    img_name = "{}-{}_daily_tip_amount.png".format(execution_date.year, execution_date.month)
    plt.savefig(img_name, bbox_inches='tight')

    upload_file_to_s3(img_name, "data-sprints-eng-test/outputs/monthly/{}".format(img_name), credentials)

    os.remove(img_name)

def generate_monthly_graphics(*args, **kwargs):
    aws_hook = AwsHook("aws_credentials")
    credentials = aws_hook.get_credentials()
    redshift_hook = PostgresHook("redshift")
    conn = redshift_hook.get_conn()

    # # #
    execution_date = datetime.datetime.strptime(kwargs["ds"], '%Y-%m-%d')
    # # #

    build_graphic_for(execution_date, conn, credentials)


from linked_list_lecture import *

# '''
# Linked List hash table key/value pair
# '''

class HashTable:
    '''
    A hash table that with `capacity` buckets
    that accepts string keys
    '''
    def __init__(self, capacity):
        self.capacity = capacity  # Number of buckets in the hash table
        self.storage = [None] * capacity

    def _hash(self, key):
        '''
        Hash an arbitrary key and return an integer.

        You may replace the Python hash with DJB2 as a stretch goal.
        '''
        return hash(key)

    def _hash_djb2(self, key):
        '''
        Hash an arbitrary key using DJB2 hash

        OPTIONAL STRETCH: Research and implement DJB2
        '''
        pass

    def _hash_mod(self, key):
        '''
        Take an arbitrary key and return a valid integer index
        within the storage capacity of the hash table.
        '''
        return self._hash(key) % self.capacity

    def insert(self, key, value):
        index = self._hash_mod(key)
        node = self.storage[index]
        if node: #hash collision
            print("hash collision detected")
            while node: # iterates through all non-Null keys of the nodes within the hash table location
                if node.key == key: #if the current node's key matches the new insertion key
                    node.value = value #update the value
                    break
                elif node.next == None: #if the current node's next is None we are at the tail
                    node.next = Node(key,value) #create new Node at tail location
                    break
                else:
                    node = node.next
        else:
            ll = LinkedList()
            ll.add_to_head(key,value)
            self.storage[index] = ll.head

        '''
        Store the value with the given key.

        # Part 1: Hash collisions should be handled with an error warning. (Think about and
        # investigate the impact this will have on the tests)

        # Part 2: Change this so that hash collisions are handled with Linked List Chaining.

        Fill this in.
        '''

    def remove(self, key):
        '''
        Remove the value stored with the given key.

        Print a warning if the key is not found.

        Fill this in.
        '''
        index = self._hash_mod(key)
        ll = LinkedList()
        ll.head = self.storage[index]
        ll.remove(key)
        self.storage[index] = ll.head
        # if node is not None:
        #     previous = node
        #     head = node
        #     while node:
        #         if node.key == key: #when match between current node and input key
        #             print(node.key," matches ",key)
        #             print(previous.next,node.next)
        #             previous.next = node.next
        #             self.storage[index] = head
        #             node = None
        #             break
        #         node = node.next #iteration: current node becomes the next node in the chain
        #         previous = node #iteration: current node becomes the node before the current node,
        #             # this does not change what the current node is, it merely assigns the current node to the previous variable

        # else:
        #     print("Warning: Key does not exist")

    def retrieve(self, key):
        '''
        Retrieve the value stored with the given key.

        Returns None if the key is not found.

        Fill this in.
        '''
        index = self._hash_mod(key)
        node = self.storage[index]
        while node:
            if node.key == key:
                return node.value
            node = node.next

        return None

    def resize(self):
        '''
        Doubles the capacity of the hash table and
        rehash all key/value pairs.

        Fill this in.
        '''
        pairs = []
        for bucket in self.storage:
            if bucket != None:
                node = bucket
                while(node):
                    pairs.append((node.key,node.value))
                    if(node.next == None):
                        break
                    node = node.next
        self.capacity *= 2  # Number of buckets in the hash table
        self.storage = [None] * self.capacity
        for key,value in pairs:
            self.insert(key,value)
        return

if __name__ == "__main__":
    ht = HashTable(8)
    ht.insert("key-0", "val-0")
    ht.insert("key-1", "val-1")
    ht.insert("key-2", "val-2")
    ht.insert("key-3", "val-3")
    ht.insert("key-4", "val-4")
    ht.insert("key-5", "val-5")
    ht.insert("key-6", "val-6")
    ht.insert("key-7", "val-7")
    ht.insert("key-8", "val-8")
    ht.insert("key-9", "val-9")
    ht.resize()
    print(len(ht.storage))
    print(ht.retrieve("key-0"))
    # ht.retrieve("key-9")

    # ht = HashTable(8)
    # ht.insert("line_1", "Tiny hash table")
    # # print(ht.storage)
    # ht.insert("line_2", "Filled beyond capacity")
    # # # print(ht.storage)
    # ht.insert("line_3", "Linked list saves the day!")
    # # # print(ht.storage)
    # # # print(len(ht.storage))

    # print("")

    # # Test storing beyond capacity
    # print(ht.retrieve("line_1"))
    # print(ht.retrieve("line_2"))
    # print(ht.retrieve("line_3"))

    ## Test remove
    # ht.remove("line_1")
    # print(ht.retrieve("line_1"))

    # # Test resizing
    # old_capacity = len(ht.storage)
    # ht.resize()
    # new_capacity = len(ht.storage)

    # print(f"\nResized from {old_capacity} to {new_capacity}.\n")

    # # Test if data intact after resizing
    # print(ht.retrieve("line_1"))
    # print(ht.retrieve("line_2"))
    # print(ht.retrieve("line_3"))

    # print("")


from enigma import Misc_Options, eDVBCIInterfaces, eDVBResourceManager
from Tools.Directories import SCOPE_PLUGINS, SCOPE_SKIN, fileCheck, fileExists, fileHas, pathExists, resolveFilename
from Tools.HardwareInfo import HardwareInfo
from boxbranding import getBoxType, getMachineBuild, getBrandOEM, getMachineMtdRoot

SystemInfo = {}
SystemInfo["HasRootSubdir"] = False	# This needs to be here so it can be reset by getMultibootslots!
SystemInfo["RecoveryMode"] = False or fileCheck("/proc/stb/fp/boot_mode")	# This needs to be here so it can be reset by getMultibootslots!
from Tools.Multiboot import getMBbootdevice, getMultibootslots  # This import needs to be here to avoid a SystemInfo load loop!

def getNumVideoDecoders():
	number_of_video_decoders = 0
	while fileExists("/dev/dvb/adapter0/video%d" % (number_of_video_decoders), 'f'):
		number_of_video_decoders += 1
	return number_of_video_decoders

def countFrontpanelLEDs():
	number_of_leds = fileExists("/proc/stb/fp/led_set_pattern") and 1 or 0
	while fileExists("/proc/stb/fp/led%d_pattern" % number_of_leds):
		number_of_leds += 1
	return number_of_leds

def getHasTuners():
	if fileExists("/proc/bus/nim_sockets"):
		nimfile = open("/proc/bus/nim_sockets")
		data = nimfile.read().strip()
		nimfile.close()
		return len(data) > 0
	return False

model = getBoxType()
SystemInfo["CommonInterface"] = eDVBCIInterfaces.getInstance().getNumOfSlots()
SystemInfo["CommonInterfaceCIDelay"] = fileCheck("/proc/stb/tsmux/rmx_delay")
for cislot in range(0, SystemInfo["CommonInterface"]):
	SystemInfo["CI%dSupportsHighBitrates" % cislot] = fileCheck("/proc/stb/tsmux/ci%d_tsclk" % cislot)
	SystemInfo["CI%dRelevantPidsRoutingSupport" % cislot] = fileCheck("/proc/stb/tsmux/ci%d_relevant_pids_routing" % cislot)

SystemInfo["NumVideoDecoders"] = getNumVideoDecoders()
SystemInfo["PIPAvailable"] = SystemInfo["NumVideoDecoders"] > 1
SystemInfo["CanMeasureFrontendInputPower"] = eDVBResourceManager.getInstance().canMeasureFrontendInputPower()
SystemInfo["12V_Output"] = Misc_Options.getInstance().detected_12V_output()
SystemInfo["ZapMode"] = fileCheck("/proc/stb/video/zapmode") or fileCheck("/proc/stb/video/zapping_mode")
SystemInfo["NumFrontpanelLEDs"] = countFrontpanelLEDs()
SystemInfo["FrontpanelDisplay"] = fileExists("/dev/dbox/oled0") or fileExists("/dev/dbox/lcd0")
SystemInfo["LCDsymbol_circle_recording"] = fileCheck("/proc/stb/lcd/symbol_circle") or model in ("hd51", "vs1500") and fileCheck("/proc/stb/lcd/symbol_recording")
SystemInfo["LCDsymbol_timeshift"] = fileCheck("/proc/stb/lcd/symbol_timeshift")
SystemInfo["LCDshow_symbols"] = (model.startswith("et9") or model in ("hd51", "vs1500")) and fileCheck("/proc/stb/lcd/show_symbols")
SystemInfo["LCDsymbol_hdd"] = model in ("hd51", "vs1500") and fileCheck("/proc/stb/lcd/symbol_hdd")
SystemInfo["DeepstandbySupport"] = model != "dm800"
SystemInfo["OledDisplay"] = fileExists(resolveFilename(SCOPE_SKIN, 'display/lcd_skin/skin_lcd_default.xml'))
SystemInfo["GBWOL"] = fileExists("/usr/bin/gigablue_wol")
SystemInfo["Fan"] = fileCheck("/proc/stb/fp/fan")
SystemInfo["FanPWM"] = SystemInfo["Fan"] and fileCheck("/proc/stb/fp/fan_pwm")
SystemInfo["PowerLED"] = fileCheck("/proc/stb/power/powerled") or model in ("gbue4k", "gbquad4k") and fileCheck("/proc/stb/fp/led1_pattern")
SystemInfo["StandbyLED"] = fileCheck("/proc/stb/power/standbyled") or model in ("gbue4k", "gbquad4k") and fileCheck("/proc/stb/fp/led0_pattern")
SystemInfo["SuspendLED"] = fileCheck("/proc/stb/power/suspendled") or fileCheck("/proc/stb/fp/enable_led")
SystemInfo["Display"] = SystemInfo["FrontpanelDisplay"] or SystemInfo["StandbyLED"]
SystemInfo["LedPowerColor"] = fileCheck("/proc/stb/fp/ledpowercolor")
SystemInfo["LedStandbyColor"] = fileCheck("/proc/stb/fp/ledstandbycolor")
SystemInfo["LedSuspendColor"] = fileCheck("/proc/stb/fp/ledsuspendledcolor")
SystemInfo["Power4x7On"] = fileCheck("/proc/stb/fp/power4x7on")
SystemInfo["Power4x7Standby"] = fileCheck("/proc/stb/fp/power4x7standby")
SystemInfo["Power4x7Suspend"] = fileCheck("/proc/stb/fp/power4x7suspend")
SystemInfo["PowerOffDisplay"] = model not in ('formuler1', ) and fileCheck("/proc/stb/power/vfd") or fileCheck("/proc/stb/lcd/vfd")
SystemInfo["WakeOnLAN"] = model not in ('et8000', ) and fileCheck("/proc/stb/power/wol") or fileCheck("/proc/stb/fp/wol")
SystemInfo["HasExternalPIP"] = getMachineBuild() not in ('et9x00', 'et6x00', 'et5x00') and fileCheck("/proc/stb/vmpeg/1/external")
SystemInfo["VideoDestinationConfigurable"] = fileExists("/proc/stb/vmpeg/0/dst_left")
SystemInfo["hasPIPVisibleProc"] = fileCheck("/proc/stb/vmpeg/1/visible")
SystemInfo["hasTuners"] = getHasTuners() or fileCheck("/usr/lib/enigma2/python/Plugins/SystemPlugins/SatipClient/plugin.pyo")
SystemInfo["hasGBIpboxClient"] = fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/GBIpboxClient/plugin.pyo"))

#if model in ('gbquadplus', ):
#	SystemInfo["WakeOnLAN"] = False
#else:
SystemInfo["WakeOnLAN"] = fileCheck("/proc/stb/fp/wol")

SystemInfo["VFD_scroll_repeats"] = fileCheck("/proc/stb/lcd/scroll_repeats")
SystemInfo["VFD_scroll_delay"] = fileCheck("/proc/stb/lcd/scroll_delay")
SystemInfo["VFD_initial_scroll_delay"] = fileCheck("/proc/stb/lcd/initial_scroll_delay")
SystemInfo["VFD_final_scroll_delay"] = fileCheck("/proc/stb/lcd/final_scroll_delay")
SystemInfo["LcdLiveTV"] = fileCheck("/proc/stb/fb/sd_detach") or fileCheck("/proc/stb/lcd/live_enable")
SystemInfo["LcdLiveTVMode"] = fileCheck("/proc/stb/lcd/mode")
SystemInfo["LcdLiveDecoder"] = fileCheck("/proc/stb/lcd/live_decoder")
SystemInfo["3DMode"] = fileCheck("/proc/stb/fb/primary/3d")
SystemInfo["Blindscan_t2_available"] = fileCheck("/proc/stb/info/vumodel")
SystemInfo["Bootvideo"] = fileCheck("/usr/bin/bootvideo")
SystemInfo["hasOSDAnimation"] = fileCheck("/proc/stb/fb/animation_mode")
SystemInfo["RcTypeChangable"] = pathExists('/proc/stb/ir/rc/type')
SystemInfo["HasFullHDSkinSupport"] = model not in ('gb800solo', 'gb800se', 'gb800ue')
SystemInfo["HasBypassEdidChecking"] = fileCheck("/proc/stb/hdmi/bypass_edid_checking")
SystemInfo["HasColorspace"] = fileCheck("/proc/stb/video/hdmi_colorspace")
SystemInfo["HasColorspaceSimple"] = SystemInfo["HasColorspace"] and model in ('vusolo4k', )
SystemInfo["HasMultichannelPCM"] = fileCheck("/proc/stb/audio/multichannel_pcm")
SystemInfo["CanNotDoSimultaneousTranscodeAndPIP"] = model in ('vusolo4k') or getMachineBuild() in ('gb7252', 'gb72604')
SystemInfo["HasColordepth"] = fileCheck("/proc/stb/video/hdmi_colordepth")
SystemInfo["HasFrontDisplayPicon"] = model in ("et8500", "vusolo4k", "vuuno4kse", "vuduo4k", "vuduo4kse", "vuultimo4k", "gbquad4k", "gbue4k")
SystemInfo["Has24hz"] = fileCheck("/proc/stb/video/videomode_24hz")
SystemInfo["Has2160p"] = fileHas("/proc/stb/video/videomode_preferred", "2160p50")
SystemInfo["HasHDMIpreemphasis"] = fileCheck("/proc/stb/hdmi/preemphasis")
SystemInfo["HasColorimetry"] = fileCheck("/proc/stb/video/hdmi_colorimetry")
SystemInfo["HasHDMI-CEC"] = HardwareInfo().has_hdmi() and fileExists(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/HdmiCEC/plugin.pyo")) and (fileExists("/dev/cec0") or fileExists("/dev/hdmi_cec") or fileExists("/dev/misc/hdmi_cec0"))
SystemInfo["HasHdrType"] = fileCheck("/proc/stb/video/hdmi_hdrtype")
SystemInfo["HasYPbPr"] = getMachineBuild() in ('gb7356', 'gb7325') or model in ('gbultraue', 'gbultraueh', 'gb800ueplus', 'gb800seplus')
SystemInfo["HasScart"] = getMachineBuild() in ('gb7325', )
SystemInfo["HasSVideo"] = getMachineBuild() in ('dummy', )
SystemInfo["HasComposite"] = getMachineBuild() in ('gb7356', 'gb7358', 'gb7325') or model in ('gbultraue', 'gbultraueh')
SystemInfo["HasAutoVolume"] = fileExists("/proc/stb/audio/avl_choices") and fileCheck("/proc/stb/audio/avl")
SystemInfo["HasAutoVolumeLevel"] = fileExists("/proc/stb/audio/autovolumelevel_choices") and fileCheck("/proc/stb/audio/autovolumelevel")
SystemInfo["Has3DSurround"] = fileExists("/proc/stb/audio/3d_surround_choices") and fileCheck("/proc/stb/audio/3d_surround")
SystemInfo["Has3DSpeaker"] = fileExists("/proc/stb/audio/3d_surround_speaker_position_choices") and fileCheck("/proc/stb/audio/3d_surround_speaker_position")
SystemInfo["Has3DSurroundSpeaker"] = fileExists("/proc/stb/audio/3dsurround_choices") and fileCheck("/proc/stb/audio/3dsurround")
SystemInfo["Has3DSurroundSoftLimiter"] = fileExists("/proc/stb/audio/3dsurround_softlimiter_choices") and fileCheck("/proc/stb/audio/3dsurround_softlimiter")
SystemInfo["HasHDMI-In"] = model in ('gbquad4k', )
SystemInfo["hasXcoreVFD"] = fileCheck("/sys/module/brcmstb_%s/parameters/pt6302_cgram" % model)
SystemInfo["CanDownmixWMApro"] = fileExists("/proc/stb/audio/wmapro_choices") or fileExists("/proc/stb/audio/wmapro")
SystemInfo["CanAACTranscode"] = fileExists("/proc/stb/audio/aac_transcode_choices") or fileExists("/proc/stb/audio/aac_transcode")
SystemInfo["HDRSupport"] = fileExists("/proc/stb/hdmi/hlg_support_choices") or fileExists("/proc/stb/hdmi/hlg_support")
SystemInfo["CanDownmixAC3"] = fileHas("/proc/stb/audio/ac3_choices", "downmix")
SystemInfo["CanDownmixAC3Plus"] = fileHas("/proc/stb/audio/ac3plus_choices", "downmix")
SystemInfo["CanDownmixDTS"] = fileHas("/proc/stb/audio/dts_choices", "downmix")
SystemInfo["CanDownmixDTSHD"] = fileHas("/proc/stb/audio/dtshd_choices", "downmix")
SystemInfo["CanDownmixAAC"] = fileHas("/proc/stb/audio/aac_choices", "downmix")
SystemInfo["CanDownmixAACPlus"] = fileHas("/proc/stb/audio/aacplus_choices", "downmix")
SystemInfo["HDMIAudioSource"] = fileCheck("/proc/stb/hdmi/audio_source")
SystemInfo["MBbootdevice"] = getMBbootdevice()
SystemInfo["canMultiBoot"] = getMultibootslots()
SystemInfo["canDualBoot"] = fileExists("/dev/block/by-name/flag")
SystemInfo["canMode12"] = getMachineBuild() in ('hd51', 'vs1500', 'h7') and ('brcm_cma=440M@328M brcm_cma=192M@768M', 'brcm_cma=520M@248M brcm_cma=200M@768M')
SystemInfo["HAScmdline"] = fileCheck("/boot/cmdline.txt")
SystemInfo["HasMMC"] = fileHas("/proc/cmdline", "root=/dev/mmcblk") or SystemInfo["canMultiBoot"] and fileHas("/proc/cmdline", "root=/dev/sda")
SystemInfo["HasSDmmc"] = SystemInfo["canMultiBoot"] and "sd" in SystemInfo["canMultiBoot"][2] and "mmcblk" in getMachineMtdRoot()
SystemInfo["canRecovery"] = getMachineBuild() in ('gbmv200',) and ('usb_update.bin', 'none')
SystemInfo["FbcTunerPowerAlwaysOn"] = model in ("vusolo4k", "vuduo4k", "vuduo4kse", "vuultimo4k", "vuuno4k", "vuuno4kse")
SystemInfo["CanWMAPRO"] = fileHas("/proc/stb/audio/wmapro_choices", "downmix")
SystemInfo["CanBTAudio"] = fileHas("/proc/stb/audio/btaudio_choices", "off")
SystemInfo["CanBTAudioDelay"] = fileCheck("/proc/stb/audio/btaudio_delay") or fileCheck("/proc/stb/audio/btaudio_delay_pcm")
SystemInfo["HasPhysicalLoopthrough"] = ["Vuplus DVB-S NIM(AVL2108)", "GIGA DVB-S2 NIM (Internal)"]
SystemInfo["HasFBCtuner"] = ["Vuplus DVB-C NIM(BCM3158)", "Vuplus DVB-C NIM(BCM3148)", "Vuplus DVB-S NIM(7376 FBC)", "Vuplus DVB-S NIM(45308X FBC)", "Vuplus DVB-S NIM(45208 FBC)", "DVB-S2 NIM(45208 FBC)", "DVB-S2X NIM(45308X FBC)", "DVB-S2 NIM(45308 FBC)", "DVB-C NIM(3128 FBC)", "BCM45208", "BCM45308X", "BCM3158"]
SystemInfo["HasHiSi"] = pathExists("/proc/hisi")
SystemInfo["FCCactive"] = False


# -*- coding: utf-8 -*-
"""
Created on Fri Aug 26 23:36:30 2016

@author: Mouli
"""
#from string import maketrans
#intab = "abcdefghijklmnopqrstuvwxyz"
#outtab = "cdefghijklmnopqrstuvwxyzab"
#trantab = maketrans(intab, outtab)
#print (str.translate(trantab))

a = "g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj";
a = "http://www.pythonchallenge.com/pc/def/map.html"
b = '';
for i in range(0, len(a)):
    if (ord(a[i]) in range (97,123)):
        b = b + ( chr(((ord(a[i])-96+2) % 26)+96));
    else:
        b = b +a[i]
print (b);


from os import system;system("cls")
import excepciones_time
import control_reservas
import datetime

#para que de color a las letras
RED = '\033[31m'
WHITE = '\033[37m'

def inico_reporte():
    while True:
        system("cls")
        print("=" * 56)
        print("|    CONTROL DE REPORTES DE CANCHAS DEPORTIVAS SAS    |")
        print("=" * 56)
        print("|    1.  --  CONSULTAR  CANCHAS RESERVADAS POR DÍA    |")
        print("|    2.  --  TOTAL DINERO CAJA                        |")
        print("|    3.  --  SALIR                                    |")
        print("=" * 56);print("")

        try:
            opcion = int(input("Ingrese la opcion a ejecutar --> "))
        except:
            excepciones_time.excepciones()
            continue

        if opcion==1:
            consultar_canchas()
        elif opcion==2:
            dinero_caja()
        elif opcion==3:
            break
        else:
            excepciones_time.errores()

def  consultar_canchas():

    #validar reservas
    if len(control_reservas.total_reservas)==0:
        print("\nNO HAY CANCHAS RESERVADAS ")
        input("Presione enter --> ")

    else:
        while True:
            total_reservadas_dia=0
            try:
                system("cls")
                print("     CONSULTAR  CANCHAS RESERVADAS POR DÍA       ")
                fecha_cancha_str=input("\nIngrese la fecha   (día-mes-año)  --> ")
                fecha_cancha=datetime.datetime.strptime(fecha_cancha_str,"%d-%m-%Y")

                #total  canchas por día
                for i in control_reservas.total_reservas:
                    if  fecha_cancha.date() == i[1].date():
                        total_reservadas_dia+=1

                if total_reservadas_dia>=1:
                    excepciones_time.tiempo("Consultando las canchas ...","Resultados");system("cls")
                    print("\n     CANCHAS RESERVADAS POR DÍA      ")
                    print(f"\nFecha: {fecha_cancha.date()}\t  Total canchas reservadas: {total_reservadas_dia}\n")
                    for i in control_reservas.total_reservas:
                        if  fecha_cancha.date() == i[1].date():
                            print(f"Cliente: {i[0]} \t Cancha: {i[3]} \t Costo total: {i[5]}")
                    input("\nPresione enter -->")
                    break
                else:
                    print("\nNo hay canchas reservadas ese día")
                    input("Presione enter --> ")
                    break
            except:
                system("cls")
                print(RED,"\nINGRESASTE MAL LA FECHA, INGRESALA ASÍ DÍA-MES-AÑO ",WHITE)

def dinero_caja():

    #validar reservas
    if len(control_reservas.total_reservas)==0:
        print("NO HAY DINERO EN CAJA ")
        input("Presione enter --> ")

    else:
        total=0
        for i in control_reservas.total_reservas:

            #el dinero de la reserva es i[5]
            total+=i[5]
        excepciones_time.tiempo("Revisando  caja ...","Resultados de la caja");system("cls")
        print(f"\nTOTAL DINERO DE CAJA:  $ {total}")
        input("Presione enter")


# Plot function for compression results

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

def plot_grid_seq(df, columns, legend_columns, ax_lims = None, markers = None, add_lines = None ):

    if ax_lims != None:
        if len(ax_lims) != len(columns):
            raise IndexError("number of ax_lims is not equal to the number of columns")
        # remove data not in axis limits
        df = df[ functools.reduce(   lambda x,y: x & ( df[y] < ax_lims[y][1] ) & ( df[y] > ax_lims[y][0] ), columns, True ) ]

    # add markers
    if markers == None:
        markers = sns.mpl.lines.Line2D.filled_markers

    df_mod = df[legend_columns]
    df_mod = df_mod.drop_duplicates()

    _lightest_col = 0.4 # > 0 and < 1
    df_mod_group_compression = df_mod.sort_values(legend_columns).groupby(["Compression"])
    palette_saturation = df_mod_group_compression.apply(lambda x: pd.Series(
            _lightest_col + ( 1 - _lightest_col )*(np.arange(len(x))+1)/len(x) )).values.flatten() # saturation > 0 and < 1
    current_palette = sns.color_palette()
    palette_colors = df_mod_group_compression.ngroup().apply(lambda x: current_palette[x] ).tolist()
    sns_ncolors_percompression = 10 # larger than total count of each algorithm's compression options
    palette_order = [sns.light_palette(color = palette_colors[i],
                       n_colors=sns_ncolors_percompression)[ int(palette_saturation[i]*sns_ncolors_percompression-1) ]
                     for i in range(len(palette_saturation)) ]

    # expand markers list if not of sufficient length
    if len(markers) < len(df_mod_group_compression):
        markers += tuple(set(matplotlib.lines.Line2D.filled_markers) - set(markers))
    marker_order = df_mod_group_compression.ngroup().apply(lambda x: markers[x] ).tolist()

    # format legends
    LegendFormatFunc = lambda x: ''.join(str(i).ljust(12) for i in x)
    legend_title = "Compression Option"
    legend_title = LegendFormatFunc(legend_title.split())
    df[legend_title] = df[legend_columns].astype(str).apply(LegendFormatFunc, axis = 1)
    legend_order = df_mod_group_compression.apply(lambda x: pd.Series(
            sorted(x.astype(str).apply(LegendFormatFunc, axis = 1))  )).values.flatten() # saturation > 0 and < 1

    # remove unused elements from legend_order, palette_order, and marker_order
    legend_present = df[legend_title].unique()
    legend_order,palette_order,marker_order = map(list, zip(*[(i,j,k) for i,j,k in
                                             zip( legend_order,palette_order,marker_order) if i in legend_present]) )

    plot_dpi = 300
    sns.set_style("darkgrid")
    sns.set(rc={'figure.facecolor': '#F8F8F8'})
    sns.set_context(context="notebook", font_scale=1.2)

    # workaround to skip kde plots with single data point
    single_elements = df.groupby(legend_columns).size() == 1
    ###import pdb; pdb.set_trace()
    sns_plot = None
    if not single_elements.any():
        try:
            sns_plot = sns.pairplot(vars=columns, hue = legend_title , hue_order = legend_order,
                                    palette = palette_order, data = df,
                                    markers= marker_order, plot_kws={ "s": 150, "linewidth": 0.05 }, height = 5 )

            # set axis limits
            if ax_lims != None:
                for i in range(len(columns)):
                    sns_plot.axes[i,i].set_xbound( ax_lims[columns[i]] )
                    sns_plot.axes[i,i].set_ybound( ax_lims[columns[i]] )

            # save plot
            sns_plot.savefig("/home/e/figure.png", dpi=plot_dpi)

        except:
            pass

    return sns_plot


#!/usr/bin/env python
# -*- coding: utf-8 -*-

#Uso de Set
def coleccion():
    set_1 = set()
    print(set_1)
    set_2 = set([1,2,3,4,5])
    print(set_2)
    set_3 = {1,2,3,4,}
    print(set_3)
    causa = ''
    try:
        set_4 = set_1 + set_2
        print(set_4)
    except TypeError as error:
        print("Ha ocurrido una excepcion: operacion invalida")
        causa = 'La causa ha sido: '+str(error)
    finally:
        print(causa)
    print("************************************************")
    cadena = set('El extraño caso de la serpiente programadora.')
    print("Contenido:\n",cadena)
    for c in cadena:
        print(c)

def main():
	coleccion()

if __name__ == '__main__':
    main()


from django.db import IntegrityError
from django.shortcuts import get_object_or_404
from django.utils.text import slugify
from rest_framework import status
from rest_framework import viewsets
from rest_framework.exceptions import ValidationError
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from sd_accounts.models import CustomUser

from .models import Project, Issue, Comment, Contributor
from .permissions import IsProjectAuthor, IsContributor
from .serializers import ProjectSerializer, IssueSerializer, CommentSerializer, ContributorSerializer

class CustomPagination(PageNumberPagination):
    page_size = 2
    page_size_query_param = 'page_size'

class ProjectViewset(ModelViewSet):
    queryset = Project.objects.all()
    serializer_class = ProjectSerializer
    lookup_field = 'slug'
    pagination_class = CustomPagination
    permission_classes = [IsProjectAuthor]
    def get_queryset(self):
        queryset = Project.objects.all()
        print("Queryset : ", queryset)
        active = self.request.query_params.get('active', None)
        if active is not None:
            active = active.lower() in ('true', 'yes', '1')
            queryset = queryset.filter(active=active)
        return queryset

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def perform_create(self, serializer):
        if self.request.user.is_authenticated:
            project_name = serializer.validated_data.get("name", "")  # assuming you have a name field
            unique_slug = self._generate_unique_slug(project_name)
            try:
                project = serializer.save(author=self.request.user, slug=unique_slug)
                contributor = Contributor.objects.create(user=self.request.user, project=project, permission='Creator')
                print("Project author set : ", contributor)
            except IntegrityError:
                raise ValidationError("Erreur lors de la création du projet. Veuillez réessayer.")
        else:
            raise ValidationError("Vous devez être connecté pour créer un projet.")

    def get_permissions(self):
        if self.action in ['update', 'partial_update', 'destroy']:
            permission_classes = [IsProjectAuthor]
        else:
            permission_classes = [IsAuthenticated]
        return [permission() for permission in permission_classes]

    def _generate_unique_slug(self, project_name):
        """Generate a unique slug for a given project name."""
        slug = slugify(project_name)
        unique_slug = slug
        num = 1
        while Project.objects.filter(slug=unique_slug).exists():
            unique_slug = f"{slug}-{num}"
            num += 1
        return unique_slug

    def destroy(self, request, *args, **kwargs):
        print("kwargs:", self.kwargs)
        try:
            instance = self.get_object()
            self.perform_destroy(instance)
            return Response(status=status.HTTP_204_NO_CONTENT)
        except Http404:
            return Response({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND)

class ContributorViewset(ModelViewSet):
    """ View to manage Contributors of a project """
    serializer_class = ContributorSerializer
    permission_classes = [IsProjectAuthor, IsContributor]

    def get_queryset(self):
        project_slug = self.kwargs.get("project_slug", None)
        if project_slug is None:
            return Contributor.objects.none()
        return Contributor.objects.filter(project__slug=project_slug)

    def perform_create(self, serializer):
        project = get_object_or_404(Project, slug=self.kwargs["project_slug"])
        if not Contributor.objects.filter(user=self.request.user,
                                          project=project).exists() and project.author != self.request.user:
            raise ValidationError("Vous n'avez pas la permission d'ajouter des contributeurs.")
        username = self.request.data.get('user')
        if not username:
            raise ValidationError("Le champ 'username' est requis.")
        try:
            user = CustomUser.objects.get(username=username)
        except CustomUser.DoesNotExist:
            raise ValidationError("L'utilisateur spécifié n'existe pas.")

        if Contributor.objects.filter(user=user, project=project).exists():
            raise ValidationError("L'utilisateur est déjà un contributeur de ce projet.")

        serializer.save(user=user, project=project, permission='Contributor')

    def get_permissions(self):
        if self.action in ['update', 'partial_update', 'destroy']:
            permission_classes = [IsProjectAuthor]
        elif self.action in ['list', 'retrieve', 'create']:
            permission_classes = [IsProjectAuthor | IsContributor]
        else:
            permission_classes = [IsProjectAuthor]
        return [permission() for permission in permission_classes]

class IssueViewset(ModelViewSet):
    """ View to manage Issues of a project """
    serializer_class = IssueSerializer
    pagination_class = CustomPagination
    lookup_field = 'id'
    permission_classes = [IsProjectAuthor, IsContributor]

    def get_queryset(self):
        project_slug = self.kwargs.get("project_slug", None)
        return Issue.objects.filter(project__slug=project_slug)

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context["project_slug"] = self.kwargs.get("project_slug", None)
        return context

    def perform_create(self, serializer):
        project = get_object_or_404(Project, slug=self.kwargs["project_slug"])
        serializer.save(author=self.request.user, project=project)

    def get_permissions(self):
        if self.action in ['create', 'list', 'retrieve']:
            permission_classes = [IsProjectAuthor | IsContributor]
        else:
            permission_classes = [IsProjectAuthor]
        return [permission() for permission in permission_classes]

class CommentViewSet(viewsets.ModelViewSet):
    serializer_class = CommentSerializer
    pagination_class = CustomPagination
    permission_classes = [IsProjectAuthor | IsContributor]

    def get_issue(self):
        project_slug = self.kwargs.get("project_slug", None)
        issue_id = self.kwargs.get("issue_id", None)
        if project_slug is None or issue_id is None:
            return None
        print("Issue id : ", issue_id)
        return get_object_or_404(Issue, project__slug=project_slug, id=issue_id)

    def get_queryset(self):
        issue = self.get_issue()
        return Comment.objects.filter(issue=issue)

    def perform_create(self, serializer):
        issue = self.get_issue()

        serializer.save(author=self.request.user, issue=issue)

    def get_permissions(self):
        if self.action in ['create', 'list', 'retrieve']:
            permission_classes = [IsProjectAuthor | IsContributor]
        else:
            permission_classes = [IsProjectAuthor]
        return [permission() for permission in permission_classes]


# from clint.textui import progress
# from curses import update_lines_cols
# from turtle import update
import os
import sys
import requests
import patoolib
import time
from django.conf import settings
from django.core.management.base import BaseCommand
from ge.models import Dataset, WFControl
from django.utils import timezone
from django.core.exceptions import ObjectDoesNotExist

"""
First process in the data flow and aims to extract new versions of external databases for the PSA area

Version Control Rule:   Collect only considers datasets marked as active and different version control
                        To reprocess a database with same version, use reset and run the dataset

Options:
--run_all       ==> Consider all active datasets to collect the files.
--run "ds"      ==> Consider just one dataset to collect the file.
--reset_all     ==> Reset version control to all datasets.
--reset "ds"    ==> Reset version control just one dataset.
--show          ==> Print all datasets
--active "ds"   ==> Active a dataset to collect the files
--deactive "ds" ==> Deactive a dataset to collect the files

Pendencies
 - Create setting to active logs
 - How to handle zip with multi files

 - Add download process
    Clint isn't works ()

- Criar um check para conferir se o link eh valido ou nao.
- no load da Dataset nao posso mudar tudo para lowcase

"""

class Command(BaseCommand):
    help = 'Collect external databases to PSA'

    def add_arguments(self, parser):

        parser.add_argument(
            '--run',
            type=str,
            metavar='dataset',
            action='store',
            default=None,
            help='Will process active Datasets and with new version',
        )

        parser.add_argument(
            '--reset',
            type=str,
            metavar='dataset',
            action='store',
            default=None,
            help='Will reset dataset version control',
        )

        parser.add_argument(
            '--show',
            action='store_true',
            help='Will show the Master Data Datasets',
        )

        parser.add_argument(
            '--activate',
            type=str,
            metavar='dataset',
            action='store',
            default=None,
            help='',
        )

        parser.add_argument(
            '--deactivate',
            type=str,
            metavar='dataset',
            action='store',
            default=None,
            help='',
        )

    def handle(self, *args, **options):
        v_path_file = str(settings.BASE_DIR) + "/psa/"

        if options['run']:
            v_time_process = time.time()
            v_opt_ds = str(options['run']).lower()

            self.stdout.write(self.style.HTTP_NOT_MODIFIED('Start: Process to collect external databases'))

            if  v_opt_ds == 'all':
                v_where_cs = {'update_ds': True}
            else:
                v_where_cs = {'update_ds': True, 'dataset': v_opt_ds}
            try:
                qs_queryset = Dataset.objects.filter(**v_where_cs)
            except ObjectDoesNotExist:
                self.stdout.write(self.style.HTTP_BAD_REQUEST('  Datasets not found or disabled'))
                sys.exit(2)
            if not qs_queryset:
                self.stdout.write(self.style.HTTP_BAD_REQUEST('  Datasets not found or disabled'))
                sys.exit(2)

            for qs in qs_queryset:
                self.stdout.write(self.style.HTTP_NOT_MODIFIED ('  Start: Run database {0} on dataset {1}'.format(qs.database, qs.dataset)))
                v_time_ds = time.time()

                # Variables
                v_dir = v_path_file + qs.dataset
                v_file_url = qs.source_path
                v_source_file = v_dir + "/" + qs.source_file_name
                v_target_file = v_dir + "/" + qs.target_file_name

                # Create folder to host file download
                if not os.path.isdir(v_dir):
                    os.makedirs(v_dir)
                    print("   Folder created to host the files in ", v_dir)

                # Get file source version from ETAG
                try:
                    v_version = str(requests.get(v_file_url, stream=True).headers["etag"])
                except:
                    v_version = "0"
                    self.stdout.write(self.style.HTTP_NOT_FOUND("    Could not find the version of the file. Assigned a random version"))

                # Get WorkFlow Control
                try:
                    qs_wfc = WFControl.objects.get(dataset_id = qs.id)
                except ObjectDoesNotExist:
                    qs_control = WFControl(
                        dataset_id = qs.id,
                        last_update = timezone.now(),
                        source_file_version = 0,
                        source_file_size = 0,
                        target_file_size = 0,
                        chk_collect = False,
                        chk_prepare = False,
                        chk_map = False,
                        chk_reduce = False
                    )
                    qs_control.save()
                    qs_wfc = WFControl.objects.get(dataset_id = qs.id)

                # Check is new version before download
                if qs_wfc.source_file_version == v_version:
                    # Same vrsion, only write the log table
                    # Create a LOG setting control (optional to log control)
                    # log = LogsCollector(source_file_name = qs.source_file_name,
                    #                     date = timezone.now(),
                    #                     dataset = qs.dataset,
                    #                     database = qs.database,
                    #                     version = v_version,
                    #                     status = False,
                    #                     size = 0)
                    # log.save()
                    self.stdout.write(self.style.HTTP_INFO('    Version already loaded in: {0}'.format(qs_wfc.last_update)))

                # New file version, start download
                else:
                    if os.path.exists(v_target_file):
                        os.remove(v_target_file)
                    if os.path.exists(v_source_file):
                        os.remove(v_source_file)

                    self.stdout.write(self.style.HTTP_SUCCESS('    Download start'))

                    r = requests.get(v_file_url, stream=True)
                    with open(v_source_file, "wb") as f:
                        # total_length = int(r.headers.get('content-length'))
                        # for chunk in progress.bar(r.iter_content(chunk_size=1024), expected_size=(total_length/1024) + 1):
                        for chunk in r.iter_content(chunk_size=1000000):
                                if chunk:
                                    f.write(chunk)
                                    f.flush()

                    # Update LOG table if new version
                    v_size = str(os.stat(v_source_file).st_size)
                    # Create a LOG setting control (optional to log control)
                    # log = LogsCollector(source_file_name = qs.source_file_name,
                    #                     date = timezone.now(), #datetime.datetime.now(),
                    #                     dataset = qs.dataset,
                    #                     database = qs.database,
                    #                     version = v_version,
                    #                     status = True,
                    #                     size = v_size)
                    # log.save()
                    self.stdout.write(self.style.HTTP_SUCCESS('    Download finish'))

                    # Unzip source file
                    if qs.source_compact:
                        try:
                            self.stdout.write(self.style.HTTP_SUCCESS('    Unzip start'))
                            patoolib.extract_archive(str(v_source_file), outdir=str(v_dir), verbosity=-1)
                            os.remove(v_source_file)
                        except:
                            self.stdout.write(self.style.HTTP_BAD_REQUEST('    Failed to unzip file'))
                            continue

                    # Check if target file is ok
                    if not os.path.exists(v_target_file):
                        self.stdout.write(self.style.HTTP_BAD_REQUEST('    Failed to read file'))
                        self.stdout.write(self.style.HTTP_SUCCESS('       Possible cause: check if the names of the source and destination files are correct in the dataset table'))
                        qs_wfc.source_file_version = "ERROR"
                        qs_wfc.last_update = timezone.now()
                        qs_wfc.save()
                        for i in os.listdir(v_dir):
                            os.remove(v_dir + "/" + i)
                        continue

                    # Update WorkFlow Control table:
                    self.stdout.write(self.style.HTTP_SUCCESS('    Update workflow control'))
                    qs_wfc.source_file_version = v_version
                    qs_wfc.source_file_size = v_size
                    qs_wfc.target_file_size = str(os.stat(v_target_file).st_size)
                    qs_wfc.last_update = timezone.now()
                    qs_wfc.chk_collect = True
                    qs_wfc.chk_prepare = False
                    qs_wfc.chk_map = False
                    qs_wfc.reduce = False
                    qs_wfc.save()

                    self.stdout.write(self.style.HTTP_REDIRECT('    Dataset loaded in {0} seconds'.format(int(time.time() - v_time_ds))))

            self.stdout.write(self.style.SUCCESS('End of process in {0} seconds'.format(int(time.time() - v_time_process))))

        if options['reset']:
            v_opt_ds = str(options['reset']).lower()

            if  v_opt_ds == 'all':
                qs_wfc = WFControl.objects.all()
                qs_wfc.update(last_update = timezone.now(),
                                source_file_version = 0,
                                source_file_size = 0,
                                target_file_size = 0,
                                chk_collect = False,
                                chk_prepare = False,
                                chk_map = False,
                                chk_reduce = False)
                self.stdout.write(self.style.SUCCESS('All datasets are defined for the prepare step'))
            else:
                try:
                    qs_wfc = WFControl.objects.get(dataset_id__dataset = v_opt_ds)
                    qs_wfc.last_update = timezone.now()
                    qs_wfc.source_file_version = 0
                    qs_wfc.source_file_size = 0
                    qs_wfc.target_file_size = 0
                    qs_wfc.chk_collect = False
                    qs_wfc.chk_prepare = False
                    qs_wfc.chk_map = False
                    qs_wfc.chk_reduce = False
                    qs_wfc.save()
                    self.stdout.write(self.style.SUCCESS('Dataset {0} is defined for the prepare step'.format(v_opt_ds)))
                except ObjectDoesNotExist:
                    self.stdout.write(self.style.HTTP_NOT_FOUND('dataset {0} not fount'.format(v_opt_ds)))

        if options['show']:
            qs_queryset = Dataset.objects.all().order_by('database')
            v_db = 0
            for qs in qs_queryset:
                if v_db != qs.database:
                    self.stdout.write(self.style.HTTP_NOT_MODIFIED(qs.database))
                self.stdout.write(self.style.HTTP_SUCCESS('  Id: {0} - status: {2} - dataset: {1}'.format(qs.id, qs.dataset, qs.update_ds)))
                v_db = qs.database

        if options['activate']:
            try:
                v_opt_ds = str(options['activate']).lower()
                qs_wfc = Dataset.objects.get(dataset = v_opt_ds)
                qs_wfc.update_ds=True
                qs_wfc.save()
                self.stdout.write(self.style.SUCCESS('dataset activated'))
            except ObjectDoesNotExist:
                self.stdout.write(self.style.ERROR('Could not find dataset'))

        if options['deactivate']:
            try:
                v_opt_ds = str(options['deactivate']).lower()
                qs_wfc = Dataset.objects.get(dataset = v_opt_ds)
                qs_wfc.update_ds=False
                qs_wfc.save()
                self.stdout.write(self.style.SUCCESS('dataset dactivated'))
            except ObjectDoesNotExist:
                self.stdout.write(self.style.ERROR('Could not find dataset'))


import random
print("Welcome to number guessing game! You must guess the number between 1-20 to win")
num=random.randint(1,20)
chance=5
while(chance>0):
    print("Number of lives ",chance)
    guess=int(input("Enter the number"))
    if(guess==num):
        print("Congratulations! You won!")
        break
    elif(guess<num):
        print("Your guess is less than the number")
    else:
        print("Your guess is more than the number")

    chance=chance-1

if(chance==0):
    print("You lose! The number was ",num)


import csv
import time

start_time = time.time() # Start time of the algorithm

def read_stock_data_from_csv(file_path):
    """Reads stock data from a CSV file and returns a list of tuples"""
    stocks = []
    with open(file_path, newline='', encoding='utf-8') as csvfile:
        stock_reader = csv.reader(csvfile, delimiter=',')
        next(stock_reader)  # Skipping the header row
        for row in stock_reader:
            name = row[0]
            cost = float(row[1])
            profit_percentage = float(row[2].replace('%', ''))
            profit = cost * profit_percentage / 100
            stocks.append((name, cost, profit))
    return stocks

# Optimized investment algorithm using a greedy approach
def optimized_investment(stocks, max_investment=500):
    """Sorts and returns the best combination of stocks and the total profit"""
    sorted_stocks = sorted(stocks, key=lambda x: x[2]/x[1], reverse=True) # Sorting by profit/cost ratio

    total_cost = 0
    total_profit = 0
    selected_stocks = []

    for stock in sorted_stocks: # Greedy approach
        if total_cost + stock[1] <= max_investment:
            selected_stocks.append(stock)
            total_cost += stock[1]
            total_profit += stock[2]

    return selected_stocks, total_profit

# File path to the CSV file
csv_file_path = 'Dataset/actions.csv'

# Reading the stock data and finding the best combination using the optimized function
stocks_from_csv = read_stock_data_from_csv(csv_file_path)
best_combination_optimized, best_profit_optimized = optimized_investment(stocks_from_csv)

end_time = time.time() # End time of the algorithm

execution_time = end_time - start_time # Total execution time

# Printing the results
print("Optimized Stock Investment Combination:")
for stock in best_combination_optimized:
    print(f"{stock[0]}: Cost {stock[1]:.2f} euros, Profit {stock[2]:.2f} euros")
print(f"Total Profit: {best_profit_optimized:.2f} euros")
print(f"Execution time: {execution_time:.4f} seconds")


from Review.views import export_to_excel
from . import views
from django.urls import path
from .views import   Allchart, ListFeedbackView, SearchResultsView, deleteAllFeedback, FeedbackDetailView,FacultyFeedbackDetailView, DeleteFeedbackView, facultyRegister, load_subjects,loginPage,registerPage,FacultyView,FacultyFeedbackList,FacultyFeedback,Chart

urlpatterns = [
    path('', ListFeedbackView.as_view(), name='ListFeedbackView'),
    path('search/', SearchResultsView.as_view(), name='SearchResultsView'),
    path('student_login', loginPage, name='LoginPage'),
    path('register', registerPage, name='RegisterPage'),
    path('faculty_login', FacultyView, name='FacultyView'),
    path('faculty_feedback', FacultyFeedbackList.as_view(), name='FacultyFeedbackList'),
    path('review/detail_feedback', FeedbackDetailView.as_view(), name='FeedbackDetailView'),
    path('facultyregister', facultyRegister, name='FacultyRegisterPage'),
    path('delete/', deleteAllFeedback, name='deleteAllFeedback'),
    path('feedback/<int:pk>/', FeedbackDetailView.as_view(), name='FeedbackDetailView'),
    path('faculty_feedback/<int:pk>/', FacultyFeedback.as_view(), name='FacultyFeedback'),
    path('faculty_detail_feedback/<int:pk>/', FacultyFeedbackDetailView.as_view(), name='FacultyFeedbackDetailView'),
    path('feedback/<int:pk>/delete/', DeleteFeedbackView.as_view(), name='DeleteFeedbackView'),

    path('<int:pk>/', views.faculty_update_view, name='faculty_change'),
    path('ajax/load-subjects/', views.load_subjects, name='ajax_load_subjects'),
    # for chart
    path('chart/', Chart, name='Chart'),
    path('allchart/', Allchart, name='AllChart'),
    path('export-to-excel/', export_to_excel, name='export-to-excel'),
]


import torch
from collections import OrderedDict

def load_pretrained_weights(net, path, replace_key=None, skip_key=None, required_key=None):
    """Loads pretrained weights from the path on disk to the network.

    This is a utility function to handle loading pretrained weights from disk
    to the network. This function handles cases when the network is initialized
    using nn.DataParallel and the weights were not or vice-versa.
    Args:
        net:
        path (str): Path to ckpt weights.
        replace_key (Optional[dict]):

    Returns:

    """
    if path is None:
        return
    if replace_key is None:
        replace_key = {}
    init_dict = net.state_dict()
    net_dict = torch.load(path)
    if 'state_dict' in net_dict:
        net_dict = net_dict['state_dict']
    net_data_parallel = ckpt_data_parallel = False
    if "module" in list(init_dict.keys())[0].lower():
        net_data_parallel = True
    if "module" in list(net_dict.keys())[0].lower():
        ckpt_data_parallel = True

    def replace_key_name(name):
        for k, v in replace_key.items():
            if k in name:
                return name.replace(k, v)
        return name

    def check_skip_key(k, required, skip):
        if skip:
            for s in skip:
                if s in k: return True

        check_res = False
        if required:
            check_res = True
            for s in required:
                if s in k: check_res = False
        return check_res

    new_state_dict = OrderedDict()
    for k, v in net_dict.items():
        if check_skip_key(k, required_key, skip_key):
            continue
        if net_data_parallel and not ckpt_data_parallel:
            new_key = "module." + replace_key_name(k)
        elif not net_data_parallel and ckpt_data_parallel:
            new_key = replace_key_name(k[7:])  # remove the prefix "module".
        else:
            new_key = replace_key_name(k)
        new_state_dict[new_key] = v

    net_dict = new_state_dict
    init_dict.update(net_dict)
    net.load_state_dict(init_dict)
    return net