#!/usr/bin/env python
#
# Author: Yang Gao <younggao1994@gmail.com>
#

import unittest
import numpy
from symtensor import symlib, random, einsum

thresh = 1e-8
sign = {'+':1, '-':-1}
nbond  = 8
ni = range(0,5)
nj = range(0,2)
nk = range(1,5)
nl = range(0,4)
nm = range(1,5)
nn = range(0,5)
no = range(0,2)
np = range(0,5)

class DMRGnpTEST(unittest.TestCase):
    def test_334(self):
        # symtensor contraction
        sym1 = ['++-', [ni,nj,nk], None, None]
        sym2 = ['++-', [nk,nl,nm], None, None]
        ijk = random.random([nbond,]*3, sym1)
        klm = random.random([nbond,]*3, sym2)
        ijlm = einsum('ijk,klm->ijlm',ijk,klm)
        # sparse tensor contraction
        ijk_dense, klm_dense = ijk.make_dense(), klm.make_dense()
        ijlm_dense = einsum('IJKijk,KLMklm->IJLMijlm', ijk_dense, klm_dense)
        ijlm_sparse = einsum('IJLMijlm,IJLM->IJLijlm',ijlm_dense, ijlm.get_irrep_map())
        diff = (ijlm-ijlm_sparse).norm() / numpy.sqrt(ijlm_sparse.size)
        self.assertTrue(diff<thresh)

    def test_444(self):
        numpy.random.seed(3)
        sym1 = ['+++-', [ni,nj,nl,nm], None, None]
        sym2 = ['++--', [nn,no,nj,nl], None, None]
        ijlm = random.random([nbond,]*4, sym1)
        nojl = random.random([nbond,]*4, sym2)
        inom = einsum('ijlm,nojl->inom', ijlm, nojl)
        equal = symlib.check_sym_equal(sym1, sym2)

        ijlm_dense, nojl_dense = ijlm.make_dense(), nojl.make_dense()
        inom_dense = einsum('IJLMijlm,NOJLnojl->INOMinom', ijlm_dense, nojl_dense)
        inom_sparse = einsum('INOMinom,INOM->INOinom', inom_dense, inom.get_irrep_map())
        diff = (inom-inom_sparse).norm() / numpy.sqrt(inom_sparse.size)
        self.assertTrue(diff<thresh)

    def test_433(self):
        sym1 = ['+++-', [ni,nn,no,nm], None, None]
        sym2 = ['++-', [ni,nn,np], None, None]
        inom = random.random([nbond,]*4, sym1)
        inp = random.random([nbond,]*3, sym2)
        pom = einsum('inom,inp->pom', inom, inp)

        inom_dense, inp_dense = inom.make_dense(), inp.make_dense()
        pom_dense = einsum('INOMinom,INPinp->POMpom', inom_dense, inp_dense)
        pom_sparse = einsum('POMpom,POM->POpom', pom_dense, pom.get_irrep_map())

        diff = (pom -pom_sparse).norm()/ numpy.sqrt(pom_sparse.size)
        self.assertTrue(diff<thresh)

    def test_453(self):
        ni = range(0,6)
        nj = range(0,3)
        nk = range(1,6)
        nl = range(0,3)
        nm = range(0,3)
        nn = range(0,6)

        sym1 = ['++--', [ni,nj,nk,nl], None, None]
        sym2 = ['-++--', [nj,nk,nl,nm,nn], None, None]

        ijkl = random.random([nbond,]*4, sym1)
        jklmn = random.random([nbond,]*5, sym2)
        imn = einsum('ijkl,jklmn->imn', ijkl,jklmn)

        ijkl_dense, jklmn_dense = ijkl.make_dense(), jklmn.make_dense()
        imn_dense = einsum('IJKLijkl,JKLMNjklmn->IMNimn', ijkl_dense,jklmn_dense)
        imn_sparse = einsum('IMNimn,IMN->IMimn', imn_dense, imn.get_irrep_map())

        diff = (imn-imn_sparse).norm() / numpy.sqrt(imn_sparse.size)
        self.assertTrue(diff<thresh)

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


#!/usr/bin/env python

"""
    Created by caixing:
    caixi@utrc.utc.com
"""

import rospy
import actionlib
from tf import TransformListener
from actionlib import GoalStatus
from geometry_msgs.msg import Pose, Point, Quaternion, Twist
from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal, MoveBaseActionFeedback
from tf.transformations import quaternion_from_euler
from visualization_msgs.msg import Marker
from math import  pi
from collections import OrderedDict
def setup_cb(self,msg):
        quaternions = list()
        position=list()
        p=msg.markers[0].pose
        print(p)
        q=msg.markers[0].orientation
        quaternions.append(q)
        print(q)
        position.append(p)
        p=msg.markers[1].pose
        q=msg.markers[1].orientation
        quaternions.append(q)
        position.append(p)
        p=msg.markers[2].pose
        q=msg.markers[2].orientation
        quaternions.append(q)
        position.append(p)
        self.waypoints = list()
        self.waypoints.append(Pose(position[0], quaternions[0]))
        self.waypoints.append(Pose(position[1], quaternions[1]))
        self.waypoints.append(Pose(position[2], quaternions[2]))
def decisionmake_setup_additivemarker(self):

    self.tf = TransformListener()
    # quaternions = list()
    # position=list()

    # #t = self.tf.getLatestCommonTime("/map", "/charging_zone")
    # #p, q = self.tf.lookupTransform("/map", "/charging_zone",rospy.Time(0))
    # now=rospy.Time.now()
    # # self.tf.waitForTransform("/base_footprint", "/base_link",now,rospy.Duration(10))
    # # p, q = self.tf.lookupTransform("/base_footprint", "/base_link",now)
    # self.tf.waitForTransform("/map", "/charging_zone",now,rospy.Duration(10))
    # p, q = self.tf.lookupTransform("/map", "/charging_zone",now)

    # quaternions.append(q)
    # position.append(p)
    # #t = self.tf.getLatestCommonTime("/map", "/pickup_zone")

    # #p, q = self.tf.lookupTransform("/map", "/pickup_zone",rospy.Time(0))
    # now=rospy.Time.now()
    # # self.tf.waitForTransform("/base_footprint", "/odom",now,rospy.Duration(10))
    # # p, q = self.tf.lookupTransform("/base_footprint", "/odom",now)
    # self.tf.waitForTransform("/map", "/pickup_zone",now,rospy.Duration(10))
    # p, q = self.tf.lookupTransform("/map", "/pickup_zone",now)

    # quaternions.append(q)
    # position.append(p)
    # #t = self.tf.getLatestCommonTime("/map", "/sorting_zone")
    # #p, q = self.tf.lookupTransform("/map", "/sorting_zone",rospy.Time(0))
    # now=rospy.Time.now()
    # # self.tf.waitForTransform("/map", "/odom",now,rospy.Duration(10))
    # # p, q = self.tf.lookupTransform("/map", "/odom",now)
    # self.tf.waitForTransform("/map", "/sorting_zone",now,rospy.Duration(10))
    # p, q = self.tf.lookupTransform("/map", "/sorting_zone",now)
    # quaternions.append(q)
    # position.append(p)

    # self.waypoints = list()

    rospy.Subscriber('/zone_destination_marker',Marker,self.setupturtlebot_cb)

    # # self.waypoints.append(Pose(position[0], quaternions[0]))
    # # self.waypoints.append(Pose(position[1], quaternions[1]))
    # # self.waypoints.append(Pose(position[2], quaternions[2]))

    self.move_base = actionlib.SimpleActionClient("move_base", MoveBaseAction)
    self.cmd_vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)

    rospy.loginfo("Waiting for move_base action server...")

    # Wait up to 60 seconds for the action server to become available
    self.move_base.wait_for_server(rospy.Duration(60))

    rospy.loginfo("Connected to move_base action server")

    rospy.loginfo("Starting Tasks")

    rospy.sleep(1)
    def setupturtlebot_cb(self,msg):
        quaternions = list()
        position=list()
        p=msg.markers[0].pose
        print(p)
        q=msg.markers[0].orientation
        quaternions.append(q)
        print(q)
        position.append(p)
        p=msg.markers[1].pose
        q=msg.markers[1].orientation
        quaternions.append(q)
        position.append(p)
        p=msg.markers[2].pose
        q=msg.markers[2].orientation
        quaternions.append(q)
        position.append(p)
        self.waypoints.append(Pose(position[0], quaternions[0]))
        self.waypoints.append(Pose(position[1], quaternions[1]))
        self.waypoints.append(Pose(position[2], quaternions[2]))


# Copyright (c) 2021 OpenKS Authors, DCD Research Lab, Zhejiang University.
# All Rights Reserved.

"""
Abstract dataset format MDD for Multi-modal Distributed Dataset
"""
from typing import List

class MMD(object):
	"""
	A structure for standard data format read from various sources
	"""
	def __init__(
		self,
		headers: List = [],
		bodies: List = [],
		name: str = ''
		) -> None:
		self._headers = headers
		self._bodies = bodies
		self._name = name

	@property
	def headers(self):
		return self._headers

	@headers.setter
	def headers(self, headers):
		self._headers = headers

	@property
	def bodies(self):
		return self._bodies

	@bodies.setter
	def bodies(self, bodies):
		self._bodies = bodies

	@property
	def name(self):
		return self._name

	@name.setter
	def name(self, name):
		self._name = name

	def info_display(self):
		print("\n")
		print("载入MMD数据集信息：")
		print("-----------------------------------------------")
		print("数据集名称：" + self.name)
		print("读入文件数量：" + str(len(self.headers)))
		print("字段名：" + str(self.headers))
		print("数据示例：")
		for data in self.bodies:
			print(data[0])
		print("-----------------------------------------------")


from datetime import timedelta, datetime
from celery.schedules import crontab
from celery.task.base import periodic_task
from couchlog.models import ExceptionRecord
from django.conf import settings

@periodic_task(run_every=crontab(minute=0, hour=0), queue=getattr(settings, 'CELERY_PERIODIC_QUEUE', 'celery'))
def purge_old_logs():
    key = datetime.now() - timedelta(weeks=52)
    results = ExceptionRecord.view(
        "couchlog/all_by_date",
        reduce=False,
        startkey=[key.isoformat()],
        descending=True,
        limit=1000,
        include_docs=False)

    db = ExceptionRecord.get_db()
    docs = []
    for result in results:
        docs.append({
            '_id': result['id'],
            '_rev': db.get_rev(result['id']),
            '_deleted': True,
        })

    db.bulk_save(docs, use_uuids=False)


import pytest

import pike.auth

# pike uses the "NONE" domain when one isn't provided
NONE = "NONE"

@pytest.mark.parametrize(
    "cred_str,exp_cred_tuple",
    (
        ("foo%bar", (NONE, "foo", "bar")),
        ("foo%ba%r", (NONE, "foo", "ba%r")),
        ("BAZ\\foo%bar", ("BAZ", "foo", "bar")),
        ("BAZ\\foo%b%ar", ("BAZ", "foo", "b%ar")),
        # not convinced this is valid, but it won't crash the splitter
        ("BA\\Z\\foo%bar", ("BA", "Z\\foo", "bar")),
        ("BA\\Z\\foo%bar%", ("BA", "Z\\foo", "bar%")),
    ),
)
def test_split_credentials(cred_str, exp_cred_tuple):
    assert pike.auth.split_credentials(cred_str) == exp_cred_tuple


from time        import time
from typing      import Dict, Iterable, List, Optional, Tuple
from dataclasses import dataclass
from irctokens   import build

from .contexts  import ServerContext
from .matching  import Response, ResponseOr, ParamAny, ParamLiteral
from .interface import ICapability
from .params    import ConnectionParams, STSPolicy

class Capability(ICapability):
    def __init__(self,
            ratified_name: Optional[str],
            draft_name:    Optional[str]=None,
            alias:         Optional[str]=None,
            depends_on:    List[str]=[]):
        self.name  = ratified_name
        self.draft = draft_name
        self.alias = alias or ratified_name
        self.depends_on = depends_on.copy()

        self._caps = [ratified_name, draft_name]

    def match(self, capability: str) -> bool:
        return capability in self._caps

    def available(self, capabilities: Iterable[str]
            ) -> Optional[str]:
        for cap in self._caps:
            if not cap is None and cap in capabilities:
                return cap
        else:
            return None

    def copy(self):
        return Capability(
            self.name,
            self.draft,
            alias=self.alias,
            depends_on=self.depends_on[:])

CAP_SASL  = Capability("sasl")
CAP_ECHO  = Capability("echo-message")
CAP_LABEL = Capability("labeled-response", "draft/labeled-response-0.2")
CAP_STS   = Capability("sts", "draft/sts")

LABEL_TAG = {
    "draft/labeled-response-0.2": "draft/label",
    "labeled-response": "label"
}

