import datetime as dt
from typing import List, Optional

from takumi.campaigns import campaign_reserve_state
from takumi.error_codes import (
    CAMPAIGN_NOT_LAUNCHED_ERROR_CODE,
    CAMPAIGN_NOT_RESERVABLE_ERROR_CODE,
    CAMPAIGN_REQUIRES_REQUEST_ERROR_CODE,
    INFLUENCER_NOT_ELIGIBLE_ERROR_CODE,
    INVALID_OFFER_STATE_ERROR_CODE,
    OFFER_REWARD_CHANGED_ERROR_CODE,
    UNREJECTABLE_OFFER_ERROR_CODE,
)
from takumi.events.offer import OfferLog
from takumi.extensions import db
from takumi.i18n import gettext as _
from takumi.i18n import locale_context
from takumi.models import Comment, Config, Notification, Offer, OfferEvent, UserCommentAssociation
from takumi.models.campaign import STATES as CAMPAIGN_STATES
from takumi.models.influencer import STATES as INFLUENCER_STATES
from takumi.models.offer import STATES as OFFER_STATES
from takumi.notifications import NotificationClient
from takumi.rewards import RewardCalculator
from takumi.schedule.period import DateTimePeriod
from takumi.services import Service
from takumi.services.exceptions import (
    AlreadyRequestedException,
    ApplyFirstException,
    CampaignFullyReservedException,
    CampaignNotLaunchedException,
    CampaignRequiresRequestForParticipation,
    InfluencerNotEligibleException,
    InfluencerOnCooldownForAdvertiserException,
    InvalidAnswersException,
    OfferAlreadyClaimed,
    OfferAlreadyExistsException,
    OfferNotClaimableException,
    OfferNotDispatchableException,
    OfferNotRejectableException,
    OfferNotReservableException,
    OfferPushNotificationException,
    OfferRewardChangedException,
    ServiceException,
)
from takumi.tasks.instagram_account import update_latest_posts

from .campaign import CampaignService
from .influencer import InfluencerService

def validate_answers(prompts, answers):
    if prompts == []:
        return

    if answers is None or len(prompts) != len(answers):
        raise InvalidAnswersException(_("You need to answer all the prompts to participate!"))

    prompts = sorted(prompts, key=lambda x: x["text"])
    answers = sorted(answers, key=lambda x: x["prompt"])

    for prompt, answer in zip(prompts, answers):
        if prompt["type"] == "confirmation":
            if len(prompt["choices"]) != len(answer["answer"]):
                raise InvalidAnswersException(_("All confirmations need to be accepted!"))
        else:
            answer_choices = answer["answer"]
            answer_text = "".join(answer_choices).strip()
            if len(answer_choices) == 0 or answer_text == "":
                raise InvalidAnswersException(
                    _("You need to answer '%(prompt)s'", prompt=prompt["text"])
                )

