import os

from torch.utils.data import DataLoader, random_split

from torchvision import transforms
from torchvision.datasets import ImageFolder

def load_dataset(
        data_transforms,
        dataset_dir='./dataset',
        dataset_name='catdog',
        is_train=True,
):
    dataset_dir = os.path.join(dataset_dir, dataset_name)
    is_train_dir = 'train' if is_train else 'test'

    dataset = ImageFolder(
        os.path.join(dataset_dir, is_train_dir),
        data_transforms[is_train_dir],
    )
    return dataset

def get_loaders(config, input_size):
    data_transforms = {
        'train': transforms.Compose([
            transforms.RandomResizedCrop(input_size),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
        ]),
        'test': transforms.Compose([
            transforms.Resize(input_size),
            transforms.CenterCrop(input_size),
            transforms.ToTensor(),
        ])
    }

    dataset_name = config.dataset_name
    train_set = load_dataset(
        data_transforms, dataset_name=dataset_name, is_train=True
    )
    test_set = load_dataset(
        data_transforms, dataset_name=dataset_name, is_train=True
    )

    # Shuffle dataset to split into valid/test set.
    train_set, valid_set, test_set = divide_dataset(
        train_set, test_set, config.dataset_name,
        config.train_ratio, config.valid_ratio, config.test_ratio
    )

    train_loader = DataLoader(
        dataset=train_set,
        batch_size=config.batch_size,
        shuffle=True, # training은 무조건 shuffling, 안하면 학습이 되지 않음
    )

    valid_loader = DataLoader(
        dataset=valid_set,
        batch_size=config.batch_size,
        shuffle=True,
    )

    test_loader = DataLoader(
        dataset=test_set,
        batch_size=config.batch_size,
        shuffle=False, # 보통 False, 일부 수정된 부분에 대한 동작/결과를 보고자 할 때,
                       # 같은 테스트셋으로 진행해야 그 수정이 올바르게 되었는지 알 수 있음
    )

    return train_loader, valid_loader, test_loader

def divide_dataset(
        train_set,
        test_set,
        data_name='catdog',
        train_ratio=.6,
        valid_ratio=.2,
        test_ratio=.2,
):
    if data_name == 'catdog': # test set은 labeling이 안되어 있기 때문에, train set으로 새로 만듦
        train_cnt = int(len(train_set) * train_ratio)
        valid_cnt = int(len(train_set) * valid_ratio)
        test_cnt = len(train_set) - train_cnt - valid_cnt

        train_set, valid_set, test_set = random_split(
            train_set,
            [train_cnt, valid_cnt, test_cnt]
        )

    elif data_name == 'hymenoptera':
        valid_ratio = valid_ratio / (train_ratio + valid_ratio)
        valid_cnt = int(len(train_set) * valid_ratio)
        train_cnt = len(train_set) - valid_cnt

        train_set, valid_set = random_split( #dataset 객체를 random하게 split하는 함수
            train_set,
            [train_cnt, valid_cnt]
        )
    else:
        raise NotImplementedError('You need to specify dataset name.')

    return train_set, valid_set, test_set


# settings.py

from langchain.callbacks.base import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

def init_settings(retriever, llm, chain):
    retriever.search_kwargs['distance_metric'] = 'cos'
    retriever.search_kwargs['fetch_k'] = 10
    retriever.search_kwargs['maximal_marginal_relevance'] = True
    retriever.search_kwargs['k'] = 10

    llm.model_name = 'gpt-3.5-turbo'
    llm.temperature = 0
    llm.streaming = True
    llm.callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])
    llm.verbose = True

    chain.max_tokens_limit = 4096
    chain.return_source_documents = True

    return retriever, llm, chain


from pytube import YouTube

# Define function to download video from YouTube with the highest resolution using the pytube library.
def Down(giv_link):
    youtubeObject = YouTube(giv_link)
    youtubeObject = youtubeObject.streams.get_highest_resolution()
    try:
        youtubeObject.download()
    except:
        print("An error has occurred")
    print("Download is completed successfully")

giv_link = input("Paste the link of the YouTube video you want to download: ")
# Calls the download funtion and downloads input URL to home directory, in the folder.
Down(giv_link)


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

import re
import inspect
import copy
from math import ceil

from flask import request, jsonify
from flask.ext.classy import FlaskView, route
from marshmallow.utils import is_collection

class Pagination(object):

    def __init__(self, iterable, page, per_page):
        iterable = list(iterable)
        self.total = len(iterable)
        offset = (page-1) * per_page
        limit = min(offset+per_page, self.total)
        self.items = iterable[offset:limit]
        self.page = page
        self.per_page = per_page

    @property
    def pages(self):
        if self.per_page == 0:
            pages = 0
        else:
            pages = int(ceil(self.total / float(self.per_page)))
        return pages

def uncamel(name):
    s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

class ResourceApi(FlaskView):
    trailing_slash = False
    endpoint_prefix = 'api'
    route_prefix = '/api'
    name_suffix = 'Api'
    obj = None

    @classmethod
    def build_route_name(cls, method_name):
        parts = []
        if hasattr(cls, 'endpoint_prefix') and cls.endpoint_prefix is not None:
            parts.append(cls.endpoint_prefix)
        parts.append(cls.get_basic_name())
        if method_name:
            parts.append(method_name)
        return '.'.join(parts)

    @classmethod
    def get_basic_name(cls):
        return uncamel(re.sub('(.)({})'.format(cls.name_suffix),
                              r'\1', cls.__name__))

    @classmethod
    def register(cls, app, route_base=None, subdomain=None, route_prefix=None,
                 trailing_slash=None):
        super(ResourceApi, cls).register(app, route_base=route_base,
                           subdomain=subdomain, route_prefix=route_prefix,
                           trailing_slash=trailing_slash)

        isnested = lambda o: isinstance(o, NestedApi)

        members = inspect.getmembers(cls, predicate=isnested)
        for name, value in members:
            nested_cls = value.nested_cls
            value.register(name, app, cls)

class NestedApi(object):

    def __init__(self, nested_cls, pk_name='pk', pk_converter='any',
                 getter='get_obj'):
        self.nested_cls = nested_cls
        self.pk_name = pk_name
        self.pk_converter = pk_converter
        self.getter = getter

    def register(self, attr_name, app, parent):
        """
        This is a lazy implementation to register nested api, by the moment
        this fits well for this project.
        """
        prefix_parts = []
        class cls(self.nested_cls):
            pass
        cls.__name__ = self.nested_cls.__name__

        getter = parent.__dict__.get(self.getter, None)
        if not getter or not isinstance(getter, classmethod):
            raise ValueError("Parent class ({}) must define '{}' as "
                    "classmethod".format(parent.__name__, self.getter))

        if parent.route_prefix:
            prefix_parts.append(parent.route_prefix)
        if parent.get_route_base():
            prefix_parts.append(parent.get_route_base())

        route_parts = [
            '<{}:{}>'.format(self.pk_converter, self.pk_name),
            attr_name,
        ]

        # change endpoint prefix for registration
        cls.endpoint_prefix = parent.build_route_name(None)

        cls.register(app, route_prefix='/'.join(prefix_parts),
                     route_base='/'.join(route_parts))

        def before_request(nested, name, **kwargs):
            pk = request.view_args.pop(self.pk_name, None)
            nested.obj = getattr(parent, self.getter)(pk)
            if hasattr(nested, 'orig_before_request'):
                return nested.orig_before_request(name, **request.view_args)

        if hasattr(cls, 'before_request'):
            cls.orig_before_request = cls.before_request
        cls.before_request = before_request
        cls.parent = parent

def build_result(query, schema):

    if is_collection(query):
        if hasattr(query, 'paginate') and callable(query.paginate):
            result = query.paginate(request.page, request.per_page)
        else:
            result = Pagination(query, request.page, request.per_page)

        out = {
            'num_results': result.total,
            'page': result.page,
            'num_pages': result.pages,
        }
        items = result.items

    else:
        items = query

    if request.select or request.omit:
        schema = copy.copy(schema)
        if list(request.select)[0]:
            schema.only = request.select.intersection(schema.fields.keys())
        if list(request.omit)[0]:
            only_set = set(schema.only or schema.fields.keys())
            schema.only = only_set.difference(request.omit)

        if schema.only:
            schema.only.add('id')

    if is_collection(items):
        out['objects'] = schema.dump(items, many=True).data
    else:
        out = schema.dump(items, many=False).data

    return jsonify(out)


import os
import struct
import numpy as np

import torch
import torch.nn as nn
import torch.utils.data
from torch.autograd import Variable
import torch.nn.functional as F

## Network structure
class myNetwork(nn.Module):
    def __init__(self):
        super(myNetwork,self).__init__()
        self.fc = nn.Sequential(nn.Linear(3,64),
                                    nn.ReLU(inplace=True),
                                    nn.Linear(64,16),
                                    nn.ReLU(inplace=True),
                                    nn.Linear(16,1))

    def forward(self, data_input):
        out = self.fc(data_input)
        return out

