import asyncio
import re
from typing import Any, Dict, Iterable, List, Set, Tuple
import click
from errata_tool import Erratum

from elliottlib import bzutil, constants, logutil
from elliottlib.cli.common import cli, click_coroutine, pass_runtime
from elliottlib.errata_async import AsyncErrataAPI, AsyncErrataUtils
from elliottlib.runtime import Runtime
from elliottlib.util import (minor_version_tuple, red_print)
from elliottlib.bzutil import Bug
from elliottlib.cli.attach_cve_flaws_cli import get_flaws
from elliottlib.cli.find_bugs_sweep_cli import FindBugsSweep, categorize_bugs_by_type

logger = logutil.getLogger(__name__)

@cli.command("verify-attached-bugs",
             short_help="Run validations on bugs attached to release advisories and report results")
@click.option("--verify-bug-status", is_flag=True,
              help="Check that bugs of advisories are all VERIFIED or more",
              type=bool, default=False)
@click.option("--verify-flaws", is_flag=True,
              help="Check that flaw bugs are attached and associated with respective builds",
              type=bool, default=False)
@click.option("--no-verify-blocking-bugs", is_flag=True,
              help="Don't check if there are open bugs for the next minor version blocking bugs for this minor version",
              type=bool, default=False)
@click.option("--skip-multiple-advisories-check", is_flag=True,
              help="Do not check if bugs are attached to multiple advisories",
              type=bool, default=False)
@click.argument("advisories", nargs=-1, type=click.IntRange(1), required=False)
@pass_runtime
@click_coroutine
async def verify_attached_bugs_cli(runtime: Runtime, verify_bug_status: bool, advisories: Tuple[int, ...], verify_flaws: bool,
                                   no_verify_blocking_bugs: bool, skip_multiple_advisories_check: bool):
    """
    Validate bugs in release advisories (specified in arguments or as part of an assembly).
    Requires group param (-g openshift-X.Y)

    Default validations:
    - Target Release: All bugs belong to the group's target release.
    - Bug Sorting: Bugs are attached to the correct advisory type (image/rpm/extras) using
    find-bugs:sweep logic. This only runs with --assembly. To skip manually specify advisories.
    - Improper Tracker Bugs: Bugs that have CVE in their title but do not have Tracker Bug labels set.
    - Regression Check: If there are any backport bugs, make sure they don't get ahead of their original bug.
    This is to make sure we don't regress when upgrading from OCP X.Y to X.Y+1. To skip use --no-verify-blocking-bugs.
    - Bugs aren't attached to multiple advisories. To skip use --skip-multiple-advisories-check.

    Additional validations:
    - Bug Status (--verify-bug-status): All bugs are in at least in VERIFIED state
    - Flaw Bugs (--verify-flaws): All flaw bugs are attached to advisories (using attach-cve-flaws logic) and
    associated with respective builds. Verify advisory type is RHSA when applicable, and CVE names field is correct.

    If any verification fails, a text explanation is given and the return code is 1.
    Otherwise, prints the number of bugs in the advisories and exits with success.
    """
    runtime.initialize()
    if advisories:
        click.echo("WARNING: Cannot verify advisory bug sorting. To verify that bugs are attached to the "
                   "correct release advisories, run with --assembly=<release>")
        advisory_id_map = {'?': a for a in advisories}
    else:
        advisory_id_map = runtime.get_default_advisories()
    if not advisory_id_map:
        red_print("No advisories specified on command line or in [group.yml|releases.yml]")
        exit(1)
    await verify_attached_bugs(runtime, verify_bug_status, advisory_id_map, verify_flaws, no_verify_blocking_bugs, skip_multiple_advisories_check)

async def verify_attached_bugs(runtime: Runtime, verify_bug_status: bool, advisory_id_map: Dict[str, int], verify_flaws:
                               bool, no_verify_blocking_bugs: bool, skip_multiple_advisories_check: bool):
    validator = BugValidator(runtime, output="text")
    advisory_bug_map = validator.get_attached_bugs(list(advisory_id_map.values()))
    bugs = {b for bugs in advisory_bug_map.values() for b in bugs}

    # bug.is_ocp_bug() filters by product/project, so we don't get flaw bugs or bugs of other products or
    # placeholder
    non_flaw_bugs = [b for b in bugs if b.is_ocp_bug()]

    validator.validate(non_flaw_bugs, verify_bug_status, no_verify_blocking_bugs)

    # skip advisory type check if advisories are
    # manually passed in, and we don't know their type
    if '?' not in advisory_id_map.keys():
        validator.verify_bugs_advisory_type(non_flaw_bugs, advisory_id_map, advisory_bug_map)

    if not skip_multiple_advisories_check:
        await validator.verify_bugs_multiple_advisories(non_flaw_bugs)

    if verify_flaws:
        await validator.verify_attached_flaws(advisory_bug_map)

    # Close client session
    await validator.close()

    if validator.problems:
        if validator.output != 'slack':
            red_print(f"Found the following problems: {validator.problems}")
            red_print("Some bug problems were listed above. Please investigate.")
        exit(1)

@cli.command("verify-bugs", short_help="Verify bugs included in an assembly (default --assembly=stream)")
@click.option("--verify-bug-status", is_flag=True, help="Check that bugs of advisories are all VERIFIED or more",
              type=bool, default=False)
@click.option("--no-verify-blocking-bugs", is_flag=True,
              help="Don't check if there are open bugs for the next minor version blocking bugs for this minor version",
              type=bool, default=False)
@click.option('--output', '-o',
              required=False,
              type=click.Choice(['text', 'json', 'slack']),
              default='text',
              help='Applies chosen format to command output')
@pass_runtime
@click_coroutine
async def verify_bugs_cli(runtime, verify_bug_status, output, no_verify_blocking_bugs: bool):
    """
    Validate bugs that qualify as being part of an assembly (specified as --assembly)
    Requires group param (-g openshift-X.Y). By default runs for --assembly=stream

    Default validations:
    - Target Release: All bugs belong to the group's target release.
    - Improper Tracker Bugs: Bugs that have CVE in their title but do not have Tracker Bug labels set.
    - Regression Check: If there are any backport bugs, make sure they don't get ahead of their original bug.
    This is to make sure we don't regress when upgrading from OCP X.Y to X.Y+1. To skip use --no-verify-blocking-bugs.

    Additional validations:
    - Bug Status (--verify-bug-status): All bugs are at least in VERIFIED state

    """
    runtime.initialize()
    await verify_bugs(runtime, verify_bug_status, output, no_verify_blocking_bugs)

async def verify_bugs(runtime, verify_bug_status, output, no_verify_blocking_bugs):
    validator = BugValidator(runtime, output)
    find_bugs_obj = FindBugsSweep(cve_only=False)
    ocp_bugs = []
    logger.info(f'Using {runtime.assembly} assembly to search bugs')
    for b in [runtime.get_bug_tracker('jira'), runtime.get_bug_tracker('bugzilla')]:
        bugs = find_bugs_obj.search(bug_tracker_obj=b, verbose=runtime.debug)
        logger.info(f"Found {len(bugs)} {b.type} bugs: {[b.id for b in bugs]}")
        ocp_bugs.extend(bugs)

    validator.validate(ocp_bugs, verify_bug_status, no_verify_blocking_bugs)

    # Close client session
    await validator.close()

    if validator.problems:
        if validator.output != 'slack':
            red_print("Some bug problems were listed above. Please investigate.")
        exit(1)

