from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton, QComboBox
from PyQt5.QtCore import Qt

serial_types = {
    "digits": "Nur Zahlen",
    "letters": "Nur Buchstaben",
    "alphanumeric": "Zahlen und Buchstaben"
}

class SerialNumberUI(QWidget):
    def __init__(self):
        super().__init__()

        self.init_ui()
        self.setWindowTitle("Seriennummern")
        self.setMinimumSize(500, 400)

    def init_ui(self):
        layout = QVBoxLayout()

        self.serial_type = QComboBox()

        for key, value in serial_types.items():
            self.serial_type.addItem(value, key)

        layout.addWidget(self.serial_type)

        self.generate_button = QPushButton("Seriennummer generieren")
        layout.addWidget(self.generate_button)

        self.serial_input = QLineEdit()
        layout.addWidget(self.serial_input)

        self.check_button = QPushButton("Seriennummer überprüfen")
        layout.addWidget(self.check_button)

        self.result_label = QLabel("")
        layout.addWidget(self.result_label)

        self.setLayout(layout)


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

data= [[38,6,12], [65,27,48],[87,45,41], [92, 87,63],[89,62,54],[78,98,72]]

x1=[i[0] for i in data]
x2=[i[1] for i in data]
y=[i[2] for i in data]

x1_data = np.array(x1)
x2_data = np.array(x2)
y_data = np.array(y)
a1=0
a2=0
b=0
#print(x1_data,x2_data,y_data)

lr =0.05
epochs =2001
for i in range(epochs):
  y_pred = a1*x1_data + a2*x2_data +b
  error = y_data - y_pred
  a1_diff =  -(1/len(x1_data))*sum(x1_data*(error))
  a2_diff =  -(1/len(x2_data))*sum(x2_data*(error))
  b_new =  -(1/len(y_data))*sum(y_data- y_pred)

  a1 = a1 - lr*a1_diff
  a2 = a2 - lr*a2_diff
  b = b -lr *b_new

  if i %100 ==0:
    print("epoch = %.f,기울기 1 = %5.4f,기울기 2 = %5.4f,절편 = %5.4f" %(i,a1,a2,b))


# 基于redis的锁  1. 大家尽量自己去完成  2. 一定要看懂源码
# 这是一个面试高频题: 连环炮
import time
from datetime import datetime
import threading

import redis
from peewee import *
from inventory_srv.settings import settings

from inventory_srv.demo.redis_lock_demo.py_redis_lock import Lock as PyLock

class BaseModel(Model):
    add_time = DateTimeField(default=datetime.now, verbose_name="添加时间")
    update_time = DateTimeField(default=datetime.now, verbose_name="更新时间")
    is_deleted = BooleanField(default=False, verbose_name="是否删除")

    def save(self, *args, **kwargs):
        # 判断这是一个新添加的数据还是更新的数据
        if self._pk is not None:
            # 这是一个新数据
            self.update_time = datetime.now()
        return super().save(*args, **kwargs)

    @classmethod
    def delete(cls, permanently=False):   # permanently 表示是否永久删除
        if permanently:
            return super().delete()
        else:
            return super().update(is_deleted=True)

    def delete_instance(self, permanently=False, recursive=False, delete_nullable=False):
        if permanently:
            return self.delete(permanently).where(self._pk_expr()).execute()
        else:
            self.is_deleted = True
            self.save()

    @classmethod
    def select(cls, *fields):
        return super().select(*fields).where(cls.is_deleted==False)

    class Meta:
        database = settings.DB

# class Stock(BaseModel):
#     # 仓库表
#     name = CharField(verbose_name="仓库名")
#     address = CharField(verbose_name="仓库地址")

class Inventory(BaseModel):
    # 商品的库存表
    # stock = PrimaryKeyField(Stock)
    goods = IntegerField(verbose_name="商品id", unique=True)      # unique:在此列上创建唯一索引
    stocks = IntegerField(verbose_name="库存数量", default=0)
    version = IntegerField(verbose_name="版本号", default=0)       # 分布式锁的一种 乐观锁

def sell(th_name, goods_list):
    # 多线程下的并发带来的数据不一致的问题

    with settings.DB.atomic() as txn:
        # 超卖
        # 续租过期时间 - 看门狗 - java 中有一个 redisson
        # 如何防止我设置的值被其他的线程给删除掉
        for goods_id, num in goods_list:
            # 查询库存
            redis_client = redis.Redis(host="192.168.16.196")
            lock = PyLock(redis_client, f"goods_{goods_id}", auto_renewal=True, expire=15)
            lock.acquire()

            goods_inv = Inventory.get(Inventory.goods==goods_id)
            print(f"{th_name} 商品{goods_id} 售出 {num} 件, 当前剩余 {goods_inv.stocks-num}")
            time.sleep(20)
            if goods_inv.stocks < num:
                print(f"{th_name} 商品: {goods_id} 库存不足")
                txn.rollback()
                break
            else:
                # 让数据库根据自己当前的值更新数据, 这个语句能不能处理并发的问题
                query = Inventory.update(stocks=Inventory.stocks-num).where(Inventory.goods==goods_id)
                ok = query.execute()
                if ok:
                    print(f"{th_name} 更新成功")
                else:
                    print(f"{th_name} 更新失败")
            lock.release()

if __name__ == '__main__':
    goods_list = [(421, 10), (422, 20), (423, 30)]
    t1 = threading.Thread(target=sell, args=("线程一", [(421, 10), (422, 20), (423, 30)]))
    t2 = threading.Thread(target=sell, args=("线程二", [(421, 10), (422, 20), (423, 30)]))
    t1.start()
    t2.start()

    t1.join()
    t2.join()


#!/usr/bin/python

import urllib, urllib2

def send_text(numstring, message):
    data = urllib.urlencode({'number': numstring, 'message': message})
    r = urllib2.urlopen("http://textbelt.com/text", data)
    return r.getcode(), r.read()

send_text("8184705599", "test from python")


# coding=utf-8
import math, sys, pygame, keymap as k
from random import randint
from pygame.locals import *
from character import Character
import os