## Data folders
class myTrainFolder(torch.utils.data.Dataset):
    def __init__(self, data_file, gt_file, training=True):
        dataset = self._read_data(data_file)
        gt = self._read_gt(gt_file)
        n = dataset.shape[0]
        assert n==gt.shape[0]
        if training:
            self.dataset = dataset[:int(n*0.8),:]
            self.gt = gt[:int(n*0.8)]
        else:
            self.dataset = dataset[int(n*0.8):,:]
            self.gt = gt[int(n*0.8):]

    def _read_data(self, file_name):
        with open(file_name, 'r') as f1:
            content = f1.read()
            content = content.split('\n')[1:-1]
            content = ('\t'.join(content)).split('\t')
            out = np.array([float(a) for a in content])
            return out.reshape([-1, 3])

    def _read_gt(self, file_name):
        with open(file_name, 'r') as f1:
            content = f1.read()
            content = content.split('\n')[1:-1]
            content = ('\t'.join(content)).split('\t')
            out = np.array([float(a) for a in content])
            return out

    def __getitem__(self, index):
        data = torch.from_numpy(self.dataset[index]).type(torch.float)
        gt = torch.tensor(self.gt[index]).type(torch.float)
        return data, gt

    def __len__(self):
        return self.dataset.shape[0]

class myTestFolder(torch.utils.data.Dataset):
    def __init__(self, data_file):
        self.dataset = self._read_data(data_file)

    def _read_data(self, file_name):
        with open(file_name, 'r') as f1:
            content = f1.read()
            content = content.split('\n')[1:-1]
            content = ('\t'.join(content)).split('\t')
            out = np.array([float(a) for a in content])
            return out.reshape([-1, 3])

    def __getitem__(self, index):
        data = torch.from_numpy(self.dataset[index]).type(torch.float)
        return data

    def __len__(self):
        return self.dataset.shape[0]

## result writer
def write_result(file_name, result):
    with open(file_name, 'w') as f1:
        f1.write('y\n')
        for row in range(len(result)):
            f1.write(str(result[row]) + '\n')


"""
test_objects.py
Unit tests for Game and GameObject methods.
"""
# Python standard library

# Third-party modules
import pytest

# Local modules
from objects import GameBoard, Ship
from enums import Directions

@pytest.fixture(scope="function")
def gameboard() -> GameBoard:
    """
    Fixture for creating an empty GameBoard object with size 2x2
    """
    gameboard = GameBoard(1, 1)

    yield gameboard

@pytest.fixture(scope="session")
def ship() -> Ship:
    """
    Fixture for creating a ship object that can scan and move
    """
    ship = Ship(
        scan_radius=1,
        movement_speed=1,
        actions=("movement", "sensors"),
        formal_name="MCRN Donnager",
        phrase_key="pytest_ship",
    )

    yield ship

def test_move(gameboard: GameBoard, ship: Ship):

    """
    Tests objects get moved and information for both player and board get updated successfully
    """

    gameboard.add_ship_to_board(ship, (0, 0))

    assert ship.coordinates == (0, 0)
    assert (0, 0) in gameboard.occupied_squares.keys()

    gameboard.move_object(ship, (1, 1))
    assert ship.coordinates == (1, 1)
    assert (1, 1) in gameboard.occupied_squares.keys()
    assert (0, 0) not in gameboard.occupied_squares.keys()

# This is kind of gross, but we want a second ship fixture with different names/phrase keys for test_scan.
newship = ship

def test_scan(gameboard: GameBoard, ship: ship, newship: ship, capfd: pytest.fixture):
    """
    Add another ship to the board and run the scan function.
    Check the output matches what is expected.
    """
    newship.formal_name = "USS Reliant"
    newship.phrase_key = "pytest_scan_target"
    print(ship.name)

    gameboard.add_ship_to_board(ship, (0, 0))
    gameboard.add_ship_to_board(newship, (0, 1))

    ship.scan(gameboard.occupied_squares)
    out, err = capfd.readouterr()
    EXPECTED_SCAN_OUTPUT = '\nTarget: USS Reliant detected. This object is 1 sectors from here.\nTarget: MCRN Donnager detected. This object is 0 sectors from here.\n'
    assert out == EXPECTED_SCAN_OUTPUT

def test_calculate_updated_location_and_validate(gameboard: GameBoard):

    """
    Tests movement direction and validation logic.
    """
    direction = Directions.EAST
    location = (0, 0)
    speed = 1

    new_location = gameboard.calculate_updated_location_and_validate(
        location, (direction, speed)
    )

    assert new_location != (0, 1)

    # This is a movement off the board and should return None.
    direction = Directions.WEST
    new_location = gameboard.calculate_updated_location_and_validate(
        location, (direction, speed)
    )
    assert new_location is None

def test_add_ship_to_board(gameboard, ship):

    """
    Tests that randomly adding ships will fill up the board
    Also tests that adding ship to full board or occupied square will fail as expected
    """

    for _ in range(0, 4):
        gameboard.add_ship_to_board(ship)

    # The board should now be fully occupied.
    assert len(gameboard.occupied_squares.keys()) == gameboard.total_squares

    # Adding with no location should fail to get a random square
    with pytest.raises(RuntimeError):
        gameboard.add_ship_to_board(ship)

    with pytest.raises(ValueError):
        gameboard.add_ship_to_board(ship, (0, 0))


# coding=utf-8

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import pickle
import numpy as np
from nash_cournot import NashCournot
from scipy.integrate import odeint

def sim_ode_yosida_secndord(prob_inst, t_len, pt_cnt=100, param_alpha=3.0, param_epsilon=3.0):

  def ode_yosida_secndord(x_vec, t):

    state_dim = prob_inst.state_dim
    state_vec = x_vec[:state_dim].copy().reshape((-1, 1))
    derv_vec = x_vec[state_dim:].copy().reshape((-1, 1))

    # dot state_vec
    vec_field = np.zeros_like(x_vec)
    vec_field[:state_dim] = x_vec[state_dim:].copy()

    # dot derv_vec
    lambda_val = ((1 + param_epsilon) / param_alpha**2) * t**2
    derv_vec_updt = -param_alpha/t * derv_vec - 1/lambda_val * (
      state_vec - prob_inst.resolvent(state_vec, lambda_val)
    )
    vec_field[state_dim:] = derv_vec_updt.reshape((-1,))

    return vec_field

  x_vec_init = prob_inst.random_state.uniform(
    low=0, high=1, size=(prob_inst.state_dim * 2, 1)
  )
  x_vec_init[:prob_inst.state_dim, :] = prob_inst.project(
    x_vec_init[:prob_inst.state_dim])
  x_vec_init = x_vec_init.reshape((-1, ))
  t_range = np.linspace(t_len/pt_cnt + 10, t_len + 10, pt_cnt)
  flow = odeint(ode_yosida_secndord, x_vec_init, t_range)

  return flow

def main():
  t_len = 1000

  prob_inst = NashCournot()
  sol = prob_inst.compute_ne().reshape((1, -1))

  # Trail 1
  data_save_path = './pkl/yosida_{}_{}.pkl'
  param_alpha, param_epsilon = 20, 20
  traject = sim_ode_yosida_secndord(prob_inst, t_len, pt_cnt=5000, param_alpha=param_alpha, param_epsilon=param_epsilon)

  diff = traject[:, :prob_inst.state_dim] - sol
  diff_norm = np.linalg.norm(diff, axis=1, ord=2)
  print(diff_norm)
  save_dict = {'diff_norm': diff_norm}
  with open(data_save_path.format(param_alpha, param_epsilon), 'wb') as pkl_writer:
    pickle.dump(save_dict, pkl_writer)

  # Trail 2
  param_alpha, param_epsilon = 10, 10
  traject = sim_ode_yosida_secndord(prob_inst, t_len, pt_cnt=5000, param_alpha=param_alpha, param_epsilon=param_epsilon)

  diff = traject[:, :prob_inst.state_dim] - sol
  diff_norm = np.linalg.norm(diff, axis=1, ord=2)
  print(diff_norm)
  save_dict = {'diff_norm': diff_norm}
  with open(data_save_path.format(param_alpha, param_epsilon), 'wb') as pkl_writer:
    pickle.dump(save_dict, pkl_writer)

if __name__ == '__main__':
  main()


#!/usr/bin/python3
"""
Module 8-model_state_fetch_first
list first state in table states
"""
from sys import argv
from model_state import Base, State
from sqlalchemy import (create_engine)
from sqlalchemy.orm import sessionmaker

if __name__ == '__main__':
    engine = create_engine('mysql+mysqldb://{}:{}@localhost:3306/{}'
                           .format(argv[1], argv[2], argv[3]))

    Base.metadata.create_all(engine)
    Session = sessionmaker(bind=engine)
    session = Session()
    inst = session.query(State).first()

    if inst is None:
        print("Nothing")
    else:
        print(inst.id, inst.name, sep=": ")


from __future__ import annotations

import re
from collections.abc import Mapping

from pipenv.exceptions import PipenvUsageError
from pipenv.patched.pip._vendor.urllib3.util import parse_url
from pipenv.utils.constants import MYPY_RUNNING

from .internet import create_mirror_source, is_pypi_url

if MYPY_RUNNING:
    from typing import List, Optional, Union  # noqa

    from pipenv.project import Project, TSource  # noqa