class BugValidator:

    def __init__(self, runtime: Runtime, output: str = 'text'):
        self.runtime = runtime
        self.target_releases: List[str] = runtime.get_bug_tracker('jira').config['target_release']
        self.et_data: Dict[str, Any] = runtime.get_errata_config()
        self.errata_api = AsyncErrataAPI(self.et_data.get("server", constants.errata_url))
        self.problems: List[str] = []
        self.output = output

    async def close(self):
        await self.errata_api.close()

    def validate(self, non_flaw_bugs: List[Bug], verify_bug_status: bool, no_verify_blocking_bugs: bool):
        non_flaw_bugs = self.filter_bugs_by_release(non_flaw_bugs, complain=True)
        self._find_invalid_trackers(non_flaw_bugs)
        if not no_verify_blocking_bugs:
            blocking_bugs_for = self._get_blocking_bugs_for(non_flaw_bugs)
            self._verify_blocking_bugs(blocking_bugs_for)

        if verify_bug_status:
            self._verify_bug_status(non_flaw_bugs)

    def verify_bugs_advisory_type(self, non_flaw_bugs, advisory_id_map, advisory_bug_map):
        bugs_by_type = categorize_bugs_by_type(non_flaw_bugs, advisory_id_map)
        for kind, advisory_id in advisory_id_map.items():
            actual = {b for b in advisory_bug_map[advisory_id] if b.is_ocp_bug()}
            expected = bugs_by_type[kind]
            if actual != expected:
                bugs_not_found = expected - actual
                extra_bugs = actual - expected
                if bugs_not_found:
                    self._complain(f'Expected Bugs not found in {kind} advisory ({advisory_id}):'
                                   f' {[b.id for b in bugs_not_found]}')
                if extra_bugs:
                    self._complain(f'Unexpected Bugs found in {kind} advisory ({advisory_id}):'
                                   f' {[b.id for b in extra_bugs]}')

    async def verify_bugs_multiple_advisories(self, non_flaw_bugs: List[Bug]):
        logger.info(f'Checking {len(non_flaw_bugs)} bugs, if any bug is attached to multiple advisories')

        async def get_all_advisory_ids(bug):
            all_advisories_id = bug.all_advisory_ids()
            if len(all_advisories_id) > 1:
                return f'Bug <{bug.weburl}|{bug.id}> is attached in multiple advisories: {all_advisories_id}'
            return None

        results = await asyncio.gather(*[asyncio.create_task(get_all_advisory_ids(bug)) for bug in non_flaw_bugs])
        for message in results:
            if message:
                self._complain(message)

    async def verify_attached_flaws(self, advisory_bugs: Dict[int, List[Bug]]):
        futures = []
        for advisory_id, attached_bugs in advisory_bugs.items():
            attached_trackers = [b for b in attached_bugs if b.is_tracker_bug()]
            attached_flaws = [b for b in attached_bugs if b.is_flaw_bug()]
            logger.info(f"Verifying advisory {advisory_id}: attached-trackers: "
                        f"{[b.id for b in attached_trackers]} "
                        f"attached-flaws: {[b.id for b in attached_flaws]}")
            futures.append(self._verify_attached_flaws_for(advisory_id, attached_trackers, attached_flaws))
        await asyncio.gather(*futures)

    async def _verify_attached_flaws_for(self, advisory_id: int, attached_trackers: Iterable[Bug], attached_flaws: Iterable[Bug]):
        flaw_bug_tracker = self.runtime.get_bug_tracker('bugzilla')
        brew_api = self.runtime.build_retrying_koji_client()
        tracker_flaws, first_fix_flaw_bugs = get_flaws(flaw_bug_tracker, attached_trackers, brew_api,
                                                       self.runtime.logger)

        # Check if attached flaws match expected flaws
        first_fix_flaw_ids = {b.id for b in first_fix_flaw_bugs}
        attached_flaw_ids = {b.id for b in attached_flaws}
        missing_flaw_ids = first_fix_flaw_ids - attached_flaw_ids
        if missing_flaw_ids:
            self._complain(f"On advisory {advisory_id}, these flaw bugs are not attached: "
                           f"{', '.join(sorted(map(str, missing_flaw_ids)))} but "
                           "they are referenced by attached tracker bugs. "
                           "You need to attach those flaw bugs or drop corresponding tracker bugs.")
        extra_flaw_ids = attached_flaw_ids - first_fix_flaw_ids
        if extra_flaw_ids:
            self._complain(f"On advisory {advisory_id}, these flaw bugs are attached: "
                           f"{', '.join(sorted(map(str, extra_flaw_ids)))} but "
                           f"there are no tracker bugs referencing them. "
                           "You need to drop those flaw bugs or attach corresponding tracker bugs.")

        # Check if advisory is of the expected type
        advisory_info = await self.errata_api.get_advisory(advisory_id)
        advisory_type = next(iter(advisory_info["errata"].keys())).upper()  # should be one of [RHBA, RHSA, RHEA]
        if not first_fix_flaw_ids:
            if advisory_type == "RHSA":
                self._complain(f"Advisory {advisory_id} is of type {advisory_type} "
                               f"but has no first-fix flaw bugs. It should be converted to RHBA or RHEA.")
            return  # The remaining checks are not needed for a non-RHSA.
        if advisory_type != "RHSA":
            self._complain(f"Advisory {advisory_id} is of type {advisory_type} but has first-fix flaw bugs "
                           f"{first_fix_flaw_ids}. It should be converted to RHSA.")

        # Validate CVE mappings (of CVEs and builds)
        flaw_id_bugs = {f.id: f for f in first_fix_flaw_bugs}
        cve_components_mapping: Dict[str, Set[str]] = {}
        for tracker in attached_trackers:
            component_name = tracker.whiteboard_component
            flaw_ids = tracker_flaws[tracker.id]
            for flaw_id in flaw_ids:
                if flaw_id not in flaw_id_bugs:  # This means associated flaw wasn't considered a first fix
                    continue
                alias = [k for k in flaw_id_bugs[flaw_id].alias if k.startswith('CVE-')]
                if len(alias) != 1:
                    raise ValueError(f"Bug {flaw_id} should have exactly 1 CVE alias.")
                cve = alias[0]
                cve_components_mapping.setdefault(cve, set()).add(component_name)

        attached_builds = await self.errata_api.get_builds_flattened(advisory_id)
        try:
            extra_exclusions, missing_exclusions = await AsyncErrataUtils.validate_cves_and_get_exclusions_diff(
                self.errata_api,
                advisory_id, attached_builds,
                cve_components_mapping)
        except ValueError as e:
            self._complain(e)

        for cve, cve_package_exclusions in extra_exclusions.items():
            if cve_package_exclusions:
                self._complain(f"On advisory {advisory_id}, {cve} is not associated with Brew components "
                               f"{', '.join(sorted(cve_package_exclusions))}."
                               " You may need to associate the CVE with the components "
                               "in the CVE mapping or drop the tracker bugs.")
        for cve, cve_package_exclusions in missing_exclusions.items():
            if cve_package_exclusions:
                self._complain(f"On advisory {advisory_id}, {cve} is associated with Brew components "
                               f"{', '.join(sorted(cve_package_exclusions))} without a tracker bug."
                               " You may need to explicitly exclude those Brew components from the CVE "
                               "mapping or attach the corresponding tracker bugs.")

        # Validate `CVE Names` field of the advisory
        advisory_cves = advisory_info["content"]["content"]["cve"].split()
        extra_cves = cve_components_mapping.keys() - advisory_cves
        if extra_cves:
            self._complain(f"On advisory {advisory_id}, bugs for the following CVEs are already attached "
                           f"but they are not listed in advisory's `CVE Names` field: {', '.join(sorted(extra_cves))}")
        missing_cves = advisory_cves - cve_components_mapping.keys()
        if missing_cves:
            self._complain(f"On advisory {advisory_id}, bugs for the following CVEs are not attached but listed in "
                           f"advisory's `CVE Names` field: {', '.join(sorted(missing_cves))}")

    def get_attached_bugs(self, advisory_ids: List[str]) -> Dict[int, Set[Bug]]:
        """ Get bugs attached to specified advisories
        :return: a dict with advisory id as key and set of bug objects as value
        """
        logger.info(f"Retrieving bugs for advisories: {advisory_ids}")
        advisories = [Erratum(errata_id=advisory_id) for advisory_id in advisory_ids]

        attached_bug_map = {advisory_id: set() for advisory_id in advisory_ids}
        for bug_tracker_type in ['jira', 'bugzilla']:
            bug_tracker = self.runtime.get_bug_tracker(bug_tracker_type)
            advisory_bug_id_map = {advisory.errata_id: bug_tracker.advisory_bug_ids(advisory)
                                   for advisory in advisories}
            bug_map = bug_tracker.get_bugs_map([bug_id for bug_list in advisory_bug_id_map.values()
                                                for bug_id in bug_list])
            for advisory_id in advisory_ids:
                set_of_bugs = {bug_map[bid] for bid in advisory_bug_id_map[advisory_id] if bid in bug_map}
                attached_bug_map[advisory_id] = attached_bug_map[advisory_id] | set_of_bugs
        return attached_bug_map

    def filter_bugs_by_release(self, bugs: List[Bug], complain: bool = False) -> List[Bug]:
        # filter out bugs with an invalid target release
        filtered_bugs = []
        for b in bugs:
            # b.target release is a list of size 0 or 1
            if any(target in self.target_releases for target in b.target_release):
                filtered_bugs.append(b)
            elif complain:
                self._complain(
                    f"bug {b.id} target release {b.target_release} is not in "
                    f"{self.target_releases}. Does it belong in this release?"
                )
        return filtered_bugs

    def _get_blocking_bugs_for(self, bugs):
        # get blocker bugs in the next version for all bugs we are examining
        candidate_blockers = []
        for b in bugs:
            if b.depends_on:
                candidate_blockers.extend(b.depends_on)
        jira_ids, bz_ids = bzutil.get_jira_bz_bug_ids(set(candidate_blockers))

        v = minor_version_tuple(self.target_releases[0])
        next_version = (v[0], v[1] + 1)

        def is_next_target(target_v):
            pattern = re.compile(r'^\d+\.\d+\.(0|z)$')
            return pattern.match(target_v) and minor_version_tuple(target_v) == next_version

        def managed_by_art(b: Bug):
            components_not_managed_by_art = self.runtime.get_bug_tracker('jira').component_filter()
            return b.component not in components_not_managed_by_art

        # retrieve blockers and filter to those with correct product and target version
        blockers = []
        if jira_ids:
            blockers.extend(self.runtime.get_bug_tracker('jira')
                            .get_bugs(jira_ids))
        if bz_ids:
            blockers.extend(self.runtime.get_bug_tracker('bugzilla')
                            .get_bugs(bz_ids))
        logger.debug(f"Candidate Blocker bugs found: {[b.id for b in blockers]}")
        blocking_bugs = {}
        for bug in blockers:
            if not bug.is_ocp_bug() or not managed_by_art(bug):
                continue
            target_release = []
            # A bug without `Target Version` shouldn't be considered as a blocking bug
            try:
                target_release = bug.target_release
            except ValueError as err:  # bug.target_release will raise ValueError if Target Version is not set
                if "does not have `Target Version` field set" not in str(err):
                    raise
            next_target = any(is_next_target(target) for target in target_release)
            if next_target:
                blocking_bugs[bug.id] = bug
        logger.info(f"Blocking bugs for next target release ({next_version[0]}.{next_version[1]}): "
                    f"{list(blocking_bugs.keys())}")

        k = {bug: [blocking_bugs[b] for b in bug.depends_on if b in blocking_bugs] for bug in bugs}
        return k

    def _verify_blocking_bugs(self, blocking_bugs_for):
        # complain about blocking bugs that aren't verified or shipped
        for bug, blockers in blocking_bugs_for.items():
            for blocker in blockers:
                message = str()
                if blocker.status not in ['VERIFIED', 'RELEASE_PENDING', 'CLOSED', 'Release Pending', 'Verified',
                                          'Closed'] and not (blocker.status == bug.status == "ON_QA"):
                    if self.output == 'text':
                        message = f"Regression possible: {bug.status} bug {bug.id} is a backport of bug " \
                            f"{blocker.id} which has status {blocker.status}"
                    elif self.output == 'slack':
                        message = f"`{bug.status}` bug <{bug.weburl}|{bug.id}> is a backport of " \
                                  f"`{blocker.status}` bug <{blocker.weburl}|{blocker.id}>"
                    self._complain(message)
                if blocker.status in ['CLOSED', 'Closed'] and \
                    blocker.resolution not in ['CURRENTRELEASE', 'NEXTRELEASE', 'ERRATA', 'DUPLICATE', 'NOTABUG', 'WONTFIX',
                                               'Done', 'Fixed', 'Done-Errata',
                                               'Current Release', 'Errata', 'Next Release',
                                               "Won't Do", "Won't Fix",
                                               'Duplicate', 'Duplicate Issue',
                                               'Not a Bug']:
                    if self.output == 'text':
                        message = f"Regression possible: {bug.status} bug {bug.id} is a backport of bug " \
                            f"{blocker.id} which was CLOSED {blocker.resolution}"
                    elif self.output == 'slack':
                        message = f"`{bug.status}` bug <{bug.weburl}|{bug.id}> is a backport of bug " \
                            f"<{blocker.weburl}|{blocker.id}> which was CLOSED `{blocker.resolution}`"
                    self._complain(message)

    def _verify_bug_status(self, bugs):
        # complain about bugs that are not yet VERIFIED or more.
        for bug in bugs:
            if bug.is_flaw_bug():
                continue
            if bug.status in ["VERIFIED", "RELEASE_PENDING", "Verified", "Release Pending"]:
                continue
            if bug.status in ["CLOSED", "Closed"] and bug.resolution in ["ERRATA", 'Errata']:
                continue
            status = f"{bug.status}"
            if bug.status in ['CLOSED', 'Closed']:
                status = f"{bug.status}: {bug.resolution}"
            self._complain(f"Bug <{bug.weburl}|{bug.id}> has status {status}")

    def _find_invalid_trackers(self, bugs):
        logger.info("Checking for invalid tracker bugs")
        # complain about invalid tracker bugs
        for bug in bugs:
            if bug.is_invalid_tracker_bug():
                self._complain(f"Bug <{bug.weburl}|{bug.id}> is an invalid tracker bug. Please fix")

    def _complain(self, problem: str):
        red_print(problem)
        self.problems.append(problem)