class PlayableCharacter(Character):

    def __init__(self, x, y, Vx=0, Vy=0, whichChar=1):
        Character.__init__(self, x, y, Vx, Vy, whichChar)

        # HUD images
        self.whichChar = whichChar
        self.heartEmpty = pygame.image.load('hud'+os.sep+'hud_heartEmpty.png').convert_alpha()
        self.heartHalf = pygame.image.load('hud'+os.sep+'hud_heartHalf.png').convert_alpha()
        self.heartFull = pygame.image.load('hud'+os.sep+'hud_heartFull.png').convert_alpha()
        self.heartWidth = pygame.Surface.get_width(self.heartFull)
        self.heartHeight = pygame.Surface.get_height(self.heartFull)
        self.coin = pygame.image.load('hud'+os.sep+'hud_coins.png').convert_alpha()
        self.coinWidth = pygame.Surface.get_width(self.coin)
        self.coinsMultiplier = pygame.image.load('hud'+os.sep+'hud_x.png').convert_alpha()
        self.hudNumber = []
        for i in range(0, 10):
            numberImage = pygame.image.load('hud'+os.sep+'hud_' + str(i) + '.png').convert_alpha()
            self.hudNumber.append(numberImage)
        self.hudTextWidth = pygame.Surface.get_width(self.hudNumber[0])
        self.playerCoins = []
        for i in range(0, 3):
            playerCoinImage = pygame.image.load('hud'+os.sep+'hud_p' + str(self.whichChar) + '.png').convert_alpha()
            self.playerCoins.append(playerCoinImage)
        self.key = pygame.image.load('hud'+os.sep+'hud_keyBlue.png').convert_alpha()
        self.noKey = pygame.image.load('hud'+os.sep+'hud_keyBlue_disabled.png').convert_alpha()

        # HUD variables
        self.spacing = 10
        self.coins = 0
        self.playerCoinCoords = (self.spacing, self.spacing)
        self.healthStart = (pygame.Surface.get_width(self.playerCoins[0]) + 2 * self.spacing, 10)
        self.healthInterval = self.spacing + self.heartWidth

        # Other variables
        if whichChar == 1:
            self.jumpSpeed = 35
            self.runSpeed = 8.5
            self.lives = 9
        else:
            self.jumpSpeed = 36
            self.runSpeed = 9.0
            self.lives = 4
        self.worldShiftCoefficient = 1.5
        self.cpuControlled = False
        self.longestPlatform = None
        self.respawnPoint = None
        self.keys = pygame.key.get_pressed()                # Keyboard key state

    # -----------------------------------------------------------------------------------------------------------------

    def update(self, platforms, ev, movableObjects, blocks, aiCharacters, mainChar, pool, surface,
               scrW=0, scrH=0, FPS=75, autoscroll=False, checkpoints=None, torches=None):
        self.collide(platforms, blocks, aiCharacters, pool, torches)
        self.collideCheckpoint(checkpoints)
        self.draw(surface, FPS)
        if self.move(ev, platforms, movableObjects, aiCharacters, scrW, scrH, autoscroll):
            return True
        return False

    # -----------------------------------------------------------------------------------------------------------------

    def collideCheckpoint(self, checkpoints):
        if checkpoints:
            for fence in checkpoints:
                if self.getRect().colliderect(fence.getRect()) and not fence.broken:
                    self.respawnPoint = [fence.x + 20, fence.y - 70]
                    fence.broken = True

    # -----------------------------------------------------------------------------------------------------------------

    def incrementMapH(self, aiCharacters, movableObjects, amount, doMoveSelf=True):
        # Moves all of the map details left or right by the specified amount
        if doMoveSelf:
            self.x += amount
        if self.respawnPoint:
            self.respawnPoint[0] += amount
        for obj in movableObjects:
            obj.x += amount
            if hasattr(obj, 'invertedX'):
                obj.invertedX += amount
        for aiCharacter in aiCharacters:
            if aiCharacter.limit[0] != -1:
                aiCharacter.limit[0] += amount
            if aiCharacter.limit[1] != -1:
                aiCharacter.limit[1] += amount

    # -----------------------------------------------------------------------------------------------------------------

    def incrementMapV(self, movableObjects, amount, doMoveSelf=True):
        # Moves all of the map details up or down by the specified amoun
        if doMoveSelf:
            self.y += amount
        if self.respawnPoint:
            self.respawnPoint[1] += amount
        for obj in movableObjects:
            obj.y += amount

    # -----------------------------------------------------------------------------------------------------------------

    def setMapObjX(self, aiCharacters, movableObjects, platforms, newX):
        # Shifts all of the map details
        shift = newX - platforms[0][0]
        self.x += shift
        if self.respawnPoint:
            self.respawnPoint[0] += shift
        for obj in movableObjects:
            obj.x += shift
        for aiCharacter in aiCharacters:
            if aiCharacter.limit[0] != -1:
                aiCharacter.limit[0] += shift
            if aiCharacter.limit[1] != -1:
                aiCharacter.limit[1] += shift

    # -----------------------------------------------------------------------------------------------------------------

    def getNextPlatform(self, platforms):
        currX = platforms[self.currentPlatform].x
        longX = platforms[self.longestPlatform].x
        if currX == longX and self.longestPlatform + 1 < len(platforms):
            return platforms[self.longestPlatform + 1]
        elif self.currentPlatform >= len(platforms) - 1:
            return platforms[self.currentPlatform]
        else:
            return platforms[self.currentPlatform + 1]

    # -----------------------------------------------------------------------------------------------------------------

    def initSpawnpoint(self, autoscroll, platforms, nextPlatform):
        if not autoscroll and not self.respawnPoint:
            self.respawnPoint = [0.5 * platforms[0][0] + 0.5 * platforms[0][2], platforms[0][1] - self.height - 10]
        elif autoscroll:
            self.respawnPoint = [nextPlatform[0] + 0.5 * nextPlatform.width, nextPlatform[1] - self.height - 10]

    # -----------------------------------------------------------------------------------------------------------------

    def respawn(self, x, y, loseLife=True):
        self.x = int(x)
        self.y = int(y)
        self.Vx, self.Vy = 0, 0
        self.health = self.recoveryHealth
        if loseLife:
            self.flashing = True
            self.lives -= 1

    # -----------------------------------------------------------------------------------------------------------------

    def allowJumping(self):
        if self.jumping and self.onGround:
            self.jumping = False
        if (self.keys[k.ACTION] or self.keys[k.ACTION2]) and self.canJump and self.onGround:
            Character.jump(self)
            self.jumping = True
            self.canJump = False
            self.onGround = False
        if not self.keys[k.ACTION] and not self.keys[k.ACTION2] and self.onGround:
            self.canJump = True

    # -----------------------------------------------------------------------------------------------------------------

    def scanWorld(self, aiCharacters, autoscroll, movableObjects, nextPlatform, scrH, scrW):
        rightEdge = int(0.5 * scrW) + 2
        leftEdge = int(0.5 * scrW) - 2
        bottomEdge = int(0.25 * scrH) if self.ducking else int(0.7 * scrH) + 5
        topEdge = int(0.3 * scrH) - 5
        if self.y <= scrH and not autoscroll:
            self.incrementMapH(aiCharacters, movableObjects, -self.Vx, doMoveSelf=False)
            if self.x >= rightEdge:
                self.incrementMapH(aiCharacters, movableObjects, -int(self.worldShiftCoefficient * self.runSpeed))
            if self.x <= leftEdge:
                self.incrementMapH(aiCharacters, movableObjects, int(self.worldShiftCoefficient * self.runSpeed))
        if self.y <= scrH:
            if self.y <= topEdge:
                self.incrementMapV(movableObjects, int(self.worldShiftCoefficient * self.runSpeed))
            if self.y >= bottomEdge or nextPlatform[3] >= scrH:
                self.incrementMapV(movableObjects, -int(self.worldShiftCoefficient * self.runSpeed))
        elif randint(0, 10) == 0:
            self.health -= 1

    # -----------------------------------------------------------------------------------------------------------------

    def determineLongestPlatform(self, platforms):
        if not self.longestPlatform:
            self.longestPlatform = 0
            for platformIndex in xrange(1, len(platforms)):
                if platforms[platformIndex].width > platforms[self.longestPlatform].width:
                    self.longestPlatform = platformIndex
            for platformIndex in xrange(0, len(platforms)):
                if platforms[platformIndex][0] == platforms[self.longestPlatform][0] and \
                                platforms[platformIndex][1] >= platforms[self.longestPlatform][1]:
                    self.longestPlatform = platformIndex

    # -----------------------------------------------------------------------------------------------------------------

    def enableHorizMovement(self):
        pressingLeft = self.keys[k.LEFT] or self.keys[k.LEFT2]
        pressingRight = self.keys[k.RIGHT] or self.keys[k.RIGHT2]
        pressingDown = self.keys[k.DUCK] or self.keys[k.DUCK2]
        movable = not self.cpuControlled
        if pressingLeft and movable:
            self.Vx = -self.runSpeed
        if pressingRight and movable:
            self.Vx = self.runSpeed
        if not pressingLeft and not pressingRight and movable:
            self.Vx = 0
            self.movingLaterally = False
        if self.Vx > 0:
            self.direction = 1
            self.movingLaterally = True
        elif self.Vx < 0:
            self.direction = 0
            self.movingLaterally = True
        else:
            self.direction = 2
        if pressingDown and movable:
            self.ducking = True
            self.Vx = 0
        else:
            self.ducking = False

    # -----------------------------------------------------------------------------------------------------------------

    def handleWorldScrolling(self, aiCharacters, autoscroll, movableObjects, scrW):
        if autoscroll and 0 <= self.x + self.width:
            self.incrementMapH(aiCharacters, movableObjects, -0.5 * self.runSpeed)
            self.x += self.Vx
        elif autoscroll and self.health > 0:
            self.health -= 0.5
        # Scroll faster if the player is off screen
        if self.x <= 0 or self.x >= scrW:
            self.worldShiftCoefficient = 20
        else:
            self.worldShiftCoefficient = 1.5

    # -----------------------------------------------------------------------------------------------------------------

    def move(self, events, platforms, movableObjects, aiCharacters, scrW, scrH, autoscroll):
        # Call base class implementation and cancel the position increment
        Character.updateMotion(self, platforms)
        self.x -= self.Vx

        # Get keyboard state
        self.keys = pygame.key.get_pressed()

        # Enable horizontal motion
        self.enableHorizMovement()

        # Determine the longest platform and the next platform
        self.determineLongestPlatform(platforms)
        nextPlatform = self.getNextPlatform(platforms)

        # Move world horizontally and vertically to follow player
        self.scanWorld(aiCharacters, autoscroll, movableObjects, nextPlatform, scrH, scrW)

        # Autoscroll as necessary
        self.handleWorldScrolling(aiCharacters, autoscroll, movableObjects, scrW)

        # Allow jumping
        self.allowJumping()

        # If necessary, initialize the respawn point
        self.initSpawnpoint(autoscroll, platforms, nextPlatform)

        # Respawn if the health reaches zero
        if self.health <= 0:
            self.respawn(self.respawnPoint[0], self.respawnPoint[1])

        # Show game over screen if no lives are remaining
        if self.lives <= 0 and self.x != 0:
            return False

        # Check for any other I/O events
        for event in events:
            if event.type == QUIT or self.keys[k.EXIT]:
                pygame.quit(); sys.exit()
        return True

    # -----------------------------------------------------------------------------------------------------------------

    def draw(self, surface, FPS=75):
        Character.draw(self, surface)

        # DRAW HUD:

        # Player symbol
        surface.blit(self.playerCoins[self.whichChar - 1], self.playerCoinCoords)
        surface.blit(self.coinsMultiplier, (self.spacing + self.heartWidth, int(2.5 * self.spacing)))
        surface.blit(self.hudNumber[self.lives], (5 * self.spacing + self.heartWidth, int(1.5 * self.spacing)))
        # Health
        health = self.health / 2.0
        for filledHearts in range(1, int(math.floor(health)) + 1):
            if health >= 0:
                surface.blit(self.heartFull, (self.healthInterval * filledHearts - 55, 7 * self.spacing))
        if math.floor(health) != health and health >= 0:
            surface.blit(self.heartHalf, (self.healthInterval * math.ceil(health) - 55, 7 * self.spacing))
        # Coins
        surface.blit(self.coin, (self.spacing, 8 * self.spacing + self.heartHeight))
        surface.blit(self.coinsMultiplier, (self.spacing + self.heartWidth,
                                                  8 * self.spacing + self.heartHeight + 15))
        coinsAsList = []
        for i in str(self.coins):
            coinsAsList.append(int(i))
        for i in range(0, len(coinsAsList)):
            surface.blit(self.hudNumber[coinsAsList[i]], (3 * self.spacing + self.coinWidth + self.hudTextWidth *
                                                                (i + 1), 7 * self.spacing + self.heartHeight + 15))
        # Key
        if self.hasKey:
            surface.blit(self.key, (self.spacing, 13 * self.spacing + self.heartHeight + 15))
        else:
            surface.blit(self.noKey, (self.spacing, 13 * self.spacing + self.heartHeight + 15))


#!/usr/bin/env python

"""
Downloads WebSim-COMPASS simulations

Based on shell script by Mathieu Puech

**Note** Skips simulations for existing files in local directory starting with
         that simulation ID.
         Example: if it finds file(s) "C001006*", will skip simulation C001006

**Note** Does not create any directory (actually creates it but deletes later).
         All files stored in local directory!

**Note** Will work only on if os.name == "posix" (Linux, UNIX ...)
"""

import os
import argparse
import sys
import glob
import logging
import aosss
import a99

a99.logging_level = logging.INFO
a99.flag_log_file = True

def print2(*args):
  a99.get_python_logger().info(*args)

if __name__ == "__main__":
    if os.name != "posix":
        print2("OS is '"+os.name+"', this script is only for 'posix' OS's, sorry.")
        sys.exit()

    parser = argparse.ArgumentParser(description=__doc__, formatter_class=a99.SmartFormatter)
    parser.add_argument('--max', metavar='N', type=int, default=100,
                        help='Maximum number of simulations to get')
    parser.add_argument('--stage', type=str, nargs='?', default="all",
     help="Websim-Compass pipeline stage: if specified, will download files named, e.g., "
          "C000793_<stage>.fits (**note**: .par and .out files are always downloaded)")

    parser.add_argument('numbers', metavar='N', type=str, nargs='+',
                     help='List of simulation numbers (single value and ranges accepted, e.g. 1004, 1004-1040)')
    args = parser.parse_args()

    simids = aosss.compile_simids(args.numbers)
    print2("List of simulation IDs: "+", ".join(simids))

    if len(simids) > args.max:
        print2("Number of simulations to download (%d) exceeds maximum number (%d)" % (len(simids), args.max))
        print2("Use --max option to raise this maximum number")
        sys.exit()

    # Part based on Mathieu Puech's script
    #
    # wget options explained:
    #   -v       -- verbose
    #   -P       --  prefix: directory to save files to
    #   -A       -- accept: accept only certain file types
    #   -r       -- recursive
    #   -l1      -- specify maximum recursion level depth
    #   -e       -- execute a command as if it were part of .wgetrc
    #   -np      -- (--no-parent)
    #               do not ever ascend to the parent directory when retrieving recursively
    site = "http://websim-compass.obspm.fr/wcompass"
    for simid in simids:
        ff = glob.glob("%s*" % simid)
        if len(ff) > 0:
            print2("Files found starting with '%s', skipping this download" % simid)
        print2("Downloading %s simulation files..." % simid)
        # os.system("wget -v -r -l1 -np -nd -erobots=off -P %s %s/%s/" % (simid, site, simid))
        os.system("wget -v -P %s %s/%s.out" % (simid, site, simid))
        os.system("wget -v -P %s %s/%s.par" % (simid, site, simid))

        if args.stage == "all":
            os.system("wget -v -r -l1 -np -nd -erobots=off -P %s -A.fits -A.par %s/%s/" % (simid, site, simid))
        else:
            os.system("wget -v -P {0} {1}/{0}/{0}_{2}.fits".format(simid, site, args.stage))

        os.system("mv %s/* ." % simid)
        os.system("rm -r %s" % simid)


import cv2
import numpy as np
import math

print("-- Histogram Equalized Image -- ")

img 	= cv2.imread("pollen2.tif",0)

height 	= img.shape[0]
width 	= img.shape[1]

final = np.zeros(( height, width ,3), np.uint8)

newImg = np.zeros(( height, width ,3), np.uint8)

