import struct

import numpy as np

from .data_type import DataType
from .operation import CustomType
from .operation import Op
from .tflite import AbsOptions
from .tflite import AddNOptions
from .tflite import AddOptions
from .tflite import ArgMaxOptions
from .tflite import ArgMinOptions
from .tflite import BatchMatMulOptions
from .tflite import BatchToSpaceNDOptions
from .tflite import BidirectionalSequenceLSTMOptions
from .tflite import BidirectionalSequenceRNNOptions
from .tflite import CallOptions
from .tflite import CastOptions
from .tflite import ConcatEmbeddingsOptions
from .tflite import ConcatenationOptions
from .tflite import Conv2DOptions
from .tflite import CosOptions
from .tflite import DensifyOptions
from .tflite import DepthToSpaceOptions
from .tflite import DepthwiseConv2DOptions
from .tflite import DequantizeOptions
from .tflite import DivOptions
from .tflite import EmbeddingLookupSparseOptions
from .tflite import EqualOptions
from .tflite import ExpandDimsOptions
from .tflite import ExpOptions
from .tflite import FakeQuantOptions
from .tflite import FillOptions
from .tflite import FloorDivOptions
from .tflite import FloorModOptions
from .tflite import FullyConnectedOptions
from .tflite import GatherNdOptions
from .tflite import GatherOptions
from .tflite import GreaterEqualOptions
from .tflite import GreaterOptions
from .tflite import HardSwishOptions
from .tflite import IfOptions
from .tflite import L2NormOptions
from .tflite import LeakyReluOptions
from .tflite import LessEqualOptions
from .tflite import LessOptions
from .tflite import LocalResponseNormalizationOptions
from .tflite import LogicalAndOptions
from .tflite import LogicalNotOptions
from .tflite import LogicalOrOptions
from .tflite import LogSoftmaxOptions
from .tflite import LSHProjectionOptions
from .tflite import LSTMOptions
from .tflite import MatrixDiagOptions
from .tflite import MatrixSetDiagOptions
from .tflite import MaximumMinimumOptions
from .tflite import MirrorPadOptions
from .tflite import MulOptions
from .tflite import NegOptions
from .tflite import NonMaxSuppressionV4Options
from .tflite import NonMaxSuppressionV5Options
from .tflite import NotEqualOptions
from .tflite import OneHotOptions
from .tflite import PackOptions
from .tflite import PadOptions
from .tflite import PadV2Options
from .tflite import Pool2DOptions
from .tflite import PowOptions
from .tflite import QuantizeOptions
from .tflite import RangeOptions
from .tflite import RankOptions
from .tflite import ReducerOptions
from .tflite import ReshapeOptions
from .tflite import ResizeBilinearOptions
from .tflite import ResizeNearestNeighborOptions
from .tflite import ReverseSequenceOptions
from .tflite import ReverseV2Options
from .tflite import RNNOptions
from .tflite import ScatterNdOptions
from .tflite import SegmentSumOptions
from .tflite import SelectOptions
from .tflite import SelectV2Options
from .tflite import SequenceRNNOptions
from .tflite import ShapeOptions
from .tflite import SkipGramOptions
from .tflite import SliceOptions
from .tflite import SoftmaxOptions
from .tflite import SpaceToBatchNDOptions
from .tflite import SpaceToDepthOptions
from .tflite import SparseToDenseOptions
from .tflite import SplitOptions
from .tflite import SplitVOptions
from .tflite import SquaredDifferenceOptions
from .tflite import SquareOptions
from .tflite import SqueezeOptions
from .tflite import StridedSliceOptions
from .tflite import SubOptions
from .tflite import SVDFOptions
from .tflite import TileOptions
from .tflite import TopKV2Options
from .tflite import TransposeConvOptions
from .tflite import TransposeOptions
from .tflite import UnidirectionalSequenceLSTMOptions
from .tflite import UniqueOptions
from .tflite import UnpackOptions
from .tflite import WhereOptions
from .tflite import WhileOptions
from .tflite import ZerosLikeOptions
from .tflite.ActivationFunctionType import ActivationFunctionType
from .tflite.BuiltinOperator import BuiltinOperator
from .tflite.BuiltinOptions import BuiltinOptions
from .tflite.Padding import Padding
from .tflite.TensorType import TensorType

def inverse_map(map):
    return {v: k for k, v in map.items()}

datatype_map = {
    TensorType.UINT8: DataType.uint8,
    TensorType.INT8: DataType.int8,
    TensorType.INT16: DataType.int16,
    TensorType.INT32: DataType.int32,
    TensorType.INT64: DataType.int64,
    TensorType.FLOAT16: DataType.float16,
    TensorType.FLOAT32: DataType.float32,
    TensorType.FLOAT64: DataType.float64,
    TensorType.STRING: DataType.string,
    TensorType.BOOL: DataType.bool,
    TensorType.COMPLEX64: DataType.complex64,
    TensorType.COMPLEX128: DataType.complex128,
}

datatype_inv_map = inverse_map(datatype_map)
datatype_inv_map[DataType.quint8] = TensorType.UINT8

datatype_inv_map[DataType.qint8] = TensorType.INT8
datatype_inv_map[DataType.qint16] = TensorType.INT16
datatype_inv_map[DataType.qint32] = TensorType.INT32

datatype_map_numpy = {
    TensorType.UINT8: np.uint8,
    TensorType.INT8: np.int8,
    TensorType.INT16: np.int16,
    TensorType.INT32: np.int32,
    TensorType.INT64: np.int64,
    TensorType.FLOAT16: np.float16,
    TensorType.FLOAT32: np.float32,
    TensorType.FLOAT64: np.float64,
    TensorType.BOOL: np.bool,
    TensorType.COMPLEX64: np.complex64,
    TensorType.COMPLEX128: np.complex128,
    TensorType.STRING: np.dtype("S1"),
}

builtin_options_map = {
    BuiltinOptions.Conv2DOptions: Conv2DOptions.Conv2DOptions,
    BuiltinOptions.DepthwiseConv2DOptions: DepthwiseConv2DOptions.DepthwiseConv2DOptions,
    BuiltinOptions.ConcatEmbeddingsOptions: ConcatEmbeddingsOptions.ConcatEmbeddingsOptions,
    BuiltinOptions.LSHProjectionOptions: LSHProjectionOptions.LSHProjectionOptions,
    BuiltinOptions.Pool2DOptions: Pool2DOptions.Pool2DOptions,
    BuiltinOptions.SVDFOptions: SVDFOptions.SVDFOptions,
    BuiltinOptions.RNNOptions: RNNOptions.RNNOptions,
    BuiltinOptions.FullyConnectedOptions: FullyConnectedOptions.FullyConnectedOptions,
    BuiltinOptions.SoftmaxOptions: SoftmaxOptions.SoftmaxOptions,
    BuiltinOptions.ConcatenationOptions: ConcatenationOptions.ConcatenationOptions,
    BuiltinOptions.AddOptions: AddOptions.AddOptions,
    BuiltinOptions.L2NormOptions: L2NormOptions.L2NormOptions,
    BuiltinOptions.LocalResponseNormalizationOptions: LocalResponseNormalizationOptions.LocalResponseNormalizationOptions,  # noqa: E501
    BuiltinOptions.LSTMOptions: LSTMOptions.LSTMOptions,
    BuiltinOptions.ResizeBilinearOptions: ResizeBilinearOptions.ResizeBilinearOptions,
    BuiltinOptions.CallOptions: CallOptions.CallOptions,
    BuiltinOptions.ReshapeOptions: ReshapeOptions.ReshapeOptions,
    BuiltinOptions.SkipGramOptions: SkipGramOptions.SkipGramOptions,
    BuiltinOptions.SpaceToDepthOptions: SpaceToDepthOptions.SpaceToDepthOptions,
    BuiltinOptions.EmbeddingLookupSparseOptions: EmbeddingLookupSparseOptions.EmbeddingLookupSparseOptions,
    BuiltinOptions.MulOptions: MulOptions.MulOptions,
    BuiltinOptions.PadOptions: PadOptions.PadOptions,
    BuiltinOptions.GatherOptions: GatherOptions.GatherOptions,
    BuiltinOptions.BatchToSpaceNDOptions: BatchToSpaceNDOptions.BatchToSpaceNDOptions,
    BuiltinOptions.SpaceToBatchNDOptions: SpaceToBatchNDOptions.SpaceToBatchNDOptions,
    BuiltinOptions.TransposeOptions: TransposeOptions.TransposeOptions,
    BuiltinOptions.ReducerOptions: ReducerOptions.ReducerOptions,
    BuiltinOptions.SubOptions: SubOptions.SubOptions,
    BuiltinOptions.DivOptions: DivOptions.DivOptions,
    BuiltinOptions.SqueezeOptions: SqueezeOptions.SqueezeOptions,
    BuiltinOptions.SequenceRNNOptions: SequenceRNNOptions.SequenceRNNOptions,
    BuiltinOptions.StridedSliceOptions: StridedSliceOptions.StridedSliceOptions,
    BuiltinOptions.ExpOptions: ExpOptions.ExpOptions,
    BuiltinOptions.TopKV2Options: TopKV2Options.TopKV2Options,
    BuiltinOptions.SplitOptions: SplitOptions.SplitOptions,
    BuiltinOptions.LogSoftmaxOptions: LogSoftmaxOptions.LogSoftmaxOptions,
    BuiltinOptions.CastOptions: CastOptions.CastOptions,
    BuiltinOptions.DequantizeOptions: DequantizeOptions.DequantizeOptions,
    BuiltinOptions.MaximumMinimumOptions: MaximumMinimumOptions.MaximumMinimumOptions,
    BuiltinOptions.ArgMaxOptions: ArgMaxOptions.ArgMaxOptions,
    BuiltinOptions.LessOptions: LessOptions.LessOptions,
    BuiltinOptions.NegOptions: NegOptions.NegOptions,
    BuiltinOptions.PadV2Options: PadV2Options.PadV2Options,
    BuiltinOptions.GreaterOptions: GreaterOptions.GreaterOptions,
    BuiltinOptions.GreaterEqualOptions: GreaterEqualOptions.GreaterEqualOptions,
    BuiltinOptions.LessEqualOptions: LessEqualOptions.LessEqualOptions,
    BuiltinOptions.SelectOptions: SelectOptions.SelectOptions,
    BuiltinOptions.SliceOptions: SliceOptions.SliceOptions,
    BuiltinOptions.TransposeConvOptions: TransposeConvOptions.TransposeConvOptions,
    BuiltinOptions.SparseToDenseOptions: SparseToDenseOptions.SparseToDenseOptions,
    BuiltinOptions.TileOptions: TileOptions.TileOptions,
    BuiltinOptions.ExpandDimsOptions: ExpandDimsOptions.ExpandDimsOptions,
    BuiltinOptions.EqualOptions: EqualOptions.EqualOptions,
    BuiltinOptions.NotEqualOptions: NotEqualOptions.NotEqualOptions,
    BuiltinOptions.ShapeOptions: ShapeOptions.ShapeOptions,
    BuiltinOptions.PowOptions: PowOptions.PowOptions,
    BuiltinOptions.ArgMinOptions: ArgMinOptions.ArgMinOptions,
    BuiltinOptions.FakeQuantOptions: FakeQuantOptions.FakeQuantOptions,
    BuiltinOptions.PackOptions: PackOptions.PackOptions,
    BuiltinOptions.LogicalOrOptions: LogicalOrOptions.LogicalOrOptions,
    BuiltinOptions.OneHotOptions: OneHotOptions.OneHotOptions,
    BuiltinOptions.LogicalAndOptions: LogicalAndOptions.LogicalAndOptions,
    BuiltinOptions.LogicalNotOptions: LogicalNotOptions.LogicalNotOptions,
    BuiltinOptions.UnpackOptions: UnpackOptions.UnpackOptions,
    BuiltinOptions.FloorDivOptions: FloorDivOptions.FloorDivOptions,
    BuiltinOptions.SquareOptions: SquareOptions.SquareOptions,
    BuiltinOptions.ZerosLikeOptions: ZerosLikeOptions.ZerosLikeOptions,
    BuiltinOptions.FillOptions: FillOptions.FillOptions,
    BuiltinOptions.BidirectionalSequenceLSTMOptions: BidirectionalSequenceLSTMOptions.BidirectionalSequenceLSTMOptions,
    BuiltinOptions.BidirectionalSequenceRNNOptions: BidirectionalSequenceRNNOptions.BidirectionalSequenceRNNOptions,
    BuiltinOptions.UnidirectionalSequenceLSTMOptions: UnidirectionalSequenceLSTMOptions.UnidirectionalSequenceLSTMOptions,  # noqa: E501
    BuiltinOptions.FloorModOptions: FloorModOptions.FloorModOptions,
    BuiltinOptions.RangeOptions: RangeOptions.RangeOptions,
    BuiltinOptions.ResizeNearestNeighborOptions: ResizeNearestNeighborOptions.ResizeNearestNeighborOptions,
    BuiltinOptions.LeakyReluOptions: LeakyReluOptions.LeakyReluOptions,
    BuiltinOptions.SquaredDifferenceOptions: SquaredDifferenceOptions.SquaredDifferenceOptions,
    BuiltinOptions.MirrorPadOptions: MirrorPadOptions.MirrorPadOptions,
    BuiltinOptions.AbsOptions: AbsOptions.AbsOptions,
    BuiltinOptions.SplitVOptions: SplitVOptions.SplitVOptions,
    BuiltinOptions.UniqueOptions: UniqueOptions.UniqueOptions,
    BuiltinOptions.ReverseV2Options: ReverseV2Options.ReverseV2Options,
    BuiltinOptions.AddNOptions: AddNOptions.AddNOptions,
    BuiltinOptions.GatherNdOptions: GatherNdOptions.GatherNdOptions,
    BuiltinOptions.CosOptions: CosOptions.CosOptions,
    BuiltinOptions.WhereOptions: WhereOptions.WhereOptions,
    BuiltinOptions.RankOptions: RankOptions.RankOptions,
    BuiltinOptions.ReverseSequenceOptions: ReverseSequenceOptions.ReverseSequenceOptions,
    BuiltinOptions.MatrixDiagOptions: MatrixDiagOptions.MatrixDiagOptions,
    BuiltinOptions.QuantizeOptions: QuantizeOptions.QuantizeOptions,
    BuiltinOptions.MatrixSetDiagOptions: MatrixSetDiagOptions.MatrixSetDiagOptions,
    BuiltinOptions.DensifyOptions: DensifyOptions.DensifyOptions,
    BuiltinOptions.DepthToSpaceOptions: DepthToSpaceOptions.DepthToSpaceOptions,
    BuiltinOptions.HardSwishOptions: HardSwishOptions.HardSwishOptions,
    BuiltinOptions.IfOptions: IfOptions.IfOptions,
    BuiltinOptions.NonMaxSuppressionV4Options: NonMaxSuppressionV4Options.NonMaxSuppressionV4Options,
    BuiltinOptions.NonMaxSuppressionV5Options: NonMaxSuppressionV5Options.NonMaxSuppressionV5Options,
    BuiltinOptions.ScatterNdOptions: ScatterNdOptions.ScatterNdOptions,
    BuiltinOptions.SegmentSumOptions: SegmentSumOptions.SegmentSumOptions,
    BuiltinOptions.SelectV2Options: SelectV2Options.SelectV2Options,
    BuiltinOptions.WhileOptions: WhileOptions.WhileOptions,
    BuiltinOptions.BatchMatMulOptions: BatchMatMulOptions.BatchMatMulOptions,
}