CAPS: List[ICapability] = [
    Capability("multi-prefix"),
    Capability("chghost"),
    Capability("away-notify"),
    Capability("userhost-in-names"),

    Capability("invite-notify"),
    Capability("account-tag"),
    Capability("account-notify"),
    Capability("extended-join"),

    Capability("message-tags", "draft/message-tags-0.2"),
    Capability("cap-notify"),
    Capability("batch"),

    Capability(None, "draft/rename", alias="rename"),
    Capability("setname", "draft/setname")
]

def _cap_dict(s: str) -> Dict[str, str]:
    d: Dict[str, str] = {}
    for token in s.split(","):
        key, _, value = token.partition("=")
        d[key] = value
    return d

async def sts_transmute(params: ConnectionParams):
    if not params.sts is None and not params.tls:
        now   = time()
        since = (now-params.sts.created)
        if since <= params.sts.duration:
            params.port = params.sts.port
            params.tls  = True

class CAPContext(ServerContext):
    async def on_ls(self, tokens: Dict[str, str]):
        caps = list(self.server.desired_caps)+CAPS

        if (not self.server.params.sasl is None and
                not CAP_SASL in caps):
            caps.append(CAP_SASL)

        matched   = (c.available(tokens) for c in caps)
        cap_names = [name for name in matched if not name is None]

        if cap_names:
            await self.server.send(build("CAP", ["REQ", " ".join(cap_names)]))

            while cap_names:
                line = await self.server.wait_for(ResponseOr(
                    Response("CAP", [ParamAny(), ParamLiteral("ACK")]),
                    Response("CAP", [ParamAny(), ParamLiteral("NAK")])
                ))

                current_caps = line.params[2].split(" ")
                for cap in current_caps:
                    if cap in cap_names:
                        cap_names.remove(cap)
        if (self.server.cap_agreed(CAP_SASL) and
                not self.server.params.sasl is None):
            await self.server.sasl_auth(self.server.params.sasl)

    async def handshake(self):
        cap_sts = CAP_STS.available(self.server.available_caps)
        if not cap_sts is None:
            sts_dict = _cap_dict(self.server.available_caps[cap_sts])
            params   = self.server.params
            if not params.tls:
                if "port" in sts_dict:
                    params.port = int(sts_dict["port"])
                    params.tls  = True

                    await self.server.bot.disconnect(self.server)
                    await self.server.bot.add_server(self.server.name, params)
                    return
            elif "duration" in sts_dict:
                policy = STSPolicy(
                    int(time()),
                    params.port,
                    int(sts_dict["duration"]),
                    "preload" in sts_dict)
                self.server.sts_policy(policy)

        await self.on_ls(self.server.available_caps)
        await self.server.send(build("CAP", ["END"]))


"""
Classes and functions to help fetching ACA telemetry data using MAUDE.
These include the following global variables

    * PIXEL_MAP: dict of np.array, with values mapping integer pixel indices to pixel string ID
    * PIXEL_MAP_INV: dict of dict, with values mapping pixel string ID to integer pixel indices.
    * PIXEL_MASK: dict of np.array. Values are boolean masks that apply to images of different sizes
    * ACA_MSID_LIST: dictionary of commonly-used ACA telemetry MSIDs.
    * ACA_SLOT_MSID_LIST: dictionary of ACA image telemetry MSIDs.

PIXEL_MAP contains maps between pixel indices and pixel IDm depending on the image size.
In the following tables, column index increases to the right and row index increases to the top
(c.f. ACA User Manual Figs 1.8 and 1.9 )::

  - Size 4X41:

    -----------------------------------------
    | -- | -- | -- | -- | -- | -- | -- | -- |
    -----------------------------------------
    | -- | -- | -- | -- | -- | -- | -- | -- |
    -----------------------------------------
    | -- | -- | D1 | H1 | L1 | P1 | -- | -- |
    -----------------------------------------
    | -- | -- | C1 | G1 | K1 | O1 | -- | -- |
    -----------------------------------------
    | -- | -- | B1 | F1 | J1 | N1 | -- | -- |
    -----------------------------------------
    | -- | -- | A1 | E1 | I1 | M1 | -- | -- |
    -----------------------------------------
    | -- | -- | -- | -- | -- | -- | -- | -- |
    -----------------------------------------
    | -- | -- | -- | -- | -- | -- | -- | -- |
    -----------------------------------------

  - Size 6X61 or 6X62:

    -----------------------------------------
    | -- | -- | -- | -- | -- | -- | -- | -- |
    -----------------------------------------
    | -- | -- | E2 | F2 | G2 | H2 | -- | -- |
    -----------------------------------------
    | -- | D2 | D1 | H1 | L1 | P1 | I2 | -- |
    -----------------------------------------
    | -- | C2 | C1 | G1 | K1 | O1 | J2 | -- |
    -----------------------------------------
    | -- | B2 | B1 | F1 | J1 | N1 | K2 | -- |
    -----------------------------------------
    | -- | A2 | A1 | E1 | I1 | M1 | L2 | -- |
    -----------------------------------------
    | -- | -- | P2 | O2 | N2 | M2 | -- | -- |
    -----------------------------------------
    | -- | -- | -- | -- | -- | -- | -- | -- |
    -----------------------------------------

  - Size 8X81, 8X82, 8X83 or 8X84:

    -----------------------------------------
    | H1 | P1 | H2 | P2 | H3 | P3 | H4 | P4 |
    -----------------------------------------
    | G1 | O1 | G2 | O2 | G3 | O3 | G4 | O4 |
    -----------------------------------------
    | F1 | N1 | F2 | N2 | F3 | N3 | F4 | N4 |
    -----------------------------------------
    | E1 | M1 | E2 | M2 | E3 | M3 | E4 | M4 |
    -----------------------------------------
    | D1 | L1 | D2 | L2 | D3 | L3 | D4 | L4 |
    -----------------------------------------
    | C1 | K1 | C2 | K2 | C3 | K3 | C4 | K4 |
    -----------------------------------------
    | B1 | J1 | B2 | J2 | B3 | J3 | B4 | J4 |
    -----------------------------------------
    | A1 | I1 | A2 | I2 | A3 | I3 | A4 | I4 |
    -----------------------------------------
"""

import copy
from struct import Struct
from struct import unpack as _unpack

import maude
import numpy as np
from astropy.table import Table, vstack
from Chandra.Time import DateTime

# The following are the tables in the docstring above. They appear to be transposed,
# but the resultt agrees with level0.
PIXEL_MAP = {
    "4x4": np.array(
        [
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "A1", "B1", "C1", "D1", "  ", "  "],
            ["  ", "  ", "E1", "F1", "G1", "H1", "  ", "  "],
            ["  ", "  ", "I1", "J1", "K1", "L1", "  ", "  "],
            ["  ", "  ", "M1", "N1", "O1", "P1", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
        ]
    ),
    "6x6": np.array(
        [
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "A2", "B2", "C2", "D2", "  ", "  "],
            ["  ", "P2", "A1", "B1", "C1", "D1", "E2", "  "],
            ["  ", "O2", "E1", "F1", "G1", "H1", "F2", "  "],
            ["  ", "N2", "I1", "J1", "K1", "L1", "G2", "  "],
            ["  ", "M2", "M1", "N1", "O1", "P1", "H2", "  "],
            ["  ", "  ", "L2", "K2", "J2", "I2", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
        ]
    ),
    "8x8": np.array(
        [
            ["A1", "B1", "C1", "D1", "E1", "F1", "G1", "H1"],
            ["I1", "J1", "K1", "L1", "M1", "N1", "O1", "P1"],
            ["A2", "B2", "C2", "D2", "E2", "F2", "G2", "H2"],
            ["I2", "J2", "K2", "L2", "M2", "N2", "O2", "P2"],
            ["A3", "B3", "C3", "D3", "E3", "F3", "G3", "H3"],
            ["I3", "J3", "K3", "L3", "M3", "N3", "O3", "P3"],
            ["A4", "B4", "C4", "D4", "E4", "F4", "G4", "H4"],
            ["I4", "J4", "K4", "L4", "M4", "N4", "O4", "P4"],
        ]
    ),
    "DNLD": np.array(
        [
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
            ["  ", "  ", "  ", "  ", "  ", "  ", "  ", "  "],
        ]
    ),
}

PIXEL_MASK = {k: PIXEL_MAP[k] == "  " for k in PIXEL_MAP}
_ROWS, _COLS = np.meshgrid(np.arange(8), np.arange(8), indexing="ij")

PIXEL_MAP_INV = {
    k: {
        p: (i, j)
        for i, j, p in zip(
            _ROWS[PIXEL_MAP[k] != "  "],
            _COLS[PIXEL_MAP[k] != "  "],
            PIXEL_MAP[k][PIXEL_MAP[k] != "  "],
        )
    }
    for k in ["6x6", "4x4", "8x8"]
}

_msid_prefix = {1: "A", 2: "R"}

def _aca_msid_list(pea):
    # helper method to make a dictionary with all global (non-slot) MSIDs used here
    return {
        "status": "AOACSTAT",  # ASPECT CAMERA DATA PROCESSING OVERALL STATUS FLAG
        "integration_time": f"{_msid_prefix[pea]}ACAINT0",
        "major_frame": "CVCMJCTR",
        "minor_frame": "CVCMNCTR",
        "cmd_count": f"{_msid_prefix[pea]}CCMDS",
        "cmd_progress_to_go": f"{_msid_prefix[pea]}AROW2GO",  # No. of ROWS TO GO COMMAND PROGRESS
        "cmd_progress": "AOCMDPG1",  # COMMAND PROGRESS COUNT
        "pixel_telemetry_type": f"{_msid_prefix[pea]}APIXTLM",
        "dynamic_background_type": f"{_msid_prefix[pea]}ABGDTYP",
    }

def _aca_image_msid_list(pea):
    # helper method to make a list of dictionaries with MSIDs for each slot in a given PEA.
    msid_prefix = _msid_prefix[pea]

    px_ids = {
        "A",
        "B",
        "C",
        "D",
        "E",
        "F",
        "G",
        "H",
        "I",
        "J",
        "K",
        "L",
        "M",
        "N",
        "O",
        "P",
    }
    px_nums = [str(n) for n in range(1, 5)]
    px_img_nums = [str(n) for n in range(8)]

    pixels = [
        sorted(
            [
                f"{msid_prefix}CIMG{px_img_num}{px_id}{px_num}"
                for px_num in px_nums
                for px_id in px_ids
            ]
        )
        for px_img_num in px_img_nums
    ]

    res = {
        "pixels": pixels,
        "sizes": [
            f"{msid_prefix}CA00040",  # Size of image 0
            f"{msid_prefix}CA00043",  # Size of image 1
            f"{msid_prefix}CA00046",  # Size of image 2
            f"{msid_prefix}CA00049",  # Size of image 3
            f"{msid_prefix}CA00052",  # Size of image 4
            f"{msid_prefix}CA00055",  # Size of image 5
            f"{msid_prefix}CA00058",  # Size of image 6
            f"{msid_prefix}CA00061",
        ],  # Size of image 7
        "rows": [
            f"{msid_prefix}CA00076",  # Row of pixel A1 of image 0
            f"{msid_prefix}CA00292",  # Row of pixel A1 of image 1
            f"{msid_prefix}CA00508",  # Row of pixel A1 of image 2
            f"{msid_prefix}CA00724",  # Row of pixel A1 of image 3
            f"{msid_prefix}CA00940",  # Row of pixel A1 of image 4
            f"{msid_prefix}CA01156",  # Row of pixel A1 of image 5
            f"{msid_prefix}CA01372",  # Row of pixel A1 of image 6
            f"{msid_prefix}CA01588",
        ],  # Row of pixel A1 of image 7
        "cols": [
            f"{msid_prefix}CA00086",  # Column of pixel A1 of image 0
            f"{msid_prefix}CA00302",  # Column of pixel A1 of image 1
            f"{msid_prefix}CA00518",  # Column of pixel A1 of image 2
            f"{msid_prefix}CA00734",  # Column of pixel A1 of image 3
            f"{msid_prefix}CA00950",  # Column of pixel A1 of image 4
            f"{msid_prefix}CA01166",  # Column of pixel A1 of image 5
            f"{msid_prefix}CA01382",  # Column of pixel A1 of image 6
            f"{msid_prefix}CA01598",
        ],  # Column of pixel A1 of image 7
        "scale_factor": [
            f"{msid_prefix}CA00096",  # Scale factor of image 0
            f"{msid_prefix}CA00312",  # Scale factor of image 1
            f"{msid_prefix}CA00528",  # Scale factor of image 2
            f"{msid_prefix}CA00744",  # Scale factor of image 3
            f"{msid_prefix}CA00960",  # Scale factor of image 4
            f"{msid_prefix}CA01176",  # Scale factor of image 5
            f"{msid_prefix}CA01392",  # Scale factor of image 6
            f"{msid_prefix}CA01608",
        ],  # Scale factor of image 7
        "image_status": [f"AOIMAGE{i}" for i in range(8)],  # IMAGE STATUS FLAG
        "fiducial_flag": [f"AOACFID{i}" for i in range(8)],  # FIDUCIAL LIGHT FLAG (OBC)
        "image_function_obc": [f"AOACFCT{i}" for i in range(8)],  # IMAGE FUNCTION (OBC)
        "image_function": [
            f"{msid_prefix}AIMGF{i}1" for i in range(8)
        ],  # IMAGE FUNCTION (PEA)
        # this one exists also as FUNCTION2/3/4
        # 'image_function':
        #     [f'{msid_prefix}AIMGF{i}1' for i in range(8)],  # IMAGE FUNCTION1 (PEA)
        "saturated_pixel": [
            f"{msid_prefix}ASPXF{i}" for i in range(8)
        ],  # DEFECTIVE PIXEL FLAG
        "defective_pixel": [
            f"{msid_prefix}ADPXF{i}" for i in range(8)
        ],  # SATURATED PIXEL FLAG
        "quad_bound": [
            f"{msid_prefix}QBNDF{i}" for i in range(8)
        ],  # QUADRANT BOUNDRY FLAG
        "common_col": [
            f"{msid_prefix}ACOLF{i}" for i in range(8)
        ],  # COMMON COLUMN FLAG
        "multi_star": [
            f"{msid_prefix}AMSTF{i}" for i in range(8)
        ],  # MULTIPLE STAR FLAG
        "ion_rad": [
            f"{msid_prefix}AIRDF{i}" for i in range(8)
        ],  # IONIZING RADIATION FLAG
        "background_rms": [f"{msid_prefix}CRMSBG{i}" for i in range(8)],
        "background_avg": [
            f"{msid_prefix}CA00110",
            f"{msid_prefix}CA00326",
            f"{msid_prefix}CA00542",
            f"{msid_prefix}CA00758",
            f"{msid_prefix}CA00974",
            f"{msid_prefix}CA01190",
            f"{msid_prefix}CA01406",
            f"{msid_prefix}CA01622",
        ],
        "housing_temperature": [
            f"{msid_prefix}ACH1T{i}2" for i in range(8)
        ],  # AC HOUSING TEMPERATURE
        "ccd_temperature": [
            f"{msid_prefix}CCDPT{i}2" for i in range(8)
        ],  # CCD TEMPERATURE
        "primary_temperature": [
            f"{msid_prefix}QTAPMT{i}" for i in range(8)
        ],  # PRIMARY MIRROR/LENS CELL TEMP
        "secondary_temperature": [
            f"{msid_prefix}QTH2MT{i}" for i in range(8)
        ],  # AC SECONDARY MIRROR TEMPERATURE
        "magnitude": [
            f"AOACMAG{i}" for i in range(8)
        ],  # STAR OR FIDUCIAL MAGNITUDE (OBC)
        "centroid_ang_y": [
            f"AOACYAN{i}" for i in range(8)
        ],  # YAG CENTROID Y ANGLE (OBC)
        "centroid_ang_z": [
            f"AOACZAN{i}" for i in range(8)
        ],  # ZAG CENTROID Z ANGLE (OBC)
        "bgd_stat_pixels": [
            [f"ACBPX{j}1{i}" for j in "ABGH"] + [f"ACBPX{j}4{i}" for j in "IJOP"]
            for i in range(8)
        ],
    }
    return [{k: res[k][i] for k in res.keys()} for i in range(8)]