from random import randint

import requests

import common
import discord
from discord.ext import commands

class Reddit(commands.Cog):
    """ Reddit Fetchers"""

    def __init__(self, bot):
        self.bot = bot

    @commands.command(name='dankmeme', aliases=['dankmay', 'dankmaymay'])
    @commands.cooldown(2, 60 * 5)
    async def dankmeme(self, ctx):
        """Get a succulent dank may-may"""
        await ctx.send(get_reddit("dankmemes"))

    @commands.command(name='bertstrip', aliases=['badchildhood'])
    @commands.cooldown(2, 60 * 5)
    async def bertstrip(self, ctx):
        """Ruin your childhood"""
        await ctx.send(get_reddit("bertstrips"))

def get_reddit(subreddit):
    """
    Function that fetches dank memes.

    :param subreddit: Subreddit to use for the reddit fetch
    :return: a string to send the client
    """
    number_to_fetch = str(100)
    url = 'https://www.reddit.com/r/{}.json?limit={}'.format(
        subreddit,
        number_to_fetch)
    headers = {
        'User-Agent': 'Brochat-Bot {}.{}'.format(common.VERSION_YEAR,
                                                 common.VERSION_MONTH)
    }
    response = requests.get(url, headers=headers)
    response_json = response.json()

    if 'data' in response_json:
        for entry in response_json['data']['children']:
            if entry['data']['stickied'] is True \
                    or (entry['data']['url'][-4:] != '.png' and
                        entry['data']['url'][-4:] != '.jpg'):
                response_json['data']['children'].remove(entry)
        print(str(len(response_json['data']['children'])))
        seed = randint(0, len(response_json['data']['children']) - 1)
        link = response_json['data']['children'][seed]['data']['url']

        return '{}'.format(link)
    else:
        print('Error, response code: {}'.format(response.status_code))
        return "Looks like an adversary developer pwned " \
               "us...\nhttps://cdn.meme.am/cache/instances/" \
               "folder861/20989861.jpg"

def setup(bot):
    bot.add_cog(Reddit(bot))


# 두개의 숫자를 입력 받는다.
# 두수 중 최대 값을 출력 하시오
num1 = int(input('Input num1..'));

num2 = int(input('Input num2..'));

# 두개의 숫자는 모두 한자리로 입력이 되어야 한다.
# 한자리가 아니면 프로그램 종료 시킨다.
# 음수로 입력해도 프로그램 종료 시킨다.

if not((num1 // 10) < 1 and (num2 // 10) < 1)  or (num1 < 0 or num2 < 0):
    print('bye');
    exit(0);

max = 0;
# 두개의 숫자의 큰값을 max 값에 넣는다.
# 두개의 숫자를 비교 한다.
# 큰수를 max 값에 넣는다.
if num1 == num2:
    max = num1;
elif num1 > num2:
    max = num1;
else:
    max = num2;
print(max);

sal = int(input('Input salary'));

asal = sal - (sal * 0.92);
print(asal)


# Função que calcula a sequência de Fibonacci até um determinado valor n
def VerificaFib(n):
  # Inicia a sequência com 0 e 1
    fib = [0, 1]
    # Adiciona os próximos valores da sequência até n
    while fib[-1] < n:
      fib.append(fib[-1] + fib[-2])
    # Retorna a sequência
    return fib
#Solicitando o valor de entrada para comparar com a sequencia fib
num = int(input("Digite um numero para verificar se faz parte da sequêcia de Fibonacci: "))
#Chamando a função que vai fazer a verificação
seq_fib = VerificaFib(num)

print("---" *18)
#Printando o resultado referente a comparação
if num in seq_fib:
  print("O numero ", num ," faz parte da sequencia ", seq_fib)
else:
  print("O numero ", num ,"Não faz parte da sequencia ",seq_fib)


#classmethods and staticmethods

class Employee:
	num_of_emps = 0
	raise_ammount = 1.04

	def __init__(self,first,last,pay):
		self.first = first
		self.last = last
		self.pay = pay
		self.email = first + '.' + last + '@company.com'

		Employee.num_of_emps += 1

	def fullname(self):
		return '{} {}'.format(self.first,self.last)

	def apply_raise(self):
		self.pay = int(self.pay * self.raise_ammount)

	#working with the class	instead of the instance
	@classmethod
	def set_raise_amt(cls, amount):
		cls.raise_amt = amount

	#alternative constructor
	@classmethod
	def from_string(cls,emp_str):
		first,last,pay = emp_str.split('-')
		return cls(first,last,pay)

	#if day its Saturday or Sunday
	@staticmethod
	def is_workday(day):
		if day.weekday() == 5 or day.weekday() == 6:
			return False
		return True

emp_1 = Employee('John','Bary',1000)
emp_2 = Employee('Mike','Jason',3500)

import datetime
my_date = datetime.date(2019,1,6)

print('Is it a work day?')
print(Employee.is_workday(my_date))

#emp_str_1 = 'John-Doe-9999'
#emp_str_2 = 'Steve-Smith-10000'
#emp_str_3 = 'Jane-Doe-9999'

#new_emp_1 = Employee.from_string(emp_str_1)

#print(new_emp_1.email)
#print(new_emp_1.pay)


def even_fib_sum(n):
    first = -1
    second = 1
    third = first + second
    even_sum = 0
    for i in range(n):
        first = second
        second = third
        third = first + second
        if third % 2 == 0:
            even_sum += third
    return even_sum

if __name__ == "__main__":
    limit = 4000
    print(even_fib_sum(limit))


import logging
# for splitting text with regex
import re
import time
from bs4 import BeautifulSoup as bs
# use selenium to have js enabled while webcrawling
from selenium import webdriver
# used for checking dropdown menus so we have a standard view
from selenium.webdriver.support.select import Select

# options we need to have selenium run firefox in the background
options = webdriver.firefox.options.Options()
options.headless = True
options.add_argument('start-maximized')
options.set_preference('browser.download.folderList',2)
options.set_preference('browser.download.manager.showWhenStarting',False)
options.set_preference('browser.helperApps.neverAsk.saveToDisk','text/*')
driver = webdriver.Firefox(executable_path='./geckodriver',options=options)

class Parser:
    _basics = {'Plains','Island','Swamp','Mountain','Forest'}

    def __init__(self,url=''):
        self.url = url
        self.decklist = set()

    def _parse_decklist(self):
        driver.get(self.url)
        soup = bs(driver.page_source,'html5lib')
        return soup

    def _add_card(self,card):
        # ignore basic lands
        if card not in self._basics and 'Snow-Covered' not in card:
            self.decklist.add(card)

    def run(self):
        try:
            return self._parse_decklist()
        except Exception:
            logging.exception(f'Failed to crawl: {self.url}')

class ArchidektParser(Parser):
    def _parse_decklist(self):
        driver.get(self.url)
        # we need to wait for archidekt to load metadata to easily get the cmdr
        time.sleep(7.5)
        soup = bs(driver.page_source,'html5lib')
        cmdr = soup.find('meta',{'data-react-helmet':True})['content']
        if 'Commander' not in cmdr:
            return
        # TODO: there's an edgecase of partners but we're ignoring b/c lazy
        cmdr = cmdr[cmdr.index('Commander:'):cmdr.index('.')]
        cmdr = re.sub('Commander:','',cmdr).strip()
        super()._add_card(cmdr)
        # load goldfishing probability as an easy way to scrape text card names
        xpath = "//i[@class='pie chart icon']"
        element = driver.find_element_by_xpath(xpath)
        element.click()
        xpath = "//a[@class='item'][contains(text(),'Probability')]"
        element = driver.find_element_by_xpath(xpath)
        element.click()
        soup = bs(driver.page_source,'html.parser')
        for table in soup.find_all('tbody',class_=''):
            cards = re.split(r'\d+\%',table.text.strip())[:-1]
            for card in cards:
                super()._add_card(card)

class GoldfishParser(Parser):
    def _parse_decklist(self):
        soup = super()._parse_decklist()
        tab = soup.find(id='tab-paper')
        for table in tab.find_all(class_='deck-view-deck-table'):
            # remove non-breaking spaces
            text = table.text.replace(u'\xa0','')
            # ignore the sideboard section
            if 'Sideboard' in text:
                text = text[:text.index('Sideboard')]
            # regex filtering
            # remove prices
            text = re.sub(r'\$\d+\,*\d*\.\d+','',text)
            # remove counts (x) for sections
            text = re.sub(r'\(\d+\)','',text)
            # remove white space
            text = re.sub(r'\n',' ',text)
            # remove section titles
            text = text.replace('  Commander  ','')
            text = text.replace('  Creatures  ','')
            text = text.replace('  Planeswalkers  ','')
            text = text.replace('  Enchantments  ','')
            text = text.replace('  Artifacts  ','')
            text = text.replace('  Spells  ','')
            text = text.replace('  Lands  ','')
            # remove white space
            text = text.strip()
            while '  ' in text:
                text = text.replace('  ',' ')
            # split text into card names
            cards = re.split(r' *\d+ ',text)[1:]
            for card in cards:
                super()._add_card(card)

class MoxfieldParser(Parser):
    def _parse_decklist(self):
        soup = super()._parse_decklist()
        # use dropdowns to guarantee we always default to table view
        try:
            select = Select(driver.find_element_by_id('viewMode'))
        # in case moxfield doesn't properly load the page
        # we return None here, relying on main.py to retry this until it works
        except:
            return
        # option 0 = view mode as a table, if visual view is on instead
        if select.all_selected_options[0] != select.options[0]:
            # when opening moxfield links w/ visual view in headless,
            # 'deck-footer ' will obscure the dropdown that lets you change
            # use javascript to hide the div 'deck-footer '
            e = driver.find_element_by_xpath("//div[@class='deck-footer ']")
            driver.execute_script("arguments[0].style.visibility='hidden'",e)
            try:
                select.select_by_value('table')
            except:
                return
            # refresh the soup for the updated html
            html = driver.page_source
            soup = bs(html,'html.parser')
        for table in soup.find_all(class_='table-deck'):
            # split up card name from type
            text = table.text.strip().split(maxsplit=1)
            # use regex to filter card names
            cards = text[1].split(')',1)[1]
            if 'Lands' in text[0]:
                if 'mdfc' in text[1]:
                    cards = text[1].split('mdfc',1)[1]
            cards = re.split(r'[\d+]',cards)[1:]
            # check for companions in sideboard
            if 'Sideboard' in text[0]:
                for i,row in enumerate(table.tbody.find_all('tr')):
                    if row.select('#companion-icon'):
                        self.decklist.add(cards[i])
                        break
                continue
            for card in cards:
                super()._add_card(card)


from django.conf.urls import url

# from apps.user import views
# from django.contrib.auth.decorators import login_required

from apps.user.views import (RegisterView, ActiveView, LoginView, UserInfoView, UserOrderView,
                             AddressView, LogoutView, TestView)

urlpatterns = [
    url(r"^register/$", RegisterView.as_view(), name='register'),    # 将注册改为类视图的使用模式
    # url(r"^register/$", views.register, name='register'),
    # url(r"^register_handle/$", views.register_handle, name='register_handle'),

    # url(r"^active/(?P<token>.*)$", ActiveView.as_view(), name='active'),    # 用户激活 拼接 url 的模式
    url(r"^active/$", ActiveView.as_view(), name='active'),    # 用户激活 将 token 作为参数进行传递

    url(r"^login/$", LoginView.as_view(), name='login'),    # 用户登录
    url(r"^logout/$", LogoutView.as_view(), name='logout'),    # 用户登出

    # login_required 要在视图函数上使用 as_view() 的返回值是函数 所以我们要在这里手动调用一次
    # url(r"^$", login_required(UserInfoView.as_view()), name='info'),    # info
    # url(r"^order/$", login_required(UserOrderView.as_view()), name='order'),    # order
    # url(r"^site/$", login_required(AddressView.as_view()), name='site'),    # site

    url(r"^$", UserInfoView.as_view(), name='info'),  # info
    url(r"^order/$", UserOrderView.as_view(), name='order'),  # order
    url(r"^site/$", AddressView.as_view(), name='site'),  # site

    url(r"^test/$", TestView.as_view(), name='test'),  # test

]


# Double linked list

class Node(object):
    def __init__(self, data=None, next=None, prev=None):
        self.data = data
        self.next = next
        self.prev=  prev

class DoubleLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def insertAtStart(self, data):
        newNode = Node(data, None, None)
        newNode.next = self.head

        if self.head is not None:
            self.head.prev = newNode

        self.head = newNode
        return

    def insertAfter(self, prevNode, data):
        temp = self.head

        while(temp.next is not None):         # get last node
            if temp.data == prevNode:
                prevNode = temp
                break
            temp = temp.next

        if temp.next == None:
            return

        newNode = Node(data, None, None)

        newNode.next = prevNode.next

        prevNode.next = newNode

        newNode.prev = prevNode

        if newNode.next is not None:
            newNode.next.prev = newNode

        return

    def insertAtEnd(self, data):
        newNode = Node(data, None, None)
        temp = self.head
        if temp is None:
            return self.insertAtStart(data)

        while(temp.next is not None):         # get last node
            temp = temp.next
        temp.next = newNode
        newNode.prev = temp

        return

    def print_list(self):
        # if self.is_empty():
        #     print("Queue is empty")
        #     return

        current = self.head
        while current is not None:
            print(current.data, end=" ")
            current = current.next

    def clear(self):
        self.head = None
        self.tail = None

if __name__ == "__main__":
    dll = DoubleLinkedList()

    dll.insertAtEnd("A")
    dll.insertAtEnd("C")
    dll.insertAtEnd("D")
    dll.insertAtEnd("F")

    print("Insert pertama: ")
    dll.print_list()
    print("\n")

    dll.insertAfter("A", "B")
    dll.insertAfter("D", "E")

    print("Insert After yaitu menambahkan elemen B dan E: ")
    dll.print_list()


#@+leo-ver=5-thin
#@+node:ekr.20220823200700.1: * @file ../plugins/leofts.py
import os
from whoosh.index import create_in, open_dir
from whoosh.fields import ID, TEXT, Schema
from whoosh.qparser import MultifieldParser
from whoosh.analysis import RegexTokenizer, LowercaseFilter, StopFilter

g = None

#@+others
#@+node:ekr.20220823205609.1: ** set_leo
def set_leo(gg):
    global g
    g = gg
    g._fts = None

#@+node:ekr.20220823205609.2: ** init
def init():

    print("bigdash init")
    import leo.core.leoGlobals as g

    set_leo(g)
    ok = g.app.gui.guiName() == "qt"
    g._fts = None
    g._gnxcache = GnxCache()

    return ok

#@+node:ekr.20220823205609.3: ** get_fts
def get_fts():
    if g._fts is None:
        g._fts = LeoFts(g.app.homeLeoDir + "/fts_index")
    return g._fts

#@+node:ekr.20220823205609.4: ** all_positions_global
def all_positions_global():
    for c in g.app.commanders():
        for p in c.all_unique_positions():
            yield(c, p)

#@+node:ekr.20220823205609.5: ** class GnxCache
class GnxCache:
    """ map gnx => vnode """
    #@+others
    #@+node:ekr.20220823205610.1: *3* __init__
    def __init__(self):
        self.clear()
    #@+node:ekr.20220823205610.2: *3* update_new_cs
    def update_new_cs(self):
        for c in g.app.commanders():
            if c.hash() not in self.cs:
                for p in c.all_unique_positions():
                    k = p.gnx
                    self.ps[k] = c, p.v
                self.cs.add(c.hash())

    #@+node:ekr.20220823205610.3: *3* get
    def get(self, gnx):
        if not self.ps:
            self.update_new_cs()
        res = self.ps.get(gnx, None)
        return res
    #@+node:ekr.20220823205610.4: *3* get_p
    def get_p(self, gnx):
        r = self.get(gnx)
        if r:
            c, v = r
            for p in c.all_unique_positions():
                if p.v is v:
                    return c, p.copy()

        print("Not in gnx cache, slow!")

        for c, p in all_positions_global():

            if p.gnx == gnx:
                return c, p.copy()
        return None

    #@+node:ekr.20220823205610.5: *3* clear
    def clear(self):
        self.ps = {}
        self.cs = set()

    #@-others
#@+node:ekr.20220823205610.6: ** class LeoFts
class LeoFts:
    #@+others
    #@+node:ekr.20220823205610.7: *3* __init__
    def __init__(self, idx_dir):
        self.idx_dir = idx_dir
        if not os.path.exists(idx_dir):
            os.mkdir(idx_dir)
            self.create()
        else:
            self.ix = open_dir(idx_dir)

    #@+node:ekr.20220823205610.8: *3* schema
    def schema(self):
        my_analyzer = RegexTokenizer("[a-zA-Z_]+") | LowercaseFilter() | StopFilter()
        schema = Schema(
            h=TEXT(stored=True, analyzer=my_analyzer),
            gnx=ID(stored=True), b=TEXT(analyzer=my_analyzer),
            parent=ID(stored=True),
            doc=ID(stored=True),
        )
        return schema

    #@+node:ekr.20220823205610.9: *3* create
    def create(self):

        schema = self.schema()
        self.ix = create_in(self.idx_dir, schema)

    #@+node:ekr.20220823205610.10: *3* index_nodes
    def index_nodes(self, c):
        writer = self.ix.writer()
        doc = c.mFileName
        for p in c.all_unique_positions():
            if p.hasParent():
                par = p.parent().get_UNL()
            else:
                par = c.mFileName

            writer.add_document(h=p.h, b=p.b, gnx=p.gnx, parent=par, doc=doc)

        writer.commit()
        g._gnxcache.clear()

    #@+node:ekr.20220823205610.11: *3* drop_document
    def drop_document(self, docfile):
        writer = self.ix.writer()
        print("Drop index", docfile)
        writer.delete_by_term("doc", docfile)
        writer.commit()

    #@+node:ekr.20220823205610.12: *3* statistics
    def statistics(self):
        r = {}
        with self.ix.searcher() as s:
            r['documents'] = list(s.lexicon("doc"))  # pylint:disable=no-member
        print("stats", r)
        return r

    #@+node:ekr.20220823205610.13: *3* search
    def search(self, searchstring, limit=30):

        res = []
        g._gnxcache.update_new_cs()
        with self.ix.searcher() as searcher:
            query = MultifieldParser(["h", "b"], schema=self.schema()).parse(searchstring)
            results = searcher.search(query, limit=limit)
            print(results)
            for r in results:
                rr = r.fields()

                gnx = rr["gnx"]
                tup = g._gnxcache.get(gnx)
                if tup:
                    rr['f'] = True
                    cont = tup[1].b

                    hl = r.highlights("b", text=cont)
                    rr["highlight"] = hl

                else:
                    rr['f'] = False
                res.append(rr)

        return res

    #@+node:ekr.20220823205610.14: *3* close
    def close(self):
        self.ix.close()

    #@-others
#@+node:ekr.20220823205610.15: ** main
def main():
    fts = LeoFts("c:/t/ltest")
    fts.create()

#@-others
if __name__ == '__main__':
    main()

#@@language python
#@@tabwidth -4
#@-leo


"""
This file is part of HornMorpho.

    HornMorpho is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    HornMorpho is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with HornMorpho.  If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------------
Author: Michael Gasser <gasser@indiana.edu>

Strip off affixes, returning stem and affixes.

"""

import re

def sub_curry(lg='', n=1, acc=0, deacc=0, ins=''):
    """Function returning a function that takes a match object, to
    be used as the second argument of re.subn."""
    def subber(match):
        result = ''
        for gindex in range(n):
            i = gindex + 1
            string = match.group(i)
            if i == acc:
                string = lg.accent[string]
            elif i == deacc:
                string = lg.deaccent[string]
            result += string
        if ins:
            result += ins
        return result
    return subber

def sufstrip(word, suffixes, verbose=False):
    """
    word: string
    suffixes: dict with strings as keys and dicts of features values.
    Returns a list of segmentations and analyses.
    """
    # Start at the left-end to prefer longer suffixes
    result = []
    for n in range(1, len(word)):
        suf = word[n:]
#        print('suf {}'.format(suf))
        if suf in suffixes:
            attribs = suffixes[suf]
            aff = attribs[0]
            entries = attribs[1:]
            for entry in entries:
                stem = word[:n]
                pat = entry.get('pat', '')
                change = entry.get('change')
                # Use a different suffix for this entry
                aff = entry.get('aff', aff)
                # Whether to analyze the resulting stem (default is True)
                anal = entry.get('anal', entry.get('pos'))
                if pat and not change:
                    # Just check to see whether the entry matches the pattern
                    # and return it unchanged
#                    print("Trying to match pattern {} against stem {}".format(pat, stem))
                    if re.search(pat, stem):
                        result.append((stem + aff, entry.get('gram'), anal))
                    else:
                        continue
                if pat and change:
                    form, nmatch = re.subn(pat, change, stem)
                    if nmatch:
                        # form has changed
                        result.append((form + aff, entry.get('gram'), anal))
                    else:
                        continue
    return result

def accent(word, index):
    """Accent the first vowel in index position on right side."""
    count = 0
    segs = []
    done = False
    for pos in range(1, len(word)+1):
        c = word[-pos]
        if c in ACCENT and not done:
            if count == index:
                segs.insert(0, ACCENT[c])
                done = True
            else:
                count += 1
                segs.insert(0, c)
        else:
            segs.insert(0, c)
    return ''.join(segs)

def deaccent(word, index):
    """Deaccent the first vowel in index position on right side.
    If index is negative, deaccent all vowels."""
    count = 0
    segs = []
    done = False
    for pos in range(1, len(word)+1):
        c = word[-pos]
#        print('pos {}, count {}, c {}'.format(pos, count, c))
        if done or c not in DEACCENT:
            segs.insert(0, c)
            if c in ACCENT:
                count += 1
        elif c in DEACCENT:
            if index < 0 or count == index:
                segs.insert(0, DEACCENT[c])
                done = True
            else:
                count += 1
                segs.insert(0, c)
    return ''.join(segs)

#### Worry about prefixes later.
##
##def prestrip(word, prefixes):
##    """word: string
##    prefixes: dict with strings as keys and lists of prefixes as values.
##    """
##    # Start at right-end of word to prefer longer prefixes
##    for n in range(1, len(word)):
##        pre = word[:-n]
###        print('pre {}'.format(pre))
##        if pre in prefixes:
##            stem = word[-n:]
##            return stem + prefixes[pre].get('aff', '')
##    return False

##def left_accent(word, index):
##    """Accent the first vowel in index position on left side."""
##    count = 0
##    segs = []
##    done = False
##    for pos in range(0, len(word)):
##        c = word[pos]
##        if c in ACCENT and not done:
##            if count == index:
##                segs.append(ACCENT[c])
##                done = True
##            else:
##                count += 1
##                segs.append(c)
##        else:
##            segs.append(c)
##    return ''.join(segs)
##
##def left_deaccent(word, index):
##    """Deaccent the first vowel in index position on left side."""
##    count = 0
##    segs = []
##    done = False
##    for pos in range(0, len(word)):
##        c = word[pos]
##        if c in ACCENT and not done:
##            if count == index:
##                segs.append(ACCENT[c])
##                done = True
##            else:
##                count += 1
##                segs.append(c)
##        else:
##            segs.append(c)
##    return ''.join(segs)


# -*- coding: utf-8 -*-
"""
: Sat Mar 25 2020, 08:30:56

version: Version 1

Description:
    1. Developed a function to compute Earth repeat orbits geometry when
        a or i, j, k, e are provided as inputs
    2. Low fidelity approach (default) where Earth-repeat orbit solutions are
        computed cosindering the effect of $J_2$ perturbation on $\Omega$ only
    3. High fidelity approach where Earth-repeat orbit solutions are
        computed cosindering the effect of $J_2$ perturbation on $\Omega$,
        $\omega$, and $M$
    4. Either altitude or inclination values (minimum,maximum,step size) are
        to be provided.
    5. Low fidelity approach does not work when the inclination is known
        while altitude is unknown
    6. For eccentric orbits, altitude values (input and output) should
        corrospond to the perigee altitude.

"""

import numpy as np2

def EarthRepeatOrbits(jk,e,Variable,VarType,isHighFidelity=False,printStatus=False):
    # importing the required modules
    import spiceypy as spice
    import math
    import numpy as np

    Result = 0
    Nsolutions = 0

    # Error handling
    jkSize = jk.shape
    if (int(jkSize[1])!=2):
        print('Incorrect matrix size for jk matrix. Only two coloumns are required.')
        return Result
    elif (VarType != 'Alti') and (VarType != 'Inclin'):
        print('Inrecognized input for the argument specifying the variable type.')
        return Result
    elif e >= 1.0 or e < 0:
        print('Only circular or elliptical orbits are possible. Check the value of eccentricity.')
        return Result
    elif (Variable[1]-Variable[0])% Variable[2] !=0:
        print('Integer number of steps are not possible. Check inputs for the argument - "Variable".')
        return Result

    # Extracting the parameters
    spice.furnsh("./External_files/Spice_kernels/kernel_load.txt")
    muE = spice.bodvrd('Earth','GM',1)
    mu = muE[1][0] #km3/s2 for earth
    J2 = 1082.63E-6 #J2 for earth - import from spice
    RE = spice.bodvrd('EARTH','RADII',3)
    Re= RE[1][0]
    De = 86164.1004 # s, Sidereal day, to be extracted from spice
    k2 = 0.75 * J2 * math.sqrt(mu)* Re*Re
    r2d = 1/spice.rpd() # Radian to degree conversion

    # Creating storage
    steps = int((Variable[1]-Variable[0])/Variable[2])+1
    Result = np.zeros(int(jkSize[0])*int(steps)*6)
    Result.shape= [int(jkSize[0]),int(steps),6]

    # Computations
    for count in range(0,jkSize[0]):
#        print(count)
        for rowCount in range(0,int(steps)):
            j = jk[count,0]
            k = jk[count,1]

            # Extracting the value of variable
            var = Variable[0]+rowCount*Variable[2]

            # Storing values known so far
            Result[count,rowCount,0] = j
            Result[count,rowCount,1] = k
            Result[count,rowCount,2] = e
            Result[count,rowCount,3] = var
            Result[count,rowCount,4] = math.nan # to be computed
            Result[count,rowCount,5] = math.nan # to be computed

            # computations
            if isHighFidelity == False:
#                print('Approach 1')
                if VarType == 'Alti':
#                    print('Inclination is unknown')
#                    if e == 0:
#                        a = Re + var
#                        T = 2 * math.pi * math.sqrt(a**3/mu)
#                    else:
#                        print('Problem not defined yet for non-circular orbits.')
#                        sys.exit # DOES NOT WORK PROPERLY, LOOP IS NOT BROKEN
                    a = (Re + var)/(1-e)
                    T = 2 * math.pi * math.sqrt(a**3/mu)

                    DeltaL1 = -2 * math.pi * (T/De)
                    # DeltaL2 = C1 * cosi
                    C1 = (-3*math.pi * J2 * Re**2)/(a**2 * (1 - e**2)**2)
                    C2 = -2 * math.pi* k/j  - DeltaL1
                    C3 = 2 * math.pi* k/j  - DeltaL1

                    # Inverse cosine
                    if (C2 <0) & (abs(C2/C1) <=1):
                        DeltaL2 = C2
                        i = math.acos(DeltaL2/C1) * r2d # for i = [0, 90] deg
                        Result[count,rowCount,4] = i
                        Nsolutions += 1
                    elif (C2 > 0) & (abs(C2/C1) <=1):
                        DeltaL2 = C2
                        i = math.acos(DeltaL2/C1) * r2d # for i = [90, 180] deg
                        Result[count,rowCount,4] = i
                        Nsolutions += 1
                    elif ( C3 < 0) & (abs(C3/C1) <=1): # this was missing in MATLAB script
                        DeltaL2 = C3
                        i = math.acos(DeltaL2/C1) * r2d # for i = [0, 90] deg
                        Result[count,rowCount,5] = i
                        Nsolutions += 1
                    elif (C3>0) & (abs(C3/C1) <=1):
                        DeltaL2 = C3
                        i = math.acos(DeltaL2/C1) * r2d # for i = [90, 180] deg
                        Result[count,rowCount,5] = i
                        Nsolutions += 1
                elif VarType == 'Inclin':
                    print('Function is not defined for low fidelity + unknown inclination case.')
                    return Result
            else:
#                print('Approach 2')
                if VarType == 'Alti':
#                    if e == 0:
#                        a = Re + var
#                    else:
#                        print('Problem not defined yet for non-circular orbits.')
#                        sys.exit
                    a = (Re + var)/(1-e)
                    C1 = -2 * k2 * (a**-3.5) * ((1-e**2)**-2) * De*r2d  # RAAN_dot = C1 * cos(i)
                    C2 = k2 * (a**-3.5) *((1-e**2)**-2) * De*r2d # omega_dot = C2 *(5*(cosd(i))^2 -1)
                    C3 = k2 * (a**-3.5) *((1-e**2)**-1.5) * De * r2d # M_dot = C3 *(3*(cosd(i))^2 -1)
                    n = De * r2d * math.sqrt(mu/a**3);

                    # For the quadratic equation A*x^2 + B*x +C = 0 with x = cos(i)
                    A = 5* C2 + 3 * C3
                    B = C1 * j/k
                    C = n - 360 *j/k - (C2 + C3)
                    D = B**2-4*A*C

                    if D >=0:
                        if (D == 0) & (abs(-B/(2*A)) <=1):
                            i1 = math.acos(-B/(2*A))
                            Result[count,rowCount,4] = i1*r2d
                            Nsolutions += 1
                        elif (D > 0):
                            x1 = (-B + math.sqrt(D))/ (2 * A)
                            x2 = (-B - math.sqrt(D))/ (2 * A)
                            if abs(x1) <=1:
                                i1 = math.acos(x1)
                                Result[count,rowCount,4] = i1*r2d
                                Nsolutions += 1
                            if abs(x2) <=1:
                                i2 = math.acos(x2)
                                Result[count,rowCount,5] = i2*r2d
                                Nsolutions += 1
                elif VarType == 'Inclin':

                    a0 = math.pow((mu*De**2*k**2/(4*math.pi**2*j**2)),1/3)
                    iterations = 0
                    i = var
                    L_dot = 360

                    while True:
                        iterations = iterations+1

                        RAAN_dot = - 2 * k2 * math.pow(a0,-3.5) * math.cos(i/r2d) * math.pow(1-e**2,-2) * De * r2d
                        #       print(RAAN_dot)
                        omega_dot = k2 * math.pow(a0,-3.5) * (5*(math.cos(i/r2d))**2 -1) * math.pow(1-e**2,-2) * De * r2d
                        #       print(omega_dot)
                        M_dot = k2 * math.pow(a0,-3.5) * (3*(math.cos(i/r2d))**2 -1) * math.pow(1-e**2,-1.5) * De * r2d
                        #       print(M_dot)
                        n = (j/k) * (L_dot - RAAN_dot) -(omega_dot + M_dot)
                        #       print(n)
                        a1 = (mu/(n/(De*r2d))**2)**(1/3)
                        #       print('a1 is:',a1)

#                      # print('At iteration:',iterations,' a1 was ',a1, 'a0 was', a0)
                        if iterations > 1000:
#                            print('Maximum number of iterations executed')
                            a0 = a1
                            break
                        elif (abs(a1-a0) < 10**(-10)):
#                            print('Convergence reached after ',iterations, 'iterations')
                            a0 = a1
                            break
                        else:
                            a0 = a1

                    # Only tracking the feasible solutions
                    if ((a0 * (1-e)) - Re) > 0:
                        Nsolutions += 1
                        Result[count,rowCount,4] = (a0 * (1-e)) - Re

    # Printing the status of solutions obtained
    if printStatus == True:
        print(Nsolutions, ' solutions are obtained for the Earth-repeat orbits.')

#    print(Result.shape)
    return Result

##########################
######### Executing runs
##########################

Run = 1 # 1 - Approach 1 with i as unknown
        # 2 - Approach 2 with i as unknown
        # 3 - Approach 2 with altitude as unknown

# Approach 1, i as unknown
if Run == 1:
#    jk = np.matrix('14, 1; 43, 3; 29, 2; 59, 4; 74, 5 ; 15,1')
    jk = np2.matrix('39, 3; 40, 3; 41, 3; 42, 3; 43,3; 44, 3 ; 45,3; 46, 3; 47,3 ; 48, 3')
    e = 0.1
    a = np2.array([200,2000,5])
    Result = EarthRepeatOrbits(jk,e,a,'Alti',False,True)

# Approach 2, i as unknown
elif Run == 2:
    jk = np2.matrix('39, 3; 40, 3; 41, 3; 42, 3; 43,3; 44, 3 ; 45,3; 46, 3; 47,3 ; 48, 3')
    e = 0.1
    a = np2.array([200,2000,5])
    Result = EarthRepeatOrbits(jk,e,a,'Alti',True,True)

# Approach 2 with altitude as unknown
elif Run == 3:
    jk = np2.matrix('14, 1; 43, 3; 29, 2; 59, 4; 74, 5 ; 15,1')
    e = 0
    a = np2.array([28,29,1])
    Result = EarthRepeatOrbits(jk,e,a,'Inclin',True,True)


import itertools

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import torch
import torch.utils.data
import torchvision
from torch.utils.data import Dataset

class ImbalancedDatasetSampler(torch.utils.data.sampler.Sampler):
    """Samples elements randomly from a given list of indices for imbalanced dataset
    Arguments:
        indices (list, optional): a list of indices
        num_samples (int, optional): number of samples to draw
    """

    def __init__(self, dataset, indices=None, num_samples=None):

        # if indices is not provided,
        # all elements in the dataset will be considered
        self.indices = list(range(len(dataset))) \
            if indices is None else indices

        # if num_samples is not provided,
        # draw `len(indices)` samples in each iteration
        self.num_samples = len(self.indices) \
            if num_samples is None else num_samples

        # distribution of classes in the dataset
        label_to_count = {}
        for idx in self.indices:
            label = self._get_label(dataset, idx)
            if label in label_to_count:
                label_to_count[label] += 1
            else:
                label_to_count[label] = 1

        # weight for each sample
        weights = [1.0 / label_to_count[self._get_label(dataset, idx)]
                   for idx in self.indices]
        self.weights = torch.tensor(weights, dtype=torch.float)

    def _get_label(self, dataset, idx):
        dataset_type = type(dataset)
        if dataset_type is torchvision.datasets.MNIST:
            return dataset.train_labels[idx].item()
        elif dataset_type is torchvision.datasets.ImageFolder:
            return dataset.imgs[idx][1]
        else:
            return dataset[idx][1]

    def __iter__(self):
        return (self.indices[i] for i in torch.multinomial(
            self.weights, self.num_samples, replacement=True))

    def __len__(self):
        return self.num_samples

class Dictionary:
    def __init__(self):
        self.word2idx = {}
        self.idx2word = {}
        self.idx = 0

    def add_word(self, word: str):
        if word not in self.word2idx:
            self.word2idx[word] = self.idx
            self.idx2word[self.idx] = word
            self.idx += 1

    def __len__(self):
        return len(self.word2idx)

class RawDataset(Dataset):
    """
    Intentionally to use only
    """

    def __init__(self, df: pd.DataFrame):
        super().__init__()
        self.df = df.copy()
        self.len = len(self.df)

    def __getitem__(self, index):
        record = self.df.iloc[index]
        return record.Phrase, record.Sentiment

    def __len__(self):
        return self.len

def plot_confusion_matrix(cm, classes,
                          normalize=False,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    """
    This function prints and plots the confusion matrix.
    Normalization can be applied by setting `normalize=True`.
    """
    print(cm)
    plt.figure(figsize=(10, 10))
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=45)
    plt.yticks(tick_marks, classes)

    fmt = '.2f' if normalize else 'd'
    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, format(cm[i, j], fmt),
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.tight_layout()

def make_var(names):
    ans = []
    for name in sorted(names, reverse=True, key=len):
        name = name.lower()
        tmp = [ord(chr) for chr in name]
        tmp = torch.tensor(tmp, dtype=torch.long)
        ans.append(tmp)
    return torch.nn.utils.rnn.pad_sequence(ans, batch_first=True)

def count_non_zero_length(aaa):
    """
    aaa = [[116, 105, 114,  97, 115],
         [ 97, 110, 110,   0,   0],
         [101, 108,   0,   0,   0]]
    ans -> [5, 3, 2]
    """
    bbb = []
    for item in aaa:
        counting = 0
        for element in item:
            if element != 0:
                counting += 1
        bbb.append(counting)
    return bbb

def str2ascii_arr(name):
    """
    0-255
    """
    arr = [ord(c) for c in name]
    return arr, len(arr)


from discord.ext import commands
import os
import logging
import bot_tokens as bt

#define what will trigger bot commands
#https://discordpy.readthedocs.io/en/stable/ext/commands/commands.html
bot = commands.Bot(command_prefix='!')

#keeps a running event log while bot is on
#https://discordpy.readthedocs.io/en/stable/logging.html
logger = logging.getLogger('discord')
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(filename='discord.log', encoding='utf-8', mode='w')
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s'))
logger.addHandler(handler)

#posts message to console once the bot has succesfully logged into Discord
#https://discordpy.readthedocs.io/en/stable/quickstart.html
@bot.event
async def on_ready():
	print(f'{bot.user} Initialized')

for filename in os.listdir('./cogs'):
	if filename.endswith('.py'):
		bot.load_extension(f'cogs.{filename[:-3]}')

#!reload (command) to reload edited cogs from discord
@bot.command()
async def reload(ctx):
    #reloads the cog file to update without restarting bot
	bot.reload_extension('cogs.tracking')
	await ctx.send('Cog reloaded.')

#bot's authentication token with Discord
bot.run(bt.DISCORD_TOKEN)


from constructs import Construct
from aws_cdk import Stack
import aws_cdk.aws_route53 as route53
from requests import get

class Route53CdkDyndnsStack(Stack):
    def __init__(
        self,
        scope: Construct,
        construct_id: str,
        hosted_zone_id: str,
        zone_name: str,
        record_name: str,
        **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        ip = get("https://api.ipify.org").text

        zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            "MyZone",
            zone_name=zone_name,
            hosted_zone_id=hosted_zone_id,
        )

        route53.ARecord(
            self,
            "ExternalIP",
            record_name=record_name,
            zone=zone,
            target=route53.RecordTarget.from_ip_addresses(ip),
        )


# Allows using rotate_character and alphabet_position functions
from helpers import rotate_character, alphabet_position

# Encrypts all letters in text by rot letters
def encrypt(text, rot):
    crypted_text = ''
    for char in text:
        crypted_text += rotate_character(char, rot)
    return crypted_text

def main():
    from sys import argv, exit
    if argv[1].isdigit():
        rotation = int(argv[1])
    else:
        print("usage: python caesar.py [INTEGER VALUE]")
        exit()
    text = str(input("Type a message:\n"))
    print(encrypt(text, rotation))

if __name__ == "__main__":
    main()


#!/usr/bin/env python

"""Tests for `blast2xl` package."""

from os.path import abspath
from pathlib import Path

from click.testing import CliRunner

from blast2xl import cli

def test_command_line_interface():
    """Test the CLI."""
    runner = CliRunner()
    help_result = runner.invoke(cli.main, ['--help'])
    assert help_result.exit_code == 0
    assert 'blast2xl: BLAST XLSX Report Creator' in help_result.stdout

    result = runner.invoke(cli.main)
    assert result.exit_code == 2
    assert 'Missing option' in result.output

    blast_tsv_dir = abspath('tests/data/blast_tsv')
    fasta_dir = abspath('tests/data/fastas')
    with runner.isolated_filesystem():
        excel_report = 'blast-report.xlsx'
        seq_outdir = 'seq-outdir'
        result = runner.invoke(cli.main, ['--blast-tsv-dir', blast_tsv_dir,
                                          '--blast-tsv-sample-name-pattern', r'^blastn-(.+)-vs-nt.*',
                                          '--seq-dir', fasta_dir,
                                          '--top-n-results', 5,
                                          '-o', excel_report,
                                          '-O', seq_outdir,
                                          '-vvv'])

        assert result.exit_code == 0
        path_seq_outdir = Path(seq_outdir)
        assert path_seq_outdir.exists()
        output_fastas = list(path_seq_outdir.glob('**/*.fasta'))
        assert len(output_fastas) > 2

        fasta_path = path_seq_outdir / 'FMDV' / 'Foot_and_mouth_disease_virus___type_O-12118' / 'FMDV.fasta'
        assert fasta_path.exists()
        assert fasta_path.stat().st_size > 0
        assert Path(excel_report).exists()
        assert Path(excel_report).stat().st_size > 0


import mmcv

import argparse
import copy
import json
import os
from collections import defaultdict
from collections import OrderedDict
import os.path as osp
import Polygon as plg

import numpy as np
from PIL import Image
import editdistance

def group_by_key(detections, key):
    groups = defaultdict(list)
    for d in detections:
        groups[d[key]].append(d)
    return groups

def get_union(pa, pb):
    pa_area = pa.area()
    pb_area = pb.area()
    return pa_area + pb_area - get_intersection(pa, pb)

def get_intersection(pa, pb):
    pInt = pa & pb
    if len(pInt) == 0:
        return 0
    else:
        return pInt.area()

def cat_best_hmean(gt, predictions, thresholds):
    num_gts = len([g for g in gt if g['ignore'] == False])
    image_gts = group_by_key(gt, 'name')
    image_gt_boxes = {k: np.array([b['bbox'] for b in boxes])
                      for k, boxes in image_gts.items()}
    image_gt_trans = {k: np.array([b['trans'] for b in boxes])
                      for k, boxes in image_gts.items()}
    image_gt_ignored = {k: np.array([b['ignore'] for b in boxes])
                        for k, boxes in image_gts.items()}
    image_gt_checked = {k: np.zeros((len(boxes), len(thresholds)))
                        for k, boxes in image_gts.items()}
    predictions = sorted(predictions, key=lambda x: x['score'], reverse=True)

    # go down dets and mark TPs and FPs
    nd = len(predictions)
    tp = np.zeros((nd, len(thresholds)))
    fp = np.zeros((nd, len(thresholds)))
    ned = np.zeros((nd, len(thresholds)))
    for i, p in enumerate(predictions):
        pred_polygon = plg.Polygon(np.array(p['bbox']).reshape(-1, 2))
        ovmax = -np.inf
        jmax = -1
        try:
            gt_boxes = image_gt_boxes[p['name']]
            gt_ignored = image_gt_ignored[p['name']]
            gt_checked = image_gt_checked[p['name']]
            gt_trans = image_gt_trans[p['name']]
        except KeyError:
            gt_boxes = []
            gt_checked = None

        if len(gt_boxes) > 0:
            ovmax = 0
            jmax = 0
            for j, gt_box in enumerate(gt_boxes):
                gt_polygon = plg.Polygon(np.array(gt_box).reshape(-1, 2))
                union = get_union(pred_polygon, gt_polygon)
                inter = get_intersection(pred_polygon, gt_polygon)
                overlap = inter / (union + 1e-6)
                if overlap > ovmax:
                    ovmax = overlap
                    jmax = j

        for t, threshold in enumerate(thresholds):
            if ovmax > threshold:
                if gt_checked[jmax, t] == 0:
                    if gt_ignored[jmax]:
                        tp[i, t] = 0.
                        ned[i, t] = 0
                    else:
                        tp[i, t] = 1.
                        ned[i, t] = 1 - editdistance.eval(p['trans'], gt_trans[jmax]) / \
                                    max(len(p['trans']), len(gt_trans[jmax]))
                    gt_checked[jmax, t] = 1
                else:
                    fp[i, t] = 1.
                    ned[i, t] = 0
            else:
                fp[i, t] = 1.

    # compute precision recall
    fp = np.cumsum(fp, axis=0)
    tp = np.cumsum(tp, axis=0)
    ned = np.cumsum(ned, axis=0) / (fp + num_gts + np.finfo(np.float64).eps)

    recalls = tp / float(num_gts)
    # avoid divide by zero in case the first detection matches a difficult
    # ground truth
    precisions = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)

    fmeasures = 2 * precisions * recalls / (precisions + recalls + 1e-6)
    best_i = np.argmax(fmeasures)
    print('[Best F-Measure] p: {:.2f}, r: {:.2f}, f: {:.2f}, 1-ned: {:.2f}, best_score_th: {:.3f}'.format(
        float(precisions[best_i]) * 100, float(recalls[best_i]) * 100, float(fmeasures[best_i]) * 100,
        float(ned[best_i]) * 100, predictions[best_i]['score']))

    best_i = np.argmax(ned)
    print('[Best 1-NED]     p: {:.2f}, r: {:.2f}, f: {:.2f}, 1-ned: {:.2f}, best_score_th: {:.3f}'.format(
        float(precisions[best_i]) * 100, float(recalls[best_i]) * 100, float(fmeasures[best_i]) * 100,
        float(ned[best_i]) * 100, predictions[best_i]['score']))

def trans_pred_format(pred):
    bdd = []
    img_name = pred['img_name']
    ponits = pred['points']
    scores = pred['scores']
    texts = pred['texts']
    for i in range(len(ponits)):
        bdd_i = {
            'category': 'text',
            'timestamp': 1000,
            'name': img_name,
            'bbox': np.array(ponits[i]).reshape(-1).tolist(),
            'score': scores[i],
            'trans': texts[i]
        }
        bdd.append(bdd_i)
    return bdd

def trans_gt_format(img_name, gt):
    bdd = []
    for i in range(len(gt)):
        bdd_i = {
            'category': 'text',
            'timestamp': 1000,
            'name': img_name,
            'bbox': gt[i]['points'],
            'score': 1,
            'ignore': gt[i]['ignore'],
            'trans': gt[i]['transcription']
        }
        bdd.append(bdd_i)
    return bdd

def main():
    cfg = mmcv.Config.fromfile('local_configs/rects_ae_textspotter_lm_r50_1x.py')
    gt_root = cfg.data.val.data_root + cfg.data.val.ann_file
    preds = mmcv.load('results.json')

    preds_bdd = []
    gts_bdd = []
    for pred in preds:
        img_name = pred['img_name']
        pred_bdd = trans_pred_format(pred)
        preds_bdd.extend(pred_bdd)

        gt_path = gt_root + img_name.replace('.jpg', '.json')
        gt = mmcv.load(gt_path)['lines']
        gt_bdd = trans_gt_format(img_name, gt)
        gts_bdd.extend(gt_bdd)

    cat_gt = group_by_key(gts_bdd, 'category')
    cat_pred = group_by_key(preds_bdd, 'category')
    thresholds = [0.5]
    cat_best_hmean(cat_gt['text'], cat_pred['text'], thresholds)

if __name__ == '__main__':
    main()


#!/usr/bin/env python3

class SparseArray(object):

    def __init__(self, sequence):
        self.iter_current = 0
        self.values_map = {}
        self.length = len(sequence)
        for i, item in enumerate(sequence):
            if item != 0:
                self.values_map[i] = item

    def __str__(self):
        return str(self.inflate_sequence())

    def __len__(self):
        return self.length

    def __getitem__(self, key):
        if isinstance(key, slice):
            return self.get_slice(key)
        else:
            if (key < 0):
                key = self.length + key
            if (key > self.length - 1):
                raise IndexError("Index out of bounds.")
            return self.values_map.get(key, 0)

    def __setitem__(self, key, value):
        if (key > self.length - 1):
            raise IndexError("Index out of bounds.")
        self.values_map[key] = value

    def __delitem__(self, key):
        if (key > self.length - 1):
            raise IndexError("Index out of bounds.")
        try:
            del self.values_map[key]
        except KeyError:
            pass
        finally:
            self.remove_item(key)
            self.length = self.length - 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.iter_current >= self.length:
            raise StopIteration
        else:
            self.iter_current += 1
            return self.__getitem__(self.iter_current - 1)

    # object.__reversed__(self)
    # object.__contains__(self, item)

    # object.__index__(self)

    def get_slice(self, key):
        print('Slice Start: ' + str(key.start))
        print('Slice End: ' + str(key.stop))
        print('Slice Step: ' + str(key.step))
        array_slice = []

        start = key.start or 0
        stop = key.stop or self.length
        step = key.step or 1
        if (stop < 0):
            stop = self.length + stop

        if step < 0:
            tmp_stop = stop
            stop = start - 1
            start = tmp_stop - 1

        for i in range(start, stop, step):
            array_slice.append(self.values_map.get(i, 0))
        return array_slice

    def inflate_sequence(self):
        sequence = []
        for i in range(self.length):
            sequence.append(self.values_map.get(i, 0))
        return sequence

    def remove_item(self, key):
        for i in range(self.length):
            if i > key:
                print('Trying ' + str(i))
                try:
                    val = self.values_map[i]
                    del self.values_map[i]
                    self.values_map[i - 1] = val
                except KeyError:
                    pass


'''
根据每日 气温 列表，请重新生成一个列表，对应位置的输入是你需要再等待多久温度才会升高的天数。如果之后都不会升高，请输入 0 来代替。

例如，给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]，你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示：气温 列表长度的范围是 [1, 30000]。每个气温的值的都是 [30, 100] 范围内的整数。
'''

class Solution:
    def dailyTemperatures(self, T):
        """
        :type T: List[int]
        :rtype: List[int]
        """
        l = len(T)
        res=[0]*l
        stack = []
        i = 0
        while i<l:
            if not stack or stack[-1]>=T[i]:
                stack.append(T[i])
            else:
                idx = T.index(stack.pop())
                T[idx] = 0
                res[idx] = i-idx
                continue
            i+=1
        l = len(stack)

        return res

S=Solution()
T=[73, 74, 75, 71, 69, 72, 76, 73]
print(S.dailyTemperatures(T))