builtin_options_inv_map = inverse_map(builtin_options_map)

def underscore_to_camel_case(s):
    return "".join(x.title() for x in s.split("_"))

def padding_deserialize(x):
    return padding_map[x]

def padding_serialize(builder, x):
    return padding_inv_map[x]

def activation_deserialize(x):
    return activation_function_map[x]

def activation_serialize(builder, x):
    return activation_function_inv_map[x]

def datatype_deserialize(x):
    return datatype_map[x]

def datatype_serialize(builder, x):
    return datatype_inv_map[x]

def identity(x):
    return x

def identity_serialize(builder, x):
    return x

def write_byte_vector(builder, v):
    builder.StartVector(1, len(v), 1)
    for e in v[::-1]:
        builder.PrependByte(e)
    return builder.EndVector(len(v))

def write_int_vector(builder, v):
    builder.StartVector(4, len(v), 4)
    for e in v[::-1]:
        builder.PrependInt32(e)
    return builder.EndVector(len(v))

class OptionsSerializer:
    def __init__(self, name, members=[]):
        self.name = name
        self.module = globals()[self.name]
        self.cls = getattr(self.module, self.name)
        self.builtin_opt_type = builtin_options_inv_map[self.cls]
        self.members = []
        for mem in members:
            deserialize = identity
            serialize = identity_serialize
            is_vector = False
            if isinstance(mem, tuple):
                if len(mem) == 3:
                    mem, deserialize, serialize = mem
                elif len(mem) == 2:
                    mem, is_vector = mem
                    deserialize = tuple
                    serialize = write_int_vector
                else:
                    assert 0
            underscore_mem = mem
            camelcase_mem = underscore_to_camel_case(mem)
            self.members.append((underscore_mem, camelcase_mem, deserialize, serialize, is_vector))

    def deserialize(self, op_data):
        builtin_options = op_data.BuiltinOptions()
        attrs = {}
        if builtin_options:
            tfattrs = self.cls()
            tfattrs.Init(builtin_options.Bytes, builtin_options.Pos)
            for underscore_mem, camelcase_mem, deserialize, serialize, is_vector in self.members:
                fun = camelcase_mem
                if is_vector:
                    fun += "AsNumpy"

                attr = getattr(tfattrs, fun)()
                try:
                    attrs[underscore_mem] = deserialize(attr)
                except TypeError:
                    print("Warning: {0} could not read attribute '{1}'.".format(self.name, underscore_mem))

        return attrs

    def serialize(self, builder, attrs):
        ser_attrs = []
        for underscore_mem, camelcase_mem, deserialize, serialize, is_vector in self.members:
            a = serialize(builder, attrs[underscore_mem])
            ser_attrs.append((camelcase_mem, a))

        getattr(self.module, self.name + "Start")(builder)

        for camelcase_mem, a in ser_attrs:
            getattr(self.module, self.name + "Add" + camelcase_mem)(builder, a)

        return getattr(self.module, self.name + "End")(builder), None

class CustomOptionsSerializer:
    CUSTOM_OPTIONS_NPU_OP = [0x01, 0x04, 0x01]  # NpuOp=1, FlexbufferFormat.UINT8=4, byte length=1
    CUSTOM_OPTIONS_FORMAT_DEFAULT = 0

    def __init__(self):
        self.custom_opt_format = 0

    def deserialize(self, op_data):
        attrs = {}
        custom_options = op_data.CustomOptionsAsNumpy()
        attrs["custom_options"] = custom_options
        attrs["custom_options_format"] = op_data.CustomOptionsFormat()

        if np.array_equal(custom_options, self.CUSTOM_OPTIONS_NPU_OP):
            attrs["custom_type"] = CustomType.ExistingNpuOp

        return attrs

    def serialize(self, builder, attrs):
        custom_type = attrs.get("custom_type", CustomType.ThirdPartyOp)
        self.custom_opt_format = attrs.get("custom_options_format", self.CUSTOM_OPTIONS_FORMAT_DEFAULT)

        # Set NPU op custom options for the TensorFlow Lite custom operator
        if custom_type == CustomType.NpuOp:
            custom_options = self.CUSTOM_OPTIONS_NPU_OP
        else:
            custom_options = attrs.get("custom_options", [])

        custom_options_bytes = struct.pack("<{0}B".format(len(custom_options)), *custom_options)
        custom_offset = write_byte_vector(builder, custom_options_bytes)

        return None, custom_offset

padding_map = {
    Padding.SAME: b"SAME",
    Padding.VALID: b"VALID",
}

padding_inv_map = inverse_map(padding_map)

activation_function_map = {
    ActivationFunctionType.NONE: None,
    ActivationFunctionType.RELU: Op.Relu,
    ActivationFunctionType.RELU_N1_TO_1: Op.ReluN1To1,
    ActivationFunctionType.RELU6: Op.Relu6,
    ActivationFunctionType.TANH: Op.Tanh,
    ActivationFunctionType.SIGN_BIT: Op.SignBit,
}

activation_function_inv_map = inverse_map(activation_function_map)

fused_act = ("fused_activation_function", activation_deserialize, activation_serialize)
padding = ("padding", padding_deserialize, padding_serialize)

pool2d_opts = OptionsSerializer(
    "Pool2DOptions", (padding, "stride_w", "stride_h", "filter_width", "filter_height", fused_act,)
)

depthwise_opts = OptionsSerializer(
    "DepthwiseConv2DOptions",
    (padding, "stride_w", "stride_h", "depth_multiplier", fused_act, "dilation_w_factor", "dilation_h_factor",),
)

conv2d_opts = OptionsSerializer(
    "Conv2DOptions", (padding, "stride_w", "stride_h", fused_act, "dilation_w_factor", "dilation_h_factor",)
)

lstm_opts = OptionsSerializer(
    "LSTMOptions", (fused_act, "cell_clip", "proj_clip", "kernel_type", "asymmetric_quantize_inputs")
)

unidir_seq_lstm_opts = OptionsSerializer(
    "UnidirectionalSequenceLSTMOptions",
    (fused_act, "cell_clip", "proj_clip", "time_major", "asymmetric_quantize_inputs",),
)

bidir_seq_lstm_opts = OptionsSerializer(
    "BidirectionalSequenceLSTMOptions",
    (fused_act, "cell_clip", "proj_clip", "merge_outputs", "time_major", "asymmetric_quantize_inputs"),
)

rnn_opts = OptionsSerializer("RNNOptions", (fused_act, "asymmetric_quantize_inputs"))

seq_rnn_opts = OptionsSerializer("SequenceRNNOptions", ("time_major", fused_act, "asymmetric_quantize_inputs",))

bidir_seq_rnn_opts = OptionsSerializer(
    "BidirectionalSequenceRNNOptions", ("time_major", fused_act, "merge_outputs", "asymmetric_quantize_inputs")
)

reducer_opts = OptionsSerializer("ReducerOptions", ("keep_dims",))

is_int_vec = True

