#! /usr/bin/env python

def solution(prices, money):
    prices = [i for i in prices if i < money]
    if len(prices) < 2:
        return money
    prices.sort()
    res = []
    for i in range(len(prices)-1):
        left = money - prices[i]
        del prices[i]
        res = [i for i in prices if left-i >= 0]
        if len(res) == 0:
            return money
        for j in res:
            if left-j >= 0:
                return left-j

print(solution([1,2,2], 3))
print(solution([3,2,3], 3))


# Team work
# Peizeng Kang
# Jinxian Cheng
import numpy as np
import matplotlib.pyplot as plt
from sklearn import svm
from scipy import io

def main():
    data = io.loadmat('./data.mat')
    train_X = data["X"][:150, :]
    train_y = data["Y"][:150, :]
    test_X = data["X"][150:, :]
    test_y = data["Y"][150:, :]

    para_c =  [1e-4, 1e-3, 1e-2, 1e-1, 1, 10, 100, 200]
    kernel_func = ['linear', 'poly', 'rbf', 'sigmoid']
    tot = []
    for i in kernel_func:
        func_with_diff_c = []
        for j in para_c:
            svm_svc = svm.SVC(C=j, kernel=i)
            svm_svc.fit(train_X, train_y.ravel())
            func_with_diff_c.append(len(svm_svc.support_vectors_))
        tot.append(func_with_diff_c)

    plt.plot(para_c, tot[0], label=kernel_func[0], color="blue")
    plt.plot(para_c, tot[1], label=kernel_func[1], color="yellow")
    plt.plot(para_c, tot[2], label=kernel_func[2], color="red")
    plt.plot(para_c, tot[3], label=kernel_func[3], color="green")
    plt.xlabel("C value")
    plt.ylabel("Support Vector Number")
    plt.legend()
    plt.grid(True)
    plt.show()

    # Question on 4
    # C is the regularization parameter which is L2 penalty.
    # It must be greater than 0. It means once the number of
    # c is greater, the penalty for those misclassify points
    # is greater then the boundary is more thinner. In our
    # graph, it was shown than the number of support_vector
    # decrease.
    # For the same C number, penalty aparameter, the different
    # kernel function have different number of support vectors
    # at C = 25, the sequence of support vector number is
    # "rbf" > "poly" > "sigmoid" > "linear".
    # When C = 100, the sequence is "poly" > "rbf" > "linear" > "sigmoid"

if __name__ == "__main__":
    main()


#!/usr/bin/python3
"""
This is the 3-say_my_name.py module
"""

def say_my_name(first_name, last_name=""):
    """
    prints My name is <first name> <last name>

    Args:
        first_name (str): str argument
        last_name (str, optional): str argument. Defaults to "".
    """
    if not isinstance(first_name, str):
        raise TypeError("first_name must be a string")
    if not isinstance(last_name, str):
        raise TypeError("last_name must be a string")
    if type(first_name) is str and type(last_name) is str:
        print("My name is {} {}".format(first_name, last_name))


import graphene
from models import Person

class CreatePerson(graphene.Mutation):
    class Arguments:
        name = graphene.String()
        age = graphene.Int()

    person = graphene.Field(Person)

    async def mutate(self, info, name, age):
        request = info.context["request"]
        doc = request.state.db.users.insert(
            {
                'name': name,
                'age': age
            }
        )
        print(doc)
        person = Person(name=name, age=age)

        return CreatePerson(person=person)

class UpdatePerson(graphene.Mutation):
    class Arguments:
        name = graphene.String()
        age = graphene.Int()

    person = graphene.Field(Person)

    async def mutate(self, info, name, age):
        request = info.context['request']
        doc = request.state.db.users
        doc.update_one({'name': name}, {'$set': {'age': age}})
        person = Person(name=name, age=age)

        return UpdatePerson(person=person)

class DeletePerson(graphene.Mutation):
    class Arguments:
        name = graphene.String()

    person = graphene.Field(Person)

    async def mutate(self, info, name):
        request = info.context['request']
        documents = request.state.db.users

        doc = documents.find_one_and_delete({
            'name': name
        })
        person = Person(name=name, age=doc['age'])
        return DeletePerson(person=person)

class Mutations(graphene.ObjectType):
    create_person = CreatePerson.Field()
    update_person = UpdatePerson.Field()
    delete_person = DeletePerson.Field()


import time, os, random
from torchvision import transforms
import torchvision.transforms.functional as F

class MyRandomResizeTransform(transforms.RandomResizedCrop):
    ACTIVE_SIZE = 224
    IMAGE_SIZE_LIST = [224]

    CONTINUOUS = False
    SYNC_DISTRIBUTED = False

    EPOCH = 0
    # __init__(self, size, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=2)
    def __call__(self, img):
        # i, j, h, w = self.get_params(img, self.scale, self.ratio)
        return F.resize(img, [MyRandomResizeTransform.ACTIVE_SIZE, MyRandomResizeTransform.ACTIVE_SIZE])

    @staticmethod
    def get_candidate_image_size():
        if MyRandomResizeTransform.CONTINUOUS:
            min_size = min(MyRandomResizeTransform.IMAGE_SIZE_LIST)
            max_size = max(MyRandomResizeTransform.IMAGE_SIZE_LIST)
            candidate_sizes = []
            for i in range(min_size, max_size + 1):
                if i % 4 == 0:
                    candidate_sizes.append(i)
        else:
            candidate_sizes = MyRandomResizeTransform.IMAGE_SIZE_LIST

        relative_probs = None
        return candidate_sizes, relative_probs

    @staticmethod
    def sample_image_size(batch_id):
        if MyRandomResizeTransform.SYNC_DISTRIBUTED:
            _seed = int('%d%.3d' % (batch_id, MyRandomResizeTransform.EPOCH))
        else:
            _seed = os.getpid() + time.time()
        random.seed(_seed)
        candidate_sizes, relative_probs = MyRandomResizeTransform.get_candidate_image_size()
        MyRandomResizeTransform.ACTIVE_SIZE = random.choices(candidate_sizes, weights=relative_probs)[0]

class MyDeterministicResizeTransform(transforms.RandomResizedCrop):
    # __init__(self, size, scale=(0.08, 1.0), ratio=(0.75, 1.3333333333333333), interpolation=2)
    def __call__(self, img):
        # i, j, h, w = self.get_params(img, self.scale, self.ratio)
        return F.resize(img, self.size)


"""
Two positive integers N and M are given. Integer N represents the number of chocolates arranged in a circle, numbered from 0 to N − 1.

You start to eat the chocolates. After eating a chocolate you leave only a wrapper.

You begin with eating chocolate number 0. Then you omit the next M − 1 chocolates or wrappers on the circle, and eat the following one.

More precisely, if you ate chocolate number X, then you will next eat the chocolate with number (X + M) modulo N (remainder of division).

You stop eating when you encounter an empty wrapper.

For example, given integers N = 10 and M = 4. You will eat the following chocolates: 0, 4, 8, 2, 6.

The goal is to count the number of chocolates that you will eat, following the above rules.

Write a function:

def solution(N, M)

that, given two positive integers N and M, returns the number of chocolates that you will eat.

For example, given integers N = 10 and M = 4. the function should return 5, as explained above.

Assume that:

N and M are integers within the range [1..1,000,000,000].
Complexity:

expected worst-case time complexity is O(log(N+M));
expected worst-case space complexity is O(log(N+M)).
"""

# https://app.codility.com/demo/results/trainingPU9WRV-757/
# Not good performance
def solution(N,M):

	wrap = [0] * N
	count = 0
	i = 0
	while wrap[i] == 0:
		# We eat this candy
		wrap[i] = 1
		count += 1
		# move to the next one
		i = (i+M) % N
		print('Eat: ' + str(i) + ' wraps: ' + str(wrap))

	return count

