from functools import partial
import torch
import torch.nn as nn
import torch.nn.functional as F
# from timm.models.vision_transformer import PatchEmbed, Block, to_2tuple
from models.vision_transformer import Block
from models.pos_embed import get_2d_sincos_pos_embed
from models.model_modules import PatialPatchEmbed
# from models.multiscale_transformer_module import MultiscaleTransformerEncoder
from models.multiscale_transformer_module_v2 import MultiscaleTransformerEncoder

class MaskedAutoencoderViT(nn.Module):
    def __init__(self, config):
        super().__init__()
        img_size = config['img_size']
        patch_size = config['patch_size']
        in_chans = config['in_chans']
        embed_dim = config['embed_dim']
        depth = config['depth']
        num_heads = config['num_heads']
        decoder_embed_dim = config['decoder_embed_dim']
        decoder_depth = config['decoder_depth']
        decoder_num_heads = config['decoder_num_heads']
        mlp_ratio = config['mlp_ratio']
        self.use_pconv = config['use_pconv']
        self.use_random_mask = config['use_random_mask']
        norm_layer = partial(nn.LayerNorm, eps=1e-6)
        self.decoder_arch = config['decoder_arch']
        fpn_type = config['fpn_type']
        q_downsample_layers = eval(config['q_downsample_layers'])
        kv_downsample_layers = eval(config['kv_downsample_layers'])
        use_pyramid = config['use_pyramid']
        pool_type = config['pool_type']
        pool_pos = config['pool_pos']
        use_norm_pred = config['use_norm_pred']
        self.use_mae_loss = config['use_mae_loss']

        self.patch_embed = PatialPatchEmbed(img_size, patch_size, in_chans, embed_dim)
        num_patches = self.patch_embed.num_patches
        self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim), requires_grad=False)
        self.mask_enc_token = nn.Parameter(torch.zeros(1, embed_dim))

        self.mae_blocks = nn.ModuleList([
            Block(embed_dim, num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer)
            for i in range(depth)])
        self.norm = norm_layer(embed_dim)

        if embed_dim != decoder_embed_dim:
            self.decoder_embed = nn.Linear(embed_dim, decoder_embed_dim, bias=True)
        self.mask_token = nn.Parameter(torch.zeros(1, decoder_embed_dim))
        self.decoder_pos_embed = nn.Parameter(torch.zeros(1, num_patches, decoder_embed_dim), requires_grad=False)

        if self.decoder_arch == 'multiscale_transformer':
            #             self.decoder = MultiscaleTransformerEncoder(embed_dim=decoder_embed_dim, dim_out=patch_size ** 2 * in_chans,
            #                                                         dropout=0., fpn_type=fpn_type,
            #                                                         q_downsample_layers=q_downsample_layers,
            #                                                         kv_downsample_layers=kv_downsample_layers)
            self.decoder = MultiscaleTransformerEncoder(embed_dim=decoder_embed_dim, dim_out=decoder_embed_dim,
                                                        dropout=0., fpn_type=fpn_type, patch_size=patch_size,
                                                        downsample_layers=q_downsample_layers,
                                                        use_pyramid=use_pyramid, pool_type=pool_type,
                                                        use_norm_pred=use_norm_pred, depth=decoder_depth,
                                                        pool_pos=pool_pos)
        else:
            self.decoder = nn.ModuleList([
                Block(decoder_embed_dim, decoder_num_heads, mlp_ratio, qkv_bias=True, qk_scale=None,
                      norm_layer=norm_layer)
                for i in range(decoder_depth)])
            self.decoder_norm = norm_layer(decoder_embed_dim)
            self.decoder_pred = nn.Linear(decoder_embed_dim, patch_size ** 2 * in_chans, bias=True)  # decoder to patch

        if self.use_mae_loss:
            self.mae_norm = norm_layer(decoder_embed_dim)
            self.mae_pred = nn.Linear(decoder_embed_dim, patch_size ** 2 * in_chans, bias=True)  # decoder to patch

        self.initialize_weights()

    def initialize_weights(self):
        # initialization
        # initialize (and freeze) pos_embed by sin-cos embedding
        pos_embed = get_2d_sincos_pos_embed(self.pos_embed.shape[-1], int(self.patch_embed.num_patches ** .5),
                                            cls_token=False)
        self.pos_embed.data.copy_(torch.from_numpy(pos_embed).float().unsqueeze(0))

        decoder_pos_embed = get_2d_sincos_pos_embed(self.decoder_pos_embed.shape[-1],
                                                    int(self.patch_embed.num_patches ** .5), cls_token=False)
        self.decoder_pos_embed.data.copy_(torch.from_numpy(decoder_pos_embed).float().unsqueeze(0))

        # initialize patch_embed like nn.Linear (instead of nn.Conv2d)
        w = self.patch_embed.proj.weight.data
        torch.nn.init.xavier_uniform_(w.view([w.shape[0], -1]))

        # timm's trunc_normal_(std=.02) is effectively normal_(std=0.02) as cutoff is too big (2.)
        # torch.nn.init.normal_(self.cls_token, std=.02)
        torch.nn.init.normal_(self.mask_token, std=.02)

        # initialize nn.Linear and nn.LayerNorm
        self.apply(self._init_weights)

    def _init_weights(self, m):
        if isinstance(m, nn.Linear):
            # we use xavier_uniform following official JAX ViT:
            torch.nn.init.xavier_uniform_(m.weight)
            if isinstance(m, nn.Linear) and m.bias is not None:
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.LayerNorm):
            nn.init.constant_(m.bias, 0)
            nn.init.constant_(m.weight, 1.0)

    def patchify(self, imgs):
        """
        imgs: (N, 3, H, W)
        x: (N, L, patch_size**2 *3)
        """
        p = self.patch_embed.patch_size[0]
        assert imgs.shape[2] == imgs.shape[3] and imgs.shape[2] % p == 0

        h = w = imgs.shape[2] // p
        x = imgs.reshape(shape=(imgs.shape[0], 3, h, p, w, p))
        x = torch.einsum('nchpwq->nhwpqc', x)
        x = x.reshape(shape=(imgs.shape[0], h * w, p ** 2 * 3))
        return x

    def unpatchify(self, x):
        """
        x: (N, L, patch_size**2 *3)
        imgs: (N, 3, H, W)
        """
        p = self.patch_embed.patch_size[0]
        h = w = int(x.shape[1] ** .5)
        assert h * w == x.shape[1]

        x = x.reshape(shape=(x.shape[0], h, w, p, p, 3))
        x = torch.einsum('nhwpqc->nchpwq', x)
        imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p))
        return imgs

    def random_masking(self, x, mask_ratio):
        """
        Perform per-sample random masking by per-sample shuffling.
        Per-sample shuffling is done by argsort random noise.
        x: [N, L, D], sequence
        """
        N, L, D = x.shape  # batch, length, dim
        len_keep = int(L * (1 - mask_ratio))

        noise = torch.rand(N, L, device=x.device)  # noise in [0, 1]

        # sort noise for each sample
        ids_shuffle = torch.argsort(noise, dim=1)  # ascend: small is keep, large is remove
        ids_restore = torch.argsort(ids_shuffle, dim=1)

        # keep the first subset
        ids_keep = ids_shuffle[:, :len_keep]
        x_masked = torch.gather(x, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D))

        # generate the binary mask: 0 is keep, 1 is remove
        mask = torch.ones([N, L], device=x.device)
        mask[:, :len_keep] = 0
        # unshuffle to get the binary mask
        mask = torch.gather(mask, dim=1, index=ids_restore)

        attn_mask = torch.ones(x_masked.size()[:2], device=x.device)

        return x_masked, mask, ids_restore, attn_mask

    def masking(self, x, mask):
        """
        x: [N, L, D], sequence
        mask: [N, 1, H, W]
        """
        N, L, D = x.shape  # batch, length, dim
        # mask: 0 is keep, 1 is remove
        patch = self.patch_embed.patch_size[0]
        kernels = torch.ones((1, 1, patch, patch), device=x.device)
        stride = (patch, patch)
        mask = F.conv2d(mask, weight=kernels, stride=stride, bias=torch.zeros(1, device=x.device))
        mask = mask.flatten(2).squeeze(1)

        mask[mask < patch ** 2] = 0
        mask[mask >= patch ** 2] = 1

        #         mask[mask >= 0] = 1

        b = mask.size()[0]
        max_len = 0
        for i in range(b):
            index = torch.where(mask[i] == 0)[0]
            max_len = max(max_len, len(index))

        restore_index_list = []
        x_masked_list = []
        attn_mask_list = []
        for i in range(b):
            mask_index = torch.where(mask[i] == 1)[0]
            keep_index = torch.where(mask[i] == 0)[0]
            # print(x[i].shape, keep_index.shape)
            x_masked = torch.gather(x[i], dim=0, index=keep_index.unsqueeze(-1).repeat(1, D))
            seq_len = x_masked.size()[0]
            padding_len = max_len - seq_len
            if padding_len > 0:
                x_masked = torch.cat([x_masked, self.mask_enc_token.repeat(padding_len, 1)])
            x_masked_list.append(x_masked)

            attn_mask = torch.zeros(max_len, device=x.device)
            attn_mask[:seq_len] = 1
            attn_mask_list.append(attn_mask)

            restore_index = torch.argsort(torch.cat([keep_index, mask_index], dim=0))
            restore_index_list.append(restore_index)

        ids_restore = torch.stack(restore_index_list, dim=0)
        x_masked = torch.stack(x_masked_list, dim=0)
        attn_mask = torch.stack(attn_mask_list, dim=0)

        return x_masked, mask, ids_restore, attn_mask

    def forward_encoder(self, x, mask_ratio, mask=None):
        # embed patches
        if self.use_pconv:
            x = self.patch_embed(x, 1 - mask)
        else:
            x = self.patch_embed(x)

        x = x + self.pos_embed

        # masking: length -> length * mask_ratio
        if self.use_random_mask and self.training:
            x, mask, ids_restore, attn_mask = self.random_masking(x, mask_ratio)
        else:
            x, mask, ids_restore, attn_mask = self.masking(x, mask)

        for blk in self.mae_blocks:
            x = blk(x, attn_mask)
        x = self.norm(x)

        return x, mask, ids_restore, attn_mask

    def forward_decoder(self, x, ids_restore, attn_mask):
        # embed tokens
        x = self.decoder_embed(x) if hasattr(self, 'decoder_embed') else x

        # append mask tokens to sequence
        B, L, D = x.shape
        x_list = []
        for i in range(B):
            index = torch.where(attn_mask[0] == 1)[0]
            x_masked = torch.gather(x[i], dim=0, index=index.unsqueeze(-1).repeat(1, D))
            mask_tokens = self.mask_token.repeat(ids_restore.shape[1] + 1 - x_masked.shape[0], 1)
            x_ = torch.cat([x_masked, mask_tokens], dim=0)  # no cls token
            x_list.append(x_)
        x_ = torch.stack(x_list, dim=0)
        x = torch.gather(x_, dim=1, index=ids_restore.unsqueeze(-1).repeat(1, 1, x.shape[2]))  # unshuffle

        # mae encoder 编码后的patch，在不规则mask的情况下修复一个patch内既有mask又有合法像素的patch
        mae_x = x
        if self.use_mae_loss:
            mae_x = self.mae_norm(mae_x)
            mae_x = self.mae_pred(mae_x)
            mae_x = self.unpatchify(mae_x)

        # 加上位置信息
        x = x + self.decoder_pos_embed

        if self.decoder_arch == 'multiscale_transformer':
            x = self.decoder(x)
            fpn_feats = x[1:]
            x = x[0]
        else:
            for layer in self.decoder:
                x = layer(x)
            x = self.decoder_norm(x)
            x = self.decoder_pred(x)
            x = self.unpatchify(x)
            fpn_feats = None

        return x, mae_x, fpn_feats

    def forward(self, imgs, mask_ratio=0.75, mask=None):
        latent, mask, ids_restore, attn_mask = self.forward_encoder(imgs, mask_ratio, mask)
        image_pred, image_mae_pred, fpn_feats = self.forward_decoder(latent, ids_restore, attn_mask)  # [N, L, p*p*3]

        mask = mask.unsqueeze(-1).repeat(1, 1, self.patch_embed.patch_size[0] ** 2 * 3)  # (N, H*W, p*p*3)
        mask = self.unpatchify(mask)  # 1 is removing, 0 is keeping
        return image_pred, mask, image_mae_pred, fpn_feats