def prepare_pip_source_args(sources, pip_args=None):
    if pip_args is None:
        pip_args = []
    if sources:
        # Add the source to pip.
        package_url = sources[0].get("url")
        if not package_url:
            raise PipenvUsageError("[[source]] section does not contain a URL.")
        pip_args.extend(["-i", package_url])
        # Trust the host if it's not verified.
        if not sources[0].get("verify_ssl", True):
            url_parts = parse_url(package_url)
            url_port = f":{url_parts.port}" if url_parts.port else ""
            pip_args.extend(["--trusted-host", f"{url_parts.host}{url_port}"])
        # Add additional sources as extra indexes.
        if len(sources) > 1:
            for source in sources[1:]:
                url = source.get("url")
                if not url:  # not harmless, just don't continue
                    continue
                pip_args.extend(["--extra-index-url", url])
                # Trust the host if it's not verified.
                if not source.get("verify_ssl", True):
                    url_parts = parse_url(url)
                    url_port = f":{url_parts.port}" if url_parts.port else ""
                    pip_args.extend(["--trusted-host", f"{url_parts.host}{url_port}"])
    return pip_args

def get_project_index(
    project: Project,
    index: str | TSource | None = None,
    trusted_hosts: list[str] | None = None,
) -> TSource:
    from pipenv.project import SourceNotFound

    if trusted_hosts is None:
        trusted_hosts = []
    if isinstance(index, Mapping):
        return project.find_source(index.get("url"))
    try:
        source = project.find_source(index)
    except SourceNotFound:
        index_url = parse_url(index)
        src_name = project.src_name_from_url(index)
        verify_ssl = index_url.host not in trusted_hosts
        source = {"url": index, "verify_ssl": verify_ssl, "name": src_name}
    return source

def get_source_list(
    project: Project,
    index: str | TSource | None = None,
    extra_indexes: str | list[str] | None = None,
    trusted_hosts: list[str] | None = None,
    pypi_mirror: str | None = None,
) -> list[TSource]:
    sources = project.sources[:]
    if index:
        sources.append(get_project_index(project, index))
    if extra_indexes:
        if isinstance(extra_indexes, str):
            extra_indexes = [extra_indexes]

        for source in extra_indexes:
            extra_src = get_project_index(project, source)
            if not sources or extra_src["url"] != sources[0]["url"]:
                sources.append(extra_src)

        for source in project.sources:
            if not sources or source["url"] != sources[0]["url"]:
                sources.append(source)

    if pypi_mirror:
        sources = [
            create_mirror_source(pypi_mirror, source["name"])
            if is_pypi_url(source["url"])
            else source
            for source in sources
        ]
    return sources

def parse_indexes(line, strict=False):
    from argparse import ArgumentParser

    comment_re = re.compile(r"(?:^|\s+)#.*$")
    line = comment_re.sub("", line)
    parser = ArgumentParser("indexes", allow_abbrev=False)
    parser.add_argument("-i", "--index-url", dest="index")
    parser.add_argument("--extra-index-url", dest="extra_index")
    parser.add_argument("--trusted-host", dest="trusted_host")
    args, remainder = parser.parse_known_args(line.split())
    index = args.index
    extra_index = args.extra_index
    trusted_host = args.trusted_host
    if (
        strict
        and sum(bool(arg) for arg in (index, extra_index, trusted_host, remainder)) > 1
    ):
        raise ValueError("Index arguments must be on their own lines.")
    return index, extra_index, trusted_host, remainder


"""frame.py – Draws the selected frame sized to a given sheet and fills in the fields"""

import logging
import sys
from sqlalchemy import select, and_
from flatland.database.flatlanddb import FlatlandDB as fdb
from collections import namedtuple
from flatland.datatypes.geometry_types import Position, Rect_Size, Alignment, HorizAlign, VertAlign
from flatland.node_subsystem.canvas import points_in_mm
from flatland.text.text_block import TextBlock
import math
from flatland.sheet_subsystem.resource import resource_locator
from flatland.sheet_subsystem.titleblock_placement import draw_titleblock
from typing import TYPE_CHECKING, Dict

if TYPE_CHECKING:
    from flatland.node_subsystem.canvas import Canvas

DataBox = namedtuple('_Databox', 'metadata content position size alignment style')
FieldPlacement = namedtuple('_FieldPlacement', 'metadata position max_area')

