import asyncio
import json
import logging
import traceback
from typing import Generator

from eth_utils import to_checksum_address
from web3 import HTTPProvider, Web3
from web3.contract import Contract
from web3.types import HexBytes, LogReceipt

from backend.admin import send_admin_message
from backend.database import Database
from backend.notifier import Notifier
from backend.types import Chain, ChainAccount, ChainAccountWithAllData

HEALTH_FACTOR_CHECK_PERIOD = 60 * 15  # every 15 minutes
LIQUIDATIONS_CHECK_PERIOD = 60 * 15  # every 15 minutes
HEALTH_FACTOR_BATCH_SIZE = 100  # How many accounts to check at once. Limited by max gas per call.
MAX_UINT256 = 2 ** 256 - 1
MAX_BLOCK_RANGE = 100

LIQUIDATION_TOPIC = '0xe413a321e8681d831f4dbccbca790d2952b56f977908e45be37335533e005286'
MULTICALL_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11'

def topic_to_address(topic: HexBytes) -> str:
    return to_checksum_address('0x' + topic.hex()[-40:])

def build_subscription_message(pool_address: str, liquidation_topic: str) -> dict:
    return {'id': 2, 'method': 'eth_subscribe', 'params': ['logs', {
        'address': pool_address,
        'topics': [liquidation_topic],
    }]}

def make_batches(lst: list, batch_size: int) -> Generator[list, None, None]:
    """Yield successive n-sized batches from lst."""
    for i in range(0, len(lst), batch_size):
        yield lst[i:i + batch_size]

class ChainConnector():
    def __init__(
            self,
            chain: Chain,
            http_rpc_url: str,
            notifier: Notifier,
            database: Database,
            pool_address: str,
            aave_version: int,
    ) -> None:
        self.http_rpc_url = http_rpc_url
        self.web3 = Web3(HTTPProvider(http_rpc_url))
        self.chain = chain
        self.notifier = notifier
        self.database = database
        self.pool_address = pool_address
        self.aave_version = aave_version

        with open(f'./backend/abi/v{aave_version}_pool.json') as f:
            pool_abi = json.loads(f.read())

        with open('./backend/abi/erc20.json') as f:
            erc20_abi = json.loads(f.read())

        with open('./backend/abi/multicall.json') as f:
            multicall_abi = json.loads(f.read())

        self.erc20_abi = erc20_abi
        self.pool_contract: Contract = self.web3.eth.contract(
            address=pool_address,
            abi=pool_abi,
        )
        self.multical_contract: Contract = self.web3.eth.contract(
            address=MULTICALL_ADDRESS,
            abi=multicall_abi,
        )

    def get_health_factors(
            self,
            accounts_batch: list[ChainAccountWithAllData],
    ) -> list[float]:
        """Get aave health factors of all accounts in the batch"""
        encoded_calls = []
        for account in accounts_batch:
            encoded = self.pool_contract.encodeABI(
                fn_name='getUserAccountData',
                args=[account.account.address],
            )
            encoded_calls.append((self.pool_contract.address, encoded))

        accounts_data = self.multical_contract.functions.aggregate(encoded_calls).call()[1]

        health_factors = []
        for account_data in accounts_data:
            raw_health_factor = int.from_bytes(account_data[-32:], "big")
            if raw_health_factor == MAX_UINT256:
                health_factors.append(-1)
            else:
                health_factors.append(raw_health_factor / 1e18)

        return health_factors

    def check_health_factors(self) -> None:
        """
        1. Get all accounts from the DB that belong to this chain and their threshold health factors.
        2. Check health factor of all these accounts.
        3. Check the health factors against the thresholds and send notifications if needed.
        """
        logging.info(f'Checking health factors on {self.chain.name} x Aave V{self.aave_version}')
        all_accounts = self.database.get_accounts_for_hf_check(self.chain, self.aave_version)
        health_factors: list[float] = []
        for batch in make_batches(all_accounts, HEALTH_FACTOR_BATCH_SIZE):
            health_factors += self.get_health_factors(batch)

        logging.info(f'Got {len(health_factors)} health factors on {self.chain.name} x Aave V{self.aave_version}')
        for account, health_factor in zip(all_accounts, health_factors):
            if health_factor < account.health_factor_threshold and health_factor != -1:
                message = f'Health factor on your account {str(self.chain)} {account.account.address} is {health_factor:.2f} which is below the threshold of {account.health_factor_threshold}.'
                self.notifier.notify_about_health_factor(account=account, message=message)

    async def monitor_health_factor(self) -> None:
        """Periodically check health factor of all accounts on this chain"""
        while True:
            try:
                self.check_health_factors()
            except Exception:
                await send_admin_message('Critical error!')
                logging.error(f'Error while checking health factors on {self.chain.name} x Aave V{self.aave_version}: {traceback.format_exc()}')

            await asyncio.sleep(HEALTH_FACTOR_CHECK_PERIOD)

    def catchup_on_liquidations(self) -> None:
        """Catchup on liquidations that occured while the program was not running"""
        logging.info(f'Checking for liquidations on {self.chain.name} x Aave V{self.aave_version}')
        setting_key = f'LAST_{self.chain.name}_V{self.aave_version}_CHECKED_BLOCK'
        last_checked_block_raw = self.database.get_setting(setting_key)
        current_block = self.web3.eth.block_number - 1  # Doing -1 because it may be that the current block is not confirmed yet on Avalanche.
        if last_checked_block_raw is None:
            logging.info(f'No last checked block found. But we set {setting_key} to {current_block}')
            return  # Cant do anything. No state saved.

        logging.info(f'Checking liquidations from block {last_checked_block_raw} to {current_block} on {self.chain.name} x Aave V{self.aave_version}')
        last_checked_block = int(last_checked_block_raw)
        logs = []
        for from_block in range(last_checked_block, current_block, MAX_BLOCK_RANGE):
            logs += self.web3.eth.get_logs({
                'address': self.pool_address,
                'topics': [LIQUIDATION_TOPIC],
                'fromBlock': from_block,
                'toBlock': min(current_block, from_block + MAX_BLOCK_RANGE),
            })
        logging.info(f'Found {len(logs)} liquidations on {self.chain.name} x Aave V{self.aave_version}')
        for log in logs:
            self.process_liquidation_log(log)

        self.database.set_setting(setting_key, str(current_block))

    def process_liquidation_log(self, log: LogReceipt) -> None:
        """Process a single aave liquidation log and send a notification if the liquidated account is tracked."""
        collateral_token_address = topic_to_address(log['topics'][1])
        debt_token_address = topic_to_address(log['topics'][2])
        user = topic_to_address(log['topics'][3])

        account = ChainAccount(
            address=user,
            chain=self.chain,
            aave_version=self.aave_version,
        )
        if not self.database.is_tracked(account):
            logging.info(f'The liquidated address {user} is not being tracked on {self.chain.name} x Aave V{self.aave_version}. Skipping.')
            return

        logging.info(f'The liquidated address {user} is being tracked on {self.chain.name} x Aave V{self.aave_version}! Querying data for the notification.')
        covered_debt_amount_raw = int(log['data'][:32].hex(), 16)
        liquidated_collateral_amount_raw = int(log['data'][32:64].hex(), 16)

        collateral_token_symbol = self.web3.eth.contract(address=collateral_token_address, abi=self.erc20_abi).functions.symbol().call()  # type: ignore[call-overload]
        collateral_token_decimals = self.web3.eth.contract(address=collateral_token_address, abi=self.erc20_abi).functions.decimals().call()  # type: ignore[call-overload]
        liquidated_collateral_amount = liquidated_collateral_amount_raw / 10 ** collateral_token_decimals

        debt_token_symbol = self.web3.eth.contract(address=debt_token_address, abi=self.erc20_abi).functions.symbol().call()  # type: ignore[call-overload]
        debt_token_decimals = self.web3.eth.contract(address=debt_token_address, abi=self.erc20_abi).functions.decimals().call()  # type: ignore[call-overload]
        covered_debt_amount = covered_debt_amount_raw / 10 ** debt_token_decimals

        logging.info(f'Queried data for the liquidation of {user} on {self.chain.name} x Aave V{self.aave_version}. Sending the notification!')
        message = f'Your account {user} on chain {self.chain.name} was liquidated. {collateral_token_symbol} {liquidated_collateral_amount} was liquidated to cover {debt_token_symbol} {covered_debt_amount} debt.'
        self.notifier.notify_about_liquidation(chain_account=account, title='Liquidation occured!', message=message)

    async def monitor_liquidations(self):
        """Periodically check liquidations on this chain"""
        while True:
            try:
                self.catchup_on_liquidations()
            except Exception:
                await send_admin_message('Critical error!')
                logging.error(f'Error while catching up on liquidations on {self.chain.name} x Aave V{self.aave_version}: {traceback.format_exc()}')
            await asyncio.sleep(LIQUIDATIONS_CHECK_PERIOD)


from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError

from newspaper.models import Newspaper, Redactor

class NewspaperForm(forms.ModelForm):
    publishers = forms.ModelMultipleChoiceField(
        queryset=get_user_model().objects.all(),
        widget=forms.CheckboxSelectMultiple,
    )

    class Meta:
        model = Newspaper
        fields = "__all__"

class RedactorCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = Redactor
        fields = UserCreationForm.Meta.fields + (
            "years_of_experience",
            "first_name",
            "last_name",
        )

    def clean_experience(self):
        return validate_experience(self.cleaned_data["years_of_experience"])