if __name__ == '__main__':
    # chkpt_dir = '../pretrained_models/mae_visualize_vit_base.pth'

    config = {'img_size': 224, 'patch_size': 8, 'in_chans': 3, 'embed_dim': 256, 'depth': 0,
              'num_heads': 4, 'decoder_embed_dim': 256, 'decoder_depth': 12, 'decoder_num_heads': 12,
              'mlp_ratio': 4, 'norm_pix_loss': False, 'use_pconv': True, 'use_random_mask': False,
              'decoder_arch': 'multiscale_transformer',
              'fpn_type': 'crossattn_1d', 'q_downsample_layers': '[4, 8]', 'kv_downsample_layers': '[]',
              'use_pyramid': True,
              'pool_type': 'conv', 'use_norm_pred': True, 'use_mae_loss': True, 'pool_pos': 'first'}
    model = MaskedAutoencoderViT(config)

    x = torch.rand((1, 196, 768))
    import torch.nn.functional as F
    import numpy as np
    from utils import generate_stroke_mask

    mask = generate_stroke_mask([224, 224])[:, :, 0]
    mask = (mask > 0).astype(np.uint8)
    # print(np.shape(mask))
    # print(mask.sum())
    # print(mask.shape)

    # import matplotlib.pyplot as plt
    # plt.figure()
    # plt.imshow(mask, cmap=plt.get_cmap('gray'))
    # plt.show()

    mask = torch.tensor(mask, dtype=torch.float)[None, None, :, :]
    x = torch.rand((1, 3, 224, 224))
    print(mask.shape)
    pred, mask, mae_pred, fpn_feats = model(x, mask=mask)

    print(pred.shape, mae_pred.shape, mask.shape)

    if fpn_feats is not None:
        for p in fpn_feats:
            print(p.shape)


#!/usr/bin/env python3

def selectionSort(items):
    length = len(items)
    for i in range(length):
        min = i
        temp = items[i]
        for j in range(i+1, length):
            #select index of smallest item
            if items[j] < items[min]:
                min = j
        items[i] = items[min]
        items[min] = temp
    return items

print(selectionSort([23,4,1,6,22,40,61,8,2,34,25,11,7]))


import shutil
import tempfile
from http import HTTPStatus

from django import forms
from django.conf import settings
from django.core.cache import cache
from django.core.files.uploadedfile import SimpleUploadedFile
from django.shortcuts import get_object_or_404
from django.test import Client, TestCase, override_settings
from django.urls import reverse
from posts.forms import PostForm
from posts.models import Follow, Group, Post, User

TEMP_MEDIA_ROOT = tempfile.mkdtemp(dir=settings.BASE_DIR)