class Frame:
    """
    On any serious project it is not adequate to generate model diagrams absent any metadata such as
    authors, dates, revision numbers, copyright notices, organization logos and so forth.
    A Frame represents a pattern of Fields and/or a Title Block Pattern on the surface area defined by
    a Sheet. The lower left corner placements of each Frame element (Field or Scaled Title Block) are
    customized to fit the dimensions of a given Sheet.

        Attributes

        - Name (str) -- Size independent name of the Frame such as 'Open Source Engineer' or 'Architect'
        - Canvas (obj) -- Canvas has selected a Sheet which determines Frame sizing
        - metadata (dict) -- <Metadata> : <Content>, such as 'Title' : 'Sheet Subsystem Class Diagram'
        - Open_fields (list) -- Open field metadata label and positional info loaded from flatland database
        - Databoxes (dict) -- All Databox data loaded from flatland database (See named tuple above)
    """

    def __init__(self, name: str, presentation: str, canvas: 'Canvas', metadata: Dict[str, str]):
        """
        Constructor

        :param name: Size independent name of the Frame such as 'Open Source Engineer' or 'Architect'
        :param canvas: Canvas has selected the Sheet which determines sizing
        :param presentation: They Frame's Presentation (determines all styling of Frame content)
        :param metadata: Text and images to display in the Frame
        """
        self.logger = logging.getLogger(__name__)
        self.Name = name
        self.Canvas = canvas
        self.Orientation = canvas.Orientation
        self.metadata = metadata
        self.Open_fields = []
        self.Databoxes = {}

        # Create a Layer where we'll draw all of the Frame contents

        self.logger.info('Creating Frame Layer')
        drawing_type_name = ' '.join([name, self.Canvas.Sheet.Size_group, 'frame'])  # e.g. "OS Engineer large frame"
        # Whereas a diagram's drawing type is something like 'xUML Class Diagram',
        # the Frame's drawing type name systematically incorporates both purpose and Sheet Size Group
        # That's because a model element like a class or state is typically drawn the same size regardless
        # of sheet size. Frame's, on the other hand are more likely to change proportions with large sheet size
        # differences.  That said, there is nothing preventing us from doing the same for diagram layers on a case by
        # case basis. So an 'xUML Class Diagram tiny' could certainly be defined by us or a user in the future
        self.Layer = self.Canvas.Tablet.add_layer(
            name='frame', presentation=presentation, drawing_type=drawing_type_name
        )  # We're gonna be drawing metadata and title block borders all over this thing.

        # If there is a title block cplace specified for this Frame, get the name of the pattern
        tb_placement_t = fdb.MetaData.tables['Title Block Placement']
        f = and_(
            (tb_placement_t.c['Frame'] == self.Name),
            (tb_placement_t.c['Sheet'] == self.Canvas.Sheet.Name),
            (tb_placement_t.c['Orientation'] == self.Orientation),
        )
        query = select([tb_placement_t.c['Title block pattern']]).select_from(tb_placement_t).where(f)
        row = fdb.Connection.execute(query).fetchone()
        # Nothing says "I'm a serious engineer or architect" more than a fancy bordered title block on your Frame,
        # but it is optional
        self.Title_block_pattern = None if not row else row[0]

        # If a Title Block Pattern is specified, let's gather all the Data Box content from the flatland database
        if self.Title_block_pattern:
            self.logger.info('Assembling title block pattern on frame')
            # Assemble a text block for each Data Box containing the Metadata Text Content
            # We'll register that text block with the Layer for rendering
            # Image (Resource) content is not supported within a Title Block Pattern, so we assume only text content
            # If any non-text Resources were mistakenly specified by the user, we will ignore them
            boxplace_t = fdb.MetaData.tables['Box Placement']  # Box positions and sizes, scaled for our Frame
            databox_t = fdb.MetaData.tables['Data Box']  # Alignment and style of text within box
            boxline_t = fdb.MetaData.tables['Box Text Line']  # Vertical ordering of metadata within a Data Box
            # s = select (row criteria), p = project (columns), j = join, q = query
            s = and_(
                (boxplace_t.c.Frame == self.Name),
                (boxplace_t.c.Sheet == self.Canvas.Sheet.Name),
                (boxplace_t.c.Orientation == self.Orientation),
                (boxplace_t.c['Title block pattern'] == self.Title_block_pattern),
            )
            p = [databox_t.c.ID, boxplace_t.c.X, boxplace_t.c.Y, boxplace_t.c.Width, boxplace_t.c.Height,
                 databox_t.c['H align'], databox_t.c['V align'], databox_t.c.Style,
                 boxline_t.c.Box, boxline_t.c.Order, boxline_t.c.Metadata]
            j = databox_t.join(
                boxplace_t,
                and_((databox_t.c.Pattern == boxplace_t.c['Title block pattern']), (databox_t.c.ID == boxplace_t.c.Box))
            ).join(
                boxline_t,
                and_((databox_t.c.Pattern == boxline_t.c['Title block pattern']), (databox_t.c.ID == boxline_t.c.Box))
            )
            q = select(p).select_from(j).where(s).order_by(boxplace_t.c.Box, boxline_t.c.Order)
            rows = fdb.Connection.execute(q).fetchall()
            # Populate our Databoxes dictionary from the row data we just fetched
            for r in rows:
                if r.Box in self.Databoxes:
                    # The Data Box was recorded with an initial text line, so this must be an additional line
                    try:
                        # Extract the user supplied metadata value for this Data Box
                        metadata_value = metadata[r.Metadata][0]
                    except KeyError:
                        self.logger.error(f"No metadata value supplied for: {r.Metadata}")
                        sys.exit(1)
                    self.Databoxes[r.Box].content.append(metadata_value)
                else:
                    # Rows are ordered by Data Box, so if the box id is new, we create an initial dictioary entry
                    # With level 1
                    self.Databoxes[r.Box] = DataBox(
                        content=[metadata[r.Metadata][0]],  # Text to render:  Leon Starr, mint.flatland.td.1, etc
                        position=Position(r.X, r.Y),  # Lower left corner of the Data Box
                        size=Rect_Size(height=r.Height, width=r.Width),
                        style=r.Style,  # Style of text inside this box such as: Block body, Block title, etc
                        metadata=r.Metadata,  # Name of data item: Author, Document ID, etc
                        # Finally, how text is aligned inside this box
                        alignment=Alignment(vertical=VertAlign[r['V align']], horizontal=HorizAlign[r['H align']])
                    )
            # All done with the title block Metacontent. We'll unwind all this when we render to our Layer

        # Gather the Open Field content (other text and graphics scattered around the Frame)
        self.logger.info('Assembling open fields on frame')
        open_field_t = fdb.MetaData.tables['Open Field']
        s = and_(
            (open_field_t.c['Frame'] == self.Name),
            (open_field_t.c['Sheet'] == self.Canvas.Sheet.Name),
            (open_field_t.c['Orientation'] == self.Orientation),
        )
        q = select([open_field_t]).where(s)
        rows = fdb.Connection.execute(q).fetchall()
        for r in rows:
            p = Position(round(r['x position'] * points_in_mm, 2), round(r['y position'] * points_in_mm, 2))
            ma = Rect_Size(round(r['max height'] * points_in_mm, 2), round(r['max width'] * points_in_mm, 2))
            self.Open_fields.append(
                FieldPlacement(metadata=r.Metadata, position=p, max_area=ma)
            )
        # All done with the Open Fields. Much easier to compute than Boxed Fields!

        # Now let's register all text and graphics for everything in our Frame on its Layer
        self.render()

    def render(self):
        """Draw the Frame on its Layer"""
        self.logger.info('Rendering frame')

        # Fill each open field
        for f in self.Open_fields:
            asset = 'Open ' + f.metadata.lower()
            content, isresource = self.metadata.get(f.metadata, (None, None))
            # If there is no data supplied to fill in the field, just leave it blank and move on
            if content and isresource:
                # Key into resource locator using this size and orientation delimited by an underscore
                rsize = '_'.join([content, self.Canvas.Sheet.Size_group, self.Canvas.Orientation])
                # Get the full path to the resource (image) using the rsize
                rloc = resource_locator.get(rsize)
                if rloc:
                    self.Layer.add_image(resource_path=rloc, lower_left=f.position, size=f.max_area)
                else:
                    self.logger.warning(
                        f"Couldn't find file for: [{content}] in your flatland resource directory. "
                        f"Default resource location is in ~/.flatland"
                    )
            elif content:  # Text content
                # Content is a line of text to print directly
                self.Layer.add_text_line(
                    asset=asset,
                    lower_left=f.position,
                    text=content,
                )

        if self.Title_block_pattern:
            # Draw the title block box borders
            draw_titleblock(frame=self.Name, sheet=self.Canvas.Sheet, orientation=self.Orientation, layer=self.Layer)

            # Get the margins to pad the Data Box content
            # The same margins are applied to each Data Box in the same Scaled Title Block
            # So we are looking only for one pair of h,v margin values to use throughout
            scaledtb_t = fdb.MetaData.tables['Scaled Title Block']
            s = and_(
                (scaledtb_t.c['Title block pattern'] == self.Title_block_pattern),
                (scaledtb_t.c['Sheet size group'] == self.Canvas.Sheet.Size_group),
            )
            p = [scaledtb_t.c['Margin H'], scaledtb_t.c['Margin V']]
            q = select(p).where(s)
            row = fdb.Connection.execute(q).fetchone()
            assert row, f"No Title Block Placement for frame: {self.Name}"
            h_margin, v_margin = row

            # Render all the box fields
            for k, v in self.Databoxes.items():
                # compute lower left corner position
                # Layer asset is composed from the data box style and its size group
                block_size = self.Layer.text_block_size(asset=v.style, text_block=v.content)
                # When there is a single line of text in a Data Box that is longer than the Box width,
                # we will wrap it as necessary. Especially useful for a long title in the title box
                # For multiple line boxes, this feature is not yet (or ever) supported
                padded_box_width = round(v.size.width - h_margin * 2, 2)
                content = v.content
                if len(v.content) == 1 and block_size.width > padded_box_width:
                    lines_to_wrap = math.ceil(block_size.width / padded_box_width)  # Round up to nearest int
                    content = TextBlock(v.content[0], wrap=lines_to_wrap).text
                    block_size = self.Layer.text_block_size(asset=v.style, text_block=content)
                # For now we will just let any exessive line length in multi field Data Boxes
                # overrun the title block boundary, since it is not so obvious how to recover automatically
                # User correction is more likely to yield a satisfactory outcome
                # They can either use more box fields, use shorter lines of text, change the size of
                # the Title Block Pattern or just create one that is larger and use that
                xpos = v.position.x + h_margin
                ypos = v.position.y + v_margin + round((v.size.height - block_size.height) / 2, 2)
                self.Layer.add_text_block(
                    asset=v.style, lower_left=Position(xpos, ypos), text=content, align=v.alignment.horizontal
                )


from collections import OrderedDict
from copy import deepcopy
from typing import Dict, MutableMapping, Optional, Sequence
from warnings import warn

from mudata import MuData
from pandas import DataFrame, concat
from singlecellexperiment import SingleCellExperiment
from summarizedexperiment import SummarizedExperiment
from summarizedexperiment.type_checks import is_bioc_or_pandas_frame, is_list_of_type

from .types import SlicerArgTypes, SlicerResult, SlicerTypes, StrOrListStr

__author__ = "jkanche"
__copyright__ = "jkanche"
__license__ = "MIT"