def solution(N,M):

	# We start eating the first candy
	start_eating = 0
	count = 0

	while True:
		# we eat the follwing candies.
		# Remember we ate one already
		count += 1 + ( (N - start_eating - 1) // M)
		# Some are left at the end
		left_candies = (N - start_eating - 1) % M
		# In the next iteration we start eating at a different place
		start_eating = M - left_candies - 1

		print('count = ' + str(count) + '  left_candies: ' + str(left_candies) + '  start_eating: ' + str(start_eating))

		if start_eating == 0:
			break

	return count

def gcd(a, b):
    # Get the greatest common divisor
    if (a % b == 0):
        return b
    else:
        return gcd(b, a % b)

def solution2(N, M):
    lcm = N * M / gcd(N, M) # Least common multiple
    return lcm / M

gcd(10,4)

M = 4
N = 10
solution(N,M) # 5

M = 3
N = 10
solution(N,M) # 10

M = 1
N = 1
solution(N,M) # 1

M = 10
N = 10
solution(N,M) # 1


from collections import OrderedDict

def _str_or_empty(value):
    mapping = {True: 1, False: 0, None: ""}
    return mapping.get(value, str(value))

def _fetch_related_strings(manager, field):
    return [_str_or_empty(getattr(entry, field)) for entry in manager.iterator()]

class IdentityExport:
    FIELDS = {
        "first_name": lambda i, a: i.first_name,
        "last_name": lambda i, a: i.last_name,
        "localized_salutation": lambda i, a: i.localized_salutation,
        "localized_title": lambda i, a: i.localized_title,
        "language": lambda i, a: i.language,
        "is_organisation": lambda i, a: i.is_organisation,
        "organisation_name": lambda i, a: i.organisation_name,
        "email": lambda i, a: i.email,
        "additional_emails": lambda i, a: "\n".join(
            _fetch_related_strings(i.additional_emails, "email"),
        ),
        "phone_numbers": lambda i, a: "\n".join(
            _fetch_related_strings(i.phone_numbers, "phone"),
        ),
        "address_addition_1": lambda i, a: "" if not a else a.address_addition_1,
        "address_addition_2": lambda i, a: "" if not a else a.address_addition_2,
        "address_addition_3": lambda i, a: "" if not a else a.address_addition_3,
        "street_and_number": lambda i, a: "" if not a else a.street_and_number,
        "po_box": lambda i, a: "" if not a else a.po_box,
        "postcode": lambda i, a: "" if not a else a.postcode,
        "town": lambda i, a: "" if not a else a.town,
        "country": lambda i, a: "" if not a else a.country.name,
    }

    def fetch_identity_data(self, identity, fields):
        address = None
        if identity.addresses.exists():
            address = identity.addresses.get(default=True)

        data = OrderedDict()

        for field_key, field_getter in fields.items():
            data[field_key] = _str_or_empty(field_getter(identity, address))

        return data

    def export(self, qs, include_fields=None, ignore_empty=False):
        include_fields = include_fields if include_fields else self.FIELDS.keys()
        fields = {name: self.FIELDS[name] for name in include_fields}

        records = []
        for identity in qs.iterator():
            identity_data = self.fetch_identity_data(identity, fields)

            if not ignore_empty or any(identity_data.values()):
                records.append(identity_data)

        return records

class MembershipExport:
    FIELDS = {
        "first_name": lambda m, a: m.identity.first_name,
        "last_name": lambda m, a: m.identity.last_name,
        "localized_salutation": lambda m, a: m.identity.localized_salutation,
        "localized_title": lambda m, a: m.identity.localized_title,
        "language": lambda m, a: m.identity.language,
        "email": lambda m, a: m.identity.email,
        "address_addition_1": lambda m, a: "" if not a else a.address_addition_1,
        "address_addition_2": lambda m, a: "" if not a else a.address_addition_2,
        "address_addition_3": lambda m, a: "" if not a else a.address_addition_3,
        "street_and_number": lambda m, a: "" if not a else a.street_and_number,
        "po_box": lambda m, a: "" if not a else a.po_box,
        "postcode": lambda m, a: "" if not a else a.postcode,
        "town": lambda m, a: "" if not a else a.town,
        "country": lambda m, a: "" if not a else a.country.name,
        "organisation": lambda m, a: m.organisation.organisation_name,
        "role": lambda m, a: "" if not m.role else m.role.title[m.identity.language],
        "inactive": lambda m, a: m.inactive,
        "tenure": lambda m, a: ""
        if not m.time_slot
        else f"{m.time_slot.lower if m.time_slot.lower else ''} - {m.time_slot.upper if m.time_slot.upper else ''}",
        "next_election": lambda m, a: m.next_election,
    }

    def fetch_membership_data(self, membership, fields):
        address = None
        if membership.identity.addresses.exists():
            address = membership.identity.addresses.get(default=True)

        data = OrderedDict()

        for field_key, field_getter in fields.items():
            data[field_key] = _str_or_empty(field_getter(membership, address))

        return data

    def export(self, qs, include_fields=None, ignore_empty=False):
        include_fields = include_fields if include_fields else self.FIELDS.keys()
        fields = {name: self.FIELDS[name] for name in include_fields}

        records = []
        for membership in qs.iterator():
            membership_data = self.fetch_membership_data(membership, fields)

            if not ignore_empty or any(membership_data.values()):
                records.append(membership_data)

        return records


import logging

import time

import redis
from django.conf import settings
from django.http import HttpRequest, HttpResponseForbidden

url = getattr(settings, 'HTTP_MONITOR_REDIS_URL', 'redis://localhost:6379/0')
url_prefix_list = getattr(settings, 'HTTP_MONITOR_PREFIX_LIST', ['/'])
force_url_list = getattr(settings, 'HTTP_MONITOR_FORCE_URL_LIST', [])
exclude_url_prefix_list = getattr(settings, 'HTTP_MONITOR_EXCLUDE_URL_PREFIX_LIST', ['/http_monitor'])
expire_seconds = getattr(settings, 'HTTP_MONITOR_EXPIRE_SECONDS', 60 * 60 * 24 * 7)

store_prefix = getattr(settings, 'HTTP_MONITOR_STORE_PREFIX', 'http_monitor:')

redis_client = redis.StrictRedis.from_url(url, decode_responses=True)
auth_level = getattr(settings, "HTTP_MONITOR_AUTH_PERMISSION", None)
dynamic_force_url_status = getattr(settings, 'HTTP_MONITOR_DYNAMIC_FORCE_URL_STATUS', False)
force_url_key = 'http_monitor_force_url'

def request_monitor(func):
    def wrapper(*args, **kw):
        from http_monitor.models import Request
        print('request_monitor start')

        request = kw.get('request')

        if not request or not isinstance(request, HttpRequest):
            request = args[0]
        if not request or not isinstance(request, HttpRequest):
            logging.error('no request found for request monitor')
            return

        print('request_monitor %s' % request.build_absolute_uri())
        request._http_request_body = request.body.decode()
        request._start_time = time.time()
        response = func(*args, **kw)
        if hasattr(request, '_start_time'):
            performance = time.time() - request._start_time
            response['API-performance'] = performance
            # request._start_time = None  # when _start_time equal None, there is a error in action retry
        response['Request-UUID'] = Request().add_request(request=request, response=response)

        print('request_monitor end')
        return response

    return wrapper

def auth_permission(func):
    def wrapper(request, *args, **kwargs):
        if auth_level and hasattr(request, 'user'):
            for auth_type in auth_level:
                if getattr(request.user, auth_type):
                    return func(request, *args, **kwargs)
            return HttpResponseForbidden()
        return func(request, *args, **kwargs)
    return wrapper


# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from urllib.parse import urljoin
from copy import deepcopy
from ..items import *
import re
import json
from scrapy_redis.spiders import RedisCrawlSpider

class AiqiyiSpider(RedisCrawlSpider):
    name = 'aiqiyi'
    allowed_domains = ['iqiyi.com']
    # start_urls = ['http://list.iqiyi.com/www/1/-------------24-1-1-iqiyi--.html']
    redis_key = 'aiqiyi:start_urls'
    host_url = 'http://list.iqiyi.com/'

    rules = (
        # 标签首页
        Rule(LinkExtractor(allow=r'list.iqiyi.com/www/1/-------------24-1-1-iqiyi--.html', unique=False), callback='parse_tag', follow=True),
        # 电影列表页，并实现翻页
        Rule(LinkExtractor(allow=r'www/1/-------------24-\d+-1-iqiyi--.html'), callback='parse_mv_info', follow=True),
        # 电影详情页
        Rule(LinkExtractor(restrict_xpaths='//div[@class="site-piclist_pic"]/a'), callback='parse_mv_detail_info', follow=True),
        # 演员详情页
        Rule(LinkExtractor(restrict_xpaths='//ul[@class="intro-detail"]/li[2]//a'), callback='parse_actor_info'),
    )

    def parse_tag(self, response):  # 提取标签分类
        div_list = response.xpath('//div[@class="mod_sear_menu mt20 mb30"]/div[not(@id="block-B")]')[1:]
        for div in div_list:
            item = TagItem()
            item['b_cate'] = div.xpath('./h3/text()').extract_first().replace('：', '')
            li_list = div.xpath('./ul/li[not(@class="selected") and not(@class="close-mod_btn")]')
            for li in li_list:
                item['s_cate'] = li.xpath('./a/text()').extract_first()
                item['s_cate_href'] = urljoin(self.host_url, li.xpath('./a/@href').extract_first())
                yield deepcopy(item)

    def parse_mv_info(self, response):  # 提取电影基本信息
        li_list = response.xpath('//div[@class="wrapper-piclist"]//li')
        for li in li_list:
            item = MovieInfoItem()
            item['mv_id'] = li.xpath('.//a[@class="site-piclist_pic_link"]/@data-qidanadd-tvid').extract_first()
            item['mv_name'] = li.xpath('.//a[@class="site-piclist_pic_link"]/@title').extract_first()
            item['mv_href'] = li.xpath('.//a[@class="site-piclist_pic_link"]/@href').extract_first()
            item['mv_duration'] = li.xpath('.//span[@class="icon-vInfo"]/text()').extract_first().strip()
            item['mv_img'] = li.xpath('.//a[@class="site-piclist_pic_link"]/img/@src').extract_first()
            item['mv_score'] = ''.join(li.xpath('.//span[@class="score"]//text()').extract())
            yield item

    def parse_mv_detail_info(self, response):  # 提取电影详情信息
        item = MovieDetailInfoItem()
        tvid = re.findall(r"param\['tvid'\] = \"(\d+)\"", response.body.decode(), re.S)[0]
        item['mv_id'] = tvid
        director = response.xpath('//div[@class="intro-right"]//em[text()="导演："]/following-sibling::span//a/text()').extract()
        if len(director):
            item['mv_director'] = ','.join(director) if len(director) > 1 else director[0]
        else:
            item['mv_director'] = ''
        item['mv_cates'] = re.findall(r'"categories":"(.*?)"', response.body.decode(), re.S)[0] if len(re.findall(r'"categories":"(.*?)"', response.body.decode(), re.S)) else None
        item['mv_desc'] = response.xpath('//span[@class="content-paragraph"]/text()').extract_first()
        # 获取看点标签
        hot_url = 'https://qiqu.iqiyi.com/apis/video/tags/get?area=azalea&entity_id={}&limit=10'.format(tvid)
        yield scrapy.Request(hot_url, callback=self.parse_hot, meta={'item': item})

        # 提取演员和角色对应关系
        span_list = response.xpath('//ul[@class="intro-detail"]/li[2]//span[@class="name-wrap"]')
        for span in span_list:
            item = ActorPlayItem()
            item['mv_id'] = tvid
            item['actor'] = span.xpath('./a/text()').extract_first()
            item['character'] = span.xpath('./span/text()').extract_first()
            yield item

    def parse_hot(self, response):  # 提取看点标签
        item = response.meta['item']
        html = json.loads(response.body.decode())
        tag_list = []
        try:
            for tag in html['data']:
                tag_list.append(tag['tag'])
            item['mv_tag'] = ','.join(tag_list)
        except:
            item['mv_tag'] = None
        yield item

    def parse_actor_info(self, response):  # 提取演员信息
        item = ActorInfoItem()
        item['actor_name'] = response.xpath('//h1/text()').extract_first()
        item['actor_en_name'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="外文名"]/following-sibling::dd/text()').extract_first()
        item['actor_gender'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="性别"]/following-sibling::dd/text()').extract_first()
        item['actor_height'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="身高"]/following-sibling::dd/text()').extract_first()
        item['actor_weight'] = response.xpath('//span[text()="体重："]/../text()').extract_first()
        item['actor_birthday'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="出生日期"]/following-sibling::dd/text()').extract_first()
        item['actor_birth_area'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="出生地"]/following-sibling::dd/text()').extract_first()
        item['actor_school'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="毕业院校"]/following-sibling::dd/text()').extract_first()
        item['actor_fame'] = response.xpath('//dl[@class="basicInfo-block basicInfo-left"]/dt[text()="成名年代"]/following-sibling::dd/text()').extract_first()
        item['actor_alias'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="别名"]/following-sibling::dd/text()').extract_first()
        item['actor_blood_group'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="血型"]/following-sibling::dd/text()').extract_first()
        item['actor_local'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="地区"]/following-sibling::dd/text()').extract_first()
        item['actor_constellation'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="星座"]/following-sibling::dd/text()').extract_first()
        item['actor_life_area'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="现居地"]/following-sibling::dd/text()').extract_first()
        item['actor_agency'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="经纪公司"]/following-sibling::dd/text()').extract_first()
        item['actor_hobby'] = response.xpath('//dl[@class="basicInfo-block basicInfo-right"]/dt[text()="爱好"]/following-sibling::dd/text()').extract_first()
        item['actor_desc'] = response.xpath('//p[@class="introduce-info"]/text()').extract_first()
        item['actor_img'] = response.xpath('//img[@itemprop="image"]/@src').extract_first().strip()
        yield item


from bitcoin import SelectParams
import bitcoin.rpc
import math
import time

from bitcoin.core import b2x, b2lx, str_money_value, COIN, CMutableTransaction, CMutableTxIn, CMutableTxOut
from bitcoin.wallet import CBitcoinAddress

SelectParams('testnet')

rpc = bitcoin.rpc.Proxy()

dust_amount = int(0.0001 * COIN)

feeperbyte1 = 0.000011 / 1000 * COIN
feeperbyte2 = 0.001 / 1000 * COIN

optinrbf = True
tx1_nSequence = 0xFFFFFFFF-2 if optinrbf else 0xFFFFFFFF
tx2_nSequence = tx1_nSequence

payment_address = CBitcoinAddress("n4Wux6bCxwFPvj7BYNb8REvtahhJ9fHJFv")

payment_txout = CMutableTxOut(int(0.1 * COIN), payment_address.to_scriptPubKey())
change_txout = CMutableTxOut(0, rpc.getnewaddress().to_scriptPubKey())

tx = CMutableTransaction()
tx.vout.append(change_txout)
tx.vout.append(payment_txout)

unspent = sorted(rpc.listunspent(1), key=lambda x: x['amount'])
value_in = 0
value_out = sum([vout.nValue for vout in tx.vout])
while (value_in - value_out) / len(tx.serialize()) < feeperbyte1:

    delta_fee = math.ceil((feeperbyte1 * len(tx.serialize())) - (value_in - value_out))

    if change_txout.nValue - delta_fee > dust_amount:
        change_txout.nValue -= delta_fee
        value_out -= delta_fee

    if value_in - value_out < 0:
        new_outpoint = unspent[-1]['outpoint']
        new_amount = unspent[-1]['amount']
        unspent = unspent[:-1]

        print('Adding new input %s:%d with value %s BTC' % \
                      (b2lx(new_outpoint.hash), new_outpoint.n,
                       str_money_value(new_amount)))

        new_txin = CMutableTxIn(new_outpoint, nSequence=tx1_nSequence)
        tx.vin.append(new_txin)

        value_in += new_amount
        change_txout.nValue += new_amount
        value_out += new_amount

        r = rpc.signrawtransaction(tx)
        assert(r['complete'])

        tx.vin[-1].scriptSig = r['tx'].vin[-1].scriptSig

r = rpc.signrawtransaction(tx)
assert(r['complete'])
tx = CMutableTransaction.from_tx(r['tx'])

print('Payment raw transaction %s' % b2x(tx.serialize()))
print('Payment raw transaction size: %.3f KB, fees: %s, %s BTC/KB' % \
             (len(tx.serialize()) / 1000,
              str_money_value(value_in-value_out),
              str_money_value((value_in-value_out) / len(tx.serialize()) * 1000)))

txid = rpc.sendrawtransaction(tx)
print('Sent payment with txid: %s' % b2lx(txid))

print('Waiting for %d seconds before double spending' % 2)
time.sleep(10)

tx.vout = tx.vout[0:1]
change_txout = tx.vout[0]
value_out = value_in
change_txout.nValue = value_out

while (value_in - value_out) / len(tx.serialize()) < feeperbyte2:
    # What's the delta fee that we need to get to our desired fees per byte at
    # the current tx size?
    delta_fee = math.ceil((feeperbyte2 * len(tx.serialize())) - (value_in - value_out))

    print('Delta fee: %s' % str_money_value(delta_fee))

    if change_txout.nValue - delta_fee > dust_amount:
        change_txout.nValue -= delta_fee
        value_out -= delta_fee

    if value_in - value_out < 0:
        new_outpoint = unspent[-1]['outpoint']
        new_amount = unspent[-1]['amount']
        unspent = unspent[:-1]

        print('Adding new input %s:%d with value %s BTC' % \
                      (b2lx(new_outpoint.hash), new_outpoint.n,
                       str_money_value(new_amount)))

        new_txin = CMutableTxIn(new_outpoint, nSequence=tx2_nSequence)
        tx.vin.append(new_txin)

        value_in += new_amount
        change_txout.nValue += new_amount
        value_out += new_amount

        r = rpc.signrawtransaction(tx)
        assert(r['complete'])

        tx.vin[-1].scriptSig = r['tx'].vin[-1].scriptSig

r = rpc.signrawtransaction(tx)
assert(r['complete'])
tx = r['tx']

print('Double-spend raw transaction %s' % b2x(tx.serialize()))
print('Double-spend raw transaction size: %.3f KB, fees: %s, %s BTC/KB' % \
             (len(tx.serialize()) / 1000,
              str_money_value(value_in-value_out),
              str_money_value((value_in-value_out) / len(tx.serialize()) * 1000)))

txid = rpc.sendrawtransaction(tx)
print('Sent double-spend txid: %s' % b2lx(txid))


import numpy as np
import pdb
from tqdm import tqdm
import logging
from faster_mask_regression import \
        get_iter_from_one_input, get_iter_from_two_inputs
import sys
import os
from brainscore.utils import fullname

class CadenaRegression(object):
    def __init__(
            self,
            smooth_reg_weight=0.1,
            sparse_reg_weight=0.01,
            group_sparsity_weight=0.01,
            output_nonlin_smooth_weight=-1,
            b_norm=True,
            batch_size=256,
            _decay_rate=[300, 375, 400],
            max_epochs=440,
            init_lr=1e-4,
            *args, **kwargs):
        self.smooth_reg_weight = smooth_reg_weight
        self.sparse_reg_weight = sparse_reg_weight
        self.group_sparsity_weight = group_sparsity_weight
        self.b_norm = b_norm
        self._batch_size = batch_size
        self._decay_rate = _decay_rate
        self._max_epochs = max_epochs
        self._lr = init_lr
        assert output_nonlin_smooth_weight == -1, "Adding non lin not supported"

        self._graph = None
        self._lr_ph = None
        self._opt = None
        self._logger = logging.getLogger(fullname(self))

    def fit(self, X, Y):
        assert not np.isnan(X).any()
        self.setup()
        X = self.reindex(X)

        assert X.ndim == 4, 'Input matrix rank should be 4.'
        with self._graph.as_default():
            self._init_mapper(X, Y)
            lr = self._lr
            for epoch in tqdm(range(self._max_epochs), desc='mask epochs'):
                for _ in range(0, len(X), self._batch_size):
                    feed_dict = {self._lr_ph: lr}
                    _ = self._sess.run(
                            [self.train_op],
                            feed_dict=feed_dict)
                if (len(self._decay_rate)>0) \
                        and (epoch % self._decay_rate[0] == 0 and epoch != 0):
                    lr /= 3.
                    self._decay_rate.remove(self._decay_rate[0])

    def predict(self, X):
        self.is_training = False
        import tensorflow as tf
        assert not np.isnan(X).any()
        X = self.reindex(X)
        with self._graph.as_default():
            self._input = get_iter_from_one_input(X, self._batch_size).get_next()
            self._make_map()

            preds = []
            for _ in range(0, len(X), self._batch_size):
                preds.append(
                        np.squeeze(self._sess.run([self._predictions])))
            final_preds = np.concatenate(preds, axis=0)
            return final_preds

    def setup(self):
        import tensorflow as tf
        self._graph = tf.Graph()
        with self._graph.as_default():
            self._lr_ph = tf.placeholder(dtype=tf.float32)
            self._opt = tf.train.AdamOptimizer(learning_rate=self._lr_ph)

    def reindex(self, X):
        channel_names = ['channel', 'channel_x', 'channel_y']
        assert all(hasattr(X, coord) for coord in channel_names)
        shapes = [len(set(X[channel].values)) for channel in channel_names]
        X = np.reshape(X.values, [X.shape[0]] + shapes)
        X = np.transpose(X, axes=[0, 2, 3, 1])
        return X

    def _make_map(self):
        import tensorflow as tf
        sys.path.append(os.path.expanduser('~/Cadena2019PlosCB'))
        from cnn_sys_ident import vggsysid
        with self._graph.as_default():
            with tf.variable_scope('mapping', reuse=tf.AUTO_REUSE):
                if self.b_norm:
                    self._input = tf.layers.batch_normalization(
                            self._input, training=self.is_training,
                            momentum=0.9, epsilon=1e-4, fused =True)
                self._input = tf.nn.relu(self._input)
                self._predictions = vggsysid.readout(
                        self._input,
                        self.out_shape,
                        self.smooth_reg_weight,
                        self.sparse_reg_weight,
                        self.group_sparsity_weight)
                self._predictions = tf.nn.elu(self._predictions - 1.0) + 1.0

    def _make_loss(self):
        import tensorflow as tf
        prediction = self._predictions
        response = self._target
        realresp = tf.math.logical_not(tf.math.is_nan(response))
        prediction = tf.boolean_mask(prediction, realresp)
        response = tf.boolean_mask(response, realresp)
        self._pred_loss = tf.reduce_mean(
                    prediction - response * tf.log(prediction + 1e-9))
        self._reg_loss = tf.add_n(
                tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES))
        self.total_loss = self._pred_loss + self._reg_loss
        self.tvars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)
        update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        print_op = tf.print(
                'L2 error: ', self._pred_loss,
                'Total loss: ', self.total_loss
                )
        print_op = tf.no_op()
        update_ops.append(print_op)
        with tf.control_dependencies(update_ops):
            self.train_op = self._opt.minimize(
                    self.total_loss, var_list=self.tvars,
                global_step=tf.train.get_or_create_global_step())

    def _init_mapper(self, X, Y):
        self.is_training = True
        import tensorflow as tf
        assert len(Y.shape) == 2
        self.out_shape = Y.shape[1]
        with self._graph.as_default():
            # Make input
            self._input, self._target = get_iter_from_two_inputs(X, Y, self._batch_size).get_next()
            # Build the model graph
            self._make_map()
            self._make_loss()

            # initialize graph
            self._logger.debug('Initializing mapper')
            init_op = tf.variables_initializer(tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES))
            gpu_options = tf.GPUOptions(allow_growth=True)
            self._sess = tf.Session(
                    config=tf.ConfigProto(
                        allow_soft_placement=True,
                        gpu_options=gpu_options,
                        ))
            self._sess.run(init_op)