@override_settings(MEDIA_ROOT=TEMP_MEDIA_ROOT)
class PostViewTests(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Создаем неавторизованный клиент
        cls.guest_client = Client()
        # Создаем пользователя
        cls.user = User.objects.create_user(username='HasNoName')
        cls.user2 = User.objects.create_user(username='HasNoName2')

        small_gif = (
            b'\x47\x49\x46\x38\x39\x61\x02\x00'
            b'\x01\x00\x80\x00\x00\x00\x00\x00'
            b'\xFF\xFF\xFF\x21\xF9\x04\x00\x00'
            b'\x00\x00\x00\x2C\x00\x00\x00\x00'
            b'\x02\x00\x01\x00\x00\x02\x02\x0C'
            b'\x0A\x00\x3B'
        )
        uploaded = SimpleUploadedFile(
            name='small.gif',
            content=small_gif,
            content_type='image/gif'
        )

        cls.group = Group.objects.create(
            title='Тестовая Группа',
            slug='test-slug',
            description='тестовое описание группы'
        )

        cls.post = Post.objects.create(
            text='Тестовый текст',
            author=cls.user,
            group=cls.group,
            image=uploaded
        )

    def setUp(self):
        # Создаем пользователя
        self.authorized_client = Client()
        # Создаем второй клиент
        self.authorized_client2 = Client()
        # Авторизуем пользователя
        self.authorized_client.force_login(self.user)
        # Авторизуем пользователя2
        self.authorized_client2.force_login(self.user2)
        # выборка всей ленты новостей
        author_querry = Follow.objects.filter(user=self.user)
        author_values_list = author_querry.values_list('author')
        self.post_list = Post.objects.filter(author_id__in=author_values_list)
        # добавление подписки
        self.follow = Follow.objects.create(
            user=self.user,
            author=self.post.author
        )
        cache.clear()

    @classmethod
    def tearDownClass(cls):
        super().tearDownClass()
        shutil.rmtree(TEMP_MEDIA_ROOT, ignore_errors=True)

    def test_pages_posts_correct_template(self):
        """views функция использует соответствующий шаблон."""
        # Собираем в лист пары "имя_html_шаблона, reverse(name)"
        templates_pages_names = [
            (
                'posts/index.html',
                reverse('posts:index')
            ),
            (
                'posts/group_list.html', reverse(
                    'posts:group_list', kwargs={'slug': self.group.slug}
                )
            ),
            (
                'posts/profile.html', reverse(
                    'posts:profile',
                    args=[self.user]
                )
            ),
            (
                'posts/post_detail.html', reverse(
                    'posts:post_detail', kwargs={'post_id': self.post.pk}
                )
            ),
            (
                'posts/create_post.html', reverse(
                    'posts:create_post'
                )
            ),
            (
                'posts/create_post.html',
                reverse(
                    'posts:post_edit',
                    kwargs={'post_id': self.post.pk})
            )

        ]

        for template, reverse_name in templates_pages_names:
            with self.subTest(reverse_name=reverse_name):
                response = self.authorized_client.get(reverse_name)
                self.assertTemplateUsed(response, template)

    def test_pages_show_correct_context(self):
        """Шаблон index сформирован с правильным контекстом."""

        for post in Post.objects.select_related("group"):
            response = self.authorized_client.get(reverse('posts:index'))
            self.assertEqual(response.context.get('post'), post)

    def test_group_list_pages_show_correct_context(self):
        """Шаблон group_list сформирован с правильным контекстом."""
        response = self.authorized_client.get(reverse(
            'posts:group_list', kwargs={'slug': self.group.slug})
        )

        group = get_object_or_404(Group, slug=self.group.slug)
        first_objects = group.posts.all()
        for post in first_objects:
            self.assertEqual(response.context.get('post'), post)

        second_object = response.context.get('page_obj').object_list
        for post in second_object:
            self.assertEqual(response.context.get('post'), post)

    def test_profile_pages_show_correct_context(self):
        """Шаблон profile сформирован с правильным контекстом."""
        response = self.authorized_client.get(reverse(
            'posts:profile',
            args=[self.user])
        )

        author = self.user
        first_objects = author.posts.all()
        for post in first_objects:
            self.assertEqual(response.context.get('post'), post)

        second_object = response.context.get('page_obj').object_list
        for post in second_object:
            self.assertEqual(response.context.get('post'), post)

    def test_post_detail_pages_show_correct_context(self):
        """Шаблон post_detail сформирован с правильным контекстом."""
        response = self.authorized_client.get(reverse(
            'posts:post_detail',
            kwargs={'post_id': self.post.pk})
        )
        self.assertEqual(response.context.get('post'), self.post)

    def test_post_edit_show_correct_context(self):
        """Шаблон post_edit сформирован с правильным контекстом."""
        response = (self.authorized_client.get(reverse(
            'posts:post_edit', kwargs={'post_id': self.post.pk}))
        )

        form_field = response.context.get('form').fields.get('text')
        self.assertIsInstance(form_field, forms.fields.CharField)

        form_field = response.context.get('form').fields.get('group')
        self.assertIsInstance(form_field, forms.fields.ChoiceField)

        form = response.context.get('form')
        self.assertIsInstance(form, PostForm)

    def test_create_post_show_correct_context(self):
        """Шаблон post_create сформирован с правильным контекстом."""
        response = self.authorized_client.get(reverse(
            'posts:create_post')
        )
        form_fields = {
            'text': forms.fields.CharField,
            'group': forms.fields.ChoiceField,
        }
        for value, expected in form_fields.items():
            with self.subTest(value=value):
                form_field = response.context.get('form').fields.get(value)
                self.assertIsInstance(form_field, expected)

    def test_show_correct_img_context(self):

        """Шаблоны сформированы с правильным контекстом

         проверка на наличие картинки"""
        url_names = [
            reverse('posts:index'),
            reverse('posts:group_list', args=['test-slug']),
            reverse('posts:profile', args=[self.user]),
            reverse('posts:post_detail', args=[self.post.pk]),
        ]

        for url in url_names:
            with self.subTest(value=url):
                response = self.authorized_client.get(url)
                self.assertEqual(
                    response.context.get('post').image,
                    self.post.image
                )

    def test_add_comment_correct_context(self):
        """Проверка add_comment

        комментарий появляется на странице поста
        комментировать посты может только авторизованный пользователь
        """
        url = reverse('posts:add_comment', args=[self.post.pk])
        response = self.authorized_client.get(url,)

        if self.post.author == self.authorized_client:
            self.assertEqual(response.status_code, HTTPStatus.OK)

        elif self.user == self.authorized_client:
            self.assertRedirects(response, url)

        else:
            response = self.guest_client.get(url)
            self.assertRedirects(
                response, reverse(
                    'users:login'
                ) + "?next=" + reverse(
                    'posts:add_comment', args=[self.post.pk])
            )

    def test_post_right_group_exists(self):
        """Проверка Создания Поста ,

        что если при создании поста указать группу то этот пост появляется."""

        response = self.authorized_client.get(
            reverse('posts:index')
        )
        object = self.group.posts.filter(
            group=response.context.get('post').group
        )
        self.assertTrue(object.exists())

        response = self.authorized_client.get(reverse(
            'posts:group_list', kwargs={'slug': self.group.slug})
        )

        object = self.group.posts.filter(
            group=response.context.get('post').group
        )
        self.assertTrue(object.exists())

    def test_post_right_group(self):
        response = self.authorized_client.get(
            reverse('posts:index')
        )

        for post in Post.objects.select_related("group"):
            self.assertEqual(response.context.get('post').group, post.group)

        response = self.authorized_client.get(reverse(
            'posts:group_list', kwargs={'slug': self.group.slug})
        )

        object = self.group.posts.all()
        for post in object:
            self.assertEqual(response.context.get('post').group, post.group)

    def test_follow(self):
        """Проверка авторизованный пользователь может

        подписываться на других пользователей """

        self.authorized_client.get(f'/profile/{self.user}/follow/')
        response = self.authorized_client.get('/follow/')

        for post in self.post_list:
            self.assertEqual(response.context.get('post'), post)

    def test_unfollow(self):
        """Проверка авторизованный пользователь может

        удалять других пользователей из подписок """

        self.authorized_client.get(f'/profile/{self.user}/unfollow/')
        response = self.authorized_client.get('/follow/')

        for post in self.post_list:
            self.assertEqual(response.context.get('post'), post)

    def test_check_correct_followed(self):
        """Проверка Ленты постов авторов

        Новая запись пользователя появляется в ленте
        тех, кто на него подписан"""

        response = self.authorized_client.get('/follow/')

        for post in self.post_list:
            self.assertEqual(response.context.get('post'), post)

    def test_check_correct_unfollowed(self):
        """Проверка Ленты постов авторов

        В ленте подписок нет лишних постов"""

        response = self.authorized_client2.get('/follow/')

        self.assertEqual(response.context.get('post'), None)

class PaginatorViewsTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        # Создаем пользователя
        # Создаем неавторизованный клиент
        cls.guest_client = Client()
        # Создаем пользователя
        cls.user = User.objects.create_user(username='HasNoName')
        # Создаем второй клиент
        cls.authorized_client = Client()
        # Авторизуем пользователя
        cls.authorized_client.force_login(cls.user)

        cls.group = Group.objects.create(
            title='Тестовая Группа',
            slug='test-slug',
            description='тестовое описание группы'
        )

        cls.post = Post.objects.bulk_create(
            [
                Post(
                    text=f'Тестовый текст{i}',
                    author=cls.user,
                    group=cls.group
                )
                for i in range(0, 13)
            ]
        )

    def test_first_page_contains(self):
        """Тест Пагинатора для Первой странцы"""
        PAGE_LIMIT = 10
        url_names = {
            reverse('posts:index'): PAGE_LIMIT,
            reverse(
                'posts:group_list',
                kwargs={'slug': self.group.slug}
            ): PAGE_LIMIT,
            reverse(
                'posts:profile',
                args=[self.user]
            ): PAGE_LIMIT,
        }

        for value, expected in url_names.items():
            with self.subTest(value=value):
                response = self.client.get(value + '?page=1')
                self.assertEqual(len(response.context['page_obj']), expected)

    def test_second_page_contains_three_records(self):
        """Тест Пагинатора для Второй странцы"""
        PAGE_LIMIT_SECOND_PAGE = 3

        url_names = {
            reverse(
                'posts:index'
            ): PAGE_LIMIT_SECOND_PAGE,

            reverse(
                'posts:group_list',
                kwargs={'slug': self.group.slug}
            ): PAGE_LIMIT_SECOND_PAGE,

            reverse(
                'posts:profile',
                args=[self.user]
            ): PAGE_LIMIT_SECOND_PAGE,
        }

        for value, expected in url_names.items():
            with self.subTest(value=value):
                response = self.client.get(value + '?page=2')
                self.assertEqual(len(response.context['page_obj']), expected)


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

import aiohttp
import pandas as pd
import pytz
from pandas import DataFrame, Timestamp
from tqdm import tqdm

from finclaw.data_store.schema import OHCL, STOCK_SYMBOL
from finclaw.data_store.store import PriceStore
from finclaw.vendor.fmp import fmp_client
import pyarrow as pa

async def get_symbols(session: aiohttp.ClientSession, market: str) -> pd.DataFrame:
    if market != "TO":
        raise ValueError(f"Market {market} not supported")

    symbols = await fmp_client.get_symbols(session=session)
    df = pd.DataFrame(data=symbols)
    df["mic"] = ""
    df.loc[df["stockExchange"] == "Toronto Stock Exchange", "mic"] = "XTSE"
    df.loc[df["stockExchange"] == "TSXV", "mic"] = "XTSX"
    df = df.rename(columns={"symbol": "ticker", "name": "description", "currency": "currency_name"})
    df["type"] = ""
    df["figi"] = ""
    return df[STOCK_SYMBOL.names]

async def get_ohcl_for_symbol(session: aiohttp.ClientSession, symbol: str, resolution: str) -> Optional[pd.DataFrame]:
    ohcl_json = await fmp_client.get_stock_candle(session=session, symbol=symbol, resolution=resolution)
    if not ohcl_json:
        return None
    df = pd.DataFrame(data=ohcl_json)
    df["timestamp"] = pd.to_datetime(df["date"]).dt.tz_localize('America/New_york')
    df["timestamp"] = df["timestamp"].dt.tz_convert("UTC")
    df["symbol"] = symbol
    return df[OHCL.names]

async def get_ohcl_data(session: aiohttp.ClientSession,
                        start: Timestamp,
                        end: Timestamp,
                        symbols: List[str],
                        frequency: str) -> pd.DataFrame:
    if start > end:
        raise ValueError("Start date cannot be greater than end date")
    if start.tz != pytz.UTC or end.tz != pytz.UTC:
        raise ValueError("Start and end dates must be UTC")

    print("Getting OHCL data")
    dfs = []
    for symbol in tqdm(symbols):
        symbol_df = await get_ohcl_for_symbol(session=session, symbol=symbol, resolution=frequency)
        if symbol_df is not None:
            dfs.append(symbol_df)

    result_df = pd.concat(dfs)
    return result_df[(result_df.timestamp >= start) & (result_df.timestamp <= end)]

async def get_symbol_table(market: str) -> pa.Table:
    async with aiohttp.ClientSession() as session:
        symbol_df = await get_symbols(session=session, market=market)
        return pa.Table.from_pandas(symbol_df, schema=STOCK_SYMBOL)

async def get_ohcl_table_for(start: Timestamp, end: Timestamp, symbols: List[str], frequency: str) -> pa.Table:
    async with aiohttp.ClientSession() as session:
        ohcl_df = await get_ohcl_data(session=session, start=start, end=end, symbols=symbols, frequency=frequency)
        return pa.Table.from_pandas(ohcl_df, schema=OHCL)

def pull_symbols(*, store: PriceStore, market: str, start: pd.Timestamp, end: pd.Timestamp):
    symbol_table = asyncio.run(get_symbol_table(market=market))
    store.store_symbols(symbol_table=symbol_table, start=start, end=end, vendor="fmp")

def pull_ohcl_data(*, store: PriceStore, symbols: List[str], start: Timestamp, end: Timestamp, frequency: str):
    table = asyncio.run(get_ohcl_table_for(start, end, symbols, frequency))
    store.store_prices(price_table=table, start=start, end=end, vendor="fmp", frequency=frequency)


# @Author    : 小杜同学
# @Email       : anmutu@hotmail.com
# @Github     : www.github.com/anmutu
# @怎么肥四  : https://www.zmfei4.com
# @Time        : 2020/5/21 17:09

# https://leetcode-cn.com/problems/first-bad-version/

# 你是产品经理，目前正在带领一个团队开发新的产品。不幸的是，你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的，所以错误的版本之后的所有版本都是错的。
# 假设你有 n 个版本 [1, 2, ..., n]，你想找出导致之后所有版本出错的第一个错误的版本。
# 你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

# example
# 给定 n = 5，并且 version = 4 是第一个错误的版本。
# 调用 isBadVersion(3) -> false
# 调用 isBadVersion(5) -> true
# 调用 isBadVersion(4) -> true
# 所以，4 是第一个错误的版本。

def first_bad_version(nums):
    left = 1
    right = len(nums)
    while left < right:
        mid = (left + right)//2
        if is_bad_version(mid):
            if is_bad_version(mid - 1):
                right = mid
            else:
                return mid
        else:
            if is_bad_version(mid + 1):
                return mid + 1
            else:
                left = mid

def is_bad_version(num):
    if num == 2:
        return True
    else:
        return False

if __name__ == "__main__":
    nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    res = first_bad_version(nums)
    print(res)


import os
import numpy as np
import torch
import torch.nn as nn

from agent.agent import stochastic_action, wrap_action, dict2obs
from agent.reinforce.network import Policy

def get_action(policy: nn.Module, obs: np.ndarray):
    raw_action = stochastic_action(policy, obs)
    action = wrap_action(raw_action).tolist()
    return action

def load_policy(state_dim, action_dim, path='') -> nn.Module:
    policy = Policy(state_dim, action_dim).to('cpu')
    model_path = path + '/reinforce.pt'
    if os.path.exists(model_path):
        model = torch.load(model_path, map_location=torch.device('cpu'))
        policy.load_state_dict(model['policy'])
    return policy

def evaluate(env, policy_red: nn.Module, policy_blue: nn.Module):
    state_dict = env.reset()
    total_reward_red = 0
    total_reward_blue = 0
    while True:
        obs_red = dict2obs(state_dict, 0)
        obs_blue = dict2obs(state_dict, 1)
        action_red = get_action(policy_red, obs_red)
        action_blue = get_action(policy_blue, obs_blue)
        state_dict, reward, done, info = env.step([action_red, action_blue])
        total_reward_red += reward[0]
        total_reward_blue += reward[1]
        if done:
            break
    return [total_reward_red, total_reward_blue], info


def import_module_path():
    # add project root to module path if not added already
    import os
    import sys
    module_path = os.path.abspath(os.path.join('.'))
    if module_path not in sys.path and os.path.basename(module_path) == "t212-tax-and-profit":
        sys.path.append(module_path)
        print(f"Path '{module_path}' added to module path.")

import_module_path()

from models.input import Event, Action
from datetime import datetime, timedelta

stock_dict = {
    "apple": {
        "ticker": "AAPL",
        "name": "Apple",
        "isin": "US0378331005",
    },
    "pg": {
        "ticker": "PG",
        "name": "Procter & Gamble",
        "isin": "US7427181091"
    }
}

class EventGenerator:

    def __init__(self) -> None:
        self.time: datetime = datetime.strptime("2022-09-01 13:00:00", "%Y-%m-%d %H:%M:%S")
        self.idx = 0

    def buy_event(self, shares, price_per_share, stock="apple"):
        self.time += timedelta(hours=1)
        self.idx += 1
        stock = stock_dict[stock]
        return Event(
            action=Action.BUY,
            time=self.time,
            isin=stock["isin"],
            ticker=stock["ticker"],
            name=stock["name"],
            shares_count=shares,
            price_per_share=price_per_share,
            price_currency="USD",
            exchange_rate=1,
            total_eur=price_per_share * shares,
            ID=f"EOF{self.idx:010d}",
            conversion_fee_eur=0.1,
        )

    def sell_event(self, shares, price_per_share, stock="apple"):
        self.time += timedelta(hours=1)
        self.idx += 1
        stock = stock_dict[stock]
        return Event(
            action=Action.SELL,
            time=self.time,
            isin=stock["isin"],
            ticker=stock["ticker"],
            name=stock["name"],
            shares_count=shares,
            price_per_share=price_per_share,
            price_currency="USD",
            exchange_rate=1,
            total_eur=price_per_share * shares,
            ID=f"EOF{self.idx:010d}",
            conversion_fee_eur=0.1,
            result_eur=0, # dont care
        )


class Solution:
	def isValidBST(self, root: TreeNode) -> bool:
		valid = False
		data = []

		def _in(node):
			if node is None: return
			if node.left: _in(node.left)
			data.append(node.val)
			if node.right: _in(node.right)

		_in(root)

		for i in range(len(data) - 1):
			if data[i] >= data[i + 1]:
				return False

		return True


import pandas as pd
import numpy as np
import scipy as sp
import sys, os, glob, time
import datetime

import matplotlib
matplotlib.use('Agg') # to still plot even when no display is defined
import matplotlib.pyplot as plt
import seaborn as sns

# more handy imports
import hddm, kabuki
from utils_plot import results_long2wide_hddmnn, corrfunc

# ============================================ #
# define some functions
# ============================================ #

# Get around a problem with saving regression outputs in Python 3
def savePatch(self, fname):
    import pickle
    with open(fname, 'wb') as f:
        pickle.dump(self, f)

hddm.HDDMnn.savePatch = savePatch
hddm.HDDMnnRegressor.savePatch = savePatch

def run_model(data, modelname, mypath, n_samples=1000, trace_id=0):

    from hddmnn_modelspec import make_model # specifically for HDDMnn models

    print('HDDM version: ', hddm.__version__)
    print('Kabuki version: ', kabuki.__version__)

    # get the model
    m = make_model(data, modelname)
    time.sleep(trace_id) # to avoid different jobs trying to make the same folder

    # make a new folder if it doesn't exist yet
    if not os.path.exists(mypath):
        os.makedirs(mypath)
        print('creating directory %s' % mypath)

    print("begin sampling") # this is the core of the fitting

    # If you are running multiple models simultaneously, make sure to name the .db files differently, otherwise they might all
    # write to the same location and when HDDM tries to save the model by consulting the .db file it'll just get a jumble.
    m.sample(n_samples, burn = np.max([n_samples/10, 100]),
             dbname= os.path.join(mypath, 'traces.db'),
             db='pickle')

    print('saving model itself')
    m.savePatch(os.path.join(mypath, 'model.mdl')) # use the patched code

    print("save model comparison indices")
    df = dict()
    df['dic'] = [m.dic]
    df['aic'] = [aic(m)]
    df['bic'] = [bic(m)]
    df2 = pd.DataFrame(df)
    df2.to_csv(os.path.join(mypath, 'model_comparison.csv'))

    # save useful output
    print("saving summary stats")
    results = m.gen_stats().reset_index()  # point estimate for each parameter and subject
    results.to_csv(os.path.join(mypath, 'results_combined.csv'))

    print("saving traces")
    # get the names for all nodes that are available here
    group_traces = m.get_group_traces()
    group_traces.to_csv(os.path.join(mypath, 'group_traces.csv'))

    return m

# ============================================ #
# MODEL COMPARISON INDICES
# ============================================ #

def aic(self):

    k = len(self.get_stochastics())
    try:
        logp = sum([x.logp for x in self.get_observeds()['node']])
        aic = 2 * k - 2 * logp
    except:
        aic = np.nan
    return aic

def bic(self):

    k = len(self.get_stochastics())
    n = len(self.data)
    try:
        logp = sum([x.logp for x in self.get_observeds()['node']])
        bic = -2 * logp + k * np.log(n)
    except:
        bic = np.nan
    return bic

def plot_model(m, savepath):

    # MAKE SOME PLOTS
    # 'Note: The posterior pair plot does not support regression models at this point! Aborting...'
    # hddm.plotting.plot_posterior_pair(m, samples=50,
    #                                   save=True, save_path=savepath)

    # quick overview of the parameters
    hddm.plotting.plot_caterpillar(hddm_model = m,
                                   save=True, path=savepath,
                                   drop_sd = True,
                                   keep_key=list(m.get_group_nodes().reset_index()['index']),
                                   columns=5)

    # more classical posterior predictive on the RT distributions
    # the likelihood-based posterior predictives (_plot_func_posterior_pdf_node_nn) are not yet implemented for HDDMnn regression models, use simulated ones instead
    hddm.plotting.plot_posterior_predictive(model = m,
                                            save=True, path=savepath,
                                            # columns = 4, #groupby = ['subj_idx'],
                                            value_range = np.arange(-2, 2, 0.01),
                                            plot_func = hddm.plotting._plot_func_posterior_node_from_sim,
                                            figsize=(15,24),
                                            parameter_recovery_mode = False,
                                            **{'alpha': 0.01,
                                            'add_legend':False,
                                            'ylim': 3,
                                            'bin_size': 0.05,
                                            'add_posterior_mean_rts': True,
                                            'add_posterior_uncertainty_rts': False,
                                            #'samples': 30,
                                            'data_color':'darkblue',
                                            'posterior_mean_color':'firebrick',
                                            # 'legend_fontsize': 7,
                                            'subplots_adjust': {'top': 0.9, 'hspace': 1, 'wspace': 0.3}})

    # across-subject parameter correlation plot
    results = results_long2wide_hddmnn(m.gen_stats().reset_index())  # point estimate for each parameter and subject
    g = sns.PairGrid(results, vars=list(set(results.columns) - set(['subj_idx'])))
    g.map_diag(sns.histplot)
    g.map_lower(corrfunc)
    g.map_upper(sns.kdeplot)
    g.savefig(os.path.join(savepath, 'pairgrid_corrplot.png'))

    # # posterior plot for each variable
    # # https://github.com/hcp4715/hddm_docker/blob/master/example/HDDM_official_tutorial_ArviZ.ipynb
    # group_traces["chain"] = 0
    # group_traces["draw"] = np.arange(len(group_traces), dtype=int)
    # group_traces = group_traces.set_index(["chain", "draw"])
    # xdata = xr.Dataset.from_dataframe(group_traces)
    # az.plot_posterior(xdata, hdi_prob=0.95, ref_val=0)
    # plt.savefig(os.path.join(mypath, 'param_hdi.png'))


import torch.nn as nn
import torch.nn.functional as F

class Basic3DBlock(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size):
        super(Basic3DBlock, self).__init__()
        self.block = nn.Sequential(
            nn.Conv3d(in_planes, out_planes, kernel_size=kernel_size, stride=1, padding=((kernel_size-1)//2)),
            nn.BatchNorm3d(out_planes),
            nn.ReLU(True)
        )

    def forward(self, x):
        return self.block(x)

class Res3DBlock(nn.Module):
    def __init__(self, in_planes, out_planes):
        super(Res3DBlock, self).__init__()
        self.res_branch = nn.Sequential(
            nn.Conv3d(in_planes, out_planes, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm3d(out_planes),
            nn.ReLU(True),
            nn.Conv3d(out_planes, out_planes, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm3d(out_planes)
        )

        if in_planes == out_planes:
            self.skip_con = nn.Sequential()
        else:
            self.skip_con = nn.Sequential(
                nn.Conv3d(in_planes, out_planes, kernel_size=1, stride=1, padding=0),
                nn.BatchNorm3d(out_planes)
            )

    def forward(self, x):
        res = self.res_branch(x)
        skip = self.skip_con(x)
        return F.relu(res + skip, True)

class Pool3DBlock(nn.Module):
    def __init__(self, pool_size):
        super(Pool3DBlock, self).__init__()
        self.pool_size = pool_size

    def forward(self, x):
        return F.max_pool3d(x, kernel_size=self.pool_size, stride=self.pool_size)

class Upsample3DBlock(nn.Module):
    def __init__(self, in_planes, out_planes, kernel_size, stride):
        super(Upsample3DBlock, self).__init__()
        assert(kernel_size == 2)
        assert(stride == 2)
        self.block = nn.Sequential(
            nn.ConvTranspose3d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=0, output_padding=0),
            nn.BatchNorm3d(out_planes),
            nn.ReLU(True)
        )

    def forward(self, x):
        return self.block(x)

class EncoderDecorder(nn.Module):
    def __init__(self):
        super(EncoderDecorder, self).__init__()

        self.encoder_pool1 = Pool3DBlock(2)
        self.encoder_res1 = Res3DBlock(32, 64)
        self.encoder_pool2 = Pool3DBlock(2)
        self.encoder_res2 = Res3DBlock(64, 128)

        self.mid_res = Res3DBlock(128, 128)

        self.decoder_res2 = Res3DBlock(128, 128)
        self.decoder_upsample2 = Upsample3DBlock(128, 64, 2, 2)
        self.decoder_res1 = Res3DBlock(64, 64)
        self.decoder_upsample1 = Upsample3DBlock(64, 32, 2, 2)

        self.skip_res1 = Res3DBlock(32, 32)
        self.skip_res2 = Res3DBlock(64, 64)

    def forward(self, x):
        skip_x1 = self.skip_res1(x)
        x = self.encoder_pool1(x)
        x = self.encoder_res1(x)

        skip_x2 = self.skip_res2(x)
        x = self.encoder_pool2(x)
        x = self.encoder_res2(x)

        x = self.mid_res(x)

        x = self.decoder_res2(x)
        x = self.decoder_upsample2(x)
        x = x + skip_x2

        x = self.decoder_res1(x)
        x = self.decoder_upsample1(x)
        x = x + skip_x1

        return x

class V2VNet(nn.Module):
    def __init__(self, input_channels, output_channels):
        super(V2VNet, self).__init__()

        self.front_layers = nn.Sequential(
            Basic3DBlock(input_channels, 16, 7),
            Res3DBlock(16, 32),
        )

        self.encoder_decoder = EncoderDecorder()

        self.output_layer = nn.Conv3d(32, output_channels, kernel_size=1, stride=1, padding=0)

        self._initialize_weights()

    def forward(self, x):
        x = self.front_layers(x)
        x = self.encoder_decoder(x)
        x = self.output_layer(x)

        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv3d):
                # nn.init.xavier_normal_(m.weight)
                nn.init.normal_(m.weight, 0, 0.001)
                nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.ConvTranspose3d):
                # nn.init.xavier_normal_(m.weight)
                nn.init.normal_(m.weight, 0, 0.001)
                nn.init.constant_(m.bias, 0)


# Author: Blake Pennington

#----------------------------------#
# REQUIRES PYTHON 3.6.9 or greater #
#----------------------------------#

# read the input file data.txt and parse it into a dict
def readParse():
    data = []
    ID = 1
    f = open("data.txt", 'r')

    # append in each line in input with a unique ID field 'A'
    for line in f:
        temp_dict = {}
        formatted_segment = (f'A: {ID} ' + line.strip('\n ')).split(' ')
        for i in range(len(formatted_segment)):
            if (i < len(formatted_segment) and (i % 2 == 0)):
                temp_dict[formatted_segment[i].strip(':')] = formatted_segment[i+1]
        data.append(temp_dict)
        ID+=1

    return data

# process queries from final.txt in combination with the data gathered
def processQueries(data):
    processing_find = False
    processing_sort = False
    processing_error = False
    queries = []
    conditions = []
    projections = ''
    count = 1
    key = ''
    order = ''
    f = open("final.txt", "r")

    # grab queries and store in queries list
    for line in f:
        queries.append(line.strip('\n '))

    # iterate through lines in queries
    for i in queries:
        # if FIND found, set flag to true so can do appropriate action on following query lines
        if (i == 'FIND' and processing_find == False):
            processing_find = True
            processing_error = False
        # if FIND query lines
        elif (processing_find):
            # get conditions list
            if 'Y' in i:
                conditions.append(i)
            elif (any(cond in i for cond in ('=', '<', '>'))):
                conditions.append(i)
            # now get projections string and send to find() function with appropriate query attributes
            else:
                projections = i.strip(' ;')
                find(data, count, conditions, projections)
                conditions = []
                projections = ''
                processing_find = False
                count+=1
        # if SORT found, set flag to true so can do appropriate action on following query lines
        elif (i == 'SORT' and processing_sort == False):
            processing_sort = True
            processing_error = False
        # if SORT query lines
        elif (processing_sort):
            if '1' in i or '-1' in i:
                # now send to sort() function with appropriate query attributes
                key = i.split(' = ')[0]
                order = i.split(' = ')[1].strip('; ')
                sort(data, count, key, order)
                processing_sort = False
                key = ''
                order = ''
                count+=1
        # if query is NOT FIND or SORT, print error and set flag to process garbage
        elif(not processing_error):
            processing_error = True
        elif(processing_error and ';' in i):
            print(f'\nQuery {count}')
            count+=1
            print('QUERY ERROR: NO FIND OR SORT FOUND')

# sorts db based on key attribute in ascending or descending order
def sort(data, count, key, order):
    print(f'\nQuery {count}')
    temp_data = data.copy()
    sorted_data = []
    remove_list = []

    # check if ANY document contains the sort field
    if (any(key in d for d in data)):
        pass
    else:
        return

    # remove documents that DO NOT have the sort field
    for j in range(len(temp_data)):
        #temp = temp_data[j].pop(key_for_condition, '')
        if key in temp_data[j]:
            continue
        else:
            remove_list.append(temp_data[j])

    # remove all non-matches from temp_data
    for x in remove_list:
        temp_data.remove(x)

    # sort the data in either ascending/descending order based on key and order parameter
    sorted_data = bubbleSort(temp_data, key, order)

    # print sorted data structure
    for i in temp_data:
        for k, v in i.items():
            print(k, v, sep=': ', end=' ')
        print()

# helper function for sort() that sorts the data appropriately based on given parameters
def bubbleSort(data, key, order):
    size = len(data)
    for i in range(size - 1):
        for j in range(0, size-i-1):
            if order == '-1':
                if int(data[j][key]) < int(data[j+1][key]):
                    temp = data[j]
                    data[j] = data[j+1]
                    data[j+1] = temp
            elif order == '1':
                if int(data[j][key]) > int(data[j+1][key]):
                    temp = data[j]
                    data[j] = data[j+1]
                    data[j+1] = temp

    return data

# finds and prints documents in db that meet the wanted criteria for the query
def find (data, count, conditions, projections):
    # query has no conditions
    print(f"\nQuery {count}")
    if 'Y' in conditions:
        # no projections, so print all
        if 'Z' == projections:
            for i in data:
                for k, v in i.items():
                    print(k, v, sep=': ', end=' ')
                print()
        # get projections
        else:
            projections_list = projections.split(' ')

            # check if projection key even exists in db
            for i in projections_list:
                if (any(i in d for d in data)):
                    pass
                else:
                    return

            # print documents based on the given key(s)
            format_flag = False
            for i in data:
                for k, v in i.items():
                    if k in projections_list:
                        print(k, v, sep=': ', end=' ')
                        format_flag = True
                if (format_flag):
                    print()
                    format_flag = False

    # query has conditions, so process them
    else:
        temp_data = data.copy()
        key_for_condition = ''
        value_for_condition = ''
        remove_list = []

        # loop through conditions and apply appropriate actions
        for i in conditions:
            # first check if condition key even exists in db
            if (any(i.split(' ')[0] in d for d in data)):
                pass
            else:
                return

            # remove all non-matches from temp_data
            for x in remove_list:
                temp_data.remove(x)
            remove_list.clear()
            # if comparison operator is =
            if '=' in i:
                # split condition into key and value variables
                segment = i.split(' = ')
                key_for_condition = segment[0]
                value_for_condition = segment[1]
                # loop through db and gather documents that will be kept or removed
                for j in range(len(temp_data)):
                    if key_for_condition in temp_data[j]:
                        if (temp_data[j][key_for_condition] == value_for_condition):
                            # keep the line because key was found
                            continue
                        else:
                            remove_list.append(temp_data[j])
                    else:
                        remove_list.append(temp_data[j])
            # if comparison operator is >
            elif '>' in i:
                # split condition into key and value variables
                segment = i.split(' > ')
                key_for_condition = segment[0]
                value_for_condition = segment[1]
                # loop through db and gather documents that will be kept or removed
                for j in range(len(temp_data)):
                    if key_for_condition in temp_data[j]:
                        if (temp_data[j][key_for_condition] > value_for_condition):
                            # keep the line because key was found
                            continue
                        else:
                            remove_list.append(temp_data[j])
                    else:
                        remove_list.append(temp_data[j])
            # if comparison operator is <
            elif '<' in i:
                # split condition into key and value variables
                segment = i.split(' < ')
                key_for_condition = segment[0]
                value_for_condition = segment[1]
                # loop through db and gather documents that will be kept or removed
                for j in range(len(temp_data)):
                    if key_for_condition in temp_data[j]:
                        if (temp_data[j][key_for_condition] < value_for_condition):
                            # keep the line because key was found
                            continue
                        else:
                            remove_list.append(temp_data[j])
                    else:
                        remove_list.append(temp_data[j])

        # remove documents that do not match the condition
        for x in remove_list:
            temp_data.remove(x)

        # no projections, so print all
        if 'Z' == projections:
            for i in temp_data:
                for k, v in i.items():
                    print(k, v, sep=': ', end=' ')
                print()

        # projections exist, so process projections
        else:
            projections_list = projections.split(' ')
            # check if projection key even exists in db
            for i in projections_list:
                if (any(i in d for d in data)):
                    break
                else:
                    return

            # print processed db
            projections_list = projections.split(' ')
            for i in temp_data:
                for k, v in i.items():
                    if k in projections_list:
                        print(k, v, sep=': ', end=' ')
                print()

if __name__ == "__main__":

    data = readParse()
    processQueries(data)


class Solution:
    def eventualSafeNodes(self, adj: List[List[int]]) -> List[int]:
        n = len(adj)
        WHITE,GREY,BLACK = range(3)
        color = [WHITE for i in range(n)]

        def dfs(node):
            if color[node]!=WHITE:
                return color[node] == BLACK

            # starting traversal so mark node grey
            color[node]=GREY

            for neig in adj[node]:
                if not dfs(neig):
                    return False

            color[node]=BLACK
            return True

        ans = []
        for node in range(n):
            if dfs(node):
                ans.append(node)

        return ans


bl_info = {
    "name": "come back cursor",
    "author": "1C0D",
    "version": (1, 1, 1),
    "blender": (2, 90, 0),
    "location": "Text Editor > only > Text editor",
    "description": "stay home cursor",
    "wiki_url": "",
    "category": "Text Editor",
}

"""
Use shortcut shift+Right Mouse to toggle the operator. the icon in the header is more like an indicator. don't activate more than 2 limits by default down and right are True (see in addon preferences). if you need other corners uncomment lines

"""

import bpy

class COME_back_cursor(bpy.types.Operator):
    """Get back cursor in the right place"""
    bl_idname = "text.come_back"
    bl_label = "come back cursor"

    def modal(self, context, event):

        preferences = bpy.context.preferences
        addon_prefs = preferences.addons[__name__].preferences
        region=context.region

        if context.area.type=='TEXT_EDITOR':
            if addon_prefs.y_min and event.mouse_region_y <= 10:    #bottom
                context.window.cursor_warp(event.mouse_x,region.y+event.mouse_region_y+1)

            if addon_prefs.y_max and event.mouse_region_y >= (region.height-10):   #top
                context.window.cursor_warp(event.mouse_x,region.y+event.mouse_region_y-1)

            if addon_prefs.x_min and event.mouse_region_x <= 30:
                context.window.cursor_warp(region.x+event.mouse_x+1,event.mouse_y)

            if addon_prefs.x_max and event.mouse_region_x >= context.area.width-1:  #if side panel
                context.window.cursor_warp(region.x+event.mouse_x-1,event.mouse_y)

        if event.type == 'ESC' or not context.scene.toggle_cbc:
            context.scene.toggle_cbc = False
            return {'FINISHED'}

        else:
            return {'PASS_THROUGH'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):

        context.window_manager.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    @classmethod
    def _setup(cls):
        cls._keymaps = []
        kc = bpy.context.window_manager.keyconfigs.addon.keymaps
        get, new = kc.get, kc.new
        km = get('Text', new(name='Text', space_type='TEXT_EDITOR'))

        new = km.keymap_items.new
        wm = bpy.context.window_manager
        kmi = new("wm.context_toggle", 'RIGHTMOUSE', 'PRESS', shift=1)
        kmi.properties.data_path = "scene.toggle_cbc"
        cls._keymaps.append((km, kmi))

    @classmethod
    def _remove(cls):
        for km, kmi in cls._keymaps:
            km.keymap_items.remove(kmi)
        cls._keymaps.clear()

class COME_PT_back_cursor(bpy.types.AddonPreferences):
    bl_idname = __name__

    y_min: bpy.props.BoolProperty(
            name="enable y min",
            default=True,
            )
    y_max: bpy.props.BoolProperty(
            name="enable y max",
            default=False,
            )
    x_min: bpy.props.BoolProperty(
            name="enable x min",
            default=False,
            )
    x_max: bpy.props.BoolProperty(
            name="enable x max",
            default=True,
            )

    def draw(self, context):
        layout = self.layout
        layout.prop(self, "y_min")
        layout.prop(self, "y_max")
        layout.prop(self, "x_min")
        layout.prop(self, "x_max")

def update_toggle_cbc(self, context):

    print("state0", context.scene.toggle_cbc)
    if context.scene.toggle_cbc:
        bpy.ops.text.come_back('INVOKE_DEFAULT')
        print("state1", context.scene.toggle_cbc)

def draw(self, context):

    layout = self.layout
    layout.prop(context.scene, "toggle_cbc",text='', icon="VIS_SEL_11", toggle=False)

def register():
    bpy.utils.register_class(COME_back_cursor)
    COME_back_cursor._setup()
    bpy.utils.register_class(COME_PT_back_cursor)
    bpy.types.TEXT_HT_header.prepend(draw)
    bpy.types.Scene.toggle_cbc = bpy.props.BoolProperty(update=update_toggle_cbc,default=False)

def unregister():
    bpy.types.TEXT_HT_header.remove(draw)
    bpy.utils.unregister_class(COME_PT_back_cursor)
    bpy.utils.unregister_class(COME_back_cursor)
    COME_back_cursor._remove()
    del bpy.types.Scene.toggle_cbc

if __name__ == "__main__":
    register()


import wx
import objdlg

import servers
import app

import conjurerconfig as cfg

class NOHTree(wx.TreeCtrl):
    """
    This wxTreeCtrl derivative displays a tree view of nebula's namespace.

    Set 'passive' to True if you don't want this control to access its parent
    or do anything else than allowing the user to select an object in the tree.
    """
    def __init__(
        self,
        parent,
        control_id,
        root,
        style=wx.TR_DEFAULT_STYLE,
        modal=False,
        passive=False
        ):
        wx.TreeCtrl.__init__(self, parent, control_id, style=style)

        self.root = self.AddRoot(
                            root.getname(),
                            -1,
                            -1,
                            wx.TreeItemData(root)
                            )

        self.parent = parent
        self.modal = modal
        self.passive = passive

        # prepare images
        self.image_list = None
        self.set_default_icons()

        # add image to root item
        self.SetItemImage(
            self.root,
            self.fldridxnormal,
            wx.TreeItemIcon_Normal
            )
        self.SetItemImage(
            self.root,
            self.fldropenidxnormal,
            wx.TreeItemIcon_Expanded
            )

        if root.gethead() != None:
            self.SetItemHasChildren(self.root, True)

        self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.on_item_expanding, self)
        self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.on_item_collapsed, self)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.on_sel_changed, self)
        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.on_activated, self)

        self.output = None
        self.selection_changed_callback = None

        self.Expand(self.GetRootItem())

    def set_default_icons (self):
        image_size = (16, 16)
        self.image_list = wx.ImageList(
                                image_size[0],
                                image_size[1]
                                )
        self.fldridxnormal = self.image_list.Add(
                                    wx.ArtProvider_GetBitmap(
                                        wx.ART_FOLDER,
                                        wx.ART_OTHER,
                                        image_size
                                        )
                                    )
        self.fldropenidxnormal = self.image_list.Add(
                                            wx.ArtProvider_GetBitmap(
                                                wx.ART_FILE_OPEN,
                                                wx.ART_OTHER,
                                                image_size
                                                )
                                            )
        file_server = servers.get_file_server()
        bitmap_path = file_server.manglepath(
                                "outgui:images/tools/blue_folder_close.bmp"
                                )
        self.fldridxnative = self.image_list.Add( wx.Bitmap(bitmap_path) )
        bitmap_path = file_server.manglepath(
                                "outgui:images/tools/blue_folder_open.bmp"
                                )
        self.fldropenidxnative = self.image_list.Add( wx.Bitmap(bitmap_path) )
        bitmap_path = file_server.manglepath(
                                "outgui:images/tools/green_folder_close.bmp"
                                )
        self.fldridxuser = self.image_list.Add( wx.Bitmap(bitmap_path) )
        bitmap_path = file_server.manglepath(
                                "outgui:images/tools/green_folder_open.bmp"
                                )
        self.fldropenidxuser = self.image_list.Add( wx.Bitmap(bitmap_path) )
        self.SetImageList(self.image_list)

    def set_selection_changed_callback(self, callback):
        self.selection_changed_callback = callback

    def on_item_expanding (self, event):
        item = event.GetItem()
        if self.IsExpanded(item):
            # This event can happen twice in the self.Expand call
            return

        obj = self.GetPyData(item)
        node = obj.gethead()
        while node != None:
            if node.hascommand("getsucc"):
                if not node.ishideineditor():
                    new_item = self.AppendItem(
                                        item,
                                        node.getname(),
                                        -1,
                                        -1,
                                        wx.TreeItemData(node)
                                        )

                    self.SetItemImage(
                        new_item,
                        self.fldridxnormal,
                        wx.TreeItemIcon_Normal
                        )
                    self.SetItemImage(
                        new_item,
                        self.fldropenidxnormal,
                        wx.TreeItemIcon_Selected
                        )
                    self.SetItemImage(
                        new_item,
                        self.fldropenidxnormal,
                        wx.TreeItemIcon_Expanded)

                    if node.gethead() != None:
                        self.SetItemHasChildren(new_item, True)

                node = node.getsucc()
            else:
                # Some children aren't nroots...so skip checking
                break
        self.SortChildren(item)

    def on_item_collapsed(self, event):
        item = event.GetItem()
        self.DeleteChildren(item)

    def on_sel_changed(self, event):
        if event.GetItem():
            obj = self.GetPyData(event.GetItem())
            if not self.passive:
                self.parent.parent.SetTitle(obj.getfullname())
                class_name = obj.getclass()
                self.parent.obj_class.SetLabel("Class: %s" % str(class_name))
                self.parent.current_path = obj.getfullname()
            if self.selection_changed_callback is not None:
                self.selection_changed_callback(obj)
        else:
            event.Skip()

    def on_activated(self, event):
        if not self.modal:
            obj = self.GetPyData(event.GetItem())
            if not self.passive:
                win = objdlg.create_window(
                            self.parent.parent.parent,
                            obj.getfullname()
                            )
                win.display()

    def expand_tree (self, path):
        """
        Expand the NOH tree until last object in the provided path
        and select it

        \param Complete path to expand
        """
        node_name_list = path.rsplit('/')
        node_name_list.pop(0)
        node = self.GetRootItem()
        self.CollapseAndReset(node)
        self.Expand(node)

        # Autoexpand the tree to object

        end_main_loop = False
        for each in node_name_list:
            if end_main_loop:
                break
            if '' != each:
                node, cookie = self.GetFirstChild(node)
                should_exit = False
                while not should_exit:
                    # abandon if node is not valid
                    if not node.IsOk():
                        end_main_loop = True
                        break;
                    if self.GetItemText(node) == each:
                        self.Expand(node)
                        node = node
                        should_exit = True
                    else:
                        node, cookie = self.GetNextChild(node, cookie)

        # Select object and update title
        self.SelectItem(node)

    def OnCompareItems(self, first_item_id, second_item_id):
        """Case INsenstive sort on item label"""
        first_item_label = self.GetItemText(first_item_id)
        second_item_label = self.GetItemText(second_item_id)
        return first_item_label.lower() >= second_item_label.lower()