ACA_MSID_LIST = {i + 1: _aca_msid_list(i + 1) for i in range(2)}
ACA_SLOT_MSID_LIST = {i + 1: _aca_image_msid_list(i + 1) for i in range(2)}

_a2p = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P"]
# This maps image type to a list of pixel indices over the 8x8 array.
# - Type 0 is 4x4,
# - Types 1 (first batch of 6x6) and 4 (first batch of 8x8) use the same pixel IDs as 4x4.
# - Type 3 is not a real image type. It occurs when the image telemetry is used to download
#   memory dump data. In this case, the image is treated as 4x4, but the values might be giberish.
# - Types 2 (second batch of 6x6) and 5 (second batch of 8x8) use the same pixel IDs.
_IMG_INDICES = [
    np.array([PIXEL_MAP_INV["4x4"][f"{k}1"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["6x6"][f"{k}1"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["6x6"][f"{k}2"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["4x4"][f"{k}1"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["8x8"][f"{k}1"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["8x8"][f"{k}2"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["8x8"][f"{k}3"] for k in _a2p]).T,
    np.array([PIXEL_MAP_INV["8x8"][f"{k}4"] for k in _a2p]).T,
]

######################
# VCDU-based functions
######################

# these are used multiple times
_aca_front_fmt = Struct(">HBBBBBB")
_size_bits = np.zeros((8, 8), dtype=np.uint8)
_pixel_bits = np.zeros((16, 16), dtype=np.uint16)
_bits = np.array([1 << i for i in range(64)], dtype=np.uint64)[::-1]

# I'm sure there is a better way...
def _packbits(a, unsigned=True):
    # take something like this: [1,0,1,1,0] and return 2^4 + 2^2 + 2
    # This handles integer types only
    n = len(a)
    if not unsigned and a[0]:
        return np.int64(np.sum(a * _bits[-n:]) - (1 << n))
    return np.sum(a * _bits[-n:])

class _AcaImageHeaderDecom:
    """
    Class to decommute ACA image telemtry headers.

    These methods are grouped into a class because header 3 packet is split into up to 8 parts.
    The __call__ method in this class accumulates the partial packets. Once all images are of known
    types, and the packets are known, it will return the header 3 data.
    """

    def __init__(self):
        self._header = [
            self._aca_header_1,
            self._aca_header_1,
            self._aca_header_2,
            lambda b: {},
            self._aca_header_1,
            self._aca_header_2,
            self._aca_header_3,
            self._aca_header_3,
        ]

    def __call__(self, imgnum, imgtype, byte_array):
        return self._header[imgtype](byte_array)

    @staticmethod
    def _aca_header_1(bits):
        """
        Unpack ACA header 1 (ACA User Manual 5.3.2.2.1).

        :param bits: bytes-like object of length 7
        :return: dict
        """
        bits = np.unpackbits(np.array(_unpack("BBBbbBB", bits), dtype=np.uint8))
        return {
            "IMGFID": bool(bits[0]),
            "IMGNUM": _packbits(bits[1:4]),
            "IMGFUNC": _packbits(bits[4:6]),
            "IMGSTAT": _packbits(bits[6:12]),
            "SAT_PIXEL": bool(bits[6]),
            "DEF_PIXEL": bool(bits[7]),
            "QUAD_BOUND": bool(bits[8]),
            "COMMON_COL": bool(bits[9]),
            "MULTI_STAR": bool(bits[10]),
            "ION_RAD": bool(bits[11]),
            "IMGROW0": _packbits(bits[12:22], unsigned=False),
            "IMGCOL0": _packbits(bits[22:32], unsigned=False),
            "IMGSCALE": _packbits(bits[32:46]),
            "BGDAVG": _packbits(bits[46:56]),
        }

    @staticmethod
    def _aca_header_2(bits):
        """
        Unpack ACA header 2 (ACA User Manual 5.3.2.2.2).

        :param bits: bytes-like object of length 7
        :return: dict
        """
        bits = _unpack("BbbbbBB", bits)
        c = np.unpackbits(np.array(bits[:2], dtype=np.uint8))
        return {
            # do we want these?
            # 'FID2': bool(bits[0]),
            # 'IMGNUM2': _packbits(bits[1:4]),
            # 'IMGFUNC2': _packbits(bits[4:6]),
            "BGDRMS": _packbits(c[6:16]),
            "TEMPCCD": bits[2],
            "TEMPHOUS": bits[3],
            "TEMPPRIM": bits[4],
            "TEMPSEC": bits[5],
            "BGDSTAT": bits[6],
            "BGDSTAT_PIXELS": np.unpackbits(np.array(bits[-1:], dtype=np.uint8)[-1:]),
        }

    @staticmethod
    def _aca_header_3(bits):
        """
        Unpack ACA header 3 (ACA User Manual 5.3.2.2.3).

        :param bits: bytes-like object of length 7
        :return: dict
        """
        return {"DIAGNOSTIC": _unpack("BBBBBB", bits[1:])}

def unpack_aca_telemetry(packet):
    """
    Unpack ACA telemetry encoded in 225-byte packets.

    :param packet: bytes
    :return: list of dict

    A list of length 8, one entry per slot, where each entry is a dictionary.
    """
    s1, s2, s3 = _unpack("BBB", packet[5:8])
    _size_bits[:, -3:] = np.unpackbits(
        np.array([[s1, s2, s3]], dtype=np.uint8).T, axis=1
    ).reshape((8, -1))
    img_types = np.packbits(_size_bits, axis=1).T[0]
    slots = []
    header_decom = _AcaImageHeaderDecom()
    for img_num, i in enumerate(range(8, len(packet), 27)):
        img_header = {"IMGTYPE": img_types[img_num]}
        img_header.update(header_decom(img_num, img_types[img_num], packet[i : i + 7]))
        img_pixels = _unpack("B" * 20, packet[i + 7 : i + 27])
        _pixel_bits[:, -10:] = np.unpackbits(
            np.array([img_pixels], dtype=np.uint8).T, axis=1
        ).reshape((-1, 10))
        img_pixels = np.sum(np.packbits(_pixel_bits, axis=1) * [[2**8, 1]], axis=1)
        img_header["pixels"] = img_pixels
        slots.append(img_header)

    bgd_types = {0: "FLAT", 1: "DYNB"}
    pix_tlm_types = {0: "ORIG", 1: "DYNB", 2: "DIFF", 3: "ERR3"}
    # Before the dynamic background patch, the first two bytes contained INTEG in those
    # 16 bits (named integbits).  After the dynamic background patch, the first 6 bits of
    # integbits will be repurposed: two bits for PIXTLM, next bit for BGDTYP, 3 spares,
    # and 10 bits for INTEG.
    integbits = np.unpackbits(np.array(_unpack("BB", packet[0:2]), dtype=np.uint8))
    pixtlm = _packbits(integbits[0:2])
    bgdtyp = integbits[2]
    integ = _packbits(integbits[6:])
    glbstat = _unpack("B", packet[2:3])[0]
    bits = np.unpackbits(np.array(_unpack("BBB", packet[2:5]), dtype=np.uint8))
    res = {
        "AAPIXTLM": pix_tlm_types[pixtlm],
        "AABGDTYP": bgd_types[bgdtyp],
        "INTEG": integ,
        "GLBSTAT": glbstat,
        "HIGH_BGD": bool(bits[0]),
        "RAM_FAIL": bool(bits[1]),
        "ROM_FAIL": bool(bits[2]),
        "POWER_FAIL": bool(bits[3]),
        "CAL_FAIL": bool(bits[4]),
        "COMM_CHECKSUM_FAIL": bool(bits[5]),
        "RESET": bool(bits[6]),
        "SYNTAX_ERROR": bool(bits[7]),
        "COMMCNT": _packbits(bits[8:14], unsigned=False),
        "COMMCNT_SYNTAX_ERROR": bool(bits[14]),
        "COMMCNT_CHECKSUM_FAIL": bool(bits[15]),
        "COMMPROG": _packbits(bits[16:22], unsigned=False),
        "COMMPROG_REPEAT": _packbits(bits[22:24], unsigned=False),
    }
    for i, s in enumerate(slots):
        s.update(res)
    return slots

def _combine_aca_packets(aca_packets):
    """
    Combine a list of ACA packets into a single record.

    This is intended to combine the two 6X6 packets or the four 8X8 packets.

    :param aca_packets: list of dict
    :return: dict
    """
    # note that they are reverse-sorted so the first frame overwrites the others if they collide
    aca_packets = sorted(aca_packets, key=lambda p: p["TIME"], reverse=True)
    res = {}
    pixels = np.ma.masked_all((8, 8))
    pixels.data[:] = np.nan
    for f in aca_packets:
        # IMGTYPE 3 is not a real image. It means the pixels are used to download memory dump data
        # if IMGTYPE == 3, do nothing. All pixels will be masked
        if f["IMGTYPE"] != 3:
            i0, i1 = _IMG_INDICES[f["IMGTYPE"]]
            pixels[i0, i1] = f["pixels"]

    for f in aca_packets:
        res.update(f)
    del res["pixels"]
    res["IMG"] = pixels
    return res

def _group_packets(packets, discard=True):
    """
    ACA telemetry is packed in packets of 225 bytes. Each of these is split in four VCDU frames.
    Before decommuting an ACA package we group the ACA-related portion of VCDU frames to form the
    one 225-byte ACA packet.

    :param packets: list of ACA sub-packets
    :param discard: bool to discard incomplete ACA packets
    :return: list of ACA packets
    """
    res = []
    n = None
    s = None
    for packet in packets:
        if res and (packet["MJF"] * 128 + packet["MNF"] > n):
            if not discard or len(res) == s:
                yield res
            res = []
        if not res:
            # the number of minor frames expected within the same ACA packet
            s = {0: 1, 1: 2, 2: 2, 3: 1, 4: 4, 5: 4, 6: 4, 7: 4}[int(packet["IMGTYPE"])]
            # the number of minor frames within the same ACA packet expected after this minor frame
            remaining = {0: 0, 1: 1, 2: 0, 3: 0, 4: 3, 5: 2, 6: 1, 7: 0}[
                int(packet["IMGTYPE"])
            ]
            n = packet["MJF"] * 128 + packet["MNF"] + 4 * remaining
        res.append(packet)
    if res and (not discard or len(res) == s):
        yield res

def get_raw_aca_packets(start, stop, maude_result=None, **maude_kwargs):
    """
    Fetch 1025-byte VCDU frames using MAUDE and extract a list of 225-byte ACA packets.

    If the first minor frame in a group of four ACA packets is within (start, stop),
    the three following minor frames are included if present.

    returns a dictionary with keys ['TIME', 'MNF', 'MJF', 'packets', 'flags'].
    These correspond to the minor frame time, minor frame count, major frame count,
    the list of packets, and flags returned by MAUDE respectively.

    This function raises an exception if the VCDU frames in maude_result are not contiguous, which
    can also happen if the frames are corrupted in some way.

    :param start: timestamp interpreted as a Chandra.Time.DateTime
    :param stop: timestamp interpreted as a Chandra.Time.DateTime
    :param maude_result: the result of calling maude.get_frames. Optional.
    :param maude_kwargs: keyword args passed to maude.get_frames()
    :return: dict

        {'flags': int, 'packets': [],
         'TIME': np.array([]), 'MNF': np.array([]), 'MJF': np.array([])}
    """
    date_start, date_stop = DateTime(start), DateTime(
        stop
    )  # ensure input is proper date
    stop_pad = 1.5 / 86400  # padding at the end in case of trailing partial ACA packets

    # get the frames and unpack front matter
    if maude_result is None:
        frames = maude.get_frames(
            start=date_start, stop=date_stop + stop_pad, **maude_kwargs
        )["data"]
    else:
        frames = maude_result["data"]
    flags = frames["f"]
    frames = frames["frames"]

    # Getting major and minor frames to figure out which is the first ACA packet in a group
    # The VCDU counter is stored in 24 bits, and struct.unpack does not have a 24-bit format code.
    # We therefore decom the bytes separately and combine them into a single integer using the
    # following weights:
    w = np.array([1, 2**8, 2**16])[::-1]
    vcdu_times = np.array([frame["t"] for frame in frames])
    vcdu = np.array(
        [np.sum(w * _unpack("BBB", frame["bytes"][2:5])) for frame in frames]
    )

    if np.any(np.diff(vcdu) != 1):
        raise Exception("VCDU frames are not contiguous")  # a sanity check

    sub = vcdu % 4  # the minor frame index within each ACA update

    major_counter = np.cumsum(
        sub == 0
    )  # this number is monotonically increasing starting at 0

    n = major_counter.max() + 1 if len(major_counter) > 0 else 1
    # only unpack complete ACA frames in the original range:
    aca_frame_entries = np.ma.masked_all((n, 4), dtype=int)
    aca_frame_entries[major_counter, sub] = np.arange(vcdu_times.shape[0])
    aca_frame_times = np.ma.masked_all((n, 4))
    aca_frame_times[major_counter, sub] = vcdu_times

    # this will remove ACA records with at least one missing minor frame
    select = (
        (~np.any(aca_frame_times.mask, axis=1))
        * (aca_frame_times[:, 0] >= date_start.secs)
        * (aca_frame_times[:, 0] <= date_stop.secs)
    )

    # assemble the 56 bit ACA minor records and times (time is not unpacked)
    aca = []
    aca_times = []
    for frame in frames:
        aca_times.append(frame["t"])
        aca.append(b"".join([frame["bytes"][j : j + 14] for j in [18, 274, 530, 780]]))

    # combine them into 224 byte frames (it currently ensures all 224 bytes are there)
    aca_packets = [
        b"".join([aca[i] for i in entry]) for entry in aca_frame_entries[select]
    ]
    for a in aca_packets:
        assert len(a) == 224

    times = vcdu_times[aca_frame_entries[select, 0]]
    vcdu_counter = vcdu[aca_frame_entries[select, 0]]

    return {
        "flags": flags,
        "packets": aca_packets,
        "TIME": times,
        "MNF": vcdu_counter % (1 << 7),
        "MJF": vcdu_counter // (1 << 7),
        "VCDUCTR": vcdu_counter,
    }

ACA_PACKETS_DTYPE = np.dtype(
    [
        ("TIME", np.float64),
        ("VCDUCTR", np.uint32),
        ("MJF", np.uint32),
        ("MNF", np.uint32),
        ("IMGNUM", np.uint32),
        ("COMMCNT", np.uint8),
        ("COMMPROG", np.uint8),
        ("GLBSTAT", np.uint8),
        ("IMGFUNC", np.uint32),
        ("IMGTYPE", np.uint8),
        ("IMGSCALE", np.uint16),
        ("IMGROW0", np.int16),
        ("IMGCOL0", np.int16),
        ("INTEG", np.uint16),
        ("BGDAVG", np.uint16),
        ("BGDRMS", np.uint16),
        ("TEMPCCD", np.int16),
        ("TEMPHOUS", np.int16),
        ("TEMPPRIM", np.int16),
        ("TEMPSEC", np.int16),
        ("BGDSTAT", np.uint8),
        ("HIGH_BGD", bool),
        ("RAM_FAIL", bool),
        ("ROM_FAIL", bool),
        ("POWER_FAIL", bool),
        ("CAL_FAIL", bool),
        ("COMM_CHECKSUM_FAIL", bool),
        ("RESET", bool),
        ("SYNTAX_ERROR", bool),
        ("COMMCNT_SYNTAX_ERROR", bool),
        ("COMMCNT_CHECKSUM_FAIL", bool),
        ("COMMPROG_REPEAT", np.uint8),
        ("IMGFID", bool),
        ("IMGSTAT", np.uint8),
        ("SAT_PIXEL", bool),
        ("DEF_PIXEL", bool),
        ("QUAD_BOUND", bool),
        ("COMMON_COL", bool),
        ("MULTI_STAR", bool),
        ("ION_RAD", bool),
        ("IMGROW_A1", np.int16),
        ("IMGCOL_A1", np.int16),
        ("IMGROW0_8X8", np.int16),
        ("IMGCOL0_8X8", np.int16),
        ("END_INTEG_TIME", np.float64),
        ("AAPIXTLM", "<U4"),
        ("AABGDTYP", "<U4"),
        ("IMG", "<f8", (8, 8)),
    ]
)

def _aca_packets_to_table(aca_packets, dtype=None):
    """
    Store ACA packets in a table.

    :param aca_packets: list of dict
    :param dtype: dtype to use in the resulting table. Optional.
    :return: astropy.table.Table
    """
    import copy

    if dtype is None:
        dtype = ACA_PACKETS_DTYPE

    array = np.ma.masked_all([len(aca_packets)], dtype=dtype)
    names = copy.deepcopy(dtype.names)
    img = []
    for i, aca_packet in enumerate(aca_packets):
        if "IMG" in aca_packet:
            img.append(aca_packet["IMG"])
        for name in names:
            if name in aca_packet:
                array[name][i] = aca_packet[name]

    table = Table(array, masked=True)
    if img:
        table["IMG"] = img
        for i, aca_packet in enumerate(aca_packets):
            table["IMG"].mask[i] = aca_packet["IMG"].mask
    return table

def get_aca_packets(
    start,
    stop,
    level0=False,
    combine=False,
    adjust_time=False,
    calibrate=False,
    blobs=None,
    frames=None,
    dtype=None,
    **maude_kwargs,
):
    """
    Fetch VCDU 1025-byte frames, extract ACA packets, unpack them and store them in a table.

    Incomplete ACA packets (if there is a minor frame missing) can be combined or not into records
    with complete ACA telemetry. Compare these to calls to the function:

            >>> from chandra_aca import maude_decom
            >>> img = maude_decom.get_aca_packets(684089000, 684089016, combine=True)
            >>> img = img[img['IMGNUM'] == 0]
            >>> img['TIME', 'MJF', 'MNF', 'COMMCNT', 'GLBSTAT', 'IMGTYPE', 'IMGROW0', 'IMGCOL0',
            >>>     'TEMPCCD', 'TEMPHOUS']
            <Table masked=True length=4>
                 TIME      MJF    MNF   COMMCNT GLBSTAT IMGTYPE IMGROW0 IMGCOL0 TEMPCCD TEMPHOUS
               float64    uint32 uint32  uint8   uint8   uint8   int16   int16   int16   int16
            ------------- ------ ------ ------- ------- ------- ------- ------- ------- --------
            684089001.869  78006     32       0       0       4     469    -332     -20       83
            684089005.969  78006     48       0       0       4     469    -332     -20       83
            684089010.069  78006     64       0       0       4     469    -332     -20       83
            684089014.169  78006     80       0       0       4     469    -332     -20       83

    Using combined=False, results in records with incomplete images. In this case, data can be
    missing from some records. For example, with 8X8 images, IMGROW0 and IMGCOL0 are present in the
    first ACA packet (image type 4) while the temperature is present in the second (image type 5):

        >>> from chandra_aca import maude_decom
        >>> img = maude_decom.get_aca_packets(684089000, 684089016, combine=False)
        >>> img = img[img['IMGNUM'] == 0]
        >>> img['TIME', 'MJF', 'MNF', 'COMMCNT', 'GLBSTAT', 'IMGTYPE', 'IMGROW0', 'IMGCOL0',
        >>>     'TEMPCCD', 'TEMPHOUS']
            <Table masked=True length=15>
                 TIME      MJF    MNF   COMMCNT GLBSTAT IMGTYPE IMGROW0 IMGCOL0 TEMPCCD TEMPHOUS
               float64    uint32 uint32  uint8   uint8   uint8   int16   int16   int16   int16
            ------------- ------ ------ ------- ------- ------- ------- ------- ------- --------
            684089000.844  78006     28       0       0       7      --      --      --       --
            684089001.869  78006     32       0       0       4     469    -332      --       --
            684089002.894  78006     36       0       0       5      --      --     -20       83
            684089003.919  78006     40       0       0       6      --      --      --       --
            684089004.944  78006     44       0       0       7      --      --      --       --
            684089005.969  78006     48       0       0       4     469    -332      --       --
            684089006.994  78006     52       0       0       5      --      --     -20       83
            684089008.019  78006     56       0       0       6      --      --      --       --
            684089009.044  78006     60       0       0       7      --      --      --       --
            684089010.069  78006     64       0       0       4     469    -332      --       --
            684089011.094  78006     68       0       0       5      --      --     -20       83
            684089012.119  78006     72       0       0       6      --      --      --       --
            684089013.144  78006     76       0       0       7      --      --      --       --
            684089014.169  78006     80       0       0       4     469    -332      --       --
            684089015.194  78006     84       0       0       5      --      --     -20       83

        >>> img['IMG'].data[1]
        masked_BaseColumn(data =
         [[60.0 97.0 70.0 120.0 74.0 111.0 103.0 108.0]
         [67.0 90.0 144.0 96.0 88.0 306.0 82.0 67.0]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]],
                          mask =
         [[False False False False False False False False]
         [False False False False False False False False]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]],
                    fill_value = 1e+20)

        >>> img['IMG'].data[2]
        masked_BaseColumn(data =
         [[-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [76.0 81.0 160.0 486.0 449.0 215.0 88.0 156.0]
         [68.0 91.0 539.0 483.0 619.0 412.0 105.0 77.0]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]],
                          mask =
         [[ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [False False False False False False False False]
         [False False False False False False False False]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]],
                    fill_value = 1e+20)

        >>> img['IMG'].data[3]
        masked_BaseColumn(data =
         [[-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [86.0 101.0 408.0 344.0 556.0 343.0 122.0 67.0]
         [196.0 195.0 114.0 321.0 386.0 115.0 69.0 189.0]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]],
                          mask =
         [[ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [False False False False False False False False]
         [False False False False False False False False]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]],
                    fill_value = 1e+20)

        >>> img['IMG'].data[4]
        Out[10]:
        masked_BaseColumn(data =
         [[-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [-- -- -- -- -- -- -- --]
         [67.0 61.0 67.0 176.0 99.0 72.0 79.0 88.0]
         [70.0 62.0 101.0 149.0 163.0 89.0 60.0 76.0]],
                          mask =
         [[ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [ True  True  True  True  True  True  True  True]
         [False False False False False False False False]
         [False False False False False False False False]],
                    fill_value = 1e+20)

    :param start: timestamp interpreted as a Chandra.Time.DateTime
    :param stop: timestamp interpreted as a Chandra.Time.DateTime
    :param level0: bool.
        Implies combine=True, adjust_time=True, calibrate=True
    :param combine: bool.
        If True, multiple ACA packets are combined to form an image (depending on size),
        If False, ACA packets are not combined, resulting in multiple lines for 6x6 and 8x8 images.
    :param adjust_time: bool
        If True, half the integration time is subtracted
    :param calibrate: bool
        If True, pixel values will be 'value * imgscale / 32 - 50' and temperature values will
        be: 0.4 * value + 273.15
    :param blobs: bool or dict
        If set, data is assembled from MAUDE blobs. If it is a dictionary, it must be the
        output of maude.get_blobs ({'blobs': ... }).
    :param frames: bool or dict
        If set, data is assembled from MAUDE frames. If it is a dictionary, it must be the
        output of maude.get_frames ({'data': ... }).
    :param dtype: np.dtype. Optional.
        the dtype to use when creating the resulting table. This is useful to add columns
        including MSIDs that are present in blobs. If used with frames, most probably you will get
        and empty column. This option is intended to augment the default dtype. If a more
        restrictive dtype is used, a KeyError can be raised.
    :param maude_kwargs: keyword args passed to maude
    :return: astropy.table.Table
    """
    if not blobs and not frames:
        frames = True

    assert (blobs and not frames) or (
        frames and not blobs
    ), "Specify only one of 'frames' or blobs"

    if level0:
        adjust_time = True
        combine = True
        calibrate = True

    date_start, date_stop = DateTime(start), DateTime(
        stop
    )  # ensure input is proper date
    if 24 * (date_stop - date_start) > 3:
        raise ValueError(
            f"Requested {24 * (date_stop - date_start)} hours of telemetry. "
            "Maximum allowed is 3 hours at a time"
        )

    stop_pad = 0
    if adjust_time:
        stop_pad += 2.0 / 86400  # time will get shifted...
    if combine:
        stop_pad += 3.08 / 86400  # there can be trailing frames

    if frames:
        n = int(np.ceil(86400 * (date_stop - date_start) / 300))
        dt = (date_stop - date_start) / n
        batches = [
            (date_start + i * dt, date_start + (i + 1) * dt) for i in range(n)
        ]  # 0.0001????
        aca_packets = []
        for t1, t2 in batches:
            maude_result = (
                frames if (type(frames) is dict and "data" in frames) else None
            )
            raw_aca_packets = get_raw_aca_packets(
                t1, t2 + stop_pad, maude_result=maude_result, **maude_kwargs
            )
            packets = _get_aca_packets(
                raw_aca_packets,
                t1,
                t2,
                combine=combine,
                adjust_time=adjust_time,
                calibrate=calibrate,
                dtype=dtype,
            )
            aca_packets.append(packets)
        aca_data = vstack(aca_packets)
    else:
        maude_result = blobs if (type(blobs) is dict and "blobs" in blobs) else None
        merged_blobs = get_raw_aca_blobs(
            date_start, date_stop + stop_pad, maude_result=maude_result, **maude_kwargs
        )["blobs"]
        aca_packets = [
            [blob_to_aca_image_dict(b, i) for b in merged_blobs] for i in range(8)
        ]
        aca_data = _get_aca_packets(
            aca_packets,
            date_start,
            date_stop + stop_pad,
            combine=combine,
            adjust_time=adjust_time,
            calibrate=calibrate,
            blobs=True,
            dtype=dtype,
        )
        aca_data = aca_data[(aca_data["TIME"] >= start) & (aca_data["TIME"] < stop)]
    return aca_data

def _get_aca_packets(
    aca_packets,
    start,
    stop,
    combine=False,
    adjust_time=False,
    calibrate=False,
    blobs=False,
    dtype=None,
):
    """
    This is a convenience function that splits get_aca_packets for testing without MAUDE.
    Same arguments as get_aca_packets plus aca_packets, the raw ACA 225-byte packets.

    NOTE: This function has a side effect. It adds decom_packets to the input aca_packets.
    """
    start, stop = DateTime(start), DateTime(stop)  # ensure input is proper date

    if not blobs:
        # this adds TIME, MJF, MNF and VCDUCTR, which is already there in the blob dictionary
        aca_packets["decom_packets"] = [
            unpack_aca_telemetry(a) for a in aca_packets["packets"]
        ]
        for i in range(len(aca_packets["decom_packets"])):
            for j in range(8):
                aca_packets["decom_packets"][i][j]["TIME"] = aca_packets["TIME"][i]
                aca_packets["decom_packets"][i][j]["MJF"] = aca_packets["MJF"][i]
                aca_packets["decom_packets"][i][j]["MNF"] = aca_packets["MNF"][i]
                if "VCDUCTR" in aca_packets:
                    aca_packets["decom_packets"][i][j]["VCDUCTR"] = aca_packets[
                        "VCDUCTR"
                    ][i]
                aca_packets["decom_packets"][i][j]["IMGNUM"] = j

        aca_packets = [[f[i] for f in aca_packets["decom_packets"]] for i in range(8)]

    if combine:
        aca_packets = sum(
            [[_combine_aca_packets(g) for g in _group_packets(p)] for p in aca_packets],
            [],
        )
    else:
        aca_packets = [
            _combine_aca_packets([row]) for slot in aca_packets for row in slot
        ]
    table = _aca_packets_to_table(aca_packets, dtype=dtype)

    if calibrate:
        for k in ["TEMPCCD", "TEMPSEC", "TEMPHOUS", "TEMPPRIM"]:
            table[k] = 0.4 * table[k].astype(np.float32) + 273.15

    # IMGROW0/COL0 are actually the row/col of pixel A1, so we just copy them
    table["IMGROW_A1"] = table["IMGROW0"]
    table["IMGCOL_A1"] = table["IMGCOL0"]

    # if the image is embedded in an 8x8 image, row/col of the 8x8 shifts for sizes 4x4 and 6x6
    table["IMGROW0_8X8"] = table["IMGROW_A1"]
    table["IMGCOL0_8X8"] = table["IMGCOL_A1"]
    table["IMGROW0_8X8"][table["IMGTYPE"] < 4] -= 2
    table["IMGCOL0_8X8"][table["IMGTYPE"] < 4] -= 2

    # and the usual row/col needs to be adjusted only for 6x6 images
    table["IMGROW0"][table["IMGTYPE"] == 1] -= 1
    table["IMGCOL0"][table["IMGTYPE"] == 1] -= 1
    table["IMGROW0"][table["IMGTYPE"] == 2] -= 1
    table["IMGCOL0"][table["IMGTYPE"] == 2] -= 1

    table["INTEG"] = table["INTEG"] * 0.016
    table["END_INTEG_TIME"] = table["TIME"] + table["INTEG"]
    if adjust_time:
        dt = table["INTEG"] / 2 + 1.025
        table["TIME"] -= dt
        table["END_INTEG_TIME"] -= dt

    if calibrate:
        if "IMG" in table.colnames:
            table["IMG"] = (
                table["IMG"] * table["IMGSCALE"][:, np.newaxis, np.newaxis] / 32 - 50
            )

    table = table[(table["TIME"] >= start.secs) * (table["TIME"] < stop.secs)]
    if dtype:
        table = table[dtype.names]
    return table

def get_aca_images(start, stop, **maude_kwargs):
    """
    Fetch ACA image telemetry

    :param start: timestamp interpreted as a Chandra.Time.DateTime
    :param stop: timestamp interpreted as a Chandra.Time.DateTime
    :param maude_kwargs: keyword args passed to maude
    :return: astropy.table.Table
    """
    return get_aca_packets(start, stop, level0=True, **maude_kwargs)

######################
# blob-based functions
######################

def get_raw_aca_blobs(start, stop, maude_result=None, **maude_kwargs):
    """
    Fetch MAUDE blobs and group them according to the underlying 225-byte ACA packets.

    If the first minor frame in a group of four ACA packets is within (start, stop),
    the three following minor frames are included if present.

    returns a dictionary with keys ['TIME', 'MNF', 'MJF', 'packets', 'flags'].
    These correspond to the minor frame time, minor frame count, major frame count,
    the list of packets, and flags returned by MAUDE respectively.

    This is to blobs what `get_raw_aca_packets` is to frames.

    :param start: timestamp interpreted as a Chandra.Time.DateTime
    :param stop: timestamp interpreted as a Chandra.Time.DateTime
    :param maude_result: the result of calling maude.get_blobs. Optional.
    :param maude_kwargs: keyword args passed to maude.get_frames()
    :return: dict
        {'blobs': [], 'names': np.array([]), 'types': np.array([])}
    """
    date_start, date_stop = DateTime(start), DateTime(
        stop
    )  # ensure input is proper date
    stop_pad = 1.5 / 86400  # padding at the end in case of trailing partial ACA packets

    if maude_result is None:
        maude_blobs = maude.get_blobs(
            start=date_start, stop=date_stop + stop_pad, **maude_kwargs
        )
    else:
        maude_blobs = maude_result

    aca_block_start = [
        ACA_SLOT_MSID_LIST[1][3]["sizes"] in [c["n"] for c in b["values"]]
        for b in maude_blobs["blobs"]
    ]

    names = maude_blobs["names"].copy()
    types = maude_blobs["types"].copy()
    if not np.any(aca_block_start):
        return {
            "blobs": [],
            "names": names,
            "types": types,
        }

    blobs = copy.deepcopy(maude_blobs["blobs"][np.argwhere(aca_block_start).min() :])
    if len(blobs) % 4:
        blobs = blobs[: -(len(blobs) % 4)]
    for b in blobs:
        b["values"] = {v["n"]: v["v"] for v in b["values"]}

    merged_blobs = []
    for i in range(0, len(blobs), 4):
        b = {"time": blobs[i]["time"]}
        # blobs are merged in reverse order so the frame counters are the one in the first blob.
        for j in range(4)[::-1]:
            b.update(blobs[i + j]["values"])
        merged_blobs.append(b)

    result = {
        "blobs": [b for b in merged_blobs if b["time"] < date_stop.secs],
        "names": names,
        "types": types,
    }
    return result

def blob_to_aca_image_dict(blob, imgnum, pea=1):
    """
    Assemble ACA image MSIDs from a blob into a dictionary.

    This does to blobs what unpack_aca_telemetry does to frames, but for a single image.

    :param blob:
    :param imgnum:
    :param pea:
    :return:
    """
    global_msids = ACA_MSID_LIST[pea]
    slot_msids = ACA_SLOT_MSID_LIST[pea][imgnum]
    glbstat_bits = np.unpackbits(np.array(blob[global_msids["status"]], dtype=np.uint8))
    comm_count_bits = np.unpackbits(
        np.array(blob[global_msids["cmd_count"]], dtype=np.uint8)
    )
    comm_prog_bits = np.unpackbits(
        np.array(blob[global_msids["cmd_progress"]], dtype=np.uint8)
    )
    result = {
        "TIME": float(blob["time"]),
        "MJF": int(blob["CVCMJCTR"]),
        "MNF": int(blob["CVCMNCTR"]),
        "VCDUCTR": int(blob["CVCDUCTR"]),
        "IMGNUM": imgnum,
        "IMGTYPE": int(blob[slot_msids["sizes"]]),
        # 'IMGFID': '1' == blob[slot_msids['fiducial_flag']],
        # 'IMGNUM': imgnum,
        # 'IMGFUNC': int(blob[slot_msids['image_function']]),
        # 'IMGSTAT': int(blob[slot_msids['image_status']]),
        "pixels": np.array(
            [int(blob[pixel]) for pixel in slot_msids["pixels"] if pixel in blob]
        ),
        "AAPIXTLM": blob.get(global_msids["pixel_telemetry_type"], "ORIG"),
        "AABGDTYP": blob.get(global_msids["dynamic_background_type"], "FLAT"),
        "INTEG": int(blob[global_msids["integration_time"]]),
        "GLBSTAT": int(blob[global_msids["status"]]),
        "HIGH_BGD": bool(glbstat_bits[0]),
        "RAM_FAIL": bool(glbstat_bits[1]),
        "ROM_FAIL": bool(glbstat_bits[2]),
        "POWER_FAIL": bool(glbstat_bits[3]),
        "CAL_FAIL": bool(glbstat_bits[4]),
        "COMM_CHECKSUM_FAIL": bool(glbstat_bits[5]),
        "RESET": bool(glbstat_bits[6]),
        "SYNTAX_ERROR": bool(glbstat_bits[7]),
        "COMMCNT": _packbits(comm_count_bits[1:6]),
        "COMMCNT_SYNTAX_ERROR": comm_count_bits[6],
        "COMMCNT_CHECKSUM_FAIL": comm_count_bits[7],
        "COMMPROG": int(blob[global_msids["cmd_progress_to_go"]]),
        "COMMPROG_REPEAT": _packbits(comm_prog_bits[6:8]),
    }

    if result["IMGTYPE"] in [0, 1, 4]:
        imgstat_bits = np.array(
            [
                blob[slot_msids["saturated_pixel"]],
                blob[slot_msids["defective_pixel"]],
                blob[slot_msids["quad_bound"]],
                blob[slot_msids["common_col"]],
                blob[slot_msids["multi_star"]],
                blob[slot_msids["ion_rad"]],
            ]
        ).astype(int)
        imgstat = int(_packbits(imgstat_bits))

        result.update(
            {
                "IMGFID": "1" == blob[slot_msids["fiducial_flag"]],
                "IMGNUM": imgnum,
                "IMGFUNC": int(blob[slot_msids["image_function"]]),
                "IMGSTAT": imgstat,
                "SAT_PIXEL": bool(int(blob[slot_msids["saturated_pixel"]])),
                "DEF_PIXEL": bool(int(blob[slot_msids["defective_pixel"]])),
                "QUAD_BOUND": bool(int(blob[slot_msids["quad_bound"]])),
                "COMMON_COL": bool(int(blob[slot_msids["common_col"]])),
                "MULTI_STAR": bool(int(blob[slot_msids["multi_star"]])),
                "ION_RAD": bool(int(blob[slot_msids["ion_rad"]])),
                "IMGROW0": int(blob[slot_msids["rows"]]),
                "IMGCOL0": int(blob[slot_msids["cols"]]),
                # 'IMGSCALE': float(blob[slot_msids['scale_factor']]),  # this is scale / 32
                "IMGSCALE": np.round(
                    float(blob[slot_msids["scale_factor"]]) * 32
                ).astype(int),
                "BGDAVG": int(blob[slot_msids["background_avg"]]),
            }
        )

    if result["IMGTYPE"] in [2, 5]:
        bgd_stat_pixels = [int(blob[pixel]) for pixel in slot_msids["bgd_stat_pixels"]]
        result.update(
            {
                "BGDRMS": int(blob[slot_msids["background_rms"]]),
                # 'TEMPCCD': float(blob[slot_msids['ccd_temperature']]),  # this is 0.4 * T
                # 'TEMPHOUS': float(blob[slot_msids['housing_temperature']]),  # this is 0.4 * T
                # 'TEMPPRIM': float(blob[slot_msids['primary_temperature']]),  # this is 0.4 * T
                # 'TEMPSEC': float(blob[slot_msids['secondary_temperature']]),  # this is 0.4 * T
                "TEMPCCD": np.round(
                    float(blob[slot_msids["ccd_temperature"]]) / 0.4
                ).astype(int),
                "TEMPHOUS": np.round(
                    float(blob[slot_msids["housing_temperature"]]) / 0.4
                ).astype(int),
                "TEMPPRIM": np.round(
                    float(blob[slot_msids["primary_temperature"]]) / 0.4
                ).astype(int),
                "TEMPSEC": np.round(
                    float(blob[slot_msids["secondary_temperature"]]) / 0.4
                ).astype(int),
                "BGDSTAT": int(_packbits(bgd_stat_pixels)),
                "BGDSTAT_PIXELS": bgd_stat_pixels,
            }
        )
    if result["IMGTYPE"] in [6, 7]:
        result.update(
            {
                "DIAGNOSTIC": (
                    0,
                    0,
                    0,
                    0,
                    0,
                    0,
                )  # not set, and is not used downstream yet.
            }
        )

    if slot_msids["centroid_ang_y"] in blob:
        result.update(
            {
                "YAGS": float(blob[slot_msids["centroid_ang_y"]]),
                "ZAGS": float(blob[slot_msids["centroid_ang_z"]]),
            }
        )

    if "AOATTQT1" in blob:
        result["AOATTQT1"] = float(blob["AOATTQT1"])
    if "AOATTQT2" in blob:
        result["AOATTQT2"] = float(blob["AOATTQT2"])
    if "AOATTQT3" in blob:
        result["AOATTQT3"] = float(blob["AOATTQT3"])
    if "AOATTQT4" in blob:
        result["AOATTQT4"] = float(blob["AOATTQT4"])

    if "COBSRQID" in blob:
        result["COBSRQID"] = int(blob["COBSRQID"])

    return result


"""
编写一个程序，它接受一系列以逗号分隔的4位二进制数作为输入，然后检查它们是否可被5整除。可被5整除的数字将按逗号分隔的顺序打印。

例子：

0100,0011,1010,1001

那么输出应该是：

1010

注意：假设数据是由控制台输入的。
"""
ls = input("please input").split(",")
ls2 = []
ls3 = []
for i in ls:
    j = int(i[0]) * (2 ** 3) + int(i[1]) * (2 ** 2) + int(i[2]) * (2 ** 1) + int(i[3]) * (2 ** 0)
    if (j % 5 == 0):
        ls2.append(j)
        ls3.append(i)

print(ls2)
print(ls3)


# coding=utf-8
""" Module implements different path pruning strategies
"""
from collections import defaultdict
import random
import functools

from ..utils.exceptions import InvalidConfigException

_RANDOM = ['random', 'rand']
_SHORTEST = ['shortest', 'short', 'kshortest', 'k-shortest', 'kshort',
             'k-short']

def chooserand(pptc, numPaths):
    """ Chooses a number of paths uniformly at random

    :param pptc: paths per commodity
    :param numPaths: number of paths to pick per commodity
    :return: the new (chosen) paths per each commodity
    :rtype: dict
    """
    newppk = {}
    for comm in pptc:
        if len(pptc[comm]) > numPaths:
            newppk[comm] = random.sample(pptc[comm], numPaths)
        else:
            newppk[comm] = pptc[comm]
    return newppk

def sortPathsPerCommodity(pptc, key=None, inplace=True):
    """
    Sort paths per commodity

    :param pptc: paths per traffic class
    :param key: criteria to sort by. If none, path length is used
    :param inplace: sort in place. If False, new sorted ppk is returned.
    :return: New ppk if *inplace=False* otherwise None
    """
    if key is None:
        key = len
    if inplace:
        for tc in pptc:
            pptc[tc].sort(key=len)
    else:
        newppk = {}
        for tc in pptc:
            newppk[tc] = sorted(pptc[tc], key=key)
        return newppk

def kShortestPaths(pptc, numPaths, needsSorting=True, inplace=True):
    """ Chooses K shortest paths
    :param pptc: paths per commodity
    :param numPaths: number of paths to choose (k) per commodity
    :param needsSorting: whether we need to sort the paths first
    :param inplace: if *needsSorting* is True, whether to sort the ppk in
        place or make a copy
    :return: the new (chosen) paths per commodity
    :rtype: dict
    """
    newppk = None
    if needsSorting:
        newppk = sortPathsPerCommodity(pptc, key=len, inplace=inplace)
    if newppk is None:
        newppk = pptc
    result = {}
    for comm in pptc:
        result[comm] = newppk[comm][:numPaths]
    return result

def filterPaths(pptc, func):
    """
    Filter paths using a function.

    :param pptc: paths per traffic class
    :param func: function to be applied to each path
    :return: new paths per commodity with paths for which *func* returned a
        true value
    """
    assert (hasattr(func, '__call__'))
    result = defaultdict(lambda: [])
    for tc in pptc:
        for path in pptc[tc]:
            if func(path):
                result[tc].append(path)
    return result

def getSelectFunction(strName, kwargs=None):
    """
    Return the path selection function based on name.
    Allows passing of additional keyword arguments, so that the returned function can satisfy the following signature::
        function(pptc, selectNumber)

    :param strName: the name of the function
    :param kwargs: a dictionary of keyword arguements to be passed to the function
    :return: the callable object with
    :raise: InvalidConfigException
        if the name passed in is not supported

    Supported names so far: 'random' and 'shortest' For example::

        f = getSelectFunction('random')
        pptc = f(pptc, 5)

    will give you 5 paths per traffic class, randomly chosen

    """
    if kwargs is None:
        kwargs = {}
    if strName.lower() in _RANDOM:
        return functools.partial(chooserand, **kwargs)
    elif strName.lower() in _SHORTEST:
        return functools.partial(kShortestPaths, **kwargs)
    else:
        raise InvalidConfigException("Unknown select method")


import logging
from celery import shared_task, Task
from django.db.models import F
from .models import FormEntry, ShortLink
from .actions import register_new_lead, save_get_geolocal

logger = logging.getLogger(__name__)

class BaseTaskWithRetry(Task):
    autoretry_for = (Exception,)
    #                                           seconds
    retry_kwargs = {'max_retries': 5, 'countdown': 60 * 5 }
    retry_backoff = True

@shared_task
def persist_leads():
    logger.debug("Starting persist_leads")
    entries = FormEntry.objects.filter(storage_status='PENDING')
    for entry in entries:
        form_data = entry.toFormData()
        result = register_new_lead(form_data)
        if result is not None and result != False:
            save_get_geolocal(entry, form_data)

    return True

@shared_task(bind=True, base=BaseTaskWithRetry)
def persist_single_lead(self, form_data):
    logger.debug("Starting persist_single_lead")
    entry = register_new_lead(form_data)
    if entry is not None and entry != False:
        save_get_geolocal(entry, form_data)

    return True

@shared_task(bind=True, base=BaseTaskWithRetry)
def update_link_viewcount(self, slug):
    logger.debug("Starting update_link_viewcount")
    ShortLink.objects.filter(slug=slug).update(hits=F('hits') + 1)


__author__ = 'Konstantinos Tselepakis'

from ABSA.aspect_extraction.Chunking import extract_chunks
from ABSA.aspect_extraction.Frequencies import frequency_pruning
from ABSA.aspect_extraction.Ontology import ontology_pruning
import time

def aspect_extraction(calculated_reviews, reviews,reviews_train, root):
    """Extracts possible aspects and updates the calculated reviews dictionary."""

    # Returns a dictionary of id:possible_aspects pairs.
    start_time = time.time()
    #aspects_chunks = extract_chunks(calculated_reviews)
    extract_chunks(calculated_reviews)
    print("--- Chunking: %s seconds ---" % (time.time() - start_time))

    start_time = time.time()
    aspects_frequencies = frequency_pruning( calculated_reviews, reviews )
    print("--- Frequency pruning: %s seconds ---" % (time.time() - start_time))

    # Returns a dictionary of id:pruned_possible_aspects pairs.
    # Takes as parameters the root and the size of the main ontology.
    start_time = time.time()
    ontology_pruning(root, 3, calculated_reviews, reviews, aspects_frequencies, reviews_train)
    print("--- Ontology pruning: %s seconds ---" % (time.time() - start_time))
    #aspects_ontology_pruned = aspects_frequency_pruned

    # for review in reviews:
    #     #print(review.id)
    #     print(calculated_reviews[review.id].text)
    #     print(calculated_reviews[review.id].tagged_text)
    #     print(review.aspectTerms)
    #     print( calculated_reviews[review.id].aspectTerms )
    #     print()

    return calculated_reviews


import numpy as np
from sklearn.metrics import  accuracy_score,f1_score,precision_score,recall_score,confusion_matrix
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn import ensemble
from scipy.io import loadmat
from sklearn.grid_search import GridSearchCV
import h5py
def results(X,y,clf,stdSlr):
	w=np.isnan(X)
	X[w]=0
	w=np.isinf(X)
	X[w]=0
	X = stdSlr.transform(X)
	pred=clf.predict(X)
	pred=pred.ravel()
	pred=pred.tolist()
	y=y.ravel()
	y=y.tolist()
	acc=accuracy_score(y,pred)
	prec = precision_score(y, pred)
	rec = recall_score(y, pred)
	f1=f1_score(y,pred,average='weighted')
	probs=clf.predict_proba(X)
	return acc,f1,prec,rec,pred,probs

def classify(X,y):

	w=np.isnan(X)
	X[w]=0
	w=np.isinf(X)
	X[w]=0
	val_split=5
	stdSlr = StandardScaler().fit(X)
	X = stdSlr.transform(X)
	estimators=[50*i for i in range(1,6)]
	parameters={'n_estimators':estimators}

	clf = GridSearchCV(ensemble.RandomForestClassifier(class_weight='balanced'),parameters,cv=val_split)
	clf.fit(X,y)
	return clf,stdSlr

def process_hdf(file,type1,i):
	X1=file['Fold_'+str(i)]['train'][type1+'_train_1']
	arr=np.empty(X1.shape,dtype='float32')
	X1.read_direct(arr)
	X1=arr

	X2=file['Fold_'+str(i)]['train'][type1+'_train_2']
	arr=np.empty(X2.shape,dtype='float32')
	X2.read_direct(arr)
	X2=arr
	if type1=='texture':
		X1=np.delete(X1,0,0)
		X2=np.delete(X2,0,0)
	y_train=[0]*X1.shape[0]+[1]*X2.shape[0]
	y_train=np.asarray(y_train)
	X_train=np.vstack((X1,X2))

	X1=file['Fold_'+str(i)]['test'][type1+'_test_1']
	arr=np.empty(X1.shape,dtype='float32')
	X1.read_direct(arr)
	X1=arr

	if type1=='fine_tuned':
		X2=file['Fold_'+str(i)]['test'][type1+'_test_']
	else:
		X2=file['Fold_'+str(i)]['test'][type1+'_test_2']
	arr=np.empty(X2.shape,dtype='float32')
	X2.read_direct(arr)
	X2=arr
	if type1=='texture':
		X1=np.delete(X1,0,0)
		X2=np.delete(X2,0,0)
	y_test=[0]*X1.shape[0]+[1]*X2.shape[0]
	y_test=np.asarray(y_test)
	X_test=np.vstack((X1,X2))
	clf,stdSlr=classify(X_train,y_train)
	return results(X_test,y_test,clf,stdSlr)

def analyse(marker):
	acc1=np.zeros((5,6))
	f11=np.zeros((5,6))
	prediction_cnn=[]
	probability_cnn=np.zeros((1,2))
	prediction_vbow=[]
	probability_vbow=np.zeros((1,2))
	prediction_texture=[]
	probability_texture=np.zeros((1,2))
	prediction_fine_tuned=[]
	probability_fine_tuned=np.zeros((1,2))
	prediction_scratch=[]
	probability_scratch=np.zeros((1,2))
	prediction_cell_graphs=[]
	probability_cell_graphs=np.zeros((1,2))

	names=[]
	file=h5py.File('/home/aritra/Documents/research/GE_project/data/'+marker+'_features.hdf5','r')
	file1=h5py.File('/home/aritra/Documents/research/GE_project/data/'+marker+'_cnn_features.hdf5','r')
	f=loadmat('/home/aritra/Documents/research/GE_project/data/dapi_cell_graph_features.mat')
	y=[]
	for i in range(1,6):
		names1=file['Fold_'+str(i)]['test']['test_names_1']
		arr=np.empty(names1.shape,dtype='S40')
		names1.read_direct(arr)
		names1=[]
		for j in range(len(arr)):
			names1.append(arr[i][0][:15])
		names=names+names1
		names2=file['Fold_'+str(i)]['test']['test_names_2']
		arr=np.empty(names2.shape,dtype='S40')
		names2.read_direct(arr)
		names2=[]
		for j in range(len(arr)):
			names2.append(arr[i][0][:15])
		names=names+names2
		y=y+[0]*len(names1)+[1]*len(names2)

		type1='texture'
		acc,f1,_,_,pred,probs=process_hdf(file,type1,i)
		acc1[i-1,0]=acc
		f11[i-1,0]=f1
		for j in pred:
			prediction_texture.append(j)
		probability_texture=np.vstack((probability_texture,probs))

		type1='vbow'
		acc,f1,_,_,pred,probs=process_hdf(file,type1,i)
		acc1[i-1,1]=acc
		f11[i-1,1]=f1
		for j in pred:
			prediction_vbow.append(j)
		probability_vbow=np.vstack((probability_vbow,probs))

		if marker=='dapi':
			acc,f1,pred,probs=cell_graph_analysis(f,i)
			acc1[i-1,2]=acc
			f11[i-1,2]=f1
			for j in pred:
				prediction_cell_graphs.append(j)
			probability_cell_graphs=np.vstack((probability_cell_graphs,probs))
		else:
			acc1[i-1,2]=-100
			f11[i-1,2]=-100

		type1='scratch'
		acc,f1,_,_,pred,probs=process_hdf(file1,type1,i)
		acc1[i-1,3]=acc
		f11[i-1,3]=f1
		for j in pred:
			prediction_cnn.append(j)
		probability_scratch=np.vstack((probability_scratch,probs))

		type1='cnn'
		acc,f1,_,_,pred,probs=process_hdf(file,type1,i)
		acc1[i-1,4]=acc
		f11[i-1,4]=f1
		for j in pred:
			prediction_scratch.append(j)
		probability_cnn=np.vstack((probability_cnn,probs))

		type1='fine_tuned'
		acc,f1,_,_,pred,probs=process_hdf(file1,type1,i)
		acc1[i-1,5]=acc
		f11[i-1,5]=f1
		for j in pred:
			prediction_fine_tuned.append(j)
		probability_fine_tuned=np.vstack((probability_fine_tuned,probs))

	probability_cnn=np.delete(probability_cnn,0,0)
	probability_scratch=np.delete(probability_scratch,0,0)
	probability_fine_tuned=np.delete(probability_fine_tuned,0,0)
	probability_vbow=np.delete(probability_vbow,0,0)
	probability_texture=np.delete(probability_texture,0,0)
	if marker=='dapi':
		probability_cell_graphs=np.delete(probability_cell_graphs,0,0)

	write_predictions(marker,prediction_scratch,probability_scratch,'scratch',names,y)
	write_predictions(marker,prediction_cnn,probability_cnn,'pre_trained',names,y)
	write_predictions(marker,prediction_fine_tuned,probability_fine_tuned,'fine_tuned',names,y)
	write_predictions(marker,prediction_vbow,probability_vbow,'vbow',names,y)
	write_predictions(marker,prediction_texture,probability_texture,'texture',names,y)
	if marker=='dapi':
		write_predictions(marker,prediction_cell_graphs,probability_cell_graphs,'cell_graphs',names,y)
	return acc1,f11

def write_predictions(marker,prediction_scratch,probability_scratch,type1,names,y):
	f=open('../results/original_images/confusion_matrix_'+type1+'_'+marker+'.txt','w')
	f.write('Confusion matrix: \n')
	conf=confusion_matrix(y,prediction_scratch,labels=[0,1])
	f.write(str(conf[0,0])+' '+str(conf[0,1])+'\n')
	f.write(str(conf[1,0])+' '+str(conf[1,1]))
	f.close()
	prob0=probability_scratch[:,0]
	prob1=probability_scratch[:,1]
	d={'Image_name':names,'Actual_label':y,'Predicted_label':prediction_scratch,'Prob0':prob0.ravel(),'Prob1':prob1.ravel()}
	df=pd.DataFrame(data=d)
	df.to_csv('../results/original_images/'+type1+'_predictions_'+marker+'.csv',delimiter=',',index=False)

def cell_graph_analysis(f,i):
	X1=f['features_fold_train_'+str(i)+'_1']
	X2=f['features_fold_train_'+str(i)+'_2']
	X_train=np.vstack((X1,X2))
	y_train=[0]*X1.shape[0]+[1]*X2.shape[0]
	y_train=np.asarray(y_train)
	X1=f['features_fold_test_'+str(i)+'_1']
	X2=f['features_fold_test_'+str(i)+'_2']
	X_test=np.vstack((X1,X2))
	y_test=[0]*X1.shape[0]+[1]*X2.shape[0]
	y_test=np.asarray(y_test)
	clf,stdSlr=classify(X_train,y_train)
	acc,f1,_,_,pred,probs=results(X_test,y_test,clf,stdSlr)
	return acc,f1,pred,probs

if __name__=='__main__':
	accm=np.zeros((6,6))
	accs=np.zeros((6,6))
	f1m=np.zeros((6,6))
	f1s=np.zeros((6,6))

	marker='E_cad'
	acc,f1=analyse(marker)
	accm[0,:]=np.mean(acc,axis=0)
	accs[0,:]=np.std(acc,axis=0)
	f1m[0, :] = np.mean(f1,axis=0)
	f1s[0, :] = np.std(f1,axis=0)
	marker='beta_actin'
	acc,f1=analyse(marker)
	accm[1,:]=np.mean(acc,axis=0)
	accs[1,:]=np.std(acc,axis=0)
	f1m[1,:]=np.mean(f1,axis=0)
	f1s[1,:]=np.std(f1,axis=0)
	marker='CD31'
	acc,f1=analyse(marker)
	accm[2,:]=np.mean(acc,axis=0)
	accs[2,:]=np.std(acc,axis=0)
	f1m[2,:]=np.mean(f1,axis=0)
	f1s[2,:]=np.std(f1,axis=0)

	marker='S6'
	acc,f1=analyse(marker)
	accm[3,:]=np.mean(acc,axis=0)
	accs[3,:]=np.std(acc,axis=0)
	f1m[3,:]=np.mean(f1,axis=0)
	f1s[3,:]=np.std(f1,axis=0)
	marker='VHE'
	acc,f1=analyse(marker)
	accm[4,:]=np.mean(acc,axis=0)
	accs[4,:]=np.std(acc,axis=0)
	f1m[4,:]=np.mean(f1,axis=0)
	f1s[4,:]=np.std(f1,axis=0)

	marker='dapi'
	acc,f1=analyse(marker)
	accm[5,:]=np.mean(acc,axis=0)
	accs[5,:]=np.std(acc,axis=0)
	f1m[5,:]=np.mean(f1,axis=0)
	f1s[5,:]=np.std(f1,axis=0)

	accm=np.around(accm,decimals=2)
	accs=np.around(accs,decimals=2)
	f1m=np.around(f1m,decimals=2)
	f1s=np.around(f1s,decimals=2)
	markers=['E_cad','Beta_actin','CD31','S6','VHE','dapi']
	type1=['Texture-statistics','VBOW','Cell-graphs','Trained','Pre-trained','Fine-tuned']

	df=pd.DataFrame(data=accm,index=markers,columns=type1)
	df.to_csv('../results/original_images/metrics_acc_mean.csv',delimiter=',')

	df=pd.DataFrame(data=accs,index=markers,columns=type1)
	df.to_csv('../results/original_images/metrics_acc_std.csv',delimiter=',')

	df=pd.DataFrame(data=f1m,index=markers,columns=type1)
	df.to_csv('../results/original_images/metrics_f1_mean.csv',delimiter=',')

	df=pd.DataFrame(data=f1s,index=markers,columns=type1)
	df.to_csv('../results/original_images/metrics_f1_std.csv',delimiter=',')


import json
import os
from datetime import timedelta, datetime

from django.conf import settings

from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
from django.core.mail import EmailMultiAlternatives
from django.core.management.base import BaseCommand
from django.template.loader import render_to_string
from django_apscheduler.jobstores import DjangoJobStore

from NewsPaper.models import Post

def mail_sender():
    if os.path.exists('subscribers.json'):
        with open('subscribers.json', 'r', encoding='utf8') as f:
            info = json.load(f)
        post_list = Post.objects.filter(datetime__range=[datetime.now() - timedelta(days=7), datetime.now()])

        for cat, emails in info.items():

            html = render_to_string(
                'newspaper/sender_mail.html',
                {
                    'post_list': post_list,
                }
            )

            message = EmailMultiAlternatives(
                subject=f'Вот список новых Постов по категории "{cat}" за прошедшую неделю!',
                from_email='pten4ik99@yandex.ru',
                to=emails,
            )
            message.attach_alternative(html, 'text/html')
            message.send()
            print('Отправлено!')

class Command(BaseCommand):

    def handle(self, *args, **options):
        scheduler = BlockingScheduler(timezone=settings.TIME_ZONE)
        scheduler.add_jobstore(DjangoJobStore(), "default")

        scheduler.add_job(
            func=mail_sender,
            trigger=CronTrigger(week='*/1'),
            id='mail_sender',
            max_instances=1,
            replace_existing=True,
        )

        try:
            print('Задачник запущен')
            scheduler.start()
        except KeyboardInterrupt:
            scheduler.shutdown()
            print('Задачник остановлен')


import sublime, sublime_plugin, re, json, os

class Rainbowth(sublime_plugin.EventListener):
  def update_colors(self, view):
    cache_file_path = os.path.join(sublime.cache_path(), 'Rainbowth', 'Rainbowth' + '.cache')
    base_dir = sublime.packages_path()
    scheme_path = base_dir[:-8] + view.settings().get('color_scheme')
    scheme_name = scheme_path.split('/')[-1].split('.')[0]

    try:
      with open(cache_file_path, 'r') as cache_file:
        cache = json.load(cache_file)
    except (EnvironmentError, ValueError):
      cache = {}

    settings = sublime.load_settings('Rainbowth.sublime-settings')
    palettes = settings.get('palettes')
    self.colors = palettes.get(scheme_name, palettes['default'])
    if self.colors == cache.get(scheme_name, None):
      return

    with open(scheme_path, 'r') as scheme_file:
      scheme_xml = scheme_file.read()#.decode('utf-8')

    bg = re.search('background.+?g>(.+?)<', scheme_xml, re.DOTALL).group(1)
    bg = '#%06x' % max(1, (int(bg[1:], 16) - 1))
    fragment = '<dict><key>scope</key><string>rainbowth%d</string><key>settings</key><dict><key>background</key><string>' + bg + '</string><key>foreground</key><string>%s</string></dict></dict>'
    scheme_xml = re.sub('\t+<!-- rainbowth -->.+\n', '', scheme_xml)

    rainbowth = '\t<!-- rainbowth -->'
    for i, c in enumerate(self.colors):
      rainbowth += fragment % (i, c)

    scheme_xml = re.sub('</array>', rainbowth + '<!---->\n\t</array>', scheme_xml)
    with open(scheme_path, 'w') as scheme_file:
      scheme_file.write(scheme_xml)#.encode('utf-8'))
    cache[scheme_name] = self.colors

    cache_file_folder = os.path.split(cache_file_path)[0]
    if not os.path.exists(cache_file_folder):
      # ensure folder exists for cache file
      os.makedirs(cache_file_folder)

    with open(cache_file_path, 'w') as cache_file:
      json.dump(cache, cache_file)

  # plugins are not loaded properly after a hot exit
  # this causes problems with files opened automatically at boot
  def on_activated(self, view):
    if not view.settings().get('rainbowthed'):
      file_scope = view.scope_name(0)
      view.settings().set('lispy',
          file_scope.split('.')[1].split(' ')[0] in ['lisp', 'scheme', 'clojure'])
      if view.settings().get('lispy'):
        self.update_colors(view)
        self.on_modified(view, True)
        view.settings().set('rainbowthed', True)

  def on_modified(self, view, load = False):
    if not view.settings().get('lispy'):
      return

    if not hasattr(self, 'colors'):
      self.update_colors(view)

    source = view.substr(sublime.Region(0, view.size()))

    parens = [(sublime.Region(idx, idx + 1), char)
      for idx, char in enumerate(source[0:view.size()])
      if char in '()[]']

    level, depths = 0, [[sublime.Region(-1, 0)] for i in range(len(self.colors))]
    for region, char in parens:
      level += (char in '([') and -1 or 0
      depths[level % len(self.colors)].append(region)
      level += (char in ')]') and 1 or 0

    for i, regions in enumerate(depths):
      view.erase_regions('rainbowth%d' % i)
      view.add_regions('rainbowth%d' % i, regions, 'rainbowth%d' % i)


def area(a1, b1):
    mt2 = a1 * b1
    print(f'A área de um terreno {a1} x {b1} é de {mt2}m². ')

print('Controle de Terrenos')
print()
a = float(input('Largura (m): '))
b = float(input('Comprimento (m): '))
area(a, b)


# Karter Ence
# High Card
# 2/13/2020
from CardKE import *

class HighCard(Card):
    def __init__(self, rank, suit, value):
        super(HighCard, self).__init__(rank, suit)
        self.value = value

    def __str__(self):
        rep = str.format("""
         _________
        |{0:2}       |
        |{1:2}       |
        |         |
        |       {0:2}|
        |       {1:2}|
        |_________|
        value = {2}
        """, self.rank, self.suit, self.value)
        return rep

class HighCardDeck(Deck):
    def populate(self):
        for suit in HighCard.SUITS:
            for rank in HighCard.RANKS:
                if rank == "A":
                    value = 14
                elif rank == "J":
                    value = 11
                elif rank == "Q":
                    value = 12
                elif rank == "K":
                    value = 13
                else:
                    value = int(rank)
                self.add(HighCard(rank, suit, value))

def getName():
    name = ""
    while name == "":
        print("Enter your name.")
        name = input(": ")
    return name

def findWinner(hands, names):
    values = []
    winMessage = ""
    for hand in hands:
        for card in hand.cards:
            value = card.value
            values.append(int(value))
    highest = max(values)
    if values.count(int(highest)) > 1:
        winMessage = "It's a tie!"
        return winMessage
    highestIndex = values.index(highest)
    winner = names[highestIndex]
    winMessage = "The winner is: " + winner
    return winMessage

def main():
    print("How many players are there?")
    totalPlayers = int(input(": "))
    names = []
    hands = []
    for i in range(totalPlayers):
        x = getName()
        hand = Hand()
        hands.append(hand)
        names.append(x)
    deck = HighCardDeck()
    deck.populate()
    deck.shuffle()
    deck.deal(hands, 1)
    for hand in hands:
        nameIndex = hands.index(hand)
        handName = names[nameIndex]
        print(handName + "'s hand:", hand)
    winMessage = findWinner(hands, names)
    print(winMessage)

main()


# coding: utf-8

"""
    NGINX Plus REST API

    NGINX Plus REST [API](https://nginx.org/en/docs/http/ngx_http_api_module.html) provides access to NGINX Plus status information, on-the-fly configuration of upstream servers and key-value pairs management for [http](https://nginx.org/en/docs/http/ngx_http_keyval_module.html) and [stream](https://nginx.org/en/docs/stream/ngx_stream_keyval_module.html).  # noqa: E501

    OpenAPI spec version: 2.0

    Generated by: https://github.com/swagger-api/swagger-codegen.git
"""

import pprint
import re  # noqa: F401

import six

class NginxSSLObject(object):
    """NOTE: This class is auto generated by the swagger code generator program.

    Do not edit the class manually.
    """

    """
    Attributes:
      swagger_types (dict): The key is attribute name
                            and the value is attribute type.
      attribute_map (dict): The key is attribute name
                            and the value is json key in definition.
    """
    swagger_types = {
        'handshakes': 'int',
        'handshakes_failed': 'int',
        'session_reuses': 'int'
    }

    attribute_map = {
        'handshakes': 'handshakes',
        'handshakes_failed': 'handshakes_failed',
        'session_reuses': 'session_reuses'
    }

    def __init__(self, handshakes=None, handshakes_failed=None, session_reuses=None):  # noqa: E501
        """NginxSSLObject - a model defined in Swagger"""  # noqa: E501

        self._handshakes = None
        self._handshakes_failed = None
        self._session_reuses = None
        self.discriminator = None

        if handshakes is not None:
            self.handshakes = handshakes
        if handshakes_failed is not None:
            self.handshakes_failed = handshakes_failed
        if session_reuses is not None:
            self.session_reuses = session_reuses

    @property
    def handshakes(self):
        """Gets the handshakes of this NginxSSLObject.  # noqa: E501

        The total number of successful SSL handshakes.  # noqa: E501

        :return: The handshakes of this NginxSSLObject.  # noqa: E501
        :rtype: int
        """
        return self._handshakes

    @handshakes.setter
    def handshakes(self, handshakes):
        """Sets the handshakes of this NginxSSLObject.

        The total number of successful SSL handshakes.  # noqa: E501

        :param handshakes: The handshakes of this NginxSSLObject.  # noqa: E501
        :type: int
        """

        self._handshakes = handshakes

    @property
    def handshakes_failed(self):
        """Gets the handshakes_failed of this NginxSSLObject.  # noqa: E501

        The total number of failed SSL handshakes.  # noqa: E501

        :return: The handshakes_failed of this NginxSSLObject.  # noqa: E501
        :rtype: int
        """
        return self._handshakes_failed

    @handshakes_failed.setter
    def handshakes_failed(self, handshakes_failed):
        """Sets the handshakes_failed of this NginxSSLObject.

        The total number of failed SSL handshakes.  # noqa: E501

        :param handshakes_failed: The handshakes_failed of this NginxSSLObject.  # noqa: E501
        :type: int
        """

        self._handshakes_failed = handshakes_failed

    @property
    def session_reuses(self):
        """Gets the session_reuses of this NginxSSLObject.  # noqa: E501

        The total number of session reuses during SSL handshake.  # noqa: E501

        :return: The session_reuses of this NginxSSLObject.  # noqa: E501
        :rtype: int
        """
        return self._session_reuses

    @session_reuses.setter
    def session_reuses(self, session_reuses):
        """Sets the session_reuses of this NginxSSLObject.

        The total number of session reuses during SSL handshake.  # noqa: E501

        :param session_reuses: The session_reuses of this NginxSSLObject.  # noqa: E501
        :type: int
        """

        self._session_reuses = session_reuses

    def to_dict(self):
        """Returns the model properties as a dict"""
        result = {}

        for attr, _ in six.iteritems(self.swagger_types):
            value = getattr(self, attr)
            if isinstance(value, list):
                result[attr] = list(map(
                    lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
                    value
                ))
            elif hasattr(value, "to_dict"):
                result[attr] = value.to_dict()
            elif isinstance(value, dict):
                result[attr] = dict(map(
                    lambda item: (item[0], item[1].to_dict())
                    if hasattr(item[1], "to_dict") else item,
                    value.items()
                ))
            else:
                result[attr] = value

        return result

    def to_str(self):
        """Returns the string representation of the model"""
        return pprint.pformat(self.to_dict())

    def __repr__(self):
        """For `print` and `pprint`"""
        return self.to_str()

    def __eq__(self, other):
        """Returns true if both objects are equal"""
        if not isinstance(other, NginxSSLObject):
            return False

        return self.__dict__ == other.__dict__

    def __ne__(self, other):
        """Returns true if both objects are not equal"""
        return not self == other


import numpy as np
# from sklearn import svm
# from sklearn.model_selection import GridSearchCV
# from sklearn import linear_model

from feature import Feature
import statsmodels.api as sm

parameters = {'kernel': ('rbf','poly'), 'C':[1, 10, 100, 1000, 10000],'gamma': [1e-7, 1e-4, 1e-2, 1] ,'epsilon':[0.1,0.2,0.3,0.5,0.8]}

def model(trials):
	#svr = svm.SVR()
	#clf = GridSearchCV(svr, parameters)

	#clf = linear_model.LinearRegression()

	Xs =[
		p.X() for p in trials
	]

	ys = [p.y() for p in trials]

	#clf.fit(Xs, ys)

	clf = sm.OLS(ys, Xs).fit()

	return clf


import os.path
import unittest
from os import remove

from config import config
from plex_scrobble.scrobble_cache import ScrobbleCache

import logging
logging.disable(logging.CRITICAL)

class TestScrobbleCache(unittest.TestCase):

    def setUp(self):
        """ create an empty scrobble_cache object. """
        self.sc = ScrobbleCache(config)

    def tearDown(self):
        """ clean up/remove our temporary cache after test run completes. """

        if os.path.isfile(config.get('plex-scrobble',
            'cache_location')):
            remove(config.get('plex-scrobble', 'cache_location'))

    def test_add_record_to_cache(self):
        self.sc.add('artist', 'track', 'album')

        self.assertTrue(self.sc.length() == 1)

    def test_delete_record_from_cache(self):
        for key in self.sc.cache:
            self.sc.remove(key)
        self.assertTrue(self.sc.length() == 0)

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


from db import db
from models.cluster import ClusterModel
# from models.student import StudentModel

class KalikaKendraModel(db.Model):
    __tablename__ = "kalika_kendra"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    kalika_kendra_name = db.Column(db.String(200))
    cluster_id = db.Column(db.Integer, db.ForeignKey('cluster.id'))
    isactive = db.Column(db.Integer)
    isdeprecated = db.Column(db.Integer)

    # students = db.relationship('StudentModel', backref='kalika_kendra')

    def __init__(self, kalika_kendra_name, cluster_name, isactive=1, isdeprecated=0):
        self.kalika_kendra_name = kalika_kendra_name
        cluster = ClusterModel.find_by_cluster_name(cluster_name)
        if not cluster:
            return {"message": f"Cluster name not found for the Kalika Kendra"}, 401
        self.cluster_id = cluster.id
        self.isactive = isactive
        self.isdeprecated = isdeprecated

    def json(self):
        return {'kalika_kendra_name': self.kalika_kendra_name, 'cluster_id': self.cluster_id,
                'cluster_name': ClusterModel.find_by_cluster_id(self.cluster_id).cluster_name,
                'isactive': self.isactive,
                'isdeprecated': self.isdeprecated,
                "id":self.id
                }

    @classmethod
    def find_by_any(cls, **kwargs):
        filter_str = 'cls.query'
        cols = ['isactive', 'isdeprecated', 'cluster_name', 'cluster_id']
        if 'cluster_id' in kwargs.keys():
            filter_str = filter_str +  '.filter_by(cluster_id="' + str(
                kwargs['cluster_id']) + '")'
        if 'cluster_name' in kwargs.keys():
            cluster = ClusterModel.find_by_cluster_name(kwargs['cluster_name'])
            if cluster:
                cluster_id = cluster.id
                filter_str = filter_str +  '.filter_by(cluster_id="' + str(cluster_id) + '")'
        if 'isactive' in kwargs.keys():
            filter_str = filter_str +  '.filter_by(isactive="' + str(
                kwargs['isactive']) + '")'
        if 'isdeprecated' in kwargs.keys():
            filter_str = filter_str +  '.filter_by(isdeprecated="' + str(
                kwargs['isdeprecated']) + '")'
        filter_str = filter_str + '.all()'
        return eval(filter_str)

    @classmethod
    def find_by_kalika_kendra_name(cls, kalika_kendra_name):
        return cls.query.filter_by(kalika_kendra_name=kalika_kendra_name).first()

    @classmethod
    def find_by_cluster_name(cls, cluster_name):
        cluster = ClusterModel.find_by_cluster_name(cluster_name)
        if cluster:
            return cls.query.filter_by(cluster_id=cluster.id).first()

    @classmethod
    def find_by_cluster_id(cls, cluster_id):
        return cls.query.filter_by(cluster_id=cluster_id).first()

    @classmethod
    def find_by_kalika_kendra_id(cls, kalika_kendra_id):
        return cls.query.filter_by(id=kalika_kendra_id).first()

    def set_attribute(self, payload):
        cols = ['isactive', 'isdeprecated']
        for col in cols:
            if col in payload.keys():
                setattr(self, col, payload[col])
        if 'cluster_name' in payload.keys():
            cluster = ClusterModel.find_by_cluster_name(payload['cluster_name'])
            if not cluster:
                return {"message": f"Cluster name not found for the Kalika Kendra"}, 401
            self.cluster_id = cluster.id

    def save_to_db(self):
        db.session.add(self)
        db.session.commit()
        return self

    def delete_from_db(self):
        db.session.delete(self)
        db.session.commit()