class RedactorExperienceUpdateForm(forms.ModelForm):
    class Meta:
        model = Redactor
        fields = ["years_of_experience"]

    def clean_experience(self):
        return validate_experience(self.cleaned_data["years_of_experience"])

def validate_experience(
    years_of_experience,
):
    if years_of_experience > 80:
        raise ValidationError("Years of experience should be less than 80")

    return years_of_experience

class RedactorSearchForm(forms.Form):
    username = forms.CharField(
        max_length=100,
        required=False,
        label="",
        widget=forms.TextInput(attrs={"placeholder": "Search by username"})
    )

class NewspaperSearchForm(forms.Form):
    title = forms.CharField(
        max_length=100,
        required=False,
        label="",
        widget=forms.TextInput(attrs={"placeholder": "Search by title"})
    )

class TopicSearchForm(forms.Form):
    name = forms.CharField(
        max_length=100,
        required=False,
        label="",
        widget=forms.TextInput(
            attrs={"placeholder": "Search by topic name"}
        )
    )


"""Provide class model for named venv virtual environments."""

from .. import const
from .venv import VenvEnvironment

####################

class NamedVenvEnvironment(VenvEnvironment):
    """
    Model a named Python3 `venv`:py:mod: virtual environment.

    Args:
        env_prefix
            The path to a directory in which to create the virtual environment
            (required).

    See Also:
        base/parent class
    """

    def __init__(self, *args, **kwargs):
        super(NamedVenvEnvironment, self).__init__(*args, **kwargs)

        if not self.have_env_prefix():
            raise ValueError(
                "The 'env_prefix' argument is required and must not be None"
            )

    @property
    def need_setup_py(self):
        """Tell whether a setup.py is necessary."""
        return True  # We always need it for constructing env_name

    @property
    def env_name(self):
        """Get the name for this environment."""
        if self._env_name is None:
            self._env_name = self.basename
            if self.requirements.is_dev():
                self._env_name += const.DEV_SUFFIX
        return self._env_name


from django.http import HttpResponse

from fb_post.exceptions.custom_exceptions import InvalidPostException
from fb_post.interactors.presenter_interfaces.dtos import GetPostResponseDto
from fb_post.interactors.presenter_interfaces.presenter_interface_get_post import \
    PresenterInterfaceGetPost
from fb_post.interactors.storage_interfaces.comment_storage_interface import \
    CommentStorageInterface
from fb_post.interactors.storage_interfaces.dtos import GetPostParametersDto
from fb_post.interactors.storage_interfaces.post_storage_interface import \
    PostStorageInterface
from fb_post.interactors.storage_interfaces.reaction_storage_interface import \
    ReactionStorageInterface
from fb_post.adapters.service_adapter import get_service_adapter

class GetPostInteractor:
    def __init__(self, post_storage: PostStorageInterface,
                 comment_storage: CommentStorageInterface,
                 reaction_storage: ReactionStorageInterface,
                 presenter: PresenterInterfaceGetPost):
        self.post_storage = post_storage
        self.comment_storage = comment_storage
        self.reaction_storage = reaction_storage
        self.presenter = presenter

    def get_post_wrapper(self, post_id: int) -> HttpResponse:
        try:
            response_dto = self.get_post(post_id)
            return self.presenter.get_success_get_post_response(response_dto)
        except InvalidPostException:
            return self.presenter.get_invalid_get_post_response()

    def get_post(self, post_id: int) -> GetPostResponseDto:
        self._validate_post_id(post_id)

        post_dto = self.post_storage.get_post_details(post_id=post_id)

        comments_on_post_dtos = self.comment_storage.get_comments_on_post(
            post_dto.post_id)

        comment_ids = []
        commenter_ids_list = []
        for comments_on_post_dto in comments_on_post_dtos:
            comment_ids.append(comments_on_post_dto.comment_id)
            commenter_ids_list.append(comments_on_post_dto.commented_by_id)

        user_ids = commenter_ids_list
        user_ids.append(post_dto.posted_by_id)

        replies_dtos = self.comment_storage.get_replies_dtos(comment_ids)

        for replies_dto in replies_dtos:
            comment_ids.append(replies_dto.comment_id)
            user_ids.append(
                replies_dto.commented_by_id)
        adapter = get_service_adapter()
        user_dtos = adapter.fb_post_auth.get_user_dtos(user_ids=user_ids)
        reactions_on_post_dtos = self.reaction_storage.get_reactions_on_post(
            post_id=post_id)
        reactions_on_comments_dtos = self.reaction_storage.get_reactions_on_comments(
            comment_ids=comment_ids)

        response_dto = GetPostResponseDto(
            post_dto=post_dto,
            user_dtos=user_dtos,
            comment_dtos=comments_on_post_dtos,
            reply_dtos=replies_dtos,
            reactions_on_post_dtos=reactions_on_post_dtos,
            reactions_on_comments_dtos=reactions_on_comments_dtos
        )

        return response_dto

    def _validate_post_id(self, post_id: int) -> None:
        is_post_not_exists = not self.post_storage.is_post_exists(post_id)
        if is_post_not_exists:
            raise InvalidPostException


# -*- coding: utf-8 -*-
import torch
from tqdm import tqdm

from .base import SolverBase

class RK4(SolverBase):

    def __init__(self, func, t0, t1, dt, y0, *args, **kwargs):
        super(RK4, self).__init__(func, t0, t1, dt, y0, *args, **kwargs)

    def step(self, func, t0, y0, dt, *args, **kwargs):
        k1 = dt * func(t0, y0)
        k2 = dt * func(t0 + 0.5 * dt, y0 + 0.5 * k1)
        k3 = dt * func(t0 + 0.5 * dt, y0 + 0.5 * k2)
        k4 = dt * func(t0 + dt, y0 + k3)
        y1 = y0 + (k1 + k2 * 2 + k3 * 2 + k4) / 6
        return y1

class RK4_high_order(SolverBase):
    """
    仅限于输出为q_ori, dq_ori, lam的情况
    """

    def __init__(self,  *args, **kwargs):
        super(RK4_high_order, self)

    def step_with_lam(self, func, t0, y0, dt, dof, *args, **kwargs):
        q_ori, dq_ori, lam = torch.tensor_split(y0, (dof, dof * 2), dim=-1)

        k1 = q_ori
        dk1 = dq_ori
        dqddqlam = func(t0, torch.cat([k1, dk1, lam], dim=-1))
        dq, ddk1, lam = torch.tensor_split(dqddqlam, (dof, dof * 2), dim=-1)

        k2 = k1 + 0.5 * dt * dk1
        dk2 = dk1 + 0.5 * dt * ddk1
        dqddqlam = func(t0, torch.cat([k2, dk2, lam], dim=-1))
        dq, ddk2, lam = torch.tensor_split(dqddqlam, (dof, dof * 2), dim=-1)

        k3 = k1 + 0.5 * dt * dk2
        dk3 = dk1 + 0.5 * dt * ddk2
        dqddqlam = func(t0, torch.cat([k3, dk3, lam], dim=-1))
        dq, ddk3, lam = torch.tensor_split(dqddqlam, (dof, dof * 2), dim=-1)

        k4 = k1 + dt * dk3
        dk4 = dk1 + dt * ddk3
        dqddqlam = func(t0, torch.cat([k4, dk4, lam], dim=-1))
        dq, ddk4, lam = torch.tensor_split(dqddqlam, (dof, dof * 2), dim=-1)

        q_next = k1 + dt * dk1 + (dt ** 2) / 6 * (ddk1 + ddk2 + ddk3)
        dq_next = dk1 + dt / 6 * (ddk1 + 2 * ddk2 + 2 * ddk3 + ddk4)

        return torch.cat([q_next, dq_next, lam], dim=-1)

    def step(self, func, t0, y0, dt, *args, **kwargs):
        q_ori, dq_ori = torch.chunk(y0, 2, dim=-1)

        k1 = q_ori
        dk1 = dq_ori
        dqddq = func(t0, torch.cat([k1, dk1], dim=-1))
        dq, ddk1 = torch.chunk(y0, 2, dim=-1)

        k2 = k1 + 0.5 * dt * dk1
        dk2 = dk1 + 0.5 * dt * ddk1
        dqddq = func(t0, torch.cat([k2, dk2], dim=-1))
        dq, ddk2 = torch.chunk(dqddq, 2, dim=-1)

        k3 = k1 + 0.5 * dt * dk2
        dk3 = dk1 + 0.5 * dt * ddk2
        dqddq = func(t0, torch.cat([k3, dk3], dim=-1))
        dq, ddk3 = torch.chunk(dqddq, 2, dim=-1)

        k4 = k1 + dt * dk3
        dk4 = dk1 + dt * ddk3
        dqddq = func(t0, torch.cat([k4, dk4], dim=-1))
        dq, ddk4 = torch.chunk(dqddq, 2, dim=-1)

        q_next = k1 + dt * dk1 + (dt ** 2) / 6 * (ddk1 + ddk2 + ddk3)
        dq_next = dk1 + dt / 6 * (ddk1 + 2 * ddk2 + 2 * ddk3 + ddk4)

        return torch.cat([q_next, dq_next], dim=-1)

    def solve(self, func, t, y0, dt, *args, **kwargs):
        sol = torch.empty(len(t), *y0.shape, device=self.device, dtype=self.dtype)
        sol[0] = y0

        pbar = tqdm(range(len(self.t) - 1), desc='solving ODE...')
        for idx in pbar:
            temp = self.step_with_lam(self.func, self.t[idx], sol[idx], self.dt, *args, **kwargs)
            if sum((temp[0, 0:3] - temp[0, 15:18]) * (temp[0, 12:15] - temp[0, 3:6])) < 0:  # 16与52的夹角
                print('stop time is ', self.t[idx].cpu().detach().numpy())
                sol = sol[:idx + 1]
                t = t[:idx + 1]
                break
            else:
                sol[idx + 1] = temp
        sol = sol.permute(1, 0, 2)
        return t, sol