class NOHSelectionDialog (wx.Dialog):
    def __init__(self, parent):
        wx.Dialog.__init__(
            self,
            parent,
            -1,
            "Select a library location",
            style=cfg.DEFAULT_DIALOG_STYLE
            )
        self.target_library = None
        self.tree_view = NOHTree(
                        self,
                        -1,
                        app.get_libraries(),
                        passive=True
                        )
        self.button_ok = wx.Button(self, -1, "&OK")
        #giving cancel button special ID so it will close when ESC is pressed
        self.button_cancel = wx.Button(self, wx.ID_CANCEL, "&Cancel")

        self.__set_properties()
        self.__do_layout()
        self.__bind_events()

    def __set_properties(self):
        self.SetDefaultItem(self.button_ok)

    def __do_layout(self):
        sizer_layout = wx.BoxSizer(wx.VERTICAL)
        sizer_buttons = wx.BoxSizer(wx.HORIZONTAL)
        sizer_layout.Add(
            self.tree_view,
            1,
            wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND,
            cfg.BORDER_WIDTH
            )
        horizontal_line = wx.StaticLine(
                                    self,
                                    -1,
                                    ( -1, -1 ),
                                    ( -1, -1 ),
                                    wx.LI_HORIZONTAL
                                    )
        sizer_layout.Add(
            horizontal_line,
            0,
            wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP,
            cfg.BORDER_WIDTH
            )
        sizer_buttons.Add(
            self.button_ok,
            1,
            wx.FIXED_MINSIZE
            )
        sizer_buttons.Add(
            self.button_cancel,
            1,
            wx.LEFT|wx.FIXED_MINSIZE,
            cfg.BORDER_WIDTH
            )
        sizer_layout.Add(
            sizer_buttons,
            0,
            wx.ALL|wx.ALIGN_RIGHT,
            cfg.BORDER_WIDTH
            )
        self.SetAutoLayout(True)
        # Set the sizer and make sure the dialog cannot be
        # made any smaller than its appropriate minimum size
        self.SetSizerAndFit(sizer_layout)
        # Set the initial size so that the title is visible
        self.SetSize( (250, 300) )
        self.Layout()

    def __bind_events(self):
        self.tree_view.set_selection_changed_callback(
            self.__on_select_target
            )
        self.Bind(
            wx.EVT_BUTTON,
            self.__on_ok,
            self.button_ok
            )
        self.Bind(
            wx.EVT_BUTTON,
            self.__on_cancel,
            self.button_cancel
            )

    def __on_select_target(self, selected_object):
        if selected_object.isa('nstringlist'):
            self.target_library = selected_object.getfullname()
        else:
            self.target_library = None
        self.__update_button_ok()

    def __update_button_ok(self):
        self.button_ok.Enable(
            self.target_library is not None
            )

    def __on_ok(self, event):
        self.EndModal(wx.ID_OK)

    def __on_cancel(self, event):
        self.EndModal(wx.ID_CANCEL)

