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

# In[2]:

import pandas as pd
import numpy as np
my_array = np.array([['Montgomery','Yellohammer state',52423],
                     ['Sacramento','Golden state',163707],
                     ['Oklahoma City','Sooner state',69960 ]])
b=pd.DataFrame(my_array)
b

# In[3]:

b.columns=['a1','b1','c1']
b.index=['cal','bos','ny']
b

# In[5]:

names = ['George',
         'John',
         'Thomas',
         'James',
         'Andrew',
         'Martin',
         'William',
         'Zachary',
         'Millard',
         'Franklin']
data=pd.DataFrame(index=names)
print(data)

# In[28]:

data['country']=['USA','CAN','USA','IND','IND','GRE','GER','NETH','UK','GER']
data['country']

# In[33]:

data['ad_views'] = [16, 42, 32, 13, 63, 19, 65, 23, 16, 77]
data['items_purchased'] = [2, 1, 0, 8, 0, 5, 7, 3, 0, 5]
data['avg']=data['items_purchased']/data['ad_views']
print (data)
data['items_purchased']/data['ad_views']

# In[17]:

data.loc['George']

# In[20]:

data.loc[:,'ad_views']

# In[22]:

data.iloc[2:6,2]

# data.loc[lambda b:data['items_purchased']>2,:]

# In[23]:

data.loc[lambda b:data['items_purchased']>2,:]

# In[27]:

data.loc[lambda c:data['ad_views']>10,:]

# In[25]:

data[data['items_purchased'] > 1]

# In[29]:

data.groupby('country')

# In[34]:

data.groupby('country')['ad_views'].aggregate(np.mean)

# In[35]:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
get_ipython().run_line_magic('matplotlib', 'inline')
plt.plot([0, 1, 2, 3])
plt.show()

# In[36]:

np.random.seed(1221)

# In[37]:

df = pd.DataFrame()

# In[38]:

df

# In[39]:

df['rand'] = np.random.rand(100)

# In[44]:

df['rand_sq'] = df['rand'] ** 2
df['rand_shift'] = df['rand'] + 2
df['counts_sq'] = df.index ** 2
df['counts_sqrt'] = np.sqrt(df.index)
df

# In[45]:

plt.plot(df['rand'])
plt.show()

# In[51]:

plt.plot(df['rand'], color='purple')
plt.plot(df['rand_shift'],color='green')
plt.ylim([-0.1, 4.1])
plt.ylabel('Values')
plt.title('Random Series')
plt.show()

# In[52]:

plt.scatter(x=df['rand'], y=df['rand_sq'])
plt.show()

# In[55]:

plt.scatter(
    x=df['rand'],
    y=df['rand_sq'],
    color='purple',
    marker='x', s=10
)
plt.scatter(
    x=df['rand'],
    y=df['rand_shift'],
    color='green',
    marker='x', s=10
)
plt.show()

# In[62]:

df.plot(kind='scatter', x='counts_sq',y= 'counts_sqrt')
df.plot(kind='line')
plt.show()

# In[63]:

plt.figure(figsize=(10, 5))

# In[64]:

plt

# In[65]:

plt.figure(figsize=(10, 5))

plt.subplot(1, 2, 1)
plt.plot(df['rand'], color='purple')
plt.ylabel('Values')
plt.title('Random Series')

# In[73]:

plt.figure(figsize=(10, 5))

plt.subplot(1, 2, 1)
plt.plot(df['rand'], color='purple')
plt.ylabel('Values')
plt.title('Random Series')

plt.subplot(1, 2, 2)
plt.scatter(x = df['rand_sq'], y = df['rand'], color='green')
plt.ylabel('Squared Values')
plt.title('Squared Series')

plt.tight_layout()
plt.show()

# In[74]:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
# Data to play with. Twice the histograms, twice the fun.
x = np.random.normal(10, 5, 1000)
y = np.random.normal(15, 5, 10000)

# Override bin defaults with specific bin bounds.
# FYI `alpha` controls the opacity.
plt.hist(x, color='blue', bins=np.arange(-10, 40), alpha=.5)
plt.hist(y, color='red', bins=np.arange(-10, 40), alpha=.5)
plt.title('Manually setting bin placement')
plt.xlabel('Random Values')

plt.show()

# In[2]:

import pandas as pd

# Make a blank data frame.
df = pd.DataFrame()

# Populate it with data.
df['age'] = [14, 12, 11, 10, 8, 6, 8]
import numpy as np

np.mean(df['age'])
import statistics

statistics.median(df['age'])

# Using NumPy.
#import numpy as np

#np.median(df['age'])

# In[5]:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
bernoulli= np.random.binomial(1, .5, 100)

#Plot a histogram.
plt.hist(bernoulli)
plt.axvline(bernoulli.mean(), color='b', linestyle='solid', linewidth=2)

# Add a vertical line at one standard deviation above the mean.
plt.axvline(bernoulli.mean() + bernoulli.std(), color='b', linestyle='dashed', linewidth=2)
# Print the histogram

# Print the histogram.

plt.show()

# In[9]:

binomial = np.random.binomial(20, 0.5, 100)

# Plot a histogram.
plt.hist(binomial)
plt.axvline(binomial.mean(), color='b', linestyle='solid', linewidth=2)

# Add a vertical line at one standard deviation above the mean.
plt.axvline(binomial.mean() + binomial.std(), color='b', linestyle='dashed', linewidth=2)
plt.show()

# In[10]:

gamma = np.random.gamma(5,1, 100)
plt.axvline(gamma.mean(), color='b', linestyle='solid', linewidth=2)

# Add a vertical line at one standard deviation above the mean.
plt.axvline(gamma.mean() + gamma.std(), color='b', linestyle='dashed', linewidth=2)
# Plot a histogram.
plt.hist(gamma)

# Print the histogram.
plt.show()

# In[11]:

poisson = np.random.poisson(3, 100)
plt.axvline(poisson.mean(), color='b', linestyle='solid', linewidth=2)

# Add a vertical line at one standard deviation above the mean.
plt.axvline(poisson.mean() + poisson.std(), color='b', linestyle='dashed', linewidth=2)
# Plot a histogram.
plt.hist(poisson)

# Print the histogram.
plt.show()

# In[12]:

norm1 = np.random.normal(5, 0.5, 1000)
norm2 = np.random.normal(10, 1, 1000)
third=norm1+norm2
mean = np.mean(third)
sd = np.std(third)
plt.hist(third)
plt.axvline(third.mean(), color='b', linestyle='solid', linewidth=2)

# Add a vertical line at one standard deviation above the mean.
plt.axvline(third.mean() + third.std(), color='b', linestyle='dashed', linewidth=2)
plt.axvline(third.mean()-third.std(), color='b', linestyle='dashed', linewidth=2)
plt.show()

# In[23]:

pop1 = np.random.binomial(10, 0.2, 10000)
pop2 = np.random.binomial(10,0.5, 10000)

# Let’s make histograms for the two groups.

plt.hist(pop1, alpha=0.5, label='Population 1')
plt.hist(pop2, alpha=0.5, label='Population 2')
plt.legend(loc='upper right')
plt.show()
sample1 = np.random.choice(pop1, 1000, replace=True)
sample2 = np.random.choice(pop2, 1000, replace=True)

plt.hist(sample1, alpha=0.5, label='sample 1')
plt.hist(sample2, alpha=0.5, label='sample 2')
plt.legend(loc='upper right')
plt.show()
print(sample1.mean())
print(sample2.mean())
print(sample1.std())
print(sample2.std())
sample1 = np.random.choice(pop1, 20, replace=True)
sample2 = np.random.choice(pop2, 20, replace=True)

plt.hist(sample1, alpha=0.5, label='sample 1')
plt.hist(sample2, alpha=0.5, label='sample 2')
plt.legend(loc='upper right')
plt.show()
print(sample1.mean())
print(sample2.mean())
print(sample1.std())
print(sample2.std())

# In[24]:

pop1 = np.random.binomial(10, 0.3, 10000)
pop2 = np.random.binomial(10,0.5, 10000)

# Let’s make histograms for the two groups.

plt.hist(pop1, alpha=0.5, label='Population 1')
plt.hist(pop2, alpha=0.5, label='Population 2')
plt.legend(loc='upper right')
plt.show()
sample1 = np.random.choice(pop1, 100, replace=True)
sample2 = np.random.choice(pop2, 100, replace=True)

plt.hist(sample1, alpha=0.5, label='sample 1')
plt.hist(sample2, alpha=0.5, label='sample 2')
plt.legend(loc='upper right')
plt.show()
from scipy.stats import ttest_ind
print(ttest_ind(sample2, sample1, equal_var=False))

# In[22]:

pop1 = np.random.binomial(10, 0.4, 10000)
pop2 = np.random.binomial(10,0.5, 10000)

# Let’s make histograms for the two groups.

plt.hist(pop1, alpha=0.5, label='Population 1')
plt.hist(pop2, alpha=0.5, label='Population 2')
plt.legend(loc='upper right')
plt.show()
sample1 = np.random.choice(pop1, 100, replace=True)
sample2 = np.random.choice(pop2, 100, replace=True)

plt.hist(sample1, alpha=0.5, label='sample 1')
plt.hist(sample2, alpha=0.5, label='sample 2')
plt.legend(loc='upper right')
plt.show()
from scipy.stats import ttest_ind
print(ttest_ind(sample2, sample1, equal_var=False))

# In[ ]:


import os
from pathlib import Path
import pytest  # type: ignore
from openstates.cli.legacy_people_to_yaml import (
    reformat_phone_number,
    reformat_address,
    compute_merge,
    Append,
    Replace,
    merge_people,
    merge_contact_details,
    find_file,
)
from openstates.models.people import OtherName, OtherIdentifier, ContactDetail
from pydantic import BaseModel

@pytest.mark.parametrize(
    "input,output",
    [
        ("1234567890", "123-456-7890"),
        ("123-456-7890", "123-456-7890"),
        ("1-123-456-7890", "1-123-456-7890"),
        ("+1-123-456-7890", "1-123-456-7890"),
        ("1-800-FAKENUM", "1-800-FAKENUM"),
        ("email@example.com", "email@example.com"),
        ("555.333.1111", "555-333-1111"),
        ("+1 (555) 333-1111", "1-555-333-1111"),
        ("555-333-1111 ext.100", "555-333-1111 ext. 100"),
        ("555.333.1111 EXT.100", "555-333-1111 ext. 100"),
    ],
)
def test_reformat_phone(input, output):
    assert reformat_phone_number(input) == output

@pytest.mark.parametrize(
    "input,output",
    [
        ("123 Maple Lane\nRaleigh, NC 27511", "123 Maple Lane;Raleigh, NC 27511"),
        (
            "123 Maple Lane   \n   Raleigh, NC    27511",
            "123 Maple Lane;Raleigh, NC 27511",
        ),
        ("123 Maple Lane\n \nRaleigh, NC 27511", "123 Maple Lane;Raleigh, NC 27511"),
    ],
)
def test_reformat_address(input, output):
    assert reformat_address(input) == output

@pytest.mark.parametrize(
    "a, b, output",
    [
        # no diff
        ({"a": "one", "b": "two"}, {"a": "one", "b": "two"}, []),
        # simple difference
        (
            {"a": "one", "b": "two"},
            {"a": "bad", "b": "two"},
            [Replace("a", "one", "bad")],
        ),
        # missing key from first
        ({"a": "one"}, {"a": "one", "b": "two"}, [Replace("b", None, "two")]),
        # missing key from second
        ({"a": "one", "b": "two"}, {"a": "one"}, []),
    ],
)
def test_compute_merge_simple(a, b, output):
    class Model(BaseModel):
        a: str = None
        b: str = None

    assert compute_merge(Model(**a), Model(**b)) == output

@pytest.mark.parametrize(
    "a, b, output",
    [
        # no diff
        ({"a": {"b": "c"}}, {"a": {"b": "c"}}, []),
        # nothing new on right
        ({"a": {"b": "c"}}, {"a": {}}, []),
        # replace
        ({"a": {}}, {"a": {"b": "c"}}, [Replace("a.b", None, "c")]),
    ],
)
def test_compute_merge_nested(a, b, output):
    class Inner(BaseModel):
        b: str = None

    class Model(BaseModel):
        a: Inner = None

    assert compute_merge(Model(**a), Model(**b)) == output

@pytest.mark.parametrize(
    "a, b, output",
    [
        # no errors
        ({"a": [{"b": 1}, {"c": 2}]}, {"a": [{"b": 1}, {"c": 2}]}, []),
        # no errors - just different order
        ({"a": [{"b": 1}, {"c": 2}]}, {"a": [{"c": 2}, {"b": 1}]}, []),
        # extra item left
        ({"a": [{"b": 1}, {"c": 2}, {"d": 3}]}, {"a": [{"b": 1}, {"c": 2}]}, []),
        # extra item right
        (
            {"a": [{"b": 1}, {"c": 2}]},
            {"a": [{"b": 1}, {"c": 2}, {"d": 3}]},
            [Append("a", {"d": 3})],
        ),
    ],
)
def test_compute_merge_list(a, b, output):
    class Model(BaseModel):
        a: list[dict]

    assert compute_merge(Model(**a), Model(**b)) == output

@pytest.mark.parametrize(
    "a, b, keep_both, output",
    [
        # discard id
        ({"id": "1"}, {"id": "2"}, False, []),
        # keep id
        (
            {"id": "1"},
            {"id": "2"},
            True,
            [
                Append(
                    "other_identifiers",
                    OtherIdentifier(identifier="2", scheme="openstates"),
                )
            ],
        ),
        # append name
        (
            {"name": "A"},
            {"name": "B"},
            True,
            [Append("other_names", OtherName(name="A")), Replace("name", "A", "B")],
        ),
    ],
)
def test_compute_merge_special_cases(a, b, keep_both, output):
    class Model(BaseModel):
        id: str = None
        name: str = ""

    assert compute_merge(Model(**a), Model(**b), keep_both_ids=keep_both) == output

@pytest.mark.parametrize(
    "old, new, expected",
    [
        # no changes
        ({"name": "Anna"}, {"name": "Anna"}, {"name": "Anna"}),
        # field only in old
        (
            {"name": "Anna", "birth_date": "1980"},
            {"name": "Anna"},
            {"name": "Anna", "birth_date": "1980"},
        ),
        # field only in new
        (
            {"name": "Anna"},
            {"name": "Anna", "birth_date": "1980"},
            {"name": "Anna", "birth_date": "1980"},
        ),
        # special: name field differs
        (
            {"name": "Bob"},
            {"name": "Robert"},
            {"name": "Robert", "other_names": [OtherName(name="Bob")]},
        ),
    ],
)
def test_simple_merge(old, new, expected):
    class Model(BaseModel):
        name: str
        birth_date: str = ""
        other_names: list[OtherName] = []

    assert merge_people(Model(**old), Model(**new)) == Model(**expected)

@pytest.mark.parametrize(
    "old, new, expected",
    [
        # more in first list
        (
            {"other_names": [{"name": "A"}, {"name": "B"}]},
            {"other_names": [{"name": "A"}]},
            {"other_names": [{"name": "A"}, {"name": "B"}]},
        ),
        # more in second list
        (
            {"other_names": [{"name": "A"}]},
            {"other_names": [{"name": "A"}, {"name": "B"}]},
            {"other_names": [{"name": "A"}, {"name": "B"}]},
        ),
        # each list is unique
        (
            {"other_names": [{"name": "A"}]},
            {"other_names": [{"name": "B"}]},
            {"other_names": [{"name": "A"}, {"name": "B"}]},
        ),
    ],
)
def test_list_merge(old, new, expected):
    class Model(BaseModel):
        other_names: list[OtherName] = []

    # note that keep doesn't matter for these
    assert merge_people(Model(**old), Model(**new), None) == Model(**expected)

@pytest.mark.parametrize(
    "old, new, expected",
    [
        # simplest case
        (
            {"id": "ocd-person/1"},
            {"id": "ocd-person/2"},
            {
                "id": "ocd-person/1",
                "other_identifiers": [
                    OtherIdentifier(scheme="openstates", identifier="ocd-person/2")
                ],
            },
        ),
        # already has identifiers
        (
            {
                "id": "ocd-person/1",
                "other_identifiers": [
                    OtherIdentifier(scheme="openstates", identifier="ocd-person/0")
                ],
            },
            {"id": "ocd-person/2"},
            {
                "id": "ocd-person/1",
                "other_identifiers": [
                    OtherIdentifier(scheme="openstates", identifier="ocd-person/0"),
                    OtherIdentifier(scheme="openstates", identifier="ocd-person/2"),
                ],
            },
        ),
    ],
)
def test_keep_both_ids(old, new, expected):
    class Model(BaseModel):
        id: str
        other_identifiers: list[OtherIdentifier] = []

    assert merge_people(Model(**old), Model(**new), keep_both_ids=True) == Model(
        **expected
    )

@pytest.mark.parametrize(
    "old, new",
    [
        (
            [ContactDetail(note="Capitol Office", voice="123-555-9999")],
            [ContactDetail(note="Capitol Office", voice="123-555-9999")],
        ),
        (
            [
                ContactDetail(note="Capitol Office", voice="123-555-9999"),
                ContactDetail(note="District Office", address="abc"),
            ],
            [
                ContactDetail(note="Capitol Office", voice="123-555-9999"),
                ContactDetail(note="District Office", address="abc"),
            ],
        ),
    ],
)
def test_merge_contact_details_no_change(old, new):
    assert merge_contact_details(old, new) is None

@pytest.mark.parametrize(
    "old, new, expected",
    [
        # replace a value with a new one
        (
            [ContactDetail(note="Capitol Office", voice="111-111-1111")],
            [ContactDetail(note="Capitol Office", voice="222-222-2222")],
            [ContactDetail(note="Capitol Office", voice="222-222-2222")],
        ),
        # merge two partial records
        (
            [ContactDetail(note="Capitol Office", voice="111-111-1111")],
            [ContactDetail(note="Capitol Office", fax="444-444-4444")],
            [
                ContactDetail(
                    note="Capitol Office", voice="111-111-1111", fax="444-444-4444"
                )
            ],
        ),
        # merge two offices into a single list
        (
            [ContactDetail(note="Capitol Office", voice="111-111-1111")],
            [ContactDetail(note="District Office", voice="444-444-4444")],
            [
                ContactDetail(note="Capitol Office", voice="111-111-1111"),
                ContactDetail(note="District Office", voice="444-444-4444"),
            ],
        ),
    ],
)
def test_merge_contact_details_changes(old, new, expected):
    assert merge_contact_details(old, new) == expected

def test_merge_extras():
    # replace was adding a key like extras._internal_id
    old = {"extras": {"_internal_id": 123}}
    new = {}
    expected = old.copy()

    class Model(BaseModel):
        extras: dict = {}

    assert merge_people(Model(**new), Model(**old)) == expected

def test_find_file_good():
    os.environ["OS_PEOPLE_DIRECTORY"] = str(Path(__file__).parent / "testdata/people")
    filename = find_file("a2e4a1b2-f0fd-4c35-9e0c-bb009778792f", state="pa")
    assert "Pam-Snyder" in str(filename)
    filename = find_file("a2e4a1b2-f0fd-4c35-9e0c-bb009778792f")
    assert "Pam-Snyder" in str(filename)

def test_find_file_missing():
    with pytest.raises(FileNotFoundError):
        find_file("77777777-ffff-0000-9000-bbbbbbbbbbbb")
    # good file, bad directory
    with pytest.raises(FileNotFoundError):
        find_file("a2e4a1b2-f0fd-4c35-9e0c-bb009778792f", state="nc")


#views.py
# -*- coding: utf-8 -*-
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.shortcuts import render_to_response
from ujourney.forms import ContactForm, AddMessage
from django.views.decorators.csrf import csrf_protect
from django.core.mail import send_mail
import datetime, MySQLdb
from django.db import connection
from django.template import loader, Context

def current_datetime(request):
	now = datetime.datetime.now()
	html = "It is now %s." % now
	return HttpResponse(html)

def hours_ahead(request, offset):
	try:
		offset = int(offset)
	except ValueError:
		raise Http404()
	dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
	#assert False
	html = "In %s hour(s), it will be %s." % (offset, dt)
	return HttpResponse(html)

def display_meta(request):
	values = request.META.items()
	values.sort()
	html = []
	for k, v in values:
		html.append('
%s	%s
' % (k,v))
	return HttpResponse('
%s
' % '\n'.join(html))

def search_form(request):
	return render_to_response('base.html')

def search(request):
	if 'q' in request.GET:
		message = 'you search in: %r' % request.GET['q']
	else:
		message = 'you send a blank message.'
	return HttpResponse(message)

def blog_form(request):
	return render_to_response('blog.html')

def blog(request):
	if 'message' in request.GET and request.GET['message']:
		message = 'add: %r' % request.GET['message']
		return HttpResponse(message)
	else:
		return HttpResponse('Write you message')

def contact(request):
	if request.method == 'POST':
		form = ContactForm(request.POST)
		if form.is_valid():
			topic = form.cleaned_data['topic']
			message = form.cleaned_data['message']
			sender = form.cleaned_data.get('sender', 'noreply@example.com')
			#send_mail(
            #    'Feedback from your site, topic: %s' % topic,
            #    message, sender,
            #    ['administrator@example.com']
            #)
			return render_to_response('out.html', { 'form':form })
			#return HttpResponseRedirect('/contact/thanks/')
	else:
		form = ContactForm(
			initial={'topic':'I really like your site!'}
		)
	return render_to_response('forms.html', { 'form':form })

def my_list(request):
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM tester")
    out_rows = cursor.fetchall()
    tt = loader.get_template("archive.html")
    cc = Context({ 'out_rows':out_rows })
    return HttpResponse(tt.render(cc))

#forms.py

class PersonForm(forms.Form):
	first = forms.CharField(max_length=100, required=True)
	last = forms.CharField(max_length=100, required=True, initial='Smith')
	middle = forms.CharField(max_length=100)

class ContactForm(forms.Form):
	topic = forms.CharField(max_length=100)
	message = forms.CharField(widget=forms.Textarea)
	#sender = forms.EmailField(required=False, label="E-mail adress")

	def clean_message(self):
		message = self.cleaned_data['message']
		num_words = len(message.split())
		if num_words < 4:
			raise forms.ValidationError('Not enough words!')
		return message


## -*- coding: utf-8 -*-
# (C) 2020 முத்து அண்ணாமலை
# https://en.wikipedia.org/wiki/WX_notation
# Ref: https://github.com/irshadbhat/indic-wx-converter/blob/7ce1ac54b9df5ac8beed71c73e2e8b80b2eca65d/wxconv/wx.py#L2562
from collections import OrderedDict

from tamil.utf8 import uyirmei_letters, splitMeiUyir

_uyir = (
    ("அ", "A"),
    ("ஆ", ("A")),
    ("இ", "I"),
    ("ஈ", ("II")),
    ("உ", "U"),
    ("ஊ", ("UU")),
    ("எ", "E"),
    ("ஏ", ("EY")),
    ("ஐ", "AI"),
    ("ஒ", "O"),
    ("ஓ", ("OW")),
    ("ஔ", "AU"),
)
_aytham = (("ஃ", "H"),)
_mei = (
    ("க்", ("K")),
    ("ங்", "NG"),
    ("ச்", "CH"),
    ("ஜ்", "JA"),
    ("ஞ்", "nY"),
    ("ட்", ("d", "t")),
    ("ண்", "NAA"),
    ("த்", ("dh", "dt")),
    ("ந்", "N"),
    ("ன்", "NA"),
    ("ப்", ("b", "bh", "p")),
    ("ம்", "m"),
    ("ய்", "y"),
    ("ர்", "r"),
    ("ற்", "R"),
    ("ல்", "l"),
    ("ள்", "L"),
    ("ழ்", ("z", "zh")),
    ("வ்", ("v", "w")),
    ("ஷ்", "sh"),
    ("ஸ்", "s"),
    ("ஹ்", "h"),
    ("ஃப்", "f"),
)

class Transliteration:
    """
    ITRANS encoding formats.
    """

    table = OrderedDict()  # {}

def _options(_ref, _sym):
    _v = []
    for _k, _v in _ref:
        if _k == _sym:
            break
    return _v

for ta_map in [_uyir, _mei, _aytham]:
    for obj in ta_map:
        ta, en = obj[0], obj[1]
        if not isinstance(en, (list, tuple)):
            en = list(en)
        for e in en:
            Transliteration.table[e] = ta

# mix of consonants and compound - uyirmei - letters
for vc in uyirmei_letters:
    c, v = splitMeiUyir(vc)
    for vo in _options(_uyir, v):
        for co in _options(_mei, c):
            if not Transliteration.table.get(co + vo, None):
                Transliteration.table[co + vo] = vc

from pprint import pprint

pprint(Transliteration.table)
print(len(Transliteration.table))


import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
import sys, os

from sklearn.preprocessing import OneHotEncoder

sys.path.append("../../../")
sys.path.extend([os.path.join(root, name) for root, dirs, _ in os.walk("../../../") for name in dirs])

class GBDTLR:
    def __init__(self, lr, gbdt, gbdt_enc):
        self.lr = lr
        self.gbdt = gbdt
        self.gbdt_enc = gbdt_enc

def load_dataset(path):
    df = pd.read_csv(path, header=None)
    df = df.dropna()
    X = df.drop([1824], axis=1)
    Y = df[1824]
    return X, Y

def load_model(*args, **kwargs):
    gbdt = GradientBoostingClassifier(n_estimators=10)
    """
    n_estimators,最大的弱学习器的个数，即有多少个回归树
    max_depth : int, default=3。每个回归树的的深度
    """
    gbdt_enc = OneHotEncoder()
    lr = LogisticRegression(max_iter=1000)
    model = GBDTLR(lr, gbdt, gbdt_enc)
    return model

def train(model: GBDTLR, X, Y):
    model.gbdt.fit(X, Y)
    model.gbdt_enc.fit(model.gbdt.apply(X)[:, :, 0])
    model.lr.fit(model.gbdt_enc.transform(model.gbdt.apply(X)[:, :, 0]), Y)

def predict(model, X):
    y_pred_gbdt_lr = model.lr.predict_proba(
        model.gbdt_enc.transform(model.gbdt.apply(X)[:, :, 0]))[:, 1]
    return y_pred_gbdt_lr

def run():
    # 加载数据
    X, Y = load_dataset()
    # 加载模型
    model = load_model()
    # 训练数据
    train(model, X, Y)


# -*- coding: utf-8 -*-
"""
PubChemPy

Python interface for the PubChem PUG REST service.
https://github.com/mcs07/PubChemPy
"""

import json
import os
import time

from .mapper import PROPERTY_MAP

from urllib.error import HTTPError
from urllib.parse import quote, urlencode
from urllib.request import urlopen
from .errors import PubChemHTTPError, NotFoundError
import re
from .logger import createLogger

log = createLogger(__name__)

API_BASE = 'https://pubchem.ncbi.nlm.nih.gov/rest/pug'
API_VIEW = 'https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound'

text_types = str, bytes

def request(identifier, namespace='cid', domain='compound', operation=None, output='JSON', searchtype=None, **kwargs):
    """
    Construct API request from parameters and return the response.

    Full specification at http://pubchem.ncbi.nlm.nih.gov/pug_rest/PUG_REST.html
    """
    if not identifier:
        raise ValueError('identifier/cid cannot be None')
    # If identifier is a list, join with commas into string
    if isinstance(identifier, int):
        identifier = str(identifier)
    if not isinstance(identifier, text_types):
        identifier = ','.join(str(x) for x in identifier)
    # Filter None values from kwargs
    kwargs = dict((k, v) for k, v in kwargs.items() if v is not None)
    # Build API URL
    urlid, postdata = None, None
    if namespace == 'sourceid':
        identifier = identifier.replace('/', '.')
    if namespace in ['listkey', 'formula', 'sourceid'] \
            or searchtype == 'xref' \
            or (searchtype and namespace == 'cid') or domain == 'sources':
        urlid = quote(identifier.encode('utf8'))
    else:
        postdata = urlencode([(namespace, identifier)]).encode('utf8')
    comps = filter(None, [API_BASE, domain, searchtype, namespace, urlid, operation, output])
    apiurl = '/'.join(comps)
    if kwargs:
        apiurl += '?%s' % urlencode(kwargs)
    # Make request
    try:
        # log.debug('Request URL: %s', apiurl)
        # log.debug('Request data: %s', postdata)
        response = urlopen(apiurl, postdata)
        return response
    except HTTPError as e:
        raise PubChemHTTPError(e)

def get(identifier, namespace='cid', domain='compound', operation=None, output='JSON', searchtype=None, **kwargs):
    """Request wrapper that automatically handles async requests."""
    if (searchtype and searchtype != 'xref') or namespace in ['formula']:
        response = request(identifier, namespace, domain, None, 'JSON', searchtype, **kwargs).read()
        status = json.loads(response.decode())
        if 'Waiting' in status and 'ListKey' in status['Waiting']:
            identifier = status['Waiting']['ListKey']
            namespace = 'listkey'
            while 'Waiting' in status and 'ListKey' in status['Waiting']:
                time.sleep(2)
                response = request(identifier, namespace, domain, operation, 'JSON', **kwargs).read()
                status = json.loads(response.decode())
            if not output == 'JSON':
                response = request(identifier, namespace, domain, operation, output, searchtype, **kwargs).read()
    else:
        response = request(identifier, namespace, domain, operation, output, searchtype, **kwargs).read()
    return response

def get_json(identifier, namespace='cid', domain='compound', operation=None, searchtype=None, **kwargs):
    """Request wrapper that automatically parses JSON response and supresses NotFoundError."""
    try:
        return json.loads(get(identifier, namespace, domain, operation, 'JSON', searchtype, **kwargs).decode())
    except NotFoundError as e:
        log.info(e)
        return None

def get_sdf(identifier, namespace='cid', domain='compound',operation=None, searchtype=None, **kwargs):
    """Request wrapper that automatically parses SDF response and supresses NotFoundError."""
    try:
        return get(identifier, namespace, domain, operation, 'SDF', searchtype, **kwargs).decode()
    except NotFoundError as e:
        log.info(e)
        return None

def get_properties(properties, identifier, namespace='cid', searchtype=None, as_dataframe=False, **kwargs):
    """Retrieve the specified properties from PubChem.

    :param identifier: The compound, substance or assay identifier to use as a search query.
    :param namespace: (optional) The identifier type.
    :param searchtype: (optional) The advanced search type, one of substructure, superstructure or similarity.
    :param as_dataframe: (optional) Automatically extract the properties into a pandas :class:`~pandas.DataFrame`.
    """
    if isinstance(properties, text_types):
        properties = properties.split(',')
    properties = ','.join([PROPERTY_MAP.get(p, p) for p in properties])
    properties = 'property/%s' % properties
    results = get_json(identifier, namespace, 'compound', properties, searchtype=searchtype, **kwargs)
    results = results['PropertyTable']['Properties'] if results else []
    if as_dataframe:
        import pandas as pd
        return pd.DataFrame.from_records(results, index='CID')
    return results

def get_synonyms(identifier, namespace='cid', domain='compound', searchtype=None, **kwargs):
    results = get_json(identifier, namespace, domain, 'synonyms', searchtype=searchtype, **kwargs)
    return results['InformationList']['Information'] if results else []

def get_cids(identifier, namespace='name', domain='compound', searchtype=None, **kwargs):
    results = get_json(identifier, namespace, domain, 'cids', searchtype=searchtype, **kwargs)
    if not results:
        return []
    elif 'IdentifierList' in results:
        return results['IdentifierList']['CID']
    elif 'InformationList' in results:
        return results['InformationList']['Information']

def get_sids(identifier, namespace='cid', domain='compound', searchtype=None, **kwargs):
    results = get_json(identifier, namespace, domain, 'sids', searchtype=searchtype, **kwargs)
    if not results:
        return []
    elif 'IdentifierList' in results:
        return results['IdentifierList']['SID']
    elif 'InformationList' in results:
        return results['InformationList']['Information']

def get_aids(identifier, namespace='cid', domain='compound', searchtype=None, **kwargs):
    results = get_json(identifier, namespace, domain, 'aids', searchtype=searchtype, **kwargs)
    if not results:
        return []
    elif 'IdentifierList' in results:
        return results['IdentifierList']['AID']
    elif 'InformationList' in results:
        return results['InformationList']['Information']

def get_all_sources(domain='substance'):
    """Return a list of all current depositors of substances or assays."""
    results = json.loads(get(domain, None, 'sources').decode())
    return results['InformationList']['SourceName']

def download(outformat, path, identifier, namespace='cid', domain='compound', operation=None, searchtype=None,
             overwrite=False, **kwargs):
    """Format can be  XML, ASNT/B, JSON, SDF, CSV, PNG, TXT."""
    response = get(identifier, namespace, domain, operation, outformat, searchtype, **kwargs)
    if not overwrite and os.path.isfile(path):
        raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % path)
    with open(path, 'wb') as f:
        f.write(response)

def _parse_prop(search, proplist):
    """Extract property value from record using the given urn search filter."""
    props = [i for i in proplist if all(item in i['urn'].items() for item in search.items())]
    if len(props) > 0:
        return props[0]['value'][list(props[0]['value'].keys())[0]]

def request_SDS(cid):
    if not cid:
        raise ValueError('identifier/cid cannot be None')
    # Make request
    try:
        log.debug('Request URL: %s', API_VIEW)
        log.debug('Request data: %s', cid)
        response = urlopen(API_VIEW + '/{}/JSON?heading=safety+and+hazards'.format(cid))
        return _parse_sds(json.loads(response.read().decode()))
    except HTTPError as e:
        log.info(e)
        raise PubChemHTTPError(e)

def _parse_sds(result):
    info = result["Record"]["Section"][0]["Section"][0]['Section'][0]['Information']
    pictogram = []
    hazard = []
    precautionary = []
    for resp in info:
        if resp['Name'] == 'Pictogram(s)':
            for picto in resp['Value']['StringWithMarkup'][0]['Markup']:
                pictObject = {"icon": picto['URL'].split('/')[-1], "string": picto['Extra']}
                if pictObject not in pictogram:
                    pictogram.append(pictObject)
        elif resp['Name'] == 'GHS Hazard Statements':
            for stat in resp["Value"]['StringWithMarkup']:
                if stat['String'][0] == "H" and stat['String'][1:4].isnumeric():
                    if stat['String'][0:4] not in hazard:
                        hazard.append(stat['String'][0:4])
                        hazard.sort()
        elif resp['Name'] == 'Precautionary Statement Codes':
            for codes in resp["Value"]["StringWithMarkup"]:
                r1 = re.findall(r"[P0-9+]{3,30}", codes['String'])
                if r1:
                    for ps in r1:
                        if ps not in precautionary:
                            precautionary.append(ps)
                            precautionary.sort()
    return {"pictogram": pictogram, "hazard": hazard, "precautionary": precautionary}


# -*- coding: utf-8 -*-
"""Interface to Lightnet object proposals."""
import copy
import logging
import os
import random
import time
from os.path import expanduser, join

import cv2
import numpy as np
import PIL
import tqdm
import utool as ut

from wbia import constants as const

(print, rrr, profile) = ut.inject2(__name__, '[densenet]')
logger = logging.getLogger('wbia')

PARALLEL = not const.CONTAINERIZED
INPUT_SIZE = 224

ARCHIVE_URL_DICT = {
    'canonical_zebra_grevys_v1': 'https://wildbookiarepository.azureedge.net/models/classifier.canonical.zebra_grevys.v1.zip',
    'canonical_zebra_grevys_v2': 'https://wildbookiarepository.azureedge.net/models/classifier.canonical.zebra_grevys.v2.zip',
    'canonical_zebra_grevys_v3': 'https://wildbookiarepository.azureedge.net/models/classifier.canonical.zebra_grevys.v3.zip',
    'canonical_zebra_grevys_v4': 'https://wildbookiarepository.azureedge.net/models/classifier.canonical.zebra_grevys.v4.zip',
    'canonical_giraffe_reticulated_v1': 'https://wildbookiarepository.azureedge.net/models/classifier.canonical.giraffe_reticulated.v1.zip',
    'ryan_densenet_v1': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.ryan.densenet.v1.zip',
    'ryan_densenet_v2': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.ryan.densenet.v2.zip',
    'megan_argentina_v1': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.megan.argentina.densenet.v1.zip',
    'megan_kenya_v1': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.megan.kenya.densenet.v1.zip',
    'megan_kenya_v2': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.megan.kenya.densenet.v2.zip',
    'laterals_v0': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.laterals.densenet.v0.zip',
    'belly_v0': 'https://wildbookiarepository.azureedge.net/models/classifier.cameratrap.right_whale_belly.densenet.v0.zip',
    'zebra_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.zebra_grevys-zebra_plains.v1.zip',
    'zebra_mountain_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.zebra_mountain.v0.zip',
    'giraffe_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.giraffe.v1.zip',
    'jaguar_v3': 'https://wildbookiarepository.azureedge.net/models/labeler.jaguar.v3.zip',
    'lynx_v3': 'https://wildbookiarepository.azureedge.net/models/labeler.lynx.v3.zip',
    'manta_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.manta_ray_giant.v1.zip',
    'seaturtle_v3': 'https://wildbookiarepository.azureedge.net/models/labeler.seaturtle.v3.zip',
    'hendrik_dorsal_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.hendrik_dorsal.v2.zip',
    'spotted_dolphin_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.dolphin_spotted.v0.zip',
    'spotted_skunk_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.skunk_spotted.v0.zip',
    'humpback_dorsal': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_humpback.dorsal.v0.zip',
    'orca_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_orca.v0.zip',
    'whale_sperm_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_sperm.v0.zip',
    'fins_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.fins.v0.zip',
    'fins_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.fins.v1.1.zip',
    'fins_enforcement_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.fins.enforcement.v0.zip',
    'wilddog_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.wild_dog.v0.zip',
    'wilddog_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.wild_dog.v1.zip',
    'wilddog_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.wild_dog.v2.zip',
    'wilddog_v3': 'https://wildbookiarepository.azureedge.net/models/labeler.wild_dog.v3.zip',
    'leopard_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.leopard.v0.zip',
    'cheetah_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.cheetah.v1.zip',
    'cheetah_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.cheetah.v2.zip',
    'hyaena_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.hyaena.v0.zip',
    'wild_horse_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.wild_horse.v0.zip',
    'seadragon_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.seadragon.v0.zip',
    'seadragon_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.seadragon.v1.zip',
    'seadragon_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.seadragon.v2.zip',
    'jaguar_v4': 'https://wildbookiarepository.azureedge.net/models/labeler.jaguar.v4.zip',
    'lynx_v4': 'https://wildbookiarepository.azureedge.net/models/labeler.lynx.v4.zip',
    'manta_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.manta_ray_giant.v2.zip',
    'seaturtle_v4': 'https://wildbookiarepository.azureedge.net/models/labeler.seaturtle.v4.zip',
    'nassau_grouper_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.grouper_nassau.v0.zip',
    'nassau_grouper_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.grouper_nassau.v1.zip',
    'nassau_grouper_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.grouper_nassau.v2.zip',
    'nassau_grouper_v3': 'https://wildbookiarepository.azureedge.net/models/labeler.grouper_nassau.v3.zip',
    'salanader_fire_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.salamander_fire.v0.zip',
    'salanader_fire_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.salamander_fire.v1.zip',
    'salamander_fire_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.salamander_fire.v0.zip',
    'salamander_fire_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.salamander_fire.v1.zip',
    'salamander_fire_v2': 'https://wildbookiarepository.azureedge.net/models/labeler.salamander_fire.v2.zip',
    'spotted_dolphin_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.dolphin_spotted.v1.zip',
    'spotted_skunk_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.skunk_spotted.v1.zip',
    'monk_seal_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.mediterranean_monk_seal.v0.zip',
    'iot_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.iot.v0.zip',
    'right_whale_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.rightwhale.v0.zip',
    'whale_shark_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_shark.v0.zip',
    'flukebook_v1': 'https://wildbookiarepository.azureedge.net/models/classifier2.flukebook.v1.zip',
    'rightwhale_v5': 'https://wildbookiarepository.azureedge.net/models/labeler.rightwhale.v5.zip',
    'snow_leopard_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.snow_leopard.v0.zip',
    'grey_whale_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_grey.v0.zip',
    'beluga_whale_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_beluga.v0.zip',
    'beluga_whale_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_beluga.v1.zip',
    'sea_turtle_v4': 'https://wildbookiarepository.azureedge.net/models/labeler.sea_turtle.v4.zip',
    'seals_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.seals.v0.zip',
    'seals_v1': 'https://wildbookiarepository.azureedge.net/models/labeler.seals.v1.zip',
    'lions_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.lions.v0.zip',
    'spotted_eagle_ray_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.spotted_eagle_ray.v0.zip',
    'scout-d3e8bf43-boost0': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.0.zip',
    'scout-d3e8bf43-boost1': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.1.zip',
    'scout-d3e8bf43-boost2': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.2.zip',
    'scout-d3e8bf43-boost3': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.3.zip',
    'scout-d3e8bf43-boost4': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.4.zip',
    'scout-d3e8bf43-boost5': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.5.zip',
    'scout-d3e8bf43-boost6': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.6.zip',
    'scout-d3e8bf43-boost7': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.d3e8bf43.7.zip',
    'scout-5fbfff26-boost0': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.5fbfff26.0.zip',
    'scout-5fbfff26-boost1': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.5fbfff26.1.zip',
    'scout-5fbfff26-boost2': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.5fbfff26.2.zip',
    'scout-5fbfff26-boost3': 'https://wildbookiarepository.azureedge.net/models/classifier2.scout.5fbfff26.3.zip',
    'whale_fin_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.whale_fin.v0.zip',
    'leopard_shark_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.leopard_shark.v10.zip',
    'tigershark_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.tigershark.v0.zip',
    'snail_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.snail.v0.zip',
    'deer_v0': 'https://wildbookiarepository.azureedge.net/models/labeler.deer.v0.zip',

}

if not ut.get_argflag('--no-pytorch'):
    try:
        import torch
        import torch.nn as nn
        import torch.optim as optim
        import torchvision

        logger.info('PyTorch Version: {}'.format(torch.__version__))
        logger.info('Torchvision Version: {}'.format(torchvision.__version__))
    except ImportError:
        logger.info('WARNING Failed to import pytorch.  PyTorch is unavailable')
        if ut.SUPER_STRICT:
            raise

    try:
        import imgaug  # NOQA

        class Augmentations(object):
            def __call__(self, img):
                img = np.array(img)
                return self.aug.augment_image(img)

        class TrainAugmentations(Augmentations):
            def __init__(self, blur=True, flip=False, rotate=10, shear=10, **kwargs):
                from imgaug import augmenters as iaa

                sequence = []

                sequence += [
                    iaa.Scale((INPUT_SIZE, INPUT_SIZE)),
                    iaa.ContrastNormalization((0.75, 1.25)),
                    iaa.AddElementwise((-10, 10), per_channel=0.5),
                    iaa.AddToHueAndSaturation(value=(-20, 20), per_channel=True),
                    iaa.Multiply((0.75, 1.25)),
                ]
                sequence += [
                    iaa.PiecewiseAffine(scale=(0.0005, 0.005)),
                    iaa.Affine(
                        rotate=(-rotate, rotate), shear=(-shear, shear), mode='symmetric'
                    ),
                    iaa.Grayscale(alpha=(0.0, 0.5)),
                ]
                if flip:
                    sequence += [
                        iaa.Fliplr(0.5),
                    ]
                if blur:
                    sequence += [
                        iaa.Sometimes(0.01, iaa.GaussianBlur(sigma=(0, 1.0))),
                    ]
                self.aug = iaa.Sequential(sequence)

        class ValidAugmentations(Augmentations):
            def __init__(self, **kwargs):
                from imgaug import augmenters as iaa

                self.aug = iaa.Sequential([iaa.Scale((INPUT_SIZE, INPUT_SIZE))])

        AUGMENTATION = {
            'train': TrainAugmentations,
            'val': ValidAugmentations,
            'test': ValidAugmentations,
        }
    except ImportError:
        AUGMENTATION = {}
        logger.info(
            'WARNING Failed to import imgaug. '
            'install with pip install git+https://github.com/aleju/imgaug'
        )
        if ut.SUPER_STRICT:
            raise

def _init_transforms(**kwargs):
    TRANSFORMS = {
        phase: torchvision.transforms.Compose(
            [
                AUGMENTATION[phase](**kwargs),
                torchvision.transforms.Lambda(PIL.Image.fromarray),
                torchvision.transforms.ToTensor(),
                torchvision.transforms.Normalize(
                    [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
                ),
            ]
        )
        for phase in AUGMENTATION.keys()
    }

    return TRANSFORMS

class ImageFilePathList(torch.utils.data.Dataset):
    def __init__(self, filepaths, targets=None, transform=None, target_transform=None):
        from torchvision.datasets.folder import default_loader

        self.targets = targets is not None

        args = (filepaths, targets) if self.targets else (filepaths,)
        self.samples = list(zip(*args))

        if self.targets:
            self.classes = sorted(set(ut.take_column(self.targets, 1)))
            self.class_to_idx = {self.classes[i]: i for i in range(len(self.classes))}
        else:
            self.classes, self.class_to_idx = None, None

        self.loader = default_loader
        self.transform = transform
        self.target_transform = target_transform

    def __getitem__(self, index):
        """
        Args:
            index (int): Index
        Returns:
            tuple: (sample, target) where target is class_index of the target class.
        """
        sample = self.samples[index]

        if self.targets:
            path, target = sample
        else:
            path = sample[0]
            target = None

        sample = self.loader(path)

        if self.transform is not None:
            sample = self.transform(sample)

        if self.target_transform is not None:
            target = self.target_transform(target)

        result = (sample, target) if self.targets else (sample,)

        return result

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

    def __repr__(self):
        fmt_str = 'Dataset ' + self.__class__.__name__ + '\n'
        fmt_str += '    Number of samples: {}\n'.format(self.__len__())
        tmp = '    Transforms (if any): '
        fmt_str += '{}{}\n'.format(
            tmp, self.transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))
        )
        tmp = '    Target Transforms (if any): '
        fmt_str += '{}{}'.format(
            tmp, self.target_transform.__repr__().replace('\n', '\n' + ' ' * len(tmp))
        )
        return fmt_str

class StratifiedSampler(torch.utils.data.sampler.Sampler):
    def __init__(self, dataset, phase, multiplier=1.0):
        self.dataset = dataset
        self.phase = phase
        self.training = self.phase == 'train'

        self.labels = np.array(ut.take_column(dataset.samples, 1))
        self.classes = set(self.labels)

        self.indices = {
            cls: list(np.where(self.labels == cls)[0]) for cls in self.classes
        }
        self.counts = {cls: len(self.indices[cls]) for cls in self.classes}
        self.min = min(self.counts.values())
        self.min = int(np.around(multiplier * self.min))

        if self.training:
            self.total = 0
            for cls in self.indices:
                num_in_class = len(self.indices[cls])
                num_samples = min(self.min, num_in_class)
                self.total += num_samples
        else:
            self.total = len(self.labels)

        args = (
            self.phase,
            len(self.labels),
            len(self.classes),
            self.min,
            self.total,
            multiplier,
        )
        logger.info(
            'Initialized Sampler for %r (sampling %d for %d classes | min %d per class, %d total, %0.02f multiplier)'
            % args
        )

    def __iter__(self):
        if self.training:
            ret_list = []
            for cls in self.indices:
                num_in_class = len(self.indices[cls])
                num_samples = min(self.min, num_in_class)
                ret_list += random.sample(self.indices[cls], num_samples)
            random.shuffle(ret_list)
        else:
            ret_list = range(self.total)
        assert len(ret_list) == self.total
        return iter(ret_list)

    def __len__(self):
        return self.total

def finetune(model, dataloaders, criterion, optimizer, scheduler, device, num_epochs=128):
    phases = ['train', 'val']

    start = time.time()

    best_accuracy = 0.0
    best_model_state = copy.deepcopy(model.state_dict())

    last_loss = {}
    best_loss = {}

    for epoch in range(num_epochs):
        start_batch = time.time()

        lr = optimizer.param_groups[0]['lr']
        logger.info('Epoch {}/{} (lr = {:0.06f})'.format(epoch, num_epochs - 1, lr))
        logger.info('-' * 10)

        # Each epoch has a training and validation phase
        for phase in phases:
            if phase == 'train':
                model.train()  # Set model to training mode
            else:
                model.eval()  # Set model to evaluate mode

            running_loss = 0.0
            running_corrects = 0

            # Iterate over data.
            seen = 0
            for inputs, labels in tqdm.tqdm(dataloaders[phase], desc=phase):
                inputs = inputs.to(device)
                labels = labels.to(device)

                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    # Get model outputs and calculate loss
                    outputs = model(inputs)
                    loss = criterion(outputs, labels)

                    _, preds = torch.max(outputs, 1)

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # statistics
                seen += len(inputs)
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            epoch_loss = running_loss / seen
            epoch_acc = running_corrects.double() / seen

            last_loss[phase] = epoch_loss
            if phase not in best_loss:
                best_loss[phase] = np.inf

            flag = epoch_loss < best_loss[phase]
            if flag:
                best_loss[phase] = epoch_loss

            logger.info(
                '{:<5} Loss: {:.4f} Acc: {:.4f} {}'.format(
                    phase, epoch_loss, epoch_acc, '!' if flag else ''
                )
            )

            # deep copy the model
            if phase == 'val' and epoch_acc > best_accuracy:
                best_accuracy = epoch_acc
                logger.info('\tFound better model!')
                best_model_state = copy.deepcopy(model.state_dict())
            if phase == 'val':
                scheduler.step(epoch_loss)

                time_elapsed_batch = time.time() - start_batch
                logger.info(
                    'time: {:.0f}m {:.0f}s'.format(
                        time_elapsed_batch // 60, time_elapsed_batch % 60
                    )
                )

                ratio = last_loss['train'] / last_loss['val']
                logger.info('ratio: {:.04f}'.format(ratio))

        logger.info('\n')

    time_elapsed = time.time() - start
    logger.info(
        'Training complete in {:.0f}m {:.0f}s'.format(
            time_elapsed // 60, time_elapsed % 60
        )
    )
    logger.info('Best val Acc: {:4f}'.format(best_accuracy))

    # load best model weights
    model.load_state_dict(best_model_state)
    return model

def visualize_augmentations(dataset, augmentation, tag, num_per_class=10, **kwargs):
    import matplotlib.pyplot as plt

    samples = dataset.samples
    flags = np.array(ut.take_column(samples, 1))
    logger.info('Dataset %r has %d samples' % (tag, len(flags)))

    indices = []
    for flag in set(flags):
        index_list = list(np.where(flags == flag)[0])
        random.shuffle(index_list)
        indices += index_list[:num_per_class]

    samples = ut.take(samples, indices)
    paths = ut.take_column(samples, 0)
    flags = ut.take_column(samples, 1)

    images = [np.array(cv2.imread(path)) for path in paths]
    images = [image[:, :, ::-1] for image in images]

    images_ = []
    for image, flag in zip(images, flags):
        image_ = image.copy()
        color = (0, 255, 0) if flag else (255, 0, 0)
        cv2.rectangle(image_, (1, 1), (INPUT_SIZE - 1, INPUT_SIZE - 1), color, 3)
        images_.append(image_)
    canvas = np.hstack(images_)
    canvas_list = [canvas]

    augment = augmentation(**kwargs)
    for index in range(len(indices) - 1):
        logger.info(index)
        images_ = [augment(image.copy()) for image in images]
        canvas = np.hstack(images_)
        canvas_list.append(canvas)
    canvas = np.vstack(canvas_list)

    canvas_filepath = expanduser(
        join('~', 'Desktop', 'densenet-augmentation-{}.png'.format(tag))
    )
    plt.imsave(canvas_filepath, canvas)

def train(
    data_path,
    output_path,
    batch_size=48,
    class_weights={},
    multi=PARALLEL,
    sample_multiplier=4.0,
    allow_missing_validation_classes=False,
    **kwargs,
):
    # Detect if we have a GPU available
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    using_gpu = str(device) != 'cpu'

    phases = ['train', 'val']

    logger.info('Initializing Datasets and Dataloaders...')

    # Create training and validation datasets
    transforms = _init_transforms(**kwargs)
    datasets = {
        phase: torchvision.datasets.ImageFolder(
            os.path.join(data_path, phase), transforms[phase]
        )
        for phase in phases
    }

    # Create training and validation dataloaders
    dataloaders = {
        phase: torch.utils.data.DataLoader(
            datasets[phase],
            sampler=StratifiedSampler(
                datasets[phase], phase, multiplier=sample_multiplier
            ),
            batch_size=batch_size,
            num_workers=batch_size // 8,
            pin_memory=using_gpu,
        )
        for phase in phases
    }

    train_classes = datasets['train'].classes
    val_classes = datasets['val'].classes

    if not allow_missing_validation_classes:
        assert len(train_classes) == len(val_classes)
    num_classes = len(train_classes)

    logger.info('Initializing Model...')

    # Initialize the model for this run
    model = torchvision.models.densenet201(pretrained=True)
    num_ftrs = model.classifier.in_features
    model.classifier = nn.Linear(num_ftrs, num_classes)

    # Send the model to GPU
    model = model.to(device)

    # Multi-GPU
    if multi:
        logger.info('USING MULTI-GPU MODEL')
        model = nn.DataParallel(model)

    logger.info('Print Examples of Training Augmentation...')

    for phase in phases:
        visualize_augmentations(datasets[phase], AUGMENTATION[phase], phase, **kwargs)

    logger.info('Initializing Optimizer...')

    # logger.info('Params to learn:')
    params_to_update = []
    for name, param in model.named_parameters():
        if param.requires_grad:
            params_to_update.append(param)
            # logger.info('\t', name)

    # Observe that all parameters are being optimized
    optimizer = optim.SGD(params_to_update, lr=0.001, momentum=0.9)

    scheduler = optim.lr_scheduler.ReduceLROnPlateau(
        optimizer, 'min', factor=0.5, patience=10, min_lr=1e-6
    )

    # Get weights for the class
    class_index_list = list(dataloaders['train'].dataset.class_to_idx.items())
    index_class_list = [class_index[::-1] for class_index in class_index_list]
    weight = torch.tensor(
        [class_weights.get(class_, 1.0) for index, class_ in sorted(index_class_list)]
    )
    weight = weight.to(device)

    # Setup the loss fxn
    criterion = nn.CrossEntropyLoss(weight=weight)

    logger.info('Start Training...')

    # Train and evaluate
    model = finetune(model, dataloaders, criterion, optimizer, scheduler, device)

    ut.ensuredir(output_path)
    weights_path = os.path.join(output_path, 'classifier.densenet.weights')
    weights = {
        'state': copy.deepcopy(model.state_dict()),
        'classes': train_classes,
    }
    torch.save(weights, weights_path)

    return weights_path

def test_single(filepath_list, weights_path, batch_size=1792, multi=PARALLEL, **kwargs):

    # Detect if we have a GPU available
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    using_gpu = str(device) != 'cpu'

    logger.info('Initializing Datasets and Dataloaders...')

    # Create training and validation datasets
    transforms = _init_transforms(**kwargs)
    dataset = ImageFilePathList(filepath_list, transform=transforms['test'])

    # Create training and validation dataloaders
    dataloader = torch.utils.data.DataLoader(
        dataset, batch_size=batch_size, num_workers=0, pin_memory=using_gpu
    )

    logger.info('Initializing Model...')
    try:
        weights = torch.load(weights_path)
    except RuntimeError:
        weights = torch.load(weights_path, map_location='cpu')
    state = weights['state']
    classes = weights['classes']

    num_classes = len(classes)

    # Initialize the model for this run
    model = torchvision.models.densenet201()
    num_ftrs = model.classifier.in_features
    model.classifier = nn.Linear(num_ftrs, num_classes)

    # Convert any weights to non-parallel version
    from collections import OrderedDict

    new_state = OrderedDict()
    for k, v in state.items():
        k = k.replace('module.', '')
        new_state[k] = v

    # Load state without parallel
    model.load_state_dict(new_state)

    # Add softmax
    model.classifier = nn.Sequential(model.classifier, nn.LogSoftmax(), nn.Softmax())

    # Make parallel at end
    if multi:
        logger.info('USING MULTI-GPU MODEL')
        model = nn.DataParallel(model)

    # Send the model to GPU
    model = model.to(device)

    model.eval()

    start = time.time()

    counter = 0
    outputs = []
    for (inputs,) in tqdm.tqdm(dataloader, desc='test'):
        logger.info('Loading batch %d from disk' % (counter,))
        inputs = inputs.to(device)
        logger.info('Moving batch %d to GPU' % (counter,))
        with torch.set_grad_enabled(False):
            logger.info('Pre-model inference %d' % (counter,))
            output = model(inputs)
            logger.info('Post-model inference %d' % (counter,))
            outputs += output.tolist()
            logger.info('Outputs done %d' % (counter,))
        counter += 1

    time_elapsed = time.time() - start
    logger.info(
        'Testing complete in {:.0f}m {:.0f}s'.format(
            time_elapsed // 60, time_elapsed % 60
        )
    )

    result_list = []
    for output in outputs:
        result = dict(zip(classes, output))
        result_list.append(result)

    return result_list

def test_ensemble(
    filepath_list,
    weights_path_list,
    classifier_weight_filepath,
    ensemble_index,
    ibs=None,
    gid_list=None,
    multiclass=False,
    **kwargs,
):

    if ensemble_index is not None:
        assert 0 <= ensemble_index and ensemble_index < len(weights_path_list)
        weights_path_list = [weights_path_list[ensemble_index]]
        assert len(weights_path_list) > 0

    cached = False
    try:
        assert ensemble_index is None, 'Do not use depc on individual model computation'
        assert None not in [ibs, gid_list], 'Needs to have access to depc'
        assert len(filepath_list) == len(gid_list)

        results_list = []
        for model_index in range(len(weights_path_list)):
            if multiclass:
                classifier_two_weight_filepath_ = '%s:%d' % (
                    classifier_weight_filepath,
                    model_index,
                )
                config = {
                    'classifier_two_algo': 'densenet',
                    'classifier_two_weight_filepath': classifier_two_weight_filepath_,
                }
                scores_list = ibs.depc_image.get_property(
                    'classifier_two', gid_list, 'scores', config=config
                )
                result_list = []
                for score_dict in scores_list:
                    result = score_dict
                    result_list.append(result)
            else:
                classifier_weight_filepath_ = '%s:%d' % (
                    classifier_weight_filepath,
                    model_index,
                )
                config = {
                    'classifier_algo': 'densenet',
                    'classifier_weight_filepath': classifier_weight_filepath_,
                }
                prediction_list = ibs.depc_image.get_property(
                    'classifier', gid_list, 'class', config=config
                )
                confidence_list = ibs.depc_image.get_property(
                    'classifier', gid_list, 'score', config=config
                )
                result_list = []
                for prediction, confidence in zip(prediction_list, confidence_list):
                    # DO NOT REMOVE THIS ASSERT
                    assert prediction in {
                        'negative',
                        'positive',
                    }, 'Cannot use this method, need to implement classifier_two in depc'
                    if prediction == 'positive':
                        pscore = confidence
                        nscore = 1.0 - pscore
                    else:
                        nscore = confidence
                        pscore = 1.0 - nscore
                    result = {
                        'positive': pscore,
                        'negative': nscore,
                    }
                    result_list.append(result)
            assert len(result_list) == len(gid_list)
            results_list.append(result_list)
        assert len(results_list) == len(weights_path_list)
        cached = True
    except AssertionError:
        cached = False

    if not cached:
        # Use local implementation, due to error or not valid config
        results_list = []
        for weights_path in weights_path_list:
            result_list = test_single(filepath_list, weights_path)
            results_list.append(result_list)

    for result_list in zip(*results_list):
        merged = {}
        for result in result_list:
            for key in result:
                if key not in merged:
                    merged[key] = []
                merged[key].append(result[key])
        for key in merged:
            value_list = merged[key]
            merged[key] = sum(value_list) / len(value_list)

        yield merged

def test(
    gpath_list,
    classifier_weight_filepath=None,
    return_dict=False,
    multiclass=False,
    **kwargs,
):
    from wbia.detecttools.directory import Directory

    # Get correct weight if specified with shorthand
    archive_url = None

    ensemble_index = None
    if classifier_weight_filepath is not None and ':' in classifier_weight_filepath:
        assert classifier_weight_filepath.count(':') == 1
        classifier_weight_filepath, ensemble_index = classifier_weight_filepath.split(':')
        ensemble_index = int(ensemble_index)

    if classifier_weight_filepath in ARCHIVE_URL_DICT:
        archive_url = ARCHIVE_URL_DICT[classifier_weight_filepath]
        archive_path = ut.grab_file_url(archive_url, appname='wbia', check_hash=True)
    else:
        logger.info(
            'classifier_weight_filepath {!r} not recognized'.format(
                classifier_weight_filepath
            )
        )
        raise RuntimeError

    assert os.path.exists(archive_path)
    archive_path = ut.truepath(archive_path)

    ensemble_path = archive_path.strip('.zip')
    if not os.path.exists(ensemble_path):
        ut.unarchive_file(archive_path, output_dir=ensemble_path)

    assert os.path.exists(ensemble_path)
    direct = Directory(ensemble_path, include_file_extensions=['weights'], recursive=True)
    weights_path_list = direct.files()
    weights_path_list = sorted(weights_path_list)
    assert len(weights_path_list) > 0

    kwargs.pop('classifier_algo', None)

    logger.info(
        'Using weights in the ensemble, index %r: %s '
        % (ensemble_index, ut.repr3(weights_path_list))
    )
    result_list = test_ensemble(
        gpath_list,
        weights_path_list,
        classifier_weight_filepath,
        ensemble_index,
        multiclass=multiclass,
        **kwargs,
    )
    for result in result_list:
        best_key = None
        best_score = -1.0
        for key, score in result.items():
            if score > best_score:
                best_key = key
                best_score = score
        assert best_score >= 0.0 and best_key is not None
        if return_dict:
            yield best_score, best_key, result
        else:
            yield best_score, best_key

def test_dict(gpath_list, classifier_weight_filepath=None, return_dict=None, **kwargs):
    result_gen = test(
        gpath_list,
        classifier_weight_filepath=classifier_weight_filepath,
        return_dict=True,
        **kwargs,
    )

    for result in result_gen:
        best_score, best_key, result_dict = result
        best_key = best_key.split(':')
        if len(best_key) == 1:
            best_species = best_key
            best_viewpoint = None
        elif len(best_key) == 2:
            best_species, best_viewpoint = best_key
        else:
            raise ValueError('Invalid key {!r}'.format(best_key))

        yield (
            best_score,
            best_species,
            best_viewpoint,
            'UNKNOWN',
            0.0,
            result_dict,
        )

def features(filepath_list, batch_size=512, multi=PARALLEL, **kwargs):
    # Detect if we have a GPU available
    device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
    using_gpu = str(device) != 'cpu'

    logger.info('Initializing Datasets and Dataloaders...')

    # Create training and validation datasets
    transforms = _init_transforms(**kwargs)
    dataset = ImageFilePathList(filepath_list, transform=transforms['test'])

    # Create training and validation dataloaders
    dataloader = torch.utils.data.DataLoader(
        dataset, batch_size=batch_size, num_workers=0, pin_memory=using_gpu
    )

    # Initialize the model for this run
    model = torchvision.models.densenet201(pretrained=True)

    # Send the model to GPU
    model = model.to(device)

    if multi:
        logger.info('USING MULTI-GPU MODEL')
        model = nn.DataParallel(model)

    model.eval()

    start = time.time()

    outputs = []
    for (inputs,) in tqdm.tqdm(dataloader, desc='test'):
        inputs = inputs.to(device)
        with torch.set_grad_enabled(False):
            output = model(inputs)
            outputs += output.tolist()

    outputs = np.array(outputs, dtype=np.float32)
    time_elapsed = time.time() - start
    logger.info(
        'Testing complete in {:.0f}m {:.0f}s'.format(
            time_elapsed // 60, time_elapsed % 60
        )
    )

    return outputs


from PIL import Image, ImageDraw
import math

import players

def degreesToRadians(degrees):
  return(degrees / 180 * math.pi)

class Location:
  def __init__(self):
    self.x = 0
    self.y = 0
    self.z = 0
  def __init__(self, coordinates):
    self.x = coordinates[0]
    self.y = coordinates[1]
    self.z = coordinates[2]
  def plus(self, location):
    x = self.x + location.x
    y = self.y + location.y
    z = self.z + location.z
    return Location((x, y, z))
  ## Add a length plus angle on the XZ plane
  def plusXZAngleLength(self, xzAngle, length):
    x = self.x + length * math.cos(xzAngle)
    y = self.y
    z = self.z + length * math.sin(xzAngle)
    return Location((x, y, z))
  def toString(self):
    output = "(" + str(self.x) + "," + str(self.y) + "," + str(self.z) + ")"
    return output

class BodyAttributes:
  def __init__(self):
    ## Lengths
    self.torsoLength = 8
    self.femurLength = 7
    self.tibiaLength = 7
    self.footLength = 2.5
    self.humerusLength = 5
    self.radiusLength = 5
    self.hipWidth = 1.5
    self.shoulderWidth = 2
    self.headBottomHeight=3
    self.headTopHeight=4.7
    self.headBottomOffset=0.3
    self.headTopOffset=0.2
    ## Ratios
    self.shortsFemurRatio=0.5
    self.shortsTorsoRatio=0.2
    self.hairRadiusRatio=0.9
    ## Sizes
    self.hipRadius = 1.4
    self.kneeRadius = 1.0
    self.ankleRadius = 0.7
    self.toeRadius = 0.6
    self.shoulderTorsoRadius = 1.6
    self.shoulderRadius = 1
    self.elbowRadius=0.8
    self.wristRadius=0.5
    self.handRadius=1
    self.headTopRadius=1.6
    self.headBottomRadius=1.2
    self.hairTopRadius = 0.4
    self.hairMiddleRadius = 0.6
    self.hairBottomRadius = 0.7
    ## Colors
    self.skinTone=(255, 230, 200, 255)
    self.singletColor=(0, 160, 0, 255)
    self.shortsColor=(10, 10, 10, 255)
    self.shoeColor=(0, 255, 0, 255)
    self.hairColor=(170, 125, 100, 255)

class BodyPositions:
  def __init__(self):
    ## Angles
    self.rightElbowAngle = degreesToRadians(180)
    self.leftElbowAngle = degreesToRadians(180)
    self.rightShoulderAngle = degreesToRadians(0)
    self.leftShoulderAngle = degreesToRadians(0)
    self.rightKneeAngle = degreesToRadians(180)
    self.leftKneeAngle = degreesToRadians(180)
    self.rightHipAngle = degreesToRadians(180)
    self.leftHipAngle = degreesToRadians(180)
    self.rightAnkleAngle = degreesToRadians(90)
    self.leftAnkleAngle = degreesToRadians(90)
    self.torsoToGroundAngle = degreesToRadians(90)
    self.torsoToGroundHeight = 14
  def interpolateWith(self, bodyPositions, ratio):
    interpolatedBodyPositions = BodyPositions()
    interpolatedBodyPositions.leftElbowAngle = self.leftElbowAngle + (bodyPositions.leftElbowAngle - self.leftElbowAngle) * ratio
    interpolatedBodyPositions.rightElbowAngle = self.rightElbowAngle + (bodyPositions.rightElbowAngle - self.rightElbowAngle) * ratio
    interpolatedBodyPositions.leftShoulderAngle = self.leftShoulderAngle + (bodyPositions.leftShoulderAngle - self.leftShoulderAngle) * ratio
    interpolatedBodyPositions.rightShoulderAngle = self.rightShoulderAngle + (bodyPositions.rightShoulderAngle - self.rightShoulderAngle) * ratio
    interpolatedBodyPositions.leftKneeAngle = self.leftKneeAngle + (bodyPositions.leftKneeAngle - self.leftKneeAngle) * ratio
    interpolatedBodyPositions.rightKneeAngle = self.rightKneeAngle + (bodyPositions.rightKneeAngle - self.rightKneeAngle) * ratio
    interpolatedBodyPositions.leftHipAngle = self.leftHipAngle + (bodyPositions.leftHipAngle - self.leftHipAngle) * ratio
    interpolatedBodyPositions.rightHipAngle = self.rightHipAngle + (bodyPositions.rightHipAngle - self.rightHipAngle) * ratio
    interpolatedBodyPositions.leftAnkleAngle = self.leftAnkleAngle + (bodyPositions.leftAnkleAngle - self.leftAnkleAngle) * ratio
    interpolatedBodyPositions.rightAnkleAngle = self.rightAnkleAngle + (bodyPositions.rightAnkleAngle - self.rightAnkleAngle) * ratio
    interpolatedBodyPositions.torsoToGroundAngle = self.torsoToGroundAngle + (bodyPositions.torsoToGroundAngle - self.torsoToGroundAngle) * ratio
    interpolatedBodyPositions.torsoToGroundHeight = self.torsoToGroundHeight + (bodyPositions.torsoToGroundHeight - self.torsoToGroundHeight) * ratio
    return interpolatedBodyPositions
  def invert(self):
    invertedBodyPosition = BodyPositions()
    invertedBodyPosition.leftElbowAngle = self.rightElbowAngle
    invertedBodyPosition.leftShoulderAngle = self.rightShoulderAngle
    invertedBodyPosition.leftHipAngle = self.rightHipAngle
    invertedBodyPosition.leftKneeAngle = self.rightKneeAngle
    invertedBodyPosition.leftAnkleAngle = self.rightAnkleAngle
    invertedBodyPosition.rightElbowAngle = self.leftElbowAngle
    invertedBodyPosition.rightShoulderAngle = self.leftShoulderAngle
    invertedBodyPosition.rightHipAngle = self.leftHipAngle
    invertedBodyPosition.rightKneeAngle = self.leftKneeAngle
    invertedBodyPosition.rightAnkleAngle = self.leftAnkleAngle
    invertedBodyPosition.torsoToGroundAngle = self.torsoToGroundAngle
    invertedBodyPosition.torsoToGroundHeight = self.torsoToGroundHeight
    return invertedBodyPosition

class BodyCoordinates:
  def __init__(self, bodyAttributes, bodyPositions):
    ## Torso
    self.torsoBottom = Location((0, 0, bodyPositions.torsoToGroundHeight))
    self.torsoTop = self.torsoBottom.plusXZAngleLength(bodyPositions.torsoToGroundAngle, bodyAttributes.torsoLength)
    ## Upper leg
    self.leftHip = self.torsoBottom.plus(Location((0, bodyAttributes.hipWidth/2, 0)))
    self.rightHip = self.torsoBottom.plus(Location((0, -bodyAttributes.hipWidth/2, 0)))
    leftHipToGroundAngle = bodyPositions.torsoToGroundAngle + bodyPositions.leftHipAngle
    rightHipToGroundAngle = bodyPositions.torsoToGroundAngle + bodyPositions.rightHipAngle
    self.leftKnee = self.leftHip.plusXZAngleLength(leftHipToGroundAngle, bodyAttributes.femurLength)
    self.rightKnee = self.rightHip.plusXZAngleLength(rightHipToGroundAngle, bodyAttributes.femurLength)
    ## Lower leg
    leftKneeToGroundAngle = leftHipToGroundAngle + degreesToRadians(180) + bodyPositions.leftKneeAngle
    rightKneeToGroundAngle = rightHipToGroundAngle + degreesToRadians(180) + bodyPositions.rightKneeAngle
    self.leftAnkle = self.leftKnee.plusXZAngleLength(leftKneeToGroundAngle, bodyAttributes.tibiaLength)
    self.rightAnkle = self.rightKnee.plusXZAngleLength(rightKneeToGroundAngle, bodyAttributes.tibiaLength)
    ## Foot
    leftAnkleToGroundAngle = leftKneeToGroundAngle + degreesToRadians(180) - bodyPositions.leftAnkleAngle
    rightAnkleToGroundAngle = rightKneeToGroundAngle + degreesToRadians(180) - bodyPositions.rightAnkleAngle
    self.leftToe = self.leftAnkle.plusXZAngleLength(leftAnkleToGroundAngle, bodyAttributes.footLength)
    self.rightToe = self.rightAnkle.plusXZAngleLength(rightAnkleToGroundAngle, bodyAttributes.footLength)
    ## Upper arm
    self.leftShoulder = self.torsoTop.plus(Location((0, bodyAttributes.shoulderWidth/2, 0)))
    self.rightShoulder = self.torsoTop.plus(Location((0, -bodyAttributes.shoulderWidth/2, 0)))
    leftShoulderToGroundAngle = bodyPositions.torsoToGroundAngle + degreesToRadians(180) - bodyPositions.leftShoulderAngle
    rightShoulderToGroundAngle = bodyPositions.torsoToGroundAngle + degreesToRadians(180) - bodyPositions.rightShoulderAngle
    self.leftElbow = self.leftShoulder.plusXZAngleLength(leftShoulderToGroundAngle, bodyAttributes.humerusLength)
    self.rightElbow = self.rightShoulder.plusXZAngleLength(rightShoulderToGroundAngle, bodyAttributes.humerusLength)
    ## Lower arm
    leftElbowToGroundAngle = leftShoulderToGroundAngle + degreesToRadians(180) - bodyPositions.leftElbowAngle
    rightElbowToGroundAngle = rightShoulderToGroundAngle + degreesToRadians(180) - bodyPositions.rightElbowAngle
    self.leftHand = self.leftElbow.plusXZAngleLength(leftElbowToGroundAngle, bodyAttributes.radiusLength)
    self.rightHand = self.rightElbow.plusXZAngleLength(rightElbowToGroundAngle, bodyAttributes.radiusLength)
    ## Head
    headOffsetAngle = bodyPositions.torsoToGroundAngle - degreesToRadians(90)
    self.headTop = self.torsoTop.plusXZAngleLength(bodyPositions.torsoToGroundAngle, bodyAttributes.headTopHeight).plusXZAngleLength(headOffsetAngle, bodyAttributes.headBottomOffset)
    self.headBottom = self.torsoTop.plusXZAngleLength(bodyPositions.torsoToGroundAngle, bodyAttributes.headBottomHeight).plusXZAngleLength(headOffsetAngle, bodyAttributes.headTopOffset)
    self.hairTop = self.headTop.plusXZAngleLength(bodyPositions.torsoToGroundAngle - degreesToRadians(45), bodyAttributes.headTopRadius)
    self.hairMiddle = self.headTop.plusXZAngleLength(bodyPositions.torsoToGroundAngle + degreesToRadians(20), bodyAttributes.headTopRadius * bodyAttributes.hairRadiusRatio)
    self.hairBottom = self.headTop.plusXZAngleLength(bodyPositions.torsoToGroundAngle + degreesToRadians(105), bodyAttributes.headTopRadius * bodyAttributes.hairRadiusRatio * bodyAttributes.hairRadiusRatio)

  def toString(self):
    output = ""
    output += "torso bottom: " + self.torsoBottom.toString() + "\n"
    output += "torso top: " + self.torsoTop.toString() + "\n"
    output += "left hip: " + self.leftHip.toString() + "\n"
    output += "right hip: " + self.rightHip.toString() + "\n"
    output += "left knee: " + self.leftKnee.toString() + "\n"
    output += "right knee: " + self.rightKnee.toString() + "\n"
    output += "left ankle: " + self.leftAnkle.toString() + "\n"
    output += "right ankle: " + self.rightAnkle.toString() + "\n"
    output += "left toe: " + self.leftToe.toString() + "\n"
    output += "right toe: " + self.rightToe.toString() + "\n"
    output += "left shoulder: " + self.leftShoulder.toString() + "\n"
    output += "right shoulder: " + self.rightShoulder.toString() + "\n"
    output += "left elbow: " + self.leftElbow.toString() + "\n"
    output += "right elbow: " + self.rightElbow.toString() + "\n"
    output += "left hand: " + self.leftHand.toString() + "\n"
    output += "right hand: " + self.rightHand.toString() + "\n"
    output += "head bottom: " + self.headBottom.toString() + "\n"
    output += "head top: " + self.headTop.toString() + "\n"
    return output

class ViewAngle:
  def __init__(self, yzAngle, zoom, centerX, centerY):
    self.yRatio = math.sin(yzAngle)
    self.zRatio = math.cos(yzAngle)
    self.zoom = zoom
    self.centerX = centerX
    self.centerY = centerY
  def coordinateToScreen(self, location):
    x = self.centerX + self.zoom * location.x
    y = self.centerY - self.zoom * (self.yRatio * location.y + self.zRatio * location.z)
    return (x, y)
  def sizeToScreen(self, size):
    return (self.zoom * size)

class Circle:
  def __init__(self, coordinates, radius):
    self.coordinates = coordinates
    self.radius = radius
  def corners(self):
    return (self.coordinates[0]-self.radius, self.coordinates[1]-self.radius, self.coordinates[0]+self.radius, self.coordinates[1]+self.radius)
  def interpolateWith(self, circle, ratio):
    radius = self.radius + (circle.radius - self.radius) * ratio
    x = self.coordinates[0] + (circle.coordinates[0] - self.coordinates[0])*ratio
    y = self.coordinates[1] + (circle.coordinates[1] - self.coordinates[1])*ratio
    return Circle((x, y), radius)

RESOLUTION=10

def interpolateCircles(circleA, circleB, color, resolution, draw):
  draw.ellipse(circleA.corners(), fill=color)
  for i in range(1, resolution):
    circle = circleA.interpolateWith(circleB, i/resolution)
    draw.ellipse(circle.corners(), fill=color)
  draw.ellipse(circleB.corners(), fill=color)

def plotCircle(circle, color, draw):
  draw.ellipse(circle.corners(), fill=color)

def drawBody(bodyCoordinates, bodyAttributes, viewAngle, draw):
  ## Feet
  leftAnkleCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftAnkle)
  rightAnkleCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightAnkle)
  ankleRadius = viewAngle.sizeToScreen(bodyAttributes.ankleRadius)
  leftAnkleCircle = Circle(leftAnkleCoordinates, ankleRadius)
  rightAnkleCircle = Circle(rightAnkleCoordinates, ankleRadius)

  leftToeCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftToe)
  rightToeCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightToe)
  toeRadius = viewAngle.sizeToScreen(bodyAttributes.toeRadius)
  leftToeCircle = Circle(leftToeCoordinates, toeRadius)
  rightToeCircle = Circle(rightToeCoordinates, toeRadius)

  ## Lower legs
  leftKneeCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftKnee)
  rightKneeCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightKnee)
  kneeRadius = viewAngle.sizeToScreen(bodyAttributes.kneeRadius)
  leftKneeCircle = Circle(leftKneeCoordinates, kneeRadius)
  rightKneeCircle = Circle(rightKneeCoordinates, kneeRadius)

  ## Upper legs
  leftHipCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftHip)
  rightHipCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightHip)
  hipRadius = viewAngle.sizeToScreen(bodyAttributes.hipRadius)
  leftHipCircle = Circle(leftHipCoordinates, hipRadius)
  rightHipCircle = Circle(leftHipCoordinates, hipRadius)
  leftBottomShortsCircle = leftHipCircle.interpolateWith(leftKneeCircle, bodyAttributes.shortsFemurRatio)
  rightBottomShortsCircle = leftHipCircle.interpolateWith(rightKneeCircle, bodyAttributes.shortsFemurRatio)

  ## Torso
  leftShoulderCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftShoulder)
  rightShoulderCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightShoulder)
  shoulderTorsoRadius = viewAngle.sizeToScreen(bodyAttributes.shoulderTorsoRadius)
  leftShoulderTorsoCircle = Circle(leftShoulderCoordinates, shoulderTorsoRadius)
  rightShoulderTorsoCircle = Circle(rightShoulderCoordinates, shoulderTorsoRadius)
  leftShortsTopCircle = leftHipCircle.interpolateWith(leftShoulderTorsoCircle, bodyAttributes.shortsTorsoRatio)
  rightShortsTopCircle = rightHipCircle.interpolateWith(rightShoulderTorsoCircle, bodyAttributes.shortsTorsoRatio)

  ## Upper arm
  shoulderRadius = viewAngle.sizeToScreen(bodyAttributes.shoulderRadius)
  leftShoulderCircle = Circle(leftShoulderCoordinates, shoulderRadius)
  rightShoulderCircle = Circle(rightShoulderCoordinates, shoulderRadius)
  leftElbowCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftElbow)
  rightElbowCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightElbow)
  elbowRadius = viewAngle.sizeToScreen(bodyAttributes.elbowRadius)
  leftElbowCircle = Circle(leftElbowCoordinates, elbowRadius)
  rightElbowCircle = Circle(rightElbowCoordinates, elbowRadius)

  ## Lower arm
  leftHandCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.leftHand)
  rightHandCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.rightHand)
  handRadius = viewAngle.sizeToScreen(bodyAttributes.handRadius)
  wristRadius = viewAngle.sizeToScreen(bodyAttributes.wristRadius)
  leftHandCircle = Circle(leftHandCoordinates, handRadius)
  leftWristCircle = Circle(leftHandCoordinates, wristRadius)
  rightHandCircle = Circle(rightHandCoordinates, handRadius)
  rightWristCircle = Circle(rightHandCoordinates, wristRadius)

  ## Head
  headBottomCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.headBottom)
  headTopCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.headTop)
  headBottomRadius = viewAngle.sizeToScreen(bodyAttributes.headBottomRadius)
  headTopRadius = viewAngle.sizeToScreen(bodyAttributes.headTopRadius)
  headBottomCircle = Circle(headBottomCoordinates, headBottomRadius)
  headTopCircle = Circle(headTopCoordinates, headTopRadius)

  ## Hair
  hairTopCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.hairTop)
  hairMiddleCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.hairMiddle)
  hairBottomCoordinates = viewAngle.coordinateToScreen(bodyCoordinates.hairBottom)
  hairTopRadius = viewAngle.sizeToScreen(bodyAttributes.hairTopRadius)
  hairMiddleRadius = viewAngle.sizeToScreen(bodyAttributes.hairMiddleRadius)
  hairBottomRadius = viewAngle.sizeToScreen(bodyAttributes.hairBottomRadius)
  hairTopCircle = Circle(hairTopCoordinates, hairTopRadius)
  hairMiddleCircle = Circle(hairMiddleCoordinates, hairMiddleRadius)
  hairBottomCircle = Circle(hairBottomCoordinates, hairBottomRadius)

  ## Draw
  ### Left arm
  interpolateCircles(leftShoulderCircle, leftElbowCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  interpolateCircles(leftElbowCircle, leftWristCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  plotCircle(leftHandCircle, bodyAttributes.skinTone, draw)

  ### Left leg
  interpolateCircles(leftKneeCircle, leftAnkleCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  interpolateCircles(leftKneeCircle, leftBottomShortsCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  interpolateCircles(leftBottomShortsCircle, leftHipCircle, bodyAttributes.shortsColor, RESOLUTION, draw)
  interpolateCircles(leftAnkleCircle, leftToeCircle, bodyAttributes.shoeColor, RESOLUTION, draw)

  ### Right leg
  interpolateCircles(rightKneeCircle, rightAnkleCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  interpolateCircles(rightAnkleCircle, rightToeCircle, bodyAttributes.shoeColor, RESOLUTION, draw)
  interpolateCircles(rightKneeCircle, rightBottomShortsCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  interpolateCircles(rightBottomShortsCircle, rightHipCircle, bodyAttributes.shortsColor, RESOLUTION, draw)

  ### Torso
  interpolateCircles(leftHipCircle, leftShortsTopCircle, bodyAttributes.shortsColor, RESOLUTION, draw)
  interpolateCircles(rightHipCircle, rightShortsTopCircle, bodyAttributes.shortsColor, RESOLUTION, draw)
  interpolateCircles(leftShortsTopCircle, leftShoulderTorsoCircle, bodyAttributes.singletColor, RESOLUTION, draw)
  interpolateCircles(rightShortsTopCircle, rightShoulderTorsoCircle, bodyAttributes.singletColor, RESOLUTION, draw)

  ### Right arm
  interpolateCircles(rightShoulderCircle, rightElbowCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  interpolateCircles(rightElbowCircle, rightWristCircle, bodyAttributes.skinTone, RESOLUTION, draw)
  plotCircle(rightHandCircle, bodyAttributes.skinTone, draw)

  ### Head
  interpolateCircles(headBottomCircle, headTopCircle, bodyAttributes.skinTone, RESOLUTION, draw)

  ### Hair
  if (bodyAttributes.hairColor[3] != 0):
    interpolateCircles(hairTopCircle, hairMiddleCircle, bodyAttributes.hairColor, RESOLUTION, draw)
    interpolateCircles(hairMiddleCircle, hairBottomCircle, bodyAttributes.hairColor, RESOLUTION, draw)

  ## Lower legs
  ## Upper legs
  ## Torso
  ## Upper arms
  ## Lower arms
  ## Head

myViewAngle = ViewAngle(degreesToRadians(30), 5, 75, 200)
myBodyAttributes = BodyAttributes()
myBodyPositions = BodyPositions()

DEFAULT_TORSO_TO_GROUND_ANGLE = degreesToRadians(85)
# right foot forward
rightForwardBodyPositions = BodyPositions()

rightForwardBodyPositions.torsoToGroundAngle = DEFAULT_TORSO_TO_GROUND_ANGLE
rightForwardBodyPositions.torsoToGroundHeight = 13.66
rightForwardBodyPositions.leftHipAngle = degreesToRadians(120)
rightForwardBodyPositions.leftKneeAngle = degreesToRadians(90)
rightForwardBodyPositions.rightHipAngle = degreesToRadians(260)
rightForwardBodyPositions.rightKneeAngle = degreesToRadians(135)
rightForwardBodyPositions.leftElbowAngle = degreesToRadians(50)
rightForwardBodyPositions.rightElbowAngle = degreesToRadians(120)
rightForwardBodyPositions.leftShoulderAngle = degreesToRadians(-30)
rightForwardBodyPositions.rightShoulderAngle = degreesToRadians(65)
rightForwardBodyPositions.leftAnkleAngle = degreesToRadians(110)
rightForwardBodyPositions.rightAnkleAngle = degreesToRadians(90)

# right foot max extent
rightPlantBodyPositions = BodyPositions()
rightPlantBodyPositions.torsoToGroundAngle = DEFAULT_TORSO_TO_GROUND_ANGLE
rightPlantBodyPositions.torsoToGroundHeight = 13.89
rightPlantBodyPositions.rightHipAngle = degreesToRadians(200)
rightPlantBodyPositions.rightKneeAngle = degreesToRadians(155)
rightPlantBodyPositions.rightAnkleAngle = degreesToRadians(70)
rightPlantBodyPositions.rightShoulderAngle = degreesToRadians(15)
rightPlantBodyPositions.rightElbowAngle = degreesToRadians(105)
rightPlantBodyPositions.leftHipAngle = degreesToRadians(180)
rightPlantBodyPositions.leftKneeAngle = degreesToRadians(80)
rightPlantBodyPositions.leftAnkleAngle = degreesToRadians(120)
rightPlantBodyPositions.leftShoulderAngle = degreesToRadians(-15)
rightPlantBodyPositions.leftElbowAngle = degreesToRadians(90)

# right toe-off
rightToeoffBodyPositions = BodyPositions()
rightToeoffBodyPositions.torsoToGroundAngle = DEFAULT_TORSO_TO_GROUND_ANGLE
rightToeoffBodyPositions.torsoToGroundHeight = 15.5
rightToeoffBodyPositions.rightHipAngle = degreesToRadians(175)
rightToeoffBodyPositions.rightKneeAngle = degreesToRadians(165)
rightToeoffBodyPositions.rightAnkleAngle = degreesToRadians(80)
rightToeoffBodyPositions.rightShoulderAngle = degreesToRadians(5)
rightToeoffBodyPositions.rightElbowAngle = degreesToRadians(85)
rightToeoffBodyPositions.leftHipAngle = degreesToRadians(245)
rightToeoffBodyPositions.leftKneeAngle = degreesToRadians(70)
rightToeoffBodyPositions.leftAnkleAngle = degreesToRadians(90)
rightToeoffBodyPositions.leftShoulderAngle = degreesToRadians(10)
rightToeoffBodyPositions.leftElbowAngle = degreesToRadians(110)

#rightPlantBodyPositions.leftHipAngle = degreesToRadians(

leftForwardBodyPositions = rightForwardBodyPositions.invert()
leftPlantBodyPositions = rightPlantBodyPositions.invert()
leftToeoffBodyPositions = rightToeoffBodyPositions.invert()

#rightForwardBodyCoordinates = BodyCoordinates(myBodyAttributes, rightForwardBodyPositions)
#rightPlantBodyCoordinates = BodyCoordinates(myBodyAttributes, rightPlantBodyPositions)
#rightToeoffBodyCoordinates = BodyCoordinates(myBodyAttributes, rightToeoffBodyPositions)

# left foot forward

#print(rightForwardBodyCoordinates.toString())

bodyPositionsSet = [rightForwardBodyPositions, rightPlantBodyPositions, rightToeoffBodyPositions, leftForwardBodyPositions, leftPlantBodyPositions, leftToeoffBodyPositions]
framesAfter = [10, 5, 10, 10, 5, 10]

FRAMES_PER_POSITION=10

#frameCount = 0

#frames = []

drawnCount = 0

lookCount = 0
for commonLook in players.commonLooks:
  kitCount = 0
  for professionalKit in players.professionalKits:
    thisBodyAttributes = BodyAttributes()
    thisBodyAttributes.singletColor = players.professionalKits[professionalKit].singletColor
    thisBodyAttributes.shortsColor = players.professionalKits[professionalKit].shortsColor
    thisBodyAttributes.shoeColor = players.professionalKits[professionalKit].shoeColor
    thisBodyAttributes.skinTone = commonLook.skinTone
    thisBodyAttributes.hairColor = commonLook.hairColor
    frameCount = 0
    for i in range(len(bodyPositionsSet)):
      numFrames = framesAfter[i]
      for j in range(numFrames):
        filename = "sprites/player/" + str(kitCount) + "_" + str(lookCount) + "_" + str(frameCount) + ".png"
        bodyPositionsStart = bodyPositionsSet[i]
        bodyPositionsEnd = bodyPositionsSet[(i+1) % len(bodyPositionsSet)]
        interpolateRatio = j/FRAMES_PER_POSITION
        bodyPositionsToPlot = bodyPositionsStart.interpolateWith(bodyPositionsEnd, interpolateRatio)
        bodyCoordinatesToPlot = BodyCoordinates(thisBodyAttributes, bodyPositionsToPlot)
        image = Image.new('RGBA', (150, 300), (0, 0, 0, 0))
        draw = ImageDraw.Draw(image)
        drawBody(bodyCoordinatesToPlot, thisBodyAttributes, myViewAngle, draw)
    #    frames.append(image)
        image.save(filename, "PNG")
        frameCount += 1
    kitCount += 1
    drawnCount += 1
  lookCount += 1
  print("Drawn: " + str(drawnCount))


#coding: utf-8
from django.contrib import messages
from django.contrib.auth import login as auth_login
from django.contrib.auth.views import login
from django.core.urlresolvers import reverse_lazy
from django.views.generic import FormView
from main.forms import RegistrationForm, LoginForm

def activate_old_way_user(request):
    if request.user.username == 'vitalik':
        request.session['player'] = 2
    elif request.user.username == 'nadi':
        request.session['player'] = 1
    else:
        request.session['player'] = 0

def custom_login(request):
    response = login(request, template_name='login.html',
                     authentication_form=LoginForm,
                     extra_context={'reg_form': RegistrationForm()})
    activate_old_way_user(request)
    return response

class RegistrationView(FormView):
    template_name = 'registration.html'
    form_class = RegistrationForm
    success_url = reverse_lazy('games')

    def get_context_data(self, **kwargs):
        context = super(RegistrationView, self).get_context_data(**kwargs)
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        context.update({
            'reg_form': form,
        })
        return context

    def form_valid(self, form):
        user = form.save()
        user.backend = 'django.contrib.auth.backends.ModelBackend'
        auth_login(self.request, user)
        activate_old_way_user(self.request)
        messages.success(self.request,
                         u'Ваша учетная запись была успешно создана.')
        return super(RegistrationView, self).form_valid(form)


from itertools import combinations
N, K = map(int, input().split())
# a, n, t, i, c 는 기본적으로 배워야 함
D = "antic"
B = []
for _ in range(N):
    s = input()
    if K < 5:
        print(0)
        exit(0)
    b = 0
    for c in s:
        if c in D:
            continue
        diff = ord(c) - ord('a')
        if b & 1 << diff == 0:
            b = b | 1 << diff
    B.append(b)

C = []
for i in range(26):
    c = chr(i + ord('a'))
    if c in D:
        continue
    C.append(c)

ans = 0
for lis in combinations(C, K-5):
    C = 0
    cand = 0
    for c in lis:
        C = C | 1 << ord(c) - ord('a')
    for b in B:
        if b & C == b:
            cand += 1
    ans = max(ans, cand)
print(ans)


from functools import update_wrapper
from typing import List, Optional, Callable, Union

from aiocqhttp import Event as CQEvent
from aiocqhttp.bus import EventBus

from . import NoneBot
from .exceptions import CQHttpError
from .log import logger
from .session import BaseSession

_bus = EventBus()

class EventHandler:
    __slots__ = ('events', 'func', '__name__', '__qualname__', '__doc__',
                 '__annotations__', '__dict__')

    def __init__(self, events: List[str], func: Callable):
        self.events = events
        self.func = func

def _make_event_deco(post_type: str) -> Callable:
    def deco_deco(arg: Optional[Union[str, Callable]] = None,
                  *events: str) -> Callable:
        def deco(func: Callable) -> EventHandler:
            if isinstance(arg, str):
                events_tmp = list(map(lambda x: f"{post_type}.{x}", [arg] + list(events)))
                for e in events_tmp:
                    _bus.subscribe(e, func)
                handler = EventHandler(events_tmp, func)
                return update_wrapper(handler, func)  # type: ignore
            else:
                _bus.subscribe(post_type, func)
                handler = EventHandler([post_type], func)
                return update_wrapper(handler, func)  # type: ignore

        if isinstance(arg, Callable):
            return deco(arg)  # type: ignore
        return deco

    return deco_deco

on_notice = _make_event_deco('notice')
on_request = _make_event_deco('request')

class NoticeSession(BaseSession):
    __slots__ = ()

    def __init__(self, bot: NoneBot, event: CQEvent):
        super().__init__(bot, event)

class RequestSession(BaseSession):
    __slots__ = ()

    def __init__(self, bot: NoneBot, event: CQEvent):
        super().__init__(bot, event)

    async def approve(self, remark: str = '') -> None:
        """
        Approve the request.

        :param remark: remark of friend (only works in friend request)
        """
        try:
            await self.bot.call_action(
                action='.handle_quick_operation_async',
                self_id=self.event.self_id,
                context=self.event,
                operation={'approve': True, 'remark': remark}
            )
        except CQHttpError:
            pass

    async def reject(self, reason: str = '') -> None:
        """
        Reject the request.

        :param reason: reason to reject (only works in group request)
        """
        try:
            await self.bot.call_action(
                action='.handle_quick_operation_async',
                self_id=self.event.self_id,
                context=self.event,
                operation={'approve': False, 'reason': reason}
            )
        except CQHttpError:
            pass

async def handle_notice_or_request(bot: NoneBot, event: CQEvent) -> None:
    if event.type == 'notice':
        _log_notice(event)
        session = NoticeSession(bot, event)
    else:  # must be 'request'
        _log_request(event)
        session = RequestSession(bot, event)

    ev_name = event.name
    logger.debug(f'Emitting event: {ev_name}')
    try:
        await _bus.emit(ev_name, session)
    except Exception as e:
        logger.error(f'An exception occurred while handling event {ev_name}:')
        logger.exception(e)

def _log_notice(event: CQEvent) -> None:
    logger.info(f'Notice: {event}')

def _log_request(event: CQEvent) -> None:
    logger.info(f'Request: {event}')


#!/usr/bin/env python

from socket import socket, AF_INET, SOCK_STREAM

class LazyConnection:
	def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
		self.address = address
		self.family = family
		self.type = type
		self.sock = None

	def __enter__(self):
		if self.sock is not None:
			raise RuntimeError('Alrady connected')
		self.sock = socket(self.family, self.type)
		self.sock.connect(self.address)
		return self.sock

	# exc_ty:异常类型，exc_val:异常值，tb:对挂起异常的追溯
	# 如果忽略异常的话，返回None作为结果。
	# 如果返回True(),异常就被会任务清理干净了。
	def __exit__(self, exc_ty, exc_val, tb):
		self.sock.close()
		self.sock = None

from functools import partial

conn = LazyConnection(('www.python.org', 80))

with conn as s:
	# conn.__enter__() executes: connection open
	s.send(b'GET /index.html HTTP/1.0\r\n')
	s.send(b'Host: www.python.org\r\n')
	s.send(b'\r\n')
	resp = b''.join(iter(partial(s.recv, 8192), b''))
	print (resp)
	# conn.__exit() execuste:connection closed