builtin_operator_map = {
    BuiltinOperator.ADD: (Op.Add, OptionsSerializer("AddOptions", (fused_act, "pot_scale_int16"))),
    BuiltinOperator.AVERAGE_POOL_2D: (Op.AvgPool, pool2d_opts),
    BuiltinOperator.CONCATENATION: (Op.ConcatTFLite, OptionsSerializer("ConcatenationOptions", ("axis", fused_act))),
    BuiltinOperator.CONV_2D: (Op.Conv2DBias, conv2d_opts),
    BuiltinOperator.DEPTHWISE_CONV_2D: (Op.DepthwiseConv2DBias, depthwise_opts),
    BuiltinOperator.DEPTH_TO_SPACE: (Op.DepthToSpace, OptionsSerializer("DepthToSpaceOptions", ("block_size",))),
    BuiltinOperator.DEQUANTIZE: (Op.Dequantize, OptionsSerializer("DequantizeOptions")),
    BuiltinOperator.EMBEDDING_LOOKUP: (Op.EmbeddingLookup, None),
    BuiltinOperator.FLOOR: (Op.Floor, None),
    BuiltinOperator.FULLY_CONNECTED: (
        Op.FullyConnected,
        OptionsSerializer("FullyConnectedOptions", (fused_act, "weights_format", "asymmetric_quantize_inputs")),
    ),
    BuiltinOperator.HASHTABLE_LOOKUP: (Op.HashtableLookup, None),
    BuiltinOperator.L2_NORMALIZATION: (Op.L2Norm, OptionsSerializer("L2NormOptions", (fused_act,))),
    BuiltinOperator.L2_POOL_2D: (Op.L2Pool2D, pool2d_opts),
    BuiltinOperator.LOCAL_RESPONSE_NORMALIZATION: (
        Op.LRN,
        OptionsSerializer("LocalResponseNormalizationOptions", ("radius", "bias", "alpha", "beta")),
    ),
    BuiltinOperator.LOGISTIC: (Op.Sigmoid, None),
    BuiltinOperator.LSH_PROJECTION: (Op.LSHProjection, OptionsSerializer("LSHProjectionOptions", ("type",))),
    BuiltinOperator.LSTM: (Op.Lstm, lstm_opts),
    BuiltinOperator.MAX_POOL_2D: (Op.MaxPool, pool2d_opts),
    BuiltinOperator.MUL: (Op.Mul, OptionsSerializer("MulOptions", (fused_act,))),
    BuiltinOperator.RELU: (Op.Relu, None),
    BuiltinOperator.RELU_N1_TO_1: (Op.ReluN1To1, None),
    BuiltinOperator.RELU6: (Op.Relu6, None),
    BuiltinOperator.RESHAPE: (Op.Reshape, OptionsSerializer("ReshapeOptions", (("new_shape", is_int_vec),))),
    BuiltinOperator.RESIZE_BILINEAR: (
        Op.ResizeBilinear,
        OptionsSerializer("ResizeBilinearOptions", ("align_corners", "half_pixel_centers")),
    ),
    BuiltinOperator.RNN: (Op.Rnn, rnn_opts),
    BuiltinOperator.SOFTMAX: (Op.Softmax, OptionsSerializer("SoftmaxOptions", ("beta",))),
    BuiltinOperator.SPACE_TO_DEPTH: (Op.SpaceToDepth, OptionsSerializer("SpaceToDepthOptions", ("block_size",))),
    BuiltinOperator.SVDF: (
        Op.Svdf,
        OptionsSerializer("SVDFOptions", ("rank", fused_act, "asymmetric_quantize_inputs")),
    ),
    BuiltinOperator.TANH: (Op.Tanh, None),
    BuiltinOperator.CONCAT_EMBEDDINGS: (
        Op.ConcatEmbeddings,
        OptionsSerializer(
            "ConcatEmbeddingsOptions",
            (
                "num_channels",
                "num_columns_per_channel",
                "num_columns_per_channel_as_numpy",
                "num_columns_per_channel_as_length",
                "embedding_dim_per_channel",
                "embedding_dim_per_channel_as_numpy",
                "embedding_dim_per_channel_as_length",
            ),
        ),
    ),
    BuiltinOperator.SKIP_GRAM: (
        Op.SkipGram,
        OptionsSerializer("SkipGramOptions", ("ngram_size", "max_skip_size", "include_all_ngrams")),
    ),
    BuiltinOperator.CALL: (Op.Call, OptionsSerializer("CallOptions", ("subgraph",))),
    BuiltinOperator.EMBEDDING_LOOKUP_SPARSE: (
        Op.EmbeddingLookupSparse,
        OptionsSerializer("EmbeddingLookupSparseOptions", ("combiner",)),
    ),
    BuiltinOperator.PAD: (Op.Pad, OptionsSerializer("PadOptions")),
    BuiltinOperator.UNIDIRECTIONAL_SEQUENCE_RNN: (Op.UnidirectionalSequenceRnn, seq_rnn_opts),
    BuiltinOperator.GATHER: (Op.GatherV2, OptionsSerializer("GatherOptions", ("axis",))),
    BuiltinOperator.BATCH_TO_SPACE_ND: (Op.BatchToSpaceND, OptionsSerializer("BatchToSpaceNDOptions")),
    BuiltinOperator.SPACE_TO_BATCH_ND: (Op.SpaceToBatchND, OptionsSerializer("SpaceToBatchNDOptions")),
    BuiltinOperator.TRANSPOSE: (Op.Transpose, OptionsSerializer("TransposeOptions")),
    BuiltinOperator.MEAN: (Op.Mean, None),
    BuiltinOperator.SUB: (Op.Sub, OptionsSerializer("SubOptions", (fused_act, "pot_scale_int16",))),
    BuiltinOperator.DIV: (Op.Div, OptionsSerializer("DivOptions", (fused_act,))),
    BuiltinOperator.SQUEEZE: (Op.Squeeze, OptionsSerializer("SqueezeOptions", (("squeeze_dims", is_int_vec),))),
    BuiltinOperator.UNIDIRECTIONAL_SEQUENCE_LSTM: (Op.UnidirectionalSequenceLstm, unidir_seq_lstm_opts),
    BuiltinOperator.STRIDED_SLICE: (
        Op.StridedSlice,
        OptionsSerializer(
            "StridedSliceOptions", ("begin_mask", "end_mask", "ellipsis_mask", "new_axis_mask", "shrink_axis_mask")
        ),
    ),
    BuiltinOperator.BIDIRECTIONAL_SEQUENCE_RNN: (Op.BidirectionalSequenceRnn, bidir_seq_rnn_opts),
    BuiltinOperator.EXP: (Op.Exp, OptionsSerializer("ExpOptions")),
    BuiltinOperator.TOPK_V2: (Op.TopKV2, OptionsSerializer("TopKV2Options")),
    BuiltinOperator.SPLIT: (Op.Split, OptionsSerializer("SplitOptions", ("num_splits",))),
    BuiltinOperator.LOG_SOFTMAX: (Op.LogSoftmax, OptionsSerializer("LogSoftmaxOptions")),
    BuiltinOperator.DELEGATE: (Op.Delegate, None),
    BuiltinOperator.BIDIRECTIONAL_SEQUENCE_LSTM: (Op.BidirectionalSequenceLstm, bidir_seq_lstm_opts),
    BuiltinOperator.CAST: (
        Op.Cast,
        OptionsSerializer(
            "CastOptions",
            (
                ("in_data_type", datatype_deserialize, datatype_serialize),
                ("out_data_type", datatype_deserialize, datatype_serialize),
            ),
        ),
    ),
    BuiltinOperator.PRELU: (Op.Prelu, None),
    BuiltinOperator.MAXIMUM: (Op.Maximum, OptionsSerializer("MaximumMinimumOptions")),
    BuiltinOperator.ARG_MAX: (
        Op.ArgMax,
        OptionsSerializer("ArgMaxOptions", (("output_type", datatype_deserialize, datatype_serialize),)),
    ),
    BuiltinOperator.MINIMUM: (Op.Minimum, OptionsSerializer("MaximumMinimumOptions")),
    BuiltinOperator.LESS: (Op.Less, OptionsSerializer("LessOptions")),
    BuiltinOperator.NEG: (Op.Neg, OptionsSerializer("NegOptions")),
    BuiltinOperator.PADV2: (Op.PadV2, OptionsSerializer("PadV2Options")),
    BuiltinOperator.GREATER: (Op.Greater, OptionsSerializer("GreaterOptions")),
    BuiltinOperator.GREATER_EQUAL: (Op.GreaterEqual, OptionsSerializer("GreaterEqualOptions")),
    BuiltinOperator.LESS_EQUAL: (Op.LessEqual, OptionsSerializer("LessEqualOptions")),
    BuiltinOperator.SELECT: (Op.Select, OptionsSerializer("SelectOptions")),
    BuiltinOperator.SLICE: (Op.Slice, OptionsSerializer("SliceOptions")),
    BuiltinOperator.SIN: (Op.Sin, None),
    BuiltinOperator.TRANSPOSE_CONV: (
        Op.Conv2DBackpropInput,
        OptionsSerializer("TransposeConvOptions", (padding, "stride_w", "stride_h")),
    ),
    BuiltinOperator.SPARSE_TO_DENSE: (
        Op.SparseToDense,
        OptionsSerializer("SparseToDenseOptions", ("validate_indices",)),
    ),
    BuiltinOperator.TILE: (Op.Tile, OptionsSerializer("TileOptions")),
    BuiltinOperator.EXPAND_DIMS: (Op.ExpandDims, OptionsSerializer("ExpandDimsOptions")),
    BuiltinOperator.EQUAL: (Op.Equal, OptionsSerializer("EqualOptions")),
    BuiltinOperator.NOT_EQUAL: (Op.NotEqual, OptionsSerializer("NotEqualOptions")),
    BuiltinOperator.LOG: (Op.Log, None),
    BuiltinOperator.SUM: (Op.Sum, None),
    BuiltinOperator.SQRT: (Op.Sqrt, None),
    BuiltinOperator.RSQRT: (Op.Rsqrt, None),
    BuiltinOperator.SHAPE: (
        Op.Shape,
        OptionsSerializer("ShapeOptions", (("out_type", datatype_deserialize, datatype_serialize),)),
    ),
    BuiltinOperator.POW: (Op.Pow, OptionsSerializer("PowOptions")),
    BuiltinOperator.ARG_MIN: (
        Op.ArgMin,
        OptionsSerializer("ArgMinOptions", (("output_type", datatype_deserialize, datatype_serialize),)),
    ),
    BuiltinOperator.FAKE_QUANT: (
        Op.FakeQuantWithMinMaxArgs,
        OptionsSerializer("FakeQuantOptions", ("min", "max", "num_bits", "narrow_range")),
    ),
    BuiltinOperator.REDUCE_PROD: (Op.Prod, reducer_opts),
    BuiltinOperator.REDUCE_MAX: (Op.Max, reducer_opts),
    BuiltinOperator.PACK: (Op.Pack, OptionsSerializer("PackOptions", ("values_count", "axis"))),
    BuiltinOperator.LOGICAL_OR: (Op.LogicalOr, OptionsSerializer("LogicalOrOptions")),
    BuiltinOperator.ONE_HOT: (Op.OneHot, OptionsSerializer("OneHotOptions", ("axis",))),
    BuiltinOperator.LOGICAL_AND: (Op.LogicalAnd, OptionsSerializer("LogicalAndOptions")),
    BuiltinOperator.LOGICAL_NOT: (Op.LogicalNot, OptionsSerializer("LogicalNotOptions")),
    BuiltinOperator.UNPACK: (Op.Unpack, OptionsSerializer("UnpackOptions", ("num", "axis"))),
    BuiltinOperator.REDUCE_MIN: (Op.Min, reducer_opts),
    BuiltinOperator.FLOOR_DIV: (Op.FloorDiv, OptionsSerializer("FloorDivOptions")),
    BuiltinOperator.REDUCE_ANY: (Op.Any, reducer_opts),
    BuiltinOperator.SQUARE: (Op.Square, OptionsSerializer("SquareOptions")),
    BuiltinOperator.ZEROS_LIKE: (Op.ZerosLike, OptionsSerializer("ZerosLikeOptions")),
    BuiltinOperator.FILL: (Op.Fill, OptionsSerializer("FillOptions")),
    BuiltinOperator.FLOOR_MOD: (Op.FloorMod, OptionsSerializer("FloorModOptions")),
    BuiltinOperator.RANGE: (Op.Range, OptionsSerializer("RangeOptions")),
    BuiltinOperator.RESIZE_NEAREST_NEIGHBOR: (
        Op.ResizeNearestNeighbor,
        OptionsSerializer("ResizeNearestNeighborOptions", ("align_corners", "half_pixel_centers")),
    ),
    BuiltinOperator.LEAKY_RELU: (Op.LeakyRelu, OptionsSerializer("LeakyReluOptions", ("alpha",))),
    BuiltinOperator.SQUARED_DIFFERENCE: (Op.SquaredDifference, OptionsSerializer("SquaredDifferenceOptions")),
    BuiltinOperator.MIRROR_PAD: (Op.MirrorPad, OptionsSerializer("MirrorPadOptions", ("mode",))),
    BuiltinOperator.ABS: (Op.Abs, OptionsSerializer("AbsOptions")),
    BuiltinOperator.SPLIT_V: (Op.SplitV, OptionsSerializer("SplitVOptions", ("num_splits",))),
    BuiltinOperator.UNIQUE: (
        Op.Unique,
        OptionsSerializer("UniqueOptions", (("idx_out_type", datatype_deserialize, datatype_serialize),)),
    ),
    BuiltinOperator.CEIL: (Op.Ceil, None),
    BuiltinOperator.REVERSE_V2: (Op.ReverseV2, OptionsSerializer("ReverseV2Options")),
    BuiltinOperator.ADD_N: (Op.AddN, OptionsSerializer("AddNOptions")),
    BuiltinOperator.GATHER_ND: (Op.GatherNd, OptionsSerializer("GatherNdOptions")),
    BuiltinOperator.COS: (Op.Cos, OptionsSerializer("CosOptions")),
    BuiltinOperator.WHERE: (Op.Where, OptionsSerializer("WhereOptions")),
    BuiltinOperator.RANK: (Op.Rank, OptionsSerializer("RankOptions")),
    BuiltinOperator.ELU: (Op.Elu, None),
    BuiltinOperator.REVERSE_SEQUENCE: (
        Op.ReverseSequence,
        OptionsSerializer("ReverseSequenceOptions", ("seq_dim", "batch_dim")),
    ),
    BuiltinOperator.MATRIX_DIAG: (Op.MatrixDiag, OptionsSerializer("MatrixDiagOptions")),
    BuiltinOperator.QUANTIZE: (Op.Quantize, OptionsSerializer("QuantizeOptions")),
    BuiltinOperator.MATRIX_SET_DIAG: (Op.MatrixSetDiag, OptionsSerializer("MatrixSetDiagOptions")),
    BuiltinOperator.ROUND: (Op.Round, None),
    BuiltinOperator.HARD_SWISH: (Op.HardSwish, OptionsSerializer("HardSwishOptions")),
    BuiltinOperator.IF: (Op.If, OptionsSerializer("IfOptions", ("then_subgraph_index", "else_subgraph_index"))),
    BuiltinOperator.WHILE: (
        Op.While,
        OptionsSerializer("WhileOptions", ("cond_subgraph_index", "body_subgraph_index")),
    ),
    BuiltinOperator.NON_MAX_SUPPRESSION_V4: (Op.NonMaxSuppressionV4, OptionsSerializer("NonMaxSuppressionV4Options")),
    BuiltinOperator.NON_MAX_SUPPRESSION_V5: (Op.NonMaxSuppressionV5, OptionsSerializer("NonMaxSuppressionV5Options")),
    BuiltinOperator.SCATTER_ND: (Op.ScatterNd, OptionsSerializer("ScatterNdOptions")),
    BuiltinOperator.SELECT_V2: (Op.SelectV2, OptionsSerializer("SelectV2Options")),
    BuiltinOperator.DENSIFY: (Op.Densify, OptionsSerializer("DensifyOptions")),
    BuiltinOperator.SEGMENT_SUM: (Op.SegmentSum, OptionsSerializer("SegmentSumOptions")),
    BuiltinOperator.BATCH_MATMUL: (Op.BatchMatMul, OptionsSerializer("BatchMatMulOptions", ("adj_x", "adj_y"))),
    BuiltinOperator.CUSTOM: (Op.Custom, CustomOptionsSerializer()),
}