def create_selection_dialog(frame):
    return NOHSelectionDialog(frame)


from typing import Dict, List

from langchain_community.agent_toolkits.base import BaseToolkit
from langchain_community.tools import BaseTool
from langchain_community.tools.clickup.prompt import (
    CLICKUP_FOLDER_CREATE_PROMPT,
    CLICKUP_GET_ALL_TEAMS_PROMPT,
    CLICKUP_GET_FOLDERS_PROMPT,
    CLICKUP_GET_LIST_PROMPT,
    CLICKUP_GET_SPACES_PROMPT,
    CLICKUP_GET_TASK_ATTRIBUTE_PROMPT,
    CLICKUP_GET_TASK_PROMPT,
    CLICKUP_LIST_CREATE_PROMPT,
    CLICKUP_TASK_CREATE_PROMPT,
    CLICKUP_UPDATE_TASK_ASSIGNEE_PROMPT,
    CLICKUP_UPDATE_TASK_PROMPT,
)
from langchain_community.tools.clickup.tool import ClickupAction
from langchain_community.utilities.clickup import ClickupAPIWrapper

class ClickupToolkit(BaseToolkit):
    """Clickup Toolkit.

    *Security Note*: This toolkit contains tools that can read and modify
        the state of a service; e.g., by reading, creating, updating, deleting
        data associated with this service.

        See https://python.langchain.com/docs/security for more information.
    """

    tools: List[BaseTool] = []

    @classmethod
    def from_clickup_api_wrapper(
        cls, clickup_api_wrapper: ClickupAPIWrapper
    ) -> "ClickupToolkit":
        operations: List[Dict] = [
            {
                "mode": "get_task",
                "name": "Get task",
                "description": CLICKUP_GET_TASK_PROMPT,
            },
            {
                "mode": "get_task_attribute",
                "name": "Get task attribute",
                "description": CLICKUP_GET_TASK_ATTRIBUTE_PROMPT,
            },
            {
                "mode": "get_teams",
                "name": "Get Teams",
                "description": CLICKUP_GET_ALL_TEAMS_PROMPT,
            },
            {
                "mode": "create_task",
                "name": "Create Task",
                "description": CLICKUP_TASK_CREATE_PROMPT,
            },
            {
                "mode": "create_list",
                "name": "Create List",
                "description": CLICKUP_LIST_CREATE_PROMPT,
            },
            {
                "mode": "create_folder",
                "name": "Create Folder",
                "description": CLICKUP_FOLDER_CREATE_PROMPT,
            },
            {
                "mode": "get_list",
                "name": "Get all lists in the space",
                "description": CLICKUP_GET_LIST_PROMPT,
            },
            {
                "mode": "get_folders",
                "name": "Get all folders in the workspace",
                "description": CLICKUP_GET_FOLDERS_PROMPT,
            },
            {
                "mode": "get_spaces",
                "name": "Get all spaces in the workspace",
                "description": CLICKUP_GET_SPACES_PROMPT,
            },
            {
                "mode": "update_task",
                "name": "Update task",
                "description": CLICKUP_UPDATE_TASK_PROMPT,
            },
            {
                "mode": "update_task_assignees",
                "name": "Update task assignees",
                "description": CLICKUP_UPDATE_TASK_ASSIGNEE_PROMPT,
            },
        ]
        tools = [
            ClickupAction(
                name=action["name"],
                description=action["description"],
                mode=action["mode"],
                api_wrapper=clickup_api_wrapper,
            )
            for action in operations
        ]
        return cls(tools=tools)

    def get_tools(self) -> List[BaseTool]:
        """Get the tools in the toolkit."""
        return self.tools


