#!/usr/bin/env python3
"""Illustration code for solving heat equation with Jacobi method."""
import argparse
import sys
import time

import numpy as np
import tensorflow as tf

DEVICES = ['/cpu:0', '/gpu:0']
FUNCTIONS = {
    '1': lambda x, y: 1.,
    '0': lambda x, y: 1.,
    'sample': lambda x, y: -np.exp(-10. * ((x - 0.5)**2 + (y - 0.5)**2))
}

def build_iteration(u, f, h):
    """
    Build computation step of Jacobi method for a heat equation.

    We have current approximation in u variable and return the next step approximation.
    The solution is
    result[i][j] = (u[i - 1][j] + u[i + 1][j] + u[i][j - 1] + u[i][j + 1] - h*h*f[i][j]) / 4

    In order to get the best of vectorized computation we aim to use matrix operations when
    available

    The idea is to have u-variable have additional columns and rows for borders. That allows us
    to add views (submatrices) of the u. E.g. if N = 4 we have (u - actual values, b - border):

    b|bbb|b
    -+---+-
    b|uuu|b
    b|uuu|b
    b|uuu|b
    -+---+-
    b|bbb|b

    Then we create four views (top, bottom, left, right):

    .|ttt|.        .|...|.        .|...|.        .|...|.
    -+---+-        -+---+-        -+---+-        -+---+-
    .|ttt|.        .|...|.        l|ll.|.        .|.rr|r
    .|ttt|.        .|bbb|.        l|ll.|.        .|.rr|r
    .|...|.        .|bbb|.        l|ll.|.        .|.rr|r
    -+---+-        -+---+-        -+---+-        -+---+-
    .|...|.        .|bbb|.        .|...|.        .|...|.

    This way the (u[i - 1][j] + u[i + 1][j] + u[i][j - 1] + u[i][j + 1]) becomes
    top + bottom + left + right

    In order to get N+1 x N+1 matrix as in input, we pad all top/bottom/left/right
    with zeros. In order not to rewrite borders we mask inner values with 1, outer
    with zeros, like:

    0|000|0
    -+---+-
    0|111|0
    0|111|0
    0|111|0
    -+---+-
    0|000|0

    Args:
        u - [N + 1; N + 1] tf.Variable (including borders)
        f - [N + 1; N + 1] np.array (including borders)
        h - grid step (1 / N)
        mask - [N + 1, N + 1] matrix computed with get_mask(N)
    Returns:
        [N + 1; N + 1] matrix: result of the iteration
    """

    N = f.shape[0] - 1
    mask = tf.pad(tf.ones((N - 1, N - 1)), ((1, 1), (1, 1)))

    top = u[0:-2, 1:-1]
    bottom = u[2:, 1:-1]
    left = u[1:-1, 0:-2]
    right = u[1:-1, 2:]

    update = (tf.pad(left + right + top + bottom, ((1, 1), (1, 1))) - h*h*f) / 4.

    return update * mask + u * (1 - mask)

def prepare_data(N, boundary_condition_method, heat_source_method):
    """Build data matrices: first approximation and f."""
    u0 = np.zeros((N + 1, N + 1), dtype=np.float32)
    f = np.zeros((N + 1, N + 1), dtype=np.float32)
    h = 1. / N

    for ix in range(N + 1):
        x = h * ix
        for iy in range(N + 1):
            y = h * iy
            if ix == 0 or iy == 0 or ix == N or iy == N:
                u0[ix][iy] = boundary_condition_method(x, y)
            else:
                f[ix][iy] = heat_source_method(x, y)

    return u0, f

def build_computation_graph(u0, f, device):
    """Build computation graph for Jacobi method.
    Args:
        u0, f - data matrices from prepare_data() method
        device - device to run operations on
    Returns
        init_op - operation to initialize all algorithm variables
        diff - tensor that has a norm difference between subsequent steps
        finish_step - operation to finish the current operation
    """
    N = f.shape[0] - 1
    h = 1. / N
    with tf.device(device):
        u = tf.Variable(u0)
        nextu = build_iteration(u, f, h)
        diff = tf.reduce_max(tf.abs(u - nextu))
        finish_step = tf.assign(u, nextu)
        init_op = tf.initialize_all_variables()
    return init_op, diff, finish_step

def run_algorithm(operations, eps):
    """Run actual computations by Jacobi method, until norm difference doesn't exceed eps."""
    init_op, diff, finish_step = operations

    with tf.Session() as session:
        print('Starting evaluation', file=sys.stderr)
        start_time = time.time()
        session.run(init_op)

        iteration_num = 0
        while True:
            iteration_num += 1
            diff_value = session.run(diff)
            session.run(finish_step)

            if iteration_num % 1000 == 0:
                print('Iteration {}: {}'.format(iteration_num, diff_value), file=sys.stderr)
            if diff_value < eps:
                break
        print(
            'Finished with {} iterations. Computation took {:.1f}s'.format(
                iteration_num, time.time() - start_time
            )
        )

def solve(N, boundary_condition_method, heat_source_method, eps, device='/cpu:0'):
    """Build computation graph and run computations."""
    u0, f = prepare_data(N, boundary_condition_method, heat_source_method)
    operations = build_computation_graph(u0, f, device)
    run_algorithm(operations, eps)

def _parse_args():
    parser = argparse.ArgumentParser(description='Solve heat problem with Jacobi algorithm')
    parser.add_argument(
        '--eps',
        type=float,
        default=2e-5,
        help='run algorithm till norm of diffence of two subsequent iterations '
        'doesn\'t exceed this value (default: %(default)s)'
    )
    parser.add_argument(
        '--device',
        default=DEVICES[0],
        choices=DEVICES,
        help='device to run operations on (default: %(default)s)'
    )
    parser.add_argument(
        '--boundary-condition-method',
        default='1',
        choices=FUNCTIONS.keys(),
        help='function to compute boundary condition, you can add more '
        'in FUNCTION variable (default: %(default)s)'
    )
    parser.add_argument(
        '--heat-method',
        default='0',
        choices=FUNCTIONS.keys(),
        help='function to compute heat source constraint, you can add more '
        'in FUNCTION variable (default: %(default)s)'
    )
    parser.add_argument(
        'grid_size',
        type=int,
        help='size of grid (e.g. 1000)'
    )
    return parser.parse_args()

def _main(args):
    solve(
        args.grid_size,
        FUNCTIONS[args.boundary_condition_method],
        FUNCTIONS[args.heat_method],
        args.eps,
        args.device
    )

if __name__ == '__main__':
    _main(_parse_args())


from datetime import datetime, timedelta, timezone

class NotificationsActivities:
    def run():
        now = datetime.now(timezone.utc).astimezone()
        results = [{
            'uuid': '5ceda019-e682-400c-af09-22b05b00ff05',
            'handle':  'Patrick Odhiambo',
            'message': 'Testing the notifications',
            'created_at': (now - timedelta(days=2)).isoformat(),
            'expires_at': (now + timedelta(days=5)).isoformat(),
            'likes_count': 15,
            'replies_count': 3,
            'reposts_count': 2,
            'replies': [{
                'uuid': '9f32a7b2-b507-4300-b7d1-c2134573608b',
                'reply_to_activity_uuid': '5ceda019-e682-400c-af09-22b05b00ff05',
                'handle':  'Worf',
                'message': 'This post has no honor!',
                'likes_count': 0,
                'replies_count': 0,
                'reposts_count': 0,
                'created_at': (now - timedelta(days=2)).isoformat()
            }],
        },
            {
            'uuid': '442699d3-c672-419c-a06b-f5b05478aa02',
            'handle':  'Patrick Odhiambo',
            'message': 'Feedback from a working endpoint',
            'created_at': (now - timedelta(days=7)).isoformat(),
            'expires_at': (now + timedelta(days=9)).isoformat(),
            'likes': 0,
            'replies': []
        },
            {
            'uuid': '81a8360d-133e-4c49-91fd-deb64d81802a',
            'handle':  'Andrew',
            'message': 'Things get tough at first but great in the end',
            'created_at': (now - timedelta(hours=1)).isoformat(),
            'expires_at': (now + timedelta(hours=12)).isoformat(),
            'likes': 0,
            'replies': []
        }
        ]
        return results


## This config file lets you automatically upload your data to
## an Amazon S3 Bucket.
##
## This is just an example config -- fill in your specific Access key
## and secret key, then rename this file from "example_botoConfig.py"
## to "botoConfig.py".
##
## Do not share your secret key with others! Add "botoConfig.py" to your
## gitignore!

[Credentials]
aws_access_key_id = YOURACCESSKEY
aws_secret_access_key = YOURSECRETKEY


import logging

LOG = logging.getLogger(__name__)

def worker(tasks):
    while True:
        task = tasks.get()

        LOG.debug('processing task %s' % task)

        try:
            operation = OPERATIONS.get(task.pop('operation'))
            operation(**task)
        finally:
            tasks.task_done()


# Machine Learning Online Class - Exercise 1: Linear Regression

#  Instructions
#  ------------
#
#  This file contains code that helps you get started on the
#  linear exercise. You will need to complete the following functions
#  in this exericse:
#
#     warmup_exercise.py
#     plotData.m
#     computeCost.m
#     gradientDescent.m
#     gradientDescentMulti.m
#     computeCostMulti.m
#     featureNormalize.m
#     normalEqn.m
#
#  For this exercise, you will not need to change any code in this file,
#  or any other files other than those mentioned above.
#
# x refers to the population size in 10,000s
# y refers to the profit in $10,000s
#
import numpy
import matplotlib.pyplot as plt

import lin_reg_funcs

# ==================== Part 1: Basic Function ====================
# Complete warmup_exercise.py
print('Running warmup_exercise ... \n')
print('5x5 Identity Matrix: \n')
print(lin_reg_funcs.warmup_exercise())

# ======================= Part 2: Plotting =======================
print("\nPlotting Data...\n")
data = numpy.loadtxt('./ex1data1.txt', dtype="float", delimiter=",")
x_data = data[:, 0]
y_data = data[:, 1]
num_examples = y_data.shape[0]  # number of training examples

# Plot Data
# Note: You have to complete the code in plotData.m
lin_reg_funcs.plot_data(x_data, y_data)

# =================== Part 3: Cost and Gradient descent ===================
x_data = numpy.c_[numpy.ones((num_examples, 1)), data[:, 0]]  # Add a column of ones to x
theta = numpy.zeros((2, 1))  # initialize fitting parameters

# Some gradient descent settings
iterations = 10000
alpha = 0.0001

print('\nTesting the cost function ...\n')
# compute and display initial cost
cost_J = lin_reg_funcs.compute_cost(x_data, y_data, theta, num_examples)
print('With theta = [0, 0]\nCost computed = {:.2f}'.format(cost_J))
print('Expected cost value (approx) 32.07\n')

# further testing of the cost function
theta = numpy.array([-1.0, 2.0])
cost_J = lin_reg_funcs.compute_cost(x_data, y_data, theta, num_examples)
print('\nWith theta = [-1, 2]\nCost computed = {:.2f}'.format(cost_J))
print('Expected cost value (approx) 54.24\n')

print('\nRunning Gradient Descent ...\n')
# run gradient descent
theta, J_history = lin_reg_funcs.gradient_descent(x_data, y_data, theta, num_examples, alpha, iterations)

# print theta to screen
print('Theta found by gradient descent:', theta)
print('Expected theta values (approx)', numpy.array([-3.6303, 1.1664]), "\n")