class MultiAssayExperiment:
    """Container class for representing and managing multi-omics genomic experiments. Checkout the
    `R/MultiAssayExperiment <https://bioconductor.org/packages/release/bioc/html/MultiAssayExperiment.html>`_
    for more information.

    Attributes:
            experiments (MutableMapping[str, SummarizedExperiment]): A dictionary of
                experiments with experiment names as keys and the experiments as values.

                Each ``experiment`` may be either a
                :py:class:`~summarizedexperiment.SummarizedExperiment.SummarizedExperiment`
                and any class that extends `SummarizedExperiment`.

            col_data (DataFrame]): Bio-specimen/sample information.
                The ``col_data`` may provide information about patients, cell lines, or
                other biological units.

                Each row in this table is an independent biological unit. Must contain an `index`
                that maps to primary in ``sample_map``.

            sample_map (DataFrame): Map biological units from
                :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.col_data`
                to the list of
                :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.experiments`.

                Must contain columns "assay", "primary" and "colname".

                - **assay** provides the names of the different experiments performed on the
                    biological units. All experiment names from
                    :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.experiments`
                    must be present in this column.
                - **primary** contains the sample name. All names in this column must match with
                    row labels from
                    :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.col_data`.
                - **colname** is the mapping of samples/cells within each experiment back to its
                    biosample information in
                    :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.col_data`.

                Each sample in ``col_data`` may map to one or more columns per assay.

                :py:class:`~multiassayexperiment.io.interface.make_mae`, or import functions to
                read data as ``MultiAssayExperiment`` from
                :py:class:`~multiassayexperiment.io.mudata.from_mudata` and
                :py:class:`~multiassayexperiment.io.anndata.from_anndata`.

            metadata (MutableMapping, optional): Additional study level metadata. Defaults to None.
    """

    def __init__(
        self,
        experiments: MutableMapping[str, SummarizedExperiment],
        col_data: DataFrame,
        sample_map: DataFrame,
        metadata: Optional[MutableMapping] = None,
    ) -> None:
        """Construct an MAE."""
        self._validate_experiments(experiments)
        self._validate_sample_map(
            sample_map=sample_map, col_data=col_data, experiments=experiments
        )
        self._sample_map = sample_map
        self._col_data = col_data
        self._experiments = experiments

        self._metadata = metadata

    def _validate_experiments(
        self, experiments: MutableMapping[str, SummarizedExperiment]
    ):
        """Internal method to validate experiments.

        Raises:
            TypeError: If experiments is not a :py:class:`~dict`.
        """
        if not isinstance(experiments, dict):
            raise TypeError("experiments must be a dictionary.")

    def _validate_col_data(self, col_data: DataFrame):
        """Internal method to validate ``col_data``.

        Args:
            col_data (DataFrame): Column data.

                ``col_data`` may be either a :py:class:`~pandas.DataFrame` or
                :py:class:`~biocframe.BiocFrame.BiocFrame` object.

        Raises:
            TypeError: If object is not an expected type.
        """
        if not is_bioc_or_pandas_frame(col_data):
            raise TypeError(
                "`col_data` must be either a pandas DataFrame or a BiocFrame object."
            )

        if isinstance(col_data, DataFrame):
            if col_data.index is None:
                raise ValueError("`col_data` must have an index column.")
        else:
            if col_data.row_names is None:
                raise ValueError("`col_data` must have row names or labels.")

    def _validate_sample_map_with_col_data(
        self, sample_map: DataFrame, col_data: DataFrame
    ):
        """Internal method to validate ``sample_map`` and ``col_data``.

        Args:
            sample_map (DataFrame): Sample mapping.
            col_data (DataFrame): Column data.

        Raises:
            ValueError: If any of the checks fail.
        """
        # check if unique samples is same as in sample data
        _samples = list(sample_map["primary"])
        _sample_set = set(_samples)
        _sample_diff = _sample_set.difference(col_data.index.tolist())
        if len(_sample_diff) > 0:
            raise ValueError(
                "'primary' from `sample_map` has unknown samples not present in `col_data`."
            )

        if len(_sample_set) != col_data.shape[0]:
            warn("'primary' from `sample_map` & `col_data` has missing samples.")

    def _validate_sample_map_with_Expts(
        self,
        sample_map: DataFrame,
        experiments: MutableMapping[str, SummarizedExperiment],
    ):
        """Internal method to validate ``sample_map`` and ``experiments``.

        Args:
            sample_map (DataFrame): Sample mapping.
            experiments (MutableMapping[str, SummarizedExperiment]): Experiments.

        Raises:
            ValueError: If any of the checks fail.
        """
        # check if all assay names are in experiments
        smapUniqueAssaynames = set(sample_map["assay"])
        UniqueExperimentname = set(list(experiments.keys()))

        if (len(UniqueExperimentname) != len(smapUniqueAssaynames)) or (
            UniqueExperimentname != smapUniqueAssaynames
        ):
            raise ValueError(
                "'assays' from sample_map does not match with `experiments`."
            )

        # check if colnames exist
        agroups = sample_map.groupby("assay")
        for group, rows in agroups:
            if group not in experiments:
                raise ValueError(
                    f"Experiment '{group}' exists in `sample_map` but not in `experiments`."
                )

            gcol_data = experiments[group].col_data

            if set(rows["colname"].tolist()) != set(gcol_data.index.tolist()):
                raise ValueError(
                    f"Experiment '{group}' does not contain all columns in `sample_map`."
                )

    def _validate_sample_map(
        self,
        sample_map: DataFrame,
        col_data: DataFrame,
        experiments: MutableMapping[str, SummarizedExperiment],
    ):
        """Validate sample map.

        Args:
            sample_map (DataFrame): Sample map.
            col_data (DataFrame): Column data.
            experiments (MutableMapping[str, SummarizedExperiment]): Experiments.

        Raises:
            TypeError, ValueError: If any of the checks fail.
        """
        if not is_bioc_or_pandas_frame(sample_map):
            raise TypeError(
                "`sample_map` must be either a pandas `DataFrame` or a `BiocFrame` object."
            )

        if not set(["assay", "primary", "colname"]).issubset(list(sample_map.columns)):
            raise ValueError(
                "`sample_map` does not contain required columns: 'assay', 'primary/ and `'colname'."
            )

        self._validate_sample_map_with_col_data(sample_map, col_data)
        self._validate_sample_map_with_Expts(sample_map, experiments)

    def _validate(self):
        """Internal method to validate the object.

        Raises:
            ValueError: If attributes don't match expectations.
        """
        self._validate_experiments(self._experiments)
        self._validate_col_data(self._col_data)
        self._validate_sample_map(self._sample_map, self._col_data, self._experiments)

    @property
    def experiments(
        self,
    ) -> Dict[str, SummarizedExperiment]:
        """Get experiments.

        Returns:
            Dict[str, SummarizedExperiment]: A dictionary of all experiments, with experiment
            names as keys and experiment data as value.
        """

        return self._experiments

    @experiments.setter
    def experiments(
        self,
        experiments: MutableMapping[str, SummarizedExperiment],
    ):
        """Set new experiments.

        Args:
            experiments (MutableMapping[str, SummarizedExperiment]): New experiments to set.
                A dictionary of experiments with experiment names as keys and the experiments
                as values.

                Each ``experiment`` may be either a
                :py:class:`~summarizedexperiment.SummarizedExperiment.SummarizedExperiment`
                and any class that extends `SummarizedExperiment`.
        """

        self._validate_experiments(experiments)
        self._validate_sample_map_with_Expts(self._sample_map, experiments)
        self._experiments = experiments

    def experiment(
        self, name: str, with_sample_data: bool = False
    ) -> SummarizedExperiment:
        """Get experiment by name.

        If ``with_sample_data`` is True, a copy of the experiment object is returned.

        Args:
            name (str): Experiment name.
            with_sampleData (bool, optional): Whether to merge column data of the experiment with
                sample data from the MAE. Defaults to False.

        Raises:
            ValueError: If experiment name does not exist.

        Returns:
            SummarizedExperiment: A class that extends
            :py:class:`~summarizedexperiment.SummarizedExperiment.SummarizedExperiment`.
        """
        if name not in self._experiments:
            raise ValueError(f"Experiment '{name}' does not exist.")

        expt = self.experiments[name]

        if with_sample_data is True:
            expt = deepcopy(expt)

            subset_map = self.sample_map[self.sample_map["assay"] == name]
            subset_map = subset_map.set_index("colname")

            expt_col_data = expt.col_data
            new_col_data = concat([subset_map, expt_col_data], axis=1)
            expt.col_data = new_col_data

        return expt

    @property
    def sample_map(self) -> DataFrame:
        """Get sample map between experiments and sample metadata.

        Returns:
            DataFrame: a DataFrame with sample mapping information.
        """
        return self._sample_map

    @sample_map.setter
    def sample_map(self, sample_map: DataFrame):
        """Set new sample mapping.

        Args:
            sample_map (DataFrame): New sample map.
        """
        self._validate_sample_map(sample_map, self._col_data, self._experiments)
        self._sample_map = sample_map

    @property
    def col_data(self) -> DataFrame:
        """Get sample metadata.

        Returns:
            DataFrame: Sample metadata.
        """
        return self._col_data

    @col_data.setter
    def col_data(self, col_data: DataFrame):
        """Set sample metadata.

        Args:
            col_data (DataFrame): New sample metadata.
        """
        self._validate_col_data(col_data)
        self._validate_sample_map_with_col_data(self._sample_map, col_data)
        self._col_data = col_data

    @property
    def assays(
        self,
    ) -> Dict[str, SummarizedExperiment]:
        """Get experiments.

        Alias to the
        :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.experiments`.

        Returns:
            Dict[str, SummarizedExperiment]: All experiments.
            A dictionary of experiments with experiment names as keys and the experiments
            as values.

            Each ``experiment`` may be either a
            :py:class:`~summarizedexperiment.SummarizedExperiment.SummarizedExperiment`
            and any class that extends `SummarizedExperiment`.
        """
        return self.experiments

    @property
    def metadata(self) -> Optional[Dict]:
        """Get metadata.

        Returns:
            Optional[Dict]: Metadata if available.
        """
        return self._metadata

    @metadata.setter
    def metadata(self, metadata: MutableMapping):
        """Set metadata.

        Args:
            metadata (MutableMapping): New metadata object.
        """
        self._metadata = metadata

    def _subset_experiments(
        self, subset: StrOrListStr
    ) -> Dict[str, SummarizedExperiment]:
        """Internal method to subset experiments.

        Args:
            subset (StrOrListStr): May be an single experiment name to keep.
                Alternatively, ``subset`` may be a list of experiment names.

        Returns:
            Dict[str, SummarizedExperiment]: A dictionary with experiment names as keys
            and the subsetted experiment data as value.
        """
        if isinstance(subset, str):
            subset = [subset]

        if not is_list_of_type(subset, str):
            raise ValueError("All provided experiment names must be `strings`.")

        newExpt = OrderedDict()

        for texpt in subset:
            if texpt not in self.experiments:
                raise ValueError(
                    f"experiment {texpt} does not exist. should be {list(self.experiments.keys())}"
                )
            newExpt[texpt] = self.experiments[texpt]

        return newExpt

    def _slice(
        self,
        args: SlicerArgTypes,
    ) -> SlicerResult:
        """Internal method to slice by index.

        Args:
            args (SlicerArgTypes): Indices or names to slice. Tuple
                contains slices along dimensions (rows, columns, experiments).

                Each element in the tuple, might be either a integer vector (integer positions),
                boolean vector or :py:class:`~slice` object. Defaults to None.

        Raises:
            ValueError: Too many or too few slices.

        Returns:
            SlicerResult: Sliced row, cols and assays.
        """

        if len(args) == 0:
            raise ValueError("`args` must contain at least one slice.")

        rowIndices = args[0]
        colIndices = None
        exptIndices = None

        if len(args) > 1:
            colIndices = args[1]

        if len(args) > 2:
            exptIndices = args[2]

            if exptIndices is not None:
                if isinstance(exptIndices, str):
                    exptIndices = [exptIndices]

                if not all([isinstance(x, str) for x in exptIndices]):
                    raise ValueError(
                        "All `experiments` in the 3rd slice for `args` must be strings."
                    )

        if len(args) > 3:
            raise ValueError("`args` contains too many slices.")

        subsetExpts = self.experiments.copy()

        if exptIndices is not None:
            subsetExpts = self._subset_experiments(exptIndices)

        if rowIndices is not None:
            if isinstance(rowIndices, dict):
                incorrect = set(list(rowIndices.keys())).difference(
                    list(subsetExpts.keys())
                )
                if len(incorrect) > 0:
                    raise ValueError(
                        f"Incorrect experiment names provided: {', '.join(incorrect)}."
                    )

                for expname, expt in subsetExpts.items():
                    if expname in rowIndices:
                        subsetExpts[expname] = expt[rowIndices[expname], :]
                    else:
                        subsetExpts[expname] = expt

            elif isinstance(rowIndices, slice) or all(
                isinstance(x, int) for x in rowIndices
            ):
                for expname, expt in subsetExpts.items():
                    subsetExpts[expname] = expt[rowIndices, :]
            else:
                raise TypeError("Row indices is not an expected type.")

        if colIndices is not None:
            if isinstance(colIndices, dict):
                incorrect = set(list(colIndices.keys())).difference(
                    list(subsetExpts.keys())
                )
                if len(incorrect) > 0:
                    raise ValueError(
                        f"Incorrect experiment names provided: {', '.join(incorrect)}."
                    )

                for expname, expt in subsetExpts.items():
                    if expname in colIndices:
                        subsetExpts[expname] = expt[:, colIndices[expname]]
                    else:
                        subsetExpts[expname] = expt

            elif isinstance(colIndices, slice) or all(
                isinstance(x, int) for x in colIndices
            ):
                for expname, expt in subsetExpts.items():
                    subsetExpts[expname] = expt[:, colIndices]
            else:
                raise TypeError("Columns indices is not an expected type.")

        # filter sample_map
        subsetColnames = []
        subsetsample_map = DataFrame()
        for expname, expt in subsetExpts.items():
            subsetColnames.extend(expt.colnames)
            subsetsample_map = concat(
                [
                    subsetsample_map,
                    self.sample_map[
                        (self.sample_map["assay"] == expname)
                        & (self.sample_map["colname"].isin(expt.colnames))
                    ],
                ]
            )

        # filter col_data
        subsetcol_data = self.col_data[
            self.col_data.index.isin(subsetsample_map["primary"].unique().tolist())
        ]

        return SlicerResult(subsetExpts, subsetsample_map, subsetcol_data)

    def subset_by_experiments(self, subset: StrOrListStr) -> "MultiAssayExperiment":
        """Subset by experiment(s).

        Args:
            subset (StrOrListStr): May be an single experiment name to keep.
                Alternatively, ``subset`` may be a list of experiment names.

        Returns:
            MultiAssayExperiment: A new `MultiAssayExperiment` with the subset experiments.
        """
        sresult = self._slice(args=(None, None, subset))
        return MultiAssayExperiment(
            sresult.experiments, sresult.col_data, sresult.sample_map, self.metadata
        )

    def subset_by_row(self, subset: SlicerTypes) -> "MultiAssayExperiment":
        """Subset by rows.

        Args:
            subset (SlicerTypes): Row indices or names to slice.

                May be either a integer vector (integer positions),
                boolean vector or :py:class:`~slice` object. Defaults to None.

        Returns:
            MultiAssayExperiment: A new `MultiAssayExperiment` with the subset.
        """
        sresult = self._slice(args=(subset, None, None))
        return MultiAssayExperiment(
            sresult.experiments, sresult.col_data, sresult.sample_map, self.metadata
        )

    def subset_by_column(self, subset: SlicerTypes) -> "MultiAssayExperiment":
        """Subset by column.

        Args:
            subset (SlicerTypes): Column indices or names to slice.

                May be either a integer vector (integer positions),
                boolean vector or :py:class:`~slice` object. Defaults to None.

        Returns:
            MultiAssayExperiment: A new `MultiAssayExperiment` with the subset.
        """
        sresult = self._slice(args=(None, subset, None))
        return MultiAssayExperiment(
            sresult.experiments, sresult.col_data, sresult.sample_map, self.metadata
        )

    def __getitem__(self, args: SlicerArgTypes) -> "MultiAssayExperiment":
        """Subset a `MultiAssayExperiment`.

        Args:
            args (SlicerArgTypes): Indices or names to slice. Tuple
                contains slices along dimensions (rows, columns, experiments).

                Each element in the tuple, might be either a integer vector (integer positions),
                boolean vector or :py:class:`~slice` object. Defaults to None.

        Raises:
            ValueError: Too many or too few slices.

        Returns:
            MultiAssayExperiment: A new sliced `MultiAssayExperiment` object with the subsets.
        """
        sresult = self._slice(args=args)
        return MultiAssayExperiment(
            sresult.experiments, sresult.col_data, sresult.sample_map, self.metadata
        )

    def __str__(self) -> str:
        pattern = (
            f"Class MultiAssayExperiment with {len(self.experiments.keys())} experiments and {len(self.col_data)} samples \n"  # noqa: E501
            f"  experiments: "
        )

        for expname, expt in self.experiments.items():
            pattern = f"{pattern} \n    {expname}: {str(expt)}"
        return pattern

    def complete_cases(self) -> Sequence[bool]:
        """Identify samples that have data across all experiments.

        Returns:
            Sequence[bool]: A boolean vector, where each element is
            True if sample is present in all experiments or False.
        """
        vec = []
        for x in self.col_data.index.tolist():
            subset = self.sample_map[self.sample_map["primary"] == x]

            vec.append(len(subset["assay"].unique()) == len(self.experiments.keys()))

        return vec

    def replicated(self) -> Dict[str, Dict[str, Sequence[bool]]]:
        """Identify samples with replicates within each experiment.

        Returns:
            Dict[str, Dict[str, Sequence[bool]]]: A dictionary where experiment names
            are keys and values specify if the sample is replicated within each experiment.
        """
        replicates = {}
        allSamples = self.col_data.index.tolist()
        for expname, expt in self.experiments.items():
            if expname not in replicates:
                replicates[expname] = {}

                for s in allSamples:
                    replicates[expname][s] = []

            colnames = expt.colnames
            smap = self.sample_map[self.sample_map["assay"] == expname]

            for x in colnames:
                colmap = smap[smap["colname"] == x]
                for s in allSamples:
                    replicates[expname][s].append(s in colmap["primary"])

        return replicates

    def add_experiment(
        self,
        name: str,
        experiment: SummarizedExperiment,
        sample_map: DataFrame,
        col_data: Optional[DataFrame] = None,
    ):
        """Add a new experiment to `MultiAssayExperiment`.

        ``sample_map`` must be provided to map the cells or sample from this experiment back to
        :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.col_data`. This
        will be appended to the existing
        :py:attr:`~multiassayexperiment.MultiAssayExperiment.MultiAssayExperiment.sample_map`.

        Optionally, ``col_data`` may be provided to add new sample information to the
        `MultiAssayExperiment`

        Args:
            name (str): Name of the new experiment.
            experiment (SummarizedExperiment): The experiment to add.
                Must extend
                :py:class:`~summarizedexperiment.SummarizedExperiment.SummarizedExperiment` class.

            sample_map (DataFrame): Sample map to append to the MAE.

            col_data (DataFrame, optional): Sample data to append to the MAE. Defaults to None.

        Raises:
            ValueError: If ``name`` is an existing experiment name in ``experiments``.
        """

        if name in self.experiments:
            raise ValueError(f"An experiment with {name} already exists.")

        self._validate_col_data(col_data)

        new_experiments = self.experiments.copy()
        new_experiments[name] = experiment

        new_col_data = col_data
        if new_col_data is not None:
            new_col_data = concat([self.col_data, col_data], axis=0)

        new_sample_map = concat([self.sample_map, sample_map], axis=0)

        self._validate_experiments(new_experiments)
        self._validate_sample_map(
            sample_map=new_sample_map,
            col_data=new_col_data,
            experiments=new_experiments,
        )

        self._experiments = new_experiments
        self._sample_map = new_sample_map
        self._col_data = new_col_data

    def to_mudata(self) -> MuData:
        """Transform `SingleCellExperiment` object to :py:class:`~mudata.MuData`.

        Returns:
            MuData: A `MuData` representation.
        """

        exptsList = OrderedDict()

        for expname, expt in self.experiments.items():
            if isinstance(expt, SingleCellExperiment):
                obj, adatas = expt.to_anndata(alts=True)

                exptsList[expname] = obj

                if adatas is not None:
                    for aname, aexpt in adatas.items():
                        exptsList[f"{expname}_{aname}"] = aexpt
            elif isinstance(expt, SummarizedExperiment):
                exptsList[expname] = expt.to_anndata()
            else:
                print(f"Experiment: '{expname}' is not supported!")

        return MuData(exptsList)


