import numpy as np
from scipy.special import gamma as Gamma
from scipy.special import beta as B
from scipy.special import hyp2f1
from scipy.integrate import quad
from scipy.stats import beta as Beta
from wigner import R
from tqdm.auto import tqdm
import os

def factorial(n):
    return Gamma(n + 1)

def Ul(l):
    """
    Return the transformation matrix from complex to real Ylms.

    """
    U = np.zeros((2 * l + 1, 2 * l + 1), dtype="complex128")
    for m in range(-l, l + 1):
        for mu in range(-l, l + 1):
            if mu < 0:
                term1 = 1j
            elif mu == 0:
                term1 = np.sqrt(2) / 2
            else:
                term1 = 1
            if (m > 0) and (mu < 0) and (mu % 2 == 0):
                term2 = -1
            elif (m > 0) and (mu > 0) and (mu % 2 != 0):
                term2 = -1
            else:
                term2 = 1
            U[l + m, l + mu] = (
                term1 * term2 * 1 / np.sqrt(2) * (int(m == mu) + int(m == -mu))
            )
    return U

def clmmpi(l, m, mp, i):
    """Return the scalar c^l_{m,mu,i}."""
    if (m - mp - i) % 2 == 0:
        return (
            (-1) ** ((2 * l - m + mp - i) / 2)
            * np.sqrt(
                factorial(l - m)
                * factorial(l + m)
                * factorial(l - mp)
                * factorial(l + mp)
            )
            / (
                2 ** l
                * factorial((i - m - mp) / 2)
                * factorial((i + m + mp) / 2)
                * factorial((2 * l - i - m + mp) / 2)
                * factorial((2 * l - i + m - mp) / 2)
            )
        )
    else:
        return 0.0

def Qllpiip(l, lp, i, ip, alpha, beta):
    """Return the scalar (Q_\phi^{l,l'})_{i,i'}."""
    if (i + ip) % 2 == 0:
        return B(alpha, l + lp + beta - (i + ip) / 2) * hyp2f1(
            -(i + ip) / 2, alpha, l + lp + alpha + beta - (i + ip) / 2, -1
        )
    else:
        return 0.0

def Pllpmmp(l, lp, m, mp, alpha, beta, Ellpr):
    """Return the scalar (P_\phi^{l,l'})_{m,m'}."""
    term1 = 0
    for mu in range(-l, l + 1):
        for mup in range(-lp, lp + 1):
            term2 = 0
            for i in range(2 * l + 1):
                for ip in range(2 * lp + 1):
                    term2 += (
                        clmmpi(l, m, mu, i)
                        * clmmpi(lp, mp, mup, ip)
                        * Qllpiip(l, lp, i, ip, alpha, beta)
                    )
            term1 += (
                Ellpr[l + mu, lp + mup]
                * np.exp(1j * np.pi / 2 * (m - mu + mp - mup))
                * term2
            )
    return term1 / B(alpha, beta)

def Pllp(l, lp, alpha, beta, Ellpr):
    """Return the matrix P_\phi^{l,l'}."""
    P = np.zeros((2 * l + 1, 2 * lp + 1), dtype="complex128")
    for m in range(-l, l + 1):
        for mp in range(-lp, lp + 1):
            P[l + m, lp + mp] = Pllpmmp(l, lp, m, mp, alpha, beta, Ellpr)
    return P

def Ellpphi(l, lp, alpha, beta, Ellpr):
    """Return the matrix E_\phi^{l,l'}."""
    return (
        np.linalg.inv(Ul(l))
        @ Pllp(l, lp, alpha, beta, Ul(l) @ Ellpr @ Ul(lp).T)
        @ np.linalg.inv(Ul(lp)).T
    )

def bigEphi(alpha, beta, Er):
    """Return the latitude expectation integral E_\phi."""
    lmax = int(np.sqrt(Er.shape[0]) - 1)
    N = (lmax + 1) ** 2
    E = np.zeros((N, N), dtype="complex128")
    for l in tqdm(
        range(lmax + 1), disable=bool(int(os.getenv("NOTQDM", "0")))
    ):
        for lp in range(lmax + 1):
            i = slice(l ** 2, (l + 1) ** 2)
            j = slice(lp ** 2, (lp + 1) ** 2)
            E[i, j] = Ellpphi(l, lp, alpha, beta, Er[i, j])
    assert np.max(np.abs(E.imag)) < 1e-15
    return E.real

def bigEphi_numerical(alpha, beta, Er):
    """Return the latitude expectation integral E_\phi, computed numerically."""
    lmax = int(np.sqrt(Er.shape[0]) - 1)
    N = (lmax + 1) ** 2
    E = np.zeros((N, N))
    for n1 in tqdm(range(N), disable=bool(int(os.getenv("NOTQDM", "0")))):
        for n2 in range(N):

            def func(phi):
                Rl = R(lmax, 0.5 * np.pi, phi, -0.5 * np.pi)
                Rs = np.zeros((N, N))
                for l in range(lmax + 1):
                    for lp in range(lmax + 1):
                        i = slice(l ** 2, (l + 1) ** 2)
                        j = slice(lp ** 2, (lp + 1) ** 2)
                        Rs[i, j] = Rl[l] @ Er[i, j] @ Rl[lp].T
                jac = 0.5 * np.abs(np.sin(phi))
                return Rs[n1, n2] * jac * Beta.pdf(np.cos(phi), alpha, beta)

            E[n1, n2] = quad(func, -np.pi / 2, np.pi / 2)[0]

    return E

def test_bigEphi(lmax=3, alpha=2.0, beta=5.0):
    """
    Show that our expression for the second moment
    integral of the latitude distribution agrees
    with a numerical estimate.
    """
    np.random.seed(0)
    Er = np.random.randn((lmax + 1) ** 2, (lmax + 1) ** 2)
    Er = Er + Er.T
    Ephi1 = bigEphi(alpha, beta, Er)
    Ephi2 = bigEphi_numerical(alpha, beta, Er)
    assert np.allclose(Ephi1, Ephi2)


#!/usr/bin/env python3

import subprocess
import time
import re
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
from importlib.machinery import SourceFileLoader
import xml.etree.ElementTree as ET
import requests
from requests.auth import HTTPBasicAuth
from typing import Union
import functools
import logging