builtin_operator_inv_map = {v[0]: (k, v[1]) for k, v in builtin_operator_map.items()}

builtin_operator_inv_map[Op.CustomNpuOp] = (BuiltinOperator.CUSTOM, CustomOptionsSerializer())

BUILTIN_OPERATOR_UNKNOWN = "UNKNOWN"

def builtin_type_name(builtin):
    return next(k for k, v in vars(BuiltinOperator).items() if v == builtin)

def optype_to_builtintype(op_type):
    if op_type in builtin_operator_inv_map:
        return builtin_type_name(builtin_operator_inv_map[op_type][0])
    else:
        return BUILTIN_OPERATOR_UNKNOWN


from PIL import Image, ImageFont, ImageDraw, ImageFilter
from matplotlib import font_manager
import random
import sys

system_fonts = font_manager.findSystemFonts(fontpaths=None, fontext='ttf')
not_viable = ['mathjax', 'noto', 'symbol', 'icon', 'ding', 'emoji', 'emote', 'picture', 'awesome', 'material']
viable_fonts = [font for font in system_fonts if not any(nonviable in font.casefold() for nonviable in not_viable)]
print(f"filtered out {len(system_fonts) - len(viable_fonts)} fonts")

name = sys.argv[1] if len(sys.argv) > 1 else 'LOKI'
grow = True if len(sys.argv) > 2 and sys.argv[2] == '-grow' else False
widthfactor = 150 if grow else 100
width = widthfactor * len(name) + 200

baseframe = Image.new('RGBA', (width, widthfactor + 250), (0,0,0,255))
frames = []
for j in range(25):
    frame = baseframe.copy()
    font_add = j*5 if grow else random.randrange(5, 26)
    pos_add = j if grow else -25
    for i in range(len(name)):
        letter = Image.new('RGBA', baseframe.size, (0,0,0,0))
        fnt = ImageFont.truetype(random.choice(viable_fonts), font_add + 70)
        d = ImageDraw.Draw(letter)
        d.text(((i+1)*widthfactor - pos_add, widthfactor - pos_add), name[i], font=fnt, fill=(255,255,255,random.randrange(128, 256)))
        letter = letter.filter(ImageFilter.BoxBlur(10))
        d = ImageDraw.Draw(letter)
        d.text(((i+1)*widthfactor - pos_add, widthfactor - pos_add), name[i], font=fnt, fill=(255,255,255,random.randrange(225, 256)))
        frame = Image.alpha_composite(frame, letter)
    frames.append(frame)

frames[0].save('out.gif', save_all=True, append_images=frames[1:], duration=500, loop=0)


# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from pdsu.items import UserItem,UsertimetableItem,UserscoreItem
import logging

class PdsuSpider(CrawlSpider):
    name = 'pdsu'
    allowed_domains = ['jiaowu.pdsu.edu.cn']
    start_urls = ['http://jiaowu.pdsu.edu.cn/MAINFRM.aspx']

    def parse(self, response):
        """
        解析用户信息
        :param response: Response对象
        """
        useritem = UserItem()
        useritem['stunum'] = ''.join(response.xpath('/html/body/center[1]/table/tbody/tr[2]/td[2]//text()').extract()).strip()
        useritem['name'] = ''.join(response.xpath('/html/body/center[1]/table/tbody/tr[2]/td[4]//text()').extract()).strip()
        useritem['department'] = ''.join(response.xpath('/html/body/center[1]/table/tbody/tr[24]/td[2]//text()').extract()).strip()
        useritem['major'] = ''.join(response.xpath('/html/body/center[1]/table/tbody/tr[24]/td[4]//text()').extract()).strip()
        useritem['classes'] = ''.join(response.xpath('/html/body/center[1]/table/tbody/tr[24]/td[6]//text()').extract()).strip()
        usertimeitem = UsertimetableItem()
        usertimeitem['timetable'] = ''.join(response.xpath('//*[@id="pageRpt"]/div/div/img/@src').extract()).strip()
        usertimeitem['remark'] = ''.join(response.xpath('//*[@id="pageRpt"]/table/tbody/tr/td[2]//text()').extract()).strip().replace('\u2002', '')
        usertimeitem['time'] = ''.join(response.xpath('//*[@id="tn2"]//text()').extract()).strip()
        userscoreitem = UserscoreItem()
        userscoreitem['department'] = ''.join(response.xpath('//center/table[2]/tbody/tr[1]/td[1]//text()').extract()).strip().replace('院(系)/部：', '')
        userscoreitem['classes'] = ''.join(response.xpath('//center/table[2]/tbody/tr[1]/td[2]//text()').extract()).strip().replace('行政班级：', '')
        userscoreitem['average'] = ''.join(response.xpath('//center/table[2]/tbody/tr[1]/td[3]//text()').extract()).strip().replace('平均学分绩点：', '')
        userscoreitem['stunum'] = ''.join(response.xpath('//center/table[2]/tbody/tr[2]/td[1]//text()').extract()).strip().replace('\u2002', '').replace('学号：', '')
        userscoreitem['name'] = ''.join(response.xpath('//center//table[2]/tbody/tr[2]/td[2]//text()').extract()).strip().replace('\u2002', '').replace('姓名：', '')
        userscoreitem['looktime'] = ''.join(response.xpath('//center/table[2]/tbody/tr[2]/td[3]//text()').extract()).strip().replace('打印时间：', '')
        userscoreitem['time'] = ''.join(response.xpath('//center/table[3]/tbody/tr/td//text()').extract()).strip().replace('学年学期：', '')
        userscoreitem['score'] = ''.join(response.xpath('//center/div/div/img/@src').extract()).strip()
        yield useritem
        yield usertimeitem
        yield userscoreitem


# -*- coding: utf-8 -*-
import sys
sys.path.insert(0, 'offline-model.zip')

import numpy as np
import pandas as pd

from utils.logger import Logger
from utils import download_blob, read_pickle
from src.preprocess.utils import calculate_min_max
from src.options.train_options import TrainLinUCBOptions
from src_v2.factory.planet_news.planet_news_hot import PlanetNewsHotLinUCBFactory
from utils import download_blob, calculate_dynamic_score, save_data_to_gs
from src.model_registry import MlflowHelper

RAW_SCORE_COL = 'raw_score'
NORM_RAW_SCORE_COL = 'norm_raw_score'
DYNAMIC_SCORE_COL = 'dynamic'
FINAL_SCORE_COL = 'final_score'
ARM_COL = 'content_id'
DYNAMIC_WEIGHT = 0.01

def postprocess(factory: PlanetNewsHotLinUCBFactory, pop_score: np.array=None) -> pd.DataFrame:
    # dynamic
    dynamic_score = calculate_dynamic_score(len(factory.model_handler.arms), weight=DYNAMIC_WEIGHT)
    id2pop = list(zip(list(factory.model_handler.model.index2arm.values()), pop_score))
    df_id2pop = pd.DataFrame(id2pop, columns=[ARM_COL, RAW_SCORE_COL])
    # normalize
    min_score = df_id2pop[RAW_SCORE_COL].min()
    max_score = df_id2pop[RAW_SCORE_COL].max()
    df_id2pop[NORM_RAW_SCORE_COL] = df_id2pop[RAW_SCORE_COL].apply(lambda x: calculate_min_max(x, max_score, min_score))
    df_id2pop[DYNAMIC_SCORE_COL] = dynamic_score
    df_id2pop[FINAL_SCORE_COL] = df_id2pop[NORM_RAW_SCORE_COL] + df_id2pop[DYNAMIC_SCORE_COL]
    # trim
    df_id2pop[FINAL_SCORE_COL] = df_id2pop[FINAL_SCORE_COL].apply(lambda x: 1 if x > 1 else x)
    df_id2pop.sort_values(by=[FINAL_SCORE_COL], ascending=False, inplace=True)
    return df_id2pop

if __name__ == '__main__':
    # eval parameter
    popu_date = '20230310'
    popu_hour = '04'
    gt_date = '20230310'
    gt_hour = '05'
    hot_start_date = '20230307'
    popularity_bucket_name = 'pipeline-bf-data-prod-001'

    # option
    opt = TrainLinUCBOptions().parse()

    # logging
    logger = Logger(logger_name=opt.logger_name, dev_mode=True)

    # build mlflow helper
    opt.mlflow_host = 'http://10.32.192.39:5000' # it will be dropped
    opt.mlflow_experiment_run_name = popu_date + popu_hour
    opt.mlflow_experiment_id = '26'
    mlflow_helper = MlflowHelper(opt, logger_name='Planet News Hot Items', logger=logger)
    mlflow_helper.connection()

    # basic option
    opt.experiment_name = 'test' # it will be dropped
    base_path = f'{opt.checkpoints_dir}/{opt.experiment_name}'
    bucket_storage = f'machine-learning-models-{opt.project_id}'
    output_bucket_storage = f'pipeline-{opt.project_id}'
    run_date, run_hour = opt.run_date[:-2], opt.run_date[-2:]
    output_blob_latest = opt.output_blob.replace('RUN_DATE/RUN_HOUR', 'latest')
    output_blob_run_time = opt.output_blob.replace('RUN_DATE', run_date).replace('RUN_HOUR', run_hour)
    logger.info(f'[Model Training][Planet News Hot Item] base_path: {base_path}, experiment_name: {opt.experiment_name}')

    # add prameter to mlflow
    logger.info('[Model Training][Planet News Hot Item][MLFlow] Logging pipeline option')
    mlflow_helper.log_data(data=vars(opt), log_type='params')

    # initialize factory and training parameters
    planet_news_hot_linucb_factory = PlanetNewsHotLinUCBFactory(mode='train', use_cuda=True, **vars(opt))

    # download and read dataset
    if opt.download_dataset:
        file_to_download = [opt.dataset, planet_news_hot_linucb_factory.config.COL2CATS_NAMES]
        # download train data
        for file in file_to_download:
            logger.info(f'[Model Training][Planet News Hot Item] Download {file} from the bucket')
            download_blob(bucket_name=bucket_storage,
                          source_blob_name=f'{opt.dataset_blob_path}/{base_path}/{file}',
                          destination_file_name=f'{opt.dataroot}/{file}')

        # download popularity (it will be removed ??)
        logger.info(f'[Model Training][Planet News Hot Item] Download popularity_news.csv from the bucket')
        download_blob(bucket_name=popularity_bucket_name,
                      source_blob_name=f'metrics/popularity/news/{popu_date}/{popu_hour}/popularity_news.csv',
                      destination_file_name=f'{opt.dataroot}/popularity_news.csv')

        # download user_event (ground truth) (it will be removed ??)
        download_blob(bucket_name=bucket_storage,
                      source_blob_name=f'dataset/planet_news/hot/{gt_date}{gt_hour}/checkpoints/test/user_event.pickle',
                      destination_file_name=f'{opt.dataroot}/user_event_t.pickle')

    # load dataset, all_cats, user_event (grund truth) and popularity
    dataset = read_pickle(file_name='dataset.pickle', base_path=opt.dataroot)
    all_cats = read_pickle(file_name=planet_news_hot_linucb_factory.config.COL2CATS_NAMES, base_path=opt.dataroot)
    user_event = read_pickle(file_name='user_event_t.pickle', base_path=opt.dataroot)
    popularity_news = pd.read_csv(opt.dataroot+'/popularity_news.csv')

    # add dataset information to mlflow
    logger.info('[Model Training][Planet News Hot Item][MLFlow] Logging dataset information')
    mlflow_helper.log_data(data={'Dataset Size': dataset.shape[0]}, log_type='metrics')

    # TEST DATA
    dataset = dataset[dataset['date']>=hot_start_date]
    user_event = user_event[(user_event['date']==gt_date)&(user_event['hour']==str(int(gt_hour)))]

    # train
    planet_news_hot_linucb_factory.train(dataset, **vars(opt))

    # inference
    pop_score = planet_news_hot_linucb_factory.predict()

    # postprocess
    df_result = postprocess(factory=planet_news_hot_linucb_factory, pop_score=pop_score)

    df_result_ = df_result[['content_id', 'final_score']]
    print('df_result_ --------->')
    print(df_result_.head(15))

    # evaluation
    evaluation(hot_dat=df_result, popu_dat=popularity_news, gt_dat=user_event)

    # popularity_news
    popularity_news = popularity_news.sort_values(by=['final_score'], ascending=False)[['uuid', 'final_score']]
    print('popularity_news --------->')
    print(popularity_news.head(15))

    # dump
    if len(output_blob_run_time) > 0:
        logger.info(f'[Model Training][Planet News Hot Item] dump predict results to {output_blob_run_time}')
        save_data_to_gs(df_result, output_bucket_storage, output_blob_run_time)
    if len(output_blob_latest) > 0:
        logger.info(f'[Model Training][Planet News Hot Item] dump predict results  to {output_blob_latest}')
        save_data_to_gs(df_result, output_bucket_storage, output_blob_latest)