import numpy as np
from scipy import linalg

# Not working...
def rsvdpi(a, k, p, s):
    n, m = np.shape(a)
    O = np.random.randn(m, k + s)
    Q = np.dot(a, O)
    for i in range(p+1):
        if i < p:
            P, L, U = linalg.lu(Q)
            Q = np.dot(P.T, L)
        else:
            Q = eigsvd(Q)[0]
        Q = np.dot(a, np.dot(a.T, Q))
    b = np.dot(Q.T, a)
    V, S, U = eigsvd(b.T)
    ind = np.arange(s, k+s)
    return np.dot(Q, U[:, ind]), np.diag(S)[ind, ind], V[:, ind]

def rsvd(a, k, p, s):
    n, m = np.shape(a)
    O = np.random.randn(m, k + s)
    Q = linalg.orth(np.dot(a, O))
    for i in range(p):
        G = linalg.orth(np.dot(a.T, Q))
        Q = linalg.orth(np.dot(a, G))
    b = np.dot(Q.T, a)
    u, s, v = eigsvd(b)
    u = np.dot(Q, u)
    return u[:, :k], s[:k], v[:, :k]

def eigsvd(a):
    transposeflag = None
    if np.size(a, axis=0) < np.size(a, axis=1):
        transposeflag = True
        a = a.T
    b = np.dot(a.T, a)
    eval, v = np.linalg.eig(b)
    v = v[:, np.argsort(-eval)]
    eval = eval[np.argsort(-eval)]
    s = np.sqrt(eval)
    u = np.dot(np.dot(a, v), np.diag(1/s))
    if transposeflag:
        u = v.T
        v = u.T
    return u, s, v


import time
from pages.login_page import Login_page
from pages.product_page import Product_page
from pages.cart_page import Cart_page
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.firefox.service import Service as FirefoxService
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
import random
import allure

chrome_options = Options()
chrome_options.add_argument("--ignore-certificate-errors")
chrome_options.add_argument("--ignore-certificate-errors-spki-list")
chrome_options.add_argument("--disable-notifications")
chrome_options.add_argument("--start-maximized")
# chrome_options.add_argument("--disable-infobars")
# chrome_options.add_argument("--disable-extensions")
# chrome_options.add_argument("--no-sandbox")
# chrome_options.add_argument("--disable-dev-shm-usage")

# для безголового режима
chrome_options.add_argument("--window-size=1920,1080")
#chrome_options.add_argument("--headless=new")

driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=chrome_options)
#driver = webdriver.Firefox(service=FirefoxService(GeckoDriverManager().install()))

@allure.description('Добавление товаров в корзину')
def test_add_products_to_cart():
    """
    Добавляем в корзину случайное количество смартфонов в случайном порядке
    :return:
    Сравниваем список добавленных со списком находящихся в корзине
    """
    random.seed()
    login_page = Login_page(driver)
    login_page.location_window_close()
    print('\nВыбор каталога..')
    ActionChains(driver).move_to_element(login_page.button_catalog).perform()
    ActionChains(driver).click().perform()
    print('Переход к смартфонам..')
    ActionChains(driver).move_to_element(login_page.catalog_smf_gadget).perform()
    ActionChains(driver).move_to_element(login_page.product_cmf).perform()
    ActionChains(driver).click().perform()
    product_page = Product_page(driver)

    print('Активация фильтра по брендам..')
    product_page.select_brand(['Apple', 'Honor', 'Samsung'])
    time.sleep(1)
    # переключаем сетку товаров на список
    product_page.switch_list_grid()
    time.sleep(1)

    # список товаров
    products = product_page.get_products()
    print('Найдено активных карт товара:', len(products))
    # добавляем случайное число товаров в корзину в случайном порядке
    items_count_to_cart = random.randint(1, len(products)-1)
    print(f'Выбрано для добавления в корзину: {items_count_to_cart} карт товара')
    random.shuffle(products)
    for item in range(items_count_to_cart):
        product_page.put_to_cart(products[item][2], True)
        print(f'Добавление карты товара: {products[item][0]}, {products[item][1]}')
    #product_page.wait_until_all_item_loaded()

    item_list = set()
    for item in products[:items_count_to_cart]:
        item_list.add(item[0])

    print('Переход в корзину..')
    product_page.go_to_cart()
    assert product_page.get_current_url() == 'https://www.mvideo.ru/cart'
    print('OK')
    cart = Cart_page(driver)
    print('Определение карт товаров в корзине..')
    product_in_cart = set(cart.get_cart_item())
    # проверяем является ли множество добавленных товаров подмножеством товаров в корзине
    assert item_list.issubset(product_in_cart), '! Не все добавленные товары есть в корзине'
    print('OK.. Все добавленные товары есть в корзине')


import logging
import pytest

from mos_tests.functions.common import wait

logger = logging.getLogger(__name__)

def run_and_check_job(sahara, template_id, cluster_id, input_id, output_id):
    def is_job_succeeded(job_id):
        job = sahara.job_executions.get(job_id)
        assert job.info['status'] not in ['KILLED', 'FAILED'], (
            "job is {0}".format(job.info['status']))
        return job.info['status'] == 'SUCCEEDED'

    logger.info('Execute job on existing cluster')
    job = sahara.job_executions.create(job_id=template_id,
                                       cluster_id=cluster_id,
                                       input_id=input_id,
                                       output_id=output_id)
    wait(lambda: is_job_succeeded(job.id), timeout_seconds=10 * 60,
         sleep_seconds=10, waiting_for='job success')

@pytest.mark.check_env_('is_sahara_enabled')
@pytest.mark.testrail_id('1295481')
def test_restart_all_sahara_services(env, data_sources, cluster, job_template,
                                     sahara):
    """Restart all Sahara services

    Scenario:
        1. Register vanilla 2.7.1 image for sahara
        2. Create vanilla cluster based on default template for vanilla
        3. Create job template and run job on cluster
        4. Check that job is finished successfully
        5. Restart sahara services on controllers
        6. Re-run job and check that it's finished successfully again
    """

    input_id, output_id1, output_id2 = data_sources
    run_and_check_job(sahara, job_template, cluster, input_id, output_id1)

    for node in env.get_nodes_by_role('controller'):
        with node.ssh() as remote:
            remote.check_call("service sahara-api restart && "
                              "service sahara-engine restart")

    run_and_check_job(sahara, job_template, cluster, input_id, output_id2)


def solution(n):
    answer = []
    i = 2
    while True :
        if n == 1:
            break
        if n % i == 0:
            answer.append(i)
            n = n // i
        else :
            i +=1
    return list(dict.fromkeys(answer))


import argparse
import pandas
from mypyli import picrust

def all_by_all_correlation(table_f, out):

    # calculate using lower triangular algorithm
    ttm = picrust.TraitTableManager(table_f)
    correlations = {}
    names = []
    for ent1 in ttm:
        names.append(ent1.name)
        for ent2 in ttm:
            if ent1 == ent2:
                continue

            cor = ent1.correlation(ent2, traits=ttm.traits)
            correlations[ent1.name + ">" + ent2.name] = str(cor)

    # write as a square
    with open(out, 'w') as OUT:
        OUT.write("\t".join(["names"] + names) + "\n")

        for n1 in names:
            to_write = [n1]
            for n2 in names:
                try:
                    to_write.append(correlations[n1 + ">" + n2])
                except KeyError:
                    to_write.append(correlations[n2 + ">" + n1])

            OUT.write("\t".join(to_write)+ "\n")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="calculates correlations between entries in PICRUSt trait tables")
    parser.add_argument("-table", help="PICRUSt trait table", required=True)
    parser.add_argument("-out", help="output path for the correlations")

    args = parser.parse_args()

    all_by_all_correlation(args.table, args.out)


import os
import platform
import shutil
from pathlib import Path
from typing import List
import docker
from docker.types import Mount
from datetime import datetime
import hashlib

from aws_cdk import aws_lambda
from aws_cdk.core import BundlingOptions, DockerVolume, DockerVolumeConsistency

# pylint: disable=print-used
def timeit(method):

    def timed(*args, **kw):
        t_start = datetime.now()
        result = method(*args, **kw)
        t_end = datetime.now()
        print(f'{method.__name__} - Total time = {(t_end - t_start).total_seconds()} seconds')
        return result

    return timed