logging.basicConfig(filename='/Volumes/IDGenomics_NAS/Bioinformatics/jarnn/analysis_for_run.log', format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# create logger
logger = logging.getLogger('analysis_for_run.py')
logger.setLevel(logging.DEBUG)

def log(_func=None, *, my_logger):
    def decorator_log(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            logger = my_logger
            args_repr = [repr(a) for a in args]
            kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
            signature = ", ".join(args_repr + kwargs_repr)
            logger.debug(f"function {func.__name__} called with args {signature}")
            try:
                result = func(*args, **kwargs)
                return result
            except Exception as e:
                logger.exception(f"Exception raised in {func.__name__}. exception: {str(e)}")
                raise e
        return wrapper

    if _func is None:
        return decorator_log
    else:
        return decorator_log(_func)

config = SourceFileLoader("config","/Volumes/IDGenomics_NAS/Bioinformatics/jarnn/config.py").load_module()

# Function to handle the stdout of the bs CLI tool. Returns a list of list of strings.
@log(my_logger=logger)
def bs_out(bashCommand):
    process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
    output, error = process.communicate()
    tmp=output.decode("utf-8")
    tmp=tmp.split('\n')
    tmp.pop(0)
    tmp.pop(1)
    tmp.pop(-1)
    tmp.pop(-1)
    tmp=[x.replace('|', '') for x in tmp]
    tmp=[re.sub(r"\s+", ' ', x) for x in tmp]
    return tmp

# Slack_sdk values needed for sending messages to Slack. Uses an API already set up on the Slack website for the UPHL Workspace to post messages on the notifications channel.
# Function makes sending Slack messages as easy as using the print funcition.
client = WebClient(token=config.token)
channel_id = config.channel_id

@log(my_logger=logger)
def my_subprocess_run(*args, **kwargs):
    return subprocess.run(*args, **kwargs)

@log(my_logger=logger)
def slack_message(string):
    try:

        result = client.chat_postMessage(
            channel=channel_id,
            text=string
        )

    except:
        logger.info("Slack Error")
@log(my_logger=logger)
def open_screen_and_run_script(script_path, experiment_name, run_type=None):
    # Open a new detached screen session
    my_subprocess_run(["screen", "-dmS",  experiment_name])

    # Send the command to run the script in the screen session
    if run_type is None:
        my_subprocess_run(["screen", "-S", experiment_name, "-X", "stuff", f"python3 {script_path}  {experiment_name}\n"])

    else:
        my_subprocess_run(["screen", "-S", experiment_name, "-X", "stuff", f"python3 {script_path}  {experiment_name}  {run_type}\n"])

@log(my_logger=logger)
def my_requests_get(*args, **kwargs):
    return requests.get(*args, **kwargs)

try:
    x=1
    while x==1:

        experiments_done = []

        with open('experiments_done.txt', 'r') as file:
            for line in file:
                experiments_done.append(line.strip())

        bssh_now=[]
        tmp=bs_out('bs list --config=bioinfo runs')
        for i in range(1,len(tmp)):
            bssh_now.append(tmp[i].split()[2])

        change=set(bssh_now) - set(experiments_done)

        logger.info(change)

        if len(change) > 0:
            for i in change:
                try:
                    xml=(requests.get("https://uphl-ngs.claritylims.com/api/v2/artifacts?containername=%s" % i, auth=HTTPBasicAuth('jarnn', 'civic1225CIVIC!@@%')).content).decode("utf-8")
                                        # Parse the XML
                    root = ET.fromstring(xml)

                    # Extract the limsid attribute
                    artifact_limsids = re.findall(r'limsid="([^"]+)"', xml)

                    # Extract the limsid attribute

                    sample_lims_ids = []
                    for artifact_id in artifact_limsids:
                        xml=(requests.get("https://uphl-ngs.claritylims.com/api/v2/artifacts/%s" % artifact_id, auth=HTTPBasicAuth('jarnn', 'civic1225CIVIC!@@%')).content).decode("utf-8")
                        match = re.search(r'sample\s+limsid="([^"]+)"', xml)
                        if match:
                            sample_lims_ids.append(match.group(1))

                    species=[]
                    for j in sample_lims_ids:
                        xml=(requests.get("https://uphl-ngs.claritylims.com/api/v2/samples/%s" % j,
                                            auth=HTTPBasicAuth('jarnn', 'civic1225CIVIC!@@%')).content).decode("utf-8")
                        # Parse the XML data
                        root = ET.fromstring(xml)

                        namespace_map = {
                                'udf': 'http://genologics.com/ri/userdefined',
                                'ri': 'http://genologics.com/ri',
                                'file': 'http://genologics.com/ri/file',
                                'smp': 'http://genologics.com/ri/sample'}

                        # Find the udf:field element with name="Species"
                        species_element = root.find('.//udf:field[@name="Species"]', namespaces=namespace_map)

                        # Extract the value of the udf:field element
                        species_value = species_element.text

                        species.append(species_value)
                    logger.info(species)
                    if len(species) > 0:
                        species=set(species)
                except ValueError as ve:
                    logger.warning("API Calls to Clarity Failed for %s. Error: %s " % (i, str(ve)))
                if 'species' in locals():
                    slack_message("New Sequecning Run Started: %s. This is a run with %s samples" %  (change,species))
                    logger.info("New Sequecning Run Started: %s. This is a run with %s samples" %  (change,species))
                    if 'Candida' in species:
                        run_type = "mycosnp"
                    elif len(species) < 1:
                       run_type = ""
                    else:
                        run_type= "grandeur"
                    open_screen_and_run_script('screen_run.py',i, run_type)
                    del species

                else:
                    slack_message("New Sequecning Run Started: %s" %  change)
                    open_screen_and_run_script('screen_run.py',i)

            with open('experiments_done.txt', 'w') as file:
                for item in bssh_now:
                    file.write(str(item) + '\n')

        logger.info("No new runs sleeping: 20 min")
        time.sleep(1200)
except ValueError as ve:
    slack_message("analysis_for_run.py has errored out please restart!")
    logger.error('analysis_for_run.py has errored out. Error: %s' % ve)


from django.utils.translation import gettext_lazy
from rest_framework import serializers
from rest_framework.settings import api_settings

from datahub.search.apps import get_global_search_apps_as_mapping
from datahub.search.query_builder import MAX_RESULTS
from datahub.search.utils import SearchOrdering, SortDirection

class SingleOrListField(serializers.ListField):
    """Field can be single instance or list."""

    def to_internal_value(self, data):
        """
        If data is str, call the child serialiser's run_validation() directly.

        This is to maintain an error format matching the input (if a list is provided, return an
        error list for each item, otherwise return a single error list).

        (We call self.child.run_validation() rather than self.child.to_internal_value(), because
        ListField performs child field validation in its to_internal_value().)
        """
        if isinstance(data, str):
            return [self.child.run_validation(data)]
        return super().to_internal_value(data)

class StringUUIDField(serializers.UUIDField):
    """
    String UUID field.

    We can't use UUID in OpenSearch queries, that's why we need to convert them back to string.
    """

    def to_internal_value(self, data):
        """
        Converts string to UUID and then back to string,
        to ensure that string is valid UUID.
        """
        uuid = super().to_internal_value(data)
        return str(uuid)

class IdNameSerializer(serializers.Serializer):
    """Serializer to return metadata constant with id and name."""

    id = StringUUIDField()
    name = serializers.CharField()

class _SearchOrderingField(serializers.Field):
    """Serialiser field for specifying an ordering for a search."""

    default_error_messages = {
        'invalid_field': gettext_lazy('"{input}" is not a valid choice for the sort field.'),
        'invalid_direction': gettext_lazy('"{input}" is not a valid sort direction.'),
    }
    default_direction = SortDirection.asc

    def __init__(self, *args, **kwargs):
        """Initialise the field."""
        super().__init__(*args, **kwargs)
        self.choices = None

    def configure(self, choices, default):
        """Sets the choices and default ordering for the field."""
        self.choices = choices
        self.default = default

    def to_internal_value(self, data):
        """Converts an ordering string to an SearchOrdering."""
        field, _, direction = data.partition(':')

        if field not in self.choices:
            self.fail('invalid_field', input=field)

        if direction:
            try:
                direction = SortDirection(direction)
            except ValueError:
                self.fail('invalid_direction', input=direction)
        else:
            direction = self.default_direction

        return SearchOrdering(field, direction)

    def to_representation(self, value):
        """Converts an SearchOrdering to an ordering string."""
        return f'{value.field}:{value.direction}'

class BaseSearchQuerySerializer(serializers.Serializer):
    """Base serialiser for basic (global) and entity search."""

    SORT_BY_FIELDS = []

    DEFAULT_ORDERING = None

    offset = serializers.IntegerField(default=0, min_value=0, max_value=MAX_RESULTS - 1)
    limit = serializers.IntegerField(default=api_settings.PAGE_SIZE, min_value=1)
    sortby = _SearchOrderingField(required=False)

    def __init__(self, *args, **kwrags):
        """Initialises the serialiser and configures the `sortby` field."""
        super().__init__(*args, **kwrags)
        self.fields['sortby'].configure(self.SORT_BY_FIELDS, self.DEFAULT_ORDERING)

class _SearchModelChoiceField(serializers.Field):
    """Serialiser field for selecting an OpenSearch model by name."""

    default_error_messages = {
        'invalid_choice': gettext_lazy('"{input}" is not a valid choice.'),
    }

    def get_default(self):
        """Gets the default value for the field."""
        default = super().get_default()
        if isinstance(default, str):
            return self.to_internal_value(default)

        return default

    def to_internal_value(self, data):
        """Translates a model name to a model."""
        global_search_models = get_global_search_apps_as_mapping()
        if data not in global_search_models:
            self.fail('invalid_choice', input=data)
        return global_search_models[data].search_model

    def to_representation(self, value):
        """Translates a model to a model name."""
        return value.get_app_name()

class BasicSearchQuerySerializer(BaseSearchQuerySerializer):
    """Serialiser used to validate basic (global) search query parameters."""

    entity = _SearchModelChoiceField(default='company')
    term = serializers.CharField(required=True, allow_blank=True)

class EntitySearchQuerySerializer(BaseSearchQuerySerializer):
    """Serialiser used to validate entity search POST bodies."""

    original_query = serializers.CharField(default='', allow_blank=True)


import torch.nn as nn
import torch

class ChannelAttentionModule(nn.Module):
    def __init__(self, channel, ratio=16):
        super(ChannelAttentionModule, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)

        self.shared_MLP = nn.Sequential(
            nn.Conv2d(channel, channel // ratio, 1, bias=False),
            nn.ReLU(),
            nn.Conv2d(channel // ratio, channel, 1, bias=False)
        )
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        avgout = self.shared_MLP(self.avg_pool(x))
        maxout = self.shared_MLP(self.max_pool(x))
        return self.sigmoid(avgout + maxout)

class SpatialAttentionModule(nn.Module):
    def __init__(self):
        super(SpatialAttentionModule, self).__init__()
        self.conv2d = nn.Conv2d(in_channels=2, out_channels=1, kernel_size=7, stride=1, padding=3)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        avgout = torch.mean(x, dim=1, keepdim=True)
        maxout, _ = torch.max(x, dim=1, keepdim=True)
        out = torch.cat([avgout, maxout], dim=1)
        out = self.sigmoid(self.conv2d(out))
        return out

class CBAM(nn.Module):
    def __init__(self, channel):
        super(CBAM, self).__init__()
        self.channel_attention = ChannelAttentionModule(channel)
        self.spatial_attention = SpatialAttentionModule()

    def forward(self, x):
        out = self.channel_attention(x) * x
        out = self.spatial_attention(out) * out
        return out
class LSTM(nn.Module):
    def __init__(self, in_channel, out_channel, num_layers):
        super(LSTM, self).__init__()
        self.lstm = nn.LSTM(input_size=in_channel, hidden_size=out_channel, num_layers=num_layers, batch_first=True)

    def forward(self, x):
        x = x.reshape(x.size(0), 1, x.size(1))
        x, _ = self.lstm(x)
        x = x.reshape(x.size(0), x.size(2))
        return x

class VGG(nn.Module):
    def __init__(self, features, num_classes=1000, init_weights=False):
        super(VGG, self).__init__()
        self.features = features
        self.classifier = nn.Sequential(
            # nn.Dropout(p=0.5),
            # nn.Linear(512*7*7, 2048),
            # nn.ReLU(True),
            LSTM(512*7*7, num_classes, 1),
            # nn.Dropout(p=0.5),
            # nn.Linear(2048, 2048),
            # nn.ReLU(True),
            # nn.Linear(2048, num_classes)
        )
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        # N x 3 x 224 x 224
        x = self.features(x)
        # N x 512 x 7 x 7
        x = torch.flatten(x, start_dim=1)
        # N x 512*7*7
        x = self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
                nn.init.xavier_uniform_(m.weight)
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.xavier_uniform_(m.weight)
                # nn.init.normal_(m.weight, 0, 0.01)
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)

def make_features(cfg: list):
    layers = []
    in_channels = 3
    for v in cfg:
        if v == "M":
            # layers += [nn.MaxPool2d(kernel_size=2, stride=2), CBAM(channel=in_channels)]
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            layers += [conv2d, nn.ReLU(True)]
            # layers += [conv2d, nn.ReLU(True), CBAM(channel=v)]
            in_channels = v
    return nn.Sequential(*layers)

cfgs = {
    'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
    'vgg19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}

def vgg(model_name="vgg16", **kwargs):
    try:
        cfg = cfgs[model_name]
    except:
        print("Warning: model number {} not in cfgs dict!".format(model_name))
        exit(-1)
    model = VGG(make_features(cfg), **kwargs)
    return model

if __name__ == '__main__':
    from torchsummary import summary
    # summary(vgg(), (3, 224, 224), device='cpu')

    a = torch.zeros(size=(1, 3, 224, 224))
    model = vgg()
    model(a)


#!/usr/bin/env python
import filecmp
import urllib.request
from random import randint

import pytest
import unittest
import numpy as np

import cdflib

'''
To check code coverage, first:

pip install pytest-cov

Then

pytest --cov

This will run all unit tests.  To view the coverage results:

coverage report

Each of these results were hand checked using either IDL or
other online resources.
'''

def test_encode_cdfepoch():
    x = cdflib.cdfepoch.encode([62285326000000.0, 62985326000000.0])
    assert x[0] == '1973-09-28T23:26:40.000'
    assert x[1] == '1995-12-04T19:53:20.000'

    y = cdflib.cdfepoch.encode(62975326000002.0, iso_8601=False)
    assert y == '11-Aug-1995 02:06:40.002'

class CDFEpochTestCase(unittest.TestCase):

    def test_encode_cdfepoch16(self):
        '''
        cdf_encode_epoch16(dcomplex(63300946758.000000, 176214648000.00000)) in IDL
        returns 04-Dec-2005 20:39:28.176.214.654.976

        However, I believe this IDL routine is bugged.  This website:
        https://www.epochconverter.com/seconds-days-since-y0

        shows a correct answer.
        '''
        x = cdflib.cdfepoch.encode(np.complex128(63300946758.000000 + 176214648000.00000j))
        self.assertEqual(x, '2005-12-04T20:19:18.176214648000')
        y = cdflib.cdfepoch.encode(np.complex128([33300946758.000000 + 106014648000.00000j,
                                                  61234543210.000000 + 000011148000.00000j]),
                                   iso_8601=False)
        self.assertEqual(y[0], '07-Apr-1055 14:59:18.106.014.648.000')
        self.assertEqual(y[1], '12-Jun-1940 03:20:10.000.011.148.000')

    def test_encode_cdftt2000(self):
        x = cdflib.cdfepoch.encode(186999622360321123)
        self.assertEqual(x, '2005-12-04T20:19:18.176321123')
        y = cdflib.cdfepoch.encode([500000000100, 123456789101112131],
                                   iso_8601=False)
        self.assertEqual(y[0], '01-Jan-2000 12:07:15.816.000.100')
        self.assertEqual(y[1], '30-Nov-2003 09:32:04.917.112.131')

    def test_unixtime(self):
        x = cdflib.cdfepoch.unixtime([500000000100, 123456789101112131])
        self.assertEqual(x[0], 946728435.816)
        self.assertEqual(x[1], 1070184724.917112)

    def test_breakdown_cdfepoch(self):
        x = cdflib.cdfepoch.breakdown([62285326000000.0, 62985326000000.0])
        # First in the array
        self.assertEqual(x[0][0], 1973)
        self.assertEqual(x[0][1], 9)
        self.assertEqual(x[0][2], 28)
        self.assertEqual(x[0][3], 23)
        self.assertEqual(x[0][4], 26)
        self.assertEqual(x[0][5], 40)
        self.assertEqual(x[0][6], 0)
        # Second in the array
        self.assertEqual(x[1][0], 1995)
        self.assertEqual(x[1][1], 12)
        self.assertEqual(x[1][2], 4)
        self.assertEqual(x[1][3], 19)
        self.assertEqual(x[1][4], 53)
        self.assertEqual(x[1][5], 20)
        self.assertEqual(x[1][6], 0)

    def test_breakdown_cdfepoch16(self):
        x = cdflib.cdfepoch.breakdown(np.complex128(63300946758.000000 + 176214648000.00000j))
        self.assertEqual(x[0], 2005)
        self.assertEqual(x[1], 12)
        self.assertEqual(x[2], 4)
        self.assertEqual(x[3], 20)
        self.assertEqual(x[4], 19)
        self.assertEqual(x[5], 18)
        self.assertEqual(x[6], 176)
        self.assertEqual(x[7], 214)
        self.assertEqual(x[8], 648)
        self.assertEqual(x[9], 000)

    def test_breakdown_cdftt2000(self):
        x = cdflib.cdfepoch.breakdown(123456789101112131)
        self.assertEqual(x[0], 2003)
        self.assertEqual(x[1], 11)
        self.assertEqual(x[2], 30)
        self.assertEqual(x[3], 9)
        self.assertEqual(x[4], 32)
        self.assertEqual(x[5], 4)
        self.assertEqual(x[6], 917)
        self.assertEqual(x[7], 112)
        self.assertEqual(x[8], 131)

    def test_compute_cdfepoch(self):
        '''
        Using random numbers for the compute tests
        '''
        random_time = []
        random_time.append(randint(0, 2018))  # Year
        random_time.append(randint(1, 12))  # Month
        random_time.append(randint(1, 28))  # Date
        random_time.append(randint(0, 23))  # Hour
        random_time.append(randint(0, 59))  # Minute
        random_time.append(randint(0, 59))  # Second
        random_time.append(randint(0, 999))  # Millisecond
        x = cdflib.cdfepoch.breakdown(cdflib.cdfepoch.compute(random_time))
        i = 0
        for t in x:
            self.assertEqual(t, random_time[i], 'Time '+str(random_time) + ' was not equal to ' + str(x))
            i += 1

    def test_compute_cdfepoch16(self):
        random_time = []
        random_time.append(randint(0, 2018))  # Year
        random_time.append(randint(1, 12))  # Month
        random_time.append(randint(1, 28))  # Date
        random_time.append(randint(0, 23))  # Hour
        random_time.append(randint(0, 59))  # Minute
        random_time.append(randint(0, 59))  # Second
        random_time.append(randint(0, 999))  # Millisecond
        random_time.append(randint(0, 999))  # Microsecond
        random_time.append(randint(0, 999))  # Nanosecond
        random_time.append(randint(0, 999))  # Picosecond
        x = cdflib.cdfepoch.breakdown(cdflib.cdfepoch.compute(random_time))
        i = 0
        for t in x:
            self.assertEqual(t, random_time[i], 'Time '+str(random_time) + ' was not equal to ' + str(x))
            i += 1

    def test_compute_cdftt2000(self):
        random_time = []
        random_time.append(randint(0, 2018))  # Year
        random_time.append(randint(1, 12))  # Month
        random_time.append(randint(1, 28))  # Date
        random_time.append(randint(0, 23))  # Hour
        random_time.append(randint(0, 59))  # Minute
        random_time.append(randint(0, 59))  # Second
        random_time.append(randint(0, 999))  # Millisecond
        random_time.append(randint(0, 999))  # Microsecond
        random_time.append(randint(0, 999))  # Nanosecond
        x = cdflib.cdfepoch.breakdown(cdflib.cdfepoch.compute(random_time))
        i = 0
        for t in x:
            self.assertEqual(t, random_time[i], 'Time '+str(random_time) + ' was not equal to ' + str(x))
            i += 1

    def test_parse_cdfepoch(self):
        x = cdflib.cdfepoch.encode(62567898765432.0)
        self.assertEqual(x, "1982-09-12T11:52:45.432")
        parsed = cdflib.cdfepoch.parse(x)
        self.assertEqual(parsed, 62567898765432.0)

    def test_parse_cdfepoch16(self):
        input_time = np.complex(53467976543.0, 543218654100)
        x = cdflib.cdfepoch.encode(input_time)
        self.assertEqual(x, "1694-05-01T07:42:23.543218654100")
        parsed = cdflib.cdfepoch.parse(x, to_np=True)
        self.assertEqual(parsed, input_time)

    def test_parse_cdftt2000(self):
        input_time = 131415926535793238
        x = cdflib.cdfepoch.encode(input_time)
        self.assertEqual(x, "2004-03-01T12:24:22.351793238")
        parsed = cdflib.cdfepoch.parse(x)
        self.assertEqual(parsed, input_time)

    def test_findepochrange_cdfepoch(self):
        start_time = "2013-12-01T12:24:22.000"
        end_time = "2014-12-01T12:24:22.000"
        x = cdflib.cdfepoch.parse([start_time, end_time])
        time_array = np.arange(x[0], x[1], step=1000000)

        test_start = [2014, 8, 1, 8, 1, 54, 123]
        test_end = [2018, 1, 1, 1, 1, 1, 1]
        index = cdflib.cdfepoch.findepochrange(time_array, starttime=test_start, endtime=test_end)
        # Test that the test_start is less than the first index, but more than one less
        self.assertGreaterEqual(time_array[index[0]], cdflib.cdfepoch.compute(test_start))
        self.assertLessEqual(time_array[index[0]-1], cdflib.cdfepoch.compute(test_start))

        self.assertLessEqual(time_array[index[-1]], cdflib.cdfepoch.compute(test_end))
        return

    def test_findepochrange_cdftt2000(self):
        start_time = "2004-03-01T12:24:22.351793238"
        end_time = "2004-03-01T12:28:22.351793238"
        x = cdflib.cdfepoch.parse([start_time, end_time])
        time_array = np.arange(x[0], x[1], step=1000000)

        test_start = [2004, 3, 1, 12, 25, 54, 123, 111, 98]
        test_end = [2004, 3, 1, 12, 26, 4, 123, 456, 789]
        index = cdflib.cdfepoch.findepochrange(time_array, starttime=test_start, endtime=test_end)
        # Test that the test_start is less than the first index, but more than one less
        self.assertGreaterEqual(time_array[index[0]], cdflib.cdfepoch.compute(test_start))
        self.assertLessEqual(time_array[index[0]-1], cdflib.cdfepoch.compute(test_start))

        self.assertLessEqual(time_array[index[-1]], cdflib.cdfepoch.compute(test_end))
        self.assertGreaterEqual(time_array[index[-1]+1], cdflib.cdfepoch.compute(test_end))
        return

    def test_findepochrange_cdfepoch16(self):
        start_time = "1978-03-10T03:24:22.351793238462"
        end_time = "1978-06-13T01:28:22.338327950466"
        x = cdflib.cdfepoch.parse([start_time, end_time])
        first_int_step = int((x[1].real - x[0].real) / 1000)
        second_int_step = int((x[1].imag - x[0].imag) / 1000)
        time_array = []
        for i in range(0, 1000):
            time_array.append(x[0]+complex(first_int_step*i, second_int_step*i))

        test_start = [1978, 6, 10, 3, 24, 22, 351, 793, 238, 462]
        test_end = [1978, 6, 12, 23, 11, 1, 338, 341, 416, 466]
        index = cdflib.cdfepoch.findepochrange(time_array, starttime=test_start, endtime=test_end)

        # Test that the test_start is less than the first index, but more than one less
        self.assertGreaterEqual(time_array[index[0]].real, cdflib.cdfepoch.compute(test_start).real)
        self.assertLessEqual(time_array[index[0]-1].real, cdflib.cdfepoch.compute(test_start).real)
        self.assertLessEqual(time_array[index[-1]].real, cdflib.cdfepoch.compute(test_end).real)
        self.assertGreaterEqual(time_array[index[-1]+1].real, cdflib.cdfepoch.compute(test_end).real)

def test_latest_leapsecs():
    # Check that the built in leapseconds table is the latest one
    local = cdflib.epochs.LEAPSEC_FILE
    remote, _ = urllib.request.urlretrieve('https://cdf.gsfc.nasa.gov/html/CDFLeapSeconds.txt')
    assert filecmp.cmp(local, remote)

if __name__ == '__main__':
    pytest.main(['-x', __file__])


import data_conversion1
import knn_kdtree1
import svm
from numpy import *
import uuid
from flask import Flask, abort, request, jsonify
import face_recognition
import constant
import knn_analysis
from time import time
import os
import data_preprocess

UPLOAD_FOLDER = constant.UPLOAD_PATH
ALLOW_EXTENSIONS = set(['jpg', 'png', 'pgm', 'tiff'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
#判断文件夹是否存在，如果不存在则创建
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
else:
    pass
# 判断文件后缀是否在列表中
def allowed_file(filename):
    return '.' in filename and \
            filename.rsplit('.', 1)[1] in ALLOW_EXTENSIONS

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/knn-find-face', methods=['POST'])
def knn_findFace():
	'''
	post 传输接受参数例子
	if not request.json or 'id' not in request.json or 'info' not in request.json:
        abort(400)
    task = {
        'id': request.json['id'],
        'info': request.json['info']
    }
	'''
	if not request.files or 'file' not in request.files:
		return buildResponse({}, 400, 'no file upload')
	file_path = ''
	#获取post过来的文件名称，从name=file参数中获取
	file = request.files['file']
	if file and allowed_file(file.filename):
		filename = file.filename
		file_name = str(uuid.uuid4()) + '.' + filename.rsplit('.', 1)[1]
		file.save(app.config['UPLOAD_FOLDER'] + constant.SLASH + file_name)
		file_path = app.config['UPLOAD_FOLDER'] + constant.SLASH + file_name
	if file_path == '':
		return buildResponse({}, 400, 'no file upload')

	# 对上传图片进行人脸检测
	draw_face = face_recognition.saveFaces(file_path, app.config['UPLOAD_FOLDER'])
	if draw_face == '':
		return buildResponse({}, 400, 'no face in upload file')
	start_time = time()

	path = constant.JAFFE['last_path']
	# 获取样本图片原始数据
	train_data, train_labels = data_conversion1.loadDataSet(path)
	data_train_new,data_mean,V = data_conversion1.pca(train_data, knn_analysis.BEST_DIM)
	test_path = data_preprocess.doPreprocess(file_path, constant.JAFFE['last_height'], constant.JAFFE['last_weight']) # 图片预处理
	test_face = data_conversion1.img2vector(test_path, (constant.JAFFE['last_height'], constant.JAFFE['last_weight']))
	num_test = test_face.shape[0]
	temp_face = test_face - tile(data_mean,(num_test,1))
	data_test_new = temp_face*V # 得到测试脸在特征向量下的数据
	data_test_new = array(data_test_new)
	outputLabel = knn_kdtree1.findSimilarLable(data_train_new, train_labels, data_test_new[0,:], knn_analysis.BEST_K)
	return buildResponse({'draw_face_path': draw_face, 'face_name': outputLabel, 'cost_time': round(time() - start_time, 2)})

@app.route('/knn-accucency')
def knn_accucency():
	precision, cost_time = knn_analysis.precisionWithBestKAndDim()
	return buildResponse({'precision': round(precision, 3), 'cost_time': round(cost_time, 2)})

@app.route('/svm-accucency')
def svm_accucency():
	precision, cost_time = svm.pcaAndSvmFaceFindAnalysis()
	return buildResponse({'precision': round(precision, 3), 'cost_time': round(cost_time, 2)})

@app.route('/svm-find-face', methods=['POST'])
def svm_findFace():
	if not request.files or 'file' not in request.files:
		return buildResponse({}, 400, 'no file upload')
	file_path = ''
	#获取post过来的文件名称，从name=file参数中获取
	file = request.files['file']
	if file and allowed_file(file.filename):
		filename = file.filename
		file_name = str(uuid.uuid4()) + '.' + filename.rsplit('.', 1)[1]
		file.save(app.config['UPLOAD_FOLDER'] + constant.SLASH + file_name)
		file_path = app.config['UPLOAD_FOLDER'] + constant.SLASH + file_name
	if file_path == '':
		return buildResponse({}, 400, 'no file upload')

	# 对上传图片进行人脸检测
	draw_face = face_recognition.saveFaces(file_path, app.config['UPLOAD_FOLDER'])
	if draw_face == '':
		return buildResponse({}, 400, 'no face in upload file')
	path = constant.JAFFE['last_path']
	outputLabel, cost_time = svm.pcaAndSvmFaceFind(path, file_path)
	return buildResponse({'draw_face_path': draw_face ,'face_name': outputLabel, 'cost_time': round(cost_time, 2)})

def buildResponse(data, code = 0, message = 'success'):
	return jsonify({'code': code, 'data': data,'message': message})

if __name__ == '__main__':
    app.run(debug=True)


#!/usr/bin/env python

#imports
import argparse
import random
import pandas as pd
import numpy as np

"""
magic_item_sel.py: Random magic item selection program
       Usage: python magic_item_sel.py -s major/minor -r common/uncommon/rare/veryrare/legendary -n number of items to be generated (optional -- Default 1) -o Name of output text file -k (optional)
"""

# meta information
__author__ = "Jakob Cole"
__maintainer__ = "Jakob Cole"

#arguments
pa = argparse.ArgumentParser()
pa.add_argument('-s', '--scope', action='store', nargs=1, dest='item_scope',
                help='Item scope - major/minor', required=True)

pa.add_argument('-r', '--rarity', action='store', nargs=1, dest='item_rarity',
                help='Item rarity', required=True)

pa.add_argument('-n', '--num', action='store', nargs=1, dest='number',
                help='number of items outputted')

pa.add_argument('-o', '--out', action='store', nargs=1, dest='outFile',
                help='file to output file to (must include extention i.e. "test.txt"', required=True)

pa.add_argument('-k', '--skip', action='store_true',
                help='skip all dialogues regarding requirements')

args = pa.parse_args()

item_scope = args.item_scope[0]
item_rarity = args.item_rarity[0]
if args.number is not None:
	number = int(args.number[0])
else:
	number = 1
if args.skip:
	skip = True
else:
	skip = False

# open/create output file
f = open(args.outFile[0], "a+")

# import file
itemfile = str(item_scope) + '_' + str(item_rarity) + '.csv'
my_data = pd.read_csv(itemfile, delimiter=',', header=0)

# item filter decision
print('Do you want to filter by item type? (Y/N)')
valid = False

while valid == False: # valid input check
	dec = input()
	if dec.lower() != 'y' and dec.lower() != 'yes' and dec.lower() != 'n' and dec.lower() != 'no':
		print("I'm sorry. I do not understand your input. Please indicate Y or N\n\n")
		print("Do you want to filter by item type? (Y/N)")
	else:
		valid = True

# filter
if dec.lower() == 'y' or dec.lower == 'yes':
	print('Using the following list, please select which item types you want to choose from\n')
	print('Selection Number -- Item Type\n')

	totFilt = []
	filt_data = my_data[my_data['Type'].isin(['Armor'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       1         -- Armor\n')
		totFilt.append(1)
	filt_data = my_data[my_data['Type'].isin(['Potion'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       2         -- Potion\n')
		totFilt.append(2)
	filt_data = my_data[my_data['Type'].isin(['Ring'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       3         -- Ring\n')
		totFilt.append(3)
	filt_data = my_data[my_data['Type'].isin(['Rod'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       4         -- Rod\n')
		totFilt.append(4)
	filt_data = my_data[my_data['Type'].isin(['Scroll'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       5         -- Scroll\n')
		totFilt.append(5)
	filt_data = my_data[my_data['Type'].isin(['Staff'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       6         -- Staff\n')
		totFilt.append(6)
	filt_data = my_data[my_data['Type'].isin(['Wand'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       7         -- Wand\n')
		totFilt.append(7)
	filt_data = my_data[my_data['Type'].isin(['Weapon'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       8         -- Weapon\n')
		totFilt.append(8)
	filt_data = my_data[my_data['Type'].isin(['Wondrous Item'])]
	(rows, cols) = filt_data.shape
	if rows > 0:
		print('       9         -- Wondrous Item\n\n')
		totFilt.append(9)

	print('Please use the number selection column.\n')
	print('If you have more than one item type you want to pick from\n')
	print('please put all applicable numbers\n')
	typefilt = input()
	typefilt = list(typefilt)

	# only add to filter if item type exists
	typefiltname = []
	if '1' in typefilt and 1 in totFilt:
		typefiltname.append('Armor')
		print('You have selected Armor\n')
	if '2' in typefilt and 2 in totFilt:
		typefiltname.append('Potion')
		print('You have selected Potion\n')
	if '3' in typefilt and 3 in totFilt:
		typefiltname.append('Ring')
		print('You have selected Ring\n')
	if '4' in typefilt and 4 in totFilt:
		typefiltname.append('Rod')
		print('You have selected Rod\n')
	if '5' in typefilt and 5 in totFilt:
		typefiltname.append('Scroll')
		print('You have selected Scroll\n')
	if '6' in typefilt and 6 in totFilt:
		typefiltname.append('Staff')
		print('You have selected Staff\n')
	if '7' in typefilt and 7 in totFilt:
		typefiltname.append('Wand')
		print('You have selected Wand\n')
	if '8' in typefilt and 8 in totFilt:
		typefiltname.append('Weapon')
		print('You have selected Weapon\n')
	if '9' in typefilt and 9 in totFilt:
		typefiltname.append('Wondrous item')
		print('You have selected Wondrous item\n')

	item_data = my_data[my_data['Type'].isin(typefiltname)]
else:
	item_data = my_data

# write item scope_rarity
f.write(item_scope + " " + item_rarity + "\n")

# loop for each item
while number > 0:
	#pick random item
	(rows, cols) = item_data.shape
	x = random.randint(0, (rows-1))

	if item_data.iloc[x,3] != 'All' and not skip: # determine if item with restrictions should be used
		print(item_data.iloc[x,0] + " has the following use restriction: " + item_data.iloc[x,3])
		print("Do you want to generate a different item? (Y/N)")
		valid = False

		while valid == False: # check for valid input
			Rest_Dec = input()
			if Rest_Dec.lower() != 'y' and Rest_Dec.lower() != 'yes' and Rest_Dec.lower() != 'n' and Rest_Dec.lower() != 'no':
				print("I'm sorry. I do not understand your input. Please indicate Y or N\n\n")
				print("Do you want to generate a different item? (Y/N)")
			else:
				valid = True

	else:
		Rest_Dec = 'n'

	# print item
	if Rest_Dec.lower() == 'n' or Rest_Dec.lower == 'no':
		if args.outFile is not None:
			f.write('/////////////////\n')
			f.write('Item: ' + item_data.iloc[x, 0] + "\n")
			f.write('Type: ' + item_data.iloc[x, 1] + "\n")
			f.write('Attune: ' + item_data.iloc[x, 2] + "\n")
			f.write('Restrictions: ' + item_data.iloc[x, 3] + "\n")
			f.write('Source: ' + item_data.iloc[x, 4] + "\n")
			f.write('/////////////////\n')

		print('/////////////////')
		print(item_data.iloc[x])
		print('/////////////////')

		number = number - 1


import sys
import os
import threading
from PySide6.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QRadioButton, QCheckBox
from PySide6.QtCore import Slot
import webbrowser

from Modules.post import *
from HTTP_1_0 import *

from construction import Server_Construction

class Window(QWidget):
    '''gui class
precondition: Creates a GUI that accepts a port and host.
postcondition: Displays a GUI window that allows user to input desired host and port and then launches a webpage.
description: This class provides the user a simple way to launch a website with the desired host and port.'''

    def __init__(self):
        super().__init__()
        self.only_one_server = 0
        self.ip_lbl = QLabel('IP Address: ', self)
        self.ip_addr = QLineEdit(self)
        self.port_lbl = QLabel('Port Number: ', self)
        self.prt_nmbr = QLineEdit(self)
        self.options = QLabel('Choose exploits:')
        self.cmnd = QCheckBox("Command Injection")
        self.cmnd.toggled.connect(lambda:self.btnstate(self.cmnd))
        self.xss = QCheckBox("Cross Site Scripting")
        self.xss.toggled.connect(lambda:self.btnstate(self.xss))
        self.btn = QPushButton("Enter")
        self.btn.clicked.connect(self.on_click)

        self.cmd_inj = False
        self.xss_opt = False

        vbox = QVBoxLayout()

        vbox.addWidget(self.ip_lbl)
        vbox.addWidget(self.ip_addr)
        vbox.addWidget(self.port_lbl)
        vbox.addWidget(self.prt_nmbr)
        vbox.addWidget(self.options)
        vbox.addWidget(self.cmnd)
        vbox.addWidget(self.xss)
        vbox.addWidget(self.btn)

        self.setLayout(vbox)
        self.setWindowTitle("Multipurpose Honeypot Server")
        self.setGeometry(350,200,350,200)
        self.show()

    def btnstate(self, b):

      if b.text() == "Command Injection":
         if b.isChecked() == True:
            print(b.text() + " is selected")
            self.cmd_inj = True
         else:
            print(b.text() + " is deselected")
            self.cmd_inj = False

      if b.text() == "Cross Site Scripting":
         if b.isChecked() == True:
            print(b.text() + " is selected")
            self.xss_opt = True
         else:
            print(b.text() + " is deselected")
            self.xss_opt = False

    @Slot()
    def on_click(self):
        '''    precondition: Accepts the port and host inputed by the user.
    postcondition: Launches a webpage witht he provided host and port.
    description: This method allows us a smooth launch when the enter button is clicked.'''

        ip = self.ip_addr.text()
        prt = self.prt_nmbr.text()

        #This code could block the process unless operating system, and browser type is accounted for.
        #chrome_path="C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
        #webbrowser.register('chrome', None, webbrowser.BackgroundBrowser(chrome_path))
        #webbrowser.get('chrome').open('%s:%s/HTML_files/index.html' % (ip, prt))
        #os.system("python Main.py -ip %s -p %s" % (ip, prt))

        if self.only_one_server < 1:
            self.only_one_server += 1
            t_server = threading.Thread(target=self.module_4server_start, args=(ip, prt, self.xss, self.cmd_inj),daemon=True)
            t_server.start()
        else:
            print("Restart the server if you want to change the IP and PORT\n")
        #QWidget.close(self)

    def module_4server_start(self, ip, prt, xss, cmd_inj):
        start_server = Server_Construction(ip, prt, xss, cmd_inj)

    def closeEvent(self, event):
        '''
        Precondition : provided an event
        Postcondition: Indicates that the user tried to exit the program
        Description  : Useful code for processing a system event from the gui'''
        print("User has clicked the red x on the main window")
        #os._exit(0)
        event.accept()

if __name__ == '__main__':

    app = QApplication([])
    win = Window()
    win.show()
    ret = app.exec_()
    sys.exit(ret)


#!/usr/bin/env python

# -*- coding: utf-8 -*-

from lxml import etree
import sqlite3

conn = sqlite3.connect('report.db')

c = conn.cursor()

# Create table
c.execute('''CREATE TABLE files
             (rowid INTEGER PRIMARY KEY AUTOINCREMENT, filename text, size integer)''')
#c.execute('''CREATE TABLE IF NOT EXISTS files
#             (rowid INTEGER PRIMARY KEY AUTOINCREMENT, filename text, size integer)''')

tree = etree.parse("report.xml")
root = tree.getroot()

print("tree loaded ...")

for fileobject in root.iter('fileobject'):
	filename = fileobject.find('filename').text
	filesize = fileobject.find('filesize').text
	#byte_runs = fileobject.find('byte_runs')
	#byte_run = byte_runs.find('byte_run')
	#offset = byte_run.get('offset')
	#img_offset = byte_run.get('img_offset')
	#length = byte_run.get('len')
	#print("{} {}".format(filename,filesize))
	c.execute("INSERT INTO files(filename,size) VALUES ('{}',{})".format(filename,filesize))

print("xml file read")

conn.commit()

print("changes commited to the DB")

conn.close()


# -*- coding: utf-8 -*-

from flask import Flask, render_template
from flask.ext.assets import Environment, Bundle

from reflection import reflection
from shapewaysapi import shapeways_api

# Register flask application and blueprints, and retrieve environment
app = Flask(__name__)
app.register_blueprint(reflection)
app.register_blueprint(shapeways_api)
env = Environment(app)

app.config.update(dict(
    ASSETS_DEBUG=True
))

# Register javascript
js_common = Bundle('js/jquery/jquery.js', 'js/jquery/jquery-forms.js', output='gen/common.js')
js_charmer = Bundle('js/charmer/shapejs-charmer.js', 'js/charmer/sw.shapejs.creator-2.0.js',
                    'js/charmer/charmer.js', output='gen/charmer.js')
env.register('js_common', js_common)
env.register('js_charmer', js_charmer)

# Register css
css_common = Bundle('css/style.css', output='gen/common.css')
env.register('css_common', css_common)

@app.route('/')
def main_template():
    return render_template('selector/selector.html', widgets=[])

if __name__ == '__main__':
    app.run(debug=True, port=5051)


"""
The ``config`` command allows you to query the settings used by Papis on your
system.

Examples
^^^^^^^^

The ``config`` command returns the value used by Papis. Therefore, if you
have not customized some setting, it will return the default value. In contrast,
if you have customized it, it will return the value set in the configuration
file. For example, to find out to what your "default-library" is set to, call:

.. code::

    papis config default-library

The ``config`` command can also be used to query a settings' default
value. This is done by adding the ``--default`` flag. This ignores all
settings set in your Papis configuration file (note, however, that
settings set in a ``config.py`` script can count as default values). Check the
default "default-library" with:

.. code::

    papis config --default default-library

Settings from a specific section in the configuration file can also be
accessed. To take an example, the :ref:`papis bibtex <command-bibtex>` command's
settings can be accessed with:

.. code::

    papis config --section bibtex
    papis config --default --section bibtex

or with ``papis config`` (without the section argument) to show the settings
available for all the known sections.

You can also query a specific setting within a section. For example like this:

.. code::

    papis config --section bibtex default-read-bibfile
    papis config --default --section bibtex default-read-bibfile

Alternatively, you can also use the ``<section.setting>`` format to query the
value of a setting in a specific `section`:

.. code::

    papis config bibtex.default-read-bibfile
    papis config --default bibtex.default-read-bibfile

For some more advanced usage, we can also query multiple settings at once. Here,
sections specified with ``<section>.<setting>`` override the section specified by
``--setting <section>``. This can be achieved by:

.. code::

    papis config --section sec1 key1 key2 key3 sec2.key4 sec3.key5

You can find a list of all available settings in the configuration section
at :ref:`general-settings`. Commands and other plugins can define their own
settings, which are documented separately.

Command-line Interface
^^^^^^^^^^^^^^^^^^^^^^

.. click:: papis.commands.config:cli
    :prog: papis config
"""

from typing import Any, Dict, List, Optional, Tuple

import click
import colorama

import papis.cli
import papis.config
import papis.commands
import papis.logging

logger = papis.logging.get_logger(__name__)

def format_option(key: str, value: Any) -> str:
    return (
        "{c.Style.BRIGHT}{key}{c.Style.NORMAL} "
        "= {c.Fore.GREEN}{value!r}{c.Style.RESET_ALL}"
        .format(c=colorama, key=key, value=value))

def parse_option(
        option: str, default_section: Optional[str]
        ) -> Tuple[Optional[str], str]:
    """
    :returns: a ``(section, key)`` tuple parsed from *option*.
    """

    parts = option.split(".")
    key = section = None
    if len(parts) == 1:
        key = parts[0]
        section = default_section
    elif len(parts) == 2:
        section = parts[0] if parts[0] else None
        key = parts[1]
    else:
        raise ValueError(f"Unsupported option format: '{option}'")

    return section, key

def _get_option_safe(
        option: str, default_section: Optional[str], default: bool = False,
        ) -> Tuple[Optional[str], Optional[str]]:
    key = option
    value = None

    try:
        section, key = parse_option(option, default_section)
    except ValueError:
        logger.error(
            "Options should be in a <section>.<key> or <key> format: got '%s'.",
            option)
        return key, value

    if default:
        if section is None:
            section = papis.config.get_general_settings_name()

        defaults = papis.config.get_default_settings()
        try:
            value = defaults[section][key]
        except KeyError:
            logger.error(
                "No default value for setting '%s' found in section '%s'.",
                key, section)
    else:
        try:
            value = papis.config.get(key, section=section)
        except papis.exceptions.DefaultSettingValueMissing as exc:
            logger.error("No value for setting '%s' found in section '%s'.",
                         key, section, exc_info=exc)

    return key, value

def run(
        options: List[str],
        section: Optional[str] = None,
        default: bool = False,
        ) -> Dict[str, Any]:
    """
    :param options: a list of strings, each in a format ``[<section>].<key>``
        (i.e. where the section is optional).
    :param section: a default section to query for configuration settings.
    :param default: if *True*, return hardcoded default values, otherwise return
        the values from the configuration file.
    """
    config = papis.config.get_configuration()
    result: Dict[str, Any] = {}

    if len(options) == 0:
        # NOTE: no options given -> just get all the settings
        defaults = papis.config.get_default_settings()
        if default:
            if section is None:
                result = defaults
            elif section in defaults:
                result = defaults[section]
            else:
                logger.error("Section '%s' does not exist in defaults. "
                             "Known sections are '%s'.",
                             section, "', '".join(defaults))
        else:
            if section is None:
                for sec in defaults:
                    result[sec] = defaults[sec].copy()
                    if sec in config:
                        result.update({
                            key: papis.config.get(key, section=sec)
                            for key in config.options(sec) if key in result
                            })
            elif section in defaults:
                result = defaults[section].copy()
                if section in config:
                    result.update({
                        key: papis.config.get(key, section=section)
                        for key in config.options(section) if key in result
                        })
            elif section in config:
                # NOTE: libraries are in the config but not in the defaults,
                # so we just print whatever settings are in there.
                result = {key: config[section][key] for key in config.options(section)}
            else:
                logger.error("Section '%s' not found in configuration file. "
                             "Known sections are '%s'.",
                             section, "', '".join(config.sections()))
    else:
        # NOTE: options given -> print only chosen options
        for option in options:
            key, value = _get_option_safe(option, section, default=default)
            if value is not None:
                assert key is not None
                result[key] = value

    return result

@click.command("config")
@click.help_option("--help", "-h")
@click.argument("options", nargs=-1)
@click.option(
    "-s", "--section",
    help="select a default section for the options",
    default=None)
@papis.cli.bool_flag(
    "-d", "--default",
    help="List default configuration setting values, instead of those in the "
         "configuration file")
@papis.cli.bool_flag(
    "--json", "print_json",
    help="Print settings in a JSON format")
@papis.cli.bool_flag(
    "--list-paths",
    help="List known configuration and script locations")
def cli(options: List[str],
        section: Optional[str],
        default: bool,
        print_json: bool,
        list_paths: bool) -> None:
    """Print configuration values"""
    if list_paths:
        click.echo(format_option("Config home", papis.config.get_config_home()))
        click.echo(format_option("Config folder", papis.config.get_config_folder()))
        click.echo(format_option("Config file", papis.config.get_config_file()))
        click.echo(format_option("Config.py file", papis.config.get_configpy_file()))
        click.echo(format_option("Scripts folder", papis.config.get_scripts_folder()))
        return

    if len(options) == 1:
        # NOTE: a single option is printed directly for a bit of backwards
        # compatibility and easier use in shell scripts, so remove with care!
        _, value = _get_option_safe(options[0], section, default=default)
        if value is not None:
            click.echo(value)
        return

    result = run(options, section=section, default=default)
    if not result:
        return

    if print_json:
        import json
        click.echo(json.dumps(result, indent=2))
        return

    lines = []
    if len(options) == 0 and section is None:
        # NOTE: no inputs prints all of the sections
        is_first = True
        for section, settings in result.items():
            if not is_first:
                lines.append("")

            is_first = False
            lines.append(f"[{section}]")

            for key, value in settings.items():
                lines.append(format_option(key, value))
    else:
        if section is not None and all("." not in o for o in options):
            lines.append(f"[{section}]")

        for key, value in result.items():
            lines.append(format_option(key, value))

    click.echo("\n".join(lines))


import enum
import math
from dataclasses import dataclass
from typing import List

from sklearn.tree import DecisionTreeClassifier

from ..bagging_pu import BaggingClassifierPU
from ..transforms import CandidateTransform
from ..types import Candidate, LabelValue, PULabelType
from .transductive import TransductiveModel

@dataclass(frozen=True)
class ProbLabel:
    label: PULabelType
    p: float

@dataclass
class NodeExtractionModel(
    TransductiveModel[List[Candidate], List[PULabelType], List[ProbLabel]]
):
    n_estimators: int = 256
    max_features: float = 1.0
    max_samples: int = 100
    pos_thr: float = 0.5

    def learn(
        self, data: List[Candidate], labels: List[PULabelType]
    ) -> List[ProbLabel]:
        tf = CandidateTransform()
        # First of all we need to predict if it is a node.
        # Then we need to predict the relationship between them

        X = [tf.encode(c) for c in data]
        y = [1 if l == PULabelType.POS else 0 for l in labels]

        clf = DecisionTreeClassifier(max_features="auto")

        model = BaggingClassifierPU(
            base_estimator=clf,
            n_estimators=self.n_estimators,
            max_features=self.max_features,
            max_samples=self.max_samples,
        )
        model.fit(X, y)

        out = []
        for i, d in enumerate(model.oob_decision_function_[:, 1]):
            if labels[i] != PULabelType.UNK:
                out.append(ProbLabel(labels[i], d))
            else:
                lbl = PULabelType.POS if d > self.pos_thr else PULabelType.NEG
                out.append(ProbLabel(lbl, d))

        return out


from django.conf.urls import include, url

from rest_framework import routers

from teams import views

app_name = 'teams'

router = routers.DefaultRouter()
router.register(r'teams', views.TeamListViewSet)

urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^invites/$', views.UserInviteListView.as_view(), name='invite-list'),
    url(r'^invites/(?P<pk>[0-9]+)/$', views.UserInviteDetailView.as_view(), name='invite-detail'),      # noqa
    url(r'^members/(?P<pk>[0-9]+)/$', views.TeamMemberDetailView.as_view(), name='member-detail'),      # noqa
    url(r'^teams/(?P<pk>[0-9]+)/invites/$', views.TeamInviteListView.as_view(), name='team-invites'),   # noqa
]


######该脚本保存有待修改的部分，包括对原模拟数据的分区件处理和根据质量函数的分布区间选择
####链接路径引入
import sys
#sys.path.insert(0,'D:/Python1/pydocument/seniorproject_quenching2/practice/_pycache_/session_1')
sys.path.insert(0,'D:/Python1/pydocument/seniorproject_quenching2/practice')
##导入自己编写的脚本，需要加入这两句，一句声明符号应用，然后声明需要引入文-
##件的路径具体到文件夹
###库函数调用
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
from scipy import stats as st
import matplotlib.gridspec as gridspec
import pandas as pa
from scipy import interpolate as sinter
###mock_相关脚本调用，主要用于导入数据
from mock_data_reshow import read_mock_hmf
from Theory_calculation import the_probability
from Theory_calculation import bins_dic
### section1：导入数据产生需要使用的四个数组：mock_mstar——theory_mh,利用此关系反插的mock_mh——theory_mstar
def doload_mock_data(tt):
    mockfile = 'D:/Python1/pydocument/seniorproject_quenching2/practice/iHODcatalog_bolshoi.h5'
    Mh_arr, dndlnMh_arr, use_data = read_mock_hmf(mockfile, mmin=1.e9, mmax=1.e16,
                                                  nmbin=101, h=0.701, rcube=250.0)
    return use_data
###################对原模拟数据的分析部分
def mass_function_mock(dd):
    use_data = doload_mock_data(tt=True)
    N = np.array(use_data['b'].shape)
    print('total_number=',N)
    ###查看数据量：529308*8~=4000000
    ###把主晕取出来,并把主晕对应的物理量也取出来
    ix = use_data['d']>0
    _halos = use_data['d']
    ##取出主晕
    main_halo = np.array(_halos[ix])
    ##下面把与主晕有关的物理量取出来
    #g_color = use_data['c']
    ##取出主晕下星系颜色
    #gcolor = np.array(g_color[ix])
    ###尝试读取数据的处理
    M_star = use_data['e']
    ##取出恒星质量
    mstar = np.array(M_star[ix])
    ###求出中央星系的比例
    n = np.array(main_halo.shape)
    print('use_number=',n)
    frac_ = n[0]/N[0]
    print('fraction_sample=',frac_)
    #con_c = use_data['b']
    #con = np.array(con_c[ix])
###下面为质量函数
####mh-function
    value_mh = plt.hist(main_halo,100,normed=True)
    plt.yscale('log')
    #plt.savefig('mock_Mh',dpi=600)
    plt.show()
    p_Mh = np.array(value_mh[0])
    f_N_mh = np.array(value_mh[0])
    x_N_mh = np.array(value_mh[1])
    print(value_mh[0].size)
    #print(value_mh[1])
    media_mh = np.zeros(value_mh[0].size,dtype=np.float)
    dn_dMh = np.zeros(value_mh[0].size,dtype=np.float)
    for k in range(1,value_mh[0].size):
            media_mh[k] = (x_N_mh[k]+x_N_mh[k-1])/2
            dn_dMh[k] = f_N_mh[k]/(x_N_mh[1]-x_N_mh[0])
    media_mh[0] = media_mh[1]
    dn_dMh[0] = f_N_mh[0]/(x_N_mh[1]-x_N_mh[0])
    plt.plot(media_mh,dn_dMh,label='mock dn_dlgMh')
    plt.legend(loc=1)
    plt.yscale('log')
    plt.xlabel(r'$lgM_h[M_\odot h^{-1}]$')
    plt.ylabel(r'$dn/dlgM_h$')
    plt.grid()
    plt.title('Mh_fun')
    #plt.savefig('fun_Mh',dpi=600)
    plt.show()
####mstar-function
    value_ms = plt.hist(mstar,100,normed=True)
    plt.yscale('log')
    #plt.savefig('mock_mstar',dpi=600)
    plt.show()
    p_ms = np.array(value_ms[0])
    f_N_ms = np.array(value_ms[0])
    x_N_ms = np.array(value_ms[1])
    print(value_ms[0].size)
    #print(value_ms[1])
    media_ms = np.zeros(value_ms[0].size,dtype=np.float)
    dn_dms = np.zeros(value_ms[0].size,dtype=np.float)
    for k in range(1,value_ms[0].size):
            media_ms[k] = (x_N_ms[k]+x_N_ms[k-1])/2
            dn_dms[k] = f_N_ms[k]/(x_N_ms[1]-x_N_ms[0])
    media_ms[0] = media_ms[1]
    dn_dms[0] = f_N_ms[0]/(x_N_ms[1]-x_N_ms[0])
    plt.plot(media_ms,dn_dms,label=r'$mock-dn_dlgM_\ast$')
    plt.legend(loc=1)
    plt.yscale('log')
    plt.xlabel(r'$lgM_\ast[M_\odot h^{-2}]$')
    plt.ylabel(r'$dn/dlgM_\ast$')
    plt.grid()
    plt.title('stellarmass_fun')
    #plt.savefig('fun_Ms',dpi=600)
    plt.show()
####下面求联合质量分布函数
    vl_joint = plt.hist2d(mstar,main_halo,bins=[100,100],
              range=[[np.min(mstar),np.max(mstar)],[np.min(main_halo),np.max(main_halo)]]
               ,normed=False,cmin=0,cmap='rainbow',vmin=1,vmax=1e5,alpha=1,
               norm=mpl.colors.LogNorm())
    plt.colorbar(label=r'$dN(M_\ast,M_h)/dlgM_\ast$')
    plt.xlabel(r'$lgM_\ast[M_\odot h^{-2}]$')
    plt.ylabel(r'$lgM_h[M_\odot h^{-1}]$')
    plt.show()
    print(vl_joint[0].shape)
    ##第一行表示的是各个划分区间的数目多少
    #print(vl_joint[1])
    ##第二行表示对恒星质量的划分区间
    #print(vl_joint[2])
    ##第三行表示对暗晕质量的划分区间
    N_joint = np.array(vl_joint[0])
    ms_joint = np.array(vl_joint[1])
    mh_joint = np.array(vl_joint[2])
    dN_mh_joint = np.zeros((len(N_joint[:,0]),len(N_joint[0,:])),dtype=np.float)
    dN_ms_joint = np.zeros((len(N_joint[0,:]),len(N_joint[:,0])),dtype=np.float)
    for k in range(0,len(N_joint[:,0])):
        dN_ms_joint[k,:] = N_joint[k,:]/(ms_joint[1]-ms_joint[0])
    for k in range(0,len(N_joint[0,:])):
        dN_mh_joint[:,k] = N_joint[:,k]/(mh_joint[1]-mh_joint[0])
    bin1 = np.linspace(np.min(mstar), np.max(mstar), 100)
    bin2 = np.linspace(np.min(main_halo),np.max(main_halo),100)
    mstar_ = mstar
    mainhalo = main_halo
    mstar_, mainhalo = np.meshgrid(bin2, bin1)
    plt.pcolormesh(mstar_,mainhalo,dN_ms_joint,cmap='rainbow',vmin=1,vmax=1e5,alpha=1,
               norm=mpl.colors.LogNorm())
    plt.colorbar(label=r'$dN(M_\ast,M_h)/dlgM_\ast$')
    plt.ylabel(r'$lgM_\ast[M_\odot h^{-2}]$')
    plt.xlabel(r'$lgM_h[M_\odot h^{-1}]$')
    #plt.savefig('DN',dpi=600)
    plt.show()
####下面带入公式计算，产生另外两个数组
    ##带入恒星质量mstar，计算理论值Mh
    M0 = 2*10**10###单位是Msolar/h^2
    M1 = 1.3*10**12###单位是Msolar/h
    belta = 0.33
    sigma = 0.42
    gamma = 1.21
    ##下面计算为了和模拟数据保持一直,把SHMR的质量转为以10为底的对数
    Theory_Mh = np.log10(M1)+belta*(mstar-np.log10(M0))+\
        ((10**mstar/M0)**sigma/(1+(10**mstar/M0)**(-gamma))-1/2)
    plt.plot(mstar,Theory_Mh,'*',label='SHMR-curve')
    plt.xlabel(r'$mock-M_\ast [M_\odot h^{-2}]$')
    plt.ylabel(r'$Theory-M_h [M_\odot h^{-1}]$')
    plt.show()
    ###画出SHMR解析关系下的质量函数
    Mh_theory = plt.hist(Theory_Mh,100,alpha=0.2)
    plt.yscale('log')
    #plt.savefig('Theory_Mh',dpi=600)
    plt.show()
    N_Mh_theory = np.array(Mh_theory[0])
    x_Mh_theory = np.array(Mh_theory[1])
    print(Mh_theory[0].size)
    media_Mh_theory = np.zeros(Mh_theory[0].size,dtype=np.float)
    dn_dMh_theory = np.zeros(Mh_theory[0].size,dtype=np.float)
    for k in range(1,Mh_theory[0].size):
            media_Mh_theory[k] = (x_Mh_theory[k]+x_Mh_theory[k-1])/2
            dn_dMh_theory[k] = N_Mh_theory[k]/(x_Mh_theory[1]-x_Mh_theory[0])
    media_Mh_theory[0] = media_Mh_theory[1]
    dn_dMh_theory[0] = N_Mh_theory[0]/(x_Mh_theory[1]-x_Mh_theory[0])
    plt.plot(media_Mh_theory,dn_dMh_theory,label=r'$theory-dn_dlgM_h$')
    plt.legend(loc=1)
    plt.yscale('log')
    plt.xlabel(r'$lgM_h [M_\odot h^{-1}]$')
    plt.ylabel(r'$dn/dlgM_h$')
    plt.grid()
    plt.title('Theory_Mh_fun')
    #plt.savefig('fun_Mh_theory',dpi=600)
    plt.show()
###下面做插值处理,带入暗晕质量，插值出理论mstar
    Theory_mstar = np.interp(main_halo,Theory_Mh,mstar)
    plt.plot(main_halo,Theory_mstar,'*')
    plt.xlabel(r'$mock-M_h [M_\odot h^{-1}]$')
    plt.ylabel(r'$Theory-M_\ast [M_\odot h^{-2}]$')
    plt.show()
    ###画出给定模型理论下的恒星质量函数
    mstar_theory = plt.hist(Theory_mstar,100,alpha=0.2)
    plt.yscale('log')
    #plt.savefig('Theory_mstar',dpi=600)
    plt.show()
    N_mstar_theory = np.array(mstar_theory[0])
    x_mstar_theory = np.array(mstar_theory[1])
    print(mstar_theory[0].size)
    media_mstar_theory = np.zeros(mstar_theory[0].size,dtype=np.float)
    dn_dms_theory = np.zeros(mstar_theory[0].size,dtype=np.float)
    for k in range(1,mstar_theory[0].size):
            media_mstar_theory[k] = (x_mstar_theory[k]+x_mstar_theory[k-1])/2
            dn_dms_theory[k] = N_mstar_theory[k]/(x_mstar_theory[1]-x_mstar_theory[0])
    media_mstar_theory[0] = media_mstar_theory[1]
    dn_dms_theory[0] = N_mstar_theory[0]/(x_mstar_theory[1]-x_mstar_theory[0])
    plt.plot(media_mstar_theory,dn_dms_theory,label=r'$theory-dn_dlgM_\ast$')
    plt.legend(loc=1)
    plt.yscale('log')
    plt.xlabel(r'$lgM_\ast [M_\odot h^{-2}]$')
    plt.ylabel(r'$dn/dlgM_\ast$')
    plt.grid()
    plt.title('Theory_mstar_fun')
    #plt.savefig('fun_mstar_theory',dpi=600)
    plt.show()
    out1 = {'a':mstar,'b':Theory_Mh,'c':dn_dms,'d':dn_dMh_theory}
    out2 = {'a':main_halo,'b':Theory_mstar,'c':dn_dMh,'d':dn_dms_theory}
####计算模拟数据的<N(M*|Mh)>,该部分有待修正，需要对质量区间重新划分
    return out1,out2,p_Mh,p_ms
###############################
##############################对质量函数的区间选取部分
def Theory_fun1(ff1):
####只对mhalo做限制的情况
    media_mh,dn_dlgMh,media_ms,dn_dlgms,p_lgMh,p_lgms = bins_dic(tt=True)
    mhalo,ms,N_ms_Mh1,N_ms_Mh2,N_ms_Mh3,Theory_Mh,Theory_mstar,sigma_ms\
    = the_probability(pp=True)
####下面计算p(mstar,mh),即为联合分布概率P_joint,注意需要划分质量区间——对引入的质量函数的适应
    ng = 1
    x1 = media_mh
    y1 = dn_dlgMh
    f1 = sinter.interpolate.interp1d(x1,y1)
    ###下面这句对质量函数的自适应
    _halo = np.linspace(np.min(x1),np.max(np.log10(mhalo)),len(mhalo))
    dn_dMh_theory = f1(_halo)
    dn_dMh = dn_dMh_theory/(10**_halo*np.log(10))
    plt.plot(_halo,dn_dMh)
    plt.xlabel("$lgM_h [M_\odot h^{-1}]$")
    plt.ylabel("$dn/dMh$")
    plt.yscale('log')
    plt.grid()
    plt.show()
    ###下面对N_ms_Mh1也做相应的质量范围截断
    ###对halo质量，N_ms_Mh都做出重新的选择对ms也要做出相范围内的选择,下面这句表示对ms的调整
    halo_ = np.linspace(np.min(x1),np.max(np.log10(mhalo)),len(ms))
    ms_use = np.interp(halo_,np.log10(mhalo[0:950]),np.log10(ms))
    ms_use = 10**ms_use
    N_ms_Mh = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    for k in range(0,len(ms)):
        ix = np.log10(mhalo)>=np.min(x1)
        x2 = np.array(mhalo[ix])
        y2 = N_ms_Mh1[ix,k]
        N_ms_Mh[:,k] = np.interp(10**_halo,x2,y2)
    plt.pcolormesh(np.log10(10**_halo),np.log10(ms_use),N_ms_Mh.T,cmap='rainbow',vmin=0.01,vmax=1,alpha=1,
               norm = mpl.colors.LogNorm())
    plt.colorbar(label=r'$dN(M_\ast,M_h)/dlgM_\ast$')
    plt.ylabel(r'$lgM_\ast[M_\odot h^{-2}]$')
    plt.xlabel(r'$lgM_h[M_\odot h^{-1}]$')
    plt.title('L11_2011')
    #plt.savefig('Theory_DN_function_contrain_mh',dpi=600)
    plt.show()
    p_joint = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    for k in range(len(ms)):
        p_joint[:,k] = ((np.log10(np.e))/(ms_use[k]*ng))*N_ms_Mh[:,k]*dn_dMh
    ##下面对p_joint做归一化检验
    sum1 = np.zeros(len(mhalo),dtype=np.float)
    for k in range(len(mhalo)):
        sum1[k] = np.sum(p_joint[k,:]*ms_use*(np.log10(ms_use[2])-np.log10(ms_use[1])))
    sum2 = np.sum(sum1*10**_halo*(_halo[2]-_halo[1]))
    A = sum2
    print(A)
    P_Joint1 = p_joint/A
####下面求条件概率p_Mh_ms代替p(Mh|ms),p_ms_Mh代替p(ms|Mh)
####往下求条件概率分布遇到范围限制的困难：原因是求解的联合分布质量范围和边界条件分布不一致
    return P_Joint1

def Theory_fun2(ff2):
####只对ms做限制的情况
    media_mh,dn_dlgMh,media_ms,dn_dlgms,p_lgMh,p_lgms = bins_dic(tt=True)
    mhalo,ms,N_ms_Mh1,N_ms_Mh2,N_ms_Mh3,Theory_Mh,Theory_mstar,sigma_ms\
    = the_probability(pp=True)
####下面计算p(mstar,mh),即为联合分布概率P_joint,注意需要划分质量区间——对引入的质量函数的适应
    ng = 1
    x1 = media_ms
    y1 = dn_dlgms
    f1 = sinter.interpolate.interp1d(x1,y1)
    x2 = media_mh
    y2 = dn_dlgMh
    f2 = sinter.interpolate.interp1d(x2,y2)
    ###下面这句对质量函数的自适应
    _ms = np.linspace(np.min(x1),np.max(x1),len(ms))
    dn_dms_theory = f1(_ms)
    dn_dms = dn_dms_theory/(10**_ms*np.log(10))
    plt.plot(_ms,dn_dms)
    plt.xlabel(r'$lgM_\ast [M_\odot h^{-2}]$')
    plt.ylabel(r'$dn/dms$')
    plt.yscale('log')
    plt.grid()
    plt.show()
    ###下面对N_ms_Mh1也做相应的质量范围截断
    ###对halo质量，N_ms_Mh都做出重新的选择对mh也要做出相范围内的选择,下面这句表示对ms的调整
    ms_ = np.linspace(np.min(x1),np.max(x1),len(mhalo))
    mh_use = np.interp(ms_,np.log10(ms),np.log10(mhalo[0:950]))
    dn_dMh = f2(mh_use)/(10**mh_use*np.log(10))
    '''
    plt.plot(mh_use,dn_dMh)
    plt.xlabel(r'$lgM_h [M_\odot h^{-1}]$')
    plt.ylabel(r'$dn/dMh$')
    plt.yscale('log')
    plt.grid()
    plt.show()
    '''
    mhuse = 10**mh_use
    N_ms_Mh = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    for k in range(0,len(mhalo)):
        ix = np.log10(ms)>=np.min(x1)
        x2 = np.array(ms[ix])
        y2 = N_ms_Mh1[k,ix]
        N_ms_Mh[k,:] = np.interp(10**_ms,x2,y2)
    plt.pcolormesh(np.log10(mhuse),_ms,N_ms_Mh.T,cmap='rainbow',vmin=0.01,vmax=1,alpha=1,
               norm = mpl.colors.LogNorm())
    plt.colorbar(label=r'$dN(M_\ast,M_h)/dlgM_\ast$')
    plt.ylabel(r'$lgM_\ast [M_\odot h^{-2}]$')
    plt.xlabel(r'$lgM_h[M_\odot h^{-1}]$')
    plt.title('L11_2011')
    #plt.savefig('Theory_DN_function_contrain_ms',dpi=600)
    plt.show()
    p_joint = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    for k in range(len(ms)):
        p_joint[:,k] = ((np.log10(np.e))/(10**_ms[k]*ng))*N_ms_Mh[:,k]*dn_dMh
    ##下面对p_joint做归一化检验
    sum1 = np.zeros(len(mhalo),dtype=np.float)
    for k in range(len(mhalo)):
        sum1[k] = np.sum(p_joint[k,:]*10**_ms*(_ms[2]-_ms[1]))
    sum2 = np.sum(sum1*mhuse*(np.log10(mhuse[2])-np.log10(mhuse[1])))
    B = sum2
    print(B)
    P_Joint2 = p_joint/B
####下面求条件概率p_Mh_ms代替p(Mh|ms),p_ms_Mh代替p(ms|Mh)
####往下求条件概率分布遇到范围限制的困难：原因是求解的联合分布质量范围和边界条件分布不一致
    return P_Joint2
def Theory_fun_assum(fa):
    ####对mhalo,ms同时做限制的情况
    media_mh,dn_dlgMh,media_ms,dn_dlgms,p_lgMh,p_lgms = bins_dic(tt=True)
    mhalo,ms,N_ms_Mh1,N_ms_Mh2,N_ms_Mh3,Theory_Mh,Theory_mstar,sigma_ms =\
    the_probability(pp=True)
####下面计算p(mstar,mh),即为联合分布概率P_joint,注意需要划分质量区间——对引入的质量函数的适应
    #ng=1###宇宙平均星系数密度
    x1 = np.linspace(np.min(media_mh),np.max(media_mh),len(mhalo))
    x2 = np.linspace(np.min(media_ms),np.max(media_ms),len(ms))
    f1 = sinter.interpolate.interp1d(media_mh,p_lgMh)
    f2 = sinter.interpolate.interp1d(media_ms,p_lgms)
    plgMh = f1(x1)
    plgms = f2(x2)
    _halo = x1
    ms_use = x2
    pmh = plgMh/(np.log(10)*10**_halo)
    pms = plgms/(np.log(10)*10**ms_use)
    A = np.sum((_halo[2]-_halo[1])*pmh)
    B = np.sum((ms_use[2]-ms_use[1])*pms)
    pmh=pmh/A
    pms=pms/B
    f3 = sinter.interpolate.interp2d(ms,mhalo,N_ms_Mh3)
    N_ms_Mh = f3(10**x2,10**x1)
    plt.pcolormesh(np.log10(10**_halo),np.log10(10**ms_use),N_ms_Mh.T,cmap='rainbow',
                   vmin=0.01,vmax=1,alpha=1,norm = mpl.colors.LogNorm())
    plt.colorbar(label=r'$dN(M_\ast,M_h)/dlgM_\ast$')
    plt.ylabel(r'$lgM_\ast[M_\odot h^{-2}]$')
    plt.xlabel(r'$lgM_h[M_\odot h^{-1}]$')
    plt.title('assumption')
    #plt.savefig('Theory_DN_function_comparation',dpi=600)
    plt.show()
    ##求解联合分布概率
    f3 = sinter.interpolate.interp1d(media_mh,dn_dlgMh)
    #dn_dMh = f3(x1)/(np.log(10)*10**x1)#在HOD模型下需要带入质量函数计算
    p_joint = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    for k in range(len(ms)):
        #p_joint[:,k] = ((np.log10(np.e))/(10**ms_use[k]*ng))*N_ms_Mh[:,k]*dn_dMh
        ####在HOD模型下，联合分布概率从上式求解
        p_joint[:,k] = N_ms_Mh[:,k]*pmh
    ##下面对p_joint做归一化检验
    sum1 = np.zeros(len(mhalo),dtype=np.float)
    for k in range(len(mhalo)):
        sum1[k] = np.sum(p_joint[k,:]*10**ms_use*(ms_use[2]-ms_use[1]))
    sum2 = np.sum(sum1*10**_halo*(_halo[2]-_halo[1]))
    SA = sum2
    print(SA)
    P_Joint_as = p_joint/SA
####下面求条件概率p_Mh_ms代替p(Mh|ms),p_ms_Mh代替p(ms|Mh)
    p_Mh_ms = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    p_ms_Mh = np.zeros((len(mhalo),len(ms)),dtype=np.float)
    for k in range(len(mhalo)):
        p_ms_Mh[k,:] = P_Joint_as[k,:]/pmh[k]
    for k in range(len(ms)):
        p_Mh_ms[:,k] = P_Joint_as[:,k]/pms[k]
    plt.plot(_halo,np.log(10)*10**_halo*p_Mh_ms[:,1])
    #plt.yscale('log')
    plt.show()
    plt.plot(ms_use,np.log(10)*10**ms_use*p_ms_Mh[500,:])
    #plt.yscale('log')
    plt.show()
    ###注意因为pms和pmh包含0,上述两个条件概率存在Inf和nan
    p_Mh_ms[np.isinf(p_Mh_ms)]=0
    p_ms_Mh[np.isinf(p_ms_Mh)]=0
    p_Mh_ms[np.isnan(p_Mh_ms)]=0
    p_ms_Mh[np.isnan(p_ms_Mh)]=0
    return
def run_control(t):
    doload_mock_data(tt=True)
    mass_function_mock(dd=True)
    Theory_fun1(ff1=True)
    Theory_fun2(ff2=True)
    Theory_fun_assum(fa=True)###对比部分
    return
run_control(t=True)


import time

from appium import webdriver
from selenium.webdriver.support.wait import WebDriverWait

desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
desired_caps['appPackage'] = 'com.cyanogenmod.filemanager'
desired_caps['appActivity'] = '.activities.NavigationActivity'
desired_caps['automationName'] = 'Uiautomator2'
# desired_caps['noReset'] = True

driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

time.sleep(2)

driver.press_keycode(4)
time.sleep(1)
driver.press_keycode(4)
time.sleep(1)
driver.press_keycode(4)

# print(WebDriverWait(driver, 10, 1).until(lambda x: x.find_element_by_xpath("//*[contains(@text,'再次点击')]")).text)

print(driver.find_element_by_xpath("//*[@text='再次点击即可退出.']").text)

time.sleep(5)


# coding: utf-8

import os
import pandas as pd

from graph_tool import load_graph
from glob import glob
from tqdm import tqdm
from joblib import Parallel, delayed
from itertools import product

from eval_helpers import eval_map
from experiment import one_run
from helpers import is_processed, makedir_if_not_there

n_jobs = 4
n_sample = 1000

methods = ['our', 'pagerank', 'min-steiner-tree']

cascade_models = ['si', 'ic']

graphs = ['fb-messages', 'email-univ', 'infectious', 'lattice-1024', 'grqc']

# a batch of settings to iterate through
settings = [
    {'graphs': graphs,
     'obs_fractions': ["0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9"],
     'cascade_fractions': ["0.1"]},
    {'graphs': graphs,
     'obs_fractions': ["0.5"],
     'cascade_fractions': ["0.1", "0.2", "0.3", "0.4", "0.5"]}
]

for setting in settings:
    graphs, obs_fractions, cascade_fractions = setting['graphs'], \
                                               setting['obs_fractions'], \
                                               setting['cascade_fractions']
    for graph, cascade_model, obs_fraction, cascade_fraction, method \
            in product(
                graphs, cascade_models, obs_fractions, cascade_fractions, methods
            ):

        if cascade_model == 'ic':
            # use reversed graph
            suffix = "uniform"
            graph_path = 'data/{}/graph_weighted_{}.gt'.format(graph, suffix + '_rev')
        else:
            suffix = "0.1"
            graph_path = 'data/{}/graph_weighted_{}.gt'.format(graph, suffix)

        g = load_graph(graph_path)
        edge_weights = g.edge_properties['weights']

        dataset_id = "{}-m{}-s{}-o{}-omuniform".format(graph, cascade_model, cascade_fraction, obs_fraction)
        print('method', method)
        print('dataset_id', dataset_id)

        input_dir = 'cascade/{}/'.format(dataset_id)
        output_dir = 'output/{}/{}/'.format(method, dataset_id)
        eval_result_path = 'eval/{}/{}.pkl'.format(method, dataset_id)

        makedir_if_not_there(output_dir)
        makedir_if_not_there(os.path.dirname(eval_result_path))

        rows = Parallel(n_jobs=n_jobs)(

            delayed(one_run)(
                g, edge_weights, input_path, output_dir, method,
                n_sample=n_sample)

            for input_path in tqdm(glob(input_dir + '*.pkl'))
            if not is_processed(input_path, output_dir))

        # assert len(rows) > 0, 'nothing calculated'

        scores = eval_map(input_dir, output_dir)

        summ = pd.Series(scores).describe()
        print(summ)
        summ.to_pickle(eval_result_path)


from django.db import models
from django.conf import settings

# Create your models here.
class Genre(models.Model):
    name = models.CharField(max_length=20)

class Movie(models.Model):
    title = models.CharField(max_length=50)
    audience = models.IntegerField()
    poster_url = models.CharField(max_length=200)
    description = models.TextField()
    # related_name을 해야 장르가 영화에 대한 정보를 가지고올 수 있다.
    # related_name을 쓰지않고 genre.movie를 가지고오려면 movie_set하면 된다
    # Movie.genre는 가지고올 수 있음 why? 모델안에 존재하기 때문!
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE, related_name='movies')

class Review(models.Model):
    content = models.CharField(max_length=80)
    score = models.IntegerField()
    #  알아서 db에 movie_id로 저장시킨다.
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE, related_name='movies')
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='movies')


""" Utilities used in building example surfaces. """

from itertools import count as naturals
from math import inf
from typing import Any, Callable, Iterable, Optional, Tuple
import re

def integers(start: Optional[int] = None, stop: Optional[int] = None) -> Iterable[int]:
    """Return an iterable that yields all of the integers."""

    if start is not None and stop is not None:
        return range(start, stop)
    elif start is None and stop is not None:
        return naturals(stop, -1)
    elif start is not None and stop is None:
        return naturals(start)

    return (z for n in naturals() for z in (n, ~n))

def extract_curve_and_test(curve_names: str, name: str) -> Tuple[str, Callable[[Any], bool]]:
    """Return a curve and a test to apply for which of it's components to twist."""

    twist_match = re.match(rf"(?P<curve>[{curve_names}])_(?P<n>-?\d+)$", name)
    twist_index_match = re.match(rf"(?P<curve>[{curve_names}])\[ *(?P<n>-?\d+) *\]$", name)
    twist_slice_match = re.match(rf"(?P<curve>[{curve_names}])(\[ *(?P<start>-?\d*) *: *(?P<stop>-?\d*) *(: *(?P<step>-?\d*) *)?\])?$", name)
    twist_expr_match = re.match(rf"(?P<curve>[{curve_names}])\{{(?P<expr>.*)\}}$", name)

    if twist_match is not None:
        parameters = twist_match.groupdict()
        curve = parameters["curve"]
        n = int(parameters["n"])
        test = lambda edge: edge == n
    elif twist_index_match is not None:
        parameters = twist_index_match.groupdict()
        curve = parameters["curve"]
        n = int(parameters["n"])
        test = lambda edge: edge == n
    elif twist_slice_match is not None:
        parameters = twist_slice_match.groupdict()
        curve = parameters["curve"]
        start = int(parameters["start"]) if parameters["start"] else -inf
        stop = int(parameters["stop"]) if parameters["stop"] else inf
        step = int(parameters["step"]) if parameters["step"] else 1
        test = lambda edge: start <= edge < stop and (edge % step == (0 if start == -inf else start % step))
    elif twist_expr_match is not None:
        parameters = twist_expr_match.groupdict()
        curve = parameters["curve"]
        test = lambda n: eval(parameters["expr"], {"n": n, **globals()})  # pylint: disable=eval-used
    else:
        raise ValueError(f"Unknown mapping class {name}")

    return curve, test


### Module imports ###
import time
import argparse
from utils import VnAnnotator, read_txt

### Global Variables ###
text_path = 'vi_text.txt'

### Class declarations ###

### Function declarations ###
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--lib', type=str, default='', required=True)
    parser.add_argument('--mode', type=str, default='', required=True)
    args = parser.parse_args()

    annotator = VnAnnotator()
    text_list = read_txt(text_path)
    output = f'{args.lib}/{args.mode}_{args.lib}_output.txt'
    t = time.time()
    annotator.annotate(args.lib, text_list, args.mode, output)
    print(time.time() - t)


import requests
import bs4
import numpy as np
import matplotlib.pyplot as plt

#These are the index number when calling specific categories
#stats
games_played_in_season = 0
games_played_in_career = 1
ppg_season = 2
ppg_career = 3
rpg_season = 4
rpg_career = 5
apg_season = 6
apg_career = 7
#percentages
fgp_season = 8
fgp_career = 9
threepp_season = 10
threepp_career = 11
ftp_season = 12
ftp_career = 13
efgp_season = 14
efgp_career = 15

def get_player_info(player_name):
    base_url = "http://basketball-reference.com/players/"
    player = player_name.lower()
    player_last_initial = str(player.split(' ')[1][0])
    player_last_name = str(player.split(' ')[1][0:5])
    player_first_two = str(player.split(' ')[0][0:2])
    url = base_url + player_last_initial + '/' + player_last_name + player_first_two + '01.html'

    result = requests.get(url)
    soup = bs4.BeautifulSoup(result.text, 'lxml')
    stats = soup.select('.stats_pullout')

    player_stats = []
    for stat in stats:
        var = stat.select('div')[2]
        nvar = var.select('p')
        for i in nvar:
            i=str(i)
            x=i.split('
')[1]
            x=x.split('
')[0]
            player_stats.append(x)
    for stat in stats:
        var = stat.select('div')[7]
        nvar = var.select('p')
        for i in nvar:
            i=str(i)
            x=i.split('
')[1]
            x=x.split('
')[0]
            player_stats.append(x)
    return player_stats

def main():
    print('Welcome to an NBA stat comparison program. You will enter two NBA players to compare and be shown'
          'their current season and career averages in 12 different categories!\n')
    play1 = input('Enter a currently active NBA player: ')
    play2 = input('Enter another currently active NBA player: ')
    player1 = get_player_info(play1)
    player2 = get_player_info(play2)
    player1_stats = []
    player2_stats = []
    for i in player1:
        i = float(i)
        player1_stats.append(i)
    for x in player2:
        x = float(x)
        player2_stats.append(x)

    info_matrix = [player1_stats,player2_stats]

    color = ['black', 'blue']

    print()
    print(f'{play1} = {color[0]}\n{play2} = {color[1]}')
    plt.figure()
    for i in range(2):
        s=2
        w=0.8
        plt.bar(np.arange(len(info_matrix[0][2:8]))*s+(i*w), info_matrix[i][2:8], color=color[i])
        plt.xticks(ticks=[0,2,4,6,8,10],
                   labels=['PPG_S','PPG_C','RPG_S','RPG_C','APG_S','APG_C']);
    print()
    print()
    plt.figure()
    for i in range(2):
        s=2
        w=0.8
        plt.bar(np.arange(len(info_matrix[0][8:14]))*s+(i*w), info_matrix[i][8:14], color=color[i])
        plt.xticks(ticks=[0,2,4,6,8,10],
                   labels=['FG%_S','FG%_C','3P%_S','3P%_C','FT%_S','FT%_C']);

main()


import fragmenter
from openeye import oechem
import pandas as pd
import json
import socket
import getpass

validation_set_input = pd.read_csv('../filter/validation_set/drugbank_filtered.csv')

# Clean up names = remove space because it causes bash scripts to crash
for name in validation_set_input['name']:
    if ' ' in name:
        name_split = name.split(' ')
        new_name = ''
        for n in name_split[:-1]:
            new_name += n
            new_name += '_'
        new_name += name_split[-1]
        validation_set_input.replace(to_replace=name, value=new_name, inplace=True)
    if name[0].isdigit():
        new_name = 'four' + name[1:]
        name = new_name
        validation_set_input.replace(to_replace=name, value=new_name, inplace=True)
# save csv with fixed names
validation_set_input.to_csv('../filter/validation_set/drugbank_filtered_fixed_names.csv')

provenance = {}
provenance['creator'] = "fragmenter"
provenance['hostname'] = socket.gethostname()
provenance['username'] = getpass.getuser()
provenance['routine'] = {'enumerate_states' : {'version': fragmenter.__version__,
                        'options': {'stereoisomers': False, 'explicit_h': False, 'filter_nitro': True}}}

all_states =[]
all_names = []
for smiles, name in zip(validation_set_input.smiles, validation_set_input.name):
    mol = oechem.OEMol()
    oechem.OESmilesToMol(mol, smiles)
    mol.SetTitle(name)

    states, names = fragmenter.fragment.enumerate_states(mol,stereoisomers=False, explicit_h=False, return_names=True,
                                                   filter_nitro=True)

    states_dict = {'provenance': provenance, 'states': states}
    states_dict['provenance']['routine']['enumerate_states']['parent_molecule_name'] = name
    states_dict['provenance']['routine']['enumerate_states']['parent_molecule'] = smiles
    with open('validation_set/{}_states.json'.format(name), 'w') as f:
        json.dump(states_dict, f, indent=2, sort_keys=True)
    all_states.extend(states)
    all_names.extend(names)

fragmenter.chemi.to_pdf(molecules=all_states, names=all_names, fname='enumerated_states.pdf')
print('Number of molelcules to fragment: {}'.format(len(all_states)))


import foggie.utils.foggie_load as fog
import yt
from yt import YTQuantity,YTArray
from yt.data_objects.particle_filters import add_particle_filter
import numpy as np
import h5py

halo = 'Tempest'
hnum = '008508'

#Mogget
snap_name = '/Users/bnguyen/Downloads/DD2427/DD2427'
halo_c_v_name = '/Users/bnguyen/FOGGIE/foggie/halo_infos/'+hnum+'/nref11c_nref9f/halo_c_v'
trackname = '/Users/bnguyen/FOGGIE/foggie/halo_tracks/'+hnum+'/nref11n_selfshield_15/halo_track_200kpc_nref9'
masses_dir = '/Users/bnguyen/FOGGIE/foggie/halo_infos/'+hnum+'/nref11c_nref9f/'
hsfile = '/Users/bnguyen/Downloads/'+halo+'_RD0042_allhalostardata.h5'

f = h5py.File(hsfile,'r')
pids = f['particle_IDs'][:]
hids = f['host_IDs'].asstr()[:]
f.close()

def StarParts(pfilter, data):
    return data[("all", "particle_type")] == 2

add_particle_filter("stars", function=StarParts, filtered_type='all', requires=["particle_type"])

ds, region = fog.foggie_load(snap_name, trackname, find_halo_center=True, halo_c_v_name=halo_c_v_name, disk_relative=True, \
                            particle_type_for_angmom='young_stars', do_filter_particles=True, gravity=False,\
                            region='refine_box',masses_dir=masses_dir)

ds.add_particle_filter('stars')
ads = ds.all_data()

allstarmasses = ads['stars','particle_mass']

# Create version of star allstarmasses that contains only halo stars and
# lists the masses in the same order as the halostardata file
allstarinds = ads['stars','particle_index']
index = np.argsort(allstarinds) # put particle IDs for all stars in numerical order
sorted_allstars = allstarinds[index]
sorted_index = np.searchsorted(sorted_allstars,pids)
# Create a mask that will reorder an array so that it's in the same order as the halostardata
# file and will include only halo stars
pindex = np.take(index,sorted_index,mode="clip")
mask = allstarinds[pindex] != pids
res = np.ma.array(pindex,mask=mask)
massarr = allstarmasses[np.ma.compressed(res)].in_units('Msun')
# masarr now lists the masses of the stars in the same order that the halostardata file lists their
# particle IDs, host IDs, creation times, etc


from enum import Enum
from typing import Union, List, Optional, Tuple

from rich.color import Color, blend_rgb
from rich.console import ConsoleOptions, RenderResult, Console
from rich.measure import Measurement
from rich.segment import Segment
from rich.style import Style

from .cell import PlotCellStyle, PlotCellRenderer

class OneLinePlotStyle(Enum):
    """Styles for one-line plots.

    Args:
        cell_style (PlotCellStyle): One of the plot styles defined in PlotCellStyle.
    """

    LINE = PlotCellStyle.LINE_V
    """Style for line plots."""
    AREA = PlotCellStyle.BLOCK_V
    """Style for area plots"""
    HORIZON = PlotCellStyle.BLOCK_V
    """Style for horizon plots."""
    SHADE = PlotCellStyle.SHADE
    """Style for shaded plots."""

    def __new__(cls, *args, **kwargs):
        value = len(cls.__members__) + 1
        obj = object.__new__(cls)
        obj._value_ = value
        return obj

    def __init__(self, cell_style: PlotCellStyle):
        self.cell_style = cell_style

class Sparkline:
    """A console renderable to draw a Sparkline.

    Args:
        values (List[float]): Values displayed in the Sparkline.
        value_range (Tuple[float, float], optional): Range of values displayed in the Sparkline.
        color (Union[Color, str]): Color of the Sparkline.
        bgcolor (Union[Color, str]): Background color of the Sparkline.
        plot_style (OneLinePlotStyle): One of the plot styles defined in OneLinePlotStyle.
        end (str): End character. Defaults to "\n".
    """

    def __init__(
        self,
        values: List[float],
        value_range: Optional[Tuple[float, float]] = None,
        color: Union[Color, str] = "default",
        bgcolor: Union[Color, str] = "default",
        plot_style: OneLinePlotStyle = OneLinePlotStyle.AREA,
        end: str = "\n",
    ):
        self.values = values
        self.value_range = value_range
        self.style = Style(color=color, bgcolor=bgcolor)
        self.plot_style = plot_style
        self.end = end

    def __rich_console__(
        self, console: Console, options: ConsoleOptions
    ) -> RenderResult:
        value_range = self.value_range or (min(self.values), max(self.values))
        cell_style = self.plot_style.cell_style

        if self.plot_style == OneLinePlotStyle.HORIZON:
            lower, upper = value_range
            mid = lower + (upper - lower) / 2
            mid_shade = Color.from_triplet(
                blend_rgb(
                    self.style.bgcolor.get_truecolor(),
                    self.style.color.get_truecolor(),
                    0.5,
                )
            )
            lower_style = Style(bgcolor=self.style.bgcolor, color=mid_shade)
            upper_style = Style(bgcolor=mid_shade, color=self.style.color)
            for value in self.values:
                cell = PlotCellRenderer.render(
                    value=value,
                    value_range=(lower, mid) if value < mid else (mid, upper),
                    cell_style=cell_style,
                )
                yield Segment(cell, style=lower_style if value < mid else upper_style)
        else:
            cells = ""
            for value in self.values:
                cells += PlotCellRenderer.render(
                    value=value, value_range=value_range, cell_style=cell_style
                )
            yield Segment(cells, self.style)
        yield Segment(self.end)

    def __rich_measure__(
        self, console: Console, options: ConsoleOptions
    ) -> Measurement:
        width = len(self.values)
        return Measurement(width, width)

if __name__ == "__main__":
    from math import sin, pi
    from rich.table import Table

    WIDTH_CONSOLE = 120

    def wave(
        num: int, offset: int = 0, seed: int = 0, scale: float = 1.0
    ) -> List[float]:
        result = [sin(2 * pi * (d + offset) / 10) for d in range(num)]
        if seed > 0:  # overlay second wave
            result = [
                val * sin(2 * pi * d / (40 + seed * 5)) * scale
                for d, val in enumerate(result)
            ]
        return result

    # Sparkline Table Example

    data = wave(22, 0)

    table = Table()
    table.add_column("Plot Style")
    for style in OneLinePlotStyle:
        table.add_column(style.name)
    lines = [
        Sparkline(
            values=data,
            color="purple",
            value_range=(-1.5, 1.5),
            plot_style=style,
        )
        for style in OneLinePlotStyle
    ]
    table.add_row("Sparkline", *lines)

    console = Console(record=True, width=WIDTH_CONSOLE)
    console.print()
    console.print(table, justify="center")
    console.print()