'''
Primary module used for this project.
Used to scrape/obtain data from Principal's consumer.
It does so using a selenium web driver.
'''
from selenium.webdriver.common.by import By
from bs4 import BeautifulSoup
import time
import datetime
import json
import re
import pandas as pd
import numpy as np

class Session:
    '''Session class represents the login session

    Parameters:
        driver (selenium.webdriver): Selenium driver instance\
        used to interact with the webpage
        username (str): username to login
        password (str): password to login

    Attributes:
        accounts (list of *str* objects): list of accounts available

    Example:
        I prefer to use a headless chrome driver as my driver:

        .. code-block:: python

            chrome_options = webdriver.chrome.options.Options()
            chrome_options.add_argument('--headless')
            # Only show fatal with log level 3
            chrome_options.add_argument("--log-level=3")
            driver = webdriver.Chrome(
                executable_path='chromedriver',
                options=chrome_options
            )
            # Setting window size ensures elements are clickable
            driver.set_window_size(1440, 900)

        .. code-block:: python

            session = Session(driver, 'username', 'pa$$w0rd')

    '''

    def __init__(self, driver, username, password):
        self.driver = driver
        # I guess the account needs a DD
        self.__login([username, password])
        self.__accounts = []

        '''from the landing page, get the contract number(s) and the id number
            We need to wait for the page to load to do this'''
        time.sleep(7)  # Maybe while 'Hang on' in page text
        # Get all the hrefs from the landing page
        a_tags = driver.find_elements_by_tag_name('a')

        # Filter to links containing 'contract' in the href
        a_tags = list(filter(
            lambda x: False if not x.get_attribute(
                'href') else 'contract' in x.get_attribute('href').lower(),
            a_tags
        ))
        # Do this to avoid stale element issue
        hrefs = [x.get_attribute('href') for x in a_tags]
        # Do this to avoid stale element issue
        onclicks = [x.get_attribute('onclick') for x in a_tags]

        for i, href in enumerate(hrefs):
            d = dict()
            d['nav_url'] = href
            # Get query params from the href
            attrs = re.findall(
                '[\\&\\?]([^\\&=\\?]+)=([^\\&\\?]+)', href) if href else None

            if attrs:
                for param, val in attrs:
                    d.setdefault(param, []).append(val)

            # Get the Name of the account
            if onclicks[i]:
                # Arglist should be of form (plan_cat, plan_type, plan_name)
                argnames = ['category', 'type', 'name']
                onclick = onclicks[i].split(
                    'gtmAccountDetails')[-1].strip('()').split(',')
                # This should always be case
                if len(onclick) == 3:
                    # strip away the double quotes
                    argvals = list(map(lambda x: x.strip('"'), onclick))
                    d.update(dict(zip(argnames, argvals)))
                    self.add_account(Account(driver=self.driver, **d))

    def __verify_2FA(self):
        self.driver.implicitly_wait(10)  # seconds
        # Each field is its own box
        otp = input('MFA CODE: ')
        otp_xs = self.driver.find_element_by_id('otpXS')
        if not otp_xs.is_displayed():
            # Enter the passcode one char at a time
            for x in self.driver.find_elements_by_tag_name('input'):
                if x.get_attribute('id') == 'otp1':
                    x.clear()
                    x.send_keys(otp[0])
                elif x.get_attribute('id') == 'otp2':
                    x.clear()
                    x.send_keys(otp[1])
                elif x.get_attribute('id') == 'otp3':
                    x.clear()
                    x.send_keys(otp[2])
                elif x.get_attribute('id') == 'otp4':
                    x.clear()
                    x.send_keys(otp[3])
                elif x.get_attribute('id') == 'otp5':
                    x.clear()
                    x.send_keys(otp[4])
                elif x.get_attribute('id') == 'otp6':
                    x.clear()
                    x.send_keys(otp[5])
        else:
            # Enter the password all at once
            otp_xs.clear()
            otp_xs.send_keys(otp)

        # Click the verify button
        verify = self.driver.find_element_by_id('verifyButton')
        verify.click()

    def __requested_2FA(self):
        self.driver.implicitly_wait(10)  # seconds
        if not self.driver.find_element_by_id('otpXS'):
            return False
        return True

    def __login(self, creds):
        self.driver.implicitly_wait(10)  # seconds
        # Go to PFG login site
        url = 'https://login.principal.com/login'
        self.driver.get(url)

        # Login using credentials
        usr_field = self.driver.find_element_by_id('username')
        usr_field.clear()
        usr_field.send_keys(creds[0])
        pwd_field = self.driver.find_element_by_id('password')
        pwd_field.clear()
        pwd_field.send_keys(creds[1])

        # Accept the cookies, if applicable
        try:
            login = self.driver.find_element_by_id('continue')
            self.driver.find_element_by_id(
                'onetrust-accept-btn-handler').click()
        except:
            pass
        login.click()

        # Make sure it worked
        if 'username or password you entered was invalid'\
                in self.driver.page_source:
            print('Unable to login.')
            return None

        # Perform 2FA, if applicable
        if self.__requested_2FA():
            self.__verify_2FA()

    @property
    def accounts(self):
        return [x.name for x in self.__accounts] if self.__accounts else None

    @accounts.setter
    def accounts(self, value):
        self.__accounts = value

    def get_account(self, name=None, index=None):
        '''Retrieves the specified account from self.accounts

        Args:
            name (str): string matching one of
                the strings shown in *accounts* list
            index (int): integer for which index from *accounts* list to show

        Examples:

            .. code-block:: python

                session = pfg.Session(driver, usr, pwd)
                session.accounts
                # ['Company X 401k', ..., 'Company X Dental']

                x = session.get_account(name='Company X 401k')
                y = session.get_account(index = 0)
                x == y
                # True

            Or maybe:

            .. code-block:: python

                print(session.get_account(session.accounts[0]).name)
                # 'Company X 401k'

        '''
        if name:
            if isinstance(name, str):
                '''Case 1: a string was proided. This should
                represent one of the account names
                '''
                return list(filter(
                    lambda x: name in x.name, self.__accounts
                ))[0]
            else:
                print('name should be a string.')
                return None
        elif index is not None:
            if isinstance(index, int):
                '''Case 2: an integer was provided.
                This should represent an index
                '''
                return self.__accounts[index]
            else:
                print('index should be an integer representing an index')
                return None

    def add_account(self, obj_account):
        self.__accounts = self.__accounts + [obj_account]
        return self.__accounts