from rest_framework import serializers

from api.models import Livro
from .models import Entry, Livro, Receita, Blog

class BlogSerializer(serializers.ModelSerializer):
    class Meta:
        model = Blog
        fields = ['name', 'tagline']

class EntrySerializer(serializers.ModelSerializer):
    blog = BlogSerializer()

    class Meta:
        model = Entry
        fields = ['blog']

    def create(self, validated_data):
        blog_data = validated_data.pop('blog', None)
        if blog_data:
            blog = Blog.objects.get_or_create(**blog_data)[0]
            validated_data['blog'] = blog

        return Entry.objects.create(**validated_data)

    def update(self, instance, validated_data):
        profile_data = validated_data.pop('blog')
        instance.name = profile_data.name
        instance.tagline = profile_data.tagline
        instance.save()

class ReceitaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Receita
        fields = ['name', 'description']

class LivroSerializer(serializers.ModelSerializer):
    receitas = ReceitaSerializer(many=True)

    class Meta:
        model = Livro
        fields = ['receitas']

    def create(self, validated_data):
        receitas = validated_data.pop('receitas')
        instance = Livro.objects.create(**validated_data)
        for receita in receitas:
            instance.receitas.append(receita)
        return instance


from PyQt5.QtWidgets import QDateTimeEdit
from PyQt5.QtCore import QDateTime