from typing import List, Tuple

path = "M0 0 c-223 -18 -380 -153 -620 -535 -184 -293 -347 -364 -535 -235 -53 36 -82 65 -137 137 -48 63 -83 78 -130 55 -48 -25 -55 -56 -34 -149 57 -242 195 -455 371 -572 67 -44 133 -79 165 -87 8 -2 33 -10 55 -18 131 -47 372 -51 575 -11 260 53 421 132 590 291 l55 52 72 -68 c137 -129 269 -202 443 -246 148 -37 166 -40 310 -53 421 -37 745 141 914 503 47 100 90 258 82 299 -9 47 -33 67 -78 67 -30 0 -45 -6 -64 -27 -160 -182 -238 -236 -340 -234 -119 1 -240 92 -338 255 -193 318 -361 498 -518 553 -103 36 -326 33 -428 -6 -54 -21 -64 -21 -95 -4 -50 27 -194 42 -315 33"

def parse_position(x: str, y: str) -> complex:
    return int(x) + int(y) * 1j

def line_bezier(start: complex, end: complex) -> List[complex]:
    ctrl_pnt_rel_pos = (end - start) / 3  # control point relative position
    return [
        start,
        start + ctrl_pnt_rel_pos,
        end - ctrl_pnt_rel_pos,
        end,
    ]

data_points = path.split(" ")  # separating numbers

current_position = parse_position(data_points[0][1:], data_points[1])

current_command = ""  # svg path command

beziers: List[
    List[complex]
] = []  # a list of all the beziers (a bezier is a list of points)

# using iterator to continue multiple times
data_points_iter = iter(enumerate(data_points))

for index, data_point in data_points_iter:
    # checking for a new command
    if not (data_point[0].isdigit() or data_point[0] == "-"):
        current_command = data_point[0]
        data_point = data_point[1:]

    # translation - moving current position
    if current_command == "M":
        current_position = parse_position(data_point, data_points[index + 1])
        next(data_points_iter)
    elif current_command == "m":
        current_position = parse_position(data_point, data_points[index + 1])
        next(data_points_iter)

    # bezier curves
    elif current_command == "c":
        bezier_points: List[complex] = [
            current_position,
            current_position + parse_position(data_point, data_points[index + 1]),
        ]  # points for the current bezier

        for relative_index in [2, 4]:
            # calculating control points
            bezier_points.append(
                current_position
                + parse_position(
                    data_points[index + relative_index],
                    data_points[index + relative_index + 1],
                )
            )

        beziers.append(bezier_points)

        current_position = bezier_points[-1]

        for i in range(5):
            next(data_points_iter)  # continuing to the next data point

    elif current_command == "l":
        bezier_end_point = current_position + parse_position(
            data_point, data_points[index + 1]
        )
        beziers.append(line_bezier(current_position, bezier_end_point))
        current_position = bezier_end_point

        next(data_points_iter)

# printing a c array of the beziers
print("{")
for bezier in beziers:
    print(" Bezier(new Vector[4]{")
    for index, point in enumerate(bezier):
        comma = ", " if index != 3 else ""
        print(f"Vector({point.real}, {point.imag}){comma}", end="")
    print("}),", end="")
    print()

print("};")


# check access and log actions?

import time, serial
from random import random
from catalog.models import Door, DoorRequest, Input
from accounts.models import User

# serial port
ser = serial.Serial('/dev/tty.usbmodem14203')

starttime=time.time()
while True:

    inputs = ser.readline()
    input_bool = inputs.rstrip(b'\r\n').split(b';')[1].decode('utf8')
    input_user_public_key=inputs.rstrip(b'\r\n').split(b';')[0].decode('utf8')

#    if input_bool == 'true':
#        print("User verfied")
#    if input_bool == 'false':
#        print("Access denied")
#    print(input_user_public_key)
    input_user = None
    print('got public key:', input_user_public_key)
    try:
        user_tag = User.objects.get(user_public_key=input_user_public_key) # take door_public_key
        print('found user:', user_tag.username)

    except:
        print('User Not Found')
        print('Rejected')

    # if input_user.user_public_key == input_user_public_key:
    if user_tag:
        access = user_tag.doors.all()
        door_pubs = [door.door_public_key for door in access]

        door = Door.objects.get(door_name='EWS Computer Lab')
        door_pub = door.door_public_key

        if door_pub in door_pubs:
            print('Verified')
        else:
            print('Rejected')
    # input_access = DoorRequest.objects.get(door = input_door, user = 'user')

    # unlock = input_access.status
    # print(input_access.status)

#    if input_bool == 'True' and unlock == 'approved':
#        print("You got in!")
#    else:
#        print("Nay")
    time.sleep(1)


from copy import deepcopy

from django.test import SimpleTestCase
from pydantic import ValidationError
from couriers.validators import (CourierDataModel,
                                 CouriersListDataModel,
                                 InvalidCouriersInDataError,
                                 InvalidCourierData,
                                 CourierPatchDataModel)

class TestCourierDataModel(SimpleTestCase):

    def testValidData(self):
        valid_courier = {
            "courier_id": 1,
            "courier_type": "foot",
            "regions": [1, 12, 22],
            "working_hours": ["11:35-14:05", "09:00-11:00"]
        }
        try:
            CourierDataModel(**valid_courier)
        except:
            self.fail("exception in courier data model creation")

    def testExcessField(self):
        excess_field = {
            "courier_id": 1,
            "courier_type": "foot",
            "regions": [1, 12, 22],
            "working_hours": ["11:35-14:05", "09:00-11:00"],
            "favorite_movies": ["Scott Pilgrim vs the World"]
        }
        with self.assertRaises(ValidationError) as context:
            CourierDataModel(**excess_field)
        self.assertIn(
            "excess=excess fields: favorite_movies",
            context.exception.__str__()
        )

    def testInvalidWorkingHours(self):
        """
        Tests working hours validation
        """
        invalid_courier = {
            "courier_id": 1,
            "courier_type": "foot",
            "regions": [1, 12, 22],
            "working_hours": ["11:35-14:05", "09:00-11:65"]
        }
        with self.assertRaises(ValidationError) as context:
            CourierDataModel(**invalid_courier)
        self.assertIn("interval=wrong interval format",
                      context.exception.__str__())

    def testInvalidCourierType(self):
        """
        Tests courier_type validation
        """
        invalid_courier = {
            "courier_id": 1,
            "courier_type": "spaceship",
            "regions": [1, 12, 22],
            "working_hours": ["11:35-14:05", "09:00-11:54"]
        }
        with self.assertRaises(ValidationError) as context:
            CourierDataModel(**invalid_courier)
        self.assertIn("courier_type=must be car, foot or bike",
                      context.exception.__str__())

    def testInvalidCourierId(self):
        """
        Tests courier_id validation
        """
        invalid_courier = {
            "courier_id": 1.2,
            "courier_type": "foot",
            "regions": [1, 12, 22],
            "working_hours": ["11:35-14:05", "09:00-11:54"]
        }
        with self.assertRaises(ValidationError) as context:
            CourierDataModel(**invalid_courier)
        self.assertIn("courier_id=courier_id must be integer",
                      context.exception.__str__())

    def testInvalidRegionNumber(self):
        """
        Tests validation error if regions field contains
        non-integer values
        """
        invalid_courier = {
            "courier_id": 1,
            "courier_type": "foot",
            "regions": [1, 12.3, 22],
            "working_hours": ["11:35-14:05", "09:00-11:54"]
        }
        with self.assertRaises(ValidationError) as context:
            CourierDataModel(**invalid_courier)
        self.assertIn("regions=region must be integer",
                      context.exception.__str__())

class CouriersListDataModelTest(SimpleTestCase):
    TEST_DATA = {
        "data": [
            {
                "courier_id": 1,
                "courier_type": "foot",
                "regions": [1, 12, 22],
                "working_hours": ["11:35-14:05", "09:00-11:00"]
            },
            {
                "courier_id": 2,
                "courier_type": "bike",
                "regions": [22],
                "working_hours": ["09:00-18:00"]},
            {
                "courier_id": 3,
                "courier_type": "car",
                "regions": [12, 22, 23, 33],
                "working_hours": []
            },
        ]
    }

    def testValidData(self):
        """
        Tests model works correctly with valid data
        """
        try:
            CouriersListDataModel(**self.TEST_DATA)
        except ValidationError:
            self.fail("exception in couriers list data model creation")

    def testExcessField(self):
        """
        Tests no extra fields allowed
        """
        extra_fields_data = {
            **self.TEST_DATA,
            "pirates": ["Black Beard", "Captain Jack Sparrow"]
        }
        with self.assertRaises(ValidationError) as context:
            CouriersListDataModel(**extra_fields_data)
        self.assertIn(
            "excess",
            context.exception.__str__()
        )

    def testNoDataField(self):
        invalid_data = {
            "stuff": "some stuff"
        }
        with self.assertRaises(ValidationError):
            CouriersListDataModel(**invalid_data)

    def testInvalidCourier(self):
        data_with_invalid_user = deepcopy(self.TEST_DATA)
        data_with_invalid_user["data"][0]["courier_type"] = "teleport"
        data_with_invalid_user["data"][1]["courier_id"] = 1.2
        data_with_invalid_user["data"][2]["regions"] = [1.3, 3, 4]
        with self.assertRaises(InvalidCouriersInDataError) as context:
            CouriersListDataModel(**data_with_invalid_user)
        invalid_ids = [error.get("id") for error in context.exception.invalid_couriers]
        self.assertIn(1, invalid_ids)
        self.assertIn(1.2, invalid_ids)
        self.assertIn(3, invalid_ids)

class CourierPatchDataModelTest(SimpleTestCase):

    def testValidData(self):
        data = {
            "courier_type": "car",
            "regions": [1, 2, 3],
            "working_hours": ["12:45-14:30", "20:00-22:15"]
        }
        patch_data = CourierPatchDataModel(**data)
        self.assertEqual(patch_data.courier_type, "car")
        data = {
            "courier_type": "car",
            "working_hours": ["12:45-14:30", "20:00-22:15"]
        }
        patch_data = CourierPatchDataModel(**data)
        self.assertEqual(patch_data.regions, None)


import pygame
from sys import exit
from edges import Edges
from snake import Snake
from food import Food

pygame.init()

config = {
    "screen_width": 800,
    "screen_height": 600,
}

clock = pygame.time.Clock()
screen = pygame.display.set_mode(
    (config["screen_width"], config["screen_height"]))
pygame.display.set_caption("Snakes")

background = pygame.Rect(
    10, 40, config["screen_width"]-20, config["screen_height"]-50)

# Font
text_font = pygame.font.Font(None, 50)
start_game_text_surf = text_font.render("Press Space To Start", False, "Red")
start_game_text_rect = start_game_text_surf.get_rect(
    center=(config["screen_width"]/2, (config["screen_height"]/2)-25))

end_game_text_surf = text_font.render(
    "Game Over!! Press Space to Start Again", False, "Red")
end_game_text_rect = end_game_text_surf.get_rect(
    center=(config["screen_width"]/2, (config["screen_height"]/2)-25))

title_text_surf = text_font.render(
    "Snakes                                                      Score:", False, "Blue")
title_text_rect = title_text_surf.get_rect(topleft=(10, 5))

score = 0

# Edges
GREEN = (255, 30, 70)
BLACK = (0, 0, 0)

edges = Edges(config)
snake = Snake(config)
food = Food(config)

LEFT = pygame.K_LEFT
RIGHT = pygame.K_RIGHT
UP = pygame.K_UP
DOWN = pygame.K_DOWN
SPACE = pygame.K_SPACE

curr_direction = "right"