class Account(Session):
    '''Account class represents an account
    identified by the `Session` class

    Attributes:
        name (str): Name of the account
        type (str): Type of account,
            e.g. "Defined Contribution Retirement Plan"
        category (str): Broad category of account,
            e.g. "Retirement & Investments"
        ror: Rate of Return
        balance: Total balance of the account
        vestedBalance: Vested portion of balance
        gain: Amount of gain or loss on the account
        loss: alias for *gain*
        asof: Date when data was updated
        allocations: Summary of paycheck contribution settings
            as *Pandas DataFrame*
        contributions: Summary of employee vs employer contributions
            (along with vesting information) as *Pandas DataFrame*
    '''

    def __init__(self, **kwargs):
        '''kwargs:
            id_num
            category
            type
            name
            nav_url
            driver ... I think the account should really have the driver,
                but I cannot seem to wrap my head around that yet.
                Furthermore, I think each account having its own
                driver will cause HTMLAsynch issues.
        '''
        self.__dict__.update(
            kwargs)  # Update the attributes with provided params
        # just for shits, lets see what happens if we run summary() on init
        # ? Update: It takes about two minutes, which is kind of extra,
        # ? so lets leave it out for now
        # self.summary()

    def summary(self):
        '''
        Use nav_url to get some info on the account
        (e.g. balance, vested balance, etc.).

        Matta fact, maybe this should be done on __init__,
        since doing so could also yield hrefs to history, etc.
        '''
        self.driver.implicitly_wait(10)
        self.driver.get(self.nav_url)
        if 'defined contribution' in self.type.lower():

            # Find the nav bar (give the page time to load)
            time.sleep(5)
            self.driver.implicitly_wait(0)
            navs = self.driver.find_elements_by_tag_name('nav')
            # Assumption is that nav bar is second
            # (first would be top with logout etc)
            nav_bar = nav_bar = navs[1].find_element_by_tag_name(
                'ul') if len(navs) else None

            # Use the dropdowns to get the hrefs
            d = dict()
            if nav_bar:
                # Get the dropdowns
                # for dd in nav_bar.find_elements_by_tag_name('ul'):

                for opt in nav_bar.find_elements_by_tag_name('li'):
                    if opt.text == '':
                        continue
                    # If the opt is a dropdown
                    if opt.find_elements_by_tag_name('ul'):
                        opt.click()
                        sub = opt.find_elements_by_tag_name('li')
                        for x in sub:
                            d[x.text] = x.find_element_by_tag_name(
                                'a').get_attribute('href')
                        opt.click()
                    else:
                        d[opt.text] = opt.find_element_by_tag_name(
                            'a').get_attribute('href')  # Should only be one

            self.nav_links = d

            ########
            # Get account summary info, if available
            m = re.search(
                r'controllerData = (\\{.*\\})\;?', self.driver.page_source)
            if m:
                d = json.loads(m[1])
                # For now just add everything, I guess
                self.__dict__.update(d)
        # TODO: make this an attr like Account._home
        self.driver.get('https://secure05.principal.com/member/accounts')

    def history(self, detail='summary', start=None, end=None):
        # TODO: Include param for level of detail (summary, _, full)
        # ? when none: 'There are no transaction details
        # ? available for this date range.' on page
        '''Retrieves history for the given dates for the account object

        Args:
            detail (str): Level of detail to provide.
                Goal is to provide three levels of detail
            start (str): Date string formatted MM/DD/YY.
                This is the beginning of the requested date range.
                Must be at most 92 days before *end*
            end (str): Date string formatted MM/DD/YY.
                This is the end of the requested date range.
                Must be at most 92 days after *start*

        Returns:
            Pandas Dataframe

        '''

        if detail.lower() == 'summary':
            # Get the balanceHistory data
            transactions = pd.DataFrame(np.array(
                [[x['effectiveDate'][0:10], x['total']]
                 for x in self.balanceHistory]),
                columns=['Date', 'Total']
            )

        elif detail.lower() == 'full':
            # Get the most amount of detail possible

            # TODO: input validation:
            # Verify that end - start is <= 91 days
            # Veryify start and end are dates

            # ? 'https://secure05.principal.com/RetirementServiceCenter/
            # ?  memberview?Contract=%283%2966776&Allow365=
            # ?  &From=06%2F13%2F2020&From2=09%2F01%2F2020&To=09%2F13%2F2020
            # ?  &To2=09%2F13%2F2020&Inv=By&Cont=By&page_name=reqbyby'
            # TODO: Build request URL using above
            # TODO: as a template in following call
            self._request_history()
            # Let the page load
            time.sleep(4)

            # At this point, we've made it to the transactions
            # and it should be loaded already
            tables = pd.read_html(self.driver.page_source)[1:]
            for i, t in enumerate(tables):
                # Each table is a multiindex along column axis
                inv = t.columns[0][0]
                t = t.droplevel(0, 'columns')
                t['Investment'] = inv

                # Drop total row
                t = t.loc[~(t['Contribution Type'] == 'Total')]
                if not i:
                    transactions = pd.DataFrame(columns=t.columns)
                transactions = pd.concat([transactions, t], ignore_index=True)

        return transactions

    def _get_investments(self):
        '''Gets summary of current investments

        Data returned: fund manager, fund name, number of shares, share price,
        percent of portfolio, and total value

        Returns:
            Pandas Dataframe

        '''
        # ? when none: 'This option will become available once there
        # ? is a balance in your account.' on page
        self._view_investments()

        # Let the page load
        time.sleep(5)
        page_text = self.driver.page_source

        # Most of the table info can be grabbed by read_html
        tbl = pd.read_html(page_text)[0]
        tbl.columns = ['AssetClass', "Ignore", 'Manager',
                       'Mix', 'Units', 'UnitValue', 'Total']

        # Drop NA column
        tbl = tbl.drop(columns={"Ignore"}).dropna()

        # Asset Names need to be grabbed separately
        soup = BeautifulSoup(page_text, features='lxml')
        page_table = soup.find('tbody')

        # Each table row has an asset to be grabbed
        rows = page_table.find_all('tr')
        asset_names = [row.find('a').text for row in rows]

        tbl['AssetName'] = asset_names

        return tbl

    def _view_investments(self):
        self.driver.get(self.nav_links[
            list(filter(
                lambda x: x.lower() == 'investment details',
                self.nav_links.keys()
            ))[0]
        ])

    def _view_transactions(self):
        self.driver.get(self.nav_links[
            list(filter(
                lambda x: x.lower() == 'account history',
                self.nav_links.keys()
            ))[0]
        ])

    def _get_allocations(self):
        '''Get the current paycheck contribution percentages

        Returns:
            Pandas DataFrame

        TODO:
            Be able to strip assetName and managerName from provided data
        '''
        self.driver.get(self.nav_links[
            list(filter(
                lambda x: x.lower() == 'paycheck contribution details',
                self.nav_links.keys()
            ))[0]
        ])
        time.sleep(4)  # let the page load

        tbl = pd.read_html(self.driver.page_source)[0].droplevel(0, axis=1)
        tbl.columns = ['AssetClass', 'Manager-Asset', 'empty', 'Allocation']

        # Remove unnecessary columns and rows
        tbl = tbl.drop(columns=['empty'])
        tbl = tbl.drop(len(tbl) - 1)  # Last row is a total row
        tbl['Allocation'] = tbl.Allocation.apply(
            lambda x: float(re.search(r'(\d+\.\d{2})%', x)[1])/100)

        # Get the asset and manager names from provided column
        tbl['AssetName'] = tbl['Manager-Asset'].apply(
            lambda x:
                'Principal' + ''.join(
                    x.replace('Performance Snapshot', '')
                    .split('Principal')[1:]
                )
        )

        # Add the fund manager
        tbl['Manager'] = tbl['Manager-Asset'].apply(lambda x: ''.join(
            x.replace('Performance Snapshot', '').split('Principal')[0]))

        return tbl[['Manager-Asset', 'AssetClass', 'Allocation']]

    def _request_history(self, detail='full', start=None, end=None):
        self.driver.implicitly_wait(10)
        # Go to the transactions page
        self._view_transactions()
        if detail == 'full':
            # View in full detail
            self.driver.find_element_by_id('submit-view-more-history').click()

        # Select dates (MM/DD/YYYY)
        # By default: Let's choose the current date and 92 days prior
        if not start:
            start = (datetime.date.today() +
                     datetime.timedelta(-91)).strftime('%m/%d/%Y')
        if not end:
            end = datetime.date.today().strftime('%m/%d/%Y')

        from_field = self.driver.find_element_by_id('From')
        from_field.clear()
        from_field.send_keys(start)
        to_field = self.driver.find_element_by_id('To')
        to_field.clear()
        to_field.send_keys(end)

        if detail == 'full':
            # Select detailed view (two radio buttons)
            for x in self.driver.find_elements(
                    By.XPATH,
                    '//label[contains(text(),"Detail by each")]'):
                x.click()

        # Submit
        btn = self.driver.find_element_by_name('Submit')
        btn.click()

    def _getAdvisorNames(self, tbl, total_row=True):
        # Take in a table and return an array with the advisor names

        advisors = [x.text for x in tbl.find_elements_by_tag_name('em')]
        if total_row is True:
            advisors.extend([np.nan])  # Extend for total row

        return advisors

    def _get_contributions(self):
        self.driver.get(self.nav_links[
            list(filter(
                lambda x: x.lower() == 'contribution totals by source',
                self.nav_links.keys()
            ))[0]
        ])
        # Let the page load
        time.sleep(4)

        # This is the most generalized table, so we'll take that.
        # May want to provide flexibility later on, though.
        tbl = pd.read_html(self.driver.page_source)[1].dropna()
        tbl.columns = ['src', 'vested_pct',
                       'vested_usd', 'total_usd', 'total_pct']

        tbl['Source'] = tbl['src'].apply(
            lambda x: re.search('(.+)Summary', x)[1])

        # Change to actual numbers
        tbl.vested_pct = tbl.vested_pct.str.strip('%').astype(float)
        tbl.total_pct = tbl.total_pct.str.strip('%').astype(float)
        tbl.vested_usd = tbl.vested_usd.str.replace(
            '$', '').str.replace(',', '').astype(float)
        tbl.total_usd = tbl.total_usd.str.replace(
            '$', '').str.replace(',', '').astype(float)

        return tbl[[
            'Source',
            'vested_pct',
            'vested_usd',
            'total_usd',
            'total_pct'
        ]]

    def _return(self, date_from=None, date_to=None, range='YTD'):
        '''Get the rate of return broken down by asset holdings

        Args:
            date_from (str or datetime-like obj): Start of range for which to
                calculate return. Default is start of year.
            date_to (str or datetime-like obj): End of range for which to
                calculate return. Default is current date.
            range (str): An alternative to providing *from* and *to* dates.

                *"YTD" (default)*: See year-to-date return
                *"YOY"*: See year-over-year return (1 year ago through)
                *"MAX"*: See year-over-year return
                for max date range (two years)

        Returns:
            Pandas dataframe

        '''
        self.driver.get(self.nav_links[
            list(filter(
                lambda x: x.lower() == 'personalized rate of return',
                self.nav_links.keys()
            ))[0]
        ])
        # Let the page load
        time.sleep(4)

        # Get the name of the Advisors
        tbl = self.driver.find_element_by_tag_name('tbody')
        advisors = self._getAdvisorNames(tbl)

        tables = pd.read_html(self.driver.page_source)

        if len(tables):
            tbl = tables[0].dropna(1)
            tbl.columns = ['Manager-Asset', 'Balance', 'Return']
            tbl['Manager'] = advisors
            tbl['AssetName'] = tbl.apply(
                lambda x:
                    x['Manager-Asset']
                    .replace(x['Manager'], '')
                    .replace('Performance Snapshot', '')
                    if not pd.isna(x['Manager']) else x['Manager-Asset'],
                axis=1)
            return tbl[['Manager', 'AssetName', 'Balance', 'Return']]
        else:
            return []

    @property
    def roi(self):
        return self._return()

    @property
    def allocations(self):
        return self._get_allocations()

    @property
    def conntributions(self):
        return self._get_contributions()

    @property
    def investments(self):
        return self._get_investments()

    @property
    def ror(self):
        return self.accountBalance['rateOfReturn']

    @property
    def balance(self):
        return self.accountBalance['balance']

    @property
    def vestedBalance(self):
        return self.accountBalance['vestedBalance']

    @property
    def gain(self):
        return self.accountBalance['gainOrLoss']

    @property
    def loss(self):
        return self.gain

    @property
    def asof(self):
        return self.accountBalance['asOfDate'][:10]


pokemons = {
  "charmander": {
    "health": 72,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Scratch",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Growl",
      "damage": "sleep",
      "ppUse": 5
    },
    "move4": {
      "name": "Flamethrower",
      "damage": "10 - 20 - 30",
      "ppUse": 10
    }
  },
  "bulbasaur": {
    "health": 65,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Scratch",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Vine whip",
      "damage": 25,
      "ppUse": 5
    },
    "move4": {
      "name": "Solar beam",
      "damage": "10 - 20 - 30",
      "ppUse": 10
    }
  },
  "squirtle": {
    "health": 64,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Tackle",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Bubble",
      "damage": 15,
      "ppUse": 2
    },
    "move4": {
      "name": "Hydro Pump",
      "damage": "10 - 20 - 30 / defense",
      "ppUse": 10
    }
  },
  "pikachu": {
    "health": 55,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Scratch",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Shock",
      "damage": 25,
      "ppUse": 5
    },
    "move4": {
      "name": "Thunder Bolt",
      "damage": "20 - 40 - 60 / defense",
      "ppUse": 20
    }
  },
  "pidgey": {
    "health": 60,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Tackle",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Whirlwind",
      "damage": "sleep",
      "ppUse": 5
    },
    "move4": {
      "name": "Razor Wind",
      "damage": "20 - 30",
      "ppUse": 10
    }
  },
  "rattata": {
    "health": 50,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Tackle",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Hyper Fang",
      "damage": 25,
      "ppUse": 5
    },
    "move4": {
      "name": "Super Fang",
      "damage": "10 - 20 - 30",
      "ppUse": 10
    }
  },
  "ekans": {
    "health": 55,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Wrap",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Bite",
      "damage": 15,
      "ppUse": 2
    },
    "move4": {
      "name": "Acid",
      "damage": "40 - 50 - 60",
      "ppUse": 15
    }
  },
  "sandshrew": {
    "health": 70,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Scratch",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Slash",
      "damage": 15,
      "ppUse": 2
    },
    "move4": {
      "name": "Fury Swipes",
      "damage": "10 - 20 - 30 - 40 - 50",
      "ppUse": 15
    }
  },
  "clefairy": {
    "health": 90,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Scratch",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Double Slap",
      "damage": 25,
      "ppUse": 2
    },
    "move4": {
      "name": "Psywave",
      "damage": "10 - 20 - 30",
      "ppUse": 10
    }
  },
  "zubat": {
    "health": 60,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Scratch",
      "damage": 10,
      "ppUse": 0
    },
    "move2": {
      "name": "Supersonic",
      "damage": 25,
      "ppUse": 5
    },
    "move4": {
      "name": "Blind Bite",
      "damage": "60 but has a chance to miss",
      "ppUse": 15
    }
  },
  "onix": {
    "health": 55,
    "pp": 100,
    "baseDef": 5,
    "levels": 1,
    "move1": {
      "name": "Tackle",
      "damage":10,
      "ppUse": 0
    },
    "move2": {
      "name": "Rock Throw",
      "damage": 25,
      "ppUse": 5
    },
    "move4": {
      "name": "Explosion",
      "damage": "20 - 30 - 40",
      "ppUse": 15
    }
  }
}


import os
import uuid

import pytest

from mdbenchmark.migrations import mds_to_dtr

def test_ensure_correct_environment(capsys, monkeypatch):
    # A working environment should not yield any errors
    mds_to_dtr.ensure_correct_environment()

    # Mock an installed `datreant<1.0`
    monkeypatch.delattr("datreant.__version__")
    with pytest.raises(SystemExit):
        mds_to_dtr.ensure_correct_environment()
        out, err = capsys.readouterr()

        assert out == mds_to_dtr.MIGRATION_WARNING.format("datreant.core")

def create_file(bundle, path, filename):
    data = {
        "mdsynthesis": {},
        "categories": {
            "name": "bench",
            "started": "true",
            "module": "gromacs/2016.3",
            "host": "draco",
            "time": 15,
            "gpu": "false",
            "nodes": 1,
        },
        "tags": [],
    }

    file = bundle.join(filename)
    data = str(data).replace("'", '"')
    file.write(str(data))

    return str(file)