class DateTimeInput(QDateTimeEdit):
    ''''
    Custom subclass for inputting date/time
    '''
    def __init__(self, format:str="MM/dd/yyyy HH:mm") -> None:
        super().__init__()

        # Set minimum size so full date and time can be seen
        self.setMinimumWidth(110)

        # Set how the date/time is displayed
        if format is not None:
            self.setDisplayFormat(format)

        # Show a calendar when clicked
        self.setCalendarPopup(True)

        # Default to the current date and time
        self.setDateTime(QDateTime.currentDateTime())

    def getUNIX(self) -> int:
        """
        Returns the current date/time in UNIX integer format
        """
        return self.dateTime().toTime_t()


import requests
import json
import copy
url = "https://mobile2.successfactors.com/app_info"

resp = requests.get(url)

json_response = resp.json()

json_copy = copy.deepcopy(json_response)

print(json_copy[0])

for item in json_copy:
    #print(item)
    # for k,v in item.items():
    #     if k == "MP":
    json_copy[0]["MP"] = json_copy[3]["FILE"]

print(json_copy[0])
print(json_response[0])


import discord
from dice import diceroll as die
import sys
import asyncio
import random
from getfleethealth import hullhealth as hull
from getfleethealth import shieldhealth as shield
from getfleethealth import hullshipname as hullname
from getfleethealth import shieldregen as regen
from getfleethealth import verify as verify
from getfleethealth import shielddamage as shielddamage
from getfleethealth import hulldamage as hulldamage
from getfleethealth import damresist as damresist
from pve import botgroupcreation as bgc

dirr = sys.path[0]

def nonzero(lis):
    ran = random.choice(lis)
    while ran == 0:
        ran = random.choice(lis)
    if ran != 0:
        return ran