class OfferService(Service):
    """
    Represents the business model for Offer. This is the bridge between
    the database and the application.
    """

    SUBJECT = Offer
    LOG = OfferLog

    @property
    def offer(self) -> Offer:
        return self.subject

    # GET
    @staticmethod
    def get_by_id(offer_id) -> Optional[Offer]:
        return Offer.query.get(offer_id)

    @staticmethod
    def get_top_offers_in_campaign(campaign_id: str) -> Optional[List[Offer]]:
        """A method that filters all accepted offers related to a specific campaign,
        is ranked descending by ER in-feed and capped at the top three.

        Note:
            One offer has one creator, therefore, together with all continents of one offer,
            we get a specific Creator.

        Args:
            campaign_id: The campaign's id.

        Returns:
            List of filtered and sorted offers.
        """
        return (
            Offer.query.filter(
                Offer.campaign_id == campaign_id,
                Offer.state == OFFER_STATES.ACCEPTED,
                Offer.engagement_rate_static != 0,
            )
            .order_by(Offer.engagement_rate_static.desc().nullslast())  # type: ignore
            .limit(3)
            .all()
        )

    @staticmethod
    def get_for_influencer_in_campaign(influencer_id, campaign_id) -> Optional[Offer]:
        return Offer.query.filter(
            Offer.influencer_id == influencer_id, Offer.campaign_id == campaign_id
        ).one_or_none()

    @staticmethod
    def get_push_notifications(offer_id):
        return (
            OfferEvent.query.join(Offer)
            .filter(OfferEvent.type == "send_push_notification", Offer.id == offer_id)
            .with_entities(OfferEvent.created)
            .order_by(OfferEvent.created.desc())
        ).all()

    @staticmethod
    def get_revoke_event(id):
        return (
            OfferEvent.query.filter(OfferEvent.offer_id == id, OfferEvent.type == "revoke")
            .order_by(OfferEvent.created.desc())
            .first()
        )

    @staticmethod
    def get_rejected_date(id):
        """Rejected date is the date that an offer was one of:

        1. Rejected by influencer
        2. Revoked by Takumi
        3. Rejected by a client
        """
        return (
            OfferEvent.query.filter(
                OfferEvent.offer_id == id,
                OfferEvent.type.in_(("reject", "revoke", "reject_candidate")),
            )
            .with_entities(OfferEvent.created)
            .order_by(OfferEvent.created.desc())
            .limit(1)
            .scalar()
        )

    @staticmethod
    def get_from_filter(
        filter_by=tuple(), order_by=tuple(), with_entities=(Offer,), limit=None, method="all"
    ):
        return getattr(
            Offer.query.filter(*filter_by)
            .order_by(*order_by)
            .with_entities(*with_entities)
            .limit(limit),
            method,
        )()

    @classmethod  # NOQA: C901
    def create(cls, campaign_id, influencer_id, reward=None, skip_targeting=False):
        influencer = InfluencerService.get_by_id(influencer_id)
        campaign = CampaignService.get_by_id(campaign_id)

        if influencer is None:
            raise ServiceException(f"<Influencer: {influencer_id}> not found")

        if campaign is None:
            raise ServiceException(f"<Campaign: {campaign_id}> not found")

        if reward is None:
            reward = RewardCalculator(campaign).calculate_reward_for_influencer(influencer)

        if not campaign.fund.is_reservable():
            raise CampaignFullyReservedException("Campaign is already fully reserved")

        if campaign.advertiser.on_cooldown(influencer):
            raise InfluencerOnCooldownForAdvertiserException(
                'Influencer: "{}" is on cooldown for advertiser "{}"'.format(
                    influencer.username, campaign.advertiser.name
                )
            )

        if campaign.submission_deadline and campaign.submission_deadline < dt.datetime.now(
            dt.timezone.utc
        ):
            raise ServiceException("A submission deadline for the campaign has already passed")
        if campaign.deadline and campaign.deadline < dt.datetime.now(dt.timezone.utc):
            raise ServiceException("A deadline for the campaign has already passed")

        existing_offer = cls.get_for_influencer_in_campaign(influencer.id, campaign.id)
        if existing_offer is not None:
            raise OfferAlreadyExistsException(
                "<Influencer {}> already has an offer (<Offer {}>) for <Campaign {}>".format(
                    influencer.id, existing_offer.id, campaign.id
                )
            )

        if not skip_targeting:
            influencer_eligible_for_campaign = (
                influencer.state in (INFLUENCER_STATES.VERIFIED, INFLUENCER_STATES.REVIEWED)
                and influencer.is_eligible
                and campaign.targeting.targets_influencer(influencer)
            )

            if not influencer_eligible_for_campaign:
                raise InfluencerNotEligibleException(
                    "Influencer is not eligible", INFLUENCER_NOT_ELIGIBLE_ERROR_CODE
                )
        if influencer.target_region:
            vat_percentage = influencer.target_region.get_vat_percentage(
                dt.datetime.now(dt.timezone.utc).date()
            )
        else:
            vat_percentage = None

        offer = Offer()
        log = OfferLog(offer)

        if influencer.instagram_account:
            followers_per_post = influencer.instagram_account.followers
        else:
            followers_per_post = 0

        log.add_event(
            "create" if campaign.apply_first else "create_invite",
            {
                "campaign_id": campaign.id,
                "influencer_id": influencer.id,
                "vat_percentage": vat_percentage,
                "reward": reward,
                "followers_per_post": followers_per_post,
                "engagements_per_post": influencer.estimated_engagements_per_post,
            },
        )

        db.session.add(offer)
        db.session.commit()

        # Trigger an update of latest posts for the influencer
        if influencer.instagram_account:
            update_latest_posts.delay(influencer.instagram_account.id)

        return offer

    # PUT
    def make_comment(self, content, creator):
        self.offer.comments.append(Comment.create(content, creator, self.offer))

    def mark_comments_as_seen_by(self, user):
        for comment in self.offer.comments:
            if not comment.seen_by_user(user.id):
                UserCommentAssociation.create(user, comment)

    def revoke(self, notify=True):
        if self.offer.is_claimable:
            raise ServiceException("Can't revoke a claimable offer")
        if self.offer.state not in (
            OFFER_STATES.PENDING,
            OFFER_STATES.INVITED,
            OFFER_STATES.ACCEPTED,
            OFFER_STATES.REQUESTED,
            OFFER_STATES.APPROVED_BY_BRAND,
            OFFER_STATES.CANDIDATE,
        ):
            raise ServiceException(f"Can't revoke a {self.offer.state} offer")
        self.log.add_event("revoke")

        if notify:
            influencer = self.offer.influencer
            if self.offer.state == OFFER_STATES.REQUESTED and influencer.has_device:
                client = NotificationClient.from_influencer(influencer)
                with locale_context(influencer.user.request_locale):
                    client.send_rejection(
                        _(
                            'Unfortunately, you weren\'t selected for "%(campaign)s"',
                            campaign=self.offer.campaign.name,
                        ),
                        self.offer.campaign,
                    )

    def renew(self):
        self.log.add_event("renew")

    def request_participation(self, answers=[], ignore_prompts=False):
        from takumi.services.influencer import FetchingAudienceInsightsFailed, InfluencerService

        influencer = self.offer.influencer
        user = influencer.user
        campaign = self.offer.campaign

        if user.facebook_account:
            try:
                InfluencerService(self.offer.influencer).fetch_and_save_audience_insights()
            except FetchingAudienceInsightsFailed:
                pass

        if campaign.requires_tiktok_account and not influencer.user.tiktok_username:
            raise ServiceException(
                "This campaign requires a TikTok account. Please configure a TikTok username in your profile."
            )
        if self.offer.campaign.requires_facebook:
            if not influencer.info.get("FACEBOOK_PAGE_SKIP_CAMPAIGN_CHECK", False) and (
                not influencer.user.facebook_account or not influencer.user.facebook_account.active
            ):
                raise ServiceException("Please link your Facebook account")
        if self.offer.state == OFFER_STATES.REQUESTED:
            raise AlreadyRequestedException("Participation has already been requested")
        if self.offer.state == OFFER_STATES.REJECTED:
            raise ServiceException("Offer has already been rejected")

        if not ignore_prompts:
            validate_answers(campaign.prompts, answers)

        self.log.add_event("request_participation", {"answers": answers})

        from takumi.tasks import audit as audit_tasks

        config = Config.get("PROCESS_HYPEAUDITOR_REPORTS")
        if config and config.value is True:
            audit_tasks.create_audit.delay(influencer_id=self.offer.influencer.id)

    def reserve(self, answers=[]):
        with campaign_reserve_state(self.offer.campaign):
            if self.offer.campaign.apply_first:
                raise CampaignRequiresRequestForParticipation(
                    "Campaign needs to be requested for participation",
                    CAMPAIGN_REQUIRES_REQUEST_ERROR_CODE,
                )
            if not self.offer.campaign.fund.is_reservable():
                raise CampaignFullyReservedException(
                    "Campaign is already fully reserved", CAMPAIGN_NOT_RESERVABLE_ERROR_CODE
                )

            if self.offer.campaign.state != CAMPAIGN_STATES.LAUNCHED:
                raise CampaignNotLaunchedException(
                    "Campaign isn't launched yet!", CAMPAIGN_NOT_LAUNCHED_ERROR_CODE
                )

            if self.offer.state != OFFER_STATES.INVITED:
                raise OfferNotReservableException(
                    f"Cannot reserve {self.offer.state} offer",
                    INVALID_OFFER_STATE_ERROR_CODE,
                )

            if any(post.deadline_passed for post in self.offer.campaign.posts):
                raise OfferNotReservableException("Deadline has already passed in this campaign")

            if self.offer.campaign.reward_model == "reach":
                current_reward = RewardCalculator(
                    self.offer.campaign
                ).calculate_reward_for_influencer(self.offer.influencer)
                if current_reward != self.offer.reward:
                    self.update_reward(current_reward)
                    db.session.commit()

                    raise OfferRewardChangedException(
                        "There's limited space left on this campaign, so we're not able to offer the full reward",
                        OFFER_REWARD_CHANGED_ERROR_CODE,
                    )
            validate_answers(self.offer.campaign.prompts, answers)
            self.log.add_event("reserve", {"answers": answers})

        from takumi.tasks import audit as audit_tasks

        config = Config.get("PROCESS_HYPEAUDITOR_REPORTS")
        if config and config.value is True:
            audit_tasks.create_audit.delay(influencer_id=self.offer.influencer.id)

    def force_reserve(self):
        with campaign_reserve_state(self.offer.campaign):
            if self.offer.state not in [
                OFFER_STATES.PENDING,
                OFFER_STATES.INVITED,
                OFFER_STATES.REJECTED,
                OFFER_STATES.REVOKED,
            ]:
                raise OfferNotReservableException(
                    f"Cannot force reserve {self.offer.state} offer",
                    INVALID_OFFER_STATE_ERROR_CODE,
                )
            if not self.offer.campaign.fund.is_reservable():
                raise CampaignFullyReservedException(
                    "Campaign is already fully reserved", CAMPAIGN_NOT_RESERVABLE_ERROR_CODE
                )

            if self.offer.campaign.state != CAMPAIGN_STATES.LAUNCHED:
                raise CampaignNotLaunchedException(
                    "Campaign isn't launched yet!", CAMPAIGN_NOT_LAUNCHED_ERROR_CODE
                )

            if any(post.deadline_passed for post in self.offer.campaign.posts):
                raise OfferNotReservableException("Deadline has already passed in this campaign")

            if self.offer.campaign.shipping_required:
                # Confirm the shipping address
                address = self.offer.influencer.address

                if address:
                    address.modified = dt.datetime.now(dt.timezone.utc) + dt.timedelta(
                        minutes=1
                    )  # XXX: Horrible race condition here
                    db.session.add(address)

            self.log.add_event("force_reserve")

    def accept_request(self, ignore_campaign_limits=False):
        with campaign_reserve_state(self.offer.campaign):
            if (
                self.offer.campaign.brand_match
                and self.offer.state != OFFER_STATES.APPROVED_BY_BRAND
            ):
                raise OfferNotReservableException(
                    "Cannot accept {} offer. It needs to be brand approved first".format(
                        self.offer.state
                    ),
                    INVALID_OFFER_STATE_ERROR_CODE,
                )
            if self.offer.state not in [OFFER_STATES.APPROVED_BY_BRAND, OFFER_STATES.REQUESTED]:
                raise OfferNotReservableException(
                    "Cannot accept {} offer. It needs to be accepted by the influencer".format(
                        self.offer.state
                    ),
                    INVALID_OFFER_STATE_ERROR_CODE,
                )
            if not self.offer.campaign.fund.is_reservable() and not ignore_campaign_limits:
                raise CampaignFullyReservedException(
                    "Campaign is already fully reserved", CAMPAIGN_NOT_RESERVABLE_ERROR_CODE
                )

            if self.offer.campaign.state != CAMPAIGN_STATES.LAUNCHED:
                raise CampaignNotLaunchedException(
                    "Campaign isn't launched yet!", CAMPAIGN_NOT_LAUNCHED_ERROR_CODE
                )

            if any(post.deadline_passed for post in self.offer.campaign.posts):
                raise OfferNotReservableException("Deadline has already passed in this campaign")

            self.log.add_event("accept_requested_participation")
            if self.offer.influencer.has_device:
                self.send_push_notification(
                    _(
                        'You have been accepted into the campaign "%(campaign)s"',
                        campaign=self.offer.campaign.name,
                    )
                )

            # Clear selected flag if it was set
            if self.offer.is_selected:
                self.set_is_selected(False)

    def update_reward(self, reward):
        if self.offer.claimed:
            raise OfferAlreadyClaimed("Offer has already been claimed")

        self.log.add_event("update_reward", {"reward": reward})

    def reject(self):
        if not self.offer.can_reject():
            raise OfferNotRejectableException(
                "This offer cannot be rejected", UNREJECTABLE_OFFER_ERROR_CODE
            )
        OfferLog(self.offer).add_event("reject")

    def mark_dispatched(self, tracking_code=None):
        if not self.offer.campaign.shipping_required:
            raise OfferNotDispatchableException(
                "Can't dispatch an offer for a campaign without shipping"
            )

        if self.offer.state != OFFER_STATES.ACCEPTED:
            raise OfferNotDispatchableException("Can't dispatch an offer that hasn't been accepted")

        properties = {}
        if tracking_code:
            properties["tracking_code"] = tracking_code

        OfferLog(self.offer).add_event("mark_dispatched", properties)

    def set_claimable(self, force=False):
        if not force:
            if self.offer.state != OFFER_STATES.ACCEPTED:
                raise OfferNotClaimableException(
                    f"Cannot set {self.offer.state} offer as claimable",
                    INVALID_OFFER_STATE_ERROR_CODE,
                )
            if not self.offer.has_all_gigs_claimable():
                raise OfferNotClaimableException(
                    "All gigs need to have passed the review period in order to become claimable"
                )
        self.log.add_event("set_claimable")

    def unset_claimable(self):
        self.log.add_event("unset_claimable")

    def last_gig_submitted(self):
        claimable_time = self.offer.get_claimable_time()
        if not claimable_time:
            return None

        OfferLog(self.offer).add_event("last_gig_submitted", {"payable": claimable_time})

        if self.offer.campaign.pro_bono:
            # Create Takumi payment to mark gig as paid out
            from takumi.models.payment import STATES as PAYMENT_STATES
            from takumi.services import PaymentService

            self.offer.is_claimable = True
            payment = PaymentService.create(
                self.offer.id, {"destination": {"type": "takumi", "value": "pro-bono"}}
            )
            payment.successful = True
            payment.state = PAYMENT_STATES.PAID

    def send_push_notification(self, message=None):
        if not self.offer.influencer.has_device:
            raise OfferPushNotificationException(
                f"Influencer {self.offer.influencer.username} has no registered device"
            )
        if self.offer.state not in (
            OFFER_STATES.PENDING,
            OFFER_STATES.ACCEPTED,
            OFFER_STATES.INVITED,
        ):
            raise OfferPushNotificationException(
                f"Cannot send a push notification for offer in {self.offer.state} state",
                INVALID_OFFER_STATE_ERROR_CODE,
            )
        if self.offer.has_all_gigs():
            raise OfferPushNotificationException(
                "Offer already has all gigs. Cannot send push notification"
            )
        if self.offer.campaign.state != CAMPAIGN_STATES.LAUNCHED:
            raise OfferPushNotificationException(
                "Can't send a push notification for a campaign in {} state. Campaign needs to be launched".format(
                    self.offer.campaign.state
                )
            )

        message = (
            message
            or self.offer.campaign.push_notification_message
            or f"New campaign opportunity from {self.offer.campaign.advertiser.name}"
        )
        self.log.add_event("send_push_notification", {"message": message})
        db.session.add(
            Notification(
                campaign_id=self.offer.campaign.id,
                device_id=self.offer.influencer.device.id,
                message=message,
            )
        )

    def extend_submission_deadline(self, hours):
        if self.offer.submission_deadline is None:
            raise Exception()  # XXX: No deadline on the offer

        self.log.add_event(
            "set_submission_deadline",
            {"deadline": DateTimePeriod(hours).after(self.offer.submission_deadline)},
        )

    def update_engagements_per_post(self):
        new_engagement = self.offer.calculate_engagements_per_post()
        self.log.add_event(
            "update_engagement",
            {
                "engagements_per_post": new_engagement,
                "old_engagements_per_post": self.offer.engagements_per_post,
            },
        )

    def set_is_selected(self, is_selected):
        campaign = self.offer.campaign
        if not campaign.apply_first:
            raise ApplyFirstException("Only Apply First campaigns have selected")

        self.log.add_event("set_is_selected", {"is_selected": is_selected})

    def set_as_candidate(self):
        campaign = self.offer.campaign
        campaign.candidates_submitted = dt.datetime.now(dt.timezone.utc)

        if not campaign.apply_first:
            raise ApplyFirstException("Only apply first campaigns have candidates")

        self.log.add_event("set_as_candidate")

        # Clear selected if it was set
        if self.offer.is_selected:
            self.set_is_selected(False)

    def approve_candidate(self):
        campaign = self.offer.campaign

        if not campaign.apply_first:
            raise ApplyFirstException("Only apply first campaigns have candidates")

        self.log.add_event("approve_candidate")

    def reject_candidate(self, reason):
        campaign = self.offer.campaign

        if not campaign.apply_first:
            raise ApplyFirstException("Only apply first campaigns have candidates")

        self.log.add_event("reject_candidate", {"reason": reason})

        influencer = self.offer.influencer
        if influencer.has_device:
            client = NotificationClient.from_influencer(influencer)
            with locale_context(influencer.user.request_locale):
                client.send_rejection(
                    _(
                        'Unfortunately, you weren\'t selected for "%(campaign)s"',
                        campaign=self.offer.campaign.name,
                    ),
                    self.offer.campaign,
                )

    def revert_rejection(self):
        """Revert a rejected offer into its previous state

        Rejected offers include offers in the following states;
            * Rejected by the influencer
            * Rejected by the brand
            * Revoked by brand

        """
        if self.offer.state == OFFER_STATES.REJECTED:
            event_type = "reject"
        elif self.offer.state == OFFER_STATES.REJECTED_BY_BRAND:
            event_type = "reject_candidate"
        elif self.offer.state == OFFER_STATES.REVOKED:
            event_type = "revoke"
        else:
            raise ServiceException("Offer has to be rejected or revoked to revert rejection")

        event = (
            OfferEvent.query.filter(
                OfferEvent.offer == self.offer, OfferEvent.type == event_type
            ).order_by(OfferEvent.event["_created"].astext.desc())
        ).first()
        if event is None:
            raise ServiceException("Unable to find the rejection event")

        previous_state = event.event.get("_from_state")

        if previous_state is None:
            raise ServiceException("Previous state unknown, please contact support")
        elif previous_state == OFFER_STATES.ACCEPTED:
            campaign = self.offer.campaign
            units = campaign.fund.get_offer_units(self.offer)
            if not campaign.fund.can_reserve_units(units):
                raise ServiceException("Not enough space on the campaign to revert rejection")

        self.log.add_event("revert_rejection", {"state": previous_state})

    def set_followers_per_post(self, followers):
        """Set followers per post, if no content is live

        Followers per post is used to estimate reach for a campaign, after the
        content is live, the followers at time of posting should be used
        instead
        """

        if any(
            gig.instagram_post is not None
            or (gig.instagram_story is not None and gig.instagram_story.posted)
            for gig in self.offer.gigs
        ):
            raise ServiceException(
                "Unable to set followers per post if any content posted on Instagram"
            )

        self.log.add_event("set_followers_per_post", {"followers": followers})