from django.db import models

# Create your models here.

from django.utils import timezone
# class Product(models.Model):
#     PRODUCT_

from django.utils import  timezone
class Product(models.Model):
    PRODUCTS_CHOICES = (
        ('家用机器人', '家用机器人'),
        ('智能监控', '智能监控'),
        ('人脸识别解决方案', '人脸识别解决方案'),
    )          #不是字段
    title = models.CharField(max_length=50, verbose_name=' 产品标题')
    description = models.TextField(verbose_name='产品详情描述')
    productType = models.CharField(choices=PRODUCTS_CHOICES,
                                   max_length=50,
                                   verbose_name='产品类型')
    price = models.DecimalField(max_digits=7,
                                decimal_places=1,
                                blank=True,
                                null=True,
                                verbose_name='产品价格')
    publishDate = models.DateTimeField(max_length=20,default=timezone.now,verbose_name='发布时间')
    views = models.PositiveIntegerField('浏览量', default=0)

    def __str__(self):
        return self.title    # 在后台显示每条数据的title字段

    class Meta:
        verbose_name = '产品'
        verbose_name_plural = '产品'
        ordering = ('-publishDate', )

# “产品图片”类从属于产品类。
# 每个产品可以有多张图片，每张图片从属于一个产品。
# 两个字段
class ProductImg(models.Model):
    product = models.ForeignKey(Product,   #该外键从属于Product类
                                related_name='productImgs',  #在Product类中利用该名称调用产品图片
                                verbose_name='产品',
                                on_delete=models.CASCADE)   #当产品删掉，产品的图片也会被删掉
    photo = models.ImageField(upload_to='Product/',
                              blank=True,
                              verbose_name='产品图片')

    class Meta:
        verbose_name = '产品图片'
        verbose_name_plural = '产品图片'