game_end = False

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    pygame.draw.rect(screen, BLACK, background)
    pygame.draw.rect(screen, GREEN, edges.edge_left)
    pygame.draw.rect(screen, GREEN, edges.edge_rigth)
    pygame.draw.rect(screen, GREEN, edges.edge_top)
    pygame.draw.rect(screen, GREEN, edges.edge_bottom)

    screen.blit(title_text_surf, title_text_rect)

    key = pygame.key.get_pressed()
    if key[LEFT]:
        (curr_direction, status) = snake.move("left", curr_direction)
    elif key[RIGHT]:
        (curr_direction, status) = snake.move("right", curr_direction)
    elif key[UP]:
        (curr_direction, status) = snake.move("up", curr_direction)
    elif key[DOWN]:
        (curr_direction, status) = snake.move("down", curr_direction)
    else:
        (curr_direction, status) = snake.move(curr_direction, curr_direction)
    if snake.did_hit_self():
        status = "end"
    if status == "end":
        curr_direction = "right"
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    exit()
            key = pygame.key.get_pressed()
            if key[SPACE]:
                snake = Snake(config)
                score = 0
                break
            pygame.draw.rect(screen, BLACK, background)
            pygame.draw.rect(screen, GREEN, edges.edge_left)
            pygame.draw.rect(screen, GREEN, edges.edge_rigth)
            pygame.draw.rect(screen, GREEN, edges.edge_top)
            pygame.draw.rect(screen, GREEN, edges.edge_bottom)

            screen.blit(title_text_surf, title_text_rect)

            score_text = text_font.render(str(score), False, "Blue")
            screen.blit(score_text, (740, 6))

            for i in snake.body:
                screen.blit(i.surf, i.rect)
            screen.blit(end_game_text_surf, end_game_text_rect)
            pygame.display.update()
            clock.tick(10)

    if snake.did_eat(food):
        score += 1
        food.create_food(snake)
        snake.grow()

    for i in snake.body:
        screen.blit(i.surf, i.rect)
    screen.blit(food.surf, food.rect)

    score_text = text_font.render(str(score), False, "Blue")
    screen.blit(score_text, (740, 6))

    pygame.display.update()
    clock.tick(10)


from __future__ import unicode_literals

from flask import session
from jinja2.filters import do_filesizeformat

from indico.core import signals
from indico.core.logger import Logger
from indico.modules.events.features.base import EventFeature
from indico.modules.events.logs import EventLogKind, EventLogRealm
from indico.modules.events.models.events import EventType
from indico.modules.events.settings import EventSettingsProxy, ThemeSettingsProxy
from indico.util.i18n import _
from indico.web.flask.util import url_for
from indico.web.menu import SideMenuItem

logger = Logger.get('events.layout')
layout_settings = EventSettingsProxy('layout', {
    'is_searchable': True,
    'show_nav_bar': True,
    'show_social_badges': True,
    'show_banner': False,
    'header_text_color': '',
    'header_background_color': '',
    'announcement': None,
    'show_announcement': False,
    'use_custom_css': False,
    'theme': None,
    'timetable_theme': None,
    'timetable_theme_settings': {},
    'use_custom_menu': False,
    'timetable_by_room': False,
    'timetable_detailed': False,
})

theme_settings = ThemeSettingsProxy()

@signals.event.created.connect
def _event_created(event, **kwargs):
    defaults = event.category.default_event_themes
    if not layout_settings.get(event, 'timetable_theme') and event.type_.name in defaults:
        layout_settings.set(event, 'timetable_theme', defaults[event.type_.name])

@signals.event.type_changed.connect
def _event_type_changed(event, **kwargs):
    theme = event.category.default_event_themes.get(event.type_.name)
    if theme is None:
        layout_settings.delete(event, 'timetable_theme')
    else:
        layout_settings.set(event, 'timetable_theme', theme)

@signals.menu.items.connect_via('event-management-sidemenu')
def _extend_event_management_menu_layout(sender, event, **kwargs):
    if not event.can_manage(session.user):
        return
    yield SideMenuItem('layout', _('Layout'), url_for('event_layout.index', event), section='customization')
    if event.type_ == EventType.conference:
        yield SideMenuItem('menu', _('Menu'), url_for('event_layout.menu', event), section='customization')
    if event.has_feature('images'):
        yield SideMenuItem('images', _('Images'), url_for('event_layout.images', event), section='customization')

@signals.event.cloned.connect
def _event_cloned(old_event, new_event, **kwargs):
    if old_event.type_ == EventType.conference:
        return
    # for meetings/lecture we want to keep the default timetable style in all cases
    theme = layout_settings.get(old_event, 'timetable_theme')
    if theme is not None:
        layout_settings.set(new_event, 'timetable_theme', theme)

@signals.event_management.get_cloners.connect
def _get_cloners(sender, **kwargs):
    from indico.modules.events.layout.clone import ImageCloner, LayoutCloner
    yield ImageCloner
    yield LayoutCloner

@signals.event.get_feature_definitions.connect
def _get_feature_definitions(sender, **kwargs):
    return ImagesFeature

@signals.event_management.image_created.connect
def _log_image_created(image, user, **kwargs):
    image.event.log(EventLogRealm.management, EventLogKind.positive, 'Layout',
                    'Added image "{}"'.format(image.filename), user, data={
                        'File name': image.filename,
                        'File type': image.content_type,
                        'File size': do_filesizeformat(image.size)
                    })

@signals.event_management.image_deleted.connect
def _log_image_deleted(image, user, **kwargs):
    image.event.log(EventLogRealm.management, EventLogKind.negative, 'Layout',
                    'Deleted image "{}"'.format(image.filename), user, data={
                        'File name': image.filename
                    })

class ImagesFeature(EventFeature):
    name = 'images'
    friendly_name = _('Image manager')
    description = _('Allows event managers to attach images to the event, which can then be used from HTML code. '
                    'Very useful for e.g. sponsor logos and conference custom pages.')

    @classmethod
    def is_default_for_event(cls, event):
        return event.type_ == EventType.conference


"""
Bayesian fitting of Polynomial model

%%file requirements.txt
numpy
scipy
matplotlib
emcee
arviz
"""
__author__ = "Morgan Fouesneau"
__copyright__ = "Copyright (c) 2022,  Max Planck Institute for Astronomy"
__credits__ = ["Morgan Fouesneau", "Coryn Bailer-Jones", "Ivelina Momcheva"]
__license__ = "BSD 3-Clause"
__version__ = "1.0.0"
__maintainer__ = "Morgan Fouesneau"
__email__ = "fouesneau@mpia.de"
__status__ = "Production"

import numpy as np
from numpy.polynomial.polynomial import polyvander
from scipy.stats import norm
from typing import Union

def polynomial_model(
    deg: int,
    coeffs: np.array,
    x: np.array
    ):
    """
    Generate a polynomial model y = sum(a[k] * x ** k, k=[0..deg])

    :param deg: degree of the polynomial
    :param coeffs: coefficients of the polynomials
    :param x: evaluation points or the polynomial expanded version.
    :returns: polynomial model evaluated at x
    """
    if len(coeffs) != (deg + 1):
        raise AttributeError(f"The coefficient vector is not of length 'deg':{deg + 1} vs. {coeffs.shape}")
    if np.ndim(x) == 1:
        X = polyvander(x, deg)  # [1, x, x**2, ..., x ** deg]
        return X @ np.array(coeffs)
    return x @ np.array(coeffs)

def lnprior(
    deg: int,
    coeffs: np.array,
    l1: float = 0.,
    l2: float = 0.) -> float:
    """ln Prior on the polynomial parameters: ln p(coeffs)

    Generate a polynomial model y = sum(a[k] * x ** k, k=[0..deg])

    :param deg: degree of the polynomial
    :param coeffs: coefficients of the polynomials
    :param l1: l1 norm contribution
    :param l2: l2 norm contribution
    :return: ln-prior value
    """
    if (l1 == 0) and (l2 == 0):
        return 0.
    return np.log(np.sum(l1 * np.abs(coeffs) + 0.5 * l2 * coeffs ** 2))

def lnlikelihood(
    coeffs: np.array,
    x: np.array,
    y: np.array,
    sy: np.array,
    deg: int):
    """ ln Likelihood:  ln p(y | x, sy, coeffs)

    :param coeffs: coefficients of the polynomials
    :param x: evaluation points
    :param y: observed values
    :param sy: observed value uncertainties
    :param deg: degree of the polynomial
    :return: ln-likelihood
    """
    ypred = polynomial_model(deg, coeffs, x)
    return  np.sum(norm.logpdf(y, loc=ypred, scale=sy))

def lnposterior(
    coeffs: np.array,
    x: np.array,
    y: np.array,
    sy: np.array,
    deg: int):
    """ ln posterior:   ln p(y | x, sy, coeffs) + ln p(coeffs)

    :param coeffs: coefficients of the polynomials
    :param x: evaluation points
    :param y: observed values
    :param sy: observed value uncertainties
    :param deg: degree of the polynomial
    :return: ln-likelihood
    """
    return lnprior(deg, coeffs) + lnlikelihood(coeffs, x, y, sy, deg)

# mock data
np.random.seed(123)
N = 10
x = np.sort(np.random.uniform(-5, 5, N))
ctrue = np.array([0, 1, -2, 0.5])
deg = len(ctrue) - 1
sy = 5 * np.random.rand(N)
ytrue = polynomial_model(deg, ctrue, x)
y = ytrue + np.random.normal(0, sy)

# plot the mock data
xplot = np.linspace(-5, 5, 1000)
yplot = polynomial_model(deg, ctrue, xplot)
plt.plot(xplot, yplot, color='0.5', label='ytrue')
plt.errorbar(x, y, yerr=sy, linestyle='None', marker='o', mfc='w', label='yobs')
plt.ylim(y.min() - 5, y.max() + 5)
plt.legend(loc='best', frameon=False)
plt.xlabel('x')
plt.ylabel('y');

# Proceed to mcmc fitting
import emcee

ndim, nwalkers = deg + 1, 10
p0 = np.random.randn(nwalkers, ndim)

X = polyvander(x, deg)  # precompute
sampler = emcee.EnsembleSampler(nwalkers, ndim, lnposterior, args=[X, y, sy, deg])

# We could run sampler.run_mcmc(p0, 2000) but sometimes it could be slow,
# and it is nice to monitor what happens

# Let's run the burn-in part
for state in sampler.sample(p0, iterations=1_000, progress=True):
    pass
sampler.reset()  # tells the sampler to forget the chains

# Restart from the current state of the chains
for _ in sampler.sample(state, iterations=1_000, progress=True):
    pass

# Explore the outputs
import arviz as az

names = ["1", "x"] + [rf"$x^{k}$" for k in range(2, deg+1)]
data = az.from_emcee(sampler, var_names=names, )

axes = az.plot_pair(
    data,
    # var_names=names,
    kind="kde",
    marginals=True,
    point_estimate="median",
    kde_kwargs={
        # "hdi_probs": [0.682, 0.954, 0.997],  # Plot HDI contours
        "hdi_probs": [0.682, 0.954, 0.997],  # Plot HDI contours
        "contourf_kwargs": {"cmap": "Blues"},
    },
    figsize=(8, 6)
)

# add true values for comparison
for dim in range(len(ctrue)):
    val = ctrue[dim]
    for ax in axes[:, dim]:
        lim = ax.get_ylim()
        ax.vlines([val], *lim, color='r')
        ax.set_ylim(lim)

for dim in range(1, len(ctrue)):
    val = ctrue[dim]
    for ax in axes[dim, :dim]:
        lim = ax.get_xlim()
        ax.hlines([val], *lim, color='r')
        ax.set_xlim(lim)

plt.subplots_adjust(wspace=0.05, hspace=0.05)

plt.figure()
# plot the ppc
xplot = np.linspace(-5, 5, 1000)
yplot = polynomial_model(deg, ctrue, xplot)

params = sampler.flatchain[-1000:]
Xpred = polyvander(xplot, deg)
ypred = np.array([polynomial_model(deg, pos, Xpred) for pos in params])

plt.plot(xplot, ypred.T, rasterized=True, color='k', alpha=0.2, lw=0.1)
plt.plot(xplot, yplot, color='w', lw=5)
plt.plot(xplot, yplot, color='C0', lw=3, label='ytrue')

plt.errorbar(x, y, yerr=sy, linestyle='None', marker='o', mfc='w', label='yobs')
plt.ylim(y.min() - 5, y.max() + 5)
plt.legend(loc='best', frameon=False)
plt.xlabel('x')
plt.ylabel('y');


import json

def dict_to_json(sample, name):
    contents = json.dumps(sample)
    with open(name, "w") as f:
        f.write(contents)

def unpack_json(filename):
    with open(filename, "r") as f:
        contents = f.read()
    my_list = json.loads(contents)
    return my_list

def database_initialize(some_list):
    contents = json.dumps(some_list)
    with open("booking.json", "w", ) as f:
        f.write(contents)
    with open("request.json", "w", ) as f:
        f.write(contents)

def update_json(this_data, json_file):
    with open(json_file, "r", ) as f:
        contents = f.read()
    new_list = json.loads(contents)
    new_list.append([this_data])
    contents = json.dumps(new_list, ensure_ascii=False)
    with open(json_file, "w", ) as f:
        f.write(contents)


import math
from collections import Counter
from itertools import product