game_over = False
async def battle(authorusername, message, guildid, client, u1id, channelid, username, movetext):
    channel = client.get_channel(channelid)
    playerone = authorusername
    playertwo = message.replace("!battle ", '')
    userid = playertwo.replace(">", '').replace("<@!", "").replace("<@", "").replace("!", "")
    usertwo = await client.fetch_user(int(userid))
    poneshdamage = []
    ponehulldamage = []
    ptwoshdamage = []
    ptwohulldamage = []
    hullvals = []
    shieldvals = []
    hullvalstwo = []
    shieldvalstwo = []
    playeronedefeat = []
    playertwodefeat = []
    initshieldspone = []
    initshieldsptwo = []
    try:
        playertwoname = hullname(dirr, userid, guildid)
        name = hullname(dirr, u1id, guildid)
        initplayeroneembed=discord.Embed(title=playerone+"'s Units:", description=f'Units: {len(name)}', color=discord.Color.red())
    except Exception as e:
    	print(e)
    	await channel.send("Have both players made a group? Cancelling battle.")
    	return True
    for a in range(0, len(name)): # Player one
        try:
            p1name = name[a].replace("\n", "")
            poneshdamage.append(float(shielddamage(dirr, p1name, guildid))) # Player one collective fleet shield, and below it hull damage
            ponehulldamage.append(float(hulldamage(dirr, p1name, guildid)))
            hullvals.append(float(hull(dirr, username, p1name, guildid)))
            shieldvals.append(float(shield(dirr, username, p1name, guildid)))
            initshieldspone = shieldvals
            initplayeroneembed.add_field(name=name[a].replace("\n", ''), value="- " + "🛡: "+str(shieldvals[a])+ "\n" +" "+"❤:"+str(hullvals[a]), inline=True)
        except Exception as e:
            print(e)
            await channel.send(f"{playerone}, something went wrong with your group. Try remaking your fleet and check your spelling. Cancelling battle.")
            return True
        p1sd = poneshdamage
        p1hd = ponehulldamage

    await channel.send(embed=initplayeroneembed)
    await channel.send("------------------------")
    initplayertwoembed=discord.Embed(title=usertwo.display_name+"'s Units:", description=f'Units: {len(playertwoname)}', color=discord.Color.blue())
    for d in range(0, len(playertwoname)): # Player two
        try:
            p2name = playertwoname[d].replace("\n", "")
            ptwoshdamage.append(float(shielddamage(dirr, p2name, guildid))) # Player two collective fleet shield, and below it hull damage
            ptwohulldamage.append(float(hulldamage(dirr, p2name, guildid)))
            shieldvalstwo.append(float(shield(dirr, userid, p2name, guildid)))
            hullvalstwo.append(float(hull(dirr, userid, p2name, guildid)))
            initshieldsptwo = shieldvalstwo
            initplayertwoembed.add_field(name=playertwoname[d].replace("\n", ''), value="- " + "🛡: "+str(shieldvalstwo[d])+ "\n" +"- " +"❤: "+str(hullvalstwo[d]), inline=True)
        except:
            await channel.send(f"{usertwo.display_name}, something went wrong with your group. Try remaking your group and checking the exact spelling of the units you're using. Cancelling battle")
            return True
        p2sd = ptwoshdamage
        p2hd = ptwohulldamage
    await channel.send(embed=initplayertwoembed)
    roundnum = 0
    while not game_over: # Battle code starts here now that data is compiled
        roundnum += 1
        roundembed=discord.Embed(title="Round: "+str(roundnum), description='', color=0x00ff00)
        await channel.send(embed=roundembed)
        msg = await channel.send(usertwo.display_name+movetext)
        await msg.add_reaction("🔫")
        def check(reaction, user):
            return user == usertwo and str(reaction.emoji) == "🔫"
        try:
            turn = await client.wait_for('reaction_add', check=check, timeout=1800)
        except asyncio.TimeoutError:
            await channel.send("Battle has not continued in 30 minutes, battle concluding")
            await msg.clear_reaction("🔫")
            await msg.edit(content=msg.content + " (Reaction removed, battled ended due to inactivity).")
            return True
        shipembed=discord.Embed(title=playerone+"'s Ships:", description=f'Units alive last turn: {len(name) - len(playeronedefeat)}', color=discord.Color.red())
        for c in range(0, len(name)): # Player one gets attacked
            p1name = name[c].replace("\n", "")
            ptworoll = die(0, 100)
            if ptworoll == 0:
                shieldvals[c] -= 0
                hullvals[c] -= 0
                shieldvals[c] += float(regen(dirr, username, p1name, guildid))
                shipembed.add_field(name=name[c], value="- " + "🛡: " + str(round(shieldvals[c], 0))+ "\n" +"- " +"❤: " + str(round(hullvals[c], 0)), inline=True)
            else:
                shieldvals[c] += float(regen(dirr, username, p1name, guildid))
                shieldvals[c] -= (ptworoll + nonzero(p2sd)) / (len(name)/2) #/ float(damresist(dirr, username, p1name, guildid))
                if float(shieldvals[c]) <= 0:
                    shieldvals[c] = 0
                    hullvals[c] -= (ptworoll + nonzero(p2hd)) / (len(name)/2) #/ float(damresist(dirr, username, p1name, guildid))
                    if int(hullvals[c]) < 0:
                        hullvals[c] = 0
                        shipembed.add_field(name=p1name.capitalize(), value="- " + "🛡: "+str(round(shieldvals[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvals[c], 0))+ "\n" +"- " +"Status: Defeated", inline=True)
                        if f"s {c} " not in playeronedefeat:
                            playeronedefeat.append(f"s {c}")
                            p1sd[c] = 0
                            p1hd[c] = 0
                        if len(playeronedefeat) == len(name):
                            await msg.clear_reaction("🔫")
                            await msg.edit(content=msg.content + " (Reaction removed, turn passed).")
                            endembed=discord.Embed(title="Defeat", description='', color=discord.Color.red())
                            endembed.add_field(name=playerone + "! " + "Your fleet has been defeated", value='You have lost the battle.', inline=True)
                            await channel.send(embed=endembed)
                            return True
                    else:
                        shipembed.add_field(name=p1name.capitalize(), value="- " + "🛡: "+str(round(shieldvals[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvals[c], 0)), inline=True)
                else:
                    if shieldvals[c] > initshieldspone[c]:
                        shieldvals[c] = initshieldspone[c]
                    shipembed.add_field(name=name[c].replace("\n", '').capitalize(), value="- " + "🛡: "+str(round(shieldvals[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvals[c], 0)), inline=True)
        await channel.send(embed=shipembed) # Sends message into discord with damage done to player one's ship.
        await msg.clear_reaction("🔫")
        await msg.edit(content=msg.content + " (Reaction removed, turn passed).")

        msg = await channel.send(playerone+movetext) # Start of player one's turn
        await msg.add_reaction("🔫")
        def check(reaction, user):
            return user == username and str(reaction.emoji) == "🔫"
        try:
            turntwo = await client.wait_for('reaction_add', check=check, timeout=1800)
        except asyncio.TimeoutError:
            await channel.send("Battle has not continued in 30 minutes, battle concluding.")
            await msg.clear_reaction("🔫")
            await msg.edit(content=msg.content + " (Reaction removed, battled ended due to inactivity).")
            return True
        shipembed=discord.Embed(title=usertwo.display_name+"'s Ships:", description=f'Units alive last turn: {len(playertwoname)- len(playertwodefeat)}', color=discord.Color.blue())
        for c in range(0, len(playertwoname)): # Player two gets attacked
            poneroll = die(0, 100)
            p2name = playertwoname[c].replace("\n", "")
            if poneroll == 0:
                shieldvalstwo[c] -= 0
                hullvalstwo[c] -= 0
                shieldvalstwo[c] += float(regen(dirr, usertwo.id, p2name, guildid))
                shipembed.add_field(name=p2name.capitalize(), value="- " + "🛡: "+str(round(shieldvalstwo[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvalstwo[c], 0)), inline=True)
            else:
                shieldvalstwo[c] -= (poneroll + nonzero(p1sd)) / (len(playertwoname)/2) #/ float(damresist(dirr, usertwo.id, p2name, guildid))
                shieldvalstwo[c] += float(regen(dirr, usertwo.id, p2name, guildid))
                if float(shieldvalstwo[c]) <= 0:
                    shieldvalstwo[c] = 0
                    hullvalstwo[c] -= (poneroll + nonzero(p1hd)) / (len(playertwoname)/2)  #/ float(damresist(dirr, usertwo.id, p2name, guildid))
                    if float(hullvalstwo[c]) < 0:
                        hullvalstwo[c] = 0
                        shipembed.add_field(name=playertwoname[c].replace("\n", '').capitalize(), value="- " + "🛡: "+str(round(shieldvalstwo[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvalstwo[c], 0))+ "\n" +"- " +"Status: Defeated", inline=True)
                        if f"s {c}" not in playertwodefeat:
                            playertwodefeat.append(f"s {c}")
                            p2sd[c] = 0
                            p2hd[c] = 0
                        if len(playertwodefeat) == len(playertwoname):
                            await msg.clear_reaction("🔫")
                            await msg.edit(content=msg.content + " (Reaction removed, turn passed).")
                            endembed=discord.Embed(title="Defeat", description='', color=discord.Color.blue())
                            endembed.add_field(name=usertwo.display_name + "! " + "Your fleet has been defeated", value='You have lost the battle.', inline=True)
                            await channel.send(embed=endembed)
                            return True
                    else:
                        shipembed.add_field(name=playertwoname[c].replace("\n", '').capitalize(), value="- " + "🛡: "+str(round(shieldvalstwo[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvalstwo[c], 0)), inline=True)
                else:
                    if shieldvalstwo[c] > initshieldsptwo[c]:
                        shieldvalstwo[c] = initshieldsptwo[c]
                    shipembed.add_field(name=playertwoname[c].replace("\n", '').capitalize(), value="- " + "🛡: "+str(round(shieldvalstwo[c], 0))+ "\n" +"- " +"❤: "+str(round(hullvalstwo[c], 0)), inline=True)
        await channel.send(embed=shipembed) # Sends message into discord with damage done to player two's ship.
        await msg.clear_reaction("🔫")
        await msg.edit(content=msg.content + " (Reaction removed, turn passed).")


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
A common interface to all binary refinery configuration settings available via environment
variables. This module is also host to the logging configuration.
"""
from __future__ import annotations

import os
import logging

from enum import IntEnum
from typing import Optional, TypeVar, Generic

_T = TypeVar('_T')

Logger = logging.Logger

class LogLevel(IntEnum):
    """
    An enumeration representing the current log level:
    """
    DETACHED = logging.CRITICAL + 100
    """
    This unit is not attached to a terminal but has been instantiated in
    code. This means that the only way to communicate problems is to throw
    an exception.
    """
    NONE = logging.CRITICAL + 50

    @classmethod
    def FromVerbosity(cls, verbosity: int):
        if verbosity < 0:
            return cls.DETACHED
        return {
            0: cls.WARNING,
            1: cls.INFO,
            2: cls.DEBUG
        }.get(verbosity, cls.DEBUG)

    NOTSET   = logging.NOTSET    # noqa
    CRITICAL = logging.CRITICAL  # noqa
    FATAL    = logging.FATAL     # noqa
    ERROR    = logging.ERROR     # noqa
    WARNING  = logging.WARNING   # noqa
    WARN     = logging.WARN      # noqa
    INFO     = logging.INFO      # noqa
    DEBUG    = logging.DEBUG     # noqa

    @property
    def verbosity(self) -> int:
        if self.value >= LogLevel.DETACHED:
            return -1
        if self.value >= LogLevel.WARNING:
            return +0
        if self.value >= LogLevel.INFO:
            return +1
        if self.value >= LogLevel.DEBUG:
            return +2
        else:
            return -1

class RefineryFormatter(logging.Formatter):

    NAMES = {
        logging.CRITICAL : 'failure',
        logging.ERROR    : 'failure',
        logging.WARNING  : 'warning',
        logging.INFO     : 'comment',
        logging.DEBUG    : 'verbose',
    }

    def __init__(self, format, **kwargs):
        super().__init__(format, **kwargs)

    def formatMessage(self, record: logging.LogRecord) -> str:
        record.custom_level_name = self.NAMES[record.levelno]
        return super().formatMessage(record)

def logger(name: str) -> logging.Logger:
    """
    Obtain a logger which is configured with the default refinery format.
    """
    logger = logging.getLogger(name)
    if not logger.hasHandlers():
        stream = logging.StreamHandler()
        stream.setFormatter(RefineryFormatter(
            '({asctime}) {custom_level_name} in {name}: {message}',
            style='{',
            datefmt='%H:%M:%S',
        ))
        logger.addHandler(stream)
    logger.propagate = False
    return logger

class EnvironmentVariableSetting(Generic[_T]):
    key: str
    value: Optional[_T]

    def __init__(self, name: str):
        self.key = F'REFINERY_{name}'
        self.value = self.read()

    def read(self) -> _T:
        return None

class EVBool(EnvironmentVariableSetting[bool]):
    def read(self):
        value = os.environ.get(self.key, None)
        if value is None:
            return False
        else:
            value = value.lower().strip()
        if not value:
            return False
        if value.isdigit():
            return bool(int(value))
        return value not in {'no', 'off', 'false'}

class EVInt(EnvironmentVariableSetting[int]):
    def read(self):
        try:
            return int(os.environ[self.key], 0)
        except (KeyError, ValueError):
            return 0

class EVLog(EnvironmentVariableSetting[Optional[LogLevel]]):
    def read(self):
        try:
            loglevel = os.environ[self.key]
        except KeyError:
            return None
        if loglevel.isdigit():
            return LogLevel.FromVerbosity(int(loglevel))
        try:
            loglevel = LogLevel[loglevel]
        except KeyError:
            levels = ', '.join(ll.name for ll in LogLevel)
            logger(__name__).warning(
                F'ignoring unknown verbosity "{loglevel!r}"; pick from: {levels}')
            return None
        else:
            return loglevel

class environment:
    verbosity = EVLog('VERBOSITY')
    term_size = EVInt('TERM_SIZE')
    colorless = EVBool('COLORLESS')
    disable_size_format = EVBool('DISABLE_SIZE_FORMAT')
    silence_ps1_warning = EVBool('SILENCE_PS1_WARNING')
    disable_ps1_bandaid = EVBool('DISABLE_PS1_BANDAID')


# coding: utf-8
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from .forms import FlickrLinkForm
from .models import FlickrLink

class FlickrPlayerPlugin(CMSPluginBase):
    model = FlickrLink
    form = FlickrLinkForm
    name = _(u"Flickr player")
    render_template = "cms/plugins/flickr_player.html"

    def render(self, context, instance, placeholder):
        width = instance.width or getattr(settings, "CMS_FLICKR_PLAYER_WIDTH", "100%")
        height = instance.height or getattr(settings, "CMS_FLICKR_PLAYER_HEIGHT", "500")

        url = instance.url
        if url.startswith(u"http://") or url.startswith(u"https://"):
            url = url.replace(u"http://", u"//").replace(u"https://", u"//")
        url = u"%s/player" % url

        context.update({
            'width': width,
            'height': height,
            'url': url,
            'placeholder': placeholder,
            'object': instance
        })
        return context

plugin_pool.register_plugin(FlickrPlayerPlugin)