import BaseNetCDF
import FileMgr

from BaseLog import log_error

def init_sensor(module_name, init_dict=None):
    """
    init_sensor

    Returns:
        -1 - error in processing
         0 - success (data found and processed)
    """

    if init_dict is None:
        log_error("No datafile supplied for init_sensors - version mismatch?")
        return -1

    BaseNetCDF.register_sensor_dim_info(
        BaseNetCDF.nc_sbect_data_info, "sbect_data_point", "sbect_time", True, "sbe41"
    )
    # results are computed in MDP
    init_dict[module_name] = {
        "netcdf_metadata_adds": {
            "sbe41": [
                False,
                "c",
                {
                    "long_name": "underway thermosalinograph",
                    "nodc_name": "thermosalinograph",
                    "make_model": "unpumped Seabird SBE41",
                },
                BaseNetCDF.nc_scalar,
            ],  # always scalar
            # TODO do we want to include these in MMP/MMT? NO, because there is derived data instead
            # add 'As reported by instrument'?
            # add 'comment':'Values are reported freqences'
            # standard unpumped CT in eng file
            "eng_condFreq": [
                False,
                "d",
                {"description": "As reported by the instrument", "instrument": "sbe41"},
                (BaseNetCDF.nc_sg_data_info,),
            ],
            "eng_tempFreq": [
                False,
                "d",
                {"description": "As reported by the instrument", "instrument": "sbe41"},
                (BaseNetCDF.nc_sg_data_info,),
            ],
            # SailCT in eng file (only a few missions, rarely used. now part of scicon)
            "eng_sbect_condFreq": [
                False,
                "d",
                {"description": "As reported by the instrument", "instrument": "sbe41"},
                (BaseNetCDF.nc_sg_data_info,),
            ],
            "eng_sbect_tempFreq": [
                False,
                "d",
                {"description": "As reported by the instrument", "instrument": "sbe41"},
                (BaseNetCDF.nc_sg_data_info,),
            ],
            # SailCT via scicon
            "sbect_time": [
                True,
                "d",
                {
                    "standard_name": "time",
                    "units": "seconds since 1970-1-1 00:00:00",
                    "description": "sbe41 time in GMT epoch format",
                },
                (BaseNetCDF.nc_sbect_data_info,),
            ],
            "sbect_condFreq": [
                False,
                "d",
                {"description": "As reported by the instrument"},
                (BaseNetCDF.nc_sbect_data_info,),
            ],
            "sbect_tempFreq": [
                False,
                "d",
                {"description": "As reported by the instrument"},
                (BaseNetCDF.nc_sbect_data_info,),
            ],
            # gpctd (pumped sbect) variables are declared in Sensors/payload_ext.py
            # derived results from CT are declared in BaseNetCDF.py
        }
    }

    for cast, descr in FileMgr.cast_descr:
        init_dict[module_name]["netcdf_metadata_adds"][f"sbect_ontime_{cast}"] = [
            False,
            "d",
            {"description": f"sbect total time turned on {descr}", "units": "secs"},
            BaseNetCDF.nc_scalar,
        ]
        init_dict[module_name]["netcdf_metadata_adds"][f"sbect_samples_{cast}"] = [
            False,
            "i",
            {"description": f"sbect total number of samples taken {descr}"},
            BaseNetCDF.nc_scalar,
        ]
        init_dict[module_name]["netcdf_metadata_adds"][f"sbect_timeouts_{cast}"] = [
            False,
            "i",
            {"description": f"sbect total number of samples time out on {descr}"},
            BaseNetCDF.nc_scalar,
        ]

    return 0

# pylint: disable=unused-argument
def asc2eng(base_opts, module_name, datafile=None):
    """
    Asc2eng processor

    returns:
    -1 - error in processing
     0 - success (data found and processed)
     1 - no data found to process
    """

    if datafile is None:
        log_error("No datafile supplied for asc2eng conversion - version mismatch?")
        return -1

    #  TT8 freq counting algorithm uses a 4Mhz clock source which increments a
    #  counter. Counting is enabled by the first positive edge of the signal to
    #  be measured.  255 positive edges are counted or 255 cycles of the signal are
    #  measured with the 4Mhz clock.

    # Thus the values of raw data for conductivity, temperature, and oxygen are in units
    # of 4MHz.  255 cycles and 24bit counter permit measured frequencies 2-7kHz.

    # From first basestation code:
    #   We have observed conductivity readings of zero, which crashes the script
    #   Current theory is that they are caused by a bubble in the sensor.
    #
    #   We change those values to a small (and distinctive) value so they are clear but benign
    #   Changing to small value make the range nonsense.  Duplicate last non-zero value

    is_scct = False

    # Seabird CT - old name
    sbect_condFreq = datafile.remove_col("CondFreq")
    sbect_tempFreq = datafile.remove_col("TempFreq")

    # Seabird CT - new name
    if sbect_condFreq is None:
        sbect_condFreq = datafile.remove_col("sbect.CondFreq")
        sbect_tempFreq = datafile.remove_col("sbect.TempFreq")

    # iRobot latest naming scheme
    if sbect_condFreq is None:
        sbect_condFreq = datafile.remove_col_regex("sbect[0-9][0-9][0-9].CondFreq")
        sbect_tempFreq = datafile.remove_col_regex("sbect[0-9][0-9][0-9].TempFreq")

    # SCCT - Scicon used as pass through for CT
    if sbect_condFreq is None:
        sbect_condFreq = datafile.remove_col("scct.condFreq")
        sbect_tempFreq = datafile.remove_col("scct.tempFreq")
        is_scct = True

    if sbect_condFreq is not None:
        # Rev E (67.00 and later) - just divide by 1000.
        if datafile.version >= 67.0 or is_scct:
            sbect_condFreq = sbect_condFreq / 1000.0
            sbect_tempFreq = sbect_tempFreq / 1000.0
        else:
            sbect_condFreq = 4000000.0 / (sbect_condFreq / 255.0)
            sbect_tempFreq = 4000000.0 / (sbect_tempFreq / 255.0)

        datafile.eng_cols.append("sbect.condFreq")
        datafile.eng_cols.append("sbect.tempFreq")

        datafile.eng_dict["sbect.condFreq"] = sbect_condFreq
        datafile.eng_dict["sbect.tempFreq"] = sbect_tempFreq
        return 0

    return 1