@pytest.fixture
def create_sim_files(tmpdir):
    sim_files = []
    directory = tmpdir.mkdir("draco_gromacs").mkdir("2018.1")
    for path in ["1", "2", "3"]:
        bundle = directory.mkdir(path)
        filename = "Sim.{uid}.json".format(uid=uuid.uuid4())
        sim = create_file(bundle, path, filename)
        sim_files.append(sim)

        proxy_filename = ".{filename}.proxy".format(filename=filename)
        proxy = create_file(bundle, path, proxy_filename)
        sim_files.append(proxy)

        tpr = create_file(bundle, path, "md.tpr")
        sim_files.append(tpr)

    return directory, sim_files

def test_search_mdsynthesis_sim_files(create_sim_files):
    directory, files = create_sim_files

    bundles = mds_to_dtr.search_mdsynthesis_sim_files(str(directory))
    files = [file for file in files if file.endswith(".json")]
    assert sorted(bundles) == sorted(files)

def test_convert_to_datreant(create_sim_files):
    directory, files = create_sim_files

    sim_files = [file for file in files if file.endswith(".json")]
    proxy_files = [file for file in files if file.endswith(".proxy")]
    files_to_keep = [file for file in files if ".json" not in file]
    mds_to_dtr.convert_to_datreant(sim_files)

    for path in ["1", "2", "3"]:
        # New directory and files exist
        treant = os.path.join(str(directory), path, ".datreant")
        assert os.path.exists(os.path.join(treant))
        assert os.path.exists(os.path.join(treant, "categories.json"))

    # Old files were deleted correctly, others were kept
    for file in proxy_files:
        assert not os.path.exists(file)
    for file in files_to_keep:
        assert os.path.exists(file)

def test_migrate_to_datreant(tmpdir, capsys, create_sim_files):
    directory, _ = create_sim_files

    with tmpdir.as_cwd():
        assert mds_to_dtr.migrate_to_datreant(".") is None

    mds_to_dtr.migrate_to_datreant(str(directory))
    out, _ = capsys.readouterr()

    output = (
        "Converting old benchmark metadata to new format!\n"
        "Finished converting old benchmarks to new format!\n"
    )

    assert out == output


from data_read import *

import tkinter as tk
from tkinter import Tk, ttk, tix, Frame, Label, filedialog
import configparser
from collections import deque

import matplotlib.pyplot as plt
import matplotlib.pylab as plb

import time

import multiprocessing as mp

import scipy
from scipy import ndimage
import swertka

class Graphica():
    def __init__(self, is_array, is_var):
        # Chart preparing
        plt.ion()
        x = range(5)
        y = range(5)
        # chart lines for arrays and variables
        self.line_a = []
        self.line_v = []

        # max & min for axes
        self.a_minx = 0
        self.a_miny = 0
        self.a_maxx = 1
        self.a_maxy = 1
        self.v_minx = 0
        self.v_miny = 0
        self.v_maxx = 1
        self.v_maxy = 1

    def Draw(self):
        data = q.get()
        arr_data = data[2]
        arr_var = data[3]
        x = range(2)
        y = range(2)

        # need show arrays
        if data[0] == 1:
            # create figure if need
            if plt.get_fignums().count(1) == 0:
                self.fig = plt.figure(num = 1)
                self.line_a.clear()

            # create lines if need
            if len(self.line_a) < len(arr_data):
                for i in range(len(arr_data) - len(self.line_a)):
                    line, = plt.plot(x, y, figure = plt.figure(num = 1))
                    self.line_a.append(line)

            # overgrow protection
            if self.a_maxx > 1000000:
                self.a_maxx = 1;
            if self.a_maxy > 1000000:
                self.a_maxy = 1;
            if self.a_miny < -1000000:
                self.a_miny = 0;

            # match line length and draw lines
            for line in self.line_a:
                if len(line.get_xdata()) != len(arr_data[self.line_a.index(line)]):
                    line.set_xdata(range(len(arr_data[self.line_a.index(line)])))
                line.set_ydata(arr_data[self.line_a.index(line)])

                if self.a_minx > min(line.get_xdata()):
                    self.a_minx = min(line.get_xdata())
                if self.a_maxx < max(line.get_xdata()):
                    self.a_maxx = max(line.get_xdata())

                if self.a_miny > min(line.get_ydata()):
                    self.a_miny = min(line.get_ydata())
                if self.a_maxy < max(line.get_ydata()):
                    self.a_maxy = max(line.get_ydata())
            # set axes
            self.line_a[0].get_axes().axis([self.a_minx, self.a_maxx,
                                                self.a_miny, self.a_maxy])
            self.fig.canvas.draw()
            self.fig.canvas.flush_events()

        # need show variables
        if data[1] == 1:
            if plt.get_fignums().count(2) == 0:
                self.fig_var = plt.figure(num = 2)
                self.line_v.clear()

            if len(self.line_v) < len(arr_var):
                for i in range(len(arr_var) - len(self.line_v)):
                    line, = plt.plot(x, y, figure = plt.figure(num = 2))
                    self.line_v.append(line)

            for line in self.line_v:
                if len(line.get_xdata()) != len(arr_var[self.line_v.index(line)]):
                    line.set_xdata(range(len(arr_var[self.line_v.index(line)])))
                line.set_ydata(arr_var[self.line_v.index(line)])

                if self.v_minx > min(line.get_xdata()):
                    self.v_minx = min(line.get_xdata())
                if self.v_maxx < max(line.get_xdata()):
                    self.v_maxx = max(line.get_xdata())

                if self.v_miny > min(line.get_ydata()):
                    self.v_miny = min(line.get_ydata())
                if self.v_maxy < max(line.get_ydata()):
                    self.v_maxy = max(line.get_ydata())

            self.line_v[0].get_axes().axis([self.v_minx, self.v_maxx,
                                                self.v_miny, self.v_maxy])

            self.fig_var.canvas.draw()
            self.fig_var.canvas.flush_events()