# Plot the linear fit
line_data = numpy.reshape(numpy.dot(x_data, theta), y_data.shape)
lin_reg_funcs.plot_data_line(x_data[:, 1], y_data, line_data)

# Predict values for population sizes of 35,000 and 70,000
predict1 = numpy.dot(numpy.array([1.0, 3.5]), theta)
print('For population = 35,000, we predict a profit of {}'.format(predict1*10000))
predict2 = numpy.dot(numpy.array([1.0, 7.0]), theta)
print('For population = 70,000, we predict a profit of {}'.format(predict2*10000))

# ============= Part 4: Visualizing J(theta_0, theta_1) =============
print('Visualizing J(theta_0, theta_1) ...\n')

# Grid over which we will calculate J
theta0_vals = numpy.linspace(-10, 10, 100)
theta1_vals = numpy.linspace(-1, 4, 100)

# initialize J_vals to a matrix of 0's
J_vals = numpy.zeros((theta0_vals.shape[0], theta1_vals.shape[0]))

# Fill out J_vals
for ix in range(theta0_vals.shape[0]):
    for jx in range(theta1_vals.shape[0]):
        t = numpy.array([theta0_vals[ix], theta1_vals[jx]])
        J_vals[ix, jx] = lin_reg_funcs.compute_cost(x_data, y_data, t, num_examples)

# Because of the way meshgrids work in the surf command, we need to
# transpose J_vals before calling surf, or else the axes will be flipped
# J_vals = J_vals'
# Surface plot
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_surface(theta0_vals, theta1_vals, J_vals, cmap='viridis', edgecolor='none')
plt.xlabel('theta_0')
plt.ylabel('theta_1')
plt.show()

# Contour plot
fig = plt.figure()
ax = plt.axes()
# Plot J_vals as 15 contours spaced logarithmically between 0.01 and 100
ax.contour(theta0_vals, theta1_vals, J_vals, numpy.logspace(-2, 3, 50))
plt.xlabel('theta_0')
plt.ylabel('theta_1')
ax.plot(theta[0], theta[1], marker='x', markersize=10, linewidth=2)
plt.show()


from typing import List

class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        if n < 2:
            return n
        signs = []
        for prev, curr in zip(nums[:-1], nums[1:]):
            new_sign = curr - prev
            if new_sign != 0:
                new_sign = new_sign // abs(new_sign)
                signs.append(new_sign)

        res = len(signs) + 1
        for prev, curr in zip(signs[:-1], signs[1:]):
            if prev == curr:
                res -= 1
        return res


from . import PAYMENT_METHOD_STRIPE, PAYMENT_EVENT_PURCHASE, STRIPE_EMAIL, STRIPE_TOKEN
#from .docdata import CustomDocdataFacade
from .facade import Facade
import logging
from oscar.apps.payment.models import Source
from . import gateway
from oscar.apps.checkout import views as oscar_views

from paypal.payflow import facade
from django.contrib import messages

from django.shortcuts import redirect
from oscar.apps.payment.models import SourceType
from oscar.apps.payment.forms import BankcardForm
from .forms import *
from oscar.apps.checkout import exceptions
from django.urls import reverse, reverse_lazy
from oscar.core.loading import get_model, get_class
from globalsettings.models import Paymentmethod
OscarPaymentMethodView = get_class("checkout.views", "PaymentMethodView")
OscarPaymentDetailsView = get_class("checkout.views", "PaymentDetailsView")
OscarShippingMethodView = get_class("checkout.views", "ShippingMethodView")
OscarCheckoutSessionMixin = get_class("checkout.views", "CheckoutSessionMixin")
from django.views.generic import FormView
from django.conf import settings
BillingAddress = get_model("order", "BillingAddress")
from django.views import generic
from oscar.core.loading import get_classes, get_model

logger = logging.getLogger(__name__)
Country = get_model('address', 'Country')
ShippingAddressForm, ShippingMethodForm, GatewayForm \
    = get_classes('checkout.forms', ['ShippingAddressForm', 'ShippingMethodForm', 'GatewayForm'])

# Sample pre-condition
class CheckCountryPreCondition(object):
    """DRY class for check country in session pre_condition"""

    def get_pre_conditions(self, request):
        if 'check_country_in_session' not in self.pre_conditions:
            return self.pre_conditions + ['check_country_in_session']
        return super().get_pre_conditions(request)

    def check_country_in_session(self, request):
        if request.session.get('country', None) is None:
            raise exceptions.FailedPreCondition(
                    url=reverse('checkout:shipping-address'),
                )