nA , nB = map(int, input().split())

A = list(input().split())
B = list(input().split())

hash_map = {}
for b in B:
    hash_map[b] = 1

commonValue = []
for a in A:
    if a in hash_map:
        commonValue.append(a)

#print("commonValue", commonValue)
if len(commonValue) == nA:  #모두 중복이라면
    print(0)
else:   #일부 중복이라면
    for cValue in commonValue:
        A.remove(cValue)

    print(len(A))
    A = list(map(int, A))
    A.sort  #작은수 부터 출력
    for i in range(0,len(A)):
        print(A[i], end=" ")


from collections import deque

q = deque()

command = input()

while command != 'End':
    if command == 'Paid':
        [print(name) for name in q]
        q.clear()
    else:
        q.append(command)
    command = input()

print(f'{len(q)} people remaining.')


import sys
input = sys.stdin.readline

def isValid(mid):
    min_v = max_v = arr[0]
    cnt = 1

    for x in arr:
        if x > max_v:
            max_v = x
        if x < min_v:
            min_v = x
        if max_v - min_v > mid: # mid가 가장 작은 최댓값이 돼야하므로
            cnt += 1
            max_v = x
            min_v = x

    return m >= cnt

n, m = map(int, input().split())
arr = list(map(int, input().split()))

s = 0
e = max(arr)

res = float("inf")
while s<=e:
    mid = (s+e)//2
    if isValid(mid):
        e = mid - 1
        res = min(res, mid)
    else:
        s = mid + 1

print(res)


'''
Created on April , 2021
@author:
'''

## Import libraries in python
import argparse
import time
import json
import logging
import sys
import os
import math
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import random
import importlib
from scipy.stats import randint, expon, uniform

import tensorflow as tf
import sklearn as sk
from sklearn import svm
from sklearn.utils import shuffle
from sklearn import metrics
from sklearn import preprocessing
from sklearn import pipeline
from sklearn.metrics import mean_squared_error
from math import sqrt

from rp_creator import input_gen
from network import network_fit

# Ignore tf err log
pd.options.mode.chained_assignment = None  # default='warn'
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
tf.get_logger().setLevel(logging.ERROR)

# random seed predictable
seed = 0
random.seed(seed)
np.random.seed(seed)

current_dir = os.path.dirname(os.path.abspath(__file__))

## Dataset path
train_FD001_path = current_dir +'/cmapss/train_FD001.csv'
test_FD001_path = current_dir +'/cmapss/test_FD001.csv'
RUL_FD001_path = current_dir+'/cmapss/RUL_FD001.txt'
FD001_path = [train_FD001_path, test_FD001_path, RUL_FD001_path]

train_FD002_path = current_dir +'/cmapss/train_FD002.csv'
test_FD002_path = current_dir +'/cmapss/test_FD002.csv'
RUL_FD002_path = current_dir +'/cmapss/RUL_FD002.txt'
FD002_path = [train_FD002_path, test_FD002_path, RUL_FD002_path]

train_FD003_path = current_dir +'/cmapss/train_FD003.csv'
test_FD003_path = current_dir +'/cmapss/test_FD003.csv'
RUL_FD003_path = current_dir +'/cmapss/RUL_FD003.txt'
FD003_path = [train_FD003_path, test_FD003_path, RUL_FD003_path]

train_FD004_path =current_dir +'/cmapss/train_FD004.csv'
test_FD004_path = current_dir +'/cmapss/test_FD004.csv'
RUL_FD004_path = current_dir +'/cmapss/RUL_FD004.txt'
FD004_path = [train_FD004_path, test_FD004_path, RUL_FD004_path]

## Assign columns name
cols = ['unit_nr', 'cycles', 'os_1', 'os_2', 'os_3']
cols += ['sensor_{0:02d}'.format(s + 1) for s in range(26)]
col_rul = ['RUL_truth']

## Read csv file to pandas dataframe
FD_path = ["none", FD001_path, FD002_path, FD003_path, FD004_path]
dp_str = ["none", "FD001", "FD002", "FD003", "FD004"]

## temporary model path for NN
model_path = current_dir +'/temp_net.h5'

def concat_vec(train_samples, test_samples):
    '''
    concatenate vectors for MLPs (this is not to be used for the case of CNN which allows 2D input)
    :param train_samples:
    :param test_samples:
    :return:
    '''
    # flatten 2D rp to 1D vector and concatenate all vectors.
    if len(train_samples.shape)==4:
        train_vec_samples = train_samples.reshape(train_samples.shape[0],
                                                  train_samples.shape[1]*train_samples.shape[2]*train_samples.shape[3])
        test_vec_samples = test_samples.reshape(test_samples.shape[0],
                                                  test_samples.shape[1]*test_samples.shape[2]*test_samples.shape[3])

    # concatenate all the flattened vectors. ( if 2D rps are already flattened)
    elif len(train_samples.shape)==3:
        train_vec_samples = train_samples.reshape(train_samples.shape[0],
                                                  train_samples.shape[1]*train_samples.shape[2])
        test_vec_samples = test_samples.reshape(test_samples.shape[0],
                                                  test_samples.shape[1]*test_samples.shape[2])

    return train_vec_samples, test_vec_samples

def main():
    # current_dir = os.path.dirname(os.path.abspath(__file__))
    parser = argparse.ArgumentParser(description='RPs creator')
    parser.add_argument('-i', type=int, help='Input sources', required=True)
    parser.add_argument('-l', type=int, default=10, help='sequence length')
    parser.add_argument('--method', type=str, default='rps', help='data representation: rps')
    parser.add_argument('--thres_type', type=str, default=None, required=False,
                        help='threshold type for RPs: distance or point ')
    parser.add_argument('--thres_value', type=int, default=50, required=False,
                        help='percentage of maximum distance or black points for threshold')
    parser.add_argument('--flatten', type=str, default='no', help='flatten rps array.')
    parser.add_argument('--visualize', type=str, default='yes', help='visualize rps.')
    parser.add_argument('--n_hidden1', type=int, default=100, required=False,
                        help='number of neurons in the first hidden layer')
    parser.add_argument('--n_hidden2', type=int, default=10, required=False,
                        help='number of neurons in the second hidden layer')
    parser.add_argument('--epochs', type=int, default=1000, required=False, help='number epochs for network training')
    parser.add_argument('--batch', type=int, default=700, required=False, help='batch size of BPTT training')
    parser.add_argument('--verbose', type=int, default=2, required=False, help='Verbose TF training')
    parser.add_argument('--device', type=str, default='cpu', help='Device to run model on cpu or cuda.')

    args = parser.parse_args()

    dp = FD_path[args.i]
    subdataset = dp_str[args.i]
    sequence_length = args.l
    thres_type = args.thres_type
    thres_value = args.thres_value
    device = args.device
    method = args.method
    n_hidden1 = args.n_hidden1
    n_hidden2 = args.n_hidden2
    epochs = args.epochs
    batch = args.batch
    verbose = args.verbose

    flatten = args.flatten
    if flatten == 'yes':
        flatten = True
    elif flatten == 'no':
        flatten = False

    visualize = args.visualize
    if visualize == 'yes':
        visualize = True
    elif visualize == 'no':
        visualize = False

    # Sensors not to be considered (those that do not disclose any pattern in their ts)
    sensor_drop = ['sensor_01', 'sensor_05', 'sensor_06', 'sensor_10', 'sensor_16', 'sensor_18', 'sensor_19']

    start = time.time()

    print("Dataset: ", subdataset)
    print("Seq_len: ", sequence_length)

    """ Creates a new instance of the training-validation task and computes the fitness of the current individual """
    data_class = input_gen(data_path_list=dp, sequence_length=sequence_length, sensor_drop= sensor_drop, visualize=visualize)

    if method == 'rps':
        train_samples, label_array_train, test_samples, label_array_test = data_class.rps(
            thres_type=thres_type,
            thres_percentage=thres_value,
            flatten=flatten,
            visualize=visualize)

    elif method == 'jrp': # please implement any method if needed
        pass

    print ("train_samples.shape: ", train_samples.shape) # shape = (samples, sensors, height, width)
    print ("label_array_train.shape: ", label_array_train.shape) # shape = (samples, label)
    print ("test_samples.shape: ", test_samples.shape) # shape = (samples, sensors, height, width)
    print ("label_array_test.shape: ", label_array_test.shape) # shape = (samples, ground truth)

    train_samples, test_samples = concat_vec(train_samples, test_samples)

    print ("train_samples.shape: ", train_samples.shape) # shape = (samples, sensors, height, width)
    print ("label_array_train.shape: ", label_array_train.shape) # shape = (samples, label)
    print ("test_samples.shape: ", test_samples.shape) # shape = (samples, sensors, height, width)
    print ("label_array_test.shape: ", label_array_test.shape) # shape = (samples, ground truth)

    mlps_net = network_fit(train_samples, label_array_train, test_samples, label_array_test,
                           model_path = model_path, n_hidden1=n_hidden1, n_hidden2=n_hidden2, verbose=verbose)

    trained_net = mlps_net.train_net(epochs=epochs, batch_size=batch)
    rms, score = mlps_net.test_net(trained_net)

    print(subdataset + " test RMSE: ", rms)
    print(subdataset + " test Score: ", score)

    end = time.time()
    print("Computing time: ", end - start)

if __name__ == '__main__':
    main()


from pygame.rect import *
from Pkg.Denovo_Learning.Parameters import Parameters

import pygame as pg

class Target:

    def __init__(self):
        self.rect = Rect(Parameters.target_x, Parameters.target_y, Parameters.target_diameter, Parameters.target_diameter)

    def move(self):
        self.rect.move_ip(Parameters.speed)

        if self.rect.left < 0:
            Parameters.speed[0] *= -1
        if self.rect.right > Parameters.width:
            Parameters.speed[0] *= -1
        if self.rect.top < 0:
            Parameters.speed[1] *= -1
        if self.rect.bottom > Parameters.height:
            Parameters.speed[1] *= -1

    def update(self, mode, Screen):
        if mode == 'base':
            self.target = pg.draw.ellipse(Screen.screen, Parameters.gray, self.rect, width = 1)
        elif mode == 'adapt':
            self.target = pg.draw.ellipse(Screen.screen, Parameters.blue, self.rect, width = 1)
        elif mode == 'reverse':
            self.target = pg.draw.ellipse(Screen.screen, Parameters.yellow, self.rect, width = 1)

    def get_pos(self):
        return [list(self.rect.copy())[0],list(self.rect.copy())[1]]