class Application(tk.Frame):
    def __init__(self, master=None):
        self.ini_file = 'setting.ini'
        self.config = configparser.ConfigParser()
        self.config.read(self.ini_file)
        self.stop = False

        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()
        self.setWindowPosition()
        self.master.bind("<Destroy>", self.onDestroy)

        self.gr = Graphica(self.is_show_graph.get(), self.is_show_var_graph.get())

        self.time_queue = deque([])
        self.time_queue_max = 100

    def onDestroy(self, event):
        self.save_geometry()
        plt.close('all')

    def setWindowPosition(self):
        if self.config.has_option('POS', 'geom'):
            g = self.config.get('POS', 'geom').split('+')
            self.master.geometry('+%s+%s' % (g[1], g[2]))

    def createWidgets(self):
        if self.config.has_option('FILES', 'config'):
            self.config_file_name = self.config.get('FILES', 'config')
        else:
            self.config_file_name = ''
        if self.config.has_option('FILES', 'data'):
            self.data_file_name = self.config.get('FILES', 'data')
        else:
            self.data_file_name = ''
        if self.config.has_option('FILES', 'result'):
            self.result_file_name = self.config.get('FILES', 'result')
        else:
            self.result_file_name = ''

        self.ini_var = []
        if self.config.has_section('SELVAR'):
            ini_var_opt = self.config.options('SELVAR')
            self.ini_var = [self.config.get('SELVAR', opt) for opt in self.config.options('SELVAR')]

        # binded variables preparing
        self.is_show_graph = tk.IntVar()
        self.is_show_var_graph = tk.IntVar()
        self.is_not_thinned = tk.IntVar()
        self.is_use_skip = tk.IntVar()
        self.str_skip_b = tk.StringVar()
        self.str_skip_e = tk.StringVar()
        self.str_skip_b.set("0")
        self.str_skip_e.set("0")
        if self.config.has_option('OPTIONS', 'graph'):
            self.is_show_graph.set(self.config.getint('OPTIONS', 'graph'))
        if self.config.has_option('OPTIONS', 'use_skip'):
            self.is_use_skip.set(self.config.getint('OPTIONS', 'use_skip'))
        if self.config.has_option('OPTIONS', 'skip_begin'):
            self.str_skip_b.set(self.config.getint('OPTIONS', 'skip_begin'))
        if self.config.has_option('OPTIONS', 'skip_end'):
            self.str_skip_e.set(self.config.getint('OPTIONS', 'skip_end'))
        if self.config.has_option('OPTIONS', 'var_graph'):
            self.is_show_var_graph.set(self.config.getint('OPTIONS', 'var_graph'))
        if self.config.has_option('OPTIONS', 'not_thinned'):
            self.is_not_thinned.set(self.config.getint('OPTIONS', 'not_thinned'))

        # for variable selecting
        self.varSelVar = tk.StringVar(self)
        self.varSelVar.set("---")

        self.sel_var_list = {}
        self.sel_varframe_list = {}

        # Files group
        g_files = ttk.LabelFrame(self, text = "Files", padding = 5)
        g_files.pack(fill = 'x', expand = 1)
        Label(g_files, text = 'config: ').grid(row = 0)
        Label(g_files, text = 'data: ').grid(row = 1)
        self.l_config = Label(g_files, text = self.config_file_name)
        self.l_data = Label(g_files, text = self.data_file_name)
        self.l_config.grid(row = 0, column = 1)
        self.l_data.grid(row = 1, column = 1)

        self.bt_config = tk.Button(g_files, text = 'select...')
        self.bt_data = tk.Button(g_files, text = 'select...')
        self.bt_config.grid(row = 0, column = 2)
        self.bt_data.grid(row = 1, column = 2)
        self.bt_config['command'] = lambda : self.get_fname('config')
        self.bt_data['command'] = lambda : self.get_fname('data')

        Label(g_files, text = 'result: ').grid(row = 2)
        self.l_result = Label(g_files, text = self.result_file_name)
        self.l_result.grid(row = 2, column = 1)
        self.bt_result = tk.Button(g_files, text = 'select...')
        self.bt_result.grid(row = 2, column = 2)
        self.bt_result['command'] = self.get_result_fname

        # Options group
        g_options = ttk.LabelFrame(self, text = "Options", padding = 5)
        g_options.pack(fill = 'x', expand = 1)

        g_graph_opt = ttk.Frame(g_options)
        g_graph_opt.pack(fill = 'x', expand = 1, ipadx = 5)

        tk.Checkbutton(g_graph_opt, text = 'Show array graph',
                                    variable = self.is_show_graph).pack(side = 'left')
        tk.Checkbutton(g_graph_opt, text = 'Show variable graph',
                                    variable = self.is_show_var_graph).pack(side = 'left')
        tk.Checkbutton(g_graph_opt, text = 'Not thinning data (slowly)',
                                    variable = self.is_not_thinned).pack(side = 'left')

        g_skip = ttk.Frame(g_options)
        g_skip.pack(fill = 'x', expand = 1, ipadx = 5)
        tk.Checkbutton(g_skip, text = 'Use skip',
                            variable = self.is_use_skip).pack(side = 'left')
        Label(g_skip, text = "from begin=").pack(side = 'left')
        e_skip_b = ttk.Entry(g_skip, textvariable = self.str_skip_b)
        e_skip_b.pack(side = 'left')
        Label(g_skip, text = ", to end=").pack(side = 'left')
        e_skip_e = ttk.Entry(g_skip, textvariable = self.str_skip_e)
        e_skip_e.pack(side = 'left')

        # Info group
        g_info = ttk.LabelFrame(self, text = "Info")
        g_info.pack(fill = 'x', expand = 1)

        g_time_info = ttk.Frame(g_info)
        g_time_info.pack(anchor = 'ne', fill = 'x', side = 'left', padx = 10)

        g_sel_var = ttk.Frame(g_info)
        g_sel_var.pack(anchor = 'ne', fill = 'x', side = 'left', padx = 10)

        self.g_vars = ttk.Frame(g_info)
        self.g_vars.pack(anchor = 'ne', fill = 'x', side = 'left', padx = 10)

        Label(g_time_info, text = 'packets: ').grid(row = 0)
        self.l_packets = Label(g_time_info, text = '-')
        self.l_packets.grid(row = 0, column = 1)

        Label(g_time_info, text = 'packet #: ').grid(row = 1)
        self.l_packet = Label(g_time_info, text = '0')
        self.l_packet.grid(row = 1, column = 1)

        Label(g_time_info, text = 'Elapsed time: ').grid(row = 2)
        self.l_time = Label(g_time_info, text = '-')
        self.l_time.grid(row = 2, column = 1)

        Label(g_time_info, text = 'Remained time: ').grid(row = 3)
        self.l_rem_time = Label(g_time_info, text = '-')
        self.l_rem_time.grid(row = 3, column = 1)

        Label(g_time_info, text = 'Expected time: ').grid(row = 4)
        self.l_exp_time = Label(g_time_info, text = '-')
        self.l_exp_time.grid(row = 4, column = 1)

        self.cbSelVar = tk.ttk.Combobox(g_sel_var, textvariable = self.varSelVar)
        self.cbSelVar.grid(row = 0, column = 3)
        self.btAddVarInfo = tk.Button(g_sel_var, text = '+', command = self.add_var_info)
        self.btAddVarInfo.grid(row = 0, column = 4)
        for var_name in self.ini_var:
            self.create_var_info_frame(var_name)

        # Buttons
        self.bt_open = tk.Button(self)
        self.bt_open["text"] = "Open"
        self.bt_open["command"] = self.open_data
        self.bt_open.pack(pady=5)

        self.bt_process = tk.Button(self)
        self.bt_process["text"] = "Process"
        self.bt_process["command"] = self.process_data
        self.bt_process.pack(pady = 5)

        self.bt_stop = tk.Button(self)
        self.bt_stop["text"] = "Stop"
        self.bt_stop["command"] = self.set_stop
        self.bt_stop.pack(pady = 5)

        self.QUIT = tk.Button(self, text="QUIT", fg="red", command=root.destroy)
        self.QUIT.pack(side="bottom", pady = 5)

        self.pb = tk.ttk.Progressbar(self, maximum = 10, )
        self.pb.pack(fill = 'x', expand = 1, pady = 5)
        self.pb["maximum"] = 5      #self.pb.config(maximum=5)

    def get_fname(self, what_file):
        if what_file == 'config':
            ftypes = [('config files', '*.txt'), ('All files', '*')]
        else:
            ftypes = [('data files', '*.bin'), ('All files', '*')]
        dlg = tk.filedialog.Open(self, filetypes = ftypes)
        fname = dlg.show()
        if fname != '':
            if what_file == 'config':
                self.config_file_name = fname
                self.l_config['text'] = self.config_file_name
            else:
                self.data_file_name = fname
                self.l_data['text'] = self.data_file_name

    def get_result_fname(self):
        ftypes = [('text files', '*.txt'), ('All files', '*')]
        dlg = tk.filedialog.SaveAs(self, filetypes = ftypes)
        fname = dlg.show()
        self.result_file_name = fname
        self.l_result['text'] = self.result_file_name

    def open_data(self):
        self.dr = DataRead(self.data_file_name, self.config_file_name)
        self.l_packets["text"] = '%d' % self.dr.block_num

        options = tuple([opt[0] for opt in self.dr.dconf.config if opt[2] == 1])
        self.varSelVar.set(options[0])
        self.cbSelVar['values'] = options

    def set_stop(self):
        self.stop = True

    def add_var_info(self):
        var_name = self.varSelVar.get()
        if list(self.sel_var_list.keys()).count(var_name) == 0:
            self.create_var_info_frame(var_name)

    def create_var_info_frame(self, name):
         _g_ = ttk.Frame(self.g_vars)
         _g_.pack(anchor = 'ne')
         _l_ = tk.Label(_g_, text = '{} = '.format(name))
         _l_.grid(row = 0, column = 0)
         _l_data = tk.Label(_g_, text = '-')
         _l_data.grid(row = 0, column = 1)
         _b_ = tk.Button(_g_, text = 'x')
         _b_.grid(row = 0, column = 2)
         _b_['command'] = lambda : self.del_sel_var(name)
         self.sel_var_list.update({name:_l_data})
         self.sel_varframe_list.update({name:_g_})

    def del_sel_var(self, name):
        _g_ = self.sel_varframe_list[name]
        _g_.destroy()
        del self.sel_var_list[name]
        del self.sel_varframe_list[name]

    def process_data(self):
        self.bt_process["state"] = 'disabled'

        # get skip values
        if self.is_use_skip.get() == 1:
            skip_b = int(self.str_skip_b.get())
            skip_e = int(self.str_skip_e.get())
        # for timer
        t1 = time.perf_counter()
        # skip count
        skip = 0
        if self.is_use_skip.get() == 1:
            skip = skip_b + skip_e
        pack_cnt = skip
        self.pb["maximum"] = self.dr.block_num - skip
        self.pb["value"] = 0

        # open data file
        data_file = open(self.data_file_name, "rb")

        start_h = 11
        start_m = 27
        start_s = 22
        start_t = start_h * 60 * 60 + start_m * 60 + start_s
        # get time of first block
        i = self.dr.get_vars(data_file, 1).__next__()
        self.start_time = i['Sys_t_']
        data_file.seek(0)
        if self.is_use_skip.get() == 1:
            data_file.seek(self.dr.dconf.packet_length * skip_b)
        # open result file
        result_file = open(self.result_file_name, "w", 1)

        # assembling data names to out
        out_vars = ("Time", "Hi", "Sys_t")
        # write the header to the result file
        res_header = '\t'.join(out_vars)
        result_file.writelines('{}{}'.format(res_header, '\n'))

        # data preparing for var chart
        hi_ = []
        sys_dt_ = []
        old_sys_t = 0

        # subprocess initialization
        q.put([0, 0,  0, 0])
        pp = mp.Process(target = self.gr.Draw())

        now_t = time.perf_counter()
        # data processing loop
        for i in self.dr.get_vars(data_file, self.dr.block_num - skip):
            if self.stop:
                self.stop = False
                break
            # ============== Data processing and indication here ===============
            result = swertka.get_swertka(i['CodNonius'], i['Num_Swr'],
                                 i['Num_Div'], i['Diapazon'], i['Srez'])

            # prepare data for file
            curr_t = (i['Sys_t_'] - self.start_time) * 244.15e-6  + start_t
            out_data = {}
            out_data.update({"Time": '%f' % curr_t})
            out_data.update({"Hi": '%f' % (i['Hi'] / 8 - 32)})
            out_data.update({"Sys_t": '%d' % i['Sys_t_']})

            # write data to file
            out_data_str = [out_data[ind] for ind in out_vars]
            result_file.writelines('{}{}'.format('\t'.join(out_data_str), '\n'))

            # data for charts
            hi_.append(i['Hi'] / 8 - 32)

            if (self.is_show_graph.get() == 1) or (self.is_show_var_graph.get() == 1):
                arr_data = []
                arr_data.append(result)
                arr_data.append(i['Swertka'][0:i['Num_Swr']])
                arr_var = [hi_]

                if self.is_not_thinned.get():
                    q.put([self.is_show_graph.get(),
                                self.is_show_var_graph.get(), arr_data, arr_var])
                    self.gr.Draw()
                else:
                    if not pp.is_alive():
                        q.put([self.is_show_graph.get(),
                                self.is_show_var_graph.get(), arr_data, arr_var])
                        pp = mp.Process(target = self.gr.Draw())
                        pp.start()

            # show variables on GUI
            for var in self.sel_var_list.keys():
                if list(i.keys()).count(var) > 0:
                    self.sel_var_list[var]["text"] = str(i[var])
                if list(out_data.keys()).count(var) > 0:
                    self.sel_var_list[var]["text"] = str(out_data[var])
            # ==================================================================
            self.l_packet["text"] = str(pack_cnt)
            pack_cnt = pack_cnt + 1

            # progress bar and timer
            self.pb.step()
            if self.pb["value"] > 0:
                old_t = now_t
                now_t = time.perf_counter()
                now_dt = now_t - old_t
                self.time_queue.append(now_dt)

                if len(self.time_queue) > self.time_queue_max:
                    self.time_queue.popleft()

                #t_aver = (now_t - self.time_queue[0]) / len(self.time_queue)
                if len(self.time_queue) > 0:
                    t_aver = sum(self.time_queue) / len(self.time_queue)
                else:
                    t_aver = 0

                t2 = now_t - t1
                self.l_time["text"] = self.time_to_text(t2)
                #t_expected = (t2 / self.pb["value"]) * self.pb["maximum"]
                t_expected = (t_aver) * self.pb["maximum"]
                self.l_exp_time["text"] = self.time_to_text(t_expected)
                #t_remained = t_expected - t2
                #self.l_rem_time["text"] = self.time_to_text(t_remained)
                t_remained = t_aver * (self.pb["maximum"] - self.pb["value"])
                self.l_rem_time["text"] = self.time_to_text(t_remained)

            self.update()

        data_file.close()
        result_file.close()
        self.bt_process["state"] = 'normal'

    def time_to_text(self, t):
        Secs = t % 60
        Mins = (t/60) % 60
        Hrs = (t/3600) % 60
        return '%.2d:%.2d:%.2d' % (Hrs, Mins, Secs)

    def save_app_config(self):
        if not self.config.has_section('FILES'):
            self.config.add_section('FILES')
        self.config.set('FILES', 'config', self.config_file_name)
        self.config.set('FILES', 'data', self.data_file_name)
        self.config.set('FILES', 'result', self.result_file_name)
        if not self.config.has_section('OPTIONS'):
            self.config.add_section('OPTIONS')
        self.config.set('OPTIONS', 'graph', str(self.is_show_graph.get()))
        self.config.set('OPTIONS', 'use_skip', str(self.is_use_skip.get()))
        self.config.set('OPTIONS', 'skip_begin', self.str_skip_b.get())
        self.config.set('OPTIONS', 'skip_end', self.str_skip_e.get())
        self.config.set('OPTIONS', 'var_graph', str(self.is_show_var_graph.get()))
        self.config.set('OPTIONS', 'not_thinned', str(self.is_not_thinned.get()))

        if self.config.has_section('SELVAR'):
            if len(self.config.options('SELVAR')) > 0:
                self.config.remove_section('SELVAR')
        if not self.config.has_section('SELVAR'):
            self.config.add_section('SELVAR')
        for var in self.sel_var_list.keys():
            self.config.set('SELVAR', var, var)

        with open(self.ini_file, 'w') as configfile:
            self.config.write(configfile)

    def save_geometry(self):
        if not self.config.has_section('POS'):
            self.config.add_section('POS')
        self.config.set('POS', 'geom', self.master.geometry(None))

if __name__ == '__main__':
    root = tk.Tk()
    q = mp.Queue()
    app = Application(master=root)
    app.mainloop()
    app.save_app_config()