def occurrences(string, sub):
    count = start = 0
    while True:
        start = string.find(sub, start) + 1
        if start > 0:
            count+=1
        else:
            return count

def solve():
    a=input()
    K=int(a.split()[0])
    L=int(a.split()[1])
    S=int(a.split()[2])
    charK=input()
    target = input()

    countP=Counter()
    for i in product(charK,repeat=S):
        prod="".join(i)
        countP[prod]+=1

    total=0

    max=0
    for i in countP:
        num = occurrences(i,target)
        total += num*countP[i]
        if num > max:
            max=num

    return str(max - total/(K**S))

T=int(input());

for t in range(1,T+1):
    print ("Case #" + str(t) + ": " + solve())


import pandas as pd
from sklearn.preprocessing import LabelEncoder

# Read the data
df = pd.read_csv("/kaggle/input/credit-score-classification-dataset/Credit Score Classification Dataset.csv")

# Simplify education categories
df["Education"] = df["Education"].replace({"High School Diploma": "Undergraduate", "Associate's Degree": "Undergraduate",
                                           "Bachelor's Degree": "Graduate", "Master's Degree": "Postgraduate",
                                           "Doctorate": "Postgraduate"})

# Encode categorical features
label_encoder = LabelEncoder()
categorical_cols = df.select_dtypes(include='object').columns
for col in categorical_cols:
    df[col] = label_encoder.fit_transform(df[col])

# Perform any additional preprocessing steps based on the findings

# Drop unnecessary columns
df.drop(['ID'], axis=1, inplace=True)

# Scale numerical features if necessary

# Split the data into features and target
X = df.drop('Credit Score', axis=1)
y = df['Credit Score']


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

import json
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import os
import shutil
import datetime
import plotly_express as px
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import pandas as pd

def is_json(myjson):
    try:
        json_object = json.loads(myjson)
    except ValueError as e:
        return False
    return True

def read_data(files, path):
    data = []
    for file in files:
        with open(path + file, errors='ignore') as f:
            for line in f.readlines():
                try:
                    if not is_json(line):
                        continue
                    data.append(json.loads(line))
                except:
                    print('bad json: ', line)
    return data

# convert the data into pandas dataframe
def data_processing(data):
    df = pd.DataFrame(data)

    # convert all the keys in the staking into columns, fill nan values
    df = pd.concat([df.drop(['staking'], axis=1), df['staking'].apply(pd.Series)], axis=1)
    df.fillna(0, inplace = True)

    # drop duplicates
    df.drop_duplicates(inplace = True)

    # sort by time
    df.sort_values(by=['timestamp'], inplace = True)
    df.reset_index(drop = True, inplace = True)

    # remove some useless time
    df = df.iloc[1300:]
    df.reset_index(drop = True, inplace = True)

    # convert timestamp to datetime64[ns]
    df["timestamp"] = df["timestamp"].apply(lambda t: t.replace(" +0000 UTC",""))
    df["timestamp"] = pd.to_datetime(df['timestamp'])

    # do calculation for each shard
    shard = []
    for name, s in df.groupby("shard"):
        shard.append(s.reset_index(drop = True))

    # calculate the average time per block, transaction_per_second
    for s in shard:
        # time per block
        s["time_diff"] = (s['timestamp']-s['timestamp'].shift()).fillna(pd.Timedelta(seconds=0))
        s["block_diff"] = (s['block']-s['block'].shift()).fillna(0).astype(int)
        s["time_per_block"] = s.apply(lambda c: c["time_diff"].seconds /c["block_diff"]                                       if c["block_diff"] != 0 else np.nan, axis = 1)

        # plain transaction_per_second
        s["transaction_per_second"] = s.apply(lambda c: c["transactions"]/c["time_diff"].seconds                                               if c["time_diff"].seconds != 0 else np.nan, axis = 1)
        # staking transaction_per_second
        s["staking_transaction_per_second"] = s.apply(lambda c: c["total"]/c["time_diff"].seconds                                               if c["time_diff"].seconds != 0 else np.nan, axis = 1)
        # total transacton per second
        s["total_transaction_per_second"] = s["transaction_per_second"] + s["staking_transaction_per_second"]

        s.rename(columns={"total": "total_staking"}, inplace = True)
        s.drop(['time_diff', 'block_diff'], axis=1, inplace = True)
    return shard

log_path = "../../logs/test_logs/stress_test_02_27/"
fig_folder = "../../graphs/test_logs/stress_test_02_27/"
if os.path.exists(fig_folder):
    shutil.rmtree(fig_folder)
    os.mkdir(fig_folder)

files = os.listdir(log_path)
data = read_data(files, log_path)
shard = data_processing(data)

# get the index of blockchain changes

index = []
for s in shard:
    i = s[s['time_per_block'] < 0].index.tolist()
    i.insert(0,0)
    i.append(len(s))
    index.append(i)

state = "When DOS Enabled in Tx Pool"
df = []
for s in range(len(shard)):
    df.append(shard[s].iloc[index[s][1]+1:index[s][2]])
new = pd.concat(df)

col_options = [dict(label=x, value=x) for x in new.columns]
# dimensions = ["x", "y", "color", "facet_col", "facet_row"]
dimensions = ["x", "y", "color"]

app = dash.Dash(
    __name__, external_stylesheets=["https://codepen.io/chriddyp/pen/bWLwgP.css"]
)

app.layout = html.Div(
    [
        html.H1("Log Analysis and Visualization " + state),
        html.Div(
            [
                html.P([d + ":", dcc.Dropdown(id=d, options=col_options)])
                for d in dimensions
            ],
            style={"width": "25%", "float": "left"},
        ),
        dcc.Graph(id="graph", style={"width": "75%", "display": "inline-block"}),
    ]
)

@app.callback(Output("graph", "figure"), [Input(d, "value") for d in dimensions])
def make_figure(x, y, color):
    return px.line(
        new,
        x=x,
        y=y,
        color=color,
        color_discrete_sequence=["#00AEE9","#FFA07A","#758796"],
        hover_data = new.columns.tolist()
    )

app.run_server(debug=True)


from os import listdir
import json, os
import numpy as np
from torch.utils.data import Dataset
from sklearn.model_selection import train_test_split

# 12: TB > RL > Tigga > P > LD
# 16: TB > RL > P > LD > Tigga
# 24: TB > P > LD > RL > Tigga
# 32: TB > LD > P > RL > Tigga

#TEAM = ['Toad Brigade', 'RL is all you need', 'Love Deluxe', 'Tigga', 'perspective']
#TEAM = ['Toad Brigade', 'RL is all you need']
#TEAM = ['Toad Brigade']
#TEAM = ['RL is all you need']
def to_label(action):
    strs = action.split(' ')
    unit_id = strs[1]
    if strs[0] == 'm':
        label = {'c': None, 'n': 0, 's': 1, 'w': 2, 'e': 3}[strs[2]]
        unit_id = strs[1]
    elif strs[0] == 'bcity':
        label = 4
        unit_id = strs[1]
    else:
        label = None
    return unit_id, label

def depleted_resources(obs):
    for u in obs['updates']:
        if u.split(' ')[0] == 'r':
            return False
    return True

def create_dataset(obses_list, map_size=24):
    obses = {}
    samples = []

    for data in obses_list:

        eps_id = data['EpisodeId']
        #if data['info']['TeamNames'][index] not in TEAM or \

        for i in range(len(data['steps'])-1):
            #if data['steps'][i][index]['status'] == 'ACTIVE':
            if True:
                actions = data['steps'][i+1]['action']
                obs = data['steps'][i]['observation']

                if not actions:
                    continue

                if depleted_resources(obs): # if no resources left, dump rest steps
                    break

                obs['player'] = 0
                obs = dict([
                    (k,v) for k,v in obs.items()
                    if k in ['step', 'updates', 'player', 'width', 'height']
                ])
                obs_id = f'{eps_id}_{i}'
                obses[obs_id] = obs

                for action in actions:
                    unit_id, label = action
                    if label is not None:
                        samples.append((obs_id, unit_id, label))

    return obses, samples

def make_input(obs, unit_id):

    width, height = obs['width'], obs['height']
    #x_shift = (24 - width) // 2
    #y_shift = (24 - height) // 2
    cities = {}

    b = np.zeros((21, width, width), dtype=np.float32)
    pos_x, pos_y = 0, 0
    count_u, count_ct = 0, 0

    for update in obs['updates']:
        strs = update.split(' ')
        input_identifier = strs[0]

        # example: 'u 0 0 u_11 2 26 0 100 0 0'
        # identifier unit_type team unit_id pos_x pos_y cooldown wood coal uranium
        if input_identifier == 'u':
            #count_u += 1
            x = int(strs[4]) #+ x_shift
            y = int(strs[5]) #+ y_shift
            wood = int(strs[7])
            coal = int(strs[8])
            uranium = int(strs[9])

            if unit_id == strs[3]:
                pos_x, pos_y = x, y
                # Position and Cargo
                b[:2, x, y] = (1, (wood + coal + uranium) / 100)
            #else:
                # Units
            team = int(strs[2])
            cooldown = float(strs[6])

            # idx 0:3 own resources
            # idx 3:6 adversary's resources
            #idx = (team - obs['player']) % 2 * 3
            idx = 2 + (team - obs['player']) % 2 * 3
            b[idx:idx + 3, x, y] = (1, cooldown / 6, (wood + coal + uranium) / 100)

        elif input_identifier == 'ct':
            # CityTiles
            #count_ct += 1
            team = int(strs[1])
            city_id = strs[2]
            x = int(strs[3]) #+ x_shift
            y = int(strs[4]) #+ y_shift
            cooldown = float(strs[5])

            if unit_id == strs[3]+strs[4]:
                pos_x, pos_y = x, y
            # idx 6:9 own citytiles
            # idx 9:12 adversary citytiles
            #idx = 6 or 8 (cooldown) + (team - obs['player']) % 2 * 3
            idx = 8 + (team - obs['player']) % 2 * 3
            b[idx:idx + 3, x, y] =  (1, cities[city_id], cooldown / 6)
            #b[idx:idx + 2, x, y] =  (1, cities[city_id])

        elif input_identifier == 'r':
            # Resources
            r_type = strs[1]
            x = int(strs[2]) #+ x_shift
            y = int(strs[3]) #+ y_shift
            amt = int(float(strs[4]))
            #b[{'wood': 12, 'coal': 13, 'uranium': 14}[r_type], x, y] = amt / 800
            b[{'wood': 14, 'coal': 15, 'uranium': 16}[r_type], x, y] = amt / 800

        elif input_identifier == 'rp':
            # Research Points
            team = int(strs[1])
            rp = int(strs[2])
            #b[15 + (team - obs['player']) % 2, :] = min(rp, 200) / 200
            b[17 + (team - obs['player']) % 2, :] = min(rp, 200) / 200

        elif input_identifier == 'c':
            # Cities
            city_id = strs[2]
            fuel = float(strs[3])
            lightupkeep = float(strs[4])
            cities[city_id] = min(fuel / lightupkeep, 10) / 10

        #elif input_identifier == 'ccd':
            # Road
        #    x =
    # #unity, #citytile
    #b[17, :] = count_u / 100
    #b[18, :] = count_ct / 100

    # Day/Night Cycle
    b[19, :] = obs['step'] % 40 / 40
    # Turns
    b[20, :] = obs['step'] / 360

    # Map Size
    #b[19, x_shift:32 - x_shift, y_shift:32 - y_shift] = 1

    #distance_mask = np.zeros((32,32))
    #for i in range(len(distance_mask)):
    #    for j in range(len(distance_mask)):
    #        distance_mask[i, j] = 1 - ((i - pos_y)**2 + (j - pos_x)**2) / 2048
    #map_mask = np.zeros((32,32))
    #map_mask[x_shift:32 - x_shift, y_shift:32 - y_shift] = 1
    #b[22, :] = distance_mask
    #b[21, :] = map_mask

    return b

class LuxDataset(Dataset):
    def __init__(self, states, actions):
        self.states = states
        self.actions = actions

    def __len__(self):
        return len(self.states)

    def __getitem__(self, idx):
        return states[idx], actions[idx]


from collections import defaultdict
from dnutils import logs, ProgressBar
from .fastconj import FastConjunctionGrounding
from mln.util import dict_union
from mln.constants import HARD
from logic.elements import Logic
from utils.multicore import with_tracing, check_mem
import multiprocessing
from multiprocessing import Value

import pdb

import types
from multiprocessing.pool import Pool

# this readonly global is for multiprocessing to exploit copy-on-write
# on linux systems
global_bpll_grounding = None

logger = logs.getlogger(__name__)

# multiprocessing function