from django.contrib import admin
from django.forms import ModelForm

from .models import User,UserInfo,Question,Answer
from refill.models import NewRx

class AlwaysChangedModelForm(ModelForm):
    def has_changed(self):
        return True

class UserInfoInline(admin.TabularInline):
    model = UserInfo
    raw_id_fields = ['user']

class UserAdmin(admin.ModelAdmin):
    #list_display = [ ]
    #list_filter = ['paid', 'created', 'updated']
    inlines = [UserInfoInline]

class QuestionInline(admin.TabularInline):
    extra = 0
    form = AlwaysChangedModelForm
    model = Answer
    raw_id_fields = ['parrent']
class QuestionAdmin(admin.ModelAdmin):
    inlines = [QuestionInline]

admin.site.register(User, UserAdmin)
admin.site.register(Question,QuestionAdmin)
admin.site.register(UserInfo)

#admin.site.register(UserProfile)


import os
import numpy as np
import matplotlib
matplotlib.use('Agg')
from matplotlib import pylab as plt
import matplotlib.cm as cm

# paths
DATAPATH = '../../Data'
OUTPATH = '../../Outcome'

def mkdir(path):
    try:
        os.mkdir(path)
    except:
        pass

# parameters
image_id = 0
conv_size = [96, 256, 384, 384, 256]
conv_side = [55, 27, 13, 13, 13]

# prepare directory structure

# load activations
for conv_id in range(len(conv_size)):
    mkdir('%s/Figures/Layer reconstruction/conv%d' % (OUTPATH, conv_id + 1))
    mkdir('%s/Figures/Layer reconstruction/conv%d/image%d/' % (OUTPATH, conv_id + 1, image_id))

    flat_activations = np.load('%s/DNN/activations/alexnet/conv%d/activations.npy' % (DATAPATH, conv_id + 1))
    all_filters = flat_activations[image_id, :].reshape((conv_size[conv_id], conv_side[conv_id], conv_side[conv_id]))

    for fid in range(conv_size[conv_id]):
        plt.figure();
        plt.imshow(all_filters[fid, :, :], interpolation='none', cmap=cm.Blues);
        plt.savefig('%s/Figures/Layer reconstruction/conv%d/image%d/filter%d.png' % (OUTPATH, conv_id + 1, image_id, fid), bbox_inches='tight');
        plt.clf();
        plt.close();


from bottle import get, view, redirect, response, request
import g
import jwt
import time

##############################
@get("/login")
@get("/<language>/login")
@view("login")
def _(language = "en"):
    if f"{language}_server_error" not in g.ERRORS: language = "en"

    if request.get_cookie("jwt"):
        display_page = True

        cookie = request.get_cookie("jwt")
        decoded_jwt = jwt.decode(cookie, g.JWT_SECRET, algorithms=["HS256"])
        now = int(time.time())
        seconds_since_session_created = int(now - decoded_jwt["iat"])
        try:
            if seconds_since_session_created > 86000:
                print("Session expired")
                g._DELETE_SESSION(decoded_jwt, language)
                response.set_cookie("jwt", cookie, expires=0)
            if seconds_since_session_created < 86000:
                print("Session not expired")
                g._UPDATE_SESSION(decoded_jwt, now, language)

                decoded_jwt["iat"] = now
                encoded_jwt = jwt.encode(decoded_jwt, g.JWT_SECRET, algorithm="HS256")
                response.set_cookie("jwt", encoded_jwt, path="/")

                display_page = False

        except Exception as ex:
            print(ex)
            return g._SEND(500, g.ERRORS[f"{language}_server_error"])

        if not display_page: return redirect("/home")

    return


from os import system
import string
import sys

cipher_alphabet = list(string.ascii_uppercase)
plain_alphabet = list(string.ascii_lowercase)

def decrypt(ciphertext: str) -> str:
    plaintext = ""
    for char in ciphertext:
        if char in cipher_alphabet:
            index = cipher_alphabet.index(char)
            plaintext += plain_alphabet[index]
        else:
            plaintext += char
    return plaintext

if __name__ == "__main__":
    ciphertext = open(sys.argv[1], 'r').read()
    while True:
        system('clear')
        print("Stage 2: Caesar Shift Cipher")
        print()
        print("Ciphertext:" + ciphertext)
        print("Cipher alphabet: " + ' '.join(cipher_alphabet))
        print("Plain alphabet : " + ' '.join(plain_alphabet))
        print()
        print("Plaintext: " + decrypt(ciphertext))
        input("Press any key to shift...")
        plain_alphabet.append(plain_alphabet.pop(0))


# -*- coding: utf-8 -*-
"""The Windows services event formatter.

The Windows services are derived from Windows Registry files.
"""

from plaso.formatters import manager
from plaso.formatters import winreg
from plaso.winnt import human_readable_service_enums

class WinRegistryServiceFormatter(winreg.WinRegistryGenericFormatter):
  """Formatter for a Windows service event."""

  DATA_TYPE = u'windows:registry:service'

  def GetMessages(self, formatter_mediator, event_object):
    """Determines the formatted message strings for an event object.

    Args:
      formatter_mediator: the formatter mediator object (instance of
                          FormatterMediator).
      event_object: the event object (instance of EventObject).

    Returns:
      A tuple containing the formatted message string and short message string.

    Raises:
      WrongFormatter: if the event object cannot be formatted by the formatter.
    """
    regvalue = getattr(event_object, u'regvalue', {})
    # Loop over all the registry value names in the service key.
    for service_value_name in regvalue.keys():
      # A temporary variable so we can refer to this long name more easily.
      service_enums = human_readable_service_enums.SERVICE_ENUMS
      # Check if we need to can make the value more human readable.
      if service_value_name in service_enums.keys():
        service_enum = service_enums[service_value_name]
        # Find the human readable version of the name and fall back to the
        # raw value if it's not found.
        human_readable_value = service_enum.get(
            regvalue[service_value_name],
            regvalue[service_value_name])
        regvalue[service_value_name] = human_readable_value

    return super(WinRegistryServiceFormatter, self).GetMessages(
        formatter_mediator, event_object)

manager.FormattersManager.RegisterFormatter(WinRegistryServiceFormatter)


from xml.dom import minidom

import cairo
import math
import random
import re

LETTER_SPACING = 12
RANDOMNESS_SCALE = 2
LINE_WIDTH = 0.8
MIN_LINE_WIDTH = 0.6
MAX_LINE_WIDTH = 0.9
LETTER_HEIGHT = 14
AVG_LETTER_WIDTH = 11

LETTER_WIDTHS = {'a':9,
                 'b':6,
                 'c':10,
                 'd':6,
                 'e':8.5,
                 'f':5,
                 'g':6,
                 'h':6,
                 'i':2,
                 'j':1,
                 'k':4.5,
                 'l':2,
                 'm':9,
                 'n':6,
                 'o':7,
                 'p':9,
                 'q':7,
                 'r':9,
                 's':6,
                 't':5,
                 'u':7,
                 'v':7,
                 'w':7,
                 'x':9,
                 'y':6,
                 'z':8,
                 'A':9,
                 'B':9,
                 'C':10,
                 'D':9,
                 'E':8,
                 'F':8,
                 'G':11,
                 'H':7,
                 'I':1,
                 'J':8,
                 'K':8,
                 'L':7.5,
                 'M':8,
                 'N':7,
                 'O':11,
                 'P':7,
                 'Q':10,
                 'R':7,
                 'S':9,
                 'T':8,
                 'U':11,
                 'V':9,
                 'W':11,
                 'X':12,
                 'Y':7,
                 'Z':13,
                 '0':9,
                 '1':3,
                 '2':9,
                 '3':7,
                 '4':9,
                 '5':7.5,
                 '6':7,
                 '7':6,
                 '8':7,
                 '9':6,
                 '.':3,
                 ',':3,
                 "'": 3,
                 ';':3,
                 '-':9,
                 ':':3,
                 '\n':0,
                 }

SPECIAL_CHARS = {".": "period",
                 ",": "comma",
                 "'": "apostrophe",
                 ";":"semicolon",
                 '-':"hyphen",
                 ":": "colon"}

class TypeWriter:
    def __init__(self, ctx, START_X, START_Y, X_LIMIT, LINE_HEIGHT):
        self.ctx = ctx
        self.START_X = START_X
        self.x = START_X
        self.y = START_Y
        self.X_LIMIT = X_LIMIT
        self.LINE_HEIGHT = LINE_HEIGHT

        self.ctx.set_line_width(LINE_WIDTH)
        self.ctx.set_line_cap(cairo.LINE_CAP_ROUND)
        self.ctx.move_to(START_X, START_Y)

    def random(self):
        return (random.random()-0.5)*RANDOMNESS_SCALE

    def small_random(self):
        return self.random()/10

    def line(self, dx, dy):
        self.ctx.line_to(self.x+dx+self.random(), self.y+dy+self.random())
        self.ctx.stroke()

        self.update_stroke()

    def arc(self, init_x, init_y, x1, y1, x2, y2, xf, yf):
        self.ctx.curve_to(init_x+x1+self.random(), init_y+y1+self.random(), init_x+x2+self.random(), init_y+y2+self.random(), init_x+xf, init_y+yf)
        self.ctx.stroke()

        self.update_stroke()

    # Takes care of flipping the y-axis by subtracting LETTER_HEIGHT on its own. Just pass whatever coords come from the svg file now.
    def new_arc(self, init_x, init_y, x1, y1, x2, y2, xf, yf):
        self.ctx.curve_to(init_x+x1+self.random(), -LETTER_HEIGHT+init_y+y1+self.random(), init_x+x2+self.random(), -LETTER_HEIGHT+init_y+y2+self.random(), init_x+xf, -LETTER_HEIGHT+init_y+yf)
        self.ctx.stroke()

        self.update_stroke()

    def execute(self, init_x, init_y, s):
        tokens = re.split(' |,', s)
        tokens.pop(0)
        tokens.pop(2)
        tokens = [float(x) for x in tokens]
        self.move_to_relative(init_x, init_y, tokens[0], tokens[1])
        self.new_arc(init_x, init_y, tokens[2], tokens[3], tokens[4], tokens[5], tokens[6], tokens[7])

    def execute2(self, init_x, init_y, s):
        tokens = re.split(' |,', s)
        tokens.pop(0)
        tokens.pop(2)
        tokens = [float(x) for x in tokens]
        self.move_to_relative(init_x, init_y, tokens[0], tokens[1])
        self.new_arc_without_stroke(init_x, init_y, tokens[2], tokens[3], tokens[4], tokens[5], tokens[6], tokens[7])
        self.new_arc_without_stroke(init_x, init_y, tokens[8], tokens[9], tokens[10], tokens[11], tokens[12], tokens[13])

        self.ctx.stroke()
        self.update_stroke()

    def new_arc_without_stroke(self, init_x, init_y, x1, y1, x2, y2, xf, yf):
        self.ctx.curve_to(init_x+x1+self.random(), -LETTER_HEIGHT+init_y+y1+self.random(), init_x+x2+self.random(), -LETTER_HEIGHT+init_y+y2+self.random(), init_x+xf, -LETTER_HEIGHT+init_y+yf)

    def update_stroke(self):
        new_stroke = self.ctx.get_line_width() + self.small_random()*2
        while new_stroke < MIN_LINE_WIDTH or new_stroke > MAX_LINE_WIDTH:
            new_stroke = self.ctx.get_line_width() + self.small_random()*2
        self.ctx.set_line_width(new_stroke)

    def move_by(self, dx, dy):
        self.x += dx + self.random()
        self.y += dy + self.random()
        self.update_point()

    # Moves to coords relative to init_x and init_y. Also flips y so you don't have to care about -14
    def move_to_relative(self, init_x, init_y, x, y):
        self.x = init_x+x+self.random()
        self.y = init_y+(-LETTER_HEIGHT+y)+self.random()*2
        self.update_point()

    def update_point(self):
        self.ctx.move_to(self.x, self.y)

    def next_line(self):
        self.x = self.START_X
        self.y += self.LINE_HEIGHT
        self.ctx.move_to(self.x, self.y)

    def space_bar(self):
        self.x += LETTER_SPACING + abs(self.random()*3)

    def type(self, string):
        words = string.split(' ')
        for word in words:
            init_x = self.x
            for ch in word:
                try:
                    init_x += LETTER_WIDTHS[ch]
                except:
                    print(f"Letter width for {ch} not found.")
            if init_x >= self.X_LIMIT:
                self.next_line()

            for ch in word:
                if ch == '\n':
                    self.next_line()
                    continue
                if ch == ' ':
                    self.space_bar()
                    continue
                try:
                    if ch >= 'A' and ch <= 'Z':
                        doc = minidom.parse(f'letters/{ch}2.svg')
                    elif ch >= 'a' and ch <= 'z' or ch >= '0' and ch <= '9':
                        doc = minidom.parse(f'letters/{ch}.svg')
                    else:
                        doc = minidom.parse(f'letters/{SPECIAL_CHARS[ch]}.svg')
                except:
                    print(f"Letter {ch} file not found")

                path_strings = [path.getAttribute('d') for path in doc.getElementsByTagName('path')]
                doc.unlink()

                init_x, init_y = self.x, self.y + self.small_random()*3
                for path in path_strings:
                    if len(re.split(' |,', path)) >= 12:
                        self.execute2(init_x, init_y, path)
                    else:
                        self.execute(init_x, init_y, path)
                self.x = init_x
                self.y = init_y

                if ch != ' ':
                    try:
                        self.x += LETTER_WIDTHS[ch] + abs(self.random())
                    except:
                        pass

                if self.x > self.X_LIMIT:
                    self.x = self.START_X
                    self.y += self.LINE_HEIGHT

                self.ctx.move_to(self.x, self.y)
                self.prev_char = ch
            self.space_bar()


# -*- coding: utf-8 -*-
"""
Created on Wed Dec 12 16:24:21 2018

@author: mob3f
"""
import pandas as pd
import matplotlib.pyplot as plt
import nltk
from math import pi

threshold = 20

data = pd.read_csv('C:/Users/mob3f/Documents/Python Scripts/DrFirst/search_data.csv')
data.describe()#Describe our data
data['totalResults'] = pd.to_numeric(data.totalResults, errors='coerce')#parse this column to numeric and put NA in place of text
#Change timestamps to datetime format
data['requestDate'] = pd.to_datetime(data['requestDate'])
data['responseDate'] = pd.to_datetime(data['responseDate'])

data['requestDuration']= (data['responseDate']-data['requestDate']).astype('timedelta64[ms]')#Calculate excution time

#Sort data by request time, this is similar to sorting by response time.
data = data.sort_values(by=['requestDate'])

#Looping through data and detecting unique requests (see report)
window={}
results={}
for index, row in data.iterrows():
    if not pd.isnull(row['request']):
        c_search=row['request'].lower()
        c_time=row['requestDate']
        if not window: #If window is empty, add the term to it
            window[c_search]=c_time
        else:
            for key in list(window):
                key=key.lower()
                if (key in c_search) or (c_search in key) or nltk.edit_distance(c_search, key)<=3: #For each term, compare it with the previous terms in the window. Not that this can be improved by using a Jaccard_similarity_score
                    window[c_search] = window.pop(key)#If they are similiar, replace the term in the window and its corresponding time by the new term
                else:
                     #If we didn't find a similiar word in the window
                    if (c_time-window[key]).total_seconds() > threshold: #If ther current term in the window has expired, move it from the window to the result dictionary
                        results[window[key]]=key
                window[c_search]=c_time #add the new term to the dictionary

results=pd.DataFrame(pd.Series(results,name='request'))#Parse the result dictionary to a pandas dataframe
results.to_csv('C:/Users/mob3f/Documents/Python Scripts/DrFirst/search_data_users.csv')#Export results to a csv file
results.shape #number of request
results.request.unique().size #number of unique requests
results.request.groupby(results.request).count().nlargest(20).plot(kind='bar')# Plot top 20 requests

#Plot number of users over time
fig,ax = plt.subplots()
results.request.groupby(results.index.date).count().plot(ax=ax,marker='D',color='green', linestyle='--')

#Plot number of users over hours of the day
count=results.request.groupby(results.index.hour).count()
categories=count.keys()
N = len(categories)
# What will be the angle of each axis in the plot? (we divide the plot / number of variable)
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
# Initialise the spider plot
ax = plt.subplot(111,polar=True)
# If you want the first axis to be on top:
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Draw one axe per hour + add labels
plt.xticks(angles[:-1], categories)
# Draw ylabels
ax.set_rlabel_position(0)
ax.plot(angles[:-1], count, linewidth=2.5,color='green', linestyle='--', label="number of requests")
ax.fill(angles[:-1], count, 'b', alpha=0.2)


import os
import numpy as np
import BilliardClasses as BC
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
FIG_DIR = 'Plot images/'
FIG_DIR = os.path.join(CURRENT_DIR, FIG_DIR)
NUM_OF_COLLISIONS = 200

def printPositionPlot(board_list, title, start_angles):
    title = "Billiard table - %s" % title
    fig, ax = plt.subplots(nrows=1, ncols=len(board_list), figsize=(15, 7))
    fig.suptitle(title, fontsize=14, y=1)
    for i in range(len(board_list)):
        # Retrieve all relevant data
        collision_points = board_list[i].collision_points
        # Draw the board
        board_list[i].drawBoard(ax[i])
        # Draws the lines between collision points
        ax[i].plot(collision_points[0], collision_points[1], color="b", linewidth=0.5)
        ax[i].set_xlabel(eval("start_angles[i]") / np.pi * 180)
    fig.tight_layout()

    return plt.gcf()

def animate(board, title, start_angle, figsize, fps):
    print('animate')
    filename = "Billiard_table_%s.gif" % title
    filename = os.path.join(FIG_DIR, filename)
    title = "Billiard table - %s" % title

    fig, ax = plt.subplots(figsize=figsize)
    fig.suptitle(title, fontsize=14, y=1)
    board.drawBoard(ax, color='w')
    collision_points = board.collision_points

    xdata, ydata = [], []
    ln, = plt.plot([], [], linewidth=1, color='r')

    def init_func():
        ax.set_xlabel(start_angle / np.pi * 180)
        ax.set_facecolor('xkcd:black')
        fig.patch.set_facecolor('xkcd:black')
        return ln

    def update(i):
        xdata.append(collision_points[0][i])
        ydata.append(collision_points[1][i])
        ln.set_data(xdata, ydata)
        print(i)
        return ln

    writergif = PillowWriter(fps=fps)
    anim = FuncAnimation(fig, update, frames=np.arange(0, NUM_OF_COLLISIONS, 1, dtype=int), init_func=init_func)
    anim.save(filename, writer=writergif)

# ANIMATIONS #

def animateSquareBilliard(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    square_start_position = np.array([[0], [-1]])
    square_vertices = [(1, 1), (-1, 1), (-1, -1), (1, -1)]
    sq_para = (num_collisions, square_vertices, square_start_position, start_angle)
    square_board = BC.PolygonBilliardBoard(*sq_para)
    animate(square_board, 'Square', start_angle, figsize=(10, 10), fps=fps)
    return 0

def animateTriangleBilliard(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    tri_start_position = np.zeros((2, 1))
    tri_para = (num_collisions, 'triangle', tri_start_position, start_angle)
    tri_board = BC.PolygonBilliardBoard(*tri_para)
    animate(tri_board, 'Triangle', start_angle, figsize=(10, 10), fps=fps)
    return 0

def animateRightAnlgeTriangleBilliard(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    tri_start_position = np.zeros((2, 1))
    triangle_vertices = [(1, 1), (-1, 1), (1, -1)]
    tri_para = (num_collisions, triangle_vertices, tri_start_position, start_angle)
    tri_board = BC.PolygonBilliardBoard(*tri_para)
    animate(tri_board, 'RightAngleTriangle', start_angle, figsize=(10, 10), fps=fps)
    return 0

def animateCircleBilliard(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    circ_start_position = np.array([[0], [-1]])
    circ_para = (num_collisions, (1, 1), circ_start_position, start_angle)
    circ_board = BC.EllipticalBilliardBoard(*circ_para)
    animate(circ_board, 'Circle', start_angle, figsize=(10,10), fps=fps)
    return 0

def animateSemiCircleBilliard(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    semi_circle_start = np.array([[0], [0.999999]])
    semi_circle_para = (num_collisions, (1, 1, 0), semi_circle_start, start_angle)
    semi_circle_board = BC.BunimovichBilliardBoard(*semi_circle_para)
    animate(semi_circle_board, 'SemiCircle', start_angle, figsize=(10, 6), fps=fps)
    return 0

def animateElipseBilliard(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    ellipse_start_position = np.array([[-1.9], [0]])
    ellipse_para = (num_collisions, (2, 1), ellipse_start_position, start_angle)
    ellipse_board = BC.EllipticalBilliardBoard(*ellipse_para)
    animate(ellipse_board, 'Elipse', start_angle, figsize=(10,6), fps=fps)
    return 0

def animateElipseBilliard2(start_angle, num_collisions=NUM_OF_COLLISIONS, fps=30):
    ellipse_start_position = np.array([[-0.1], [0]])
    ellipse_para = (num_collisions, (2, 1), ellipse_start_position, start_angle)
    ellipse_board = BC.EllipticalBilliardBoard(*ellipse_para)
    animate(ellipse_board, 'Elipse2', start_angle, figsize=(10,6), fps=fps)
    return 0

# Graphs #

def printSquareBilliard(start_angle_1, start_angle_2, num_collisions):
    square_start_position = np.array([[0], [-1]])
    square_vertices = [(1, 1), (-1, 1), (-1, -1), (1, -1)]
    sq_para_1 = (num_collisions, square_vertices, square_start_position, start_angle_1)
    sq_para_2 = (num_collisions, square_vertices, square_start_position, start_angle_2)
    square_board_1 = BC.PolygonBilliardBoard(*sq_para_1)
    square_board_2 = BC.PolygonBilliardBoard(*sq_para_2)
    square_boards = [square_board_1, square_board_2]
    return printPositionPlot(square_boards, 'Square', [start_angle_1, start_angle_2])

def printTriangleBilliard(start_angle_1, start_angle_2, num_collisions):
    tri_start_position = np.zeros((2, 1))
    tri_para_1 = (num_collisions, 'triangle', tri_start_position, start_angle_1)
    tri_para_2 = (num_collisions, 'triangle', tri_start_position, start_angle_2)
    tri_board_1 = BC.PolygonBilliardBoard(*tri_para_1)
    tri_board_2 = BC.PolygonBilliardBoard(*tri_para_2)
    tri_boards = [tri_board_1, tri_board_2]
    return printPositionPlot(tri_boards, 'Triangle', [start_angle_1, start_angle_2])

def printRightAngleTriangleBilliard(start_angle_1, start_angle_2, num_collisions):
    tri_start_position = np.zeros((2, 1))
    triangle_vertices = [(1, 1), (-1, 1), (1, -1)]
    tri_para_1 = (num_collisions, triangle_vertices, tri_start_position, start_angle_1)
    tri_para_2 = (num_collisions, triangle_vertices, tri_start_position, start_angle_2)
    tri_board_1 = BC.PolygonBilliardBoard(*tri_para_1)
    tri_board_2 = BC.PolygonBilliardBoard(*tri_para_2)
    tri_boards = [tri_board_1, tri_board_2]
    return printPositionPlot(tri_boards, 'RATriangle', [start_angle_1, start_angle_2])

def printCircleBilliard(start_angle_1, start_angle_2, num_collisions):
    circ_start_position = np.array([[0], [-1]])
    circ_para_1 = (num_collisions, (1, 1), circ_start_position, start_angle_1)
    circ_para_2 = (num_collisions, (1, 1), circ_start_position, start_angle_2)
    circ_board_1 = BC.EllipticalBilliardBoard(*circ_para_1)
    circ_board_2 = BC.EllipticalBilliardBoard(*circ_para_2)
    circ_boards = [circ_board_1, circ_board_2]
    return printPositionPlot(circ_boards, 'Circle', [start_angle_1, start_angle_2])

def printSemiCircle(start_angle_1, start_angle_2, num_collisions):
    # Two billiard maps, same starting position but different launch angles
    semi_circle_start = np.array([[0], [0.999999]])
    # Parameters of the hyperbolic board class to use
    semi_circle_para_1 = (num_collisions, (1, 1, 0), semi_circle_start, start_angle_1)
    semi_circle_para_2 = (num_collisions, (1, 1, 0), semi_circle_start, start_angle_2)
    semi_circle_board_1 = BC.BunimovichBilliardBoard(*semi_circle_para_1)
    semi_circle_board_2 = BC.BunimovichBilliardBoard(*semi_circle_para_2)
    semi_circle_boards = [semi_circle_board_1, semi_circle_board_2]
    return printPositionPlot(semi_circle_boards, 'SemiCircle', [start_angle_1, start_angle_2])

def printElipseBilliard(start_angle_1, start_angle_2, num_collisions):
    ellipse_start_position_1 = np.array([[-0.1], [0]])
    ellipse_start_position_2 = np.array([[-1.9], [0]])
    ellipse_para_1 = (num_collisions, (2, 1), ellipse_start_position_1, start_angle_1)
    ellipse_para_2 = (num_collisions, (2, 1), ellipse_start_position_2, start_angle_2)
    ellipse_board_1 = BC.EllipticalBilliardBoard(*ellipse_para_1)
    ellipse_board_2 = BC.EllipticalBilliardBoard(*ellipse_para_2)
    ellipse_boards = [ellipse_board_1, ellipse_board_2]
    return printPositionPlot(ellipse_boards, 'Ellipse', [start_angle_1, start_angle_2])

def printHyperbolicBilliard(start_angle_1, start_angle_2, num_collisions):
    # Two billiard maps, same starting position but different launch angles
    hb_start = np.zeros((2, 1))
    # Parameters of the hyperbolic board class to use
    hb_para_1 = (num_collisions, (1, 1), hb_start, start_angle_1)
    hb_para_2 = (num_collisions, (1, 1), hb_start, start_angle_2)
    hb_board_1 = BC.HyperbolicBilliardBoard(*hb_para_1)
    hb_board_2 = BC.HyperbolicBilliardBoard(*hb_para_2)
    hb_boards = [hb_board_1, hb_board_2]
    return printPositionPlot(hb_boards, 'Hyperbolic', [start_angle_1, start_angle_2])

def printStadiumBilliard(start_angle_1, start_angle_2, num_collisions):
    # Two billiard maps, same starting position but different launch angles
    stad_start = np.array([[0.5], [0]])
    # Parameters of the hyperbolic board class to use
    stad_para_1 = (num_collisions, (1, 1, 0.5), stad_start, start_angle_1)
    stad_para_2 = (num_collisions, (1, 1, 0.5), stad_start, start_angle_2)
    stad_board_1 = BC.StadiumBilliardBoard(*stad_para_1)
    stad_board_2 = BC.StadiumBilliardBoard(*stad_para_2)
    stad_boards = [stad_board_1, stad_board_2]
    return printPositionPlot(stad_boards, 'Stadium', [start_angle_1, start_angle_2])

def printBunimovichBilliard(start_angle_1, start_angle_2, num_collisions):
    # Two billiard maps, same starting position but different launch angles
    bunimovich_start = np.array([[0.5], [0]])
    # Parameters of the hyperbolic board class to use
    bunimovich_para_1 = (num_collisions, (1, 1, -0.25), bunimovich_start, start_angle_1)
    bunimovich_para_2 = (num_collisions, (1, 1, -0.25), bunimovich_start, start_angle_2)
    bunimovich_board_1 = BC.BunimovichBilliardBoard(*bunimovich_para_1)
    bunimovich_board_2 = BC.BunimovichBilliardBoard(*bunimovich_para_2)
    bunimovich_boards = [bunimovich_board_1, bunimovich_board_2]
    return printPositionPlot(bunimovich_boards, 'Bunimovich', [start_angle_1, start_angle_2])

def printLorentzGasBilliard(start_angle_1, start_angle_2, num_collisions):
    # Two billiard maps, same starting positions and different launch angles
    lg_start = np.array([[-1.2], [0]])
    # Parameters of the hyperbolic board class to use
    lg_para_1 = (num_collisions, None, lg_start, start_angle_1)
    lg_para_2 = (num_collisions, None, lg_start, start_angle_2)
    lg_board_1 = BC.LorentzGasBilliardBoard(*lg_para_1)
    lg_board_2 = BC.LorentzGasBilliardBoard(*lg_para_2)
    lg_boards = [lg_board_1, lg_board_2]
    return printPositionPlot(lg_boards, 'Lorentz Gas', [start_angle_1, start_angle_2])

def printHyperbolicLorentzGasBilliard(start_angle_1, start_angle_2, num_collisions):
    # Two billiard maps, same starting positions and different launch angles
    hlg_start = np.array([[0], [1.5]])
    # Parameters of the hyperbolic board class to use
    hlg_para_1 = (num_collisions, None, hlg_start, start_angle_1)
    hlg_para_2 = (num_collisions, None, hlg_start, start_angle_2)
    hlg_board_1 = BC.HyperbolicLorentzGasBilliardBoard(*hlg_para_1)
    hlg_board_2 = BC.HyperbolicLorentzGasBilliardBoard(*hlg_para_2)
    hlg_boards = [hlg_board_1, hlg_board_2]
    return printPositionPlot(hlg_boards, 'Hyperbolic Lorentz Gas', [start_angle_1, start_angle_2])


from DriveTest.WebScraper import WebScraper
from DriveTest.TimeManager import TimeManager
from DriveTest.DriveTestCandidate import DriveTestCandidate
from selenium.webdriver.common.by import By

import time

class RoadTestService:
    def __init__(self, web_driver=None, web_address=None,
                 candidate=DriveTestCandidate()):

        self.scraper = web_driver
        self.web_address = web_address
        self.candidate = candidate

    def set_web_driver(self, web_driver):
        self.scraper = web_driver

    def get_drive_test_home_page(self):
        return self.scraper.get_page(self.web_address)

    def start_drive_road_test(self):
        self.scraper.get_page(self.web_address)
        # click drive road test button
        return self.scraper.click_element(focused_element_locator="//*[@class='btn btn-primary btn-main' and"
                                                                  " contains(text(), 'Book a Road test')]")

    def edit_existing_road_test_step(self):
        # click edit an existing road test
        return self.scraper.click_element(focused_element_locator="//a[contains(text(), 'Edit an Existing Road Test')]",
                                          waiting_element_locator=(By.ID, "emailAddress"))

    def send_licence_info_step(self):
        time.sleep(2)
        licence_element = self.scraper.set_text(value=self.candidate.licence_number,
                              focused_element_locator="//input[@type='text' and @id='licenceNumber']", setting_method="JAVA_SCRIPT")
        time.sleep(2)
        expiry_element = self.scraper.set_text(value=self.candidate.licence_expiry,
                              focused_element_locator="//input[@type='text' and @id='licenceExpiryDate']", setting_method="JAVA_SCRIPT")
        time.sleep(2)
        licence_element.click()
        expiry_element.click()
        licence_element.click()
        time.sleep(2)
        self.scraper.submit_form(form_name="driverInfo")

    def new_road_test_step(self):
        return self.scraper.click_element(focused_element_locator="//*[contains(text(),"
                                                                  "'Book a New Road Test')]",
                                          waiting_element_locator=(By.XPATH, "//*[contains(text(),"
                                                                             "'You have no booked road"
                                                                             " tests at this time')]"))

    def reschedule_test_step(self):
        self.scraper.click_element(focused_element_locator="//button[contains(text(), 'Reschedule')]")
        popup_element = self.scraper.click_element(focused_element_locator="//div[@class='form-group lic-submit']/button[@title='reschedule']")
        return popup_element

    def select_test_class_step(self):
        # select class of road test
        self.scraper.click_element(focused_element_locator="//input[@type='radio' "
                                                           "and @value='" + self.candidate.road_test_class + "']",
                                   waiting_element_locator=(By.XPATH, "//input[@type='radio' and "
                                                                      "@value='" + self.candidate.road_test_class + "']"),
                                   clicking_method="JAVA_SCRIPT")
        result = self.scraper.submit_form(form_name='driverInfo')
        return result

    def select_location_step(self):
        self.scraper.click_element(focused_element_locator="//a[@title='" + self.candidate.location + "']")
        result = self.scraper.submit_form(form_name="locationInfo")
        return result

    def select_available_date_step(self):
        date_selectable_class = "date-link"
        date_selected_class = "date-link selected"
        selected_day = None
        selected_month = None
        is_date_selected = False
        is_day_acceptable = False
        max_next_month = TimeManager.next_acceptable_month_count(self.candidate.interval_day)
        next_month_count = 1
        previous_month_count = max_next_month
        result = None
        # selectable_date_elements = []
        # calendar_month = 0
        while not is_date_selected:
            selectable_date_elements = self.scraper.find_elements(focused_element_locator="//a[@class='"
                                                                                + date_selectable_class + "']",
                                                                  waiting_element_locator=(By.XPATH, "//div[@class="
                                                                                "'calendar-body']"),
                                                                  waiting_time=20)
            calendar_month = self.scraper.find_element(focused_element_locator="//*[@class='calendar-header']/h3")
            if len(selectable_date_elements) > 0:
                print("there is some dates available to select")
                for date_element in selectable_date_elements:
                    candidate_day = int(date_element.get_attribute("title"))
                    print("candidate day is :", candidate_day)
                    if next_month_count == 1:
                        if candidate_day >= TimeManager.today:
                            is_day_acceptable = True
                    elif next_month_count == max_next_month:
                        if candidate_day <= TimeManager.max_acceptable_day(self.candidate.interval_day):
                            is_day_acceptable = True
                    else:
                        is_day_acceptable = True
                    if is_day_acceptable and WebScraper.element_class_checker(date_element,
                                                                              date_selectable_class):
                        self.scraper.click_by_java_script(element=date_element)
                        if WebScraper.element_class_checker(date_element, date_selected_class):
                            selected_day = candidate_day
                            selected_month = calendar_month.text
                            is_date_selected = True
                            print("one date is selected : " + str(selected_month) + " " + str(selected_day))
                            break

            else:
                if next_month_count <= max_next_month:
                    self.nex_month_step()
                    next_month_count += 1

                elif previous_month_count >= 1:
                    self.previous_month_step()
                    previous_month_count -= 1
                else:
                    next_month_count = 1
                    previous_month_count = max_next_month
            if not is_date_selected:
                print("waiting to load data of another month...")
                time.sleep(1)
        if is_date_selected:
            result = self.scraper.submit_form(form_name="driverInfo")
        else:
            print("date is not selected")
        return is_date_selected, result

    def select_available_time_step(self):
        time_selectable_class = "timeslot_label ng-binding"
        time_selected_class = "timeslot_label ng-binding active"
        selected_time = None
        is_time_selected = False
        result = None
        selectable_time_elements = self.scraper.find_elements(focused_element_locator="//label[@class='"
                                                                                + time_selectable_class + "']")
        if len(selectable_time_elements) > 0:
            print("there is some times available to select")
            available_times = [t.get_attribute("for") for t in selectable_time_elements]
            print("available times are :", available_times)
            for time_element in selectable_time_elements:
                candidate_time = time_element.get_attribute("for")
                print("candidate time is :", candidate_time)
                if self.scraper.element_class_checker(time_element, time_selectable_class):
                    self.scraper.click_by_java_script(element=time_element)
                    if self.scraper.element_class_checker(time_element, time_selected_class):
                        selected_time = candidate_time
                        is_time_selected = True
                        print("one time is selected : " + str(selected_time))
                        break
        else:
            print("there are not any available times ")
        if is_time_selected:
            result = self.scraper.submit_form(form_id="timeslot-form")
        return is_time_selected

    def nex_month_step(self):
        # go to the next month to find an available date
        print("clicking on next month...")
        self.scraper.click_element(focused_element_locator="//*[@class='calendar-header']/a[@title='next month']",
                                   clicking_method="JAVA_SCRIPT")

    def previous_month_step(self):
        # go to the previous month to find an available date
        print("clicking on previous month...")
        self.scraper.click_element(focused_element_locator="//*[@class='calendar-header']/a[@title='previous month']",
                                   clicking_method="JAVA_SCRIPT")


def read_file(file_name):
    try:
        with open(file_name, "r") as fh:
            data = fh.read()
            return data
    except Exception as e:
        print(e)

def remove_attributes(record, indices):
    new_record = [i for j, i in enumerate(record) if j not in indices]
    return new_record


from tqdm.auto import tqdm
import concurrent.futures
from multiprocessing import Pool
import copy,os,sys
from collections import Counter,deque
import itertools
import os
import time
import tensorflow as tf
import tensorflow_hub as hub
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from PIL import Image
import pandas as pd
import subprocess
import dlib

# IMAGE_SHAPE = (96,96)
IMAGE_SHAPE = (224,224)
IMAGE_SHAPE = (299,299)
batch_size = 32
validation_ratio=0.2
sample_dir = "./tmp/CV_clf/ethnicity/face/dlib_frontal_0.25"
label = ['Caucasoid','Mongoloid','Indian','Negroid']
# label = ['Caucasoid','Mongoloid']
# label = ['Indian','Negroid']
# label = ['CauMon','IndNeg']

augment_params={"horizontal_flip":True, "rotation_range":90}
# augment_params={}

ig_normal = tf.keras.preprocessing.image.ImageDataGenerator(validation_split=validation_ratio,rescale=1/255,**augment_params)

generic_params = dict(directory=sample_dir, classes=label, target_size=IMAGE_SHAPE, batch_size=batch_size)
normal_flow_train = ig_normal.flow_from_directory(subset='training', **generic_params)
normal_flow_valid = ig_normal.flow_from_directory(subset='validation', **generic_params)

for image_batch, label_batch in normal_flow_train:
    print("Image batch shape: ", image_batch.shape)
    print("Label batch shape: ", label_batch.shape)
    break
print(label)
# 重新加载一下iter
normal_flow_train.reset()
print(">>> 训练集分布：")
print(np.vstack(np.unique([i.split("/")[-2] for i in normal_flow_train.filepaths],return_counts=True)).T)
print(">>> 测试集分布：")
print(np.vstack(np.unique([i.split("/")[-2] for i in normal_flow_valid.filepaths],return_counts=True)).T)

class EthnicityM_inceptionV3_App(tf.keras.Model):
    def __init__(self, num_classes:int, fine_tuning:bool=False, scope:str=None, rate:float=0.1, **kwargs):
        if scope is None:
            scope=self.__class__.__name__
        super().__init__(name=scope, **kwargs)
        tf.keras.backend.set_learning_phase=True
        # featM
        xcep = tf.keras.applications.inception_v3.InceptionV3(weights='imagenet',include_top=False)
        self.featM = tf.keras.Model(inputs=xcep.input, outputs=xcep.layers[-1].output)
        self.featM.trainable=fine_tuning
        # avg pool
        self.avg_pool = tf.keras.layers.GlobalAveragePooling2D()
        # 全连接
        self.dropout1 = tf.keras.layers.Dropout(rate)
        self.prediction_layer = tf.keras.layers.Dense(num_classes,
                                                      activation='softmax',
                                                      kernel_regularizer=tf.keras.regularizers.l2(1e-4))
        self.FC=self.prediction_layer

    def call(self, inp, training=False):
        x = self.featM(inp)
        x = self.avg_pool(x)
        x = self.dropout1(x, training=training)
        x = self.prediction_layer(x)
        return x

    def build(self, input_shape, *args, **kwargs):
        self.inp_shape=input_shape[1:] # idx=0元素是batch_size，不取
        super().build(input_shape,*args,**kwargs)

    def summary(self):
        x = tf.keras.Input(shape=self.inp_shape)
        tf.keras.Model(inputs=[x], outputs=self.call(x)).summary()

model=EthnicityM_inceptionV3_App(num_classes=normal_flow_train.num_classes, fine_tuning=True)
model.build((None,)+IMAGE_SHAPE+(3,))
model.summary()
# model.model().summary()

checkpoint_dir = "./tmp/CV_clf/ethnicity/ckpt_Subclass_KerasApp"

model.featM.trainable = False
print(f"trainable:{model.featM.trainable}")
bn=[i for i in model.featM.layers if type(i).__name__ =="BatchNormalization"][0]
print(">>> fit前")
for i in [(i.name, np.mean(i.numpy()),np.std(i.numpy())) for i in bn.variables]:
    print(i)
model.featM.compile(optimizer=tf.keras.optimizers.Adam(), loss="categorical_crossentropy", metrics=['acc'])
model.featM.fit(x=normal_flow_train.next()[0],y=np.ones((normal_flow_train.batch_size,1,1,2048)))
print(">>> fit后")
for i in [(i.name, np.mean(i.numpy()),np.std(i.numpy())) for i in bn.variables]:
    print(i)


#usage: python find_circular_fast.py contigs.fasta 150 2 contigs
## the last argument is either 'ids' or 'contigs'
import sys
from Bio import SeqIO

try:
  import edlib
except:
  print("ERROR: PLEASE RUN pip install edlib")
  sys.exit(1)

#read_length is 2nd argument; default 150 bp
try:
  read_length = int(sys.argv[2])
except:
  read_length = 150

# Max # of mismatches is 3rd argument; default 3
try:
  mismatch = int(sys.argv[3])
except:
  mismatch = 3

#FASTA file is 1st argument
for rec in SeqIO.parse(sys.argv[1], 'fasta'):

  start = str(rec.seq[:read_length])
  end = str(rec.seq[len(rec.seq)-read_length:])

  if edlib.align(start,end)['editDistance'] <= mismatch:
    if sys.argv[4] == 'contigs':
      print(">" + str(rec.id))
      print(str(rec.seq))
    else:
      print(rec.id)


#####
# Monocular Depth Mapping code demo found at https://github.com/niconielsen32/ComputerVision/blob/master/monocularDepthAI/monocularDepth.py
# Model from https://github.com/isl-org/MiDaS/releases/tag/v2_1
#####
import numpy as np
import cv2
import time

path_model = "models/"

# The floor plane should have an x_gradient ~ 0 and a y_gradient > 0
x_lt_threshold = 0.05
y_gt_threshold = 0.25
y_lt_threshold = 0.8

# Minimum area to allow floor find
area_threshold = 25000

##############################
# Load Monocular Depth Model #
##############################
# Load MiDas nueral network model for monocular depth mapping
def loadMonocularDepthModel():
  print("Loading Monocular Depth Model...")
  # Read Network
  model_name = "model-f6b98070.onnx"; # MiDaS v2.1 Large

  # Load the DNN model
  model = cv2.dnn.readNet(path_model + model_name)

  if (model.empty()):
      print("Could not load the neural net! - Check path")
      exit

  # Set backend and target to CUDA to use GPU
  model.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
  model.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)

  return model

#############
# Depth Map #
#############
def depthMap(img, model):
  imgHeight, imgWidth, channels = img.shape
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

  # Create Blob from Input Image
  # MiDaS v2.1 Large ( Scale : 1 / 255, Size : 384 x 384, Mean Subtraction : ( 123.675, 116.28, 103.53 ), Channels Order : RGB )
  blob = cv2.dnn.blobFromImage(img, 1/255., (384,384), (123.675, 116.28, 103.53), True, False)

  # Set input to the model
  model.setInput(blob)

  # Make forward pass in model
  depth_map = model.forward()

  depth_map = depth_map[0,:,:]
  depth_map = cv2.resize(depth_map, (imgWidth, imgHeight))

  # Normalize the depth_map
  depth_map = cv2.normalize(depth_map, None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

  return depth_map

#############
# Gradients #
#############
# Absolute value shows gradient both ways (values range from 0 to 1)
def gradients(depth_map):
  sobelx64f = cv2.Sobel(depth_map,cv2.CV_64F,1,0,ksize=5)
  sobelx = np.absolute(sobelx64f)
  sobely64f = cv2.Sobel(depth_map,cv2.CV_64F,0,1,ksize=5)
  sobely = np.absolute(sobely64f)
  return sobelx, sobely

###############################
# Find Candidate Floor Pixels #
###############################
def findCandidateFloorPixels(grad_x, grad_y):
  imgHeight, imgWidth = grad_x.shape
  is_floor = np.zeros((imgHeight, imgWidth), np.uint8)

  for i, row in enumerate(grad_x):
    for j, pixel in enumerate(grad_x[0]):
      if grad_x[i][j] < x_lt_threshold and grad_y[i][j] > y_gt_threshold and grad_y[i][j] < y_lt_threshold:
        is_floor[i][j] = 255

  return is_floor

###################
# Threshold Floor #
###################
def thresholdFloor(floor):
  thresh_floor = floor.copy()
  window_size = 12
  threshold = 0.95
  for i in range(0, thresh_floor.shape[0], window_size):
    for j in range(0, thresh_floor.shape[1], window_size):
      if sum(thresh_floor[i:i+window_size, j:j+window_size].flatten()) / (255*window_size*window_size) > threshold:
        thresh_floor[i:i+window_size, j:j+window_size] = 1
      else:
        thresh_floor[i:i+window_size, j:j+window_size] = 0
  ret, thresh = cv2.threshold(thresh_floor,0,255,cv2.THRESH_BINARY)
  return thresh

###################
# Center of Floor #
###################
def centerOfFloor(thresh_floor):
  largest_section = thresh_floor.copy()

  contours, hierarchy = cv2.findContours(largest_section,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
  if not contours:
    return (0, 0), largest_section

  blob = max(contours, key=cv2.contourArea)
  #print(cv2.contourArea(blob))

  mask = np.zeros_like(largest_section)
  cv2.fillPoly(mask,[blob],1)

  largest_section = np.multiply(largest_section, mask)

  moments = cv2.moments(blob)
  if cv2.contourArea(blob) > area_threshold and moments["m00"] != 0:
    cX = int(moments["m10"] / moments["m00"])
    cY = int(moments["m01"] / moments["m00"])
  else:
    cX, cY = 0, 0

  return (cX, cY), largest_section

##############
# Find Floor #
##############
# Main function to call into
# Returns center point of largest floor section found in pixel location (x from left, y from top)
# Set should_render to True to see images of each step
#
# Steps:
# 1. Extract depth map
# 2. Calculate x/y gradients
# 3. Find candidate floor pixels
# 4. Threshold floor candidates
# 5. Extract largest floor section
# 6. Find center of largest floor section
def findFloor(img, should_render = False):
      # start time to calculate FPS
      start = time.perf_counter()

      depth_map = depthMap(img, model)
      grad_x, grad_y = gradients(depth_map)
      is_floor = findCandidateFloorPixels(grad_x, grad_y)
      thresh_floor = thresholdFloor(is_floor)
      center, largest_section = centerOfFloor(thresh_floor)

      # End time
      end = time.perf_counter()
      # calculate the FPS for current frame detection
      fps = 1 / (end-start)

      if should_render:
        # Show FPS
        #cv2.putText(img, f"{fps:.2f} FPS", (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
        grad_xy = np.concatenate((grad_x, grad_y), axis=1)
        # cv2.imshow('RGB Image', img) # Image without center crosshair
        cv2.imshow('Depth Map', depth_map)
        cv2.imshow('Gradient x/y', grad_xy)
        cv2.imshow('Floor Candidate Pixels', is_floor)
        cv2.imshow('Floor After Thresholding', thresh_floor)
        cv2.imshow('Largest Section of Floor', largest_section)

        cv2.line(img, (center[0] - 15, center[1]), (center[0] + 15, center[1]), (0, 0, 255), 4)
        cv2.line(img, (center[0], center[1] - 15), (center[0], center[1] + 15), (0, 0, 255), 4)
        cv2.imshow('Center of Floor', img) # Image with center crosshair

      return center

##############
# Load Model #
##############
# Must be performed before running the Find Floor algorithm
model = loadMonocularDepthModel()


from collections import defaultdict

class Solution:
    def countCharacters(self, words: List[str], chars: str) -> int:
        chars_dict = defaultdict(lambda: 0)
        result = 0

        for word in words:
            count = 0
            for char in chars:
                chars_dict[char] += 1
            for char in word:
                if chars_dict[char] > 0:
                    chars_dict[char] -= 1
                    count += 1
                else:
                    break
            if count == len(word):
                result += count
            chars_dict.clear()
        return result


"""Panda package management for Windows.

DC/OS package configuration files manager definition.
"""
from pathlib import Path
import tempfile as tf

import jinja2 as j2

from cfgm import exceptions as cfgm_exc
from common import logger
from common.storage import ISTOR_NODE
from common.utils import transfer_files
from core import constants as cr_const
from core import exceptions as cr_exc
from core.package.manifest import PackageManifest
from core.rc_ctx import ResourceContext

LOG = logger.get_logger(__name__)

class PkgConfManager:
    """DC/OS package configuration files manager."""

    def __init__(self, pkg_manifest: PackageManifest):
        """Constructor.

        :param pkg_manifest: PackageManifest, DC/OS package manifest object
        """
        self.msg_src = self.__class__.__name__
        self._pkg_manifest = pkg_manifest

    def __str__(self):
        return str(f'{self.__class__.__name__}({self._pkg_manifest})')

    def setup_conf(self):
        """Setup configuration objects for a DC/OS package."""
        pkg_id = self._pkg_manifest.pkg_id
        pkg_cfg_dpath = getattr(
            self._pkg_manifest.istor_nodes, ISTOR_NODE.PKGREPO
        ).joinpath(pkg_id.pkg_id, cr_const.PKG_CFG_DNAME)
        LOG.debug(f'{self.msg_src}: Setup configuration: {pkg_id.pkg_name}:'
                  f' Source directory path: {pkg_cfg_dpath}')

        config_dir = getattr(self._pkg_manifest.istor_nodes, ISTOR_NODE.CFG)
        pkg_shrcfg_dpath = config_dir.joinpath(pkg_id.pkg_name)
        LOG.debug(f'{self.msg_src}: Setup configuration: {pkg_id.pkg_name}:'
                  f' Destination directory path: {pkg_shrcfg_dpath}')

        pkg_context = self._pkg_manifest.context

        if pkg_cfg_dpath.exists():
            # Check source is a directory
            if pkg_cfg_dpath.is_symlink():
                err_msg = (f'Source directory: Symlink conflict:'
                           f' {pkg_cfg_dpath}')
                raise cfgm_exc.PkgConfInvalidError(err_msg)
            elif pkg_cfg_dpath.is_reserved():
                err_msg = (f'Source directory: Reserved name conflict:'
                           f' {pkg_cfg_dpath}')
                raise cfgm_exc.PkgConfInvalidError(err_msg)
            elif not pkg_cfg_dpath.is_dir():
                err_msg = (f'Source directory: Not a directory:'
                           f' {pkg_cfg_dpath}')
                raise cfgm_exc.PkgConfInvalidError(err_msg)

            # Ensure destination exists and is a directory
            try:
                pkg_shrcfg_dpath.mkdir(parents=True, exist_ok=True)
            except FileExistsError:
                raise cr_exc.InstallationStorageError(
                    f'Setup configuration: {pkg_id.pkg_name}:'
                    f' {pkg_shrcfg_dpath} exists but is not a directory'
                )

            try:
                with tf.TemporaryDirectory(dir=str(config_dir)) as tdp:

                    self._process_pkgconf_srcdir(
                        src_dpath=pkg_cfg_dpath,
                        tmp_dpath=Path(tdp),
                        context=pkg_context
                    )
                    transfer_files(tdp, str(pkg_shrcfg_dpath))
                    LOG.debug(
                        f'{self.msg_src}: Setup configuration:'
                        f' {pkg_id.pkg_name}: Save: {pkg_shrcfg_dpath}: OK'
                    )
            except (OSError, RuntimeError) as e:
                err_msg = (f'Setup configuration: {pkg_id.pkg_name}:'
                           f' Process configuration sources:'
                           f' {pkg_cfg_dpath}: {type(e).__name__}: {e}')
                raise cfgm_exc.PkgConfManagerError(err_msg)
        else:
            err_msg = f'Source directory: Not found: {pkg_cfg_dpath}'
            raise cfgm_exc.PkgConfNotFoundError(err_msg)

    def _process_pkgconf_srcdir(self, src_dpath: Path, tmp_dpath: Path,
                                context=None):
        """Process (read, render, save) content of a DC/OS package
        configuration directory.

        :param src_dpath: Path, path to a source configuration
                          directory
        :param tmp_dpath: Path, path to a temporary directory to save
                          intermediate rendered content
        :param context:   ResourceContext, rendering context data object
        """
        if not src_dpath.exists():
            return

        if src_dpath.is_symlink():
            raise cfgm_exc.PkgConfInvalidError(f'Symlink conflict:'
                                               f' {src_dpath}')
        elif src_dpath.is_reserved():
            raise cfgm_exc.PkgConfInvalidError(f'Reserved name conflict:'
                                               f' {src_dpath}')
        elif not src_dpath.is_dir():
            raise cfgm_exc.PkgConfInvalidError(f'Not a directory:'
                                               f' {src_dpath}')
        else:
            for sub_path in src_dpath.iterdir():
                if sub_path.is_dir():
                    sub_tmp_dpath = tmp_dpath.joinpath(sub_path.name)
                    sub_tmp_dpath.mkdir()
                    self._process_pkgconf_srcdir(
                        src_dpath=sub_path,
                        tmp_dpath=sub_tmp_dpath,
                        context=context
                    )
                else:
                    self._process_pkgconf_srcfile(
                        src_fpath=sub_path,
                        tmp_dpath=tmp_dpath,
                        context=context
                    )

    def _process_pkgconf_srcfile(self, src_fpath: Path, tmp_dpath: Path,
                                 context: ResourceContext=None):
        """Process DC/OS package configuration source file.

        :param src_fpath: Path, path to a source configuration file
        :param tmp_dpath: Path, path to a temporary directory to save
                          intermediate rendered content
        :param context:   ResourceContext, rendering context data object
        """
        if '.j2' in src_fpath.suffixes[-1:]:
            dst_fname = src_fpath.stem
            json_ready = '.json' in src_fpath.suffixes[-2:-1]
        else:
            dst_fname = src_fpath.name
            json_ready = '.json' in src_fpath.suffixes[-1:]

        try:
            j2_env = j2.Environment(
                loader=j2.FileSystemLoader(str(src_fpath.parent))
            )
            j2_tmpl = j2_env.get_template(str(src_fpath.name))
            context_items = {} if context is None else context.get_items(
                json_ready=json_ready)
            rendered_str = j2_tmpl.render(**context_items)
            dst_fpath = tmp_dpath.joinpath(dst_fname)
            LOG.debug('Render file %s -> %s', src_fpath, dst_fpath)
            dst_fpath.write_text(rendered_str, encoding='utf-8')
        except (FileNotFoundError, j2.TemplateNotFound) as e:
            err_msg = f'Load: {src_fpath}'
            raise cfgm_exc.PkgConfFileNotFoundError(err_msg) from e
        except (OSError, RuntimeError) as e:
            err_msg = f'Load: {src_fpath}: {type(e).__name__}: {e}'
            raise cfgm_exc.PkgConfError(err_msg) from e
        except j2.TemplateError as e:
            err_msg = f'Load: {src_fpath}: {type(e).__name__}: {e}'
            raise cfgm_exc.PkgConfFileInvalidError(err_msg) from e


def summer_69(arr):
    result = 0
    for i in range(0, len(arr)):
        if arr[i] == 6 or arr[i] == 7 or arr[i] == 8 or arr[i] == 9:
            continue
        result += arr[i]
    return result

print(summer_69([2, 1, 6, 9, 11]))