levels = []

total = height*width

for x in range(0,256):
	levels.append(0)

for x in range(0,height):
	for y in range(0,width):
		levels[img[x,y]] += 1;

for x in range(0,256):
	levels[x] = levels[x]/total

sums = 0;

clevels = []

for x in range(0,256):
	for y in range(0,x+1):
		sums += levels[y]
		# print(l[y])
	clevels.append(sums)
	# print()
	sums = 0

# for x in range(0,256):
# 	print(x,clevels[x])

for x in range(0,256):
	clevels[x] = int(clevels[x]*255)

# for x in range(0,height):
# 	for y in range(0,width):
# 		newImg[x,y] = clevels[img[x,y]];

# ---------------------------------------

imf 	= cv2.imread("org.tif",0)

_height 	= imf.shape[0]
_width 	= imf.shape[1]

newImf = np.zeros(( _height, _width ,3), np.uint8)

_levels = []

total = _height*_width

for x in range(0,256):
	_levels.append(0)

for x in range(0,_height):
	for y in range(0,_width):
		_levels[imf[x,y]] += 1;

for x in range(0,256):
	_levels[x] = _levels[x]/total

sums = 0;

_clevels = []

for x in range(0,256):
	for y in range(0,x+1):
		sums += _levels[y]
		# print(l[y])
	_clevels.append(sums)
	# print()
	sums = 0

# for x in range(0,256):
# 	print(x,_clevels[x])

for x in range(0,256):
	_clevels[x] = int(_clevels[x]*255)

# for x in range(0,_height):
# 	for y in range(0,_width):
# 		newImf[x,y] = _clevels[imf[x,y]];

flevels = []

for x in range(0,256):
	flevels.append(0)

for x in range(0,256):
	if clevels[x] in _clevels:
		flevels[x] = _clevels.index(clevels[x]);
	else:
		for y in range(0,256):
			if abs(_clevels[y] - clevels[x]) <= 5:
				flevels[x] = _clevels[y];

for x in range(0,height):
	for y in range(0,width):
		final[x,y] = flevels[img[x,y]];

# for x in range(0,256):
# 	print(x,clevels[x])

cv2.imshow("Original",img)
cv2.moveWindow("Original", 800,0);

cv2.imshow("Matched With",imf)
cv2.moveWindow("Matched With", 400,0);

cv2.imshow("Matched",final)
cv2.moveWindow("Matched",0,0);

cv2.waitKey(0)
cv2.destroyAllWindows()


from webob import exc

from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova import exception
from nova import network
from nova.openstack.common import log as logging

LOG = logging.getLogger(__name__)
authorize = extensions.extension_authorizer('compute', 'networks_associate')

class NetworkAssociateActionController(wsgi.Controller):
    """Network Association API Controller."""

    def __init__(self, network_api=None):
        self.network_api = network_api or network.API()

    @wsgi.action("disassociate_host")
    def _disassociate_host_only(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)
        LOG.debug(_("Disassociating host with network with id %s"), id)
        try:
            self.network_api.associate(context, id, host=None)
        except exception.NetworkNotFound:
            raise exc.HTTPNotFound(_("Network not found"))
        return exc.HTTPAccepted()

    @wsgi.action("disassociate_project")
    def _disassociate_project_only(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)
        LOG.debug(_("Disassociating project with network with id %s"), id)
        try:
            self.network_api.associate(context, id, project=None)
        except exception.NetworkNotFound:
            raise exc.HTTPNotFound(_("Network not found"))
        return exc.HTTPAccepted()

    @wsgi.action("associate_host")
    def _associate_host(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        try:
            self.network_api.associate(context, id,
                                       host=body['associate_host'])
        except exception.NetworkNotFound:
            raise exc.HTTPNotFound(_("Network not found"))
        return exc.HTTPAccepted()

class Networks_associate(extensions.ExtensionDescriptor):
    """Network association support."""

    name = "NetworkAssociationSupport"
    alias = "os-networks-associate"
    namespace = ("http://docs.openstack.org/compute/ext/"
                 "networks_associate/api/v2")
    updated = "2012-11-19T00:00:00+00:00"

    def get_controller_extensions(self):
        extension = extensions.ControllerExtension(
                self, 'os-networks', NetworkAssociateActionController())

        return [extension]


#import speech_recognition as sr
#
#r = sr.Recognizer()
#
#with sr.Microphone() as source:
#    print('Say Something:')
#    audio = r.listen(source)
#    print ('Done!')
#
#text = r.recognize_google(audio, language = 'hi-IN')
#
#print (text)
#
#print (r.recognize_google(audio))

import speech_recognition as sr
from googletrans import Translator

r = sr.Recognizer()

with sr.Microphone() as source:
    print('Say Something:')
    audio = r.listen(source)
    print ('Done!')

text = r.recognize_google(audio, language = 'EN')
translator = Translator()
updatedText = translator.translate(text, dest='es')
print ("Original Text is : ",updatedText.origin)
print ("Converted Text is : ",updatedText.text)


"""Twitter."""
import json
import logging

from random import uniform
from tweepy import OAuthHandler
from tweepy.streaming import Stream
from tweepy.streaming import StreamListener

KEY_PUB_TOPIC = "pub_topic"

class StdOutListener(StreamListener):
    """A listener handles tweets that are received from the stream."""

    def __init__(self, fields, publishers):
        """Constructor."""
        self.logger = logging.getLogger()
        self.fields = fields
        self.publishers = publishers
        self.control = {}
        for pub in publishers:
            pub.connect()

    def on_data(self, data):
        """On data."""
        self.parse_tweet(json.loads(data))
        return True

    def on_error(self, status):
        """On error."""
        self.logger.debug(status)

    def _extract(self, data, path):
        if type(data) == dict:
            cur = path[0]
            if cur not in data:
                self.logger.debug("Key not found: %s" % cur)
                return None
            if len(path) == 1:
                return data[cur]
            else:
                path.pop(0)
                return self._extract(data[cur], path)
        elif type(data) == list:
            values = []
            for obj in data:
                values.append(self, self._extract(obj, path))
            return values

    def extract(self, data, path):
        """Extractor."""
        return self._extract(data, path.split("."))

    def parse_tweet(self, content):
        """Parser."""
        # Extract data
        twitter_data = {}
        result = {}

        for key in self.fields:
            values = self.extract(content, key)

            key = key.replace(".", "_")
            if key == "geo_coordinates" and values is None:
                values = [uniform(-23.580001, -23.589999),
                          uniform(-47.520001, -47.529999)]
            twitter_data[key] = values

        if twitter_data is not None:
            result["twitter"] = twitter_data
            self.logger.debug("Result: '%s'", json.dumps(result))
            for pub in self.publishers:
                topic = pub.get_connection_data(KEY_PUB_TOPIC)
                pub.publish(topic, json.dumps(result))

class Twitter(StreamListener):
    """Twitter class."""

    def __init__(self, settings, publishers):
        """Constructor."""
        if "consumer_key" not in settings:
            raise ValueError("consumer_key must not be None")
        if "consumer_secret" not in settings:
            raise ValueError("consumer_secret must not be None")
        if "access_token" not in settings:
            raise ValueError("access_token must not be None")
        if "access_secret" not in settings:
            raise ValueError("access_secret must not be None")
        if "fields" not in settings:
            raise ValueError("access_secret must not be None")

        self.auth = OAuthHandler(settings["consumer_key"],
                                 settings["consumer_secret"])
        self.auth.set_access_token(settings["access_token"],
                                   settings["access_secret"])

        twitter_stream = Stream(self.auth,
                                StdOutListener(settings["fields"], publishers))
        twitter_stream.filter(track=settings["post_strings"])


import logging
from selectorlib import Extractor
import requests
from base import Base, RESP_DEFAULT
import os
from dotenv import load_dotenv

load_dotenv()

pathfile = os.path.dirname(os.path.realpath(__file__))
DNS_WEB = "https://www.belk.com"

class Belk(Base):
    eP = Extractor.from_yaml_file("{}/selector_product.yml".format(pathfile))
    __instance = None

    def __init__(self, dns=DNS_WEB) -> None:
        if Belk.__instance != None:
            raise Exception("This is singleton class!!")
        self.dns = dns
        Belk.__instance = self

    @staticmethod
    def getInstance() -> object:
        """This is static method be called by class"""
        if Belk.__instance == None:
            Belk()
        return Belk.__instance

    def product(self, url) -> dict:
        try:
            logging.info("Downloading {}".format(url))
            proxyDict = {
                'http': os.getenv('HTTP_PROXY'),
                'https': os.getenv('HTTPS_PROXY')
            }
            r = requests.get(url, headers=self.headers,
                             timeout=10, proxies=proxyDict)
            if r.status_code > 500:
                if "To discuss automated access to Website data please contact" in r.text:
                    print(
                        "Page %s was blocked by Website. Please try using better proxies\n" % url)
                else:
                    print("Page %s must have been blocked by Website as the status code was %d" % (
                        url, r.status_code))
                return {}
            resp = Belk.eP.extract(r.text)
            resp.update({
                'price': resp["price"] or resp["price_standard"]
            })
            return resp
        except Exception as e:
            logging.error(e)
        return RESP_DEFAULT

    def __str__(self) -> str:
        return "Belk Model"


import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, StoppingCriteriaList, StoppingCriteria
# from nltk.tokenize import word_tokenize
from nltk.tokenize.treebank import TreebankWordDetokenizer

BOS = "[BOS]"
EOS = "[EOS]"

class KeywordsStoppingCriteria(StoppingCriteria):
    def __init__(self, keywords_ids:list):
        self.keywords = keywords_ids

    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:
        if input_ids[0][-1] in self.keywords:
            return True
        return False

class GPT2:
    def __init__(self) -> None:
        self.tokenizer = AutoTokenizer.from_pretrained("huangtuoyue/GPT2-large-GOTfinetuned_v5")
        self.model = AutoModelForCausalLM.from_pretrained("huangtuoyue/GPT2-large-GOTfinetuned_v5")
        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.model.to(self.device)
        # for context generation #
        # 1. stop if we get [BOS] -- Jon talking
        stop_context_words = ['[BOS]']
        stop_context_ids = [self.tokenizer.encode(w)[0] for w in stop_context_words]
        self.stop_context_criteria = KeywordsStoppingCriteria(stop_context_ids)
        # 2. exclude EOS
        bad_context_words = ['[EOS]']
        bad_context_ids = self.tokenizer(bad_context_words, add_special_tokens=False).input_ids

        # for dialogue generation #
        # 1. stop if we get [EOS] -- Jon stops talking
        stop_dialogue_words = ['[EOS]']
        stop_dialogue_ids = [self.tokenizer.encode(w)[0] for w in stop_dialogue_words]
        self.stop_dialogue_criteria = KeywordsStoppingCriteria(stop_dialogue_ids)
        # 2. exclude BOS
        bad_dialogue_words = ['[BOS]', ' "', ' Jon', ' said', ' he', ' Snow']
        self.bad_dialogue_ids = self.tokenizer(bad_dialogue_words, add_special_tokens=False).input_ids
    def _generate(self, text, pred_dialogue):
        encoded_input = self.tokenizer(text, return_tensors='pt').input_ids

        # for context generation
        if not pred_dialogue:

            outputs = self.model.generate(encoded_input.to(self.device), do_sample=True, min_length=60, max_new_tokens=150, pad_token_id = 50256,
                                    temperature=0.95, top_p = 1, repetition_penalty = 1.1,
                                    stopping_criteria=StoppingCriteriaList([self.stop_context_criteria]), bad_words_ids = bad_context_ids)

            # for dialogue generation
        else:
            outputs = self.model.generate(encoded_input.to(self.device), do_sample=True, min_length=3, max_new_tokens=50, pad_token_id = 50256,
                                    temperature=1.1, top_p = 1, repetition_penalty = 1,
                                    stopping_criteria=StoppingCriteriaList([self.stop_dialogue_criteria]), bad_words_ids = bad_dialogue_ids)

        # deceode outputs and keep speical_tokens
        res = self.tokenizer.batch_decode(outputs, skip_speical_tokens=False)
        return res[0]

    def generate(self, context, pred_dialogue):
        incorrect_generation = 0
        total = 0
        options = []
        prev_context_end_idx = len(context)
        context_list = context.split()

        # check context length #
        if len(context_list) < 50: # used last 50 words to generate new context
            run_context = TreebankWordDetokenizer().detokenize(context_list)
            last_idx = len(run_context)

        else:
            run_context = TreebankWordDetokenizer().detokenize(context_list[-50:])
            last_idx = len(run_context)

        # dialogue generation #
        pred = self._generate(run_context, pred_dialogue)

        # count total generation time #
        total += 1

        # check if generation includes [BOS] & [EOS] #
        words = pred.split()
        eos_list = []
        bos_list = []
        for j, word in enumerate(words):
            if word == BOS:
                bos_list.append(j)
            elif word == EOS:
                eos_list.append(j)

        # Validity for context generation #
        if words[-1] == BOS and not pred_dialogue: # correct context
        # if '[BOS]' in words: # correct context
            context = pred
            # print(context)
            print(context[last_idx:-5] + ":")
            print("\n")
            f.write(context[last_idx:-5]+ ":")
            f.write("\n")

            pred_dialogue = True

        elif words[-1] != '[BOS]' and not pred_dialogue: # no [BOS]
            # print("Invalid Context: no BOS or too long \n")
            incorrect_generation += 1

            pred_dialogue = False
        elif pred_dialogue:
            if words[-1] != '[EOS]':
                # print("Invalid Dialogue: no EOS or too long \n")
                incorrect_generation += 1

            elif words[-1] == '[EOS]': # correct dialogue
                option = TreebankWordDetokenizer().detokenize(words[bos_list[-1]+1:eos_list[-1]])
                options.append(option)
                pred_dialogue = True
                if len(options) == 3:
                    pass
        # Validity for dialogue generation #


import os
import time
import datetime
from connection.db import my_connection

class Course:
    def __init__(self, course_name, course_code, course_lecture, course_duration, course_type, course_added_date):
        self.course_name = course_name
        self.course_type = course_type
        self.course_lecture = course_lecture
        self.course_duration = course_duration
        self.course_code = course_code
        self.course_added_date = course_added_date
        self.database_cursor = my_connection.cursor()

    #  ---------------------the function to save course records-----------------//
    def add_course_details(self):
        """the function to add course details here------"""
        try:
            sql = "INSERT INTO Course(course_name, course_code, course_lecture, course_duration, course_type, course_added_date) VALUES(%s, %s, %s, %s, %s, %s)"
            values = (self.course_name, self.course_type, self.course_lecture, self.course_duration, self.course_code,
                      self.course_added_date)
            self.database_cursor.execute(sql, values)
            my_connection.commit()
        except Exception as ex:
            print(ex)

    #  ----------------------------the function will update the course details here-----------------//
    def update_course_details(self, current_course_id):
        """------------------the function will update the records in the database-------------"""
        try:
            sql = "UPDATE Course SET course_name = %s, course_code = %s, course_lecture = %s, course_duration = %s, course_type = %s, course_added_date = %s WHERE id = %s"
            values = (self.course_name, self.course_type, self.course_lecture, self.course_duration, self.course_code,
                      self.course_added_date, current_course_id)
            self.database_cursor.execute(sql, values)
            my_connection.commit()
        except Exception as ex:
            print(ex)

    #  -------------------------------the method will be used to delete the records in the database-----------//
    def delete_course_details(self, current_course_id):
        # try:
            sql = "DELETE FROM Course WHERE id = %s"
            values = (current_course_id,)
            self.database_cursor.execute(sql, values)
            my_connection.commit()
        # except Exception as ex:
        #     print(ex)


from abc import ABC, abstractmethod
from typing import Optional, Sequence, Tuple

import torch
from torch.utils.data import Dataset

class BaseDataset(Dataset, ABC):
    @abstractmethod
    def y(self, indices: Optional[Sequence[int]] = None) -> list:
        pass

def dataset_mean_std(dataset: Dataset) -> Tuple[float, float]:
    """
    Compute the mean and standard deviation of a dataset. The dataset must return a tensor as first element in each
    sample tuple.
    This can be quite long because each sample is processed separately, to avoid saturating the memory with a huge tensor.

    :param dataset: The dataset for which to compute mean and std
    :return: The mean and std
    """

    len_dataset = len(dataset)

    # Mean
    sum_mean = torch.tensor(0, dtype=torch.float)
    for sample in dataset:
        sum_mean += sample[0].mean()

    global_mean = sum_mean / len_dataset

    # STD
    sum_variance = torch.tensor(0, dtype=torch.float)
    for sample in dataset:
        var, mean = torch.var_mean(sample[0])
        sum_variance += (mean - global_mean) ** 2 + var

    global_variance = sum_variance / len_dataset
    std = global_variance.sqrt()

    return global_mean.item(), std.item()

def dataset_min_max(dataset: Dataset) -> Tuple[float, float]:
    """
    Compute the min and max value of a dataset. The dataset must return a tensor as first element in each
    sample tuple.
    This can be quite long because each sample is processed separately, to avoid saturating the memory with a huge tensor.

    :param dataset: The dataset for which to compute min and max
    :return: The min and max values
    """

    min_value = torch.tensor(torch.finfo().max, dtype=torch.float)
    max_value = torch.tensor(torch.finfo().min, dtype=torch.float)

    for sample in dataset:
        # Min
        min_sample = sample[0].min()
        if min_sample < min_value:
            min_value = min_sample

        # Max
        max_sample = sample[0].max()
        if max_sample > max_value:
            max_value = max_sample

    return min_value.item(), max_value.item()


'''
# 백준_1633_최고의 팀 만들기. 골드 4. 풀이: 23.05.28 -> 실패

# How to
- 흑과 백은 각각 15명으로 한정되어 있으므로, 이중 for문으로 입력시마다 탐색
- 점화식
dp[a][b] : 백은 a명, 흑은 b명일 때의 능력치
dp[a][b] = max(dp[a][b], dp[a-1][b]+white, dp[a][b-1]+black)

# Review
- 왜 실패일까..진짜 왜 틀렸을까..도저히 모르겠다ㅠㅠ
'''

# 1. Top-Down 실패
import sys
input = sys.stdin.readline

answer = 0
dp = [[0] * 16 for _ in range(16)]
# 첫줄은 우선 포함해서? -> 이 줄을 포함해야할까?
dp[1][0], dp[0][1] = map(int, input().split())

def solve(a, b):
    global white, black
    if dp[a][b]:
        return dp[a][b]

    # 이번 선수 포함X vs 백팀 O vs 흑팀 O
    if a >= 1 and b >= 1:
        dp[a][b] = max(dp[a][b], solve(a-1, b)+white, solve(a, b-1)+black)

    # 이번 선수 포함X vs 백팀 O
    elif a >= 1:
        dp[a][b] = max(dp[a][b], solve(a-1, b)+white)

    # 이번 선수 포함X vs 흑팀 O
    elif b >= 1:
        dp[a][b] = max(dp[a][b], solve(a, b-1)+black)

    return dp[a][b]

while True:
    try:
        white, black = map(int, input().split())
        # 최댓값 구하기
        answer = max(answer, solve(15, 15))

    except:
        print(answer)
        break

# 2. Bottom-Up 실패
import sys
input = sys.stdin.readline

answer = 0
dp = [[0] * 16 for _ in range(16)]
while True:
    try:
        white, black = map(int, input().split())
        # 0명부터 차근차근 쌓아가기
        for a in range(16):
            for b in range(16):
                # 이번 선수 포함X vs 백팀 O vs 흑팀 O
                if a >= 1:
                    dp[a][b] = max(dp[a][b], dp[a-1][b]+white)

                if b >= 1:
                    dp[a][b] = max(dp[a][b], dp[a][b-1]+black)

    except:
        print(dp[15][15])
        break

'''
# Result
풀이 시간:
메모리:  KB
시간:  ms
코드 길이:  B
'''


import pandas as pd
from my_config import Config
from experiment import Experiment
import os
from multiprocessing import Process
import multiprocessing

class Runner:
    @staticmethod
    def run(exp,epochs):
        exp.run(epochs)

class ExperimentManager():
    def __init__(self,expm_dir,ds_man):
        self.expm_dir = expm_dir
        self.ds_man = ds_man

    @classmethod
    def load(cls,expm_dir,ds_man):
        if not Config.FS.dir_exists(expm_dir):
            raise ValueError("Cannot load exp as {} not found".format(expm_dir))
        return cls(expm_dir,ds_man)

    @classmethod
    def create(cls,expm_dir,ds_man):
        if Config.FS.dir_exists(expm_dir):
            raise ValueError("Cannot create new exp in existing dir {}".format(expm_dir))
        Config.FS.mkdirs(expm_dir)
        my_exps = {}
        Config.FS.pickle_dump(my_exps,os.path.join(expm_dir,'my_exps.p'))
        return cls(expm_dir,ds_man)

    @classmethod
    def create_or_load(cls,expm_dir,ds_man):
        if Config.FS.dir_exists(expm_dir):
            return cls.load(expm_dir,ds_man)
        else:
            return cls.create(expm_dir,ds_man)

    def new_exp(self,dskey,model_key,train_size):
        data_set = self.ds_man.get_ds(dskey)
        my_exps = Config.FS.pickle_load(os.path.join(self.expm_dir,'my_exps.p'))
        new_exp_key = (dskey.get_dict_key(),model_key,train_size)
        if new_exp_key in my_exps:
            raise ValueError("Attempting to add the same experiment {}".format(new_exp_key))
        exp_dir = os.path.join(self.expm_dir,"exp_{}".format(len(my_exps)))
        Experiment.create(data_set,model_key,exp_dir,train_size)
        my_exps[new_exp_key] = exp_dir
        Config.FS.pickle_dump(my_exps,os.path.join(self.expm_dir,'my_exps.p'))

    def get_info_df(self):
        all_exps = Config.FS.pickle_load(os.path.join(self.expm_dir,'my_exps.p'))
        if len(all_exps) == 0:
            return pd.DataFrame()
        def get_exp_df(exp_dir):
            exp = Experiment.load(exp_dir,self.ds_man)
            exp_df = exp.get_info_df()
            exp_df['exp_dir'] = exp_dir
            return exp_df
        all_exp_dfs = [get_exp_df(exp_dir) for key,exp_dir in all_exps.items()]
        return pd.concat(all_exp_dfs,axis=0,sort=False).reset_index(drop=True)

    def get_exp(self,dskey,model_key,train_size):
        all_exps = Config.FS.pickle_load(os.path.join(self.expm_dir,'my_exps.p'))
        exp_dir = all_exps[(dskey.get_dict_key(),model_key,train_size)]
        exp = Experiment.load(exp_dir,self.ds_man)
        return exp

    def get_all_exp(self):
        all_exps = Config.FS.pickle_load(os.path.join(self.expm_dir,'my_exps.p'))
        all_exps = [Experiment.load(v,self.ds_man) for k,v in all_exps.items()]
        return all_exps

    @staticmethod
    def run_exps_multithread0(exps,epochs):

        processes = [Process(target=Runner.run,args=(exp,epoch))
                     for exp,epoch in zip(exps,epochs)]
        for proc in processes:
            proc.start()
        for proc in processes:
            proc.join()

    @staticmethod
    def run_exps_multithread(exps,epochs,num_processors=96):
        tasks = [(exp,epoch) for exp,epoch in zip(exps,epochs)]
        with multiprocessing.Pool(processes = num_processors) as p:
            p.starmap(ExperimentManager.exps_worker, [(i, tasks, num_processors) for i in range(num_processors)])

    @staticmethod
    def exps_worker(i, tasks, num_processors):
        num_tasks = len(tasks)
        work_load = int(num_tasks / num_processors)
        if i == num_processors-1:
            start, end = i*work_load, num_tasks
        else:
            start, end = i*work_load, (i+1)*work_load
        sub_tasks = tasks[start:end]
        for exp,epoch in sub_tasks:
            exp.run(epoch)


"""
Ejercicio 3.2.11¶

El directorio de los clientes de una empresa está organizado en una cadena de texto
como la de más abajo, donde cada línea contiene la información del nombre, email,
teléfono, nif, y el descuento que se le aplica. Las líneas se separan
con el carácter de cambio de línea \n y la primera línea contiene los nombres
de los campos con la información contenida en el directorio.

"nif;nombre;email;teléfono;descuento\n
01234567L;Luis González;luisgonzalez@mail.com;656343576;12.5\n
71476342J;Macarena Ramírez;macarena@mail.com;692839321;8\"

Escribir un programa que genere un diccionario con la información del directorio, donde cada
elemento corresponda a un cliente y tenga por clave su nif y por valor otro diccionario
con el resto de la información del cliente.
Los diccionarios con la información de cada cliente tendrán como claves los nombres de los campos
y como valores la información de cada cliente correspondientes a los campos.
Es decir, un diccionario como el siguiente

{'01234567L': {'nombre': 'Luis González', 'email': 'luisgonzalez@mail.com', 'teléfono': '656343576', 'descuento': 12.5},
 '71476342J': {'nombre': 'Macarena Ramírez', 'email': 'macarena@mail.com', 'teléfono': '692839321', 'descuento': 8.0}}
"""

def dividir(cadena_bruta: str) -> tuple:
    listado = cadena_bruta.split("\n")
    cabecera = listado.pop(0)
    return cabecera, listado

def personas(listado: list) -> list:
    informacion = []
    for linea in listado:
        datos = linea.split(";")
        informacion.append(datos)
    return informacion

def diccionario(asociacion: list, info_personas: list) -> dict:
    diccionario = {}
    for persona in info_personas:
        individuo = {}
        for valor in persona:
            if valor == persona[0]:
                nif = persona[0]
            else:
                individuo.update({asociacion[persona.index(valor)]: valor})
        diccionario.update({nif: individuo})
    return diccionario

if __name__ == "__main__":
    # Entrada
    directorio = ("nif;nombre;email;teléfono;descuento\n"
                  "01234567L;Luis González;luisgonzalez@mail.com;656343576;12.5\n"
                  "71476342J;Macarena Ramírez;macarena@mail.com;692839321;8\n"
                  "63823376M;Juan José Martínez;juanjo@mail.com;664888233;5.2\n"
                  "98376547F;Carmen Sánchez;carmen@mail.com;667677855;15.7")
    # Proceso
    referencia, directorio_dividido = dividir(directorio)
    claves = referencia.split(";")
    datos_personas = personas(directorio_dividido)
    clientes = diccionario(claves, datos_personas)
    # Salida
    print(clientes)


import sys
from PIL import Image

CENTER = Image.open('center.bmp')
N = Image.open('N.bmp')
S = Image.open('S.bmp')
W = Image.open('W.bmp')
E = Image.open('E.bmp')
NW = Image.open('NW.bmp')
NE = Image.open('NE.bmp')
SW = Image.open('SW.bmp')
SE = Image.open('SE.bmp')
WIDTH = 32
HEIGHT = 32

def do():
    if len(sys.argv) != 3:
        print('Bad argument count')
        return
    width = int(sys.argv[1])
    height = int(sys.argv[2])
    result = Image.new('RGBA', (width*WIDTH, height*HEIGHT), (0, 0, 0, 0))
    result.paste(NW, (0, 0))
    result.paste(NE, ((width-1)*WIDTH, 0))
    result.paste(SW, (0, (height-1)*HEIGHT))
    result.paste(SE, ((width-1)*WIDTH, (height-1)*HEIGHT))
    # left
    for i in range(height-2):
        result.paste(W, (0, (i+1)*HEIGHT))
    # right
    for i in range(height-2):
        result.paste(E, ((width-1)*WIDTH, (i+1)*HEIGHT))
    # top
    for i in range(width-2):
        result.paste(N, ((i+1)*WIDTH, 0))
    # bottom
    for i in range(width-2):
        result.paste(S, ((i+1)*WIDTH, (height-1)*HEIGHT))
    # center
    for i in range(height-2):
        for j in range(width-2):
            result.paste(CENTER, ((j+1)*WIDTH, (i+1)*HEIGHT))

    result.save('result.bmp')

do()


import sys
import os
import getopt
import glob

from Bio import SeqIO
from zoo.wrappers.treebuilders import Fasttree
from tables import *
from Bio import AlignIO
from zoo.wrappers.aligners import Mafft
from Bio.SeqIO import FastaIO

from zoo.seq_utils.utils import concatenate

def get_coverage(og):
    return (len(og[-1].seq)-og[-1].seq.count('X'))/len(og[-1].seq)

def perform_mapping(DIR_MAPPING, FILE_OGS):
    og_dict = {}
    '''read in og with aa seq'''
    og = list(SeqIO.parse(FILE_OGS, "fasta"))
    for record in og:
        key = record.description.split(" | ")[-1]
        if key in og_dict:
            ids = [rec.id for rec in og_dict[key]]
            if record.id not in ids:
                og_dict[key].append(record)
        else:
            og_dict[key] = []
            og_dict[key].append(record)

    # parse the mapped reads to ogs to dictionary
    all_dict = {}
    for file in glob.glob(DIR_MAPPING + "*.fa"):
        og_name = file.split("_")[-1].split(".")[0]
        og = og_dict[og_name]

        # change ids to species names
        for i, record in enumerate(og):
            s = record.id[0:5]
            record.id = s
        all_dict[og_name] = og

    OG_OUT = DIR_MAPPING + 'origin_og/'
    if not os.path.exists(OG_OUT):
        os.makedirs(OG_OUT)

    for key, item in all_dict.items():
        file_name = OG_OUT + key + ".fa"
        fasta_out = FastaIO.FastaWriter(open(file_name, "w"), wrap=None)
        fasta_out.write_file(item)

    print("FINISHED PARSING OGs!")
    return all_dict

def read_alignments(folder):
    align_list = []
    for filename in glob.glob(folder+"*.phy"):
        # input_handle = open(filename, "rU")
        align_list.append(AlignIO.read(filename, "phylip-relaxed"))
    print("FINISHED READING ALIGNMENTS!")
    return align_list

def perform_alignment(all_dict, DIR_MAPPING):
    align_dict = {}
    align_list = []
    counter = 0
    for key, value in all_dict.items():
        mafft_wrapper = Mafft(value, datatype="PROTEIN")
        mafft_wrapper.options.options['--localpair'].set_value(True)
        mafft_wrapper.options.options['--maxiterate'].set_value(1000)
        alignment = mafft_wrapper()
        align_dict[key] = alignment
        align_list.append(alignment)
        counter += 1
        if counter % 50 == 0:
            print('{} of {} alignments done'.format(counter, len(all_dict)))

    ALIGN_OUT = DIR_MAPPING + 'origin_align/'

    if not os.path.exists(ALIGN_OUT):
        os.makedirs(ALIGN_OUT)
    print("WRITING ALIGNMENT FILES INTO: {}!".format(ALIGN_OUT))
    for key, value in align_dict.items():
        output_handle = open(ALIGN_OUT + key + ".phy", "w")
        AlignIO.write(value, output_handle, "phylip")
    print("FINISHED ALIGNMENTS!")
    return align_list

def concatenate_alignment(align_list, DIR_MAPPING):
    ALIGN_OUT = DIR_MAPPING + 'origin_align/'
    concat_align = concatenate(align_list)

    output_handle = open(ALIGN_OUT + "CONCAT.phy", "w")
    AlignIO.write(concat_align, output_handle, "phylip")
    print("FINISHED CONCATINATION!")
    return concat_align

def build_tree(concat_align, DIR_MAPPING):

    fasttree_wrapper = Fasttree(concat_align, datatype="PROTEIN")
    tree = fasttree_wrapper()
    print("FINISHED TREE INFERENCE!")
    with open(DIR_MAPPING+"original_tree.nwk", "w") as text_file:
        text_file.write("{};".format(tree))
    print("Resulting tree: {}".format(tree))
    return tree

def main():

    try:
        opts, args = getopt.getopt(sys.argv[1:], "m:o:a:t:h", ["mapping_folder=", "ortholog_file=", "alignmnet_folder="])
    except getopt.GetoptError as e:
        print(str(e))
        print('map2align_test.py -m <mapping_folder> -o <ortholog_file> -a <alignmnet_folder>')
        sys.exit(2)

    mapping_folder = None
    ortholog_file = None
    alignment_folder = None

    for opt, arg in opts:
        if opt == '-h':
            print('map2align_test.py -m <mapping_folder> -o <ortholog_file> -a <alignmnet_folder>')
            sys.exit()
        elif opt in ("-m", "--mapping_folder"):
            mapping_folder = arg
            if mapping_folder[-1] is not "/":
                mapping_folder += "/"
        elif opt in ("-a", "--alignmnet_folder"):
            alignment_folder = arg
            if alignment_folder[-1] is not "/":
                alignment_folder += "/"
        elif opt in ("-o", "--ortholog_folder"):
            ortholog_file = arg
        else:
            assert False, "unhandled option"

    if alignment_folder:
        align = read_alignments(alignment_folder)
    else:
        mapping = perform_mapping(mapping_folder, ortholog_file)
        align = perform_alignment(mapping, mapping_folder)

    concatenation = concatenate_alignment(align, mapping_folder)
    build_tree(concatenation, mapping_folder)

if __name__ == "__main__":
    main()


from flask import Flask, abort
from flask import request, jsonify
from flask_cors import CORS, cross_origin
from flask_restful import Resource, Api

import subprocess
import os.path
from os import path

app = Flask(__name__)
api = Api(app)
CORS(app, resources={r"/*": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'

class startTraining(Resource):
    def __init__(self):
        super(startTraining, self).__init__()

    @cross_origin(origin='*', headers=['Content-Type'])
    def post(self):
        try:
            args = request.get_json()
            # print(args)

            subprocess.Popen(
                ['python', 'train.py',
                '--memory', args['memory'],
                '--exploration_rate_decay', args['exploration_rate_decay'],
                '--learn_every', args['learn_every'],
                '--sync_every', args['sync_every'],
                '--episodes', args['episodes'],
                ]
            )
            return jsonify({"data": "Starting training process for Mario ...",
                            "error": None
                            }), 201
        except KeyError as err:
            return jsonify({"data": None,
                            "error": "Wrong/missing key or missing JSON body"
                            }), 404
        except TypeError as err:
            return jsonify({"data": None,
                            "error": "JSON key values are non-string"
                            }), 400
        except subprocess.CalledProcessError as err:
            return jsonify({"data": None,
                            "error": "CalledProcessError"
                            }), 504

class startTesting(Resource):
    def __init__(self):
        super(startTesting, self).__init__()

    @cross_origin(origin='*', headers=['Content-Type'])
    def post(self):
        try:
            args = request.get_json()
            # print(args)

            if path.exists(args['checkpoint']):
                subprocess.Popen(
                    ['python', 'test.py',
                    '--checkpoint', args['checkpoint'],
                    ]
                )
                return jsonify({"data": "Starting evaluation for Mario ...",
                                "error": None
                                }), 201
            else:
                return jsonify({"data": None,
                                "error": "Checkpoint path is invalid"
                                }), 405
        except KeyError as err:
            return jsonify({"data": None,
                            "error": "Wrong/missing key or missing JSON body"
                            }), 404
        except TypeError as err:
            return jsonify({"data": None,
                            "error": "Checkpoint path is non-string"
                            }), 400
        except subprocess.CalledProcessError as err:
            return jsonify({"data": None,
                            "error": "CalledProcessError"
                            }), 504

class playGame(Resource):
    def __init__(self):
        super(playGame, self).__init__()

    @cross_origin(origin='*', headers=['Content-Type'])
    def post(self):
        try:
            subprocess.Popen(
                ['gym_super_mario_bros',
                '-e', 'SuperMarioBros-v0',
                '-m', 'human',
                ]
            )
            return jsonify({"data": "Starting Mario game ...",
                        "error": None
                        }), 201
        except AttributeError as err:
            return jsonify({"data": None,
                            "error": "Bad request: game cannot be played"
                            }), 400
        except subprocess.CalledProcessError as err:
            return jsonify({"data": None,
                            "error": "CalledProcessError"
                            }), 504

##############################################################
#                      ENDPOINTS                             #
##############################################################
api.add_resource(startTraining, "/train")
api.add_resource(startTesting, "/test")
api.add_resource(playGame, "/play")

if __name__ == '__main__':

    app.run(host="0.0.0.0", port=5001, debug=True)


import tensorflow as tf

def compute_ious_for_image(boxes1, boxes2):
    """computes a lookup table vector containing the ious for a given set boxes.

    The lookup vector is to be indexed by [`boxes1_index`,`boxes2_index`].

    Bounding boxes are expected to be in the corners format of
    `[bounding_box.LEFT, bounding_box.RIGHT, bounding_box.TOP, bounding_box.BOTTOM]`.
    For example, the bounding box with it's left side at 100, bounding_box.RIGHT side at
    200, bounding_box.TOP at 101, and bounding_box.BOTTOM at 201 would be represented
    as:
    > [100, 200, 101, 201]

    Args:
      boxes1: a list of bounding boxes in 'corners' format.
      boxes2: a list of bounding boxes in 'corners' format.

    Returns:
      iou_lookup_table: a vector containing the pairwise ious of boxes1 and
        boxes2.
    """
    zero = tf.convert_to_tensor(0.0, boxes1.dtype)
    boxes1_ymin, boxes1_xmin, boxes1_ymax, boxes1_xmax = tf.unstack(
        boxes1[..., :4, None], 4, axis=-2
    )
    boxes2_ymin, boxes2_xmin, boxes2_ymax, boxes2_xmax = tf.unstack(
        boxes2[None, ..., :4], 4, axis=-1
    )
    boxes1_width = tf.maximum(zero, boxes1_xmax - boxes1_xmin)
    boxes1_height = tf.maximum(zero, boxes1_ymax - boxes1_ymin)
    boxes2_width = tf.maximum(zero, boxes2_xmax - boxes2_xmin)
    boxes2_height = tf.maximum(zero, boxes2_ymax - boxes2_ymin)
    boxes1_area = boxes1_width * boxes1_height
    boxes2_area = boxes2_width * boxes2_height
    intersect_ymin = tf.maximum(boxes1_ymin, boxes2_ymin)
    intersect_xmin = tf.maximum(boxes1_xmin, boxes2_xmin)
    intersect_ymax = tf.minimum(boxes1_ymax, boxes2_ymax)
    intersect_xmax = tf.minimum(boxes1_xmax, boxes2_xmax)
    intersect_width = tf.maximum(zero, intersect_xmax - intersect_xmin)
    intersect_height = tf.maximum(zero, intersect_ymax - intersect_ymin)
    intersect_area = intersect_width * intersect_height

    union_area = boxes1_area + boxes2_area - intersect_area
    return tf.math.divide_no_nan(intersect_area, union_area)


"""
.. module:: undirected_hypergraph
   :synopsis: Defines UndirectedHypergraph class for the basic properties
            of an undirected hypergraph, along with the relevant structures
            regarding nodes, hyperedges, adjacency, etc.

"""

import copy

class UndirectedHypergraph(object):
    """
    The UndirectedHypergraph class provides an undirected hypergraph object
    and associated functions for basic properties of undirected hypergraphs.

    An undirected hypergraph contains nodes and undirected hyperedges. Each
    undirected hyperedge simply connects a set of nodes. An undirected
    hypergraph is a special case of an undirected graph, where each edge
    connects exactly 2 nodes. The set of nodes cannot be empty.

    A node is simply any hashable type. See "add_node" or "add_nodes" for
    more details.

    An undirected hyperedge is any iterable container of nodes.
    This class assigns (upon adding) and refers to each hyperedge by an
    internal ID. See "add_hyperedge" or "add_hyperedges" for more details.

    Self-loops and parallel (multi-) hyperedges are not allowed.

    :note: This class uses several data structures to store a undirected
        hypergraph. Since these structures must stay in sync (see: __init__),
        we highly recommend that only the public methods be used for accessing
        and modifying the hypergraph.

    Examples:
    Create an empty undirected hypergraph (no nodes or hyperedges).

    >>> H = UndirectedHypergraph()

    Add nodes (with or without attributes) to the hypergraph
    one at a time (see: add_node) or several at a time (see: add_nodes).

    >>> H.add_nodes(["A", "B", "C", "D"], {color: "black"})

    Add hyperedges to the hypergraph one at a time (see: add_hyperedge)
    or several at a time (see: add_hyperedges).

    >>> H.add_hyperedges(["A", "B"], ("A", "C", "D"))

    Update attributes of existing nodes and hyperedges by simulating adding the
    node or hyperedge again, with the [potentially new] attribute appended.

    >>> H.add_node("A", label="sink")
    >>> H.add_hyperedge(["A", "C", "D"], weight=5)

    """

    def __init__(self):
        """
        Constructor for the UndirectedHypergraph class.
        Initializes all internal data structures used for the rapid
        execution of most of the fundamental hypergraph queries.

        """
        # _node_attributes: a dictionary mapping a node (any hashable type)
        # to a dictionary of attributes of that node.
        #
        # Provides O(1) time access to the attributes of a node.
        #
        # Used in the implementation of methods such as add_node and
        # get_node_attributes.
        #
        self._node_attributes = {}

        # _hyperedge_attributes: a dictionary mapping a hyperedge ID
        # (initially created by the call to add_hyperedge or add_hyperedges)
        # to a dictionary of attributes of that hyperedge.
        # Given a hyperedge ID, _hyperedge_attributes[hyperedge_id] stores
        # the nodes of the hyperedge as specified by the user (as "nodes")
        # and the weight of the hyperedge (as "weight").
        # For internal purposes, it also stores the frozenset version of
        # the nodes (as "__frozen_nodes").
        #
        # Provides O(1) time access to the attributes of a hyperedge.
        #
        # Used in the implementation of methods such as add_hyperedge and
        # get_hyperedge_attributes.
        #
        self._hyperedge_attributes = {}

        # The star of a node is the set of hyperedges such that the
        # node is a member of.
        #
        # _star: a dictionary mapping a node to the set of hyperedges
        # that are in that node's star.
        #
        # Provides O(1) time access to a reference to the set of hyperedges
        # that a node is a member of.
        #
        # Used in the implementation of methods such as add_node and
        # remove_hyperedge.
        #
        self._star = {}

        # _node_set_to_hyperedge: a dictionary mapping a set of nodes to the ID
        # of the hyperedge they compose. We represent the node set by a
        # frozenset, so that the structure is hashable.
        #
        # Provides O(1) time access to the ID of the hyperedge that
        # a specific frozenset of nodes composes.
        #
        self._node_set_to_hyperedge = {}

        # _current_hyperedge_id: an int representing the hyperedge ID that
        # was most recently assigned by the class (since users don't
        # name/ID their own hyperedges); hyperedges being added are issued
        # ID "e"+_current_hyperedge_id.
        #
        # Since the class takes responsibility for giving hyperedges
        # their IDs (i.e. a unique identifier; could be alternatively viewed
        # as a unique name, label, etc.), the class keeps track of the issued
        # IDs. A consecutive issuing of integer IDs to the hyperedges is a
        # simple strategy to ensure their uniqueness while allowing for
        # readability.
        #
        # e.g., _current_hyperedge_id = 4  implies that 4 hyperedges have
        # been added to the hypergraph, and that "e4" was the most recently
        # assigned hyperedge.
        #
        # Note: An hyperedge, once added, will receive a unique ID. If this
        # hyperedge is removed and subsequently re-added, it will not receive
        # the same ID as it was issued when it was originally added.
        #
        self._current_hyperedge_id = 0

    def _combine_attribute_arguments(self, attr_dict, attr):
        # Note: Code & comments unchanged from DirectedHypergraph
        """Combines attr_dict and attr dictionaries, by updating attr_dict
            with attr.

        :param attr_dict: dictionary of attributes of the node.
        :param attr: keyword arguments of attributes of the node;
                    attr's values will override attr_dict's values
                    if both are provided.
        :returns: dict -- single dictionary of [combined] attributes.
        :raises: AttributeError -- attr_dict argument must be a dictionary.

        """
        # If no attribute dict was passed, treat the keyword
        # arguments as the dict
        if attr_dict is None:
            attr_dict = attr
        # Otherwise, combine the passed attribute dict with
        # the keyword arguments
        else:
            try:
                attr_dict.update(attr)
            except AttributeError:
                raise AttributeError("attr_dict argument \
                                     must be a dictionary.")
        return attr_dict

    def has_node(self, node):
        # Note: Code & comments unchanged from DirectedHypergraph
        """Determines if a specific node is present in the hypergraph.

        :param node: reference to the node whose presence is being checked.
        :returns: bool -- true iff the node exists in the hypergraph.

        """
        return node in self._node_attributes

    def add_node(self, node, attr_dict=None, **attr):
        """Adds a node to the graph, along with any related attributes
           of the node.

        :param node: reference to the node being added.
        :param attr_dict: dictionary of attributes of the node.
        :param attr: keyword arguments of attributes of the node;
                    attr's values will override attr_dict's values
                    if both are provided.
        :note: Following the NetworkX model, we allow both a dictionary
            of attributes to be passed in by the user as well as key-value
            pairs of attributes to be passed in by the user to provide
            greater flexibility. This pattern is followed in methods such
            as add_nodes, add_hyperedge, and add_hyperedges.

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> attributes = {label: "positive"}
            >>> H.add_node("A", attributes)
            >>> H.add_node("B", label="negative")
            >>> H.add_node("C", attributes, root=True)

        """
        attr_dict = self._combine_attribute_arguments(attr_dict, attr)

        # If the node hasn't previously been added, add it along
        # with its attributes
        if not self.has_node(node):
            self._node_attributes[node] = attr_dict
            self._star[node] = set()
        # Otherwise, just update the node's attributes
        else:
            self._node_attributes[node].update(attr_dict)

    def add_nodes(self, nodes, attr_dict=None, **attr):
        # Note: Code & comments unchanged from DirectedHypergraph
        """Adds multiple nodes to the graph, along with any related attributes
            of the nodes.

        :param nodes: iterable container to either references of the nodes
                    OR tuples of (node reference, attribute dictionary);
                    if an attribute dictionary is provided in the tuple,
                    its values will override both attr_dict's and attr's
                    values.
        :param attr_dict: dictionary of attributes shared by all the nodes.
        :param attr: keyword arguments of attributes of the node;
                    attr's values will override attr_dict's values
                    if both are provided.

        See also:
        add_node

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> attributes = {label: "positive"}
            >>> node_list = ["A",
                             ("B", {label="negative"}),
                             ("C", {root=True})]
            >>> H.add_nodes(node_list, attributes)

        """
        attr_dict = self._combine_attribute_arguments(attr_dict, attr)

        for node in nodes:
            # Note: This won't behave properly if the node is actually a tuple
            if type(node) is tuple:
                # See ("B", {label="negative"}) in the documentation example
                new_node, node_attr_dict = node
                # Create a new dictionary and load it with node_attr_dict and
                # attr_dict, with the former (node_attr_dict) taking precedence
                new_dict = attr_dict.copy()
                new_dict.update(node_attr_dict)
                self.add_node(new_node, new_dict)
            else:
                # See "A" in the documentation example
                self.add_node(node, attr_dict.copy())

    def remove_node(self, node):
        """Removes a node and its attributes from the hypergraph. Removes
        every hyperedge that contains this node.

        :param node: reference to the node being added.
        :raises: ValueError -- No such node exists.

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> H.add_node("A", label="positive")
            >>> H.remove_node("A")

        """
        if not self.has_node(node):
            raise ValueError("No such node exists.")

        # Loop over every hyperedge in the star of the node;
        # i.e., over every hyperedge that contains the node
        for hyperedge_id in self._star[node]:
            frozen_nodes = \
                self._hyperedge_attributes[hyperedge_id]["__frozen_nodes"]
            # Remove the node set composing the hyperedge
            del self._node_set_to_hyperedge[frozen_nodes]
            # Remove this hyperedge's attributes
            del self._hyperedge_attributes[hyperedge_id]

        # Remove node's star
        del self._star[node]

        # Remove node's attributes dictionary
        del self._node_attributes[node]

    def remove_nodes(self, nodes):
        # Note: Code unchanged from DirectedHypergraph
        """Removes multiple nodes and their attributes from the graph. If
        the nodes are part of any hyperedges, those hyperedges are removed
        as well.

        :param nodes: iterable container to either references of the nodes
                    OR tuples of (node reference, attribute dictionary);
                    if an attribute dictionary is provided in the tuple,
                    its values will override both attr_dict's and attr's
                    values.

        See also:
        remove_node

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> attributes = {label: "positive"}
            >>> node_list = ["A",
                             ("B", {label="negative"}),
                             ("C", {root=True})]
            >>> H.add_nodes(node_list, attributes)
            >>> H.remove_nodes(["A", "B", "C"])

        """
        for node in nodes:
            self.remove_node(node)

    def get_node_set(self):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Returns the set of nodes that are currently in the hypergraph.

        :returns: set -- all nodes currently in the hypergraph

        """
        return set(self._node_attributes.keys())

    def node_iterator(self):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Provides an iterator over the nodes.

        """
        return iter(self._node_attributes)

    def get_node_attribute(self, node, attribute_name):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Given a node and the name of an attribute, get a copy
        of that node's attribute.

        :param node: reference to the node to retrieve the attribute of.
        :param attribute_name: name of the attribute to retrieve.
        :returns: attribute value of the attribute_name key for the
                specified node.
        :raises: ValueError -- No such node exists.
        :raises: ValueError -- No such attribute exists.

        """
        if not self.has_node(node):
            raise ValueError("No such node exists.")
        elif attribute_name not in self._node_attributes[node]:
            raise ValueError("No such attribute exists.")
        else:
            return copy.\
                copy(self._node_attributes[node][attribute_name])

    def get_node_attributes(self, node):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Given a node, get a dictionary with copies of that node's
        attributes.

        :param node: reference to the node to retrieve the attributes of.
        :returns: dict -- copy of each attribute of the specified node.
        :raises: ValueError -- No such node exists.

        """
        if not self.has_node(node):
            raise ValueError("No such node exists.")
        attributes = {}
        for attr_name, attr_value in self._node_attributes[node].items():
            attributes[attr_name] = copy.copy(attr_value)
        return attributes

    def _assign_next_hyperedge_id(self):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Returns the next [consecutive] ID to be assigned
            to a hyperedge.
        :returns: str -- hyperedge ID to be assigned.

        """
        self._current_hyperedge_id += 1
        return "e" + str(self._current_hyperedge_id)

    def add_hyperedge(self, nodes, attr_dict=None, **attr):
        """Adds a hyperedge to the hypergraph, along with any related
            attributes of the hyperedge.
            This method will automatically add any node from the node set
            that was not in the hypergraph.
            A hyperedge without a "weight" attribute specified will be
            assigned the default value of 1.

        :param nodes: iterable container of references to nodes in the
                    hyperedge to be added.
        :param attr_dict: dictionary of attributes of the hyperedge being
                        added.
        :param attr: keyword arguments of attributes of the hyperedge;
                    attr's values will override attr_dict's values
                    if both are provided.
        :returns: str -- the ID of the hyperedge that was added.
        :raises: ValueError -- nodes arguments cannot be empty.

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> x = H.add_hyperedge(["A", "B", "C"])
            >>> y = H.add_hyperedge(("A", "D"), weight=2)
            >>> z = H.add_hyperedge(set(["B", "D"]), {color: "red"})

        """
        attr_dict = self._combine_attribute_arguments(attr_dict, attr)

        # Don't allow empty node set (invalid hyperedge)
        if not nodes:
            raise ValueError("nodes argument cannot be empty.")

        # Use frozensets for node sets to allow for hashable keys
        frozen_nodes = frozenset(nodes)

        is_new_hyperedge = not self.has_hyperedge(frozen_nodes)
        if is_new_hyperedge:
            # Add nodes to graph (if not already present)
            self.add_nodes(frozen_nodes)

            # Create new hyperedge name to use as reference for that hyperedge
            hyperedge_id = self._assign_next_hyperedge_id()

            # For each node in the node set, add hyperedge to the node's star
            for node in frozen_nodes:
                self._star[node].add(hyperedge_id)

            # Add the hyperedge ID as the hyperedge that the node set composes
            self._node_set_to_hyperedge[frozen_nodes] = hyperedge_id

            # Assign some special attributes to this hyperedge. We assign
            # a default weight of 1 to the hyperedge. We also store the
            # original node set in order to return them exactly as the
            # user passed them into add_hyperedge.
            self._hyperedge_attributes[hyperedge_id] = \
                {"nodes": nodes, "__frozen_nodes": frozen_nodes, "weight": 1}
        else:
            # If its not a new hyperedge, just get its ID to update attributes
            hyperedge_id = self._node_set_to_hyperedge[frozen_nodes]

        # Set attributes and return hyperedge ID
        self._hyperedge_attributes[hyperedge_id].update(attr_dict)
        return hyperedge_id

    def add_hyperedges(self, hyperedges, attr_dict=None, **attr):
        """Adds multiple hyperedges to the graph, along with any related
            attributes of the hyperedges.
            If any node of a hyperedge has not previously been added to the
            hypergraph, it will automatically be added here.
            Hyperedges without a "weight" attribute specified will be
            assigned the default value of 1.

        :param hyperedges: iterable container to references of the node sets
        :param attr_dict: dictionary of attributes shared by all
                    the hyperedges being added.
        :param attr: keyword arguments of attributes of the hyperedges;
                    attr's values will override attr_dict's values
                    if both are provided.
        :returns: list -- the IDs of the hyperedges added in the order
                    specified by the hyperedges container's iterator.

        See also:
        add_hyperedge

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> hyperedge_list = (["A", "B", "C"],
                                  ("A", "D"),
                                  set(["B", "D"]))
            >>> hyperedge_ids = H.add_hyperedges(hyperedge_list)

        """
        attr_dict = self._combine_attribute_arguments(attr_dict, attr)

        hyperedge_ids = []

        for nodes in hyperedges:
            hyperedge_id = self.add_hyperedge(nodes, attr_dict.copy())
            hyperedge_ids.append(hyperedge_id)

        return hyperedge_ids

    def remove_hyperedge(self, hyperedge_id):
        """Removes a hyperedge and its attributes from the hypergraph.

        :param hyperedge_id: ID of the hyperedge to be removed.
        :raises: ValueError -- No such hyperedge exists.

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> hyperedge_list = (["A", "B", "C"],
                                  ("A", "D"),
                                  set(["B", "D"]))
            >>> hyperedge_ids = H.add_hyperedges(hyperedge_list)
            >>> H.remove_hyperedge(hyperedge_ids[0])
            >>> BD_id = H.get_hyperedge_id(set(["B", "D"]))
            >>> H.remove_hyperedge(BD_id)

        """
        if not self.has_hyperedge_id(hyperedge_id):
            raise ValueError("No such hyperedge exists.")

        frozen_nodes = \
            self._hyperedge_attributes[hyperedge_id]["__frozen_nodes"]

        # Remove this hyperedge from the star of every node in the hyperedge
        for node in frozen_nodes:
            self._star[node].remove(hyperedge_id)

        # Remove this set as the composer of the hyperedge
        del self._node_set_to_hyperedge[frozen_nodes]

        # Remove hyperedge's attributes dictionary
        del self._hyperedge_attributes[hyperedge_id]

    def remove_hyperedges(self, hyperedge_ids):
        # Note: Code unchanged from DirectedHypergraph
        """Removes a set of hyperedges and their attributes from
        the hypergraph.

        :param hyperedge_ids: iterable container of IDs of the hyperedges
                        to be removed.
        :raises: ValueError -- No such hyperedge exists.

        See also:
        remove_hyperedge

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> hyperedge_list = (["A", "B", "C"],
                                  ("A", "D"),
                                  set(["B", "D"]))
            >>> hyperedge_ids = H.add_hyperedges(hyperedge_list)
            >>> H.remove_hyperedges(hyperedge_ids)

        """
        for hyperedge_id in hyperedge_ids:
            self.remove_hyperedge(hyperedge_id)

    def has_hyperedge(self, nodes):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Given a set of nodes, returns whether there is a hyperedge in the
        hypergraph that is precisely composed of those nodes.

        :param nodes: iterable container of references to nodes in the
                    hyperedge being checked.
        :returns: bool -- true iff a hyperedge exists composed of the
                specified nodes.
        """
        frozen_nodes = frozenset(nodes)
        return frozen_nodes in self._node_set_to_hyperedge

    def has_hyperedge_id(self, hyperedge_id):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Determines if a hyperedge referenced by hyperedge_id
        exists in the hypergraph.

        :param hyperedge_id: ID of the hyperedge whose existence is
                            being checked.
        :returns: bool -- true iff a hyperedge exists that has id hyperedge_id.

        """
        return hyperedge_id in self._hyperedge_attributes

    def get_hyperedge_id_set(self):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Returns the set of IDs of hyperedges that are currently
        in the hypergraph.

        :returns: set -- all IDs of hyperedges currently in the hypergraph

        """
        return set(self._hyperedge_attributes.keys())

    def hyperedge_id_iterator(self):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Provides an iterator over the list of hyperedge IDs.

        """
        return iter(self._hyperedge_attributes)

    def get_hyperedge_id(self, nodes):
        """From a set of nodes, returns the ID of the hyperedge that this
        set comprises.

        :param nodes: iterable container of references to nodes in the
                    the hyperedge to be added
        :returns: str -- ID of the hyperedge that has that the specified
                node set comprises.
        :raises: ValueError -- No such hyperedge exists.

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> hyperedge_list = (["A", "B", "C"],
                                  ("A", "D"),
                                  set(["B", "D"]))
            >>> hyperedge_ids = H.add_hyperedges(hyperedge_list)
            >>> x = H.get_hyperedge_id(["A", "B", "C"])

        """
        frozen_nodes = frozenset(nodes)

        if not self.has_hyperedge(frozen_nodes):
            raise ValueError("No such hyperedge exists.")

        return self._node_set_to_hyperedge[frozen_nodes]

    def get_hyperedge_attribute(self, hyperedge_id, attribute_name):
        # Note: Code unchanged from DirectedHypergraph
        """Given a hyperedge ID and the name of an attribute, get a copy
        of that hyperedge's attribute.

        :param hyperedge_id: ID of the hyperedge to retrieve the attribute of.
        :param attribute_name: name of the attribute to retrieve.
        :returns: attribute value of the attribute_name key for the
                specified hyperedge.
        :raises: ValueError -- No such hyperedge exists.
        :raises: ValueError -- No such attribute exists.

        Examples:
        ::

            >>> H = UndirectedHypergraph()
            >>> hyperedge_list = (["A", "B", "C"],
                                  ("A", "D"),
                                  set(["B", "D"]))
            >>> hyperedge_ids = H.add_hyperedges(hyperedge_list)
            >>> attribute = H.get_hyperedge_attribute(hyperedge_ids[0])

        """
        if not self.has_hyperedge_id(hyperedge_id):
            raise ValueError("No such hyperedge exists.")
        elif attribute_name not in self._hyperedge_attributes[hyperedge_id]:
            raise ValueError("No such attribute exists.")
        else:
            return copy.\
                copy(self._hyperedge_attributes[hyperedge_id][attribute_name])

    def get_hyperedge_attributes(self, hyperedge_id):
        """Given a hyperedge ID, get a dictionary of copies of that hyperedge's
        attributes.

        :param hyperedge_id: ID of the hyperedge to retrieve the attributes of.
        :returns: dict -- copy of each attribute of the specified hyperedge_id
                (except the private __frozen_nodes entry).
        :raises: ValueError -- No such hyperedge exists.

        """
        if not self.has_hyperedge_id(hyperedge_id):
            raise ValueError("No such hyperedge exists.")
        dict_to_copy = self._hyperedge_attributes[hyperedge_id].items()
        attributes = {}
        for attr_name, attr_value in dict_to_copy:
            if attr_name != "__frozen_nodes":
                attributes[attr_name] = copy.copy(attr_value)
        return attributes

    def get_hyperedge_nodes(self, hyperedge_id):
        """Given a hyperedge ID, get a copy of that hyperedge's nodes.

        :param hyperedge_id: ID of the hyperedge to retrieve the nodes from.
        :returns: a copy of the container of nodes that the user provided
                for the hyperedge referenced as hyperedge_id.

        """
        return self.get_hyperedge_attribute(hyperedge_id, "nodes")

    def get_hyperedge_weight(self, hyperedge_id):
        # Note: Code and comments unchanged from DirectedHypergraph
        """Given a hyperedge ID, get that hyperedge's weight.

        :param hyperedge: ID of the hyperedge to retrieve the weight from.
        :returns: int -- the weight of the hyperedge referenced as
                hyperedge_id.

        """
        return self.get_hyperedge_attribute(hyperedge_id, "weight")

    def get_star(self, node):
        """Given a node, get a copy of that node's star, that is, the set of
        hyperedges that the node belongs to.

        :param node: node to retrieve the star of.
        :returns: set -- set of hyperedge_ids for the hyperedges
                        in the node's star.
        :raises: ValueError -- No such node exists.

        """
        if node not in self._node_attributes:
            raise ValueError("No such node exists.")
        return self._star[node].copy()

    def copy(self):
        # Note: Code unchanged from DirectedHypergraph
        """Creates a new UndirectedHypergraph object with the same node and
        hyperedge structure.
        Copies of the nodes' and hyperedges' attributes are stored
        and used in the new hypergraph.

        :returns: UndirectedHypergraph -- a new hypergraph that is a copy of
                the current hypergraph

        """
        return self.__copy__()

    def __copy__(self):
        """Creates a new UndirectedHypergraph object with the same node and
        hyperedge structure.
        Copies of the nodes' and hyperedges' attributes are stored
        and used in the new hypergraph.

        :returns: UndirectedHypergraph -- a new hypergraph that is a copy of
                the current hypergraph

        """
        new_H = UndirectedHypergraph()

        # Loop over every node and its corresponding attribute dict
        # in the original hypergraph's _node_attributes dict
        for node, attr_dict in self._node_attributes.items():
            # Create a new dict for that node to store that node's attributes
            new_H._node_attributes[node] = {}
            # Loop over each attribute of that node in the original hypergraph
            # and, for each key, copy the corresponding value into the new
            # hypergraph's dictionary using the same key
            for attr_name, attr_value in attr_dict.items():
                new_H._node_attributes[node][attr_name] = \
                    copy.copy(attr_value)

        # Loop over every hyperedge_id and its corresponding attribute dict
        # in the original hypergraph's _hyperedge_attributes dict
        for hyperedge_id, attr_dict in self._hyperedge_attributes.items():
            # Create a new dict for that node to store that node's attributes
            new_H._hyperedge_attributes[hyperedge_id] = {}
            # Loop over each attribute of that hyperedge in the original
            # hypergraph and, for each key, copy the corresponding value
            # the new hypergraph's dictionary
            for attr_name, attr_value in attr_dict.items():
                new_H.\
                    _hyperedge_attributes[hyperedge_id][attr_name] = \
                    copy.copy(attr_value)

        # Copy the original hypergraph's nodes' stars
        new_H._star = self._star.copy()
        for node in self._node_attributes.keys():
            new_H._star[node] = self._star[node].copy()

        # Copy the original hypergraph's composed hyperedges
        for frozen_nodes, hyperedge_id in self._node_set_to_hyperedge.items():
            new_H._node_set_to_hyperedge[frozen_nodes] = \
                copy.copy(hyperedge_id)

        # Start assigning edge labels at the same
        new_H._current_hyperedge_id = self._current_hyperedge_id

        return new_H

    # TODO: make reading more extensible (attributes, variable ordering, etc.)
    def read(self, file_name, delim=',', sep='\t'):
        """Reads an undirected hypergraph from a file, where nodes are
        represented as strings.
        Each column is separated by "sep", and the individual nodes are
        delimited by "delim".
        The header line is currently ignored, but columns should be of
        the format:
        node1[delim]..nodeM[sep]weight

        As a concrete example, an arbitrary line with delim=',' and
        sep='    ' (4 spaces) may look like:
        ::

            x1,x2,x3,x5    12

        which defines a hyperedge of weight 12 from a node set containing
        nodes "x1", "x2", "x3", and "x5".

        """
        in_file = open(file_name, 'r')

        # Skip the header line
        in_file.readline()

        line_number = 2
        for line in in_file.readlines():
            line = line.strip()
            # Skip empty lines
            if not line:
                continue

            words = line.split(sep)
            if not (1 <= len(words) <= 2):
                raise \
                    IOError("Line {} ".format(line_number) +
                            "contains {} ".format(len(words)) +
                            "columns -- must contain only 1 or 2.")

            nodes = set(words[0].split(delim))
            if len(words) == 2:
                weight = float(words[1].split(delim)[0])
            else:
                weight = 1
            self.add_hyperedge(nodes, weight=weight)

            line_number += 1

        in_file.close()

    # TODO: make writing more extensible (attributes, variable ordering, etc.)
    def write(self, file_name, delim=',', sep='\t'):
        """Writes an undirected hypergraph from a file, where nodes are
        represented as strings.
        Each column is separated by "sep", and the individual nodes are
        delimited by "delim".
        The header line is currently ignored, but columns should be of
        the format:
        node1[delim]..nodeM[sep]node1[delim]..nodeN[sep]weight

        As a concrete example, an arbitrary line with delim=',' and
        sep='    ' (4 spaces) may look like:
        ::

            x1,x2,x3,x5    12

        which defines a hyperedge of weight 12 from a node set containing
        nodes "x1", "x2", "x3", and "x5".

        """
        out_file = open(file_name, 'w')

        # write first header line
        out_file.write("nodes" + sep + "weight\n")

        for hyperedge_id in self.get_hyperedge_id_set():
            line = ""
            # Write each node to the line, separated by delim
            for node in self.get_hyperedge_nodes(hyperedge_id):
                line += node + delim
            # Remove last (extra) delim
            line = line[:-1]

            # Write the weight to the line and end the line
            line += sep + str(self.get_hyperedge_weight(hyperedge_id)) + "\n"

            out_file.write(line)

        out_file.close()


#Getting inputs and decisions

# we put end=" " so that the cursor stays on the same line
print ("What's your name", end=" ")
name = input();

print ("How old are you (in years)?", end=" ")
age = int(input());

print ("How tall are you (in inches)?", end=" ")
height = float(input());

print ("How much do you weigh (in lbs)?", end=" ")
weight = float(input());

print (f"Hello {name}, you are {age} years old, weighs {weight} lbs and you are {height} inches tall")

if age > 40:
    young_or_old = "Old"
else:
    young_or_old = "Young"
print (f"At {age} years old, you are considered {young_or_old}")

if height > 65:
    if weight > 180:
        heavy = "heavy"
    else:
        heavy = "not heavy"
else:
    if weight > 150:
        heavy = "heavy"
    else:
        heavy = "not heavy"
print (f"At {height} inches tall and weighing {weight} lbs, you are {heavy}")