# Inspired by https://github.com/django-oscar/django-oscar-docdata/blob/master/sandbox/apps/checkout/views.py
class PaymentMethodView(OscarPaymentMethodView, FormView):
    """
    View for a user to choose which payment method(s) they want to use.

    This would include setting allocations if payment is to be split
    between multiple sources. It's not the place for entering sensitive details
    like bankcard numbers though - that belongs on the payment details view.
    """
    template_name = "oscar/checkout/payment_method.html"
    step = 'payment-method'
    form_class = PaymentMethodForm
    pre_conditions = []
    skip_conditions = []
    success_url = reverse_lazy('checkout:payment-details')

    def get(self, request, *args, **kwargs):

        # if only single payment method, store that
        # and then follow default (redirect to preview)
        # else show payment method choice form
        if Paymentmethod.objects.count() == 1:
            self.checkout_session.pay_by(settings.OSCAR_PAYMENT_METHODS[0][0])
            return redirect(self.get_success_url())
        else:

            return FormView.get(self, request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        #print("Context")
        """Insert the form into the context dict."""
        if 'form' not in kwargs:
            kwargs['form'] = self.get_form()
        return super().get_context_data(**kwargs)

    def get_success_url(self, *args, **kwargs):

        # Redirect to the correct payments page as per the method (different methods may have different views &/or additional views)
        if (self.checkout_session.payment_method() == 'cod'):
            return reverse_lazy('checkout:preview')
        return reverse_lazy('checkout:payment-details')

    def get_initial(self):

        return {
            'payment_method': self.checkout_session.payment_method(),
        }

    def form_valid(self, form):
        # Store payment method in the CheckoutSessionMixin.checkout_session (a CheckoutSessionData object)
        self.checkout_session.pay_by(form.cleaned_data['payment_method'])
        return super().form_valid(form)

class PaymentDetailsView(oscar_views.PaymentDetailsView):
    """
    An example view that shows how to integrate BOTH PayPal Express
    (see `get_context_data method`) and PayPal Flow (the other methods).
    Naturally, you will only want to use one of the two.
    """
    #template_name = 'website/payment_details.html'
    #template_name = "oscar/checkout/payment_details.html"
    #template_name_preview = 'website/preview.html'
    #template_name_preview = 'oscar/checkout/preview.html'

    def get_billing_address_form(self, billing_address):
        """
        Return an instantiated billing address form
        """
        addr = self.get_default_billing_address()
        if not addr:
            return BillingAddressForm(billing_address)
        billing_addr = BillingAddress()
        addr.populate_alternative_model(billing_addr)
        return BillingAddressForm(billing_address,
                                  instance=billing_addr)

    def get_context_data(self, **kwargs):
        """
        Add data for Paypal Express flow.
        """
        # Override method so the bankcard and billing address forms can be
        # added to the context.
        ctx = super(PaymentDetailsView, self).get_context_data(**kwargs)

        if 'billing_address_form' not in kwargs:
            ctx['billing_address_form'] = self.get_billing_address_form(
                ctx['shipping_address']
            )
        method = self.checkout_session.payment_method()
        ctx['payment_method'] = {
            'code': method,
            'title': self.get_payment_method_display(method),
        }

        if (method=='card'):

            if self.preview:
                ctx['stripe_token_form'] = StripeTokenForm(self.request.POST)
                ctx['order_total_incl_tax_cents'] = (
                        ctx['order_total'].incl_tax * 100
                ).to_integral_value()
            else:
                ctx['stripe_publishable_key'] = settings.STRIPE_PUBLISHABLE_KEY
        #print("Context "+str(ctx))
        return ctx

    def get_payment_method_display(self, payment_method):
        method = Paymentmethod.objects.filter(method=payment_method).first()
        dict = {method.code:method.code}

        return dict
        #return dict(settings.OSCAR_PAYMENT_METHODS).get(payment_method)

    def handle_place_order_submission(self, request):
        # Collect all the data!
        submission = self.build_submission()

        # docdata needs to have a lot of information to start the payment.
        # TODO: Is this the right way to pass the information??
        submission['payment_kwargs']['submission'] = submission

        # Start the payment process!
        # This jumps to handle_payment()
        return self.submit(**submission)

    def post(self, request, *args, **kwargs):

        # Override so we can validate the bankcard/billing_address submission.
        # If it is valid, we render the preview screen with the forms hidden
        # within it.  When the preview is submitted, we pick up the 'action'
        # parameters and actually place the order.
        if request.POST.get('action', '') == 'place_order':
            return self.do_place_order(request)

            #paypal
            if (self.checkout_session.payment_method() == 'paypal'):

                bankcard_form = forms.BankcardForm(request.POST)
                billing_address_form = forms.BillingAddressForm(request.POST)
                if not all([bankcard_form.is_valid(),
                    billing_address_form.is_valid()]):
                 # Form validation failed, render page again with errors
                    self.preview = False
                    ctx = self.get_context_data(
                    bankcard_form=bankcard_form,
                    billing_address_form=billing_address_form)
                    return self.render_to_response(ctx)

            # Render preview with bankcard and billing address details hidden
                return self.render_preview(request,
                                   bankcard_form=bankcard_form,
                                   billing_address_form=billing_address_form)
            #cod
            #if (self.checkout_session.payment_method() == 'cod'):
            #    return self.handle_place_order_submission(request)
        #else:
            return self.handle_payment_details_submission(request)

        return super(PaymentDetailsView, self).post(request, *args, **kwargs)

    def do_place_order(self, request):

        # Helper method to check that the hidden forms wasn't tinkered
        # with.
        submission = self.build_submission()
        # paypal
        if (self.checkout_session.payment_method() == 'paypal'):
            bankcard_form = forms.BankcardForm(request.POST)
            billing_address_form = forms.BillingAddressForm(request.POST)
            if not all([bankcard_form.is_valid(),
                    billing_address_form.is_valid()]):
                messages.error(request, "Invalid submission")
                return redirect('checkout:payment-details')

            # Attempt to submit the order, passing the bankcard object so that it
            # gets passed back to the 'handle_payment' method below.

            submission['payment_kwargs']['bankcard'] = bankcard_form.bankcard
            submission['payment_kwargs']['billing_address'] = billing_address_form.cleaned_data
        return self.submit(**submission)

    def payment_description(self, order_number, total, **kwargs):
        return self.request.POST[STRIPE_EMAIL]

    def payment_metadata(self, order_number, total, **kwargs):
        return {'order_number': order_number}

    def handle_payment(self, order_number, total, **kwargs):
        """
                    Make submission to PayPal
                    """
        if (self.checkout_session.payment_method() == 'card'):

            stripe_ref = Facade().charge(
                order_number,
                total,
                card=self.request.POST[STRIPE_TOKEN],
                description=self.payment_description(order_number, total, **kwargs),
                metadata=self.payment_metadata(order_number, total, **kwargs))

            source_type, __ = SourceType.objects.get_or_create(name=PAYMENT_METHOD_STRIPE)
            source = Source(
                source_type=source_type,
                currency=settings.STRIPE_CURRENCY,
                amount_allocated=total.incl_tax,
                amount_debited=total.incl_tax,
                reference=stripe_ref)
            self.add_payment_source(source)

            self.add_payment_event(PAYMENT_EVENT_PURCHASE, total.incl_tax)

        if (self.checkout_session.payment_method() == 'paypal'):

            # Using authorization here (two-stage model).  You could use sale to
            # perform the auth and capture in one step.  The choice is dependent
            # on your business model.
            facade.authorize(
                order_number, total.incl_tax,
                kwargs['bankcard'], kwargs['billing_address'])

            # Record payment source and event
            source_type, is_created = SourceType.objects.get_or_create(
                name='PayPal')
            source = source_type.sources.model(
                source_type=source_type,
                amount_allocated=total.incl_tax, currency=total.currency)
            self.add_payment_source(source)
            self.add_payment_event('Authorised', total.incl_tax)
        if (self.checkout_session.payment_method() == 'cod'):

            reference = gateway.create_transaction(order_number, total)

            source_type, is_created = SourceType.objects.get_or_create(
                name='Cash on Delivery')
            source = Source(source_type=source_type,
                            currency=total.currency,
                            amount_allocated=total.incl_tax,
                            amount_debited=total.incl_tax)
            self.add_payment_source(source)
            self.add_payment_event('Issued', total.incl_tax,
                                   reference=reference)
            #self.add_payment_event('Issued', total.incl_tax
            #                       )


"""Template-script for running a parallel kMC simulation.

The script determines which process number the current machine
(world.rank) is in the set of total processes (world.size).
One directory is created for each process and run separately in
this.

Note
------
This script is to be used in combination with submit_script.sh

"""

import os
import sys
from ase.build import fcc111
from ase.parallel import MPI4PY
from user_sites import Site
from user_system import System
from user_events import A, B, Z
from user_kmc import NeighborKMC
from user_constants import *

world = MPI4PY()
rank = world.rank # What number simulation copy am I?
size = world.size # How many total simulation copies?
rundir = "run_"+str(rank)  # Name of the dir I create

os.mkdir(rundir) # Create dir
os.system("cp kMC_options.cfg "+rundir) # copy kMC_options.cfg here
os.chdir(rundir)

T= float(sys.argv[1])  # Temperature
pA = float(sys.argv[2])  # C2H2 pressure

tend = 1.0  # End time of simulation (s)
a0 = 4.00  # Lattice Parameter (not related to DFT!)
Ncutoff = a0 / np.sqrt(2.) + 0.05  # Nearest neighbor cutoff

atoms = fcc111("Pt", size=(10, 10, 1), a=a0)
sites = []

for i, indic in enumerate(atoms):
    sites.append(Site(stype=0, covered=0, ind=[i]))

events = [A, B, Z]
reverse_events = {0: 1}

p = System(atoms=atoms, sites=sites)
p.set_neighbors(Ncutoff)

parameters = {"pA": pA,
              "T": T,
              "Name": "Parallel Simulation",
              "reverse events": reverse_events}

sim = NeighborKMC(system=p,
                  tend=tend,
                  parameters=parameters,
                  events=events,
                  rev_events=reverse_events)

result = sim.run_kmc()


from chatterbox import Chatter
from chatterbox.chatter import HomeBase
from chatterbox.response import Keyboard

class TestChatter:
    def test_create_chatter(self):
        chatter = Chatter()
        assert chatter is not None

    def test_handler_functions(self, handler):
        assert isinstance(handler, dict)

        for func_name in handler:
            assert callable(handler[func_name])

    def test_add_rule(self, chatter, handler):
        chatter.add_rule(action='자기소개',
                         src='홈',
                         dest='소개',
                         func=handler['intro'])

        rule = chatter.rules.action('자기소개').one()
        assert rule is not None
        assert rule.src == '홈'
        assert rule.dest == '소개'
        assert callable(rule.func)

    def test_add_rule_decorator(self, chatter):
        @chatter.rule(action='자기소개', src='홈', dest='소개')
        def intro(data):
            pass

        rule = chatter.rules.action('자기소개').one()
        assert rule is not None
        assert rule.src == '홈'
        assert rule.dest == '소개'
        assert callable(rule.func)

    def test_add_rule_multiple_action(self, chatter, handler):
        actions = ['자기소개', '소개하기', '안내']
        chatter.add_rule(action=actions,
                         src='홈',
                         dest='소개',
                         func=handler['intro'])

        rule = chatter.rules.action('자기소개').src('홈').first()
        assert rule.dest == '소개'
        assert callable(rule.func)

        rules = chatter.rules.src('홈').dest('소개').all()
        for rule in rules:
            assert rule.action in actions

        funcs = [rule.func for rule in rules]
        assert len(set(funcs)) == 1

    def test_add_base(self, chatter, handler):
        chatter.add_base(name='홈', func=handler['home_keyboard'])

        assert chatter.home.name == '홈'
        assert callable(chatter.home.func)
        assert isinstance(chatter.home(), Keyboard)
        assert isinstance(chatter.home, HomeBase)

    def test_add_base_decorator(self, chatter):
        @chatter.base('홈')
        def home_keyboard():
            pass

        assert chatter.home.name == '홈'
        assert callable(chatter.home.func)

class TestHomeBase:
    def test_homebase_with_args(self):
        def keyboard():
            return Keyboard(['버튼'])
        home = HomeBase()
        home.register('홈', keyboard)

        assert home.name == '홈'
        assert callable(home.func)
        assert callable(home)
        assert home() == home.func()

    def test_homebase_without_args(self):
        home = HomeBase()
        home.name = '홈'
        home.func = lambda: Keyboard(['버튼'])
        assert home() == home.func()


import sys
from _tablviews import PrintViews
from _tablinverse import InverseTabl
from _tabltypes import tgen, rgen

def TablTest(T: tgen, dim: int = 8, short: bool = False) -> None:

    PrintViews(T, dim, verbose=True)

    # Increase the default recursion limit
    sys.setrecursionlimit(3000)
    sys.set_int_max_str_digits(5000)

    arg: int = 500 if short else 1000
    gen: rgen = T.gen
    eq: bool = T(arg, arg) == gen(arg)[-1]

    a1: str = str(arg)
    a2: str = str(arg // 2)

    if eq:
        print(f"py> T({a1}, {a1}) == row({a1})[-1] = {eq}")
    else:
        print(f"Error! \n {T(arg, arg)} \n {gen(arg)[-1]}")

    try:
        print(f"py> tabl[{arg}][{a2}] =")
        print(gen(arg)[arg // 2])
    except:
        print("Exceeds the limit for integer string conversion.")

    I = InverseTabl(T.tab(8))
    if I == []:
        print("\nTriangle is not invertibel.")
    else:
        print("\nInverse triangle:")
        for row in I: print(row)

    print("\n--- TablTest done!\n")


#!/usr/bin/env python
# coding: utf-8

# In[16]:

import os
from heapq import heappush, heappop

# In[17]:

def preprocess(filename):
    from nltk import word_tokenize
    from nltk.stem.porter import PorterStemmer
    from nltk.corpus import stopwords

    tokens = []
    with open(filename, 'r') as f_in:
        for line in f_in:
            line = line.strip()
            tokens.extend(word_tokenize(line))
            tokens = [token.lower() for token in tokens if token.isalpha()]
#     print('Tokenize: {}'.format(tokens))
    stemmer = PorterStemmer()
    singles = [stemmer.stem(t) for t in tokens]
#     print('Porter\'s result: {}'.format(singles))
    stops = set(stopwords.words('english'))
    results = ([s for s in singles if s not in stops])
    return results

# In[18]:

def get_vocabulary_dict(count_list):
    import pickle
    if not os.path.isfile('dictionary.txt'):
        df = {}
        for count in count_list:
            _list = list()
            for word in count:
                if word not in df and word not in _list:
                    df[word] = 1
                    _list.append(word)
                elif word in df and word not in _list:
                    df[word] += 1
                    _list.append(word)
        with open('dictionary.txt', 'w') as f_out:
            for i, key in enumerate(sorted(df.keys()), start=1):
                f_out.write(str(i) + ' ' + key + ' ' + str(df[key]) + '\n')
        with open('dictionary.pkl', 'wb') as pkl_out:
            pickle.dump(df, pkl_out)
    with open('dictionary.pkl', 'rb') as pkl_in:
        df = pickle.load(pkl_in)
        return df

def tf(word, count):
    return count[word] / sum(count.values())

def n_containing(word, count_list):
    return get_vocabulary_dict(count_list)[word]

def idf(word, count_list):
    return math.log(len(count_list) / n_containing(word, count_list))

def tfidf(word, count, count_list):
    return tf(word, count) * idf(word, count_list)

def cos_sim(docx, docy):
    from scipy import spatial
    import numpy as np
    key_union = list(set(docx.keys()) | set(docy.keys()))
    result = 1 - spatial.distance.cosine([docx[k] if k in docx else 0 for k in key_union], [docy[k] if k in docy else 0 for k in key_union])
    return result

def get_int(filename):
    start, end = '/', '.'
    return int(filename[filename.find(start)+1:filename.find(end)])

def save_vector_file(filename, sorted_document):
    if not os.path.isfile('vector_files/' + filename + 'txt'):
        with open('vector_files/' + filename + '.txt', 'w') as f:
            f.write(str(len(sorted_document)) + '\n')
            f.write('t_index tf-idf' + '\n')
            for t_index, tf_idf in sorted_document:
                f.write(str(t_index) + ' ' + str(tf_idf) + '\n')

# In[19]:

import glob
import math
from collections import Counter

directory = glob.glob('IRTM/*.txt')
countList = []
for d in sorted(directory, key=get_int):
    tokens = preprocess(d)
    count = Counter(tokens)
    countList.append(count)
# print(countList)
tf_documents = []
sorted_documents = []
for i, count in enumerate(countList):
    word2id = {key: index for index, key in enumerate(sorted(get_vocabulary_dict(countList).keys()), start=1)}
    scores = {word2id[word]: tfidf(word, count, countList) for word in count}
    sorted_words = sorted(scores.items(), key=lambda x: x[0])
    save_vector_file(str(i+1), sorted_words)
    tf_documents.append(scores)

# In[20]:

c = cos_sim(tf_documents[0], tf_documents[1])
print(c, cos_sim(tf_documents[1], tf_documents[2]))

# In[21]:

def build_table_and_heap(tf_documents):
    doc_num = len(tf_documents)
    cos_heap = []
    for i in range(doc_num):
        for j in range(i+1, doc_num):
            heappush(cos_heap, (-cos_sim(tf_documents[i], tf_documents[j]), i, j))
    return cos_heap

# In[22]:

doc_num = len(tf_documents)
merge_list = [[y] for y in range(doc_num)]
cos_heap = build_table_and_heap(tf_documents)
tree_dict = {}

# In[23]:

print(doc_num)
record_cluster = [20, 13, 8]

# In[67]:

def linking(cos_heap, record_cluster, doc_num):
    count = 0
    tree_dict = {}
    merge_list = [[y] for y in range(doc_num)]
    while cos_heap:
        e = heappop(cos_heap)
#         print(e)
        cos = e[0]
        node_x = e[1]
        node_y = e[2]
        if node_y in merge_list[node_x]: continue
        else:
            count += 1
            print(len(merge_list[node_x]), len(merge_list[node_y]))
            print('{} not in merge_list[{}]: {}'.format(node_y, node_x, merge_list[node_x]))
            print('merge merge_list[{}]: {} into merge_list[{}]: {}'.format(node_y, merge_list[node_y], node_x, merge_list[node_x]))
            docs = list(set(merge_list[node_x]) | set(merge_list[node_y]))
            for doc in sorted(docs):
                merge_list[doc] = docs
            print('get merge_list[{}]: {}'.format(node_x, merge_list[node_x]))
            for i in record_cluster:
                if i == doc_num - count:
                    tree_dict[i] = [list(item) for item in set(tuple(sorted(row)) for row in merge_list)]
#                     print(i, tree_dict[i])
        if doc_num - count <= 8: break
    return tree_dict

# In[68]:

tree_dict = linking(list(cos_heap), list(record_cluster), doc_num)

# c_heap = list(cos_heap)
# len(cos_heap)

# In[69]:

# print(doc_num)
tree_dict = linking(list(cos_heap), list(record_cluster), doc_num)

# In[74]:

with open('20.txt', 'w') as f:
    for docs in tree_dict[20]:
        for doc in docs:
            f.write(str(doc+1) + '\n')
        f.write('\n')

with open('13.txt', 'w') as f:
    for docs in tree_dict[13]:
        for doc in docs:
            f.write(str(doc+1) + '\n')
        f.write('\n')

with open('8.txt', 'w') as f:
    for docs in tree_dict[8]:
        for doc in docs:
            f.write(str(doc+1) + '\n')
        f.write('\n')

# print(len(tree_dict[20]))
# print(len(tree_dict[13]))
# print(len(tree_dict[8]))

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:


from __future__ import annotations

import asyncio
from typing import (
    Any,
    AsyncIterable,
    AsyncIterator,
    Awaitable,
    Callable,
    Collection,
    Deque,
    Generic,
    Iterator,
    List,
    Optional,
    Set,
    Tuple,
    Type,
    TypeVar,
    Union,
)

A = TypeVar("A")
T = TypeVar("T")
T_co = TypeVar("T_co", covariant=True)
R = TypeVar("R")

async def consume(iterable: AsyncIterable[Any]) -> None:
    async for _ in iterable:
        pass

class BoostExecutor:
    """BoostExecutor implements a concurrent.futures-like interface for running async tasks.

    The idea is: you want to run a limited number of tasks at a time. Moreover, if you have spare
    capacity, you want to redistribute it to tasks you're running. For instance, when downloading
    chunks of a file, we could use spare capacity to proactively download future chunks. That is,
    instead of the following serial code:
    ```
    for chunk in iterable_of_chunks:
        data = await download_func(chunk)
        write(data)
    ```
    You can instead do:
    ```
    async with BoostExecutor(4) as executor:
        async for data in executor.map_ordered(download_func, iterable_of_chunks):
            write(data)
    ```

    The number supplied to BoostExecutor is the number of units of concurrency you wish to maintain.
    That is, using ``BoostExecutor(1)`` would make the above example function approximately similar
    to the serial code.

    """

    def __init__(self, concurrency: int) -> None:
        assert concurrency > 0
        self.concurrency = concurrency
        # Okay, so this is a little tricky. We take away one unit of concurrency now, and give it
        # back when you iterate over a boostable. You can think of concurrency - 1 as the number of
        # units of "background" concurrency. When our "foreground" starts iterating over a
        # boostable, for instance, with an async for loop, it donates one unit of concurrency to the
        # cause for the duration of the iteration.
        # Why this rigmarole? To avoid deadlocks on reentrancy. If a boostable spawns more work on
        # the same executor and then blocks on that work, it's holding a unit of concurrency while
        # trying to acquire another one. If that happens enough times, we deadlock. For examples,
        # see test_composition_nested_(un)?ordered.
        # To solve this, we treat Boostable.__aiter__ as an indicator that we are entrant. We then
        # donate a unit of concurrency by releasing the semaphore. Conceptually, this is our
        # "foreground" or "re-entrant" unit of concurrency. We give this back when the Boostable is
        # done iterating. We could be more granular and do this on every Boostable.__anext__, but
        # that's a lot more overhead, makes iteration less predictable and can result in what feels
        # like unnecessary blocking. We could also do something complicated using contextvars, but
        # that would have to be something complicated and would have to use contextvars.
        self.semaphore = asyncio.Semaphore(concurrency - 1)
        self.boostables: Deque[Boostable[Any]] = Deque()

        self.waiter: Optional[asyncio.Future[None]] = None
        self.runner: Optional[asyncio.Task[None]] = None
        self.shutdown: bool = False

    async def __aenter__(self) -> BoostExecutor:
        self.runner = asyncio.create_task(self.run())
        return self

    async def __aexit__(
        self, exc_type: Optional[Type[BaseException]], exc_value: Any, traceback: Any
    ) -> None:
        self.shutdown = True
        if exc_type:
            # If there was an exception, let it propagate and don't block on the runner exiting.
            # Also cancel the runner.
            assert self.runner is not None
            self.runner.cancel()
            return
        self.notify_runner()
        assert self.runner is not None
        await self.runner

    def eagerise(self, iterator: AsyncIterator[T]) -> EageriseBoostable[T]:
        ret = EageriseBoostable(iterator, self)
        self.boostables.appendleft(ret)
        self.notify_runner()
        return ret

    def map_ordered(
        self, func: Callable[[A], Awaitable[T]], iterable: BoostUnderlying[A]
    ) -> OrderedMappingBoostable[A, T]:
        ret = OrderedMappingBoostable(func, iterable, self)
        self.boostables.appendleft(ret)
        self.notify_runner()
        return ret

    def map_unordered(
        self, func: Callable[[A], Awaitable[T]], iterable: BoostUnderlying[A]
    ) -> UnorderedMappingBoostable[A, T]:
        ret = UnorderedMappingBoostable(func, iterable, self)
        self.boostables.appendleft(ret)
        self.notify_runner()
        return ret

    def enumerate(self, iterable: BoostUnderlying[T]) -> EnumerateBoostable[T]:
        ret = EnumerateBoostable(iterable, self)
        self.boostables.appendleft(ret)
        self.notify_runner()
        return ret

    def filter(
        self, filter_fn: Optional[Callable[[T], bool]], iterable: BoostUnderlying[T]
    ) -> FilterBoostable[T]:
        ret = FilterBoostable(filter_fn, iterable, self)
        self.boostables.appendleft(ret)
        self.notify_runner()
        return ret

    def notify_runner(self) -> None:
        if self.waiter and not self.waiter.done():
            self.waiter.set_result(None)

    async def run(self) -> None:
        loop = asyncio.get_running_loop()
        exhausted_boostables: List[Boostable[Any]] = []
        not_ready_boostables: Deque[Boostable[Any]] = Deque()

        MIN_TIMEOUT = 0.01
        MAX_TIMEOUT = 0.1
        timeout = MIN_TIMEOUT

        if self.concurrency == 1:
            return

        while True:
            await self.semaphore.acquire()
            self.semaphore.release()

            while self.boostables:
                # We round robin the boostables until they're either all exhausted or not ready
                task = self.boostables[0].provide_boost()
                if isinstance(task, NotReady):
                    not_ready_boostables.append(self.boostables.popleft())
                    continue
                if isinstance(task, Exhausted):
                    exhausted_boostables.append(self.boostables.popleft())
                    continue
                assert isinstance(task, asyncio.Task)

                await asyncio.sleep(0)
                self.boostables.rotate(-1)
                if self.semaphore.locked():
                    break
            else:
                self.boostables = not_ready_boostables
                not_ready_boostables = Deque()

            if self.semaphore.locked():
                # If we broke out of the inner loop due to a lack of available concurrency, go to
                # the top of the outer loop and wait for concurrency
                continue

            if self.shutdown and not self.boostables:
                # If we've been told to shutdown and we have nothing more to boost, exit
                break

            self.waiter = loop.create_future()
            try:
                # If we still have boostables (because they're currently not ready), timeout in
                # case they become ready
                # Otherwise, (since we have available concurrency), wait for us to be notified in
                # case of more work
                await asyncio.wait_for(self.waiter, timeout if self.boostables else None)
                # If we were waiting for boostables to become ready, increase how long we'd wait
                # the next time. Otherwise, reset the timeout duration.
                timeout = min(MAX_TIMEOUT, timeout * 2) if self.boostables else MIN_TIMEOUT
            except asyncio.TimeoutError:
                pass
            self.waiter = None

        # It's somewhat unintuitive that we can shutdown an executor while Boostables are still
        # being iterated over. So wait for them to finish as a courtesy (but not a guarantee).
        for boostable in exhausted_boostables:
            await boostable.wait()

        # Yield, so that iterations over boostables are likely to have finished by the time we exit
        # the BoostExecutor context
        await asyncio.sleep(0)

class Exhausted:
    pass

class NotReady:
    pass

class Boostable(Generic[T_co]):
    """A Boostable is an async iterable with a twist.

    The twist is that it can make use of additional concurrency to compute the elements it iterates
    in parallel. Boostables also compose, so that additional concurrency is directed to the task
    that needs it most.

    See the docstring of MappingBoostable to see how this plays out in practice.

    You probably shouldn't use these classes directly, instead, instantiate them via the
    corresponding methods of the executor used to manage the Boostable.

    """

    def __init__(self, executor: BoostExecutor) -> None:
        self.executor = executor

    def provide_boost(self) -> Union[NotReady, Exhausted, asyncio.Task[Any]]:
        """Start an asyncio task to help speed up this boostable.

        Returns NotReady if we can't make use of a boost currently.
        Returns Exhausted if we're done. This causes the BoostExecutor to stop attempting to provide
        boosts to this Boostable.

        """
        raise NotImplementedError

    async def wait(self) -> None:
        """Wait on executor shutdown, if helpful.

        Waiting if we still have work pending makes executor shutdown more intuitive.
        Boostables don't really make any guarantees about their behaviour here, though.

        """
        pass

    def dequeue(self) -> Union[NotReady, Exhausted, T_co]:
        """Non-blockingly dequeue a result we have ready.

        Returns NotReady if it's not ready to dequeue.
        Returns Exhausted if we're definitely done.

        """
        raise NotImplementedError

    async def blocking_dequeue(self) -> T_co:
        """Dequeue a result, waiting if necessary.

        Raises StopAsyncIteration if exhausted.

        """
        raise NotImplementedError

    def __aiter__(self) -> AsyncIterator[T_co]:
        async def iterator() -> AsyncIterator[T_co]:
            try:
                self.executor.semaphore.release()
                while True:
                    yield await self.blocking_dequeue()
            except StopAsyncIteration:
                pass
            finally:
                await self.executor.semaphore.acquire()

        return iterator()

class MappingBoostable(Boostable[T], Generic[A, T]):
    """Represents a map over an underlying iterable.

    MappingBoostables map an async function over each element of some underlying iterable. To boost
    this operation, we dequeue another element from the underlying iterable and create an asyncio
    task to perform the async function call over that element.

    MappingBoostables also compose; that is, the underlying iterable can be another Boostable. In
    this case, we quickly (aka non-blockingly) check whether the underlying Boostable has an element
    ready. If so, we dequeue it, just as we would with an iterable, if not, we forward the boost we
    were provided to the underlying Boostable.

    MappingBoostables come in two flavours: ordered and unordered. Remember that Boostables are
    async iterables. An OrderedMappingBoostable will yield results corresponding to the order of the
    underlying iterable, whereas an UnorderedMappingBoostable will yield results based on what
    finishes first.

    Note that both kinds of MappingBoostables will, of course, dequeue from the underlying iterable
    in whatever order the underlying provides. This means we'll start tasks in order (but not
    necessarily finish them in order, which is kind of the point).
    """

    buffer: Collection[Awaitable[T]]

    def __init__(
        self,
        func: Callable[[A], Awaitable[T]],
        iterable: BoostUnderlying[A],
        executor: BoostExecutor,
    ) -> None:
        super().__init__(executor)

        if not isinstance(iterable, (Iterator, Boostable)):
            raise ValueError("Underlying iterable must be an Iterator or Boostable")

        async def wrapper(arg: A) -> T:
            async with self.executor.semaphore:
                return await func(arg)

        self.func = wrapper
        self.iterable = iterable

    async def wait(self) -> None:
        if self.buffer:
            await asyncio.wait(self.buffer)

    def provide_boost(self) -> Union[NotReady, Exhausted, asyncio.Task[Any]]:
        if not self.executor.shutdown and len(self.buffer) > 2 * self.executor.concurrency:
            # if we have a lot of stuff ready to go, apply backpressure by not accepting the boost
            # the main effect of this is to reduce memory usage
            # always accept boosts if the executor is shutting down to prevent hangs on misuse
            return NotReady()

        result = dequeue_underlying(self.iterable)
        if isinstance(result, NotReady):
            if isinstance(self.iterable, Boostable):
                # the underlying boostable doesn't have anything ready for us
                # so forward the boost to the underlying boostable
                return self.iterable.provide_boost()
            return result
        if isinstance(result, Exhausted):
            return result

        return self.enqueue(result)

    def enqueue(self, arg: A) -> asyncio.Task[T]:
        """Start and return an asyncio task based on an element from the underlying."""
        raise NotImplementedError

class OrderedMappingBoostable(MappingBoostable[A, T]):
    def __init__(
        self,
        func: Callable[[A], Awaitable[T]],
        iterable: BoostUnderlying[A],
        executor: BoostExecutor,
    ) -> None:
        super().__init__(func, iterable, executor)
        self.buffer: Deque[asyncio.Task[T]] = Deque()

    def enqueue(self, arg: A) -> asyncio.Task[T]:
        task = asyncio.create_task(self.func(arg))
        self.buffer.append(task)
        return task

    def dequeue(self) -> Union[NotReady, T]:
        if not self.buffer or not self.buffer[0].done():
            return NotReady()
        task = self.buffer.popleft()
        return task.result()

    async def blocking_dequeue(self) -> T:
        while True:
            if not self.buffer:
                arg = await blocking_dequeue_underlying(self.iterable)
                self.enqueue(arg)
            ret = self.dequeue()
            if not isinstance(ret, NotReady):
                return ret
            # note that dequeues are racy, so we can't return the result of self.buffer[0] instead,
            # we just take it as a signal that something is likely ready, and loop and try to
            # dequeue
            await self.buffer[0]

class UnorderedMappingBoostable(MappingBoostable[A, T]):
    def __init__(
        self,
        func: Callable[[A], Awaitable[T]],
        iterable: BoostUnderlying[A],
        executor: BoostExecutor,
    ) -> None:
        super().__init__(func, iterable, executor)
        self.buffer: Set[asyncio.Task[T]] = set()
        self.waiter: Optional[asyncio.Future[asyncio.Task[T]]] = None

    def done_callback(self, task: asyncio.Task[T]) -> None:
        if self.waiter and not self.waiter.done():
            self.waiter.set_result(task)

    def enqueue(self, arg: A) -> asyncio.Task[T]:
        task = asyncio.create_task(self.func(arg))
        self.buffer.add(task)
        task.add_done_callback(self.done_callback)
        return task

    def dequeue(self, hint: Optional[asyncio.Task[T]] = None) -> Union[NotReady, T]:
        # hint is a task that we suspect is dequeuable, which allows us to skip the linear check
        # against all outstanding tasks in the happy case.
        if hint is not None and hint in self.buffer and hint.done():
            task = hint
        else:
            try:
                task = next(t for t in self.buffer if t.done())
            except StopIteration:
                return NotReady()
        self.buffer.remove(task)
        return task.result()

    async def blocking_dequeue(self) -> T:
        task = None
        loop = asyncio.get_running_loop()
        while True:
            if not self.buffer:
                arg = await blocking_dequeue_underlying(self.iterable)
                task = self.enqueue(arg)
            ret = self.dequeue(hint=task)
            if not isinstance(ret, NotReady):
                return ret
            # note that dequeues are racy, so the task we get from self.waiter may already have been
            # dequeued. in the happy case, however, it's probably the task we want to return, so we
            # use it as the hint for the next dequeue.
            self.waiter = loop.create_future()
            task = await self.waiter
            self.waiter = None

class FilterBoostable(Boostable[T]):
    def __init__(
        self,
        filter_fn: Optional[Callable[[T], bool]],
        inner: BoostUnderlying[T],
        executor: BoostExecutor,
    ):
        super().__init__(executor)
        self.filter_fn = filter_fn or bool
        self.inner = inner

    def provide_boost(self) -> Union[NotReady, Exhausted, asyncio.Task[Any]]:
        if isinstance(self.inner, Boostable):
            return self.inner.provide_boost()
        return Exhausted()

    def dequeue(self) -> Union[NotReady, Exhausted, T]:
        while True:
            ret = dequeue_underlying(self.inner)
            if isinstance(ret, (NotReady, Exhausted)) or self.filter_fn(ret):
                return ret

    async def blocking_dequeue(self) -> T:
        while True:
            ret = await blocking_dequeue_underlying(self.inner)
            if self.filter_fn(ret):
                return ret

class EnumerateBoostable(Boostable[Tuple[int, T]]):
    def __init__(self, inner: BoostUnderlying[T], executor: BoostExecutor):
        super().__init__(executor)
        self.inner = inner
        self.index = 0

    def provide_boost(self) -> Union[NotReady, Exhausted, asyncio.Task[Any]]:
        if isinstance(self.inner, Boostable):
            return self.inner.provide_boost()
        return Exhausted()

    def dequeue(self) -> Union[NotReady, Exhausted, Tuple[int, T]]:
        inner_ret = dequeue_underlying(self.inner)
        if isinstance(inner_ret, (NotReady, Exhausted)):
            return inner_ret
        ret = (self.index, inner_ret)
        self.index += 1
        return ret

    async def blocking_dequeue(self) -> Tuple[int, T]:
        inner_ret = await blocking_dequeue_underlying(self.inner)
        ret = (self.index, inner_ret)
        self.index += 1
        return ret

class EageriseBoostable(Boostable[T]):
    def __init__(self, iterable: AsyncIterator[T], executor: BoostExecutor) -> None:
        super().__init__(executor)
        self.iterable = iterable
        self.buffer: Deque[asyncio.Task[T]] = Deque()
        self.done: bool = False

        self.waiter_buffer: Optional[asyncio.Future[None]] = None
        self.waiter_backpressure: Optional[asyncio.Future[None]] = None

        self.buffer_task = asyncio.create_task(self.eagerly_buffer())

    def provide_boost(self) -> Union[NotReady, Exhausted, asyncio.Task[Any]]:
        # If we always returned Exhausted, that would cause MappingBoostable to in turn return
        # Exhausted, if it couldn't currently make use of a boost.
        return Exhausted() if self.done else NotReady()

    async def wait(self) -> None:
        await self.buffer_task

    def dequeue(self) -> Union[NotReady, Exhausted, T]:
        if not self.buffer:
            return Exhausted() if self.done else NotReady()

        task = self.buffer.popleft()

        if self.waiter_backpressure:
            self.waiter_backpressure.set_result(None)
            self.waiter_backpressure = None

        return task.result()

    async def blocking_dequeue(self) -> T:
        loop = asyncio.get_running_loop()
        while True:
            ret = self.dequeue()
            if isinstance(ret, Exhausted):
                raise StopAsyncIteration
            if not isinstance(ret, NotReady):
                return ret

            self.waiter_buffer = loop.create_future()
            await self.waiter_buffer

    async def eagerly_buffer(self) -> None:
        loop = asyncio.get_running_loop()
        async with self.executor.semaphore:
            # We can't use async for because we need to preserve exceptions
            it = self.iterable.__aiter__()
            while True:
                # I guess in theory, __anext__ isn't guaranteed to be a coroutine
                # https://github.com/hauntsaninja/boostedblob/pull/12
                task: asyncio.Task[T] = asyncio.create_task(it.__anext__())  # type: ignore [arg-type]
                try:
                    await task
                except StopAsyncIteration:
                    break
                except Exception:
                    pass
                self.buffer.append(task)

                if self.waiter_buffer:
                    self.waiter_buffer.set_result(None)
                    self.waiter_buffer = None

                # apply backpressure
                if not self.executor.shutdown and len(self.buffer) > 10 * self.executor.concurrency:
                    self.executor.semaphore.release()
                    self.waiter_backpressure = loop.create_future()
                    await self.waiter_backpressure
                    await self.executor.semaphore.acquire()

            self.done = True
            if self.waiter_buffer:
                self.waiter_buffer.set_result(None)
                self.waiter_buffer = None

# see docstring of Boostable
BoostUnderlying = Union[Iterator[T], Boostable[T]]

def dequeue_underlying(iterable: BoostUnderlying[T]) -> Union[NotReady, Exhausted, T]:
    """Like ``dequeue``, but abstracts over a BoostUnderlying."""
    if isinstance(iterable, Boostable):
        return iterable.dequeue()
    if isinstance(iterable, Iterator):
        try:
            return next(iterable)
        except StopIteration:
            return Exhausted()
    raise AssertionError

async def blocking_dequeue_underlying(iterable: BoostUnderlying[T]) -> T:
    """Like ``blocking_dequeue``, but abstracts over a BoostUnderlying."""
    if isinstance(iterable, Boostable):
        return await iterable.blocking_dequeue()
    if isinstance(iterable, Iterator):
        try:
            return next(iterable)
        except StopIteration as e:
            raise StopAsyncIteration from e
    raise AssertionError

async def iter_underlying(iterable: BoostUnderlying[T]) -> AsyncIterator[T]:
    """Like ``iter``, but abstracts over a BoostUnderlying."""
    if isinstance(iterable, Boostable):
        async for x in iterable:
            yield x
    elif isinstance(iterable, Iterator):
        for x in iterable:
            yield x
    else:
        raise AssertionError


# -*- coding:utf-8 -*-
import os
from app import create_app
from flask_script import Manager, Server
from flask_migrate import MigrateCommand

from app.models import init_db

app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)

server = Server(host="127.0.0.1", port=5000)
manager.add_command("runserver", server)
manager.add_command('db', MigrateCommand)

# manager.add_option('-c', '--config', dest='config', required=False)

@manager.command
def hello():
    print('hello world')

@manager.option('-n', '--name', dest='name', help='Your name', default='world')
@manager.option('-u', '--url', dest='url', default='zero.brock.fun')
def test(name, url):
    # 'hello world or hello <setting name>'
    print('hello', name)
    print(url)

@manager.command
def init_db_command():
    """Clear existing data and create new tables."""
    init_db()
    print("Initialized the database.")

if __name__ == '__main__':
    manager.run()


# add required folders to Python's search path
import sys
from pathlib import Path
from os.path import dirname, realpath
script_dir = Path(dirname(realpath(__file__)))
module_dir = str(script_dir.parent)
image_dir = str(script_dir.parent.parent)
print(image_dir)
sys.path.insert(0, module_dir + '/modules')
# import modules
import tensorflow as tf
import numpy as np
import armm_ps as ps
import armm_sp as sp
import nnplot as nnp
import integrate as quad
import utility as ut
import dgm

D = 5.0
log_C = tf.math.log( 0.5 * tf.sqrt(D * np.pi**3) * (1.0 + tf.math.erf(1.0/tf.sqrt(D) ) ))
log_2_pi = tf.math.log(2.*np.pi)
print('log_C is {}'.format(log_C))
r = 2.0
space_x = r * np.array([-1., 1.])
space_y = r * np.array([-1., 1.])
time_ = [0.0, 10.0]

#num_components, param_inits = circle_params(25)
num_nodes = 57
num_layers = 5
nn_type = 'LSTM'
model_name = 'cbk_{}_{}'.format(num_nodes, num_layers)

p = dgm.DGM(dim = 3, num_nodes=num_nodes, num_layers = num_layers, regularizer=tf.keras.regularizers.L2(l2=0.01))
p.add_domain([[1e-3, 15.0], space_x, space_y])
#"""
try:
    p.load_weights('saved models/' + model_name).expect_partial()
except:
    pass
#"""
print(p(*p.domain_sampler(0, 5)))
p.summary()

@ut.timer
def diff_op(t, x, y):
    z = 4.0*(x*x + y*y - 1.0)
    with tf.GradientTape() as outer_x, tf.GradientTape() as outer_y:
        outer_x.watch(x)
        outer_y.watch(y)
        with tf.GradientTape() as inner:
            inner.watch([t, x, y])
            p_ = p(t, x, y)
            grad_p = inner.gradient(p_, [t, x, y])
        p_t = grad_p[0]
        p_x = grad_p[1]
        p_y = grad_p[2]
    p_xx = outer_x.gradient(p_x, x)
    p_yy = outer_y.gradient(p_y, y)
    a = (x*z) * p_x
    b = (y*z) * p_y
    return   p_t + a + b - D * (p_xx + p_yy)

# loss functions and domains
p.add_objective(diff_op, mean_square=True)
print(diff_op(*p.domain_sampler(0, 5)))

def init_cond(x, y):
    r2 = x*x + y*y
    log_init_p = -0.5*r2 - log_2_pi
    log_steady_p = -(r2 - 1.0)**2/D - log_C
    t0 = tf.fill(x.shape, time_[0])
    #print(log_init_p, log_steady_p)
    return p(t0, x, y) - tf.exp(log_init_p / log_steady_p)

p.add_objective(init_cond, mean_square=True)
p.add_domain([space_x, space_y])
print(init_cond(*p.domain_sampler(1, 5)))

# create the full solution
class Sol(tf.keras.models.Model):
    def __init__(self):
        super().__init__(dtype=p.dtype)
    def call(self, t, x, y):
        r2 = x*x + y*y
        log_steady_p = -(r2 - 1.0)**2/D - log_C
        return p(t, x, y) * tf.exp(log_steady_p)

P = Sol()

# learn the solution
#print('integral 1: ', quad.monte_carlo(p, [space_x, space_y], time=time_[0]))
p.solve(num_steps = 2000, num_samples = [1000, 1000, 1000], sample_types = ['static', 'dynamic'], initial_rate = 0.001)
plotter = nnp.NNPlotter(funcs=[P], space=[space_x, space_y], num_pts_per_dim=40)
plotter.animate(file_path='../../images/{}.mp4'.format(model_name), t=time_, x_lim=space_x, y_lim=space_y, z_lim=None)
plotter = nnp.NNPlotter(funcs=[p], space=[space_x, space_y], num_pts_per_dim=40)
plotter.animate(file_path='../../images/{}.mp4'.format('nn_' + model_name), t=time_, x_lim=space_x, y_lim=space_y, z_lim=None)
p.save_weights('saved models/' + model_name)
#print('integral 2: ', quad.monte_carlo(p, [space_x, space_y], time=time_[1]))


import urllib.request
from bs4 import BeautifulSoup
import json
cities = json.load('cities.json')
date = '2008/4/18' #YYYY/M/D
f = urllib.request.urlopen("https://wunderground.com/history/airport/" + airport + "/" + date +  "/DailyHistory.html?req_city=" + city + "&req_state=" + state + "&req_statename=" + country + "&reqdb.zip=00000&reqdb.magic=264&reqdb.wmo=43295")
content = f.read()
soup = BeautifulSoup(content)
res = soup.find("table", {"id": "historyTable"})
rows = res.find_all('tr')
data = []
for row in rows:
	cols = row.find_all('td')
	cols = [ele.text.strip() for ele in cols]
	data.append([ele for ele in cols if ele])
i = 0
data = data[1:]
cleaned = []
for row in data:
	if len(row)>=2:
		cleaned.append(row[:2])
for row in cleaned:
	print(row)


from collections import deque

eggs = deque([int(x) for x in input().split(', ')])
paper = deque([int(x) for x in input().split(', ')])
total_boxes = 0

while eggs and paper:

    current_egg = eggs.popleft()

    if current_egg <= 0:
        continue
    if current_egg == 13:
        first_paper = paper.popleft()
        last_paper = paper.pop()
        paper.append(first_paper)
        paper.appendleft(last_paper)
        continue

    current_paper = paper.pop()

    current_sum = current_paper + current_egg

    if current_sum <= 50:
        total_boxes += 1
        continue

if total_boxes > 0:
    print(f"Great! You filled {total_boxes} boxes.")
else:
    print("Sorry! You couldn't fill any boxes!")

if eggs:
    print(f"Eggs left: {', '.join([str(x) for x in eggs])}")

if paper:
    print(f"Pieces of paper left: {', '.join([str(x) for x in paper])}")


#!/usr/bin/env python
'''
Bruno Sanchez Garcia				A01378960
Carlos Antonio Pazos Reyes 			A01378262
Manuel Agustin Diaz Vivanco		    A01379673

Nodo para calcular y publicar la posicion ideal del robot
es decir sin ruido.
A la par, toma los datos del simulador en gazebo y publica
su transformacion en rviz para mover el robot en las mismas
posiciones.
'''
import rospy
import numpy as np
from std_msgs.msg import Float32
from sensor_msgs.msg import JointState
from geometry_msgs.msg import PoseStamped, Twist, Point, Quaternion, Point
from gazebo_msgs.msg import ModelStates
from std_srvs.srv import Empty, EmptyResponse
import tf

class Odometry_nonholonomic_robot():

    def __init__(self):
        rospy.init_node("challenge1")
        self.t0 = rospy.Time.now() # node initial time
        self.x_k = 0.0  # -0.955           # initial gazebo state to sync in rviz
        self.y_k = 0.0  # 0.753
        self.th_k = 0.0 # -1.57
        self.V = 0.0                # variables to receive cmd_vel
        self.w = 0.0
        self.tb = tf.TransformBroadcaster() # to move/update robot in rviz
        self.F = 120.0                      # frequency
        self.rate = rospy.Rate(self.F)
        self.T = float(1/self.F)            # sample time
        cmd_sub = rospy.Subscriber('/cmd_vel', Twist, self.cmd_vel_callback)
        gazebo_pos_sub = rospy.Subscriber('/gazebo/model_states',ModelStates,self.gazebo_pose_callback)
        self.odom = rospy.Publisher('/pose_sim', PoseStamped, queue_size=10)
        self.ser = rospy.Service("/reset", Empty, self.callback_ser)
        self.Wl = rospy.Publisher('/rviz/wl', Float32, queue_size=10)
        self.Wr = rospy.Publisher('/rviz/wr', Float32, queue_size=10)
        self.pJS = rospy.Publisher('/joint_states', JointState, queue_size=10)
        self.r = 0.05           # robot radius
        self.l = 0.188          # distance between wheels
        self.pose_stamped = PoseStamped()   # msg of ideal robot state
        self.frame_id = 'base_link'         # frame robot base
        self.js = JointState()              # publish to update wheel movement
        self.js.name = ["right_wheel_joint", "left_wheel_joint"] # wheel joints
        self.gazebo_x = 0.0                 # variables to receive gazebo state
        self.gazebo_y = 0.0
        self.gazebo_q = [0.0,0.0,0.0,0.0]

    def gazebo_pose_callback(self,msg):
        # in list [track,ground,puzzlebot]
        self.gazebo_x = msg.pose[-1].position.x         # receive gazebe state
        self.gazebo_y = msg.pose[-1].position.y
        self.gazebo_q[0] = msg.pose[-1].orientation.x
        self.gazebo_q[1] = msg.pose[-1].orientation.y
        self.gazebo_q[2] = msg.pose[-1].orientation.z
        self.gazebo_q[3] = msg.pose[-1].orientation.w

    def callback_ser(self,req):
        self.x_k = 0.0              # service to reset simulation
        self.y_k = 0.0
        self.th_k = 0.0
        time_stamp = rospy.Time.now()
        Q = tf.transformations.quaternion_from_euler(0, 0, self.th_k)
        self.tb.sendTransform([self.x_k, self.y_k ,0], Q, time_stamp, "base_link", "map")
        return EmptyResponse()

    def cmd_vel_callback(self,msg):
        self.V = msg.linear.x       # receive cmd_vel velocities
        self.w = msg.angular.z

    def Odometry_w_error(self):
        alpha_k = 0.0               # robot with no noise
        # alpha_k = np.random.normal(0.0, 0.5)
        x_k1 = self.x_k + (self.T *(self.V + alpha_k))* np.cos(self.th_k)   # update x
        y_k1 = self.y_k + (self.T *(self.V + alpha_k))* np.sin(self.th_k)   # update y
        th_k1 = self.th_k + (self.T *(self.w + alpha_k))                    # update yaw
        Q = tf.transformations.quaternion_from_euler(0, 0, th_k1)   # get orientation quaternion
        time_stamp = rospy.Time.now()
        self.pose_stamped.header.stamp = time_stamp     # time stamp
        self.pose_stamped.header.frame_id = self.frame_id   # same frame base_link
        self.pose_stamped.pose.position = Point(x_k1, y_k1, 0.0)    # build position
        self.pose_stamped.pose.orientation = Quaternion(Q[0],Q[1],Q[2],Q[3])    # build orientation
        self.odom.publish(self.pose_stamped)            # publish state
        wl = (self.V - 0.5 * self.l * self. w)/self.r   # get right wheel angular speed
        self.Wl.publish(wl)
        wr = (self.V + 0.5 * self.l * self.w)/self.r    # get left wheel angular speed
        self.Wr.publish(wr)

        self.tb.sendTransform([ self.gazebo_x,      # send transform tu update rviz
                                self.gazebo_y,0],
                                self.gazebo_q,
                                time_stamp, "base_link", "map")

        t = time_stamp - self.t0        # time to update wheel movement
        self.js.position = [wr * t.to_sec(), wl * t.to_sec()]   # calculation to move wheels
        self.js.header.stamp = time_stamp
        self.pJS.publish(self.js)       # update wheel movement in rviz

        self.x_k = x_k1         # update state for next iteration
        self.y_k = y_k1
        self.th_k = th_k1

        print(self.pose_stamped)

    def main(self):
        while not rospy.is_shutdown():
            try:
                self.Odometry_w_error()
            except Exception as e :
                print(e)
            self.rate.sleep()

if __name__ == '__main__':
    try:
        challenge = Odometry_nonholonomic_robot()
        challenge.main()
        print("exiting main")

    except (rospy.ROSInterruptException, rospy.ROSException):
        print("topic was closed during publish")


import asyncio
import socket
import weakref
import errno
import random
import struct
import time

from . import rr
from .constants import *
from .utils import decode_domain, decode_pascal_string, rcode_to_string, \
    build_dns_packet, MAX_PACKET_SIZE
from .wireformat import *
from .timeout import Timeout
from .resolver import Query, Reply

TIMEOUT   = 5
MAX_TRIES = 5
MAX_TTL   = 3 * 3600

class MDNSQuery(object):
    """Represents an active MDNS query."""

    def __init__(self, resolver, protocol, query, use_ipv6, unicast_reply):
        self.resolver = weakref.ref(resolver)
        self.protocol = weakref.ref(protocol)
        self.query = query
        self.use_ipv6 = use_ipv6
        self.unicast_reply = unicast_reply

        self._retry_count = 0
        self._waiters = []
        self._timeout = None

    def set_timeout(self, timeout):
        self.cancel_timeout()
        self._timeout = Timeout(timeout, self.timed_out)

    def cancel_timeout(self):
        if self._timeout is not None:
            self._timeout.cancel()
            self._timeout = None

    def timed_out(self):
        self.retry()

    def add_waiter(self, f):
        self._waiters.append(f)

    def fire_waiters(self, reply):
        self.cancel_timeout()
        for f in self._waiters:
            f.set_result(reply)
        self.resolver().query_done(self)

    def cancel_waiters(self):
        self.cancel_timeout()
        for f in self._waiters:
            f.cancel()
        self.resolver().query_done(self)

    def fail_waiters(self, exc):
        self.cancel_timeout()
        for f in self._waiters:
            f.set_exception(exc)
        self.resolver().query_done(self)

    def retry(self):
        self.cancel_timeout()

        self._retry_count += 1
        if self._retry_count >= MAX_TRIES:
            self.fire_waiters(Reply(QR, NXDOMAIN, [], [], []))
            return

        self.set_timeout(TIMEOUT)

        packet = build_dns_packet(0, self.query, False, True)

        if len(packet) > MAX_PACKET_SIZE:
            del packet
            self.fail_waiters(OSError(errno.ETOOBIG))

        self.protocol().send_packet(packet, self.use_ipv6)

_rng = random.SystemRandom()

class MulticastResolver(object):
    """Resolves queries using Multicast DNS (aka MDNS, aka Bonjour)."""

    def __init__(self):
        self._cache = {}
        self._queries = {}
        self._queue = []
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        #self._socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)

        # Bind this socket - we need to do this on Windows or we get an
        # exception inside asyncio because it tries to use getsockname().
        while True:
            port = _rng.randrange(1024, 65536)
            try:
                self._socket.bind(('0.0.0.0', port))
                break
            except OSError as e:
                if e.errno not in (errno.EADDRINUSE, EADDRNOTAVAIL):
                    raise

        ip_mreq = b'\xe0\x00\x00\xfb\x00\x00\x00\x00'
        self._socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
                                ip_mreq)
        self.transport = None
        loop = asyncio.get_event_loop()
        f = asyncio.ensure_future(loop.create_datagram_endpoint(lambda: self,
                                                                sock=self._socket))

        def callback(f):
            if f.cancelled():
                self.cancel_all_waiters()
                return

            exc = f.exception()
            if exc is not None:
                self.fail_all_waiters(exc)
                return

        f.add_done_callback(callback)

    def close(self):
        self.cancel_all_waiters()
        self.transport.abort()

    def __del__(self):
        # On Windows, we can get a (harmless) RuntimeError here from trying
        # to abort the transport after the event loop has finished.
        try:
            self.close()
        except RuntimeError:
            pass

    def connection_made(self, transport):
        self.transport = transport
        for item in self._queue:
            transport.sendto(item[0], addr=item[1])
        self._queue = []

    def connection_lost(self, exc):
        if exc is not None:
            self.fail_all_waiters(exc)

    def datagram_received(self, data, addr):
        try:
            self.process_packet(data)
        except:
            pass

    def cancel_all_waiters(self):
        for q in self._queries.values():
            q.cancel_waiters()
        self._queries = {}

    def fail_all_waiters(self, exc):
        for q in self._queries.values():
            q.fail_waiters(exc)
        self._queries = {}

    def check_domain(self, query):
        for label in query.name.split(b'.'):
            if len(label) > 63:
                raise ValueError('DNS label too long')

    def lookup(self, query, use_ipv6=False, unicast_reply=False):
        """Perform an MDNS query."""
        f = asyncio.Future()

        # First see if the result is in the cache - if so, return it
        r = self._cache.get(query, None)
        if r is not None:
            (expiry, reply) = r

            now = time.time()

            if now >= expiry:
                del _cache[query]
            else:
                ttl_ms = expiry - now
                ttl_s = (ttl_ms + 999) / 1000

                reply.update_ttls(ttl_s)

                f.set_result(reply)

                return f

        # Add this future to the list waiting on this query
        r = self._queries.get(query, None)
        if r:
            r.add_waiter(f)
            return f

        # Finally, fire off a new query
        self.check_domain(query)

        new_query = MDNSQuery(self, self, query, use_ipv6, unicast_reply)
        self._queries[query] = new_query
        new_query.add_waiter(f)
        new_query.retry()

        return f

    def query_done(self, query):
        del self._queries[query.query]

    def flush_cache(self):
        self._cache = {}

    def cache_reply(self, query, reply):
        now = time.time()
        has_ttl = False
        min_ttl = 0

        # Find the minimum ttl
        for collection in (reply.answers, reply.authorities, reply.additional):
            for rr in collection:
                ttl = rr.ttl
                if not has_ttl or min_ttl > ttl:
                    has_ttl = True
                    min_ttl = ttl

        # Can't cache things with no TTL or with TTL zero
        if not has_ttl:
            return

        if min_ttl > MAX_TTL:
            min_ttl = MAX_TTL

        self._cache[query] = (now + min_ttl, reply)

    def decode_rr(self, packet, ptr, rcode):
        name, ptr = decode_domain(packet, ptr)

        utype, uclss, ttl, rdlen = struct.unpack(b'>HHLH', packet[ptr:ptr+10])

        ptr += 10

        if utype == OPT:
            rcode |= (ttl >> 20) & 0xff0
            ptr += rdlen
            return (rcode, None, None)

        result = rr.RR.decode(name, utype, uclss, ttl, packet, ptr, rdlen)
        ptr += rdlen

        return (rcode, result, ptr)

    def send_packet(self, packet, use_ipv6=False):
        if use_ipv6:
            addr = ('ff02::fb', 5353)
        else:
            addr = ('224.0.0.251', 5353)

        if self.transport is None:
            self._queue.append((packet, addr))
        else:
            self.transport.sendto(packet, addr=addr)

    def process_packet(self, packet):
        # Decode the header
        uid, flags, qdcount, ancount, nscount, arcount \
            = struct.unpack(b'>HHHHHH', packet[:12])

        # Ignore things other than queries
        if (flags & OPCODE_MASK) != QUERY:
            return

        # Find the rcode
        rcode = flags & RCODE_MASK

        # Ignore anything other than NOERROR
        if rcode != NOERROR:
            return

        # Decode the query
        domain, ptr = decode_domain(packet, 12)

        qtype, qclss = struct.unpack(b'>HH', packet[ptr:ptr+4])
        ptr += 4

        q = Query(domain, qtype, qclss)

        # Look for the query
        found_query = None
        found_mq = None
        for fq,p in self._queries.items():
            if fq == q:
                print('Found')
                found_query = fq
                found_mq = p
                break

        # Decode the reply
        answers = []
        authorities = []
        additional = []

        for count, array in [(ancount, answers),
                             (nscount, authorities),
                             (arcount, additional)]:
            for n in range(0, count):
                rcode, rr, ptr = self.decode_rr(packet, ptr, rcode)
                if rr is not None:
                    array.append(rr)

            reply = Reply(flags,
                          rcode,
                          answers,
                          authorities,
                          additional)

        # For each answer, see if we can find a query that matches
        for answer in answers:
            for fq,p in self._queries.items():
                if fq.name.lower() == answer.name.lower() \
                   and (fq.q_type == ANY or fq.q_type == answer.rr_type) \
                   and (fq.q_class == ANY or fq.q_class == answer.rr_class):
                    self.cache_reply(fq, reply)
                    p.fire_waiters(reply)


# =============================================
# -*- coding: utf-8 -*-
# @Time    : 2020/4/26 6:39 下午
# @Author  : xiao9616
# @Email   : 749935253@qq.com
# @File    : util.py
# @Software: PyCharm
# ============================================
import numpy as np
import os
import glob

root = os.path.dirname(__file__)
ann_dir = os.path.join(root, "data", "ann", "*xml")
ann_fname = glob.glob(ann_dir)

def generator(batch_size, classes, ann_fname):
    pattern_shape = [52, 26, 13]
    anchor_shape = [3, 3]

    n = len(ann_fname)
    i = 0
    while True:
        inputs = []

        y_true = [np.zeros((batch_size, pattern_shape[i], pattern_shape[i], anchor_shape[1], 5 + len(classes))) for i in
                  range(anchor_shape[0])]
        for b in range(batch_size):
            if i == 0:
                np.random.shuffle(ann_fname)
            fname, label, boxes = get_parse(ann_fnames[i])

            i = (i + 1) % n

        yield inputs, y_true


import unittest
import numpy as np

import equation

class EquationTestCase(unittest.TestCase):
    def test_discretizeEquation(self):
        points, faces = equation.discretizeEquation('x+y', xlim=1, ylim=1, nodeCount=3)
        actualPoints = np.array([
            [-1, -1, -2],
            [-1, 0, -1],
            [-1, 1, 0],
            [0, -1, -1],
            [0, 0, 0],
            [0, 1, 1],
            [1, -1, 0],
            [1, 0, 1],
            [1, 1, 2],
        ], dtype=float)
        self.assertTrue(np.allclose(points, actualPoints))
        print(faces)
        actualFaces = np.array([
            [0, 1, 4],
            [0, 4, 3],
            [3, 4, 7],
            [3, 7, 6],
            [1, 2, 5],
            [1, 5, 4],
            [4, 5, 8],
            [4, 8, 7],
        ])
        self.assertTrue(np.allclose(faces, actualFaces))


####################################################################################################
# axis location to pixel
####################################################################################################

def coordinate_to_pixel(fitsimage, axis, coordinates, precision=2):
    """
    Calculate the pixel positions corresponding to a given coordinate along an
    axis of an fits image.

    Parameters
    ----------
    fitsimage : string or PrimaryHDU
        File name of a fits image or astropy.fits PrimaryHDU object.
    axis : int
        Axis number. No default.
    coordinates : astropy.Quantity or Quantity list
        The coordinates to be converted in the same unit as the header axis unit.
    precision : int
        Precision  of the return pixel position. Defaults to two decimal places.

    Returns
    -------
    astropy.Quantity or Quantity list
        Single value or list of pixel position corresponding to the given coordinates.

    """

    import numpy as np
    import astropy.units as u
    from astropy.io import fits

    if isinstance(fitsimage, str):
        header = fits.getheader(fitsimage)
    elif isinstance(fitsimage, fits.hdu.image.PrimaryHDU):
        header = fitsimage.header
    else:
        raise TypeError("Unknown format for fitsimage. Must be filename or HDUList.")

    crpix = header['crpix'+str(axis)]*u.pix
    crval = u.Quantity(str(header['crval'+str(axis)])+header['cunit'+str(axis)])
    cdelt = u.Quantity(str(header['cdelt'+str(axis)])+header['cunit'+str(axis)])/u.pix
    naxis = header['naxis'+str(axis)]

    if not coordinates.unit==crval.unit:
        raise TypeError("Header unit is "+str(crval.unit)+". Use matching unit.")

    return np.round((coordinates-crval)/cdelt+crpix, precision)

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


from PySide2.QtCore import QCoreApplication  #, Signal, Slot
from PySide2.QtWidgets import QComboBox
from betse.util.io.log import logs
from betse.util.type.iterable import iterables, itertest
from betse.util.type.types import (
    type_check,
    GeneratorType,
    SequenceTypes,
    SequenceOrNoneTypes,
    SequenceStandardTypes,
)
# from betsee.guiexception import BetseePySideComboBoxException
from betsee.guiexception import BetseePySideComboBoxException
from betsee.util.widget.mixin.guiwdgeditmixin import QBetseeEditWidgetMixin

# ....................{ SUBCLASSES                        }....................
class QBetseeComboBox(QBetseeEditWidgetMixin, QComboBox):
    '''
    General-purpose :mod:`QComboBox` widget implementing a Pythonic API.

    Caveats
    ----------
    To guarantee a one-to-one correspondence between the currently selected
    combo box item and the underlying model constraining these items, this
    combo box defaults to:

    * **Non-editability** (i.e., the text of each item is *not* interactively
      editable by end users).
    * **Uniqueness** (i.e., the text of each item is unique and hence differs
      from the text of each other item).

    Attributes
    ----------
    _is_items_added : bool
        ``True`` only if the :meth:`addItems` method has been previously
        called, implying this combo box to have been populated with one or more
        icon-less items.
    '''

    # ..................{ INITIALIZERS                      }..................
    def __init__(self, *args, **kwargs) -> None:

        # Initialize our superclass with all passed arguments.
        super().__init__(*args, **kwargs)

        # Nullify all instance variables for safety.
        self._is_items_added = False

        # Disable editability, preventing users from manually editing item
        # text. While our superclass already disables editability by default,
        # this is sufficiently vital to warrant doing so explicitly.
        self.setEditable(False)

        # Disable duplicability, preventing users from manually duplicating
        # text across multiple items. Since editability is already disabled by
        # default, this admittedly produces no effect. *shrug*
        self.setDuplicatesEnabled(False)

    @type_check
    def _init_safe(
        self, items_iconless_text: SequenceOrNoneTypes = None, *args, **kwargs
    ) -> None:
        '''
        Finalize the initialization of this widget.

        Parameters
        ----------
        items_iconless_text : SequenceOrNoneTypes
            Sequence of **icon-less item text** (i.e., human-readable text of
            every initial combo box item *without* corresponding icons) to
            prepopulate this combo box with. Defaults to ``None``, in which
            case this combo box initially contains no items and is thus empty.

        All remaining parameters are passed as is to the superclass method.
        '''

        # Finalize the initialization of our superclass.
        super()._init_safe(*args, **kwargs)

        # Log this finalization.
        logs.log_debug('Initializing combo box "%s"...', self.obj_name)

        # If prepopulating this combo box with icon-less items...
        if items_iconless_text is not None:
            # Remove all items previously added to this combo box *BEFORE*
            # adding these items back to this combo box. If *NOT* done, the
            # subsequent call to the add_items_iconless() method would
            # correctly raise an exception on detecting an attempt to add
            # duplicate items to this combo box.
            self.clear()

            # Prepopulating this combo box with these icon-less items.
            self.add_items_iconless(items_iconless_text)

    # ..................{ EXCEPTIONS                        }..................
    def _die_unless_items_added(self) -> None:
        '''
        Raise an exception unless the :meth:`addItems` method has been
        previously called (i.e., unless this combo box has already been
        populated with one or more icon-less items).

        Equivalently, this method raises an exception if the :meth:`addItems`
        method has *not* been previously called.

        Raises
        ----------
        BetseePySideComboBoxException
            if the :meth:`addItems` method has *not* been previously called.
        '''

        # If the addItems() method has *NOT* been called, raise an exception.
        if not self._is_items_added:
            raise BetseePySideComboBoxException(QCoreApplication.translate(
                'QBetseeComboBox',
                'Combo box unpopulated (i.e., addItems() not called).'))

    # ..................{ SUPERCLASS                        }..................
    # Superclass methods overridden to define the "_is_items_added" boolean.

    def addItems(self, items_text: SequenceTypes) -> None:

        # Defer to the superclass implementation first.
        super().addItems(items_text)

        # Note this method to now have been called.
        self._is_items_added = True

    def clear(self) -> None:

        # Defer to the superclass implementation first.
        super().clear()

        # Note the addItems() method to now have effectively *NOT* been called.
        self._is_items_added = False

    # ..................{ ADDERS                            }..................
    @type_check
    def add_items_iconless(self, items_text: SequenceTypes) -> None:
        '''
        Add **icon-less items** (i.e., plaintext combo box items with *no*
        corresponding icons) specified by the passed human-readable strings to
        this combo box after the index of this combo box defined by the
        :meth:`insertPolicy` property, defaulting to appending these items
        *after* any existing items of this combo box.

        Specifically, for each element of this sequence, this method adds a new
        combo box item whose human-readable text is that element.

        Parameters
        ----------
        items_text : SequenceTypes
            Sequence of the text of each item to be added to this combo box.
        '''

        # Log this addition.
        logs.log_debug(
            'Adding %d items to combo box "%s"...',
            len(items_text), self.obj_name)

        # Tuple aggregating both the passed and existing iterables of combo
        # box item text, optimizing the subsequent validation of uniqueness.
        items_all_text = tuple(iterables.iter_items(
            items_text, self.iter_items_text()))

        # If at least one combo box item text of the passed iterable duplicates
        # other combo box item text of either the passed or existing iterables
        # of such text, raise an exception.
        #
        # Note that this constraint *MUST* be validated explicitly, as the
        # stock "QComboBox" superclass provides no such validation. Notably,
        # official documentation for the seemingly relevant (but ultimately
        # irrelevant) "duplicatesEnabled" property reads:
        #
        #    Note that it is always possible to programmatically insert
        #    duplicate items into the combobox.
        itertest.die_unless_items_unique(items_all_text)

        # If the passed sequence is neither a standard "list" nor "tuple",
        # coerce this sequence into the latter. Why? Because inadequacies in
        # the Qt API inherited by PySide2.
        #
        # Consider a view of ordered dictionary values (i.e., instance of the
        # "collections.abc.ValuesView" interface instantiated and returned by
        # the OrderedDict.values() method). This view is a valid sequence. In
        # theory, the QComboBox.addItems() method passed this sequence should
        # technically accept this view *WITHOUT* requiring explicit coercion
        # into a tuple. It does not, raising the following exception on
        # attempting to do so:
        #
        #    TypeError: 'PySide2.QtWidgets.QComboBox.addItems' called with wrong argument types:
        #      PySide2.QtWidgets.QComboBox.addItems(ValuesView)
        #    Supported signatures:
        #      PySide2.QtWidgets.QComboBox.addItems(QStringList)
        #
        # Presumably, the underlying bindings generator (i.e., Shiboken2) only
        # implicitly coerces tuples and lists into "QStringList" instances.
        # Curiously, generic sequences appear to remain unsupported.
        if not isinstance(items_text, SequenceStandardTypes):
            items_text = tuple(items_text)

        # Add these icon-less items to this combo box.
        self.addItems(items_text)

    # ..................{ ITERATORS                         }..................
    @type_check
    def iter_items_text(self) -> GeneratorType:
        '''
        Generator iteratively yielding the human-readable text associated with
        each item of this combo box.

        Yields
        ----------
        str
            Human-readable text associated with the currently iterated item of
            this combo box.
        '''

        # Return a generator comprehension yielding...
        return (
            # The text associated with this item...
            self.itemText(item_index)
            # For the 0-based index of each item of this combo box.
            for item_index in range(self.count())
        )


import requests
from bs4 import BeautifulSoup
import String_Parser as strp

class Web_Scraper:

    URL_BASE = "https://www.azlyrics.com/"

    def __init__(self, artist, writers):
        self.artist = artist
        self.writers = [writer.lower() for writer in writers]
        self.artist_query = Web_Scraper.create_artist_query(artist)
        self.lyrics_query = Web_Scraper.create_lyrics_query(artist)
        self.current_page = None
        pass

    @staticmethod
    def create_artist_query(artist):
        artist_query = strp.convert_string_to_query(artist)
        return artist_query[0] + "/" + artist_query + ".html"

    @staticmethod
    def create_lyrics_query(artist):
        artist_query = strp.convert_string_to_query(artist)
        return "lyrics/" + artist_query + "/.html"

    def get_response(self, song=None):
        URL = None
        if song == None:
            URL = self.URL_BASE + self.artist_query
        else:
            song = strp.convert_string_to_query(song)
            print(song)
            index = self.lyrics_query.index(".html")
            song_query = self.lyrics_query[0:index] + song + ".html"
            URL = self.URL_BASE + song_query
        page = requests.get(URL)
        return BeautifulSoup(page.content, "html.parser")

    def get_songs(self):
        page_content = self.get_response()
        song_container = page_content.find(id="listAlbum")
        song_results = song_container.find_all("div", class_="listalbum-item")
        songs = list()
        for song in song_results:
            title = song.find_all("a")
            songs.append(title[0].text)
        return songs

    def get_lyrics(self, song):
        page_content = self.get_response(song)
        lyrics_container = page_content.find_all("div", class_="container main-page")[0]
        lyrics_response = lyrics_container.text
        self.current_page = lyrics_response

        if self.has_correct_writers():
            return self.extract_lyrics_from_html(lyrics_response, song)
        return -1

    def extract_lyrics_from_html(self, response, song):
        first_index = response.index("\"" + song + "\"\n") + len(song) + 2
        last_index = response.index("Submit Corrections")
        lyrics = response[first_index:last_index]

        first_index = strp.index_letter(lyrics)
        last_index = strp.rindex_letter(lyrics)+1
        return lyrics[first_index:last_index]

    def extract_album(self, song, album_content=None):
        if self.current_page == None:
            page_content = self.get_response(song)
            lyrics_container = page_content.find_all("div", class_="container main-page")[0]
            self.current_page = lyrics_container.text
        if album_content == None:
            album_content = self.get_album_content()

        if album_content != -1:
            first_quote = album_content.index("\"")
            album = album_content[first_quote+1:len(album_content)]
            return album[0:album.index("\"")]
        return "N/A"

    def extract_release_date(self, song):
        if self.current_page == None:
            self.current_page = self.get_response(song)
        album_content = self.get_album_content()

        if album_content != -1:
            album = self.extract_album(song, album_content=album_content)
            album_index = album_content.index(album)
            temp = album_content[album_index+len(album)+1:len(album_content)]
            return temp[temp.index("(")+1:temp.index(")")]
        return "N/A"

    def get_album_content(self):
        album_index = self.current_page.find('album:')
        if album_index > -1:
            return self.current_page[album_index:len(self.current_page)]
        return -1

    def has_correct_writers(self):
        page_content = self.current_page
        writer_index = page_content.find("Writer(s):")
        if writer_index > -1:
            temp = page_content[writer_index:len(page_content)]
            temp = temp[temp.index(" ")+1:temp.index("\n")]
            writers = temp.split(", ")
            for writer in writers:
                if writer.lower() in self.writers:
                    return True
        return False

    def remove_duplicate_songs(self):
        # Check for duplicate songs
        # Remove non-Taylor Swift Original Songs using the writers section on the lyrics tab
        pass