class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

#前序遍历
def preOrderNonRecursion(root):
    if root == None:
        return None

    stack = []
    stack.append(root)
    while stack:
        node = stack.pop(-1)
        print(node.val)
        if node.right:
            stack.append(node.right)
        if node.left:
            stack.append(node.left)

#中序遍历
def inOrderNonRecursion(root):
    if root == None:
        return None

    stack = []
    while stack or root:
        while root:
            stack.append(root)
            root = root.left
        root = stack.pop(-1)
        print(root.val)
        root = root.right

#后序遍历使用两个栈
def postOrderNonRecursion(root):
    if root == None:
        return None
    else:
        s1 = []
        s2 = []
        s1.append(root)
        while s1:
            node = s1.pop(-1)
            s2.append(node)
            if node.left :
                s1.append(node.left)
            if node.right:
                s1.append(node.right)
        while s2:
            print(s2.pop(-1).val)

#后序遍历使用一个栈
def postOrderNonRecursion1(root):
    if root == None:
        return
    else:
        stack = []
        while root or stack:
            while root:
                stack.append(root)
                root = root.left if root.left else root.right
            root = stack.pop(-1)
            print(root.val)
            if stack and stack[-1].left == root:
                root = stack[-1].right
            else:
                root = None


''' This program takes 1 argument = DataFile. It will parse file and present data in 2d Array
    DataParse['Make'] = [Year][Image]
    Duplicate Images are stored as seperate values
'''

import re
import linecache
from collections import defaultdict

class DataParse:
    def __init__(self, inputFile):
        self.file = inputFile
        self.index = self.generateIndex()
        self.data = self.loadData()

    def generateIndex(self):
        #Function will find sections in text file and get image and index
        f = open(self.file, "r")
        indexOutput = []
        number = 0

        for line in f:
            number += 1
            if (".iso" not in line) and (".isz" not in line): #Find start indeces of iso contents
                continue
            else:
                #print (line, number)
                image = re.findall('\(([^)]+)', line)[0]
                indexOutput.append([image, number])

        f.close()
        return indexOutput

    def loadData(self):
        #Function will read the input data and sort it in Dictlist
        #Dictlist['make'] = [Year, Disc]

        index = self.index
        data = defaultdict(list)

        for i in index: #i = [imageName, lineWhereFound]
            try:
                next = index[index.index(i)+1] #Get ranges
                #print (i[1], next[1])
            except IndexError:
                continue

            for j in range(i[1]+1,next[1]-1): #Get makes and build Dictlist. i[0] has image name
                section = linecache.getline(self.file, j) # Get each line in range i-i+1
                section = ' '.join( section.split() ) #remove special characters

                try:
                    int(section[-2]) #Simple expression to remove extra lines
                    make = section.rsplit(' ',1)[0] #Split lines
                    year = section.rsplit(' ',1)[1]

                    if ( "-" in year ): #Found range
                        starty = year.split('-')[0]
                        endy = year.split('-')[1]
                        if int(starty) < 100: #Different year format
                            starty = "19" + starty
                            endy = "19" + endy

                        for k in range( int(starty),int(endy)+1 ): #decrementing and incrementing to get 2 edge years
                            data[make].append([str(k),i[0]]) #For every year in the range
                    elif int(year) < 100: #Different year format
                        year = "19" + year
                        data[make].append([year,i[0]])
                    else:
                        data[make].append([year,i[0]])

                except:
                    continue

        return data


# -*- coding:utf-8 -*-

import socket

def main():

    # 1. 创建套接字对象
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 获取服务器的IP和端口
    dest_ip = input('请输入服务器的IP：')
    dest_port = int(input('请输入服务器的port：'))

    # 3. 链接服务器
    tcp_socket.connect((dest_ip, dest_port))

    # 4. 获取下载的文件名字
    download_file_name = input('请输入要下载的文件名称：')

    # 5. 将文件名字发送到服务器
    tcp_socket.send(download_file_name.encode('utf-8'))

    # 6. 接收文件中的数据
    recv_data = tcp_socket.recv(1024) # 1024--->1K  1024*1024--->1K*1024=1M

    # 7. 保存接收的数据到一个文件中
    if recv_data:
        with open('004_new_' + download_file_name, 'wb') as f:
            f.write(recv_data)

    # 8. 关闭套接字
    tcp_socket.close()

if __name__ == '__main__':
    main()

# 运行方式1：网络调试助手作为服务器端
# 打开网络调试助手作为服务器端，然后打开运行
# 运行代码，输入网络调试助手的IP和port
# 发送要下载的文件名称，随便写一个作为测试
# 服务器端发送数据给客户端(当做要下载文件的数据)
# 客户端接收数据，然后打开一个文件，将数据保存进去
# 下载的文件：004_new_test_file

# 运行方式2:005作为服务器端
# 先运行005，在运行004
# 下载的文件：004_new_test_file_1


# Lab 5 - Week 6
# @Author: Nurtay Maksat
# Method Parabola

import random
import math

E = 0.25
a = 1.2
b = 6.3
x1, x2, x3 = 0, 0, 0
Y = None
Y_PREV = None

def f(x):
    return 5 * math.sin(2*x) + x**2

def q(x):
    global x1, x2, x3
    a0 = f(x1)
    a1 = (f(x2)-a0) / (x2-x1)
    a2 = (f(x3)-a0-a1*(x3-x1)) / ((x3-x1)*(x3-x2))
    return a0 + a1*(x-x1) + a2*(x-x1)*(x-x2)

def q_derivative():
    global x1, x2, x3
    a0 = f(x1)
    a1 = (f(x2)-a0) / (x2-x1)
    a2 = (f(x3)-a0-a1*(x3-x1)) / ((x3-x1)*(x3-x2))
    return 1/2 * (x1 + x2 - a1/a2)

def calculate():
    global a, b, Y, Y_PREV
    global x1, x2, x3
    while True:
        # --- Step 1
        while True:
            x1 = random.uniform(a, b)
            x2 = random.uniform(x1, b)
            x3 = random.uniform(x2, b)
            f1 = f(x1)
            f2 = f(x2)
            f3 = f(x3)
            if (f1 >= f2 and f2 <= f3):
                break

        # --- Step 2
        Y_PREV = Y
        Y = q_derivative()

        # --- Step 3
        if Y_PREV != None:
            delta = abs(Y - Y_PREV)
            if delta <= E:
                return

        # --- Step 4
        print('f(x*): ', f(Y))

        # --- Step 5
        a = x1
        b = x3

print('-'*50)
calculate()
print('-'*50)
print('Xmin:   ', Y)
print('f(min): ', f(Y))


from dataset import ISICDataset, get_transform
from modules import get_model
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from tqdm import tqdm
import pickle

MODE = "debug"
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
model = get_model()
model = model.to(device)
if MODE == "debug":
    print(device)

train_data = ISICDataset(
    image_folder_path="./data/ISIC-2017_Training_Data",
    mask_folder_path="./data/ISIC-2017_Training_Part1_GroundTruth",
    diagnoses_path="./data/ISIC-2017_Training_Part3_GroundTruth.csv",
    device=device,
    transform=get_transform(True),
    )
train_data = torch.utils.data.Subset(train_data, range(100))
train_dataloader = torch.utils.data.DataLoader(
    train_data,
    batch_size=2,
    shuffle=True,
    collate_fn=lambda x:tuple(zip(*x)),
    # num_workers=4
    )

test_data = ISICDataset(
    image_folder_path="./data/ISIC-2017_Test_Data",
    mask_folder_path="./data/ISIC-2017_Test_v2_Part1_GroundTruth",
    diagnoses_path="./data/ISIC-2017_Test_v2_Part3_GroundTruth.csv",
    device=device,
    transform=get_transform(True),
    )
# train_data = torch.utils.data.Subset(train_data, range(250))
test_dataloader = torch.utils.data.DataLoader(
    train_data,
    batch_size=2,
    shuffle=True,
    collate_fn=lambda x:tuple(zip(*x)),
    # num_workers=4
    )

def single_epoch(model, optimizer, dataloader, device, epoch):
    it = 0
    total_losses = []
    for images, targets in tqdm(dataloader):
        # load tensors into GPU
        images = [image.to(device) for image in images]
        targets = [{k: v.to(device) for k, v in target.items()} for target in targets]

        # perform backprop
        optimizer.zero_grad()
        losses = model(images, targets)
        total_loss = sum(loss for loss in losses.values())
        total_loss.backward()
        # nn.utils.clip_grad_value_(model.parameters(), 5)
        optimizer.step()
        total_losses.append(total_loss.detach().cpu().item())

        it += 1
        if it % 10 == 0:
            fig, ax = plt.subplots()
            ax.plot(total_losses)

    return total_losses

def train_model(model, train_dataloader, test_dataloader, n_epochs):
    model.to(device)
    params = [p for p in model.parameters() if p.requires_grad]
    optimizer = torch.optim.SGD(params, lr=0.0025, weight_decay=0.0001, momentum=0.9)
    lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,
                                                   step_size=3,
                                                   gamma=0.1)
    model.train()
    training_loss = []
    testing_loss = []
    for epoch in tqdm(range(n_epochs)):
        all_losses = single_epoch(model, optimizer, train_dataloader, device, epoch)
        lr_scheduler.step()
        training_loss.append(sum(all_losses))
        with torch.no_grad():
            all_losses = []
            for images, targets in tqdm(test_dataloader):
                images = [image.to(device) for image in images]
                targets = [{k: v.to(device) for k, v in target.items()} for target in targets]
                losses = model(images, targets)
                total_loss = sum(loss for loss in losses.values())
                all_losses.append(total_loss.detach().cpu().item())

            testing_loss.append(sum(all_losses))

        fig, ax = plt.subplots()
        ax.plot(training_loss, label="Train")
        ax.plot(testing_loss, label="Test")
        ax.legend()

    return training_loss, testing_loss

if __name__ == "__main__":
    training_loss, testing_loss = train_model(model, train_dataloader, test_dataloader, 20)
    torch.save(model.state_dict(), "Mask_RCNN_ISIC4.pt")
    with open('training_loss.pickle', 'wb') as handle:
        pickle.dump(training_loss, handle, protocol=pickle.HIGHEST_PROTOCOL)

    with open('testing_loss.pickle', 'wb') as handle:
        pickle.dump(testing_loss, handle, protocol=pickle.HIGHEST_PROTOCOL)


from rest_framework import serializers
from django.contrib.auth.models import User
from crypto_currencies.models import Crypto

class CryptoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Crypto
        fields = [
            "id",
            "name",
            "slug",
            "price",
            "total_supply",
            "market_cap",
            "volume_change_24h",
            "percent_change_24h",
            "user_favourite",
        ]

class UserSerializer(serializers.ModelSerializer):
    favourite = CryptoSerializer(many=True, read_only=True)

    class Meta:
        model = User
        fields = ["id", "username", "favourite"]


from django.contrib.auth import logout  # last 2 imported
from django.contrib.auth.decorators import login_required
from django.shortcuts import render

from shared.forms import TeamMemberApprovalForm, \
    ProfileModelForm, UserModelForm
from .context_functions import *

# attempt
@login_required
def attempt_list_view(request, id):
    if not request.user.profile.number:
        return redirect('complete_profile')
    if not request.user.profile.valid:
        return redirect('not_active')

    template_name = 'components/teams/team_submission_list.html'

    contest_obj = get_object_or_404(Contest, id=id)
    context = {'contest': contest_obj}

    team_obj, members = get_user_team(request, contest_obj.id)
    if not team_obj:
        return redirect(os.path.join(contest_obj.get_absolute_url(), 'team/join/'))

    atempts = get_team_attempts(team_obj)

    if atempts:
        context.update({'number_of_submitions': atempts.count()})
        context.update({'last_classification': atempts.first().grade})
        context.update({'last_execution_time': atempts.first().time_benchmark})
        context.update({'last_memory_usage': atempts.first().memory_benchmark})
        if os.path.isfile(atempts.first().file.path):
            context.update({'download': atempts.first().file})
        else:
            context.update({'download': 0})
    else:
        context.update({'number_of_submitions': 0})
        context.update({'last_classification': 0})
        context.update({'last_execution_time': 0})
        context.update({'last_memory_usage': 0})
        context.update({'download': 0})

    team_obj.members = members
    context.update({'team': team_obj})
    context.update({'atempts': atempts})
    context.update({'title': "Status"})

    return render(request, template_name, context)

# contest
@login_required
def contest_list_view(request):
    if not request.user.profile.number:
        return redirect('complete_profile')
    if not request.user.profile.valid:
        return redirect('not_active')

    template_name = 'views/contest_detail_home.html'

    if request.user.is_superuser:
        contests_qs = Contest.objects.all()
    else:
        contests_qs = Contest.objects.filter(visible=True)

    qs = TeamMember.objects.select_related('team').filter(user=request.user)

    context = {'object_list': contests_qs,
               'team_contests': qs,
               'title': 'Contests',
               'description': 'PANDORA is an Automated Assement Tool.'}
    return render(request, template_name, context)

@login_required
def contest_detail_view(request, id):
    if not request.user.profile.number:
        return redirect('complete_profile')
    if not request.user.profile.valid:
        return redirect('not_active')

    obj = get_object_or_404(Contest, id=id)

    present = timezone.now()
    if present < obj.start_date:
        # contest is not yet open. Don't let anyone see a dam thing.
        template_name = 'contest/closed_error.html'
    else:
        template_name = 'contest/details.html'

    context = {"contest": obj}
    return render(request, template_name, context)

# profile
@login_required
def profile_view(request):
    template_name = 'profile.html'
    context = {'user': request.user, 'title': "My Information"}
    return render(request, template_name, context)

# ranking
@login_required
def ranking_view(request, id):
    if not request.user.profile.number:
        return redirect('complete_profile')
    if not request.user.profile.valid:
        return redirect('not_active')

    template_name = 'contest/rankings.html'

    contest_obj = get_object_or_404(Contest, id=id)
    context = {'contest': contest_obj}

    atempts = getAllContestAttemptsRanking(contest_obj)

    context.update({'atempts': atempts})
    context.update({'title': "Ranking"})
    return render(request, template_name, context)

# team
@login_required
def team_create_view(request, id):
    if not request.user.profile.number:
        return redirect('complete_profile')
    if not request.user.profile.valid:
        return redirect('not_active')

    template_name = 'components/contests/form.html'
    contest_obj = get_object_or_404(Contest, id=id)
    context = {'contest': contest_obj}

    user_team = TeamMember.objects.select_related('team').filter(team__contest=contest_obj.id,
                                                                 user=request.user).first()

    if user_team:
        # this user already has a team
        return redirect(os.path.join(contest_obj.get_absolute_url(), 'my_team/'))

    # in case individual submition - Create a team with the username with only one member
    if contest_obj.max_team_members == 1:
        t = Team(name=request.user.username, contest=contest_obj)
        t.save()
        tm = TeamMember(team=t, user=request.user, approved=True)
        tm.save()
        return redirect(os.path.join(contest_obj.get_absolute_url(), 'my_team/'))

    form = TeamModelForm(request.POST or None)
    if form.is_valid():
        obj = form.save(commit=False)
        obj.contest = contest_obj
        obj.save()
        team_member_obj = TeamMember()
        team_member_obj.user = request.user
        team_member_obj.approved = True
        team_member_obj.team = obj
        team_member_obj.save()
        return redirect(os.path.join(contest_obj.get_absolute_url(), 'my_team/'))

    context.update({'form': form})
    context.update({"title": 'Create New Team'})
    return render(request, template_name, context)

@login_required
def team_join_view(request, id):
    if not request.user.profile.number:
        return redirect('complete_profile')
    if not request.user.profile.valid:
        return redirect('not_active')

    template_name = 'components/contests/teams/team_join.html'
    contest_obj = get_object_or_404(Contest, id=id)
    context = {'contest': contest_obj}

    user_team, members = get_user_team(request, contest_obj.id)
    user_team.members = members
    # TeamMember.objects.select_related('team').filter(team__contest = contest_obj.id, user = request.user).first()

    if user_team:
        return redirect(os.path.join(contest_obj.get_absolute_url(), 'my_team/'))

    # in case individual submition - Create a team with the username with only one member
    if contest_obj.max_team_members == 1:
        t = Team(name=request.user.username, contest=contest_obj)
        t.save()
        tm = TeamMember(team=t, user=request.user, approved=True)
        tm.save()
        return redirect(os.path.join(contest_obj.get_absolute_url(), 'my_team/'))

    # get all teams active in this contenst
    teams = Team.objects.filter(contest__id=id)  # get all teams associated with this contest

    # set the members details and the amount of new member that can join
    for obj in teams:
        obj.members = TeamMember.objects.filter(team=obj)
        obj.room_left = obj.contest.max_team_members - obj.members.count()

    # update the contenxt to send to the team_join.html
    context.update({'teams': teams})

    # no idea what it does
    form = TeamMemberForm(request.POST or None)

    if form.is_valid():
        team_id = form.cleaned_data.get("team_id")
        team_member = TeamMember()

        team = Team.objects.get(id=team_id)

        qs = team.teammember_set.all()
        if qs.count() > team.contest.max_team_members:
            messages.error(request, "Error! This team can not accept new members")
        else:
            team_member.team = team
            team_member.user = request.user
            team_member.approved = False
            team_member.save()
            return redirect(os.path.join(contest_obj.get_absolute_url(), 'my_team/'))
        form = TeamMemberForm()

    # context.update({'form': form})
    return render(request, template_name, context)

# ------------------------------------------------------ The rest ------------------------------------------------------
# page logout
def pagelogout(request):
    if request.method == "POST":
        logout(request)
        return redirect('home')

# non active view
def nonactive_view(request):
    template_name = 'contest/error_message_dialog_box.html'
    context = {'title': 'Not active',
               'description': 'Your account is not active. Please wait for the administrator to activate your account.'}
    return render(request, template_name, context)

@login_required
def complete_profile_view(request):
    profile_form = ProfileModelForm(request.POST or None, instance=request.user.profile)
    user_form = UserModelForm(request.POST or None, instance=request.user)

    if all((profile_form.is_valid(), user_form.is_valid())):
        profile_form.save()
        user_form.save()
        return redirect('home')
    else:
        user_form = UserModelForm(request.POST or None, instance=request.user)
        profile_form = ProfileModelForm(request.POST or None, instance=request.user.profile)

    context = {'form': user_form,
               'form2': profile_form,
               'title': 'Complete Information'}
    return render(request, 'form.html', context)

@login_required
def home_view_old(request):
    template_name = 'contest/dashboard.html'
    context = {'title': "Dashboard"}
    return render(request, template_name, context)

#############################
#         NEW VIEWS         #
#############################

# TEAM DETAIL
@login_required
def team_detail_view(request, id):
    checkUserProfileInRequest(request)
    template_name = 'views/contests/teams/team.html'
    contest = getContestByID(id)
    context = getContestDetailLayoutContext(contest)
    # qs = TeamMember.objects.select_related('team').filter(team__contest = contest_obj.id, user = request.user).first()
    team = getUserTeamFromContest(request, contest)
    if not team:
        return redirect(os.path.join(contest.get_absolute_url(), 'team/join/'))

    team_member_obj = TeamMember.objects.get(team=team, user=request.user)

    can_be_deleted = True
    if team.members.count() > 1 or not team_member_obj.approved or get_team_attempts(team):
        can_be_deleted = False

    form = TeamMemberApprovalForm(request.POST or None)
    if form.is_valid():
        if "team_delete" in request.POST and can_be_deleted:
            team_member_obj.delete()
            team.delete()
            return redirect(os.path.join(contest.get_absolute_url(), 'team/join/'))

        if team_member_obj.approved:  # TODO: Is this duplicated check necessary?
            if "member_id" in request.POST:
                team_member_obj2 = TeamMember.objects.get(id=form.cleaned_data.get("member_id"))
                team_member_obj2.approved = True
                team_member_obj2.save()

        if team.members.count() > 1 and "member_id_remove" in request.POST:
            team_member_obj2 = TeamMember.objects.get(id=form.cleaned_data.get("member_id_remove"))
            if (team_member_obj2 == team_member_obj and not team_member_obj2.approved) or team_member_obj.approved:
                team_member_obj2.delete()
                return redirect(os.path.join(contest.get_absolute_url(), 'team/join/'))

        form = TeamMemberApprovalForm()
        team.members = team.teammember_set.all()

    team.members = team.teammember_set.all()

    context.update({'team': team})
    context.update({'can_delete': can_be_deleted})  # it it only has one member, it can be deleted
    context.update({'can_approve': team_member_obj.approved})  # it it only has one member, it can be deleted
    context.update({'form': form})
    print_variables_debug([
        "Context: " + str(context),
    ])
    return render(request, template_name, context)


N = 5
aux = -1
vetor = [None] * N

for i in range(N):
	vetor[i] = int(input('Entre com o ' + str(i + 1) + 'º valor: '))

for i in range(N - 1):
	aux = vetor[i]
	menor = vetor[i+1]
	pos = i + 1
	for j in range(i + 1, N):
		if vetor[j] < menor:
			menor = vetor[j]
			pos = j
	if menor < aux:
		vetor[i] = vetor[pos]
		vetor[pos] = aux

for i in range(N):
	print(str(i + 1) + '° número: ' + str(vetor[i]), end='\n')


# The purpose of this script is combine the GWSI and Wells55 databases into one
# Written by Danielle Tadych
# Goals:
# - Create columns in each respective database specifying its origin
# - Find column they have in common
# - Merge based on that column
# - Make GWSI wells the overriding database and fill in the gaps with Wells55
# %%
import os
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import datetime
import seaborn as sns
import geopandas as gp

# %%
# ----- Import the Data and Shapefiles with Geometries -----
shapedir = '../MergedData/Shapefiles'
outputpath = '../MergedData/Output_files/'

wellfilename = "Well_Registry__Wells55_.shp"
Wellfp = os.path.join(shapedir, wellfilename)
wells55shape = gp.read_file(Wellfp)

GWSI_fn = "GWSI_SITES.shp"
Wellfp = os.path.join(shapedir, GWSI_fn)
GWSIshape = gp.read_file(Wellfp)
# %%
GWSIshape.info()
# %%
wells55shape.info()
# %% Check that they're in the same coordinate system
print(GWSIshape.crs, wells55shape.crs)

# %%
# Preliminary Plot to check shapefiles
fig, ax = plt.subplots()
GWSIshape.plot(ax = ax, label="GWSI")
wells55shape.plot(ax = ax, label="Wells55")
ax.set_title("GWSI and Wells55 Preliminary Plot")
plt.legend()

# %% Making copies of the databases so I don't overright the originals
gwsi_gdf = GWSIshape
wells55_gdf = wells55shape

# This was to filter by driller license number but that's dumb
#wells55_gdf = wells55_gdf[wells55_gdf['DLIC_NUM'].notna()]
#wells55_gdf.info()

# ---- Adding Database Source Columns to both ----
wells55_gdf["Original_DB"] = 'Wells55'
gwsi_gdf["Original_DB"] = 'GWSI'
wells55_gdf.head()
# %%
gwsi_gdf.head()

# %% Fixing the date so that 1/1/70 in Wells55 is replaced with NAN
# https://stackoverflow.com/questions/29247712/how-to-replace-a-value-in-pandas-with-nan
wells55_gdf['INSTALLED'] = wells55_gdf['INSTALLED'].replace(['1970-01-01'], np.NaN)
wells55_gdf['INSTALLED'].unique()

# %% ---- Merging Both databases ----

# Merge wells55 'REGISTRY_I' with GWSI 'REG_ID'
# need to use how = left
#  - more info here https://www.datasciencemadesimple.com/join-merge-data-frames-pandas-python/
#  - and here regarding default options for merge
#    https://stackabuse.com/how-to-merge-dataframes-in-pandas/#mergedataframesusingmerge

# %% Changing REG_ID in GWSI to REGISTRY_I
gwsi_gdf.rename(columns={'REG_ID':'REGISTRY_I'}, inplace=True)

# %% combine registry ID and Site ID so in timeseries graphs every well has an ID
gwsi_gdf['Combo_ID'] = gwsi_gdf.REGISTRY_I.combine_first(gwsi_gdf.SITE_ID)
gwsi_gdf.info()

# %%
wells55_gdf['Combo_ID'] = wells55_gdf['REGISTRY_I']
wells55_gdf.info()

# -- Stop here if you want to filter the wells55 database for specific uses
# -- skip to line 98
# %%
#Wells55_GWSI_MasterDB = wells55_gdf.merge(gwsi_gdf, suffixes=['_wells55','_gwsi'], how="outer", left_on="REGISTRY_I", right_on="REG_ID")
Wells55_GWSI_MasterDB = pd.merge(gwsi_gdf, wells55_gdf, suffixes=['_gwsi','_wells55'], how="outer",
#                                          left_on=["REGISTRY_I", 'WELL_DEPTH', 'geometry', 'Original_DB'],
#                                          right_on=["REGISTRY_I", 'WELL_DEPTH', 'geometry', 'Original_DB'])
                                          on=['OBJECTID','Combo_ID',"REGISTRY_I", 'WELL_DEPTH', 'geometry', 'Original_DB'])
print(Wells55_GWSI_MasterDB.info())

# %% Looking for flaming duplicates
print(Wells55_GWSI_MasterDB[Wells55_GWSI_MasterDB['Combo_ID'].duplicated()])

# %%
test = Wells55_GWSI_MasterDB.groupby(['Combo_ID']).first()
test.info()

# %%
test = test.reset_index()
print(test[test['Combo_ID'] == '921247'].loc[:,['geometry','Original_DB']])

# %% Check for duplicates again
print(test[test['Combo_ID'].duplicated()])

# %% hooray! No duplicates, now to re-create all those damn files
Wells55_GWSI_MasterDB = test

# %%
# Now plot the new master db
fig, ax = plt.subplots()
#gwsi_gdf.plot(ax = ax, label="GWSI")
#wells55_gdf.plot(ax = ax, label="Wells55")
Wells55_GWSI_MasterDB.plot(ax=ax, label="Master Database")
ax.set_title("Check the merged database")
plt.legend()
plt.savefig('../MergedData/Output_files/{0}.png'.format(type), bbox_inches='tight')

# %%
# Export all the ish
Wells55_GWSI_MasterDB.to_csv('../MergedData/Output_files/Master_ADWR_database_noduplicates.csv')
Wells55_GWSI_MasterDB.to_file('../MergedData/Output_files/Master_ADWR_database_noduplicates.shp')
# %%
# --- Filter wells55 and make new MasterDB
# First, deleting the cancelled wells
wells55_nocanc = wells55_gdf[wells55_gdf.WELL_CANCE != 'Y']
wells55_nocanc.info()

#%%
# No classified mineral or exploratory wells
wells55_nomin = wells55_nocanc[wells55_nocanc.WELL_TYPE_ != 'OTHER']
wells55_nomin.info()

# %% Now filter by drill log exisence (not just filed) so we can see which water wells are actually a thing
#wells55_water = wells55_nomin
#wells55_water['DRILL_LOG'] = wells55_water['DRILL_LOG'].replace(None, np.NaN)
wells55_water = wells55_nomin[wells55_nomin['DRILL_LOG'].notna()]
wells55_water.info()

#df = df[df['EPS'].notna()]

# %% Export both the non-cancelled wells and the water wells
#  First the non-cancelled wells
Wells55_GWSI_MasterDB = pd.merge(gwsi_gdf, wells55_nocanc, suffixes=['_gwsi','_wells55'], how="outer",
                                          on=['OBJECTID','Combo_ID',"REGISTRY_I", 'WELL_DEPTH', 'geometry', 'Original_DB'])

print(Wells55_GWSI_MasterDB.info())
#%%
Wells55_GWSI_MasterDB = Wells55_GWSI_MasterDB.groupby(['Combo_ID']).first()
print(Wells55_GWSI_MasterDB.info())

# %%
Wells55_GWSI_MasterDB.to_csv('../MergedData/Output_files/Master_ADWR_database_nocancelled.csv')
Wells55_GWSI_MasterDB.to_file('../MergedData/Output_files/Master_ADWR_database_nocancelled.shp')

# %%
#  - Only water wells
Wells55_GWSI_MasterDB = pd.merge(gwsi_gdf, wells55_water, suffixes=['_gwsi','_wells55'], how="outer",
                                          on=['OBJECTID','Combo_ID',"REGISTRY_I", 'WELL_DEPTH', 'geometry', 'Original_DB'])

print(Wells55_GWSI_MasterDB.info())

# %%
Wells55_GWSI_MasterDB = Wells55_GWSI_MasterDB.groupby(['Combo_ID']).first()
print(Wells55_GWSI_MasterDB.info())

# %%
Wells55_GWSI_MasterDB.to_csv('../MergedData/Output_files/Master_ADWR_database_water.csv')
Wells55_GWSI_MasterDB.to_file('../MergedData/Output_files/Master_ADWR_database_water.shp')
# %% Follow up change to add year to the end
filename_mdb_w = 'Master_ADWR_database_water.shp'
filepath = os.path.join(outputpath, filename_mdb_w)
print(filepath)

masterdb_water = gp.read_file(filepath)
pd.options.display.float_format = '{:.2f}'.format
print(masterdb_water.info())


import sys, json
import torch
import os
import numpy as np
import opennre
from opennre import encoder, model, framework
import sys
import os
import argparse
import logging

parser = argparse.ArgumentParser()
parser.add_argument('--ckpt', default='',
                    help='Checkpoint name')
parser.add_argument('--only_test', action='store_true',
                    help='Only run test')

# Data
parser.add_argument('--metric', default='micro_f1', choices=['micro_f1', 'acc'],
                    help='Metric for picking up best checkpoint')
parser.add_argument('--dataset', default='sanwenchar', choices=['none', 'wiki_distant', 'nyt10'],
                    help='Dataset. If not none, the following args can be ignored')
parser.add_argument('--train_file', default='../sanwenc/train.txt', type=str,
                    help='Training data file')
parser.add_argument('--val_file', default='../sanwenc/valid.txt', type=str,
                    help='Validation data file')
parser.add_argument('--test_file', default='../sanwenc/test.txt', type=str,
                    help='Test data file')
parser.add_argument('--rel2id_file', default='../sanwenc/rel2id.json', type=str,
                    help='Relation to ID file')

# Bag related
parser.add_argument('--bag_size', type=int, default=0,
                    help='Fixed bag size. If set to 0, use original bag sizes')

# Hyper-parameters
parser.add_argument('--batch_size', default=160, type=int,
                    help='Batch size')
parser.add_argument('--lr', default=0.1, type=float,
                    help='Learning rate')
parser.add_argument('--optim', default='sgd', type=str,
                    help='Optimizer')
parser.add_argument('--weight_decay', default=1e-5, type=float,
                    help='Weight decay')
parser.add_argument('--max_length', default=120, type=int,
                    help='Maximum sentence length')
parser.add_argument('--max_epoch', default=100, type=int,
                    help='Max number of training epochs')

args = parser.parse_args()

# Some basic settings
root_path = '.'
sys.path.append(root_path)
if not os.path.exists('ckpt'):
    os.mkdir('ckpt')
if len(args.ckpt) == 0:
    args.ckpt = '{}_{}'.format(args.dataset, 'cnn_soft')
ckpt = 'ckpt/{}.pth.tar'.format(args.ckpt)

root_path = "../sanwenc"

rel2id = json.load(open(args.rel2id_file))

word2id = json.load(open(os.path.join(root_path, 'word2id.json')), )
word2vec = np.load(os.path.join(root_path, 'myvec.npy'))

# Define the sentence encoder
sentence_encoder = opennre.encoder.CNNEncoder(
    token2id=word2id,
    max_length=args.max_length,
    word_size=100,
    position_size=10,
    hidden_size=230,
    blank_padding=True,
    kernel_size=3,
    padding_size=1,
    word2vec=word2vec,
    dropout=0.5
)

# Define the model
model = opennre.model.SoftmaxNN(sentence_encoder, len(rel2id), rel2id)

# Define the whole training framework
framework = opennre.framework.SentenceRE(
    train_path=args.train_file,
    val_path=args.val_file,
    test_path=args.test_file,
    model=model,
    ckpt=ckpt,
    batch_size=args.batch_size,
    max_epoch=100,
    lr=args.lr,
    weight_decay=args.weight_decay,
    opt='sgd'
)

# Train the model
if not args.only_test:
    framework.train_model(args.metric)

# Test
framework.load_state_dict(torch.load(ckpt)['state_dict'])
result = framework.eval_model(framework.test_loader)

# Print the result
logging.info('Test set results:')
if args.metric == 'acc':
    logging.info('Accuracy: {}'.format(result['acc']))
else:
    logging.info('Micro precision: {}'.format(result['micro_p']))
    logging.info('Micro recall: {}'.format(result['micro_r']))
    logging.info('Micro F1: {}'.format(result['micro_f1']))


dicionario = {
    "Ana": 21,
    "Marcela": 34,
    "Pedro": 42
}

print(dicionario) #Imprimindo
print(len(dicionario)) #Imprimindo a qtd de linhas
print(type(dicionario)) #imprindo o typo

#Copiando dicionario exemplo 1
dicionario2 = dicionario.copy() #copiando o dicionario
print("Exemplo dicionario2:", dicionario2)

#Copiando dicionario exemplo 2
dicionario3 = dict(dicionario)
print("Exemplo dicionario3:", dicionario3)

dicionarioPessoas = {
    "Ana": 21,
    "Marcela": 34,
    "Pedro": 42,
    "Pedro": 53
}

print(dicionarioPessoas)

#Pegar a idade da Marcela
dados = dicionarioPessoas["Marcela"]
dados2 = dicionarioPessoas.get("Pedro")
print(dados)
print(dados2)

#Pegar somente os nomes (coluna 1)
nomes = dicionarioPessoas.keys()
print(nomes)

#Pega as idades (coluna 2)
idades = dicionarioPessoas.values()
print(idades)

alimentos = {
    "arroz": 35.90,
    "macarrão": 21.90,
    "feijão": 29
}

print(alimentos)

#Alterando o preço do macarrão
alimentos["macarrão"] = 39.90
print(alimentos)

#Alterando o preço do feijão
alimentos.update({"feijão": 31})
print(alimentos)


# from pudb import set_trace; set_trace()
from typing import List, Set
from collections import defaultdict

class Solution:
    def maxLength(self, arr: List[str]) -> int:
        """LeetCode 1239

        Not very difficult, but we got stuck on when to check the result.
        First of all, we turn each string into a set, and only keep the strings
        that have unique letters themselves.

        Then we generate a directed graph for any pair that do not share letters

        Then we DFS this directed graph, keeping rack of the current set of
        letters that have been concatenated already. For each word, we check
        whether we can concatenate the next child. And for each word, we also
        record in res the current size of the concatenation.

        Time complexity O(N^2). 88 ms, 88% ranking.

        UPDATE: the official solution says the time complexity is O(2^N), which
        I believe.

        I still prefer my way of reasoning. One optimization is to use bit
        manipulation to handle all the work done by set. It is very ingeneous
        to hide the length of the current concatenated size within the first 6
        bits, and use the remaning 26 bits to represent the actual
        word/concatenation. This is pretty smart. I think I can replace all
        the set operation with bit manipulation without changing the core of
        this algo. But I am not doing it today.
        """
        arr_set = [set(a) for a in arr if len(a) == len(set(a))]
        graph = defaultdict(list)
        for i in range(len(arr_set)):
            for j in range(i + 1, len(arr_set)):
                if not arr_set[i].intersection(arr_set[j]):
                    graph[i].append(j)
        self.res = 0

        def dfs(node: int, concat: Set[str]) -> None:
            new_concat = concat.union(arr_set[node])
            for child in graph[node]:
                if not new_concat.intersection(arr_set[child]):
                    dfs(child, new_concat)
            self.res = max(self.res, len(new_concat))

        for i in range(len(arr_set)):
            dfs(i, set())
        return self.res

sol = Solution()
tests = [
    (['un', 'iq', 'ue'], 4),
    (['cha', 'r', 'act', 'ers'], 6),
    (['abcdefghijklmnopqrstuvwxyz'], 26),
    (['ogud', 'ejipchfydrgl', 'b', 'kjxmzhnuoisgqvawel', 'mizlcgdqebwuotfnk', 'bjvkrgeozidytquchlw', 'tzjqwumkirxeal', 'x', 'rkpuabmo'], 20),
]

for i, (arr, ans) in enumerate(tests):
    res = sol.maxLength(arr)
    if res == ans:
        print(f'Test {i}: PASS')
    else:
        print(f'Test {i}; Fail. Ans: {ans}, Res: {res}')


import acme
import certbot
import certbot.account
import certbot.constants
import certbot.main
import certbot.plugins
import certbot.plugins.dns_common
import certbot.interfaces
import errno
import dns
import dns.name
import grp
import hashlib
import logging
import namedlist
import os
import OpenSSL
import pwd
import ipalib
import shutil
import stat
import sys
import zope
import zope.component
import zope.interface

__version__ = '0.0.6'

# Set up logging
logger = logging.getLogger(__name__)

class PermError(Exception):
    """ Raised if permissions don't match specifications/requirments or unsafe permissions are found """
    pass

class IntegrityError(Exception):
    """ Raised if the internal integrity and validity of the application is subject"""
    pass

def check_permission(perm_mode, flags=stat.S_IWOTH):
    """
    Check if a bit is is set in an integer, very useful for checking if
    a particular permission is set of a file by comparing os.stat.st.mode

    Multiple modes can be combined by using by using the bitwise OR operator
     e.g.
    check_permission(0o754, stat.S_IROTH | stat.S_IWGRP)
    -> True

    Valid modes from stat:

        S_ISUID = 04000
        S_ISGID = 02000
        S_ENFMT = S_ISGID
        S_ISVTX = 01000
        S_IREAD = 00400
        S_IWRITE = 00200
        S_IEXEC = 00100
        S_IRWXU = 00700
        S_IRUSR = 00400
        S_IWUSR = 00200
        S_IXUSR = 00100
        S_IRWXG = 00070
        S_IRGRP = 00040
        S_IWGRP = 00020
        S_IXGRP = 00010
        S_IRWXO = 00007
        S_IROTH = 00004
        S_IWOTH = 00002
        S_IXOTH = 00001
    """
    return bool(perm_mode & flags)

def check_dir_perms(path, dir_perm=stat.S_IWOTH, file_perm=stat.S_IWOTH, users=('root',), groups=('root',), recurse=True):
    """
    Check dir structure and verify only specified users/groups have access

    If any directories have the dir_perm bits set we'll raise an error and the
    same goes for files matching file_perm bits.

    See check_permission for more info on how permission bit checking works.
    """
    directories = ((path, (), ()),) if not recurse else os.walk(path)
    for dir_name, sub_dirs, files in directories:
        attrib = os.stat(dir_name)
        if attrib.st_uid not in [pwd.getpwnam(user).pw_uid for user in users]:
            err_msg = 'Directory: "{0}" is owned by {1} which is not in the list of allowed users: "{2!s}"'
            raise PermError(err_msg.format(dir_name, pwd.getpwuid(attrib.st_uid).pw_name, users))

        if attrib.st_gid not in [grp.getgrnam(group).gr_gid for group in groups]:
            err_msg = 'The group for directory: "{0}" is {1} which is not in the list of allowed groups: "{2!s}"'
            raise PermError(err_msg.format(dir_name, grp.getgrgid(attrib.st_gid).gr_name, groups))

        if check_permission(attrib.st_mode, dir_perm):
            # Could add strmode for python one day and make nice human errors
            err_msg = 'The permissions on directory: "{0}" are "{1!s}" and violate restriction "{2!s}"'
            raise PermError(err_msg.format(dir_name, oct(attrib.st_mode), oct(dir_perm)))

        for f in files:
            file_attrib = os.stat(os.path.join(dir_name, f))
            if check_permission(file_attrib.st_mode, file_perm):
                # Could add strmode for python one day and make nice human errors
                err_msg = 'The permissions on file: "{0}" are "{1!s}" and violate restriction "{2!s}"'
                raise PermError(err_msg.format(os.path.join(dir_name, f), oct(file_attrib.st_mode), oct(file_perm)))

def match_owner_group(dest_path, source_path):
    """ Matches owner/group from one filesystem object to another """
    source_stat = os.stat(source_path)
    return os.chown(dest_path, source_stat[stat.ST_UID], source_stat[stat.ST_GID])

def mkdirp(path, inherit_owner_group=False, permission_mode=None, strict=False):
    """ Recursive mkdir (mkdir -p) """
    try:
        if permission_mode:
            os.makedirs(path, permission_mode)
        else:
            os.makedirs(path)
        logger.debug('Created directory: {0}'.format(path))
        if inherit_owner_group is True:
            match_owner_group(path, os.path.abspath(os.path.join(path, '../')))
    except OSError as exc:
        if exc.errno == errno.EEXIST and os.path.isdir(path):
            if permission_mode and strict:
                try:
                    check_dir_perms(path,
                                    dir_perm=permission_mode,
                                    recurse=False)
                except PermError:
                    logger.debug('Provided path {0} exists and has incorrect permissions'.format(path))
                    raise
            pass
        else:
            raise

class CertMongerAction(object):
    """ Represents an action requested by Certmonger """
    # Supported Exit Codes
    EXIT_ISSUED = 0
    EXIT_WAIT = 1
    EXIT_REJECTED = 2
    EXIT_UNREACHABLE = 3
    EXIT_UNCONFIGURED = 4
    EXIT_WAIT_WITH_DELAY = 5
    EXIT_OPERATION_NOT_SUPPORTED = 6
    EXIT_NEW_KEYPAIR_REQUIRED = 17

    PATHS = {'config_dir': '/etc/certmonger/letsencrypt',
             'work_dir': '/var/lib/certmonger/letsencrypt',
             'log_dir': '/var/log/letsencrypt'}

    defaults = certbot.constants.CLI_DEFAULTS

    def __init__(self,
                 paths=PATHS,
                 email=None,
                 key_size=4096,
                 verify_ssl=True,
                 user_agent='{0}/{1}'.format(__name__, __version__),
                 staging=True,
                 verbosity=logging.INFO,
                 propagation_seconds=10):

        formatter = logging.Formatter('%(module)s.%(funcName)s: %(message)s')
        logger.setLevel(verbosity)

        # Set up logging to use syslog
        syslog_handler = logging.handlers.SysLogHandler(address='/dev/log')
        syslog_handler.setFormatter(formatter)
        syslog_handler.setLevel(verbosity)
        logger.addHandler(syslog_handler)
        # Create console logger for stdout/stderr if we have a tty, full debug
        if sys.stdout.isatty():
            console_handler = logging.StreamHandler()
            console_handler.setLevel(logging.DEBUG)
            console_handler.setFormatter(formatter)
            logger.addHandler(console_handler)

        # Load and store relevant environment variables
        self.environment = self.load_environment_variables()

        # If no email is specified we try to get one from the request
        if not email:
            try:
                email = self.environment['CERTMONGER_REQ_EMAIL']
            except KeyError:
                email = None
                self.defaults['register_unsafely_without_email'] = True

        self.defaults['email'] = email

        # Set timeout for DNS propagation
        #settattr(self.defaults, 'cerlet:ipa_propagation_seconds', propagation_seconds)
        self.defaults['propagation_seconds'] = propagation_seconds

        # Set key size
        self.defaults['key_size'] = key_size

        # Configure SSL/TLS Server cert verification
        self.defaults['verify_ssl'] = verify_ssl

        # Set prod/staging server selector
        if staging:
            self.defaults['staging'] = staging

        # Find all plugins and set
        self.defaults['plugins'] = certbot.plugins.disco.PluginsRegistry.find_all()

        # Set User Agent
        self.defaults['user_agent'] = user_agent

        # Override account directory
        self.defaults['accounts_dir'] = os.path.join(paths['config_dir'],
                                                     certbot.constants.ACCOUNTS_DIR,
                                                     self.environment['CERTMONGER_REQ_HOSTNAME'])

        # Create any directories which don't exist with correct
        # permisisons/owner/group and set in config
        for key, path in paths.iteritems():
            mkdirp(path, permission_mode=0o700)
            self.defaults[key] = path

        # Create config object from defaults in certbot and assign defaults
        Config = namedlist.namedlist('Config', ' '.join(self.defaults.keys()))
        self.namespace = Config(**self.defaults)
        self.config = certbot.configuration.NamespaceConfig(namespace=self.namespace)
        zope.component.provideUtility(self.config)

        # Configure displayer depending on if we have a tty or not
        if sys.stdout.isatty():
            self.displayer = certbot.display.util.NoninteractiveDisplay(sys.stdout)
        else:
            self.displayer = certbot.display.util.NoninteractiveDisplay(open(os.devnull, "w"))

        zope.component.provideUtility(self.displayer)

        # Set up Certbot Account Storage, at some point this should be moved
        # and stored by IPA in LDAP. For now we create separate accounts per
        # host and store details on the filesystem.
        account_storage = certbot.account.AccountFileStorage(self.config)
        accounts = account_storage.find_all()

        # Assume there will only be one account per host and that it will never
        # need to be updated with a new email address ...
        if len(accounts) == 0:
            # Register account with Let's Encrypt Server if needed, we always agree
            # to the TOS terms (see lambda).
            account, acme = certbot.client.register(config=self.config,
                                                    account_storage=account_storage,
                                                    tos_cb=lambda *_, **__: True)

            account_storage.save_regr(account, acme)
        else:
            acme = None
            account = accounts[0]

        # Instantiate authenticator using DNS/FreeIPA
        self.plugin = self.defaults['plugins']['cerlet:ipa'].init(config=self.config)
        # Instantiate the installer using Certmonger
        #self.installer = certbot.plugins.disco.PluginsRegistry.find_all()['cerlet:ipa']

        # Instantiate client
        self.client = certbot.client.Client(config=self.config,
                                            account_=account,
                                            auth=self.plugin,
                                            installer=self.plugin,
                                            acme=acme)

    @staticmethod
    def _raise_not_implemented(exception=NotImplementedError):
        """ Raises the provided exception """
        raise exception

    @staticmethod
    def load_environment_variables(pattern='CERTMONGER'):
        """ Loads environment variables matching a pattern """
        matches = {}
        for key, value in os.environ.items():
            if pattern in key:
                matches[key] = value

        return matches

    @classmethod
    def operation_factory(cls, operation):
        """
        Returns the appopriate method for an operation as they are
        specified by CertMonger in environment variables.
        """
        logger.debug('Certmonger operation detected, evaluating environment variables and performing actions as requested')
        valid_operations = {'SUBMIT': cls.submit,
                            'POLL': cls.poll,
                            'IDENTIFY': cls.identify,
                            'GET-NEW-REQUEST-REQUIREMENTS': cls.requirements,
                            'GET-RENEW-REQUEST-REQUIREMENTS': cls.renew_requirements,
                            'GET-SUPPORTED-TEMPLATES': cls.templates,
                            'GET-DEFAULT-TEMPLATE': cls.default_template,
                            'FETCH-SCEP-CA-CAPS': cls._raise_not_implemented,
                            'FETCH-SCEP-CA-CERTS': cls._raise_not_implemented,
                            'FETCH-ROOTS': cls.get_ca_root_certs}
        try:

            return valid_operations[operation](cls())
        except NotImplementedError:
            logger.warning('Operation {0} is not supported in this version of {1} ({2})'.format(operation, __name__, __version__))
            return self.EXIT_OPERATION_NOT_SUPPORTED
        except KeyError:
            logger.error('Unknown Operation: {0}'.format(operation))
            return self.EXIT_OPERATION_NOT_SUPPORTED

    def register(self, config=None):
        certbot.main.register(config or self.config, unused_plugins=None)

    def submit(self, csr=None, domains=None, ca_profile=None, ca_nickname=None, ca_issuer=None):
        """
        Accepts a single Certificate Signing Request, PKCS#10/PEM encoded

        First time enrollment requested by Certmonger

        Keyword arguments:

        csr -- Enrollment request in PEM form. PKCS#10 format, PEM encoded
        ca_profile -- Name of enrollment profile/template/certtype
        ca_nickname --  Name by which the CA is known, and would have been specified to the -c
            option to the "getcert" command. For example "prod" or "test"
        ca_issuer --  Requested issuer for enrollment

        Issues certificates will be returned in PEM encoded x.509 format
        and an exit status of 0 will be returned.

        If the certificates can't be issued immediately a "cookie" value/token
        will be returned and an exit status of 1 returned. The requestor is
        free to try again at their convenience presenting the cookie/token.

        If the request is rejected an error will returned along with an exit
        status of 2.

        If there was a connection or networking exception the error will be
        returned along with an exit status of 3.

        If additional data is required the specific error will be returned
        along with an exit status of 4.

        * If the client should wait for a specific period of time (for example, if
            the CA has told it when to try again), output a delay size in seconds, a
            newline, and a "cookie" value, and exit with status 5.  The daemon will try
            again after the specified amount of time has passed.

        * If the CA indicates that the client needs to try again using a different
            key pair in the signing request (for example, if its policy limits the
            number of times a particular key pair can be enrolled, or the length of
            time one can be in service), exit with status 17.  The daemon will generate
            a new key pair and try again.

        * If the helper does not understand what is being asked of it, exit with
            status 6.  You should never return this value for "SUBMIT" or "POLL", but
            it is mentioned here so that we can refer to this list later.
        """
        logger.debug('Submitting certificate signing request')
        CSR = namedlist.namedlist('CSR', 'data form')
        csr = CSR(data = csr or self.environment['CERTMONGER_CSR'], form='pem')
        domains = domains or [self.environment['CERTMONGER_REQ_SUBJECT']]

        try:
            cert, chain = self.client.obtain_certificate_from_csr(domains, csr)
            sys.stdout.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert.body))
            return self.EXIT_ISSUED

        except acme.messages.Error as e:
            logger.error(e)
            sys.stdout.write(str(e))
            return self.EXIT_REJECTED

        except acme.error.ClientError as e:
            logger.error(e)
            sys.stdout.write(str(e))
            return self.EXIT_UNREACHABLE

        except Exception as e: # Catch all for exceptions
            logger.exception(e)
            sys.stdout.write(str(e))
            return self.EXIT_REJECTED

    def poll(self, cookie=None):
        """
        Poll status of previously submitted request

        Keyword arguments:

        cookie -- A cookie/token to identify a previously submitted request

        If the submit method previously returned with status 1 or 5, this can
        be called to retry.

        Returned certificates and exit statuses are the same as the submit
        method.
        """
        logger.debug('Polling for certificate signing request status')
        cookie = cookie or self.environment['CERTMONGER_CA_COOKIE']

    @staticmethod
    def identify():
        """
        Outputs the version of the helper and returns an exit status of 0
        """
        logger.debug('Returning version of helper/plugin')
        return __version__

    def requirements(self, renew=False):
        """
        Returns a list of required arguments/environment variables for the
        poll and submit methods, if renew is true it lists those required when
        renewing a certificate rather than requesting a new one.
        """
        submit_requirements = 'CERTMONGER_CSR,CERTMONGER_REQ_SUBJECT,CERTMONGER_OPERATION,CERTMONGER_REQ_HOSTNAME,CERTMONGER_REQ_EMAIL'
        logger.debug('Returning list of required attributes/arguments:')
        logger.debug(submit_requirements)
        sys.stdout.write(submit_requirements)

    def renew_requirements(self):
        return self.requirements(renew=True)

    def templates(default_only=False):
        """
        Returns list of all profiles/templates/cert-types, by default all
        supported templates are returned.
        """
        logger.debug('Returning templates/profiles')

    def default_template(self):
        return self.templates(default_only=True)

    def get_ca_root_certs(self):
        """
        Return a dictionary of nickname/cert with the cert in PEM format.
        """
        logger.debug('Dumping CA Root certificates')
        cert_path = os.path.join(os.path.split(__file__)[0], 'certs')
        root_certs = {'dstrootx3.pem': b'06:87:26:03:31:A7:24:03:D9:09:F1:05:E6:9B:CF:0D:32:E1:BD:24:93:FF:C6:D9:20:6D:11:BC:D6:77:07:39',
                      'isrgrootx1.pem': '96:BC:EC:06:26:49:76:F3:74:60:77:9A:CF:28:C5:A7:CF:E8:A3:C0:AA:E1:1A:8F:FC:EE:05:C0:BD:DF:08:C6',
                      'letsencryptauthorityx3.pem': b'73:1D:3D:9C:FA:A0:61:48:7A:1D:71:44:5A:42:F6:7D:F0:AF:CA:2A:6C:2D:2F:98:FF:7B:3C:E1:12:B1:F5:68',
                      'lets-encrypt-x3-cross-signed.pem': b'25:84:7D:66:8E:B4:F0:4F:DD:40:B1:2B:6B:07:40:C5:67:DA:7D:02:43:08:EB:6C:2C:96:FE:41:D9:DE:21:8D'}

        for filename, sha256sum in root_certs.iteritems():
            cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, open(os.path.join(cert_path, filename)).read())
            if cert.digest('sha256') == sha256sum:  # Verify integrity
                nickname = ' '.join(x[1] for x in cert.get_subject().get_components())
                if cert.get_issuer() == cert.get_subject():  # Root CA's can be identified by always being self signed
                    sys.stdout.write('\n' + nickname + '\n')
                    sys.stdout.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
                    sys.stdout.write('\n')
                else:
                    sys.stdout.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
                    sys.stdout.write('\n')
            else:
                logger.error('Unable to verify the integrity of Root CA {0}'.format(filename))
                logger.error('SHA256 mismatch {0} - {1}'.format(sha256sum, cert.digest('sha256')))
                raise IntegrityError

@zope.interface.implementer(certbot.interfaces.IAuthenticator)
@zope.interface.provider(certbot.interfaces.IPluginFactory)
class Authenticator(certbot.plugins.dns_common.DNSAuthenticator):
    """ FreeIPA / Red Hat Enterprise Linux IdM authentication using DNS challenges """

    description = __doc__.strip().split("\n", 1)[0]

    def __init__(self, *args, **kwargs):
        # Maps provided domains to IPA zones
        self.zone_map = {}
        super(Authenticator, self).__init__(*args, **kwargs)

    def more_info(self):
        return self.description

    def _setup_credentials(self):
        # Set up IPA API connection
        logger.info('Setting up IPA Connection using kerberos credentials')
        try:
            ipalib.api.bootstrap_with_global_options(context=__name__)
            ipalib.api.finalize()
        except ipalib.errors.KerberosError:
            logger.exception('Exception occurred communicating and authenticating to the IPA server, make sure you have valid kerberos credentials')
            raise

        if ipalib.api.env.in_server:
            ipalib.api.Backend.ldap2.connect()
        else:
            ipalib.api.Backend.rpcclient.connect()

    def _perform(self, domain, validation_domain_name, validation):  # pragma: no cover
        logger.debug('Adding DNS Records {0} to zone: {1} with value: {2}'.format(validation_domain_name, domain, validation))
        dns_zone_candidate = dns.name.from_text(domain)
        while True:
            try:
                ipalib.api.Command.dnszone_show(idnsname=unicode(dns_zone_candidate.to_text()))
                record = dns.name.from_text(validation_domain_name).relativize(dns_zone_candidate)
                try:
                    ipalib.api.Command.dnsrecord_add(dnszoneidnsname=unicode(dns_zone_candidate.to_text()), idnsname=unicode(record), txtrecord=validation)
                except ipalib.errors.EmptyModlist:
                    logger.warning('DNS entry already exists: {0} with value: {1}'.format(record, validation))
                self.zone_map[validation_domain_name] = (dns_zone_candidate, record)
                break
            except (ipalib.errors.NotFound, ipalib.errors.ConversionError):
                logger.debug('Unable to find Zone: {0}, checking for parent'.format(dns_zone_candidate.to_text(omit_final_dot=True)))
                try:
                    dns_zone_candidate = dns_zone_candidate.parent()
                except dns.name.NoParent:
                    message = 'Unable to find DNS Zone on IPA server'
                    logger.exception(message)
                    raise ipalib.errors.NotFound(format=None, message=message.decode())

    def _cleanup(self, domain, validation_domain_name, validation):
        logger.debug('Removing DNS entry: {0} to zone: {1} with value: {2}'.format(validation_domain_name, domain, validation))
        ipalib.api.Command.dnsrecord_del(dnszoneidnsname=unicode(self.zone_map[validation_domain_name][0].to_text()), idnsname=unicode(self.zone_map[validation_domain_name][1]), txtrecord=validation)

    @classmethod
    def add_parser_arguments(cls, add, default_propagation_seconds=10):
        super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds)
        add('-h', '--host_name', '--host', dest='ipa_host', help='Hostname or IP Address of the IPA (Satellite) server')
        add('-d', '--ipa_domain_name', '--ipa_domain', dest='ipa_domain', help='Domain in IPA (Satellite) to register under')
        add('-H', '--xml_rpc_url', '--xmlrpc-url', dest='ipa_xml_rpc_url', help='XML RPC service location')
        add('-C', '--ca_path', '--capath', dest='ca_path', help='Path do a directory containing PEM encoded CA files')
        add('-c', '--ca_file', '--cafile', dest='ca_file', help='Path do a file containing PEM encoded CA certificates')
        add('-t', '--keytab_name', '--keytab-name', dest='keytab_file', help='Path to a keytab file containing credentials for IPA server authentication')
        add('-k', '--submitter_principal', '--submitter-principal', dest='submitter_principal', help='Kerberos principal for IPA server authentication')
        add('-K', '--use_ccache_creds', '--use-ccache-creds', dest='use_ccache_creds', default=False, action='store_true', help='Use default ccache for authorization instead of authenticating')
        add('-P', '--request_principal', '--principal-of-request', dest='request_principal', help='Principal(s) (FQDN) used in signing request, comma separated')
        add('-T', '--request_profile', '--profile', dest='request_profile', help='Use a specific profile when requesting enrollment')

@zope.interface.implementer(certbot.interfaces.IInstaller)
@zope.interface.provider(certbot.interfaces.IPluginFactory)
class Installer(certbot.plugins.common.Installer):
    """Certmonger Installer, outputs the cert to stdout"""
    description = __doc__.strip().split("\n", 1)[0]

    # pylint: disable=missing-docstring,no-self-use

    def prepare(self):
        pass  # pragma: no cover

    def more_info(self):
        return self.description

    def get_all_names(self):
        return []

    def deploy_cert(self, domain, cert_path, key_path,
                    chain_path=None, fullchain_path=None):
        with open(cert_path, "r") as f:
            shutil.copyfileobj(f, sys.stdout)

    def enhance(self, domain, enhancement, options=None):
        pass  # pragma: no cover

    def supported_enhancements(self):
        return []

    def save(self, title=None, temporary=False):
        pass  # pragma: no cover

    def rollback_checkpoints(self, rollback=1):
        pass  # pragma: no cover

    def recovery_routine(self):
        pass  # pragma: no cover

    def view_config_changes(self):
        pass  # pragma: no cover

    def config_test(self):
        pass  # pragma: no cover

    def restart(self):
        pass  # pragma: no cover

def main():
    """ Entry point when run directly """
    env = CertMongerAction.load_environment_variables()
    if env:
        sys.exit(CertMongerAction.operation_factory(os.getenv('CERTMONGER_OPERATION')))
    from pkg_resources import load_entry_point
    sys.argv += ['--authenticator', 'cerlet:ipa']
    sys.exit(load_entry_point('certbot', 'console_scripts', 'certbot')())


from pdb import set_trace
import numpy as np

import torch
from torch import nn, from_numpy
from torch.autograd import Variable
from torch.utils.data.sampler import Sampler

"""
Helper functions and classes for PyTorch
"""

def confusion_matrix(y_true, y_pred):
    n_classes = len(set(np.unique(y_true)) | set(np.unique(y_pred)))
    CM = np.zeros((n_classes, n_classes)).astype(int)
    for true, pred in zip(y_true.astype(int), y_pred.astype(int)):
        CM[true, pred] += 1
    return CM, CM / np.sum(CM, axis=1, keepdims=True)

def get_weight(data):
    """
    return weight for unbalanced data.
    data is a PyTorch dataset type
    """
    count = np.bincount([d[1] for d in data])
    return torch.from_numpy(len(data) / (len(count) * count)).float()

def train_test_split(data, test_size=0.2):
    """For PyTorch"""

    size = len(data)
    p = np.random.permutation(size)
    index = int(np.ceil(size * test_size))
    return p[index:], p[:index]

class SubsetRandomSampler(Sampler):
    """Samples elements randomly from a given list of indices, without replacement.

    Arguments:
        indices (list): a list of indices
    """

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

    def __iter__(self):
        return (self.indices[i] for i in torch.randperm(len(self.indices)))

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

class Estimator(object):
    """PyTorchでMulticlass Classificationをする時のboilerplate code"""

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

    def compile(self, optimizer, loss):
        self.optimizer = optimizer
        self.loss_f = loss

    def _fit(self, loader, train=True, confusion=False):
        """train one epoch"""
        # train mode
        self.model.train()

        loss_list = []
        y_pred = np.array([])
        target = np.array([])

        for X, y in loader:
            outputs = self.predict(X)
            loss = self.loss_f(outputs, Variable(y, requires_grad=False))
            ## for log
            loss_list.append(loss.data[0])
            y_pred = np.concatenate((y_pred, torch.topk(outputs, 1)[1].data.numpy().flatten()))
            target = np.concatenate((target, y.numpy()))

            if train:
                self.optimizer.zero_grad()
                loss.backward()
                self.optimizer.step()

        loss = sum(loss_list) / len(loss_list)
        acc = sum(y_pred == target) / len(y_pred)

        return (loss, acc, confusion_matrix(target, y_pred)) if confusion else (loss, acc)

    def fit(self, train_loader, nb_epoch=10, validation_data=()):
        print("train...")
        for t in range(1, nb_epoch + 1):
            loss, acc = self._fit(train_loader)
            val_log = ''
            if validation_data:
                val_loss, val_acc = self._fit(validation_data, False)
                val_log = "- val_loss: %06.4f - val_acc: %06.4f" % (val_loss, val_acc)
            print("Epoch %s/%s loss: %06.4f - acc: %06.4f %s" % (t, nb_epoch, loss, acc, val_log))

    def evaluate(self, test_loader):
        return self._fit(test_loader, False, confusion=True)

    def predict(self, X):
        """X: PyTorch Tensor"""
        X = Variable(X)
        return self.model(X)

    def predict_classes(self, X):
        """X: PyTorch Tensor"""
        # eval mode
        self.model.eval()
        return torch.topk(self.predict(X), 1)[1].data.numpy().flatten()


from injector import inject

from pdip.api.base import ResourceBase
from pdip.data import RepositoryProvider
from tests.unittests.api.basic_app_db_model.models.dao.User import User

class BasicApiDbModelResource(ResourceBase):
    @inject
    def __init__(self,
                 repository_provider: RepositoryProvider,
                 *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.repository_provider = repository_provider

    def get(self, name: str) -> str:
        user_repository = self.repository_provider.get(User)
        new_user = User()
        new_user.Name = name
        user_repository.insert(new_user)
        self.repository_provider.commit()
        user = user_repository.filter_by(Name=name).first()
        return "user:" + user.Name


from django.urls import path
from . import views

app_name = 'ehr'

urlpatterns = [
    path('', views.index, name='index'),
    path("login", views.login_view, name="login"),
    path("logout", views.logout_view, name="logout"),
    path('patient/<int:id>', views.patient_view, name='patient'),
    path('create', views.new_patient, name='new_patient'),

    # API routes
    # Set sorting preference
    path('sort', views.set_sort_method, name='set_sort'),

    # Get sorting preference
    path('preference', views.get_sort_method, name='get_sort'),

    # Save patient meds
    path('save_meds/<int:id>', views.save_patient_meds, name='save_meds'),

    # Get patient meds
    path('get_meds/<int:id>', views.get_patient_meds, name='get_meds'),

    # Send email to patient
    path('email', views.send_email, name='email')
]


import random, math
from unitClass import *

# This class applies to cities and the troops within them.
# The cityClass.py will address units in cities.
# This class gives you a few things about a city:
# 1) Province
# 2) Garrison
# 3) Stockpile (how long it can hold out under seige in amount of turns)
# 4) Tax Level (Very Low, Low, Normal, High, Very High)
# 5) Raise and Lower Taxes (Changes tax level and associated tax income as well as loyalty)
# 6) Displays taxes
# 7) Displays loyalty
# 8)
# If you need any more functionality, please notify Bonds

# Make a player class...

class City(object):
    def __init__(self,province,citytype,garrison,taxlvl,resources,income,pbuilds,cbuilds,unit_list,x,y):
        self.province = province
        self.citytype = citytype if citytype else "None"
        self.gar = garrison if garrison else 0
#        self.stockpile = stockpile if stockpile else 2
        self.taxlvl = taxlvl if taxlvl else "Normal"
#        self.taxes = taxes
        self.resources = resources
        self.income = income
#        self.expenses = expenses
#        self.loyalty = loyalty
        self.pbuilds = pbuilds if pbuilds else [] #Possible builds
        self.cbuilds = cbuilds if cbuilds else [] #Complete builds
        self.ul = unit_list if unit_list else []
        self._x = x
        self._y = y

    def __repr__(self):
        return "City({},{},{},{},{},{},{},{},{},{},{})".format(self.province,self.citytype,self.gar,self.taxlvl,self.resources,self.income,self.pbuilds,self.cbuilds,self.ul,self._x,self._y)

    def stats(self): #Good
        return "CITY STATS: | Province: {} | Garrison: {} | Taxes: {} | Income: {}".format(self.province,self.gar,self.taxlvl,self.income)

    def getProvince(self): #'str' object is not callable
        return self.province

    def getGarrison(self): #'int' object is not callable
        self.gar = self.tot()
        return self.gar #Total number of troops in garrison

    def getStockpile(self): #Good
        if self.citytype == "None":
            stockpile = 0
        elif self.citytype == "City":
            stockpile = 2
        elif self.citytype == "Castle":
            stockpile = 4
        return stockpile

    def taxLevel(self): #'str' object is not callable
        return self.taxlvl

    def raisetaxes(self): #Good
        if self.taxlvl == "Very Low":
            self.taxlvl = "Low"
            return self.taxlvl
        elif self.taxlvl == "Low":
            self.taxlvl = "Normal"
            return self.taxlvl
        elif self.taxlvl == "Normal":
            self.taxlvl = "High"
            return self.taxlvl
        elif self.taxlvl == "High":
            self.taxlvl = "Very High"
            return self.taxlvl
        elif self.taxlvl == "Very High":
            self.taxlvl = "Very High"
            return self.taxlvl

    def lowertaxes(self): #Good
        if self.taxlvl == "Very Low":
            self.taxlvl = "Very Low"
            return self.taxlvl
        elif self.taxlvl == "Low":
            self.taxlvl = "Very Low"
            return self.taxlvl
        elif self.taxlvl == "Normal":
            self.taxlvl = "Low"
            return self.taxlvl
        elif self.taxlvl == "High":
            self.taxlvl = "Normal"
            return self.taxlvl
        elif self.taxlvl == "Very High":
            self.taxlvl = "High"
            return self.taxlvl

    def taxes(self): #Good
        if self.taxlvl == "Very Low":
            tax = int(0.10 * self.income)
            return tax
        elif self.taxlvl == "Low":
            tax = int(0.20 * self.income)
            return tax
        elif self.taxlvl == "Normal":
            tax = int(0.30 * self.income)
            return tax
        elif self.taxlvl == "High":
            tax = int(0.40 * self.income)
            return tax
        elif self.taxlvl == "Very High":
            tax = int(0.50 * self.income)
            return tax

    def loyalty(self): #'tax' is not defined
        if self.taxlvl == "Very Low":
            tax = int(0.10 * self.income)
        elif self.taxlvl == "Low":
            tax = int(0.20 * self.income)
        elif self.taxlvl == "Normal":
            tax = int(0.30 * self.income)
        elif self.taxlvl == "High":
            tax = int(0.40 * self.income)
        elif self.taxlvl == "Very High":
            tax = int(0.50 * self.income)
        troop_pct = self.gar * 2 #Represents percentage out of 200 (self.garrison/100)*200 = self.garrison * 2
        troop_pct = troop_pct + ((tax / self.income) * 100)
        if troop_pct > 200:
            troop_pct = 200
        elif troop_pct < 0:
            troop_pct = 0
        if troop_pct < 100:
            loyalty = int(100 - troop_pct)
            return loyalty #There is a loyalty % chance of a rebellion
        else:
            return 0

    def rebellion(self): #'tax' is not defined
        if self.taxlvl == "Very Low":
            tax = int(0.10 * self.income)
        elif self.taxlvl == "Low":
            tax = int(0.20 * self.income)
        elif self.taxlvl == "Normal":
            tax = int(0.30 * self.income)
        elif self.taxlvl == "High":
            tax = int(0.40 * self.income)
        elif self.taxlvl == "Very High":
            tax = int(0.50 * self.income)
        troop_pct = self.gar * 2 #Represents percentage out of 200 (self.garrison/100)*200 = self.garrison * 2
        troop_pct = troop_pct + ((tax / self.income) * 100)
        if troop_pct > 200:
            troop_pct = 200
        elif troop_pct < 0:
            troop_pct = 0
        if troop_pct < 100:
            loyalty = int(100 - troop_pct)
        else:
            return 0
        if loyalty > 0:
            reb = random.randint(0,100)
            randorange = self.loyalty
            if reb in range(0,self.loyalty):
                return "REBELLION"
            else:
                return "PEACEFUL"

    def upgrade_to_city(self): #Good
        if self.citytype == "None":
            stockpile = 2
            self.citytype = "City"
        elif self.citytype == "City":
            stockpile = 2
            self.citytype = "City"
        return self.citytype,stockpile

    def upgrade_to_castle(self): #Good
        if self.citytype == "City":
            stockpile = 4
            self.citytype = "Castle"
        elif self.citytype == "Castle":
            stockpile = 4
            self.citytype = "Castle"
        return self.citytype,stockpile

    def expenses(self): #Good
        expenses = int(self.gar * 0.25)
        return expenses

    def __add__(self,units): #Merges what you select (troop) with the stationary unit (self)
        utot = self.tot()
        if (utot + unit.tot()) > 1000:
            return "Merge Armies, cannot add more troops"
        else:
            units.addToGarrison()
            unitx = self.x
            unity = self.y
            units.updateLocation(unitx,unity)
            return self.ul.append(troops)

    def remove(self,units): #Pops and returns what you select (troop) from the stationary unit (self)
        theunit = self.ul
        if unit in self.ul:
            units.remFromGarrison()
            return self.ul.pop(theunit.index(units))
        else:
            return "Nothing to do."

    def tot(self): #Good
        total = 0
        for unit in self.ul:
            add = unit.tot()
            total += add
        return total

    def buildings(self): #Good
        return self.cbuilds

    def building_options(self): #Good
        province_builds = []
        citybuilds = ["Port","Barracks","Stable"] #Represent attributes of these buildings later.
        castlebuilds = ["Foundry","University"] #Additional buildings that can only be built with a castle.
        if self.citytype == "None":
            return self.pbuilds
        elif self.citytype == "City":
            for cybuild in citybuilds:
                self.pbuilds.append(cybuild)
            return self.pbuilds
        elif self.citytype == "Castle":
            for cabuild in castlebuilds:
                self.pbuilds.append(cabuild)
            return self.pbuilds

    def build_something(self,building): #Good
        province_builds = []
        citybuilds = ["Port","Barracks","Stable"] #Represent attributes of these buildings later.
        castlebuilds = ["Foundry","University"] #Additional buildings that can only be built with a castle.
        self.pbuilds.remove(building)
        self.cbuilds.append(building)
        return self.pbuilds,self.cbuilds

    def destroy_something(self,building): #Good
        self.pbuilds.append(building)
        self.cbuilds.remove(building)
        return self.pbuilds,self.cbuilds

#    def __add__(self,item,itemtype): #Adds item based off of either the type "Building" or "Troop"
#        ttot = self.tot()
#        if itemtype == "Troop":
#            if (ttot + item.number()) > 750:
#                return "Merge Armies, cannot add more troops"
#            else:
#                return self.tl.append(item)
#        elif itemtype == "Building":
#            return self.pbuilds.append(item) #Adds the building to the possible build items

#    def build(self):
#        return "Building itself"

#    def destroy(self):
#        return "Destroying"

    def location(self): #Good
        return "({},{})".format(self._x,self._y)

    def getCityImage(self): #Good
        gar_temp = self.garrison
        while gar_temp > 0:
            gar_temp -= 20
        gar_add = math.fabs(gar_temp)
        garrison_round = int(self.garrison + gar_add)
        city_image_name = "{}{}.png".format(self.citytype,garrison_round)
        return city_image_name

    def update_right(self,change): #All good.
        self._x += change
        for uns in unit_list:
            uns.update_right()
        return self._x

    def update_left(self,change):
        self._x -= change
        for uns in unit_list:
            uns.update_right()
        return self._x

    def update_up(self,change):
        self._y += change
        for uns in unit_list:
            uns.update_right()
        return self._y

    def update_down(self,change):
        self._y -= change
        for uns in unit_list:
            uns.update_right()
        return self._y