def create_formula_groundings(formula, unsatfailure=True):
    check_mem()
    results = []

    if global_bpll_grounding.mrf.mln.logic.is_literal_conj(formula):
        for res in global_bpll_grounding.iter_groundings_fast(formula):
            check_mem()
            results.append(res)
    else:
        for gf in formula.iter_groundings(global_bpll_grounding.mrf, simplify=False):
            check_mem()
            stat = []
            for ground_atom in gf.ground_atoms():
                world = list(global_bpll_grounding.mrf.evidence)
                var = global_bpll_grounding.mrf.variable(ground_atom)
                for val_index, value in var.iter_values():
                    var.setval(value, world)
                    truth = gf(world)
                    if truth != 0:
                        stat.append((var.index, val_index, truth))
                    elif unsatfailure and gf.weight == HARD and gf(global_bpll_grounding.mrf.evidence) != 1:
                        print()
                        gf.print_structure(global_bpll_grounding.mrf.evidence)
            results.append((gf.index, stat))
    return results

class BPLLGroundingFactory(FastConjunctionGrounding):
    """
    Grounding factory for efficient grounding of conjunctions for
    pseudo-likelihood learning.
    """

    def __init__(self, mrf, formulas=None, cache=None, **params):
        FastConjunctionGrounding.__init__(self, mrf, simplify=False, unsatfailure=False, formulas=formulas, cache=cache, **params)
        self._stat = {}
        self._var_index2f_index = defaultdict(set)

    def iter_groundings_fast(self, formula):
        """
        Recursively generate the groundings of a conjunction. Prunes the
        generated grounding tree in case that a formula cannot be rendered
        true by subsequent literals.
        """
        # make a copy of the formula to avoid side effects
        formula = formula.ground(self.mrf, {}, partial=True)
        children = [formula] if not hasattr(formula, 'children') else formula.children
        # make equality constraints access their variable domains
        # this is a _really_ dirty hack but it does the job ;-)
        var_doms = formula.var_doms()

        def eqvar_doms(self, v=None, c=None):
            if v is None:
                v = defaultdict(set)
            for a in self.args:
                if self.mln.logic.isvar(a):
                    v[a] = var_doms[a]
            return v

        for child in children:
            if isinstance(child, Logic.Equality):
                setattr(child, 'var_doms', types.MethodType(eqvar_doms, child))
        lits = sorted(children, key=self._conjsort)
        for gf in self._iter_groundings_fast(formula, lits, 0, assignment={}, variables=[]):
            yield gf

    def _iter_groundings_fast(self, formula, constituents, c_index, assignment, variables, false_var=None, level=0):
        if c_index == len(constituents):
            # no remaining literals to ground. return the ground formula
            # and statistics
            stat = [(var_index, val_index, count) for (var_index, val_index, count) in variables]
            yield formula.index, stat
            return
        c = constituents[c_index]
        # go through all remaining groundings of the current constituent
        for varass in c.iter_var_groundings(self.mrf, partial=assignment):
            gnd = c.ground(self.mrf, dict_union(varass, assignment))
            # check if it violates a hard constraint
            if formula.weight == HARD and gnd(self.mrf.evidence) < 1:
                raise Exception('MLN is unsatisfiable by evidence due to hard constraint violation {} (see above)'.
                                format(global_bpll_grounding.mrf.formulas[formula.index]))
            if isinstance(gnd, Logic.Equality):
                # if an equality grounding is false in a conjunction, we can
                # stop since the  conjunction cannot be rendered true in any
                # grounding that follows
                if gnd.truth(None) == 0:
                    continue
                for gf in self._iter_groundings_fast(formula, constituents, c_index + 1, dict_union(assignment, varass),
                                                     variables, false_var, level + 1):
                    yield gf
            else:
                var = self.mrf.variable(gnd.ground_atom)
                world_ = list(self.mrf.evidence)
                stat = []
                skip = False
                false_var_ = false_var
                vars_ = list(variables)
                for val_index, value in var.iter_values():
                    var.setval(value, world_)
                    truth = gnd(world_)
                    if truth == 0 and value == var.evidence_value():
                        # if the evidence value renders the current
                        # constituent false and there was already a false
                        # literal in the grounding path, we can prune the
                        # tree since no grounding will be true
                        if false_var is not None and false_var != var.index:
                            skip = True
                            break
                        else:
                            # if there was no literal false so far, we collect statistics only for the current literal
                            # and only if all future literals will be true by evidence
                            vars_ = []
                            false_var_ = var.index
                    if truth > 0 and false_var is None:
                        stat.append((var.index, val_index, truth))
                if false_var is not None and false_var == var.index:
                    # in case of non-mutual exclusive values take only the values that render all literals true
                    # example: soft-functional constraint with !foo(?x) ^ foo(?y), x={X,Y,Z} where the evidence
                    # foo(Z) is true, here the grounding !foo(X) ^ foo(Y) is false:
                    # !foo(X) is true for foo(Z) and foo(Y) and
                    # (!foo(Z) ^ !foox(X) ^ !foo(Y)), foo(Y) is true for foo(Y), both are only true for foo(Y)
                    stat = set(variables).intersection(stat)
                    skip = not bool(stat)  # skip if no values remain
                if skip:
                    continue
                for gf in self._iter_groundings_fast(formula, constituents, c_index + 1, dict_union(assignment, varass),
                                                     vars_ + stat, false_var=false_var_, level=level + 1):
                    yield gf

    def _iter_groundings(self, simplify=False, unsatfailure=False):
        global global_bpll_grounding
        global_bpll_grounding = self
        # pdb.set_trace()
        if self.multicore:
            pool = Pool(maxtasksperchild=1)
            i = 0
            try:
                for ground_result in pool.imap(with_tracing(create_formula_groundings), self.formulas):
                    if self.verbose:
                        bar = ProgressBar(color='green')
                        bar.update(float(i + 1) / float(len(self.formulas)))
                        i += 1

                    for f_index, stat in ground_result:
                        for (var_index, val_index, val) in stat:
                            self._var_index2f_index[var_index].add(f_index)
                            self._addstat(f_index, var_index, val_index, val)
                        check_mem()
                    yield None
            except Exception as e:
                logger.error('Error in child process. Terminating pool...')
                pool.close()
                raise e
            finally:
                pool.terminate()
                pool.join()
        else:
            for ground_result in map(create_formula_groundings, self.formulas):
                for f_index, stat in ground_result:
                    for (var_index, val_index, val) in stat:
                        self._var_index2f_index[var_index].add(f_index)
                        self._addstat(f_index, var_index, val_index, val)
                yield None

    def _addstat(self, f_index, var_index, val_index, inc=1):
        if f_index not in self._stat:
            self._stat[f_index] = {}
        d = self._stat[f_index]
        if var_index not in d:
            d[var_index] = [0] * self.mrf.variable(var_index).value_count()
        d[var_index][val_index] += inc


# This challenge has the exact same logic as the 3rd one, this one being an extended version of the last one.
# i.e. We don't know which string will hold the most "English" message when xorred with a particular
#  char from amongst the 256 chars.

import requests
from bs4 import BeautifulSoup

source = requests.get("https://cryptopals.com/static/challenge-data/4.txt").text
soup =  BeautifulSoup(source, 'lxml')
text = soup.find('p').text

with open('file.txt','w') as fileW:
    fileW.write(text)

with open('file.txt', 'r') as fileR:
    val = fileR.readlines()

# The above code takes all the possible strings from the website and stores it into an array named "val."
# The array has 327 hex strings.

def scorer(input):
    frequencies = {
        'a': .08167, 'b': .01492, 'c': .02782, 'd': .04253,
        'e': .12702, 'f': .02228, 'g': .02015, 'h': .06094,
        'i': .06094, 'j': .00153, 'k': .00772, 'l': .04025,
        'm': .02406, 'n': .06749, 'o': .07507, 'p': .01929,
        'q': .00095, 'r': .05987, 's': .06327, 't': .09056,
        'u': .02758, 'v': .00978, 'w': .02360, 'x': .00150,
        'y': .01974, 'z': .00074, ' ': .13000
    }
    return sum([frequencies.get(chr(char),0) for char in input.lower()])

def xorer(input, char):
    output = b''
    for byte in input:
        output += chr(byte ^ char).encode()
    return output

# The same functions as the 3rd challenge which calculates the 'English score' and xorred array of any entered string

big = []
final = []

# Now , we want to create an array (named big) that contains 327 arrays. Each array (is named b and) contains 256 possible
# after-xorring-decrypted-message-data of a particular string.

#(1) Then we want to sort each of the 327 arrays such that the last object of each of them contains the data of the most-
# "English score" having decryted form of that string. This is exactly what we did last time, but now we have 327 such strings.

#(2) All such objects which have the largest score wrt a string are pushed into an array (named final), which now contains 327 objects.
# Again, we sort all of these objects based on their "English score" and the one with the largest score is the last object.

for hexstring in val :
    string = bytes.fromhex(hexstring)
    b = []
    big.append(b)
    for iterator in range(256):
        message = xorer(string, iterator)
        score = scorer(message)
        data = {
            'message': message.strip(b'\n').decode() ,
            'score': score,
            'key': iterator,
            'lineNumber' : val.index(hexstring) + 1
            }
        b.append(data)
    primary = sorted(b, key=lambda x: x['score'])[-1] ##refer #(1)
    final.append(primary)

secondary = sorted(final, key=lambda x: x['score'])[-1] ##refer #(2)
print(secondary)


import asyncio
import json
import websockets
import database_setup
from google.protobuf.json_format import ParseDict
import api_methods
from MarketDataFeed_pb2 import FeedResponse  # Import the generated protobuf classes
import multiprocessing
import time
import argparse
import sys

def subscribe_to_stock(subscribed_stock):

    async def main():

        print('Market Opened starting sync operation')
        websocket_url = api_methods.get_config().get('INDEX', 'websocket_url')
        ACCESS_TOKEN = api_methods.get_access_token()
        timeout_seconds = 60

        async with websockets.connect(websocket_url, ping_interval=timeout_seconds, extra_headers={
            "Api-Version": "2.0",
            "Authorization": "Bearer " + ACCESS_TOKEN,
        }) as ws:
            print("connected")

            await asyncio.sleep(1)  # Sleep for 1 second

            data = {
                "guid": "someguid",
                "method": "sub",
                "data": {
                    "mode": "full",
                    "instrumentKeys": [subscribed_stock]
                }
            }
            await ws.send(json.dumps(data).encode())

            async for message in ws:
                feed_response = FeedResponse()
                feed_response.ParseFromString(message)
                if subscribed_stock.startswith('NSE_INDEX'):
                    current_price = feed_response.feeds[subscribed_stock].ff.indexFF.ltpc.ltp
                    current_year, current_month, current_day, current_hour, current_minute, current_second,current_millisecond = database_setup.get_current_time_asia_kolkata()

                elif subscribed_stock.startswith('NSE_FO'):
                    current_price = feed_response.feeds[subscribed_stock].ff.marketFF.ltpc.ltp
                    current_year, current_month, current_day, current_hour, current_minute, current_second,current_millisecond = database_setup.get_current_time_asia_kolkata()

                data_dict = {
                    'symbol': subscribed_stock,
                    'year': current_year,
                    'month': current_month,
                    'day': current_day,
                    'hour': current_hour,
                    'minute': current_minute,
                    'second': current_second,
                    'millisecond': current_millisecond,
                    'price': current_price
                }
                # print(data_dict)
                database_setup.insert_into_table(subscribed_stock.replace('|','').replace(' ', ''), data_dict)

            print("disconnected")

    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())

def start_sync(stock):
    print(f'Websocket Sync for {stock} waiting for market to open...')

    while True:
        while not database_setup.market_opened():
            time.sleep(1)

        print(f'Websocket Sync for {stock} started')
        p = multiprocessing.Process(target=subscribe_to_stock, args=(stock,))
        p.start()

        while database_setup.market_opened():
            time.sleep(1)

        print(f'Websocket Sync for {stock} stopping...')
        p.terminate()
        p.join()

if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="WebSocket synchronization for stock symbols")
    parser.add_argument("symbols", nargs='+', help="List of stock symbols to sync (up to 3)")

    args = parser.parse_args()

    if len(args.symbols) > 3:
        print("Error: You can specify up to 3 stock symbols.")
        parser.print_help()
        sys.exit(1)

    SUBSCRIBED_STOCKS = args.symbols
    # How to use
    # SUBSCRIBED_STOCKS = ['NSE_INDEX|Nifty 50', 'NSE_INDEX|Nifty Bank', 'NSE_INDEX|Nifty Fin Service']
    # python market_socket.py 'NSE_INDEX|Nifty 50' 'NSE_INDEX|Nifty Bank' 'NSE_INDEX|Nifty Fin Service'
    # SUBSCRIBED_STOCKS = ['NSE_FO|54643', 'NSE_FO|54644']

    processes = []
    for stock in SUBSCRIBED_STOCKS:
        process = multiprocessing.Process(target=start_sync, args=(stock,))
        process.start()
        processes.append(process)

    for process in processes:
        process.join()