class BuildLambdaAsset:

    def __init__(self, include_paths: List[str], build_dir: Path, cache_dir: Path = None, requirements_txt: Path = Path('requirements.txt'),
                 consume_dependencies: bool = None, verbose: bool = False) -> None:
        self._include_paths = include_paths
        self._build_dir: Path = build_dir
        self._cache_dir: Path = cache_dir if cache_dir is not None else Path.home() / ".everest-pip-cache"
        self._requirements_txt: Path = requirements_txt
        self._req_md5_file: Path = Path(str(requirements_txt) + '.md5')
        self._consume_dependencies = consume_dependencies
        self._verbose = verbose

    @timeit
    def build(self):
        md5_sum: str = None
        if self._consume_dependencies is None:
            prev_md5_sum: str = self._req_md5_file.read_text() if self._req_md5_file.is_file() else ''
            md5_sum = hashlib.md5(self._requirements_txt.read_bytes()).hexdigest()
            self._consume_dependencies = prev_md5_sum != md5_sum
        self._clean_build_target()
        self._copy_resources()
        if self._consume_dependencies:
            self._consume()
        if md5_sum is not None:
            self._req_md5_file.write_text(md5_sum)

    def _clean_build_target(self):
        if self._consume_dependencies:
            if self._req_md5_file.is_file():
                self._req_md5_file.unlink()
            shutil.rmtree(self._build_dir, ignore_errors=True)
            self._build_dir.mkdir(parents=True, exist_ok=True)
            self._cache_dir.mkdir(parents=True, exist_ok=True)
        else:
            for include_path in self._include_paths:
                shutil.rmtree(self._build_dir / os.path.basename(os.path.normpath(include_path)), ignore_errors=True)

    def _copy_resources(self):
        print('Copying \'include\' resources:')
        for include_path in self._include_paths:
            print(f'    -  {(Path.cwd() / include_path).resolve()}')
            shutil.copytree(include_path, (self._build_dir / os.path.basename(os.path.normpath(include_path))).as_posix())
        shutil.copy(self._requirements_txt.as_posix(), (self._build_dir / 'requirements.txt').as_posix())

    def _consume(self) -> None:
        if platform.system().lower() == 'linux':
            self._consume_natively()
        else:
            self._consume_using_docker()

    @timeit
    def _consume_natively(self) -> None:
        """
        Build lambda dependencies natively on linux. Should be the same architecture though.
        """
        print('Installing lambda runtime dependencies on Linux')
        if os.system(f"python -m pip install --target {self._build_dir} --requirement {self._requirements_txt}") != 0:
            raise Exception('Cloud not resolve lambda runtime dependencies')
        print('Finish to install lambda runtime dependencies')

    @timeit
    def _consume_using_docker(self) -> None:
        """
        Build lambda dependencies in a container as-close-as-possible to the actual runtime environment.
        """
        print('Installing dependencies [running in Docker]...')
        client = docker.from_env()
        client.images.pull(repository='amazon/aws-sam-cli-build-image-python3.8', tag='latest')
        # pylint: disable=bad-option-value
        container = client.containers.run(
            image='amazon/aws-sam-cli-build-image-python3.8:latest',
            command="/bin/sh -c 'python3.8 -m pip install --target /var/task/ --requirement /var/task/requirements.txt && "
            "find /var/task -name \\*.so -exec strip \\{\\} \\;'",
            auto_remove=True,
            mounts=[
                Mount(target="/var/task", source=self._build_dir.as_posix(), type="bind", consistency="delegated"),
                Mount(target="/root/.cache", source=self._cache_dir.as_posix(), type="bind", consistency="delegated"),
                #Mount(target="/root/.netrc", source=f"{str(Path.home())}/.netrc", type="bind", consistency="delegated", read_only=True)
            ],
            user=0,
            detach=True,
        )
        try:
            if self._verbose:
                for log in container.logs(stream=True, follow=True):
                    print(log.decode('utf-8'), end='')
            else:
                container.wait()
        finally:  # handle Ctrl-C or other interruptions: kill the container
            try:
                container.kill()
            except (docker.errors.NotFound, docker.errors.APIError):
                pass  # container has already exited, was already deleted, etc.


import argparse
from os import path
import warnings
import glob
import os

from PIL import Image, ImageDraw
from tqdm import tqdm

from segmentation.model_builder import ModelBuilderLoad
from segmentation.network import EnsemblePredictor
from segmentation.network_postprocessor import NetworkMaskPostProcessor, NetworkBaselinePostProcessor
from segmentation.preprocessing.source_image import SourceImage
from segmentation.scripts.train import get_default_device

warnings.simplefilter(action='ignore', category=FutureWarning)
import itertools
import numpy as np

def dir_path(string):
    if path.isdir(string):
        return string
    else:
        raise NotADirectoryError(string)

def scale_baselines(baselines, scale_factor=1.0):
    if baselines is not None:
        for b_idx, bline in enumerate(baselines):
            for c_idx, coord in enumerate(bline):
                coord = (int(coord[0] * scale_factor), int(coord[1] * scale_factor))
                baselines[b_idx][c_idx] = coord

class Ensemble:
    def __init__(self, models):
        self.models = models

    def __call__(self, x, scale_area, additional_scale_factor=None):
        res = []
        scale_factor = None
        for m in self.models:
            p_map, s_factor = m.predict_single_image_by_path(x, rgb=True, preprocessing=True, scale_area=scale_area,
                                                             additional_scale_factor=additional_scale_factor)
            scale_factor = s_factor
            res.append(p_map)
        if len(res) == 1:
            return res[0], scale_factor
        res = np.stack(res, axis=0)
        return np.mean(res, axis=0), scale_factor

def main():
    colors = [(255, 0, 0),
              (0, 255, 0),
              (0, 0, 255),
              (255, 255, 0),
              (0, 255, 255),
              (255, 0, 255)]
    parser = argparse.ArgumentParser()
    parser.add_argument("--load", type=str, nargs="*", default=[],
                        help="load models and use it for inference (specify .torch file)")
    parser.add_argument("--image_path", type=str, nargs="*", default=[], help="load models and use it for inference")
    parser.add_argument("--scale_area", action="store_true", help="Enable image scaling")
    parser.add_argument("--scale_area_size", type=int, help="max pixel amount of an image")

    parser.add_argument("--output_xml", action="store_true", help="Outputs Xml Files")
    parser.add_argument("--output_xml_path", type=str, default=None, help="Directory of the XML output")
    parser.add_argument("--mode", choices=["xml_baseline", "xml_region", "mask"], required=True)

    parser.add_argument("--max_line_height", type=int, default=None,
                        help="If the average line_height of an document is bigger then the specified value, "
                             "the document is scaled down an processed again on the new resolution. "
                             "Proposed Value == 22")
    parser.add_argument("--min_line_height", type=int, default=None,
                        help="If the average line_height of an document is smaller then the specified value, "
                             "the document is scaled up an processed again on the new resolution")
    parser.add_argument("-d", "--device", type=str, default=get_default_device())
    parser.add_argument("--tta", action="store_true", help="Use predefined Tta-pipeline")
    parser.add_argument("--dewarp", action="store_true", help="Dewarp image using the detected baselines")
    parser.add_argument("--show_result", action="store_true")
    parser.add_argument("--output_path_debug_images", type=str, default=None, help="Directory of the debug images")

    parser.add_argument("--processes", type=int, default=8)

    args = parser.parse_args()
    image_list = sorted(itertools.chain.from_iterable([glob.glob(x) for x in args.image_path]))
    base_model_files = [ModelBuilderLoad.from_disk(model_weights=i, device=args.device) for i in args.load]
    base_models = [i.get_model() for i in base_model_files]
    base_configs = [i.get_model_configuration() for i in base_model_files]
    preprocessing_settings = [i.get_model_configuration().preprocessing_settings for i in base_model_files]
    if args.scale_area:
        for i in preprocessing_settings:
            i.scale_max_area = args.scale_area_size
            i.scale_predict = args.scale_area

    predictor = EnsemblePredictor(base_models, preprocessing_settings)
    config = base_configs[0]

    if args.mode == "mask" or args.mode == "xml_region":
        nmaskpred = NetworkMaskPostProcessor(predictor, config.color_map)
        for img_path in tqdm(image_list):
            simg = SourceImage.load(img_path)
            mask = nmaskpred.predict_image(simg)
            if args.show_result:
                mask.generated_mask.show()
            if args.output_path_debug_images:
                basename = "debug_" + os.path.basename(img_path)
                file_path = os.path.join(args.output_path_debug_images, basename)
                mask.generated_mask.save(file_path)

    if args.mode == "xml_baseline":
        nbaselinepred = NetworkBaselinePostProcessor(predictor, config.color_map)
        for img_path in tqdm(image_list):
            simg = SourceImage.load(img_path)
            simg.pil_image = simg.pil_image.convert('RGB')
            draw = ImageDraw.Draw(simg.pil_image)

            result = nbaselinepred.predict_image(simg)
            for ind, x in enumerate(result.base_lines):

                t = list(itertools.chain.from_iterable(x))
                a = t[::]
                if args.show_result:
                    draw.line(a, fill=colors[ind % len(colors)], width=4)
            if args.output_path_debug_images:
                basename = "debug_" + os.path.basename(img_path)
                file_path = os.path.join(args.output_path_debug_images, basename)
                simg.pil_image.save(file_path)

            if args.output_xml and args.output_xml_path is not None:
                from segmentation.gui.xml_util import TextRegion, BaseLine, TextLine, XMLGenerator
                regions = []
                if result.base_lines is not None:
                    text_lines = []
                    for b_line in result.base_lines:
                        text_lines.append(TextLine(coords=b_line + list(reversed(b_line)), baseline=BaseLine(b_line)))
                    regions.append(TextRegion(text_lines, coords=b_line + list(reversed(b_line))))

                xml_gen = XMLGenerator(simg.get_width(),simg.get_height(), os.path.basename(img_path), regions=regions)
                xml_gen.save_textregions_as_xml(args.output_xml_path)