from selenium.webdriver.common.by import By
from scrapers.abstract import AbstractScraper
from scrapers.websites import BASEBALL_PRESS_URL
from models.mlb.lineup import MlbLineup

class MlbLineupScraper(AbstractScraper):
    def __init__(self):
        super().__init__(BASEBALL_PRESS_URL)

    def get_resource(self, args):
        date = args["date"]
        endpoint = f"lineups/{date}"
        self.get(endpoint)
        lineups = self.driver.find_elements(By.CLASS_NAME, "lineup-card")
        data = [MlbLineup(lineup).toJson() for lineup in lineups]
        return {"lineups": data}


import os
import sys

from services.proto import delete_pb2 as dpb
from utils.articles import delete_article, get_article, get_sharers_of_article

HOSTNAME_ENV = 'HOST_NAME'

class ReceiveDeleteServicer:
    def __init__(self, logger, db, activ_util, users_util, hostname=None):
        self._logger = logger
        self._db = db
        self._activ_util = activ_util
        self._users_util = users_util
        self._hostname = hostname if hostname else os.environ.get(HOSTNAME_ENV)
        if not self._hostname:
            self._logger.error("Hostname for SendDeleteServicer not set")
            sys.exit(1)

    def ReceiveDeleteActivity(self, req, ctx):
        self._logger.info("Received delete for article '%s'", req.ap_id)
        article = get_article(self._logger, self._db, ap_id=req.ap_id)
        if article is None:
            # Don't have the article, our work here is done.
            # This can happen for natural reasons, dublicate deletes,
            # deletes of articles that were created before a follower
            # followed the creator, etc.
            self._logger.info("Don't have article %s, exiting", req.ap_id)
            return dpb.DeleteResponse(result_type=dpb.DeleteResponse.OK)
        author = self._users_util.get_user_from_db(global_id=article.author_id)
        if author is None:
            return dpb.DeleteResponse(
                result_type=dpb.DeleteResponse.ERROR,
                error="Could not retrieve author",
            )
        # Grab the people who shared the article before we delete everything.
        sharer_ids = get_sharers_of_article(
            self._logger, self._db, article.global_id)
        # Delete the local copy.
        if not delete_article(self._logger, self._db, ap_id=req.ap_id):
            return dpb.DeleteResponse(
                result_type=dpb.DeleteResponse.ERROR,
                error="Could not delete article",
            )
        # Forward the delete to the announcers.
        delete_obj = self._activ_util.build_delete(
            author, article, self._hostname)
        for user_id in sharer_ids:
            err = self._activ_util.forward_activity_to_followers(
                user_id, delete_obj)
            if err is not None:
                # Warn but do not quit on error sending to announcer followers.
                self._logger.warning(
                    "Sending activity to %d followers failed", user_id)
        return dpb.DeleteResponse(result_type=dpb.DeleteResponse.OK)


import enum
import typing

from dataclasses import dataclass, field

# Number of feet in a meter
M_2_FT = 3.28084

KM_2_MI = 0.621371

SPEED_OF_LIGHT = 299792458

EARTH_RADIUS_KM = 6371
EARTH_RADIUS_M = EARTH_RADIUS_KM * 1000

FREQUENCY_CHOICES = [
    (2.437, "2.4 GHz"),
    (3.6, "3.65 GHz"),
    (5.4925, "5 GHz"),
    (11.2, "11 GHz"),
    (18.7, "18 GHz"),
    (24.35, "24 GHz"),
    (64.79, "60 GHz"),
]

class FeatureType(enum.Enum):
    AP = "access_point"
    CPE = "cpe"
    PTP_LINK = "ptp_link"
    AP_CPE_LINK = "ap_cpe_link"
    COVERAGE_AREA = "coverage_area"
    AP_SECTOR = "sector"

@dataclass
class _Limits(object):
    min: float
    max: float
    default: float = 0

    # There might be other defaults defined. Use this to make it easier to look
    # them up
    other_defaults: typing.Dict[str, float] = field(default_factory=dict)

    # lookup <attr>_default
    def __getattr__(self, attr):
        if attr in self.other_defaults:
            return self.other_defaults[attr]
        else:
            raise AttributeError(
                f"type object {repr(self.__class__.__name__)} has no attribute {repr(attr)}"
            )

    # Return a version of this object with scaled factors
    def get_scaled_limits(self, scale_factor):
        return _Limits(
            scale_factor * self.min,
            scale_factor * self.max,
            scale_factor * self.default,
        )

class ModelLimits(object):
    # Height in meters
    HEIGHT = _Limits(0.1, 1000, 30, {"cpe_default": 1, "ptp_default": 18.29})

    # Height in ft
    HEIGHT_FT = HEIGHT.get_scaled_limits(M_2_FT)

    # Radius in km
    RADIUS = _Limits(0.1, 16, 2, {"no_check_radius_default": 0.01})

    # Radius in mi
    RADIUS_MILES = RADIUS.get_scaled_limits(KM_2_MI)

    # Frequency in GHz
    FREQUENCY = _Limits(0, 100, 2.437)

    # Heading in degrees
    HEADING = _Limits(0, 360, 0)

    # Azimuth in degrees
    AZIMUTH = _Limits(0.01, 360, 120)

    # Name length
    NAME = _Limits(1, 50)


import numpy as np

def pdf_uniform(x):
    size = x.shape[0]
    g = np.zeros(size)
    g[x <= 0] = 0
    g[(x > 0) & (x < 5)] = 1
    g[x >= 5] = 0
    return g

def pdf(x):
    size = x.shape[0]
    f = np.zeros(size)
    f[x <= 0] = 0
    f[(x > 0) & (x <= 1)] = x[(x > 0) & (x <= 1)] / 2
    f[(x > 1) & (x <= 2)] = 1 - x[(x > 1) & (x <= 2)] / 2
    f[(x > 2) & (x <= 3)] = 0
    f[(x > 3) & (x <= 4)] = (x[(x > 3) & (x <= 4)] - 3) / 2
    f[(x > 4) & (x < 5)] = (5 - x[(x > 4) & (x < 5)]) / 2
    f[x >= 5] = 0
    return f

def generate_triangles(N):
    """Return a numpy array with the length N with
    random numbers following the distribution specified
    """
    vals = np.zeros(N)
    Nvals = 0
    while Nvals < N:
        # generate x
        x = np.random.uniform(-1, 6, size=N)
        f_g = pdf(x) / pdf_uniform(x)
        M = 0.6

        # chance and probability at each x generated
        acc = np.random.uniform(0, 1, N)
        prob = pdf(x) / (M * pdf_uniform(x))

        x_index = np.nonzero(acc < prob)  # index of where acc < prob = True
        new_vals = x[x_index]  # input index into x
        new_vals = new_vals[
            : N - Nvals
        ]  # slice to get the specific amount to make up to N
        vals[Nvals : Nvals + len(new_vals)] = new_vals  # append to vals list
        Nvals = Nvals + len(new_vals)  # update Nvals

    return vals


import tensorflow as tf
import numpy as np
from scipy import ndimage

# zoom
@tf.function
def zoom(volume):
    """Zoom the volume by a few degrees"""

    volume_shape = volume.shape
    def augment_volume(volume):
        min_zoom = 0.8
        max_zoom = 1.2
        z = np.random.sample() *(max_zoom-min_zoom) + min_zoom
        zoom_matrix = np.array([[z, 0, 0, 0],
                                [0, z, 0, 0],
                                [0, 0, z, 0],
                                [0, 0, 0, 1]])
        return ndimage.affine_transform(volume, zoom_matrix, mode = "nearest", order = 1)

    augmented_volume = tf.py_function(augment_volume, [volume], tf.float32)
    augmented_volume.set_shape(volume_shape)
    return augmented_volume

@tf.function
def rotate(volume):
    """Rotate the volume by a few degrees"""

    volume_shape = volume.shape
    def augment_volume(volume):
        # define some rotation angles
        angles = [-20, -10, -5, 5, 10, 20]
        # pick angles at random
        angle = np.random.choice(angles)
        # rotate volume
        volume = ndimage.rotate(volume, angle, axes = (0,1), reshape = False, order = 3, mode = "nearest")
        #volume[volume < 0] = 0
        #volume[volume > 1] = 1
        return volume

    augmented_volume = tf.py_function(augment_volume, [volume], tf.float32)
    augmented_volume.set_shape(volume_shape)
    return augmented_volume