import numpy as np
import torch

def one_hot(x, num_classes, on_value=1., off_value=0.):
    x = x.long().view(-1, 1)
    return torch.full((x.size()[0], num_classes), off_value, device=x.device).scatter_(1, x, on_value)

def mixup_target(target, num_classes, lam=1., smoothing=0.0):
    off_value = smoothing / num_classes
    on_value = 1. - smoothing + off_value
    y1 = one_hot(target, num_classes, on_value=on_value, off_value=off_value)
    y2 = one_hot(target.flip(0), num_classes, on_value=on_value, off_value=off_value)
    return y1 * lam + y2 * (1. - lam)

def rand_bbox(img_shape, lam, margin=0., count=None):
    """ Standard CutMix bounding-box
    Generates a random square bbox based on lambda value. This impl includes
    support for enforcing a border margin as percent of bbox dimensions.

    Args:
        img_shape (tuple): Image shape as tuple
        lam (float): Cutmix lambda value
        margin (float): Percentage of bbox dimension to enforce as margin (reduce amount of box outside image)
        count (int): Number of bbox to generate
    """
    ratio = np.sqrt(1 - lam)
    img_h, img_w = img_shape[-2:]
    cut_h, cut_w = int(img_h * ratio), int(img_w * ratio)
    margin_y, margin_x = int(margin * cut_h), int(margin * cut_w)
    cy = np.random.randint(0 + margin_y, img_h - margin_y, size=count)
    cx = np.random.randint(0 + margin_x, img_w - margin_x, size=count)
    yl = np.clip(cy - cut_h // 2, 0, img_h)
    yh = np.clip(cy + cut_h // 2, 0, img_h)
    xl = np.clip(cx - cut_w // 2, 0, img_w)
    xh = np.clip(cx + cut_w // 2, 0, img_w)
    return yl, yh, xl, xh

def rand_bbox_minmax(img_shape, minmax, count=None):
    """ Min-Max CutMix bounding-box
    Inspired by Darknet cutmix impl, generates a random rectangular bbox
    based on min/max percent values applied to each dimension of the input image.

    Typical defaults for minmax are usually in the  .2-.3 for min and .8-.9 range for max.

    Args:
        img_shape (tuple): Image shape as tuple
        minmax (tuple or list): Min and max bbox ratios (as percent of image size)
        count (int): Number of bbox to generate
    """
    assert len(minmax) == 2
    img_h, img_w = img_shape[-2:]
    cut_h = np.random.randint(int(img_h * minmax[0]), int(img_h * minmax[1]), size=count)
    cut_w = np.random.randint(int(img_w * minmax[0]), int(img_w * minmax[1]), size=count)
    yl = np.random.randint(0, img_h - cut_h, size=count)
    xl = np.random.randint(0, img_w - cut_w, size=count)
    yu = yl + cut_h
    xu = xl + cut_w
    return yl, yu, xl, xu

def cutmix_bbox_and_lam(img_shape, lam, ratio_minmax=None, correct_lam=True, count=None):
    """ Generate bbox and apply lambda correction.
    """
    if ratio_minmax is not None:
        yl, yu, xl, xu = rand_bbox_minmax(img_shape, ratio_minmax, count=count)
    else:
        yl, yu, xl, xu = rand_bbox(img_shape, lam, count=count)
    if correct_lam or ratio_minmax is not None:
        bbox_area = (yu - yl) * (xu - xl)
        lam = 1. - bbox_area / float(img_shape[-2] * img_shape[-1])
    return (yl, yu, xl, xu), lam

class Mixup:
    """ Mixup/Cutmix that applies different params to each element or whole batch

    Args:
        mixup_alpha (float): mixup alpha value, mixup is active if > 0.
        cutmix_alpha (float): cutmix alpha value, cutmix is active if > 0.
        cutmix_minmax (List[float]): cutmix min/max image ratio, cutmix is active and uses this vs alpha if not None.
        prob (float): probability of applying mixup or cutmix per batch or element
        switch_prob (float): probability of switching to cutmix instead of mixup when both are active
        mode (str): how to apply mixup/cutmix params (per 'batch', 'pair' (pair of elements), 'elem' (element)
        correct_lam (bool): apply lambda correction when cutmix bbox clipped by image borders
        label_smoothing (float): apply label smoothing to the mixed target tensor
        num_classes (int): number of classes for target
    """
    def __init__(self, mixup_alpha=1., cutmix_alpha=0., cutmix_minmax=None, prob=1.0, switch_prob=0.5,
                 mode='batch', correct_lam=True, label_smoothing=0.1, num_classes=1000):
        self.mixup_alpha = mixup_alpha
        self.cutmix_alpha = cutmix_alpha
        self.cutmix_minmax = cutmix_minmax
        if self.cutmix_minmax is not None:
            assert len(self.cutmix_minmax) == 2
            # force cutmix alpha == 1.0 when minmax active to keep logic simple & safe
            self.cutmix_alpha = 1.0
        self.mix_prob = prob
        self.switch_prob = switch_prob
        self.label_smoothing = label_smoothing
        self.num_classes = num_classes
        self.mode = mode
        self.correct_lam = correct_lam  # correct lambda based on clipped area for cutmix
        self.mixup_enabled = True  # set to false to disable mixing (intended tp be set by train loop)

    def _params_per_elem(self, batch_size):
        lam = np.ones(batch_size, dtype=np.float32)
        use_cutmix = np.zeros(batch_size, dtype=bool)
        if self.mixup_enabled:
            if self.mixup_alpha > 0. and self.cutmix_alpha > 0.:
                use_cutmix = np.random.rand(batch_size) < self.switch_prob
                lam_mix = np.where(
                    use_cutmix,
                    np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size),
                    np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size))
            elif self.mixup_alpha > 0.:
                lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha, size=batch_size)
            elif self.cutmix_alpha > 0.:
                use_cutmix = np.ones(batch_size, dtype=bool)
                lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha, size=batch_size)
            else:
                assert False, "One of mixup_alpha > 0., cutmix_alpha > 0., cutmix_minmax not None should be true."
            lam = np.where(np.random.rand(batch_size) < self.mix_prob, lam_mix.astype(np.float32), lam)
        return lam, use_cutmix

    def _params_per_batch(self):
        lam = 1.
        use_cutmix = False
        if self.mixup_enabled and np.random.rand() < self.mix_prob:
            if self.mixup_alpha > 0. and self.cutmix_alpha > 0.:
                use_cutmix = np.random.rand() < self.switch_prob
                lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha) if use_cutmix else \
                    np.random.beta(self.mixup_alpha, self.mixup_alpha)
            elif self.mixup_alpha > 0.:
                lam_mix = np.random.beta(self.mixup_alpha, self.mixup_alpha)
            elif self.cutmix_alpha > 0.:
                use_cutmix = True
                lam_mix = np.random.beta(self.cutmix_alpha, self.cutmix_alpha)
            else:
                assert False, "One of mixup_alpha > 0., cutmix_alpha > 0., cutmix_minmax not None should be true."
            lam = float(lam_mix)
        return lam, use_cutmix

    def _mix_elem(self, x):
        batch_size = len(x)
        lam_batch, use_cutmix = self._params_per_elem(batch_size)
        x_orig = x.clone()  # need to keep an unmodified original for mixing source
        for i in range(batch_size):
            j = batch_size - i - 1
            lam = lam_batch[i]
            if lam != 1.:
                if use_cutmix[i]:
                    (yl, yh, xl, xh), lam = cutmix_bbox_and_lam(
                        x[i].shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam)
                    x[i][:, yl:yh, xl:xh] = x_orig[j][:, yl:yh, xl:xh]
                    lam_batch[i] = lam
                else:
                    x[i] = x[i] * lam + x_orig[j] * (1 - lam)
        return torch.tensor(lam_batch, device=x.device, dtype=x.dtype).unsqueeze(1)

    def _mix_pair(self, x):
        batch_size = len(x)
        lam_batch, use_cutmix = self._params_per_elem(batch_size // 2)
        x_orig = x.clone()  # need to keep an unmodified original for mixing source
        for i in range(batch_size // 2):
            j = batch_size - i - 1
            lam = lam_batch[i]
            if lam != 1.:
                if use_cutmix[i]:
                    (yl, yh, xl, xh), lam = cutmix_bbox_and_lam(
                        x[i].shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam)
                    x[i][:, yl:yh, xl:xh] = x_orig[j][:, yl:yh, xl:xh]
                    x[j][:, yl:yh, xl:xh] = x_orig[i][:, yl:yh, xl:xh]
                    lam_batch[i] = lam
                else:
                    x[i] = x[i] * lam + x_orig[j] * (1 - lam)
                    x[j] = x[j] * lam + x_orig[i] * (1 - lam)
        lam_batch = np.concatenate((lam_batch, lam_batch[::-1]))
        return torch.tensor(lam_batch, device=x.device, dtype=x.dtype).unsqueeze(1)

    def _mix_batch(self, x):
        lam, use_cutmix = self._params_per_batch()
        if lam == 1.:
            return 1.
        if use_cutmix:
            (yl, yh, xl, xh), lam = cutmix_bbox_and_lam(
                x.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam)
            x[:, :, yl:yh, xl:xh] = x.flip(0)[:, :, yl:yh, xl:xh]
        else:
            x_flipped = x.flip(0).mul_(1. - lam)
            x.mul_(lam).add_(x_flipped)
        return lam

    def __call__(self, x, target):
        assert len(x) % 2 == 0, 'Batch size should be even when using this'
        if self.mode == 'elem':
            lam = self._mix_elem(x)
        elif self.mode == 'pair':
            lam = self._mix_pair(x)
        else:
            lam = self._mix_batch(x)
        target = mixup_target(target, self.num_classes, lam, self.label_smoothing)
        return x, target

class FastCollateMixup(Mixup):
    """ Fast Collate w/ Mixup/Cutmix that applies different params to each element or whole batch

    A Mixup impl that's performed while collating the batches.
    """

    def _mix_elem_collate(self, output, batch, half=False):
        batch_size = len(batch)
        num_elem = batch_size // 2 if half else batch_size
        assert len(output) == num_elem
        lam_batch, use_cutmix = self._params_per_elem(num_elem)
        for i in range(num_elem):
            j = batch_size - i - 1
            lam = lam_batch[i]
            mixed = batch[i][0]
            if lam != 1.:
                if use_cutmix[i]:
                    if not half:
                        mixed = mixed.copy()
                    (yl, yh, xl, xh), lam = cutmix_bbox_and_lam(
                        output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam)
                    mixed[:, yl:yh, xl:xh] = batch[j][0][:, yl:yh, xl:xh]
                    lam_batch[i] = lam
                else:
                    mixed = mixed.astype(np.float32) * lam + batch[j][0].astype(np.float32) * (1 - lam)
                    np.rint(mixed, out=mixed)
            output[i] += torch.from_numpy(mixed.astype(np.uint8))
        if half:
            lam_batch = np.concatenate((lam_batch, np.ones(num_elem)))
        return torch.tensor(lam_batch).unsqueeze(1)

    def _mix_pair_collate(self, output, batch):
        batch_size = len(batch)
        lam_batch, use_cutmix = self._params_per_elem(batch_size // 2)
        for i in range(batch_size // 2):
            j = batch_size - i - 1
            lam = lam_batch[i]
            mixed_i = batch[i][0]
            mixed_j = batch[j][0]
            assert 0 <= lam <= 1.0
            if lam < 1.:
                if use_cutmix[i]:
                    (yl, yh, xl, xh), lam = cutmix_bbox_and_lam(
                        output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam)
                    patch_i = mixed_i[:, yl:yh, xl:xh].copy()
                    mixed_i[:, yl:yh, xl:xh] = mixed_j[:, yl:yh, xl:xh]
                    mixed_j[:, yl:yh, xl:xh] = patch_i
                    lam_batch[i] = lam
                else:
                    mixed_temp = mixed_i.astype(np.float32) * lam + mixed_j.astype(np.float32) * (1 - lam)
                    mixed_j = mixed_j.astype(np.float32) * lam + mixed_i.astype(np.float32) * (1 - lam)
                    mixed_i = mixed_temp
                    np.rint(mixed_j, out=mixed_j)
                    np.rint(mixed_i, out=mixed_i)
            output[i] += torch.from_numpy(mixed_i.astype(np.uint8))
            output[j] += torch.from_numpy(mixed_j.astype(np.uint8))
        lam_batch = np.concatenate((lam_batch, lam_batch[::-1]))
        return torch.tensor(lam_batch).unsqueeze(1)

    def _mix_batch_collate(self, output, batch):
        batch_size = len(batch)
        lam, use_cutmix = self._params_per_batch()
        if use_cutmix:
            (yl, yh, xl, xh), lam = cutmix_bbox_and_lam(
                output.shape, lam, ratio_minmax=self.cutmix_minmax, correct_lam=self.correct_lam)
        for i in range(batch_size):
            j = batch_size - i - 1
            mixed = batch[i][0]
            if lam != 1.:
                if use_cutmix:
                    mixed = mixed.copy()  # don't want to modify the original while iterating
                    mixed[:, yl:yh, xl:xh] = batch[j][0][:, yl:yh, xl:xh]
                else:
                    mixed = mixed.astype(np.float32) * lam + batch[j][0].astype(np.float32) * (1 - lam)
                    np.rint(mixed, out=mixed)
            output[i] += torch.from_numpy(mixed.astype(np.uint8))
        return lam

    def __call__(self, batch, _=None):
        batch_size = len(batch)
        assert batch_size % 2 == 0, 'Batch size should be even when using this'
        half = 'half' in self.mode
        if half:
            batch_size //= 2
        output = torch.zeros((batch_size, *batch[0][0].shape), dtype=torch.uint8)
        if self.mode == 'elem' or self.mode == 'half':
            lam = self._mix_elem_collate(output, batch, half=half)
        elif self.mode == 'pair':
            lam = self._mix_pair_collate(output, batch)
        else:
            lam = self._mix_batch_collate(output, batch)
        target = torch.tensor([b[1] for b in batch], dtype=torch.int64)
        target = mixup_target(target, self.num_classes, lam, self.label_smoothing)
        target = target[:batch_size]
        return output, target


#!C:\Python34\python.exe

import sqlite3, cgi

def htmlTop(html):
    print("""Content-type:text\html\n\n
    <!DOCTYPE html>

    <title> My First Script </title>
    <meta charset='utf-8'/>

    <form method="post" action="/cgi-bin/list.py">
    Name:  <input type="text" name="nameInput" placeholder="eg Latte..." autofocus required>

    Price:  <input type="number" name="priceInput" placeholder="00.00" step="0.01" required>

    Type:  <select name="typeInput">

 {0}""".format(html))

def addItems(itemList):
    html = ""
    for item in itemList:
        html += ("<option>"+ str(item[0]) +"</option>")
    html += ("</select>")
    return html

def htmlTail():
    print("""
    <input type="submit" value="Submit">
    </form>

    """)

def getTypes():
    with sqlite3.connect("ScriptingDatabase.db") as db:
        cursor = db.cursor()
        cursor.execute("SELECT TypeName From ItemType")
        itemTypes = cursor.fetchall()
    return itemTypes

def main():
    try:
        itemList = getTypes()
        html = addItems(itemList)
        htmlTop(html)
        htmlTail()

    except:
        cgi.print_exception()

if __name__ == '__main__':
    main()


months = [
	31, # Jan
	28, # Feb
	31, # Mar
	30, # Apr
	31, # May
	30, # Jun
	31, # Jul
	31, # Aug
	30, # Sep
	31, # Oct
	30, # Nov
	31, # Dec
]

def solution(start, end):
	total_sundays = 0
	current_day = 0
	for year in range(1900, 2001):
		count_year = year >= start and year < end
		for month in range(0, 12):
			days = months[month]
			if is_leap_year(year) and month == 1:
				days += 1
			for day in range(0, days):
				if day == 1 and current_day == 6 and count_year:
					total_sundays += 1
				current_day+=1
				if current_day == 7:
					current_day = 0
	print(total_sundays)

def is_leap_year(year):
	if year % 4 != 0:
		return False
	elif year % 100 != 0:
		return True
	elif year % 400 != 0:
		return False
	else:
		return True

if __name__ == '__main__':
	solution(1901, 2001)


#!/usr/bin/env python
"""
Usage:
    train.py [options] TRAIN_DATA_PATH VALID_DATA_PATH MODEL_FILENAME

Options:
    --aml                         Run this in Azure ML
    --amp                         Use AMP
    --azure-info=<path>           Azure authentication information file (JSON). Used to load data from Azure storage.
    --max-num-epochs=<epochs>     The maximum number of epochs to run training for. [default: 100]
    --max-files-per-fold=<n>      The maximum number of files to include in each fold.
    --minibatch-size=<size>       The minibatch size. [default: 30]
    --validate-after=<n_samples>  Run the validation after seen n_samples. [default: 1000000]
    --restore-path=<path>         The path to previous model file for starting from previous checkpoint.
    --sequential                  Do not parallelize data loading. Makes debugging easier.
    --quiet                       Do not show progress bar.
    -h --help                     Show this screen.
    --debug                       Enable debug routines. [default: False]
"""
import logging
import random
from pathlib import Path
from typing import Callable, Iterator, Optional

from docopt import docopt
from dpu_utils.utils import RichPath, load_jsonl_gz, run_and_debug
from ptgnn.baseneuralmodel import AbstractNeuralModel, ModelTrainer
from ptgnn.baseneuralmodel.utils.amlutils import configure_logging, log_run
from ptgnn.baseneuralmodel.utils.data import LazyDataIterable

from buglab.models.greatreimplementation import GreatVarMisuse
from buglab.models.utils import LinearWarmupScheduler, optimizer

LOGGER = logging.getLogger(__name__)

def load_all_json_l_gz(
    path: RichPath,
    shuffle: bool = False,
    take_only_first_n_files: Optional[int] = None,
    limit_num_yielded_elements: Optional[int] = None,
) -> Iterator:
    all_files = sorted(path.iterate_filtered_files_in_dir("*.jsonl.gz"))
    if take_only_first_n_files is not None:
        all_files = all_files[:take_only_first_n_files]
    if shuffle:
        random.shuffle(all_files)

    sample_idx = 0
    for jsonlgz_file in all_files:
        try:
            for element in jsonlgz_file.read_as_jsonl():
                if element is not None:
                    sample_idx += 1
                    yield element
                if limit_num_yielded_elements is not None and sample_idx > limit_num_yielded_elements:
                    return
        except Exception as e:
            print(f"Error loading {jsonlgz_file}: {e}.")

def construct_data_loading_callable(
    data_path: RichPath,
    shuffle: bool = False,
    max_files_per_fold: Optional[int] = None,
    limit_num_yielded_elements: Optional[int] = None,
) -> Callable[[], Iterator]:
    return lambda: load_all_json_l_gz(
        data_path,
        shuffle=shuffle,
        take_only_first_n_files=max_files_per_fold,
        limit_num_yielded_elements=limit_num_yielded_elements,
    )

def run(arguments):
    if arguments["--aml"]:
        import torch
        from azureml.core.run import Run

        aml_ctx = Run.get_context()
        assert torch.cuda.is_available(), "No CUDA available. Aborting training."
    else:
        aml_ctx = None

    log_path = configure_logging(aml_ctx)

    azure_info_path = arguments.get("--azure-info", None)

    max_files_per_fold = arguments["--max-files-per-fold"]
    if max_files_per_fold is not None:
        max_files_per_fold = int(max_files_per_fold)

    training_data_path = RichPath.create(arguments["TRAIN_DATA_PATH"], azure_info_path)
    arguments: dict
    training_data = LazyDataIterable(
        construct_data_loading_callable(
            training_data_path,
            shuffle=True,
            max_files_per_fold=max_files_per_fold,
            limit_num_yielded_elements=int(arguments["--validate-after"]),
        )
    )

    validation_data_path = RichPath.create(arguments["VALID_DATA_PATH"], azure_info_path)
    validation_data = LazyDataIterable(
        construct_data_loading_callable(
            validation_data_path,
            max_files_per_fold=max_files_per_fold,
        )
    )

    model_path = Path(arguments["MODEL_FILENAME"])
    initialize_metadata = True
    if arguments.get("--restore-path", None) is not None:
        import torch

        LOGGER.info("Resuming training from %s." % model_path)
        initialize_metadata = False
        model, nn = AbstractNeuralModel.restore_model(
            model_path, torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        )
    else:
        nn = None
        model = GreatVarMisuse(
            {
                "num_layers": 10,
                "num_heads": 8,
                "intermediate_dimension": 2048,
                "dropout_rate": 0.1,
                "rezero_mode": "off",
                "normalization_mode": "prenorm",
            },
            embedding_dim=512,
            vocab_size=10240,  # Closest multiple of 64
        )

    trainer = ModelTrainer(
        model,
        model_path,
        max_num_epochs=int(arguments["--max-num-epochs"]),
        minibatch_size=int(arguments["--minibatch-size"]),
        optimizer_creator=optimizer,
        clip_gradient_norm=0.25,  # https://github.com/VHellendoorn/ICLR20-Great/blob/472069aba236244f8e06f9f98c565df7f9b2ea64/running/run_model.py#L73
        scheduler_creator=lambda o: LinearWarmupScheduler(o),
        enable_amp=arguments["--amp"],
    )
    if nn is not None:
        trainer.neural_module = nn

    trainer.register_train_epoch_end_hook(
        lambda model, nn, epoch, metrics: log_run(aml_ctx, "train", model, epoch, metrics)
    )
    trainer.register_validation_epoch_end_hook(
        lambda model, nn, epoch, metrics: log_run(aml_ctx, "valid", model, epoch, metrics)
    )

    trainer.train(
        training_data,
        validation_data,
        show_progress_bar=not arguments["--quiet"],
        initialize_metadata=initialize_metadata,
        parallelize=not arguments["--sequential"],
        patience=10,
    )

    if aml_ctx is not None:
        aml_ctx.upload_file(name="model.pkl.gz", path_or_stream=str(model_path))
        aml_ctx.upload_file(name="full.log", path_or_stream=log_path)

if __name__ == "__main__":
    args = docopt(__doc__)

    run_and_debug(lambda: run(args), args.get("--debug", False))


# 34.

def remove_name(emp):
    try:
        emp.remove(input())
    except ValueError:
        print("Type existing name")
        return remove_name(emp)

user_emp = ["John", "Jack", "James", "Roy", "Ray"]
print(f"There are {len(user_emp)} employees: {user_emp}")

print("Enter an employee to remove")
remove_name(user_emp)
print(f"There are {len(user_emp)} employees: {user_emp}")


#making function flexible
#using argument as *args which have type tuple
#and **kwargs which have type dictionary
def add(*args):
    sum1=0
    for i in args:
        sum1=sum1+i
    return sum1
print(add(1,2,3,4))

def detail(**kwargs):
    for i,j in kwargs.items():
        print(f"{i}:{j}")
my=detail(name="rohit",gender="male",age=20,)
print(my)

#priority of arguments
''' parameter
    *args
    default parametr
    **kwargs'''
def mult1(num,*args):
    product=1
    for i in args:
        product=product*i
    return product
print(mult1(4,2,3))
#here we get value 6 because num take one value i.e. 4


import pandas as pd
import numpy as np
# IMPORT PYWR MODULE FUNCTIONS
from pywr.parameters import Parameter

class VolumeAreaCurve(Parameter):
    def __init__(self, model, folder, reservoir_name):
        super().__init__(model)
        self._model = model
        self._reservoir_name = reservoir_name
        self._parameters = pd.read_csv("{}/volume_area_parameters.csv".format(folder)).loc[:, self._reservoir_name.lower()]
        print("reservoir parameters", self._parameters)

    def power_function(self, x, a, b, c):
        y = a*x**b + c
        return np.maximum(0, y)

    def value(self, timestep, scenario_index):
        current_storage = self._model.nodes['{}_reservoir'.format(self._reservoir_name)].volume
        # print(current_storage)
        area = self.power_function(x=current_storage, a=self._parameters[0], b=self._parameters[1], c=self._parameters[2])
        # print(area)
        return area

    @classmethod
    def load(cls, model, data):
        """ This is the function that actually reads the
             data defined in the node from which it is called """
        _url = data.pop("url")
        url = _url[0]
        name = _url[1]
        # print(value)
        print("reservoir", name)
        # print(data)
        c = cls(model=model, folder=url, reservoir_name=name) # here we call the
        return c


import os
import threading

from PyQt5.QtCore import QObject, QSize, Qt, QThread, QUrl, pyqtSignal
from PyQt5.QtGui import QDesktopServices, QPalette, QPixmap
from PyQt5.QtWidgets import (QFrame, QGraphicsOpacityEffect, QLabel,
                             QPushButton, QSizePolicy, QWidget)

from addtabdialog import AddTabDialog

MIN_FOR_CLOSE = 100

class DropArea(QLabel):
    # INITIALIZE SIGNALS
    tabReordered = pyqtSignal(QWidget, int)
    tabAdded = pyqtSignal(QWidget, int)
    tabDeleted = pyqtSignal(QWidget)
    imageLoaded = pyqtSignal()

    def __init__(self, options, tabNumber, driver, minWidth, minHeight, aspectRatio, imageFolder, tabFileName, archiveTabFileName):
        super().__init__()

        # CONNECT EVENTS (MOUSE/SLOTS & SIGNALS)
        self.mousePressEvent = self.areaClicked
        self.mouseReleaseEvent = self.areaReleased

        # INITIALIZE CLASS VARIABLES
        self.taken = False
        self.startClick = 0
        self.endClick = 0
        self.aspectRatio = aspectRatio
        self.minWidth = minWidth
        self.minHeight = minHeight
        self.imageFolder = imageFolder
        self.driver = driver
        self.options = options
        self.tabFileName = tabFileName
        self.archiveTabFileName = archiveTabFileName

        self.setMinimumSize(self.minWidth, self.minHeight)
        self.setFrameStyle(QFrame.Plain)
        self.setAlignment(Qt.AlignCenter)
        self.setAcceptDrops(True)
        self.setAutoFillBackground(True)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
        self.setCursor(Qt.PointingHandCursor)
        self.setMouseTracking(True)

        self.tabNumber = tabNumber
        self.defaultTab('Drag URL Here')

    # ON MOUSE ENTER
    def enterEvent(self, event):
        if self.taken:
            self.setToolTip(self.url)
            self.setToolTipDuration(1000)
            self.button.setVisible(True)
        else: self.setBackgroundRole(QPalette.Highlight)

    # ON MOUSE LEAVE
    def leaveEvent(self, event):
        if not self.taken: self.setBackgroundRole(QPalette.Light)
        else: self.button.setVisible(False)

    def areaClicked(self, event):
        self.startClick = event.pos()
        if self.taken:
            self.setFrameStyle(QFrame.Plain | QFrame.Box)
            self.setLineWidth(5)

    # IF DRAG UP REMOVE TAB, IF CLICK OPEN URL
    def areaReleased(self, event):
        self.endClick = event.pos()
        xDiff = self.endClick.x() - self.startClick.x()
        yDiff = abs(self.endClick.y() - self.startClick.y())

        # IF X/Y DELTA GREATER THAN RESPECTIVE MINS REORDER/DELETE
        if yDiff > MIN_FOR_CLOSE or abs(xDiff) > self.sizeHint().width():
            # IF Y DELTA GREATER THAN MIN CLOSE/DELETE TAB
            if yDiff > MIN_FOR_CLOSE:self.tabDeleted.emit(self)
            # IF X DELTA GREATER THAN TAB WIDTH REORDER TAB
            elif abs(xDiff) > self.sizeHint().width():
                if self.taken:
                    index = (self.tabNumber-1) % 3
                    # GET TABS TO MOVE E.G. -1 (1 LEFT) OR 2 (2 RIGHT)
                    tabsToSwap = (int)(xDiff/self.sizeHint().width())
                    left = True if (xDiff < 0) else False
                    # IF NOT LEFT MOST TAB AND TRYING TO DRAG LEFT
                    if not (index == 0 and left):
                        #GET PARENT WIDGET AND MOVE TAB
                        parent = self.options.tabRows[int((self.tabNumber-1)/self.options.tabsPerRow)].layout()
                        parent.removeWidget(self)
                        parent.insertWidget(index + tabsToSwap, self)
                        # EMIT SIGNAL SO LIST CAN BE REORGANIZED AND CHAGNES SAVED TO FILE
                        self.tabReordered.emit(self, tabsToSwap)
        # OPEN TAB IN BROWSER OR IF EMPTY ENTER URL MANUALLY
        else:
            if self.taken: QDesktopServices.openUrl(QUrl(self.url))
            else: dialog = AddTabDialog(self)

        # RESET FRAME WHEN NOT CLICKED
        if self.taken:
            self.setFrameStyle(QFrame.NoFrame)
            self.setLineWidth(2)

    # SET TEXT TO DROP AND CHANGE COLOR
    def dragEnterEvent(self, event):
        if not self.taken:
            self.highlightTab()
            event.acceptProposedAction()

    def dragMoveEvent(self, event):
        event.setDropAction(Qt.MoveAction)

    def dragLeaveEvent(self, event):
        self.defaultTab()
        event.accept()

    #IF NOT TAKEN GET IMAGE AND SAVE TAB
    def dropEvent(self, event):
        if not self.taken:
            self.defaultTab('Loading...')
            self.addCloseButton()
            self.url = event.mimeData().text()

            duplicateTab = self.checkDuplicateTab(self.url, self.tabFileName)
            duplicateArchiveTab = self.checkDuplicateTab(self.url, self.archiveTabFileName)
            if duplicateTab or duplicateArchiveTab:
                if duplicateTab: self.setDuplicateTab(self.url)
                elif duplicateArchiveTab: self.setDuplicateArchiveTab(self.url)
                self.loadSave()
            else:
                t = threading.Thread(target=self.downloadImage, args=(self.url,True))
                t.start()

            self.taken = True
            event.acceptProposedAction()

    def loadSave(self):
        self.setLocalPixmap()
        self.saveTab()
        self.tabAdded.emit(self, self.tabNumber)

    # ON RESIZE UPDATE PIXMAP SIZE
    def resizeEvent(self, e):
        if self.pixmap() != None: self.setPixmap(self._pixmap.scaled(self.sizeHint(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
        self.setFixedHeight(self.sizeHint().height())

    # OVERLOAD SIZEHINT SO IT GETS SIZE OF PARENT LAYOUT CHILDREN / PARENT LAYOUT WIDTH
    def sizeHint(self):
        # WHEN CLEARING TABS SOMETIMES THE ROW IS NOT THERE WHEN RESIZE EVENT OCCURS
        if self.parent() != None:
            if self.parent().layout().itemAt(0).count() > 0:
                hasAttr = hasattr(self.parent().layout().itemAt(0), "count")
                if hasAttr:
                    count = self.parent().layout().itemAt(0).count()
                    width = self.parent().width() / count
                    if width >= self.minWidth:
                        return QSize(width, width*self.aspectRatio)
        return QSize(self.minWidth, self.minHeight)

    def addCloseButton(self):
        self.button = QPushButton('x', self)
        buttonOpacity = QGraphicsOpacityEffect()
        buttonOpacity.setOpacity(0.45)
        self.button.setGraphicsEffect(buttonOpacity)
        self.button.move(0, 0)
        self.button.show()
        self.button.setVisible(False)
        self.button.clicked.connect(lambda: self.tabDeleted.emit(self))

    # LOAD TAB PIXMAP AND SET CLASS VARIABLES
    def load(self, url, imagePath):
        self.taken = True
        self.url = url

        setImagePath = False
        if self.checkFileExists(self.archiveTabFileName):
            with open(self.archiveTabFileName, 'r') as f:
                for line in f:
                    currentUrl = line.split('\n')[0].split(' ')[0]
                    currentPath = line.split('\n')[0].split(' ')[1]
                    if currentUrl == url:
                        if not os.path.isfile(os.path.join(self.imageFolder, currentPath[1:])): os.rename(os.path.join(self.imageFolder, currentPath), os.path.join(self.imageFolder, currentPath[1:]))
                        self.imagePath = currentPath[1:]
                        setImagePath = True
        if not setImagePath: self.imagePath = imagePath
        self._pixmap = QPixmap(os.path.join(self.imageFolder, self.imagePath))
        self.setPixmap(self._pixmap.scaled(self.sizeHint(), Qt.KeepAspectRatio))
        self.tabAdded.emit(self, self.tabNumber)
        self.addCloseButton()

    # DOWNLOAD IMAGE FROM DRIVER
    def downloadImage(self, url, callback=False):
        self.imagePath = str(url).replace('/', '').replace(':', '') + '.png'
        self.driver.get(url)
        path = os.path.join(self.imageFolder, self.imagePath)
        self.driver.save_screenshot(path)
        self._pixmap = QPixmap(path, '1')
        if callback:
            self.loadSave()

    # SET PIXMAP FROM _PIXMAP
    def setLocalPixmap(self):
        self.setPixmap(self._pixmap.scaled(self.sizeHint(), Qt.KeepAspectRatio))
        self.options.loadedTabCount += 1
        self.imageLoaded.emit()

    # CHECK IF FILE EXISTS AND IF ITS NOT EMPTY
    def checkFileExists(self, fileName):
        exists = os.path.isfile(os.path.join(os.getcwd(), fileName))
        notEmpty = False
        if exists:
            notEmpty = True if (os.path.getsize(os.path.join(os.getcwd(), fileName)) > 0) else False
        return (exists and notEmpty)

    # CHECK IF URL IS IN FILENAME
    def checkDuplicateTab(self, url, fileName):
        if self.checkFileExists(fileName):
            with open(fileName, 'r') as f:
                for line in f:
                    if url == line.split(' ')[0]: return True
        return False

    # CHECK THROUGH TABS FILE AND SET IMAGEPATH AND PIXMAP IF URL EXISTS
    def setDuplicateTab(self, url):
        with open(self.tabFileName, 'r') as f:
            for line in f:
                if url == line.split(' ')[0]:
                    imagePath = line.split(' ')[1]
                    self.imagePath = imagePath
                    self._pixmap = QPixmap(os.path.join(self.imageFolder, imagePath), '1')

    # CHECK THROUGH ARCHIVED TABS FILE AND SET IMAGEPATH AND PIXMAP IF URL EXISTS
    def setDuplicateArchiveTab(self, url):
        with open(self.archiveTabFileName, 'r') as f:
            for line in f:
                if url == line.split(' ')[0]:
                    imagePath = line.split('\n')[0].split(' ')[1]
                    # RENAME IMAGE TO MAKE IT NOT HIDDEN
                    os.rename(os.path.join(self.imageFolder, imagePath), os.path.join(self.imageFolder, imagePath[1:]))
                    self.imagePath = imagePath[1:]
                    self._pixmap = QPixmap(os.path.join(self.imageFolder, self.imagePath), '1')

    # SAVE TAB ENTRY TO FILE
    def saveTab(self):
        with open(self.tabFileName, 'a') as f:
            info = self.url + ' ' + self.imagePath + ' ' + str(self.tabNumber) + '\n'
            f.write(info)

    def setTaken(self, url):
        self.taken = True
        self.url = url

    def addedLoaded(self):
        self.tabAdded.emit(self, self.tabNumber)
        self.imageLoaded.emit()

    ### QUICK METHODS TO SET TAB STYLING
    def defaultTab(self, text):
        self.setText(text)
        self.setBackgroundRole(QPalette.Light)

    def highlightTab(self):
        self.setBackgroundRole(QPalette.Mid)
        self.setText('Drop Here')

class DownloadThread(QThread):
    def __init__(self, tab, driver, callback, url, imageFolder):
        QThread.__init__(self)
        self.tab = tab
        self.driver = driver
        self.callback = callback
        self.url = url
        self.imageFolder = imageFolder

    def __del__(self):
        pass

    def run(self):
        self.tab.imagePath = str(self.url).replace('/', '') + '.png'
        self.driver.get(self.url)
        path = os.path.join(self.imageFolder, self.tab.imagePath)
        self.driver.save_screenshot(path)
        self.tab._pixmap = QPixmap(path, '1')
        self.callback()


#!/usr/bin/env python3

# Author: David L. Bernick
# Editted by: Jairo Navarro

'''
The MIT License (MIT)

Copyright (c) 2015 David L. Bernick, Jairo Navarro
'''

########################################################################
# CommandLine
########################################################################
class CommandLine() :
    '''
    Handle the command line, usage and help requests.

    CommandLine uses argparse, now standard in 2.7 and beyond.
    it implements a standard command line argument parser with various argument options,
    a standard usage and help, and an error termination mechanism do-usage_and_die.

    attributes:
    all arguments received from the commandline using .add_argument will be
    avalable within the .args attribute of object instantiated from CommandLine.
    For example, if myCommandLine is an object of the class, and requiredbool was
    set as an option using add_argument, then myCommandLine.args.requiredbool will
    name that option.

    '''

    def __init__(self, inOpts=None) :
        '''
        CommandLine constructor.
        Implements a parser to interpret the command line argv string using argparse.
        '''

        import argparse
        self.parser = argparse.ArgumentParser(description = 'The FOCUS program is used to view rare frequency codons using a codon usage table and ',
                                             epilog = 'This is a working prototype',
                                             add_help = True, #default is True
                                             prefix_chars = '-',
                                             usage = '%(prog)s  CodonBiasTable NucleicAcidSeq'
                                             )
        self.parser.add_argument('CodonFile', action = 'store', help='Codon Bias Table in GCG format')
        self.parser.add_argument('NucFile', action = 'store', help='Nucleic Acid sequence')
        self.parser.add_argument('SecStruct', action='store',default=None, nargs='?',help='Secondary Structure Prediction in I-TASSER format')
        self.parser.add_argument('OutFile', action = 'store', default=None,nargs='?',help='Output file name')

        if inOpts is None :
            self.args = self.parser.parse_args()
        else :
            self.args = self.parser.parse_args(inOpts)

########################################################################
# Main
# Here is the main program
#
#
########################################################################

def main(myCommandLine=None):
    '''
    Implements the Usage exception handler that can be raised from anywhere in process.

    '''
    if myCommandLine is None:
        myCommandLine = CommandLine()
    else :
        myCommandLine = CommandLine(myCommandLine)
###### replace the code between comments.
        # myCommandLine.args.inFile has the input file name
        # myCommandLine.args.outFile has the output file name
        # myCommandLine.args.longestGene is True if only the longest Gene is desired
        # myCommandLine.args.start is a list of start codons
        # myCommandLine.args.minGene is the minimum Gene length to include
        #
    print (myCommandLine.args) # print the parsed argument string .. as there is nothing better to do

    if True:
        print ('First Arg is', str(myCommandLine.args.CodonFile) )
        print (type(myCommandLine.args.CodonFile))
    else :
        pass
#######

if __name__ == "__main__":
    main()


import requests as r
import re

def make_w_req(url):
    response = r.get(url)
    return str(response.content)

def find_urls(content):
    return re.findall('href=[\'"]?([^\'" >]+)', content)

def write_urls(urls):
    with open("found_4.txt", "a+") as f:
        for url in urls:
            f.write(url + "\n")

f = open("links.txt", mode="r")
lines = f.readlines()
f.close()
for l in lines:
    c = make_w_req(l.replace("\n", ""))
    urls = find_urls(c)
    write_urls(urls)


#!python3

import os
import re

FOLDER_CONST = "emojisCut"

def tryint(s):
    """
    Return an int if possible, or `s` unchanged.
    """
    try:
        return int(s)
    except ValueError:
        return s

def alphanum_key(s):
    """
    Turn a string into a list of string and number chunks.

    >>> alphanum_key("z23a")
    ["z", 23, "a"]

    """
    return [ tryint(c) for c in re.split('([0-9]+)', s) ]

def human_sort(l):
    """
    Sort a list in the way that humans expect.
    """
    l.sort(key=alphanum_key)
    return l

def getFilesFromDir():
    list_of_files = []
    path = f'C:\\Users\\ivanp\\IdeaProjects\\ENCOG-PrepoznavanjeSlika\\{FOLDER_CONST}\\.'
    # Get list of all files in a given directory sorted by name
    for (root, dir_name, file_name) in os.walk(path):
        list_of_files.append(file_name)

    # Iterate over sorted list of files and print the file paths
    # one by one.
    return list_of_files[0]

def walk_through_files(emoji_sorted_list, flag, f, file_extension='.png'):
    counter = 0
    emoji_counter = 0

    for emoji in emoji_sorted_list:
        if flag == 0 and not "merge" in emoji:
                if emoji_counter < 8:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:smiley_face\n")
                elif emoji_counter >= 8 and emoji_counter < 16:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:sad_face\n")
                elif emoji_counter >= 16 and emoji_counter < 24:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:neutral_face\n")
                elif emoji_counter >= 24 and emoji_counter < 32:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:heart_eyes_face\n")
                elif emoji_counter >= 32 and emoji_counter < 40:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:cool_face\n")
                elif emoji_counter >= 40 and emoji_counter < 48:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:wink_face\n")
                elif emoji_counter >= 48 and emoji_counter < 56:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:money_face\n")
                elif emoji_counter >= 56 and emoji_counter < 64:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:nerd_face\n")
                elif emoji_counter >= 64 and emoji_counter < 72:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:sleeping_face\n")
                elif emoji_counter >= 72 and emoji_counter < 80:
                    f.write(f"Input: image:./{FOLDER_CONST}/{emoji}, identity:clown_face\n")
                else:
                    break
                emoji_counter += 1

        elif flag == 1 and not "merge" in emoji:
                # counter += counter + 1
                f.write(f"Whatis: image:./{FOLDER_CONST}/{emoji}\n")

#                 f.write(f"Whatis: image:./{FOLDER_CONST}/emoji_99.jpg\n")
#                 f.write(f"Whatis: image:./{FOLDER_CONST}/emoji_98.jpg\n")
#                 f.write(f"Whatis: image:./{FOLDER_CONST}/emoji_97.jpg\n")
#                 f.write(f"Whatis: image:./{FOLDER_CONST}/emoji_96.jpg\n")
#                 f.write(f"Whatis: image:./{FOLDER_CONST}/emoji_95.jpg\n")
#                 f.write(f"Whatis: image:./{FOLDER_CONST}/emoji_94.jpg\n")
#                 break

width = 16
height = 16
img_type = "RGB"
hidden_1 = 100
hidden_2 = 0
mode = "Console"
minutes = 1

emoji_sorted_list = human_sort(getFilesFromDir())
# print(emoji_sorted_list)
f = open('command_emoji.txt', 'w')
f.write(f"CreateTraining: width:{width},height:{height},type:{img_type}\n")
walk_through_files(emoji_sorted_list, flag=0, f=f, file_extension=".jpg")
f.write(f"Network: hidden1:{hidden_1}, hidden2:{hidden_2}\nTrain: Mode:{mode}, Minutes:{minutes}, StrategyError:0.25,StrategyCycles:100\n")
walk_through_files(emoji_sorted_list, flag=1, f=f, file_extension=".jpg")
f.close()


#!/usr/bin/python3
# -*- coding: utf-8 -*-
# author: JinSong.xiao(61627515@qq.com)
# time: 2019/5/30 18:44

prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
}

if __name__ == '__main__':
    p1 = {key: value for key, value in prices.items() if value > 200}
    teach_names = ['AAPL', 'FB']
    p2 = {key: value for key, value in prices.items() if key in teach_names}
    p3 = dict((key, value) for key, value in prices.items() if value > 200)
    print(p1, p2, p3)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 28 22:12:57 2017

@author: m0nT3cR1s70
"""
import matplotlib.pyplot as plt

def graError(h,ef,eb,ec,e3,e4):
    plt.figure()
    plt.plot(h,ef,'b',label='$D_{{+}}$')
    plt.plot(h,eb,'g',label='$D_{{-}}$')
    plt.plot(h,ec,'r',label='$D_{{0}}$')
    plt.plot(h,e3,'k',label='$D_{{3}}$')
    plt.plot(h,e4,'m',label='$D_{{-3}}$')
    plt.xlabel("log(h)")
    plt.ylabel("log(ux)")
    plt.legend()
    plt.loglog()
    plt.grid()
    plt.show()

def grafic(rho1,rho2,rho3,x1,x2,x3,d1,d2,d3,title):
    plt.figure()
    plt.subplot(311)
    plt.title(title)
    plt.plot(x1,rho1,'o-')
    plt.plot(x1,d1,label='Malla 10 nodos')
    plt.grid()
    plt.legend()
    plt.subplot(312)
    plt.plot(x2,rho2,'o-')
    plt.plot(x2,d2,label='Malla 20 nodos')
    plt.grid()
    plt.legend()
    plt.subplot(313)
    plt.plot(x3,rho3,'o-')
    plt.plot(x3,d3,label='Malla 100 nodos')
    plt.grid()
    plt.subplots_adjust(hspace=0.5)
    plt.legend()
    plt.show()


def solution(board, moves):
    answer = 0
    a=len(board)
    b=len(board[1])

    stack=[]

    for m in moves:
        m=m-1
        for i in range(a):
            if board[i][m]!=0:
                stack.append(board[i][m])
                board[i][m]=0
                break
        if len(stack)>=2 and stack[-1]==stack[-2]:
            stack.pop()
            stack.pop()
            answer+=2

    return answer

유섭_크레인인형뽑기.py