if __name__ == "__main__":
    main()


"""Shuttle Search"""
from functools import reduce

with open('../inputs/day13.txt', 'r') as f:
    lines = f.readlines()
    earliest = int(lines[0])
    buses = []
    for idx, x in enumerate(lines[1].split(',')):
        if x.isnumeric():
            buses.append((int(x), idx))

wait = 0
found = False
while not found:
    for bus in buses:
        bus_id, pos = bus
        if isinstance(bus_id, int):
            if (earliest+wait) % bus_id == 0:
                print(f"answer to puzzle 1 is {wait * bus_id}")
                found = True
    wait += 1

# following methods found online.
# chinese remainder theorem for solving
# systems of linear congruent equations.
def chinese_remainder(n, a):
    _sum = 0
    prod = reduce(lambda a, b: a * b, n)
    for n_i, a_i in zip(n, a):
        p = prod // n_i
        _sum += a_i * mul_inv(p, n_i) * p
    return _sum % prod

def mul_inv(a, b):
    b0 = b
    x0, x1 = 0, 1
    if b == 1:
        return 1
    while a > 1:
        q = a // b
        a, b = b, a % b
        x0, x1 = x1 - q * x0, x0
    if x1 < 0:
        x1 += b0
    return x1

modulos = [x[0] for x in buses]
remainders = [x[0]-x[1] for x in buses]
remainders[0] = 0
print(f"answer to puzzle 2 is {chinese_remainder(modulos, remainders)}")


# examples of recursive
# SUPERDIGIT
# superdigit is the number itself if it has one digit
# otherwise is the sum of the digits in the number
# ex. 9875 = 9 + 8 +7 +5 = 29 = 2 + 9 = 11 = 1 + 1 = 2 So 2 is the superdigit of 9875

def superDigit(number):

    split_number = list(str(number))
    if len(split_number) == 1:
        return split_number[0]

    else:
        ch_sum = 0
        for ch in split_number:
            ch_sum += int(ch)

    return superDigit(ch_sum)

my_number = 9875
result = superDigit(my_number)
print(result)


import argparse
import sys

if sys.version_info >= (3, 9):
  List = list
else:
  from typing import List

from pathlib import Path
from typing import Optional

from .command_base import BaseCommand
from .command_base import BaseCommandExecutor

from .encoding import has_bom

from .gettext_tools import compile_translations
from .gettext_tools import validate_gettext_tools_exist

from .paths import get_names_of_immediate_subdirectories
from .paths import make_messages_dir_path
from .paths import make_mo_file_path

from .text import flatten_comma_separated_values
from .text import stringify_path

from .utils import halt
from .utils import print_err
from .utils import print_out
from .utils import show_usage_error_and_halt

from . import defaults

class CompileCommandExecutor(BaseCommandExecutor):

  def __init__(self, args=argparse.Namespace) -> None:
    self._locales_dir_path = self._handle_locales_dir_path(args.locales_dir)
    self._validate_locales_dir_path(self._locales_dir_path)

    self._locales = self._handle_locales(
      locales=args.locale,
      locales_dir_path=self._locales_dir_path,
    )
    self._validate_locales(
      locales=self._locales,
      locales_dir_path=self._locales_dir_path,
    )

    self._exclude = set(flatten_comma_separated_values(args.exclude))

    self._fuzzy = args.fuzzy

    self._msgfmt_extra_args = flatten_comma_separated_values(args.msgfmt_extra_args)
    self._verbose = args.verbose

  @staticmethod
  def _handle_locales_dir_path(path: str) -> Path:
    return Path(path).absolute()

  @staticmethod
  def _validate_locales_dir_path(path: Path) -> None:
    if not path.exists():
      print_err(f"locales dir does not exist (path={stringify_path(path)}")
      show_usage_error_and_halt()

    if not path.is_dir():
      print_err(f"locales dir is not a directory (path={stringify_path(path)})")
      show_usage_error_and_halt()

  @staticmethod
  def _handle_locales(
    locales: Optional[List[str]],
    locales_dir_path: Path,
  ) -> List[str]:

    if locales:
      return flatten_comma_separated_values(locales)

    return get_names_of_immediate_subdirectories(locales_dir_path)

  @staticmethod
  def _validate_locales(
    locales: List[str],
    locales_dir_path: Path,
  ) -> None:
    if not locales:
      print_err(
        "specify at least 1 locale or specify processing of all existing locales"
      )
      show_usage_error_and_halt()

    for locale in locales:
      path = make_messages_dir_path(locales_dir_path, locale)
      if not (path.exists() and path.is_dir()):
        print_err(
          f"invalid locale '{locale}': "
          f"directory '{stringify_path(path)}' expected to exist"
        )
        show_usage_error_and_halt()

  def __call__(self) -> None:
    validate_gettext_tools_exist()

    if self._verbose:
      self._print_input_args(
        locales_dir_path=stringify_path(self._locales_dir_path),
        locales=self._locales,
        fuzzy=self._fuzzy,
        msgfmt_extra_args=self._msgfmt_extra_args,
        verbose=self._verbose,
      )

    final_locales = sorted(set(self._locales) - self._exclude)

    for locale in final_locales:
      self._process_locale(locale=locale)

  def _process_locale(self, locale: str) -> None:
    if self._verbose:
      print_out(f"processing locale '{locale}'")

    messages_dir_path = make_messages_dir_path(self._locales_dir_path, locale)

    for path in messages_dir_path.iterdir():
      if path.is_file() and path.suffix == ".po":
        self._process_translations_file(file_path=path)

  def _process_translations_file(self, file_path: Path) -> None:
    if self._verbose:
      print_out(f"processing file '{stringify_path(file_path)}'")

    if has_bom(file_path):
      print_err(
        f"the file '{stringify_path(file_path)}' file has a BOM (Byte Order Mark). "
        f"Verboselib supports only '.po' files encoded in UTF-8 and without any BOM."
      )
      halt()

    mo_file_path = make_mo_file_path(file_path)

    compile_translations(
      mo_file_path=mo_file_path,
      po_file_path=file_path,
      fuzzy=self._fuzzy,
      msgfmt_extra_args=self._msgfmt_extra_args,
    )

class CompileCommand(BaseCommand):
  name = "compile"
  aliases = ["c", ]
  executor_class = CompileCommandExecutor

  @classmethod
  def make_parser(cls, factory=argparse.ArgumentParser) -> argparse.ArgumentParser:
    description = "compile '.po' text files into '.mo' binaries"
    parser = factory(
      prog=cls.name,
      description=description,
      add_help=True,
      help=description,
      formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
      "-d", "--locale-dir",
      dest="locales_dir",
      default=defaults.DEFAULT_LOCALE_DIR_NAME,
      help="path to the directory where locales are stored",
    )
    parser.add_argument(
      "-l", "--locale",
      dest="locale",
      action="append",
      help=(
        "locale(s) to process, ex: 'en_US'; "
        "can be specified multiple times; "
        "all locales are processed if not specified"
      ),
    )
    parser.add_argument(
      "-e", "--exclude",
      dest="exclude",
      action="append",
      help="locale(s) to exclude, ex: 'en_US'; can be specified multiple times",
    )
    parser.add_argument(
      "-f", "--use-fuzzy",
      action="store_true",
      dest="fuzzy",
      default=False,
      help="use fuzzy translations",
    )
    parser.add_argument(
      "--msgfmt-extra-args",
      action="append",
      dest="msgfmt_extra_args",
      help=(
        "extra arguments for 'msgfmt' utility; "
        "can be comma-separated or specified multiple times"
      ),
    )
    parser.add_argument(
      "-v", "--verbose",
      action="store_true",
      dest="verbose",
      default=False,
      help="use verbose output",
    )
    return parser


from collections import defaultdict
import re
import joblib

_SMALLEST = 10e32

def argmin(x: list, minval=_SMALLEST):
    """Find the smallest index from a list"""
    idx = None
    for i, xi in enumerate(x):
        if xi < minval:
            minval = xi
            idx = i
    return idx

def read_file(filename):
    """Read the input file, nothing fancy."""
    with open(filename, "r", encoding="utf-8") as f:
        commands = []
        while True:
            n = f.readline()
            if len(n) > 0:
                commands.append(n.strip("\n"))
            else:
                break
    return commands

class File:
    def __init__(
        self,
        name: str,
        id: int,
        parent: str = None,
        type: str = "file",
        size: int = 0,
        is_dir: bool = None,
        depth: int = None,
        n_sib: int = None,
    ) -> None:
        """A simple class that holds the several attributes of each file or
        directory.

        Parameters
        ----------
        name : str
            Name of the item.
        id : int
            Identifier for the item, used sometimes to check absolute distance.
        parent : str, optional
            Parent name of the item, by default None
        type : str, optional
            Indicates the type of the item, can be "file" for a file or
            "dir" for a folder, by default "file"
        size : int, optional
            Size of the item, by default 0
        is_dir : bool, optional
            Indicates if the item is a folder, by default None
        depth : int, optional
            Indicates at what depth from the root directory "/" the item is
            located, by default None
        n_sib : int, optional
            Number of siblings (items in the same folder includng self),
            by default None
        """

        self.name = name
        self.id = id
        self.type = type
        self.size = size
        self.is_dir = is_dir
        self.parent = parent
        self.depth = depth
        self.n_sib = n_sib

    def __iter__(self):
        return iter([self])

    def __repr__(self) -> str:
        return f"File(id={self.id} p={self.parent}, n={self.name}, t={self.type}, s={self.size}, d={self.depth}, sib={self.n_sib})"
        # return f"{self.parent}/{self.name}"

    def __str__(self) -> str:
        return self.__repr__()

class System:
    """
    Class that reads the input file and parses the commands, files, folders,
    subdirectories and their attributes into a plain list of File() objects.
    """

    def __init__(self, console_log: list, commands: list = ["$ cd", "$ ls"]) -> None:
        """Initialize the System() class.

        Parameters
        ----------
        console_log : list
            Whole input from the AOC2022/7 input file
        commands : list, optional
            Commands accepted by the System, by default ["$ cd", "$ ls"]
        """
        self.commands = commands
        self.console_log = console_log
        self.log = defaultdict(lambda: [])
        self.counter = 0
        self.depth = 0
        self._prev_dirs = []
        self.n_items = 0
        self.id = 1

    def run(self, command):
        """Run each command iteratively.

        Separates the command from the arguments.

        Parameters
        ----------
        command : str
            Command as a string.
        """
        command_arg = None
        operation = command[:4]
        command_arg = command[5:]
        self.counter += 1
        if operation.startswith("$ cd"):
            if not command_arg == "..":
                # store history of directories to id parents
                self._prev_dirs.append(command_arg)
            self.cd(command_arg)

        elif operation.startswith("$ ls"):
            self.ls(command_arg)
        else:
            # print(f"skipping non-commands {command}")
            pass

    def cd(self, arg):
        print(f"executing cd {arg}")
        self.curr_path = arg
        # add/sub depth with each call to cd()
        self.depth += -1 if arg == ".." else 1

    def ls(self, arg):
        print(f"executing ls {arg}")
        self.capture_out()
        self.parse_out()

    def capture_out(self):
        """
        Capture the output from the console_log.

        Using the counter as a slicer variable, read all of the
        console_log up until the next comamnd.
        """
        self.out = []
        for out in self.console_log[self.counter :]:
            if out.startswith("$"):
                break
            self.out.append(out)
        self.n_items = len(self.out)

    def parse_out(self):
        """
        Parse the captured output as File() objects.

        If the item is a file, the size, name attributes are read from the
        captured out. If the item is a directory, the name is read.

        The parent and depth attributes are set by corresponding tracker
        variables from run() and cd().
        """
        for item in self.out:
            is_dir = item.startswith("dir")
            if is_dir:
                type = "dir"
                size = 0
                name = item[4:]
            else:
                type = "file"
                size = int(re.findall("[(0-9)]+", item)[0])
                # some files do not have .ext
                name = re.findall("[a-zA-Z].+|[a-zA-Z]+", item)[0]
            file = File(
                size=size,
                id=self.id,
                name=name,
                type=type,
                is_dir=is_dir,
                parent=self._prev_dirs[-1],
                depth=self.depth,
                n_sib=self.n_items,
            )
            print(f"found {file} in {self._prev_dirs[-1]}")
            self.log[self.depth].append(file)
            self.id += 1

def traverse_from_bottom(log: list):
    """Traverse the File() list collected in the log attribute of System().

    Read from the deepest node to the root node.

    Parameters
    ----------
    log : list
        Collection of File()'s

    Returns
    -------
    list
        A list of File() with the parents assigned as File() objects.
    """
    max_depth = max(log)  # key to access deepest node
    tree = []
    reverse_order = list(range(0, max_depth + 1))[::-1]
    for depth in reverse_order:
        parent = None
        for contents in log[depth]:
            if depth > 0:
                # find parent
                candidates = []
                for prev_depth in log[depth - 1]:
                    if (prev_depth.name == contents.parent) and prev_depth.is_dir:
                        # it should be a dir to be a parent
                        parent = prev_depth
                        candidates.append(parent)
                # if duplicate file names are used at the same depth, multiple
                # parent candidates can arise!
                if len(candidates) > 1:
                    print(contents, candidates, contents.id)
                    print(f"Warning: found {len(candidates)} parents!")
                    # Check for the closest node using absolute distance
                    # of their ids.
                    diffs = []
                    for c in candidates:
                        diff = abs(contents.id - c.id)
                        print(f"{c}: {c.id}, diff:{contents}-{c}={diff}")
                        diffs.append(diff)
                    min_idx = argmin(diffs)
                    parent = candidates[min_idx]
                    print(f"Select {parent}")
            contents.parent = parent
            tree.append(contents)
    return tree

def find_common_parent(t, other_paths):
    """
    Take a path `t` and compare iteratively with other paths `other_path` to
    find if they are in the same directory (under the same parent).

    Will return self if no other paths with same parent.
    """
    items = []
    for op in other_paths:
        conditions = (
            (t.parent is not None) and (t.parent == op.parent) and (t.depth == op.depth)
        )
        if conditions:
            items.append(op)
    return items

def assign_dir_size(t, other_paths):
    """
    Find parent directories and calculate the size attribute of
    each parent directory by summing up all of its child attribute (size),
    starting from the deepest File.
    """
    siblings = find_common_parent(t, other_paths)
    print(f"sib: {len(siblings)}, d={t.depth}, name={t.name}", end=" ")
    dir_size = 0
    for s in siblings:
        dir_size += s.size
    if (t.parent) and (t.parent.size == 0):
        # only assign oif not already assigned by other paths.
        print(f"assigned {t.parent.size} -> {dir_size}")
        t.parent.size = dir_size

if __name__ == "__main__":

    _depth = 1
    console_log = read_file("dec7/input.txt")
    # print(console_log)
    os = System(console_log)
    for c in console_log:
        os.run(c)
    # save
    tmp_log = os.log.copy()
    root_folder = File(
        id=0, parent=None, name="/", size=0, depth=0, type="dir", is_dir=True
    )
    tmp_log[0] = [root_folder]
    joblib.dump(dict(tmp_log), "dec7/inp.joblib")
    # print(f"\nbuilding tree")
    print(tmp_log)

    tree = traverse_from_bottom(tmp_log)

    for t in tree:
        assign_dir_size(t, tree)

    # save tree
    joblib.dump(tree, "dec7/tree.joblib")
    # Part 1:
    dirs = []
    sum_ = 0
    dirs_sum = []

    for t in tree:
        if t.is_dir and t.size <= 100000:
            sum_ += t.size
            # name, size, cumulative sum
            dirs_sum.append((t.name, t.size, sum_))

    print(f"\n\nSum of dirs with size <100000: {sum_}")


# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

# Generated by Django 2.1.7 on 2019-03-26 15:43

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone

class Migration(migrations.Migration):
    initial = True

    dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]

    operations = [
        migrations.CreateModel(
            name="PolicyException",
            fields=[
                (
                    "id",
                    models.AutoField(
                        auto_created=True,
                        primary_key=True,
                        serialize=False,
                        verbose_name="ID",
                    ),
                ),
                (
                    "comment",
                    models.TextField(help_text="Explanation for this exception."),
                ),
                ("created", models.DateTimeField(default=django.utils.timezone.now)),
                (
                    "user",
                    models.OneToOneField(
                        help_text="This user is excepted from the Mozilla-employees-only policy.",
                        on_delete=django.db.models.deletion.CASCADE,
                        to=settings.AUTH_USER_MODEL,
                    ),
                ),
            ],
        )
    ]


from flask import Flask, render_template, jsonify, request
app = Flask(__name__)

from urllib.request import urlopen
from urllib.parse import quote_plus
from bs4 import BeautifulSoup
from selenium import webdriver
import requests
import time

# pymongo를 임포트 하기(패키지 인스톨 먼저)
from pymongo import MongoClient
# mongoDB는 27017 포트로 돌아갑니다.
client = MongoClient('localhost', 27017)
# 'BangguseokTravel'라는 이름의 db를 만듭니다.
db = client.BangguseokTravel

# Home HTML을 주는 부분
@app.route('/')
def home():
    return render_template('PP_BGSTravel_Home.html')

@app.route('/mybucketlist')
def mybucketlist():
    return render_template('PP_BGSTravel_MyBucketlist.html')

# Crawling으로 인스타그램에서 사진을 가져오는 부분
# API를 사용하자!

# API 역할을 하는 부분: 마음에 드는 포스트를 저장하는 부분
@app.route('/home', methods = ['POST'])
def saving():
    # 1. 클라이언트로부터 데이터를 받기
    url = request.form['url_give']
    image = request.form['image_give']
    continent = request.form['continent_give']
    country = request.form['country_give']
    city = request.form['city_give']
    comment = request.form['comment_give']

    print(url)

    # 2. meta tag를 스크래핑하기
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
    data = requests.get(url, headers=headers)
    soup + BeautifulSoup(data.text, 'html.parser')

    #이 부분 어떻게 채워넣지?

    bucketlist = {'url':url, 'image':image, 'continent':continent, 'country':country, 'city':city, 'comment':comment}

    print(bucketlist)

    # 3. mongoDB에 데이터 넣기
    db.bucketlist.insert_one(bucketlist)

    return jsonify({'result':'success', 'msg':'버킷리스트를 추가했습니다:D'})

# 내가 저장한 포스트를 불러오는 부분
@app.route('/home', methods = ['GET'])
def listing():
    # 1. 모든 document 찾기 & _id 값은 출력에서 제외하기
    result = list(db.bucketlist.find({}))

    # 2. articles라는 키 값으로 포스트정보 내려주기
    return jsonify({'result':'success',
                    'msg':'저장한 포스트를 가져왔습니다:)',
                    'bucketlist':result})

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


#!/usr/bin/env python
"""
Test unit for the functions in the extractors.py module.

"""

PKG = 'mcr_manipulation_utils_ros'

import unittest
import rosunit
import sensor_msgs.msg
import mcr_manipulation_utils_ros.extractors

class TestExtractors(unittest.TestCase):
    """
    Tests functions used in the extractors.py module.

    """
    def test_extract_positions(self):
        """
        Tests that the 'extract_positions' function returns
        only the joint position values of the specified joints.

        """
        joint_state = sensor_msgs.msg.JointState()
        joint_state.name = [
            'arm_1_joint', 'arm_2_joint', 'arm_3_joint', 'arm_4_joint',
            'arm_5_joint', 'arm_6_joint', 'arm_7_joint'
        ]
        joint_state.position = [
            -1.4625, -1.4834, -2.5729, -2.0431, 0.4070, 1.8124, -2.8385
        ]

        joint_names = ['arm_6_joint', 'arm_4_joint', 'arm_2_joint']

        expected_result = [1.8124, -2.0431, -1.4834]

        result = mcr_manipulation_utils_ros.extractors.extract_positions(
            joint_state, joint_names
        )

        for i, res in enumerate(result):
            self.assertAlmostEqual(res, expected_result[i])

if __name__ == '__main__':
    rosunit.unitrun(PKG, 'test_extractors', TestExtractors)


# coding:utf-8
import unittest2
from peatio_client import StreamingClient, ClientError

class StreamingClientTestCase(unittest2.TestCase):
    def test_init(self):
        sc = StreamingClient(
            access_key= "access",
            secret_key = "secret"
        )

        self.assertEqual("access", sc.access_key)
        self.assertEqual("secret", sc.secret_key)


# https://www.acmicpc.net/problem/1978
import sys
sys.stdin = open('input.txt','r')
input = sys.stdin.readline

def is_prime(x):
    if x == 1: return 0
    else:
        for i in range(2,int(x**(1/2))+1):
            if x%i == 0: return 0
    return 1

N = int(input())
arr = list(map(int, input().split()))
answer = 0
for x in arr:
    answer += is_prime(x)
print(answer)


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

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def kthSmallest(self, root, k):
        def _inorderTraversal(root, result):
            if root.left is not None:
                _inorderTraversal(root.left, result)
            result.append(root.val)
            if root.right is not None:
                _inorderTraversal(root.right, result)

        result = []
        _inorderTraversal(root, result)
        return result[k - 1]

if __name__ == "__main__":
    solution = Solution()

    t0_0 = TreeNode(3)
    t0_1 = TreeNode(1)
    t0_2 = TreeNode(4)
    t0_3 = TreeNode(2)
    t0_1.right = t0_3
    t0_0.left = t0_1
    t0_0.right = t0_2

    assert 1 == solution.kthSmallest(t0_0, 1)


# Distributed with a free-will license.
# This code is designed to work with Finamon GNSS/Modem BG770A Shield

import sys
import time

bRPi = False
if "win" not in sys.platform:
	import smbus
	import RPi.GPIO as GPIO
	bRPi = True

class board_hw:
	# Peripheral Pin Definations Finamon
	USER_BUTTON = 27
	USER_LED = 22

	#inputs
	IN1_RI = 5
	IN2_RI = 6
	IN3_RI = 24
	IN4_RI = 25

	#outputs
	OUT1_RO = 12
	OUT2_RO = 16
	OUT3_RO = 20
	OUT4_RO = 21

	def __init__(self):
		if not bRPi:
			return
		# Get I2C bus
		self.bus = smbus.SMBus(1)
		time.sleep(0.5)

		GPIO.setmode(GPIO.BCM)
		GPIO.setwarnings(False)

		GPIO.setup(self.IN1_RI, GPIO.IN, pull_up_down = GPIO.PUD_UP)
		GPIO.setup(self.IN2_RI, GPIO.IN, pull_up_down = GPIO.PUD_UP)
		GPIO.setup(self.IN3_RI, GPIO.IN, pull_up_down = GPIO.PUD_UP)
		GPIO.setup(self.IN4_RI, GPIO.IN, pull_up_down = GPIO.PUD_UP)

		GPIO.setup(self.OUT1_RO, GPIO.OUT)
		GPIO.setup(self.OUT2_RO, GPIO.OUT)
		GPIO.setup(self.OUT3_RO, GPIO.OUT)
		GPIO.setup(self.OUT4_RO, GPIO.OUT)

	def showIOs(self):
		print("inputs:  IN1_RI  %s  IN2_RI  %s  IN3_RI  %s  IN4_RI  %s" %
			(GPIO.input(self.IN1_RI), GPIO.input(self.IN2_RI), GPIO.input(self.IN3_RI), GPIO.input(self.IN4_RI)))
		print("outputs: OUT1_RO %s  OUT2_RO %s  OUT3_RO %s  OUT4_RO %s" %
			(GPIO.input(self.OUT1_RO), GPIO.input(self.OUT2_RO), GPIO.input(self.OUT3_RO), GPIO.input(self.OUT4_RO)))
		return

	# Function for reading user button
	def readUserButton(self):
		GPIO.setup(self.USER_BUTTON, GPIO.IN, pull_up_down = GPIO.PUD_UP)
		return GPIO.input(self.USER_BUTTON)

	# Function for turning on user LED
	def turnOnUserLED(self):
		if not bRPi:
			return
		GPIO.setup(self.USER_LED, GPIO.OUT)
		GPIO.output(self.USER_LED, 1)

	# Function for turning off user LED
	def turnOffUserLED(self):
		if not bRPi:
			return
		GPIO.setup(self.USER_LED, GPIO.OUT)
		GPIO.output(self.USER_LED, 0)

if __name__=='__main__':

    shield = board_hw()
    shield.showIOs()
    while True:
        GPIO.output(shield.OUT1_RO, 0)
        GPIO.output(shield.OUT2_RO, 0)
        GPIO.output(shield.OUT3_RO, 0)
        GPIO.output(shield.OUT4_RO, 0)
        shield.showIOs()
        time.sleep(1)
        GPIO.output(shield.OUT1_RO, 1)
        GPIO.output(shield.OUT2_RO, 1)
        GPIO.output(shield.OUT3_RO, 1)
        GPIO.output(shield.OUT4_RO, 1)
        shield.showIOs()
        time.sleep(1)

    for i in range (10):
        print("user LED ON")
        shield.turnOnUserLED()
        time.sleep(1)

        print("user LED OFF")
        shield.turnOffUserLED()
        time.sleep(1)

    while(True):
        if shield.readUserButton():
            shield.turnOffUserLED()
        else:
            shield.turnOnUserLED()


from app.models import db, March_Madness_Team, League, League_User, Draft, Drafted_Team, User, Tournament
import json
from datetime import datetime
import random
from app.api.draft_routes import generate_draft_order

def seed_draft_2019():
    # This is for the Demo Draft functionality
    league = League.query.filter(
        League.name == 'The League of Extraordinary Gentlemen').one()

    tournament = Tournament.query.filter(Tournament.year==2019).one()

    draft_order = generate_draft_order(league.id)
    draft = Draft(league_id=league.id, tournament_id=tournament.id,
                  draft_order=json.dumps(draft_order), draft_index=0,
                  draft_time=datetime.now(),
                  drafting=True, current_drafter_id=draft_order[0])
    db.session.add(draft)
    db.session.commit()

    # This is for a second year of the Demo data
    league = League.query.filter(
        League.name == 'The Dumb Friends League').one()

    draft_order = generate_draft_order(league.id)
    draft = Draft(league_id=league.id, tournament_id=tournament.id,
                  draft_order=json.dumps(draft_order), draft_index=64,
                  draft_time=datetime.now(),
                  drafting=False, current_drafter_id=None)
    db.session.add(draft)
    db.session.commit()

    march_madness_team_ids = {
        march_madness_team.id for march_madness_team in tournament.march_madness_teams
    }
    for i in range(0, 64):
        pick = random.choice(tuple(march_madness_team_ids))
        march_madness_team_ids.remove(pick)
        drafted_team = Drafted_Team(
            march_madness_team_id=pick,
            league_user_id=draft_order[i],
            draft_id=draft.id,
            selection_num=i+1)
        db.session.add(drafted_team)

    db.session.commit()

def undo_draft_2019():
    db.session.execute(
        'DELETE FROM drafts USING tournaments WHERE drafts.tournament_id = tournaments.id AND tournaments.year = 2019;')
    db.session.commit()


#===== Блюпринт loader view =====#

from flask import Blueprint, render_template, request
from loader.utils import save_picture, add_new_post
from exceptions import WrongImgType
import logging

# Подключаем блюпринт для loader view
loader_blueprint = Blueprint("loader_blueprint", __name__, template_folder="templates")

# Включаем логирование
logging.basicConfig(filename="logger.log", level=logging.INFO, encoding="utf-8")

#===== Основные методы блюпринта =====#

@loader_blueprint.route("/post", methods=["GET"])
def create_new_post_page():
    """ Метод для отображения формы с созданием поста"""
    return render_template("post_form.html")

@loader_blueprint.route("/post", methods=["POST"])
def create_new_post_by_user():
    """ Метод на создание нового поста """
    # Запросы на данные получаемые в форме
    picture = request.files.get("picture")
    content = request.form.get("content")
    # Проверка контента на наличие данных
    if not picture or not content:
        logging.info("Данные не загружены, отсутствует часть данных")
        return "Отсутствует часть данных"
    # Сохранение изображения и проверка на формат файла
    try:
        picture_path = save_picture(picture)
    except WrongImgType:
        return "Неверный формат изображения"
    # Создание нового поста
    new_post = add_new_post(picture_path, content)
    # Генерируем страничку с результатами загрузки поста
    logging.info("Добавлен новый пост")
    return render_template("post_uploaded.html", new_post=new_post)


copyright = u'2021, Intel'

# The short X.Y version
version = u''
# The full version, including alpha/beta/rc tags
release = u''

# -- General configuration ---------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

# Add any paths that contain templates here, relative to this directory.
templates_path = ['../../../_templates']

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'

# The master toctree document.
master_doc = 'index'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['**/*.inc.rst']

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None

# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_book_theme'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['../../../_static']
html_logo = '../../../_static/oneapi-logo1.png'
html_favicon = '../../../_static/favicons.png'

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself.  Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}

# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = project + '-spec'  # noqa: F821

# -- Options for LaTeX output ------------------------------------------------

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
pro = project.translate(project.maketrans(' ', '-'))  # noqa: F821
file_name = f'{pro}-spec.tex'
latex_documents = [
    (
        master_doc,
        file_name,
        project + u' Specification',  # noqa: F821
        u'Intel',
        'manual',
    ),
]

# -- Options for Epub output -------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = project  # noqa: F821

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']

# -- Extension configuration -------------------------------------------------

# -- Options for todo extension ----------------------------------------------

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True

# -- Options for breathe extension -------------------------------------------

breathe_projects = {project: '../doxygen/xml'}  # noqa: F821
breathe_default_project = 'none'


import re, sys
def _syslog(filename, listOfKeywords):

    # Open syslog file and save as 'contents'
    with open(filename) as f:
        # Read file into 'contents'
        contents = f.readlines()

    # List to store the results
    results = []
    # Loopping for each element in syslog
    for line in contents:
        # Loopping for each element in keyword
        for eachKeyword in listOfKeywords:
            # If element 'line' contains element 'keyword'
            # Then print the occurrences
            x = re.findall(r"" + eachKeyword + "", line)
            # print(x)

            for found in x:
                # Append the returned key words to the results list
                results.append(found)

    # Here is check to see if there are results
    if len(results) == 0:
        print("No Results")
        sys.exit(1)
    # Here it sort the list
    results = sorted(results)
    # Remove duplicates (convert to set)
    results = set(results)
    return results


from pytube import YouTube

url = input("Enter Link: ")
youtube_1 = YouTube(url)

video = youtube_1.streams.all()
vid = list(enumerate(video))

for i in vid:
    print(i)
print()
stream = int(input("Enter ur selected quality: "))
print(f"Downloading Video: {youtube_1.title}")
video[stream].download()
print("Done!")

# *****FOR PLAYLISTS(144P)*****
# from pytube import Playlist
#
# url = input("Enter Link: ")
# py = Playlist(url)
# print(f"Downloading: {py.title}")
# for video in py.videos:
#     video.streams.first().download()
# print("Done!")


from collections import deque
import sys

n = int(sys.stdin.readline())
arr = []
x = 0
y = 0
for i in range(n):
    arr.append(list(map(int, sys.stdin.readline().split(" "))))
    if 9 in arr[i]:
        x = i
        y = arr[i].index(9)

q = deque()
chk = [[0] * n for _ in range(n)]
size = 2
exp = 0
q.append((x, y, 0))
arr[x][y] = 0
ret = 0
chk[x][y] = 1
stack = 0
slist = []
while True:
    if not q and stack != 0:
        slist.sort(key=lambda x: (x[0], x[1]))
        curr = slist[0]
        arr[curr[0]][curr[1]] = 0
        exp += 1
        if exp == size:
            exp = 0
            size += 1
        q.clear()
        chk = [[0] * n for _ in range(n)]
        chk[curr[0]][curr[1]] = 1
        stack = 0
        slist.clear()
        q.append((curr[0], curr[1], curr[2]))
        ret = max(ret, curr[2])
        continue
    elif not q:
        break
    curr = q.popleft()
    if arr[curr[0]][curr[1]] != 0 and arr[curr[0]][curr[1]] < size:
        if stack == 0:
            stack = curr[2]
            slist.append(curr)
            continue
        elif stack == curr[2]:
            slist.append(curr)
            continue
        elif stack < curr[2]:
            slist.sort(key=lambda x: (x[0], x[1]))
            curr = slist[0]
            arr[curr[0]][curr[1]] = 0
            exp += 1
            if exp == size:
                exp = 0
                size += 1
            q.clear()
            chk = [[0] * n for _ in range(n)]
            chk[curr[0]][curr[1]] = 1
            stack = 0
            slist.clear()
            q.append((curr[0], curr[1], curr[2]))
            ret = max(ret, curr[2])
            continue
    dx = [-1, 0, 0, 1]
    dy = [0, -1, 1, 0]
    for i in range(4):
        nx = dx[i] + curr[0]
        ny = dy[i] + curr[1]
        if (
            nx >= 0
            and ny >= 0
            and nx < n
            and ny < n
            and chk[nx][ny] == 0
            and arr[nx][ny] <= size
        ):
            chk[nx][ny] = 1
            q.append((nx, ny, curr[2] + 1))
print(ret)


import gc
import os
from abc import ABCMeta, abstractmethod
from pathlib import Path

from yamakawa_san_utils import pickle_dump, timer

class Features(metaclass=ABCMeta):

    def __init__(self, params, logger=None):
        self.name = self.__class__.__name__
        self.datatype = params["datatype"]
        self.debug = params["debug"]
        self.is_overwrite = params["is_overwrite"]
        self.org_columns = []
        self.logger = logger

        self.input_dir = os.path.join(os.path.dirname("__file__"), "../input")
        self.df_path = Path(self.input_dir) / f"{self.datatype}.csv"

        #self.save_dir = os.path.join(
        #    os.path.dirname("__file__"),
        #    f"../../inputs/feature")
        self.save_dir = './mnt/inputs/features'
        self.save_type_dir = Path(self.save_dir) / f"{self.datatype}"
        self.save_path = Path(self.save_type_dir) / f"{self.name}.pkl"
        os.makedirs(self.save_dir, exist_ok=True)
        os.makedirs(self.save_type_dir, exist_ok=True)

    def feature_extract(self, org_train, org_test):
        if self.check_feature_exec():
            with timer(f"FE: {self.name}", self.logger):
                a = self.calc_feature(org_train, org_test)
            return a

    @abstractmethod
    def calc_feature(self):
        """calc and save features
        Return: feature_df
        """
        raise NotImplementedError

    def format_and_save_feats(self, feat_df):
        """保存するカラムなど特徴量の形式を指定する
        """
        feat_cols = [
            c for c in list(
                feat_df.columns) if c not in self.org_columns]
        print(f'save feats to {self.save_path}')
        pickle_dump(feat_df[feat_cols], self.save_path)

        del feat_df
        gc.collect()

    def check_feature_exec(self):
        """
        すでに対象の特徴が存在するかどうかをcheckする
        Returns: bool (Falseなら特徴作成しない)

        """
        path = self.save_path

        if self.is_overwrite:
            print(f"overwrite features : {self.name}")
            return True
        else:
            if os.path.exists(path) is False:
                print(f"creates new file : {self.name}")
                return True

        print(f"file exists : {self.name}")
        return False

if __name__ == '__main__':
    features = Features()


from modelos.Grafo import Grafo

class LeitorGrafo:

    def __init__(self, caminho='files/grafo.txt'):
        self.__caminho = caminho

    def setCaminho(self, caminho='files/grafo.txt'):
        self.__caminho = caminho

    def getCaminho(self):
        return self.__caminho

    def lerArquivo(self):
        f = open(self.__caminho, 'r')
        for i in f.readlines():
            print(i)

    def leGrafo(self):
        f = open(self.__caminho, 'r')
        arquivo = f.readlines()
        if(len(arquivo) > 1):
            grafo = Grafo()
            for i in range(len(arquivo)):
                grafo.insereNo()
            for i in range(len(arquivo)):
                if len(arquivo[i]) > 0:
                    arcos = arquivo[i].split(
                        ':')[1].replace('\n', '').split(' ')
                    max = len(arcos)
                    arcos = arcos[1:max]
                    for aresta in arcos:
                        if len(aresta) > 0:
                            grafo.insereArco(i, int(aresta))
            return grafo
        else:
            raise Exception('Erro ao ler o grafo - Não nada no arquivo')

    def salvaGrafo(self, grafo):
        f = open(self.__caminho, 'a')
        matriz = grafo.getMatrizAdjacente()
        for chave in matriz.keys():
            s = ''
            s += str(chave)
            s += ': '
            for no in range(len(matriz[chave])):
                if(matriz[chave][no] != 0):
                    s += str(no) + ' '
            s += '\n'
            f.write(s)

TEG - Teoria dos Grafos/Trabalho 1/arquivos/LeitorGrafo.py