@tf.function
def shift(volume):
    """Shift the volume along the x and y axes"""

    volume_shape = volume.shape
    def augment_volume(volume):
        # define some shifts in the three different directions
        x_shift = np.random.uniform(-20, 20)
        y_shift = np.random.uniform(-20, 20)
        z_shift = np.random.uniform(0, 0)
        # shift volume
        volume = ndimage.shift(volume, [x_shift, y_shift, z_shift, 0], mode = "nearest", order = 0)
        return volume

    augmented_volume = tf.py_function(augment_volume, [volume], tf.float32)
    augmented_volume.set_shape(volume_shape)
    return augmented_volume

@tf.function
def flip(volume):
    """Randomly flip the volume"""
    volume_shape = volume.shape
    def augment_volume(volume):
        axis = np.random.choice([0,1])
        if(axis == 0): # vertical flip
            volume = volume[:,::-1,:,:]
        return volume

    augmented_volume = tf.py_function(augment_volume, [volume], tf.float32)
    augmented_volume.set_shape(volume_shape)
    return augmented_volume


# This script computes the mutual information (MI) from the covariance between atomic displacements

import numpy as np
import time
from numpy import linalg as LA
import csv
import exclusion as ex
import MDAnalysis as mda
import MDAnalysis.analysis.encore.covariance as covar
import MDAnalysis.analysis.pca as pca
import covariance as covar

#_______________________________________
# INPUTS
structure_file = '/gpfs/scratch60/fas/batista/pd455/omcs_structure/2chains/fully_ox/CNA/matrix_calculation/extract_protein/myprot_reference_ox.psf'
dcd_trajectory = '/gpfs/scratch60/fas/batista/pd455/omcs_structure/2chains/fully_ox/CNA/matrix_calculation/extract_protein/trunc_prot_only_traj_ox.dcd'
#______________________________________

def MI(covar_matrix,natoms):
	# This function computes the linear mutual information matrix
	print('computing linear mutual information matrix\n')
	twobodycorr = np.zeros([natoms,natoms])
	for i in range(0,natoms):
		temp = mat_det(covar_matrix,i,i,3)
		for j in range(0,i):
			temp1 = mat_det(covar_matrix,j,j,3)
			temp2 = mat_det(covar_matrix,i,j,6)
			temp3 = temp*temp1/temp2
			temp3 = np.log(temp3)
			twobodycorr[i,j]=temp3
			twobodycorr[j,i] = twobodycorr[i,j]
	twobodycorr = 0.5 * twobodycorr

	return twobodycorr

def gen_corr(LMI_matrix,natoms,cen=None):
	# This function converts the linear mutual information into the generalized
	# correlation coefficient
	print('computing general correlation matrix\n')
	fileOUT = open('g_corr_list.txt','w')
	matOUT = open('g_corr_mat.txt','w')

	for j in range(0,natoms):
		for i in range(0,j):
			LMI_matrix[i,j] = 1.0 - np.exp((-2.0/3.0) * LMI_matrix[i,j])
			LMI_matrix[i,j] = np.sqrt(LMI_matrix[i,j])
			LMI_matrix[j,i] = LMI_matrix[i,j]
			print('%s	%s	%.3f' % (i,j,LMI_matrix[i,j]),file=fileOUT)
		LMI_matrix[j,j] = 1.0

	# Write general correlation matrix
	print("%s\n" % natoms,file=matOUT)
	with matOUT as f:
		csv_writer = csv.writer(f,delimiter = ' ')
		csv_writer.writerows(LMI_matrix)

	matOUT.close()

	if cen:
		centrality(LMI_matrix,natoms)

def mat_det(covar_matrix,ii,jj,n):
	matrix = np.zeros([n,n])
	l = 1
	if n == 6:
		for i in range(0,3):
			for j in range(0,3):
				matrix[i,j]=covar_matrix[ii*3+i,ii*3+j]
				matrix[i,j+3]=covar_matrix[ii*3+i,jj*3+j]
				matrix[i+3,j]=covar_matrix[jj*3+i,ii*3+j]
				matrix[i+3,j+3]=covar_matrix[jj*3+i,jj*3+j]
	elif n == 3:
		for i in range(0,3):
			for j in range(0,3):
				matrix[i,j]=covar_matrix[ii*3+i,jj*3+j]

	determinant = LA.det(matrix)
	return determinant

def centrality(g_corr_mat,natoms):
	cenOUT = open('eigvec_centrality.txt','w')

	[evalues,evectors] = LA.eig(g_corr_mat)
	idx = evalues.argsort()[::-1]
	evalues = evalues[idx]
	print(evalues[0])
	evectors = abs(evectors[:,idx])
	print(evectors[0:10,0])

	for i in range(natoms):
		sum_array = 0
		for j in range(natoms):
			sum_array += g_corr_mat[i,j]*evectors[j,0]
		cen_value = (1.0/evalues[0]) * sum_array
		print("%s       %s" % (i,cen_value), file=cenOUT)

start = time.time()

## Use MDAnalysis to compute the covariance matrix from your trajectory
u = mda.Universe(structure_file,dcd_trajectory)
nframes = len(u.trajectory)

# compute the covariance matrix
print('computing covariance matrix\n')
selection = 'all'
natoms = len(u.select_atoms(selection))
#print(natoms)
covar_matrix = covar.covariance(u,structure_file,selection)

# compute the mutual information matrix from the covariance matrix
LMI = MI(covar_matrix,natoms)

# compute and output the general correlation matrix
gen_corr(LMI,natoms,cen=True)

# compute the exclusion list
ex.exclusion(u,nframes,selection=selection)

end = time.time()
print('Done')
print('WallClock: %.6f' % (end-start))


####################################################
# # mission_to_mars
# ----
#
# Written in the Python 3.7.9 Environment
#
# By Nicole Lund
#
# This Python script scrapes Mars space data from various
# locations for storage in a Pymongo DB and display on a webpage.
####################################################

# Import Dependencies
import pandas as pd
import time
from splinter import Browser
from bs4 import BeautifulSoup
from webdriver_manager.chrome import ChromeDriverManager

def nasa_news(browser):
    ####################################################
    # NASA Mars News
    ####################################################

    # Access NASA news site
    nasa_url = 'https://mars.nasa.gov/news/'
    browser.visit(nasa_url)
    nasa_html = browser.html
    nasa_soup = BeautifulSoup(nasa_html, 'html.parser')

    # Allow webpage to load fully
    time.sleep(1.5)

    # Collect the latest news headline and paragraph
    latest_container = nasa_soup.find('div', class_='image_and_description_container')

    # Final Nasa Result
    news_headline = latest_container.find('div', class_='content_title').find('a').text
    news_teaser = latest_container.find('div', class_='article_teaser_body').text
    nasa_news_headline = {'headline':news_headline,'teaser':news_teaser}

    # print('')
    # print('-------- NASA News Top Headline --------')
    # print(nasa_news_headline)

    return nasa_news_headline

def jpl_feature(browser):
    ####################################################
    # JPL Mars Space Images - Featured Image
    ####################################################

    # Access JPL image site
    jpl_base_url = 'https://data-class-jpl-space.s3.amazonaws.com/JPL_Space/'
    jpl_url = jpl_base_url + 'index.html'
    browser.visit(jpl_url)
    jpl_html = browser.html
    jpl_soup = BeautifulSoup(jpl_html, 'html.parser')
    # Allow webpage to load fully - Has not been necessary
    # time.sleep(1)

    # Collect the full url path for the full size featured image
    featured = jpl_soup.find('div', class_='floating_text_area')
    jpl_relative_url = featured.find('a')['href']

    # Final JPL Result
    featured_image_url = jpl_base_url + jpl_relative_url

    # print('')
    # print('-------- JPL Featured Image --------')
    # print(featured_image_url)

    return featured_image_url

def mars_facts(browser):
    ####################################################
    # Mars Facts
    ####################################################

    # Collect Mars Facts Table
    facts_url = 'https://space-facts.com/mars/'
    facts_df = pd.read_html(facts_url)[0]

    # print('')
    # print('-------- Mars Facts Table --------')
    # print(facts_df)
    # print('')

    # Final Mars Facts Result - Convert facts table to html string
    # Note from Nicole Lund - I chose to remove all formatting from
    # the table as an esthetic choice because the Description column
    # fields include a : at the end.
    facts_html = facts_df.to_html(justify='left',border=0,header=False,index=False)

    return facts_html

def mars_hemispheres(browser):
    ####################################################
    # Mars Hemispheres
    ####################################################

    # Access Astrogeology site
    astropedia_base_url = 'https://astrogeology.usgs.gov'
    astropedia_relative_url = '/search/results?q=hemisphere+enhanced&k1=target&v1=Mars'
    astropedia_url = astropedia_base_url + astropedia_relative_url
    browser.visit(astropedia_url)
    astropedia_html = browser.html
    astropedia_soup = BeautifulSoup(astropedia_html, 'html.parser')

    # Allow webpage to load fully - Has not been necessary
    # time.sleep(1)

    # Collect hemisphere titles
    hemisphere_titles = []
    hemisphere_containers = astropedia_soup.find_all('div', class_='description')

    for image_num in range(0,5):
        try:
            hemisphere_found = hemisphere_containers[image_num].h3.text
            hemisphere_titles.append(hemisphere_found)
            print(f'Found Hemisphere: {hemisphere_found}')
        except IndexError:
            print('All Hemispheres Found')

    # Navigate to each hemisphere link and collect image link and title in a dictionary
    hemisphere_image_urls = []

    for hemisphere in hemisphere_titles:
        # Navigate to each hemisphere link
        browser.links.find_by_partial_text(hemisphere).click()

        # Collect URL for full size image
        hemisphere_html = browser.html
        hemisphere_soup = BeautifulSoup(hemisphere_html, 'html.parser')
        # Allow webpage to load fully - Has not been necessary
        # time.sleep(1)

        hemisphere_image = hemisphere_soup.find('img', class_='wide-image')['src']
        image_link = astropedia_base_url + hemisphere_image
        hemisphere_image_urls.append(\
            {"title":hemisphere,"img_url":image_link})

        # Return to main page
        browser.visit(astropedia_url)

    # print('')
    # print('-------- Mars Hemisphere Images --------')
    # print(hemisphere_image_urls)
    # print('')

    return hemisphere_image_urls

def scrape():
    ####################################################
    # Scrape Mars Related Data
    ####################################################

    # Initialize browser
    executable_path = {'executable_path': ChromeDriverManager().install()}
    browser = Browser('chrome', **executable_path, headless=False)

    # Retrieve NASA news
    nasa_headline_teaser = nasa_news(browser)

    # Retrieve JPL Featured Image
    jpl_image = jpl_feature(browser)

    # Retrieve Mars Facts Table
    facts_table = mars_facts(browser)

    # Retrieve Mars Hemisphere Images
    hemisphere_image_links = mars_hemispheres(browser)

    # Store all retrieved data within a single dictionary
    mars_data = {\
        'nasa_top_story':nasa_headline_teaser,\
        'jpl_featured_img':jpl_image,\
        'facts_table_html':facts_table,\
        'hemisphere_images':hemisphere_image_links\
        }

    # print('')
    # print('-------- Combined Mars Data --------')
    # print(mars_data)

    # Close splinter browser
    browser.quit()

    return(mars_data)

if __name__ == "__main__":
   scrape()


from art import logo
from menu import Menu, MenuItem
from coffee_maker import CoffeeMaker
from money_machine import MoneyMachine

coffe_maker = CoffeeMaker()
menu = Menu()
money_machine = MoneyMachine()

print(logo)

is_on = True
while is_on:

    choice = input(f'What would you like? ({menu.get_items()}): ')
    if choice == 'off':
        is_on = False
    elif choice == 'report':
        coffe_maker.report()
        money_machine.report()
    else:
        # retrive drink from menu module
        drink = menu.find_drink(choice)
        # check if we have sufficient ingredients for the drink
        if coffe_maker.resource_sufficient(drink):
            print(f"Please insert ${drink.cost}.")
            # check if we have enough money for the drink then make the drink
            if money_machine.make_payment(drink.cost):
                coffe_maker.make_drink(drink)


#!/usr/bin/env python
#
# implements Python DBAPI 2.0
# see PEP 249 (http://www.python.org/dev/peps/pep-0249/)
import re
import base64
import decimal

from SPARQLWrapper.Wrapper import SELECT, INSERT, DELETE, MODIFY
# CONSTRUCT
# ASK
# DESCRIBE

class Error(Exception):
    pass

class SparqlSyntaxError(Exception):
    def __init__(self, message, line=None):
        self.message = message
        self.line = line

class DatabaseError(Error):
    pass

class ProgrammingError(DatabaseError):
    def __init__(self, msg, **kwargs):
        DatabaseError.__init__(self, msg)

class Cursor(object):
    def __init__(self, connection, prefixes=''):
        self.arraysize = 100
        self.connection = connection
        self.sparql = None
        self.results = None
        self.pointer = 0
        self.prefixes = prefixes
        self.rowcount = -1

    def __iter__(self):
        result = self.pointer and self.results[self.pointer:] or self.results
        return iter(result)

    def _desc(self):
        #(name, type_code, display_size, internal_size, precision, scale, null_ok)
        #first two are required, supply None for optional values
        if not self.results:
            return None

        if len(self.results) == 0:
            return None

        desc = []
        cols = [self.results.get_binding_name(i) for i in range(self.results.get_bindings_count())]
        for col in cols:
            desc_col = (col, literal_datatype(self.results.get_binding_value_by_name(col)), None, None, None, None, None)
            desc.append(desc_col)
        return desc

        #if no return values, or nothing executed
        return None
    description = property(_desc)

    def close(self):
        pass

    def _escape_param(self, param):
        # if type(param) in typeToSchema:
        #     return '%s^^%s' % (param, typeToSchema[type(param)])
        if isinstance(param, (str, unicode)):
            return '%s' % param
        return unicode(param)

    def escape_params(self, parameters):
        #for dict, return dict
        if isinstance(parameters, dict):
            params = {}
            for k, v in parameters.iteritems():
                params[k] = self._escape_param(v)
            return params
        #for sequence, return tuple
        params = []
        for p in parameters:
            params.append(self._escape_param(p))
        return tuple(params)

    def execute(self, sparql, params=[]):
        params = self.escape_params(params)
        sparql = '%s %s' % (' '.join(self.prefixes), sparql)
        self.sparql = sparql % params
        self.connection.setQuery(self.sparql)
        self.results = self.connection.query().convert()["results"]["bindings"]
        self.update_rowcount()

    def update_rowcount(self):
        if self.connection.queryType == SELECT:
            self.rowcount = len(self.results)
        elif self.connection.queryType == INSERT \
        or self.connection.queryType == DELETE:
            message = self.results[0]['callret-0']['value']
            finder = re.search('(?P<number>\d).*triples', message).groupdict()
            self.rowcount = int(finder['number'])
        elif self.connection.queryType == MODIFY:
            message = self.results[0]['callret-0']['value']
            finder = re.search('delete (?P<deleted>\d).*insert (?P<inserted>\d)', message).groupdict()
            deleted = int(finder['deleted'])
            inserted = int(finder['inserted'])
            self.rowcount = deleted or inserted
        else:
            raise NotImplementedError("Type %s cannot get a rowcount" % self.connection.queryType)

    def executemany(self, operation, seq_of_parameters):
        raise NotImplementedError('executemany need to implemented')

    # def next(self):
    #     row = self.fetchone()
    #     if row is None:
    #         raise StopIteration
    #     return row

    def fetchone(self):
        if self.pointer >= len(self.results):
            return None
        result = self.results[self.pointer]
        self.pointer += 1
        return _rowfactory(result)

    def fetchmany(self, size=None):
        end = self.pointer + (size or self.arraysize)
        results = self.results[self.pointer:end]
        self.pointer = min(end, len(self.results))
        return tuple([
            _rowfactory(r) for r in results
        ])

    def fetchall(self):
        if self.pointer:
            results = self.results[self.pointer:]
        else:
            results = self.results
        self.pointer = len(self.results)
        return tuple([
            _rowfactory(r) for r in results
        ])

    def dictfetchone(self):
        if not self.results:
            return None
        return self.results[0]

    def nextset(self):
        return None

    def setinputsizes(self):
        pass

    def setoutputsize(self, size, column=None):
        pass

def _rowfactory(row):
    return tuple([(key, value['value']) for key, value in row.items()])

def literal_datatype(node):
    if not node.is_literal():
        return None
    dt = node.literal_value['datatype']
    if dt:
        return unicode(dt)
    return u'http://www.w3.org/2001/XMLSchema#string'

typeToSchema = {
    unicode: '<http://www.w3.org/2001/XMLSchema#string>',
    bool: '<http://www.w3.org/2001/XMLSchema#boolean>',
    decimal: '<http://www.w3.org/2001/XMLSchema#decimal>',
    int: '<http://www.w3.org/2001/XMLSchema#integer>',
    long: '<http://www.w3.org/2001/XMLSchema#long>',
    float: '<http://www.w3.org/2001/XMLSchema#float>',
    base64: '<http://www.w3.org/2001/XMLSchema#base64Binary>',
}

SchemaToPython = {  # (schema->python, python->schema)  Does not validate.
    'http://www.w3.org/2001/XMLSchema#string': (unicode, unicode),
    'http://www.w3.org/2001/XMLSchema#normalizedString': (unicode, unicode),
    'http://www.w3.org/2001/XMLSchema#token': (unicode, unicode),
    'http://www.w3.org/2001/XMLSchema#language': (unicode, unicode),
    'http://www.w3.org/2001/XMLSchema#boolean': (bool, lambda i: unicode(i).lower()),
    'http://www.w3.org/2001/XMLSchema#decimal': (decimal.Decimal, unicode),
    'http://www.w3.org/2001/XMLSchema#integer': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#nonPositiveInteger': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#long': (long, unicode),
    'http://www.w3.org/2001/XMLSchema#nonNegativeInteger': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#negativeInteger': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#int': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#unsignedLong': (long, unicode),
    'http://www.w3.org/2001/XMLSchema#positiveInteger': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#short': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#unsignedInt': (long, unicode),
    'http://www.w3.org/2001/XMLSchema#byte': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#unsignedShort': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#unsignedByte': (int, unicode),
    'http://www.w3.org/2001/XMLSchema#float': (float, unicode),
    'http://www.w3.org/2001/XMLSchema#double': (float, unicode),  # doesn't do the whole range
#    duration
#    dateTime
#    time
#    date
#    gYearMonth
#    gYear
#    gMonthDay
#    gDay
#    gMonth
#    hexBinary
    'http://www.w3.org/2001/XMLSchema#base64Binary': (base64.decodestring, lambda i: base64.encodestring(i)[:-1]),
    'http://www.w3.org/2001/XMLSchema#anyURI': (str, str),
}


#!/usr/bin/env python3

import torch
import torch.nn.functional as F
from regilib.core.invertible_modules.invertible_module import InvertibleModule

class SphericalStereographicProjection(InvertibleModule):
    def forward(self, ds, **kwargs):
        phi, Theta = ds['state'].T

        # unit-sphere -> polar
        r = torch.sin(phi) / (1 - torch.cos(phi))

        # polar -> xy
        ds['state'] = torch.stack([
            r*torch.cos(Theta), r*torch.sin(Theta)], -1)

        # deterministic pad: g: U → M ⊂ X
        ds['state'] = F.pad(ds['state'], (0, 1))
        return ds

    def inverse(self, ds, **kwargs):
        """ φ the zenith angle, 0 ≤ φ ≤ π, and θ the azimuth, -π ≤ θ ≤ π

        :param ds:
        :returns:

        """

        # deterministic project: g⁻¹: X -> U
        ds['state'] = ds['state'][:, :-1]

        # xy -> polar coordinates
        r = torch.norm(ds['state'], p=2, dim=1)
        Theta = torch.atan2(ds['state'][:, 1], ds['state'][:, 0])

        # polar -> unit-sphere
        phi = 2*torch.arctan(1/r)
        ds['state'] = torch.stack([phi, Theta], -1)

        return ds


import os
import tensorflow as tf
import numpy as np
import cv2
from glob import glob
from tqdm import tqdm

os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"

if __name__ == "__main__":
    test_images = glob("segmentation_full_body_tik_tok_2615_img/images/*")
    model = tf.keras.models.load_model("weights/best.h5", compile=False)

    for path in tqdm(test_images, total=len(test_images)):
        x = cv2.imread(path, cv2.IMREAD_COLOR)
        original_image = x
        h, w, _ = x.shape

        x = cv2.resize(x, (256, 256))
        x = x / 255.0
        x = x.astype(np.float32)

        x = np.expand_dims(x, axis=0)
        pred_mask = model.predict(x)[0]

        pred_mask = np.concatenate(
            [
                pred_mask,
                pred_mask,
                pred_mask
            ], axis=2)
        pred_mask = (pred_mask > 0.5) * 255
        pred_mask = pred_mask.astype(np.float32)
        pred_mask = cv2.resize(pred_mask, (w, h))

        original_image = original_image.astype(np.float32)

        alpha = 0.6
        cv2.addWeighted(pred_mask, alpha, original_image, 1 - alpha, 0, original_image)

        name = path.split("/")[-1]

        cv2.imwrite(f"save_images/{name}", original_image)


import random

random_number = random.randint(1,2)
if random_number == 1:
    penz = "fej"
else:
    penz = "irás"
number2 =(input("Fej vagy írás? (fej/irás)"))
if number2 == penz:
    print("Eltaláltad!")
else:
    print("Nem találtad el!")


import re

_size_suffixes = ('B', 'KB', 'MB', 'GB', 'TB')

def humanize_bytes(size: int, precision=2) -> str:
    """Convert data size to human-readable units.

    >>> humanize_bytes(20000)
    '19.53 KB'

    >>> humanize_bytes(int(5E8), precision=4)
    '476.8372 MB'
    """
    suffix_idx = 0
    while size >= 1024 and suffix_idx < len(_size_suffixes) - 1:
        suffix_idx += 1  # Increment the index of the suffix.
        size /= 1024  # Apply the division.
    return '{size:0.{prec}f} {unit}'.format(size=size,
                                            prec=precision,
                                            unit=_size_suffixes[suffix_idx])

def dehumanize_bytes(s: str) -> int:
    """Convert human-readable size to bytes.

    Raise ValueError if conversion cannot be performed.

    >>> dehumanize_bytes('2.5 kb')
    2560
    """
    match = re.match(r'(\d*\.{0,1}\d*)\s*(\w+)', s)
    if not match:
        raise ValueError('Could not parse bytes from \'{}\''.format(s))
    size, unit = match.groups()
    size = float(size)
    unit = unit.upper()
    try:
        unit_idx = _size_suffixes.index(unit)
    except ValueError:
        raise ValueError(
            'Unit \'{}\' not one of {}'.format(unit, _size_suffixes)
        ) from None
    return int(size * (1024 ** unit_idx))


"""
Pre-processing for the Cornell Movie-Dialogs Corpus.
"""
from __future__ import print_function

import os
import random
import re

import numpy as np

import config

############# Process raw text files

def getLineId2LineTextDictionary():
    """
    Parse movie_lines.txt and return dictionary of lineId to lineText
    """
    id2line = {}
    file_path = os.path.join(config.DATA_PATH, 'movie_lines.txt')
    with open(file_path, 'rb') as f:
        lines = f.readlines()
        for line in lines:
            parts = line.split(' +++$+++ ')
            if len(parts) == 5:
                if parts[4][-1] == '\n':
                    parts[4] = parts[4][:-1]
                id2line[parts[0]] = parts[4]
    return id2line

def getConversationsList():
    """ Get list of conversations from movie_conversations.txt """
    file_path = os.path.join(config.DATA_PATH, 'movie_conversations.txt')
    conversationsList = []
    with open(file_path, 'rb') as f:
        for line in f.readlines():
            parts = line.split(' +++$+++ ')
            if len(parts) == 4:
                convo = []
                for line in parts[3][1:-2].split(', '):
                    convo.append(line[1:-1])
                conversationsList.append(convo)

    return conversationsList

###########

def conversationToQuestionAnswerPairs(id2line, conversationsList):
    """
    Divide the dataset into two sets: questions and answers.
    Take the first line of the conversation as question and second line as answer, and vice versa!!!  [A,B,C] becomes (A,B), (B,C)
    """
    questions, answers = [], []
    i = 0
    for convo in conversationsList:
        for index, line in enumerate(convo[:-1]):
            questions.append(id2line[convo[index]])
            answers.append(id2line[convo[index + 1]])

    assert len(questions) == len(answers)
    return questions, answers

def createTrainTestEncoderDecoderDataSets(questions, answers):
    """
    Create train & test encoder & decoder files.
    enc / dec means encoder input / decoder output (question / answer)
    """
    make_dir(config.PROCESSED_PATH)

    # random conversationsList to create the test set
    test_ids = random.sample([i for i in range(len(questions))], config.TESTSET_SIZE)

    filenames = ['train.enc', 'train.dec', 'test.enc', 'test.dec']
    files = []
    for filename in filenames:
        files.append(open(os.path.join(config.PROCESSED_PATH, filename),'wb'))

    for i in range(len(questions)):
        if i in test_ids:
            files[2].write(questions[i] + '\n')
            files[3].write(answers[i] + '\n')
        else:
            files[0].write(questions[i] + '\n')
            files[1].write(answers[i] + '\n')

    for file in files:
        file.close()

def make_dir(path):
    """
    Create a directory if there isn't one already.
    """
    try:
        os.mkdir(path)
    except OSError:
        pass

def tokenize(line, normalize_digits=True):
    """
    Tokenize text into tokens.
    """
    # remove placeholders
    line = re.sub('<u>', '', line)
    line = re.sub('</u>', '', line)
    line = re.sub('\[', '', line)
    line = re.sub('\]', '', line)
    words = []
    _WORD_SPLIT = re.compile(b"([.,!?\"'-<>:;)(])")
    _DIGIT_RE = re.compile(r"\d")
    for fragment in line.strip().lower().split():
        for token in re.split(_WORD_SPLIT, fragment):
            if not token:
                continue
            # replace all digits to # character
            if normalize_digits:
                token = re.sub(_DIGIT_RE, b'#', token)
            words.append(token)
    return words

def build_vocab(filename, normalize_digits=True):
    """
    Build file of vocabularies that occur more than config.THRESHOLD
    in the dataset
    """
    in_path = os.path.join(config.PROCESSED_PATH, filename)
    out_path = os.path.join(config.PROCESSED_PATH, 'vocab.{}'.format(filename[-3:]))

    # Build dictionary of each vocabulary to its frequency
    vocab = {}
    with open(in_path, 'rb') as f:
        for line in f.readlines():
            for token in tokenize(line):
                if not token in vocab:
                    vocab[token] = 0
                vocab[token] += 1

    # Sort dictionary by count and get keys ordered by count
    sorted_vocab = sorted(vocab, key=vocab.get, reverse=True)
    with open(out_path, 'wb') as f:
        f.write('<pad>' + '\n')
        f.write('<unk>' + '\n')
        f.write('<s>' + '\n')
        f.write('<\s>' + '\n')
        index = 4
        for word in sorted_vocab:
            if vocab[word] < config.THRESHOLD:
                break
            f.write(word + '\n')
            index += 1

def load_vocab(vocab_path):
    """
    Load vocabs file and
    return list of all words and dictionary of each word to its index
    """
    with open(vocab_path, 'rb') as f:
        words = f.read().splitlines()
    # get list of all words and dictionary of each word to its index
    return words, {words[i]: i for i in range(len(words))}

def stringToTokenIds(vocab, line):
    """
    Convert a sentence to id of its tokens
    """
    return [vocab.get(token, vocab['<unk>']) for token in tokenize(line)]

def convertDatasetFilesToTokenIds(data, mode):
    """
    Convert all the tokens in the data into their corresponding
    index in the vocabulary.
    A file with same name _.ids will be created

    <s> will mark beginning of utterance and </s> marks end of utterance
    """
    vocab_path = 'vocab.' + mode
    in_path = data + '.' + mode
    out_path = data + '_ids.' + mode

    _, vocab = load_vocab(os.path.join(config.PROCESSED_PATH, vocab_path))
    in_file = open(os.path.join(config.PROCESSED_PATH, in_path), 'rb')
    out_file = open(os.path.join(config.PROCESSED_PATH, out_path), 'wb')

    lines = in_file.read().splitlines()
    for line in lines:
        if mode == 'dec': # we only care about '<s>' and </s> in encoder
            ids = [vocab['<s>']]
        else:
            ids = []
        ids.extend(stringToTokenIds(vocab, line))
        # ids.extend([vocab.get(token, vocab['<unk>']) for token in tokenize(line)])
        if mode == 'dec':
            ids.append(vocab['<\s>'])
        out_file.write(' '.join(str(id_) for id_ in ids) + '\n')

def load_data(enc_filename, dec_filename, max_training_size=None):
    """
    - Load questions and answers files.
    - Each config.BUCKETS would collect QA pairs that conform to (question_max_size, answer_max_size)
    -  For each question/answer pair, find the bucket tuple that they both belong to,
           break the for loop once found and go for next line

    returns data_buckets
    """
    encode_file = open(os.path.join(config.PROCESSED_PATH, enc_filename), 'rb')
    decode_file = open(os.path.join(config.PROCESSED_PATH, dec_filename), 'rb')
    encode, decode = encode_file.readline(), decode_file.readline()

    # each bucket is a tuple of (encode_max_size, decode_max_size) that should belong to same bucket
    # used for mini-batching
    #
    # For each bucket, create an empty array
    data_buckets = [[] for _ in config.BUCKETS]
    i = 0

    # For each question/answer pair, find the bucket tuple that they both belong to,
    # break the for loop once found
    while encode and decode:
        if (i + 1) % 10000 == 0:
            print("Bucketing conversation number", i)

        # Get array of ids for question / answer pair
        encode_ids = [int(id_) for id_ in encode.split()] # Get array of ids that are in the question
        decode_ids = [int(id_) for id_ in decode.split()] # Get array of ids that are in the answer

        for bucket_id, (encode_max_size, decode_max_size) in enumerate(config.BUCKETS):
            # find question / answer pairs that comply to bucket string length limits
            if len(encode_ids) <= encode_max_size and len(decode_ids) <= decode_max_size:
                data_buckets[bucket_id].append([encode_ids, decode_ids])
                break
        encode, decode = encode_file.readline(), decode_file.readline()
        i += 1
    return data_buckets

def _pad_input(input_, size):
    """
    Pad a string up to maximum |size|
    """
    return input_ + [config.PAD_ID] * (size - len(input_))

def _reshape_batch(inputs, size, batch_size):
    """
    Create batch-major inputs. Batch inputs are just re-indexed inputs
    TODO
    """
    batch_inputs = []
    for length_id in range(size):
        batch_inputs.append(np.array([inputs[batch_id][length_id]
                                    for batch_id in range(batch_size)], dtype=np.int32))
    return batch_inputs

def get_batch(data_bucket, bucket_id, batch_size=1):
    """ Return one batch to feed into the model """
    # only pad to the max length of the bucket
    encoder_size, decoder_size = config.BUCKETS[bucket_id]
    encoder_inputs, decoder_inputs = [], []

    for _ in range(batch_size):
        encoder_input, decoder_input = random.choice(data_bucket)
        # pad both encoder and decoder, reverse the encoder
        encoder_inputs.append(list(reversed(_pad_input(encoder_input, encoder_size))))
        decoder_inputs.append(_pad_input(decoder_input, decoder_size))

    # now we create batch-major vectors from the data selected above.
    batch_encoder_inputs = _reshape_batch(encoder_inputs, encoder_size, batch_size)
    batch_decoder_inputs = _reshape_batch(decoder_inputs, decoder_size, batch_size)

    # create decoder_masks to be 0 for decoders that are padding.
    batch_masks = []
    for length_id in range(decoder_size):
        batch_mask = np.ones(batch_size, dtype=np.float32)
        for batch_id in range(batch_size):
            # we set mask to 0 if the corresponding target is a PAD symbol.
            # the corresponding decoder is decoder_input shifted by 1 forward.
            if length_id < decoder_size - 1:
                target = decoder_inputs[batch_id][length_id + 1]
            if length_id == decoder_size - 1 or target == config.PAD_ID:
                batch_mask[batch_id] = 0.0
        batch_masks.append(batch_mask)
    return batch_encoder_inputs, batch_decoder_inputs, batch_masks

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

print('Preparing raw data into train set and test set ...')
lineId2LineTextDictionary = getLineId2LineTextDictionary()
conversationsList = getConversationsList()
questions, answers = conversationToQuestionAnswerPairs(lineId2LineTextDictionary, conversationsList)
createTrainTestEncoderDecoderDataSets(questions, answers)

print('Preparing data to be model-ready ...')
build_vocab('train.enc')
build_vocab('train.dec')
convertDatasetFilesToTokenIds('train', 'enc')
convertDatasetFilesToTokenIds('train', 'dec')
convertDatasetFilesToTokenIds('test', 'enc')
convertDatasetFilesToTokenIds('test', 'dec')

for i in range(1,100):
    print (questions[i] + "    __________   " + answers[i])


import torch
from packaging import version
import numpy as np
import os
import torch.distributed as dist

if version.Version(torch.__version__) >= version.Version('1.0.0'):
  from torch import _softmax_backward_data as _softmax_backward_data
else:
  from torch import softmax_backward_data as _softmax_backward_data

class XSoftmax(torch.autograd.Function):
  """ Masked Softmax which is optimized for saving memory
  Args:

    input (:obj:`torch.tensor`): The input tensor that will apply softmax.
    mask (:obj:`torch.IntTensor`): The mask matrix where 0 indicate that element will be ignored in the softmax caculation.
    dim (int): The dimenssion that will apply softmax.

  Example::
    import torch
    from DeBERTa.deberta import XSoftmax
    # Make a tensor
    x = torch.randn([4,20,100])
    # Create a mask
    mask = (x>0).int()
    y = XSoftmax.apply(x, mask, dim=-1)

  """

  @staticmethod
  def forward(self, input, mask, dim):
    """
    """

    self.dim = dim
    if version.Version(torch.__version__) >= version.Version('1.2.0a'):
      rmask = ~(mask.bool())
    else:
      rmask = (1-mask).byte() # This line is not supported by Onnx tracing.

    output = input.masked_fill(rmask, float('-inf'))
    output = torch.softmax(output, self.dim)
    output.masked_fill_(rmask, 0)
    self.save_for_backward(output)
    return output

  @staticmethod
  def backward(self, grad_output):
    """
    """

    output, = self.saved_tensors
    inputGrad = _softmax_backward_data(grad_output, output, self.dim, output)
    return inputGrad, None, None

def build_relative_position(query_size, key_size, bucket_size=-1, max_position=-1):
  q_ids = np.arange(0, query_size)
  k_ids = np.arange(0, key_size)
  rel_pos_ids = q_ids[:, None] - np.tile(k_ids, (q_ids.shape[0],1))
  if bucket_size>0 and max_position > 0:
    rel_pos_ids = make_log_bucket_position(rel_pos_ids, bucket_size, max_position)
  rel_pos_ids = torch.tensor(rel_pos_ids, dtype=torch.long)
  rel_pos_ids = rel_pos_ids[:query_size, :]
  rel_pos_ids = rel_pos_ids.unsqueeze(0)
  return rel_pos_ids

def make_log_bucket_position(relative_pos, bucket_size, max_position):
  sign = np.sign(relative_pos)
  mid = bucket_size//2
  abs_pos = np.where((relative_pos<mid) & (relative_pos > -mid), mid-1, np.abs(relative_pos))
  log_pos = np.ceil(np.log(abs_pos/mid)/np.log((max_position-1)/mid) * (mid-1)) + mid
  bucket_pos = np.where(abs_pos<=mid, relative_pos, log_pos*sign).astype(np.int)
  return bucket_pos

class AverageMeter(object):
    """Computes and stores the average and current value"""
    def __init__(self, name, fmt=':f'):
        self.name = name
        self.fmt = fmt
        self.reset()

    def reset(self):
        self.val = 0
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        self.val = val
        self.sum += val * n
        self.count += n
        self.avg = self.sum / self.count

    def __str__(self):
        fmtstr = '{name} {val' + self.fmt + '} ({avg' + self.fmt + '})'
        return fmtstr.format(**self.__dict__)

def accuracy(output, target, topk=(1,)):
    """Computes the accuracy over the k top predictions for the specified values of k"""
    with torch.no_grad():
        maxk = max(topk)
        batch_size = target.size(0)

        _, pred = output.topk(maxk, 1, True, True)
        pred = pred.t()
        correct = pred.eq(target.view(1, -1).expand_as(pred))

        res = []
        for k in topk:
            correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True)
            res.append(correct_k.mul_(100.0 / batch_size))
        return res

def init_distributed_mode(args):

    print('Setting up distributed mode...')
    args.num_gpu = 1
    args.device = 'cuda:%d' % args.local_rank
    torch.cuda.set_device(args.local_rank)
    torch.distributed.init_process_group(backend='nccl', init_method='env://')
    args.world_size = torch.distributed.get_world_size()
    args.rank = torch.distributed.get_rank()
    print('Distributed mode set...')

def setup_for_distributed(is_master):
    """
    This function disables printing when not in master process
    """
    import builtins as __builtin__
    builtin_print = __builtin__.print

    def print(*args, **kwargs):
        force = kwargs.pop('force', False)
        if is_master or force:
            builtin_print(*args, **kwargs)

    __builtin__.print = print

def is_dist_avail_and_initialized():
    if not dist.is_available():
        return False
    if not dist.is_initialized():
        return False
    return True

def get_world_size():
    if not is_dist_avail_and_initialized():
        return 1
    return dist.get_world_size()

def get_rank():
    if not is_dist_avail_and_initialized():
        return 0
    return dist.get_rank()


from tkinter import *
import pandas
import random

data = pandas.read_csv("KoreanWords.csv")
words = data.to_dict(orient="records")

def next_card():
    new_word = random.choice(words)

    for key, value in new_word.items():
        if key == "Korean":
            card.itemconfig(language, text=f"{key}", font=('Ariel', 40, 'italic'))
            card.itemconfig(word, text=f"{value}", font=('fixed', 60, 'bold'))

BACKGROUND_COLOR = "#B1DDC6"

window = Tk()
window.title("Korean/English Flashcards")
window.config(pady=50, padx=50, background=BACKGROUND_COLOR)

card = Canvas(width=800, height=526)
card_front_image = PhotoImage(file="images/card_front.png")
card.create_image(400, 263, image=card_front_image)
card.config(background=BACKGROUND_COLOR, highlightthickness=0)
language = card.create_text(400, 150, text="Title", font=('Ariel', 40, 'italic'))
word = card.create_text(400, 263, text="Word", font=('Ariel', 60, 'bold'))
card.grid(row=0, column=0, columnspan=2)

wrong_image = PhotoImage(file="images/wrong.png")
wrong_button = Button(image=wrong_image, highlightthickness=0, borderwidth=0)
wrong_button.grid(row=1, column=0)

right_image = PhotoImage(file="images/right.png")
right_button = Button(image=right_image, highlightthickness=0, command=next_card, borderwidth=0)
right_button.grid(row=1, column=1)

window.mainloop()


from django.shortcuts import render, get_object_or_404, Http404
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.views import generic
from django.core.files.storage import FileSystemStorage
from django.utils import timezone
from django.db import models
from django.contrib.auth.decorators import permission_required

from .models import Manga, Chapter, Page

import os, errno, zipfile
import re

# Create your views here.

def index(request):
    currentList = Manga.objects.all().filter(status=Manga.CURRENT).order_by('title')[:]
    completedList = Manga.objects.all().filter(status=Manga.COMPLETED).order_by('title')[:]
    hiatusList = Manga.objects.all().filter(status=Manga.HIATUS).order_by('title')[:]
    droppedList = Manga.objects.all().filter(status=Manga.DROPPED).order_by('title')[:]
    futureList = Manga.objects.all().filter(status=Manga.FUTURE).order_by('title')[:]
    litcList = Manga.objects.all().filter(status=Manga.LITC).order_by('title')[:]

    context = {}
    if len(currentList) != 0:
        context['current_list'] = currentList
    if len(completedList) != 0:
        context['completed_list'] = completedList
    if len(hiatusList) != 0:
        context['hiatus_list'] = hiatusList
    if len(droppedList) != 0:
        context['dropped_list'] = droppedList
    if len(futureList) != 0:
        context['future_list'] = futureList
    if len(litcList) != 0:
        context['litc_list'] = litcList

    return render(request, 'reader/index.html', context)

def mangaDetail(request, mangaSeries):
    try:
        manga = Manga.objects.get(storage_name=mangaSeries)
    except(KeyError, Manga.DoesNotExist):
        render(request, 'reader/index.html')
    chapterList = manga.chapter_set.filter(visible=True).order_by('-sort_number')[:]
    context = {
        'manga': manga,
        'chapter_list': chapterList,
    }
    return render(request, 'reader/manga_details.html', context)

def readChapter(request, mangaSeries, chapterId):
    try:
        manga = Manga.objects.get(storage_name=mangaSeries)
    except(KeyError, Manga.DoesNotExist):
        render(request, 'reader/index.html')
    try:
        chapter = Chapter.objects.get(pk=chapterId)
    except(KeyError, Chapter.DoesNotExist):
        raise Http404("Chapter does not exist")
    if manga.display_method == Manga.TRADITIONAL:
        return HttpResponseRedirect(reverse('reader:pageReader', args=(mangaSeries, chapterId, 1,)))
    elif manga.display_method == Manga.WEBTOON:
        return HttpResponseRedirect(reverse('reader:stripReader', args=(mangaSeries, chapterId,)))

def stripReader(request, mangaSeries, chapterId):
    try:
        manga = Manga.objects.get(storage_name=mangaSeries)
    except(KeyError, Manga.DoesNotExist):
        render(request, 'reader/index.html')
    try:
        chapter = Chapter.objects.get(pk=chapterId)
    except(KeyError, Chapter.DoesNotExist):
        raise Http404("Chapter does not exist")

    chapterList = manga.chapter_set.filter(visible=True).order_by('sort_number')[:]
    hasPrev = False
    hasNext = False
    prevId = 0
    nextId = 0
    chapLen = len(chapterList)
    for i in range(0, chapLen):
        if chapterList[i] == chapter:
            if (i != chapLen - 1):
                nextId = chapterList[i + 1].id
                hasNext = True
            if (i != 0):
                prevId = chapterList[i - 1].id
                hasPrev = True
            break

    pageList = chapter.page_set.order_by('number')[:]
    pageUrls = []
    for page in pageList:
        strurl = str(page.image)
        pageUrls.append(strurl)

    context = {
        'manga': manga,
        'chapter': chapter,
        'chapter_list': chapterList,
        'prev_id': prevId,
        'next_id': nextId,
        'page_list': pageUrls,
    }
    if hasPrev and (not hasNext):
        context = {
            'manga': manga,
            'chapter': chapter,
            'chapter_list': chapterList,
            'prev_id': prevId,
            'page_list': pageUrls,
        }
    elif hasNext and (not hasPrev):
        context = {
            'manga': manga,
            'chapter': chapter,
            'chapter_list': chapterList,
            'next_id': nextId,
            'page_list': pageUrls,
        }
    elif (not hasNext) and (not hasPrev):
        context = {
            'manga': manga,
            'chapter': chapter,
            'chapter_list': chapterList,
            'page_list': pageUrls,
        }

    return render(request, 'reader/stripReader.html', context)

def pageReader(request, mangaSeries, chapterId, pageNum):
    try:
        manga = Manga.objects.get(storage_name=mangaSeries)
    except(KeyError, Manga.DoesNotExist):
        render(request, 'reader/index.html')
    try:
        chapter = Chapter.objects.get(pk=chapterId)
    except(KeyError, Chapter.DoesNotExist):
        raise Http404("Chapter does not exist")
    try:
        page = chapter.page_set.get(number=pageNum)
    except(KeyError, Page.DoesNotExist):
        raise Http404("Page does not exist")

    pageUrl = str(page.image)
    pageList = [i for i in range(1, chapter.num_pages + 1)]

    hasNextPage = True
    hasPrevPage = True
    hasNextChap = False
    hasPrevChap = False
    prevPage = pageNum - 1
    nextPage = pageNum + 1
    prevChapId = 0
    nextChapId = 0
    prevChapNum = 0

    chapterList = manga.chapter_set.filter(visible=True).order_by('sort_number')[:]
    hasPrev = False
    hasNext = False
    chapLen = len(chapterList)
    for i in range(0, chapLen):
        if chapterList[i] == chapter:
            if (i != chapLen - 1):
                nextChapId = chapterList[i + 1].id
                hasNext = True
            if (i != 0):
                prevChapId = chapterList[i - 1].id
                hasPrev = True
                prevChapNum = chapterList[i - 1].num_pages
            break

    if pageNum == chapter.num_pages or pageNum == 1:
        if pageNum == chapter.num_pages:
            hasNextPage = False
            if hasNext:
                hasNextChap = True
        if pageNum == 1:
            hasPrevPage = False
            if hasPrev:
                hasPrevChap = True

    context = {
        'manga': manga,
        'chapter': chapter,
        'chapter_list': chapterList,
        'page_list': pageList,
        'page_num': pageNum,
        'page_url': pageUrl,
    }
    if hasNextPage:
        context['next_page'] = nextPage
    if hasPrevPage:
        context['prev_page'] = prev_page
    if hasNextChap:
        context['next_chap'] = nextChapId
    if hasPrevChap:
        context['prev_chap'] = prevChapId
        context['prev_chap_pages'] = prevChapNum
    return render(request, 'reader/pageReader.html', context)

def jumpPage(request, mangaSeries, chapterId):
    pageNum = request.POST['page']
    return HttpResponseRedirect(reverse('reader:pageReader', args=(mangaSeries, chapterId, pageNum,)))

def jumpChapter(request, mangaSeries, display):
    chapterId = request.POST['chapter']
    if display == 'webtoon':
        return HttpResponseRedirect(reverse('reader:stripReader', args=(mangaSeries, chapterId,)))
    elif display == 'pages':
        return HttpResponseRedirect(reverse('reader:pageReader', args=(mangaSeries, chapterId, 1)))
    else:
        raise Http404("URL does not exist")

@permission_required('reader.add_chapter', login_url='accounts:login')
def upload(request, chapterUploaded=""):
    mangaList = Manga.objects.order_by('title')[:]
    context = {
        'manga_list': mangaList,
        'chapter_uploaded': chapterUploaded,
    }
    return render(request, 'reader/upload.html', context)

def submitChapter(request):
    try:
        manga = Manga.objects.get(id=request.POST['manga'])
    except(KeyError, Manga.DoesNotExist):
        mangaList = Manga.objects.order_by('title')[:]
        return render(request, 'reader/upload.html', {
            'manga_list': mangaList,
            'error_message': "You didn't select a manga choice.",
        })
    chapNumber = request.POST['chap_number'].strip()
    volNumber = request.POST['vol_number'].strip()
    if (volNumber == ""):
        volNumber = 0
    if (chapNumber == ""):
        mangaList = Manga.objects.order_by('title')[:]
        return render(request, 'reader/upload.html', {
            'manga_list': mangaList,
            'error_message': "Please enter a chapter number!",
        })
    sortNumber = int((float(volNumber) * 1000000) + (float(chapNumber) * 100))
    title = request.POST['title']
    owner = request.user
    upload_date = timezone.now()

    if os.name == 'nt':
        static = "reader\\static\\"
        path = "reader\\mangas\\" + manga.storage_name
    else:
        static = "static/"
        path = "reader/mangas/" + manga.storage_name

    try:
        os.makedirs(static + path)
    except OSError as e:
        if e.errno != errno.EEXIST:
            mangaList = Manga.objects.order_by('title')[:]
            return render(request, 'reader/upload.html', {
                'manga_list': mangaList,
                'error_message': "Oops something went wrong, please try again.",
            })

    chapterStorageName = str(sortNumber) + upload_date.strftime("%Y-%m-%d_%H-%M-%S_%f")
    if os.name == 'nt':
        path = path + "\\" + chapterStorageName
    else:
        path = path + "/" + chapterStorageName

    try:
        os.makedirs(static + path)
    except OSError as e:
        if e.errno != errno.EEXIST:
            mangaList = Manga.objects.order_by('title')[:]
            return render(request, 'reader/upload.html', {
                'manga_list': mangaList,
                'error_message': "Oops something went wrong, please try again.",
            })

    myfile = request.FILES['chapter_file']
    fs = FileSystemStorage()
    filename = fs.save(myfile.name, myfile)
    uploaded_file_url = fs.url(filename)

    sortedList = []
    with zipfile.ZipFile(uploaded_file_url) as myzip:
        unsortedList = myzip.namelist()
        for name in unsortedList:
            if (re.match("^.*\.png$", name) != None):
                sortedList.append(name)
            elif (re.match("^.*\.jpg$", name) != None):
                sortedList.append(name)
        sortedList.sort()
        myzip.extractall(static + path, sortedList)

    chapter = Chapter(manga=manga,
                      chap_number=chapNumber,
                      vol_number=volNumber,
                      sort_number=sortNumber,
                      title=title,
                      num_pages=len(sortedList),
                      owner=owner,
                      upload_date=upload_date,
                      storage_name=chapterStorageName, )
    chapter.save()

    for i in range(1, len(sortedList) + 1):
        page = Page(chapter=chapter, number=i, image=path + "\\" + sortedList[i - 1])
        page.save()

    os.remove(uploaded_file_url)
    returnString = "{0} - {1}".format(manga.title, chapter)
    return HttpResponseRedirect(reverse('reader:upload', args=(returnString,)))


# 평균은 넘겠지

n = int(input())
for i in range(n):
    scores = list(map(int, input().split()))
    scores.pop(0)
    avr = sum(scores) / len(scores)
    cnt = 0
    for j in range(len(scores)):
        if scores[j] > avr:
            cnt += 1
    print('%.3f%s' % (round(cnt/len(scores) * 100 ,3), '%'))


from infrasim.model.core.element import CElement
from infrasim import ArgsNotCorrect

class CPCIVMD(CElement):
    '''
    PciVmd provides the function related with Intel VolumnManagementDevice.
    Check its parameters and generate argument string.
    '''

    def __init__(self, vmd_info):
        super(CPCIVMD, self).__init__()
        self.__vmd_info = vmd_info
        self.__bar1_size = None
        self.__bar2_size = None
        self.bus = None
        self.id = None
        self.device = "vmd"
        self.pcie_topo = None

    def precheck(self):
        if self.__vmd_info.get("id") is None:
            raise ArgsNotCorrect("VMD's id is mandatory!")

        if self.__vmd_info.get("bus") is None:
            raise ArgsNotCorrect("VMD's bus is mandatory!")

        size = self.__vmd_info.get("bar1_size", 1024)
        if (size & (size - 1)) != 0:
            raise ArgsNotCorrect("bar1_size must be pow 2")

        size = self.__vmd_info.get("bar2_size", 1024)
        if (size & (size - 1)) != 0:
            raise ArgsNotCorrect("bar2_size must be pow 2")

    def init(self):
        self.id = self.__vmd_info["id"]
        self.bus = self.__vmd_info["bus"]
        self.__bar1_size = self.__vmd_info.get("bar1_size")
        self.__bar2_size = self.__vmd_info.get("bar2_size")

    def handle_parms(self):
        args = {}
        args["id"] = self.id
        args["bus"] = self.bus
        args["multifunction"] = "on"
        args["addr"] = "5.5"
        if self.__bar1_size:
            args["mbar1_size"] = self.__bar1_size
        if self.__bar2_size:
            args["mbar2_size"] = self.__bar2_size

        opt_list = []
        opt_list.append("-device vmd")
        for k, v in args.items():
            opt_list.append("{}={}".format(k, v))

        self.add_option(",".join(opt_list))