#!/usr/bin/env python

import gzip
from Bio import SeqIO
import argparse
import matplotlib.pyplot as plt

parser = argparse.ArgumentParser()
parser.add_argument("infile", type=str,
                    help="provide the name of the sequence input file")
parser.add_argument("format", type=str,
                    help="provide the format of the sequences in your input file")
parser.add_argument("prefixOut", type=str,
                    help="provide a prefix to create output files")

args=parser.parse_args()

pgcList=[]
lenList=[]
totalReads=0
totalLength=0
print(args.infile)
with open(args.infile, "rt") as handle:
    for record in SeqIO.parse(handle, args.format):
#        print(record.id)
        pgc=(record.seq.upper().count('G') + record.seq.upper().count('C')) / len(record.seq)
        pgcList.append(pgc)
        lenList.append(len(record.seq))
        totalLength=totalLength+len(record.seq)
        totalReads=totalReads+1

fig, (ax1, ax2,ax3) = plt.subplots(nrows=1, ncols=3, figsize=(12, 4))
ax1.hist(lenList,bins=1000,histtype='bar')
ax1.set_title('Read lengths')
ax1.set_xlabel('Length (bp)')
ax1.tick_params(axis='x', labelsize=8)
ax1.tick_params(axis='y', labelsize=8)

ax2.hist(lenList,bins=1000,histtype='bar')
ax2.set_title('Read lengths (log)')
ax2.set_xlabel('Length (log bp)')
ax2.set_xscale('log')
ax2.yaxis.set_ticklabels([])
ax2.tick_params(axis='x', labelsize=8)

ax3.hist(pgcList,bins=100,histtype='bar')
ax3.set_title('GC content')
ax3.set_xlabel('GC content')
ax3.yaxis.tick_right()
ax3.tick_params(axis='x', labelsize=8)
ax3.tick_params(axis='y', labelsize=8)

histogramsOutSVG=args.prefixOut+'_histograms.svg'
histogramsOutPNG=args.prefixOut+'_histograms.png'

plt.savefig(histogramsOutSVG, format="svg")
plt.savefig(histogramsOutPNG, format="png")

print(f'Total Length: {totalLength}; TotalReads={totalReads}')


# 169. Majority Element
# Given an array nums of size n, return the majority element.
# The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array.

from typing import List
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        res, cnt = 0, 0
        for num in nums:
            if cnt == 0:
                res = num
            if num != res:
                cnt = cnt - 1
            else:
                cnt = cnt + 1
        return res
    # 我的解法
    # def majorityElement(self, nums: List[int]) -> int:
    #     hashMap = {}
    #     for i in range(len(nums)):
    #         hashMap[nums[i]] = hashMap.get(nums[i], 0) + 1
    #     for key in hashMap:
    #         if hashMap[key] > len(nums) // 2:
    #             return key

nums = [3,2,3]
print(Solution().majorityElement(nums))
nums = [2,2,1,1,1,2,2]
print(Solution().majorityElement(nums))


# -*- coding: utf-8 -*-
# @Author: MirrorAi
# @Date:   2020-01-20 16:47:49
# @Last Modified by:   MirroAi
# @Last Modified time: 2020-01-20 16:54:12

# 八进制转换为十进制

def run():

    x = 111
    print("八进制 %d 的十进制是 %d" % (x, int(str(x), 8)))

if __name__ == "__main__":
    run()


import time
#dictionary to represent the graph, each key corresponds to a node, each value corresponds to a neighbor
graph = {
    'A': ["B", "C"],
    'B': ["D", "E"],
    'C': ["F"],
    'D': [],
    'E': ["F"],
    'F': ["H"],
    'G': [], #this node doesnt exist in the graph
    'H': []
}
start_time = time.time() #to calculate the time it takes for my program to be compiled
visited = set() #a set to add each visited node
stack = []

def depth_first_search(visited, graph, node):
    #check if the node is not visited
    if node not in visited:
        #add the visited node to the set
        visited.add(node)
        print(node)
        #for each neighbour found for the next node, perform recursion: dfs(visited, graph, 'neighbouring node')
        for neighbour in graph[node]:
            depth_first_search(visited, graph, neighbour)

depth_first_search(visited, graph, 'A')
end_time = time.time()
total_time = end_time - start_time
print("Compile Time: ", total_time)


import random as rd
import math
import csv
import matplotlib.pyplot as plt
from decimal import Decimal

#定义打印机类
class Printer:
    def __init__(self, state, graph):
        self.state = state
        self.node_curr = 0
        self.node_last = 0
        self.actions = []
        self.action = 0
        self.g = []
        for i in range(Nodes):
            self.g.append(list(graph[i]))

    def get_node(self):
        self.node_curr = self.state[-1]
        self.node_last = self.state[-2]

    def get_actions_corner(self):
        temp = []
        for i in range(Nodes):
            if(self.g[self.node_curr][i] == 1 and i != self.node_last):
                temp.append(i)
        self.actions = temp

    def get_actions_up(self):
        temp = set()
        for i in range(Nodes):
            for j in range(i):
                if(self.g[i][j] == 1):
                    temp.add(i)
                    temp.add(j)
        self.actions = list(temp)

    def select_action(self, Q_temp, greed_temp):
        if(Q_temp.get(self.state, 0) == 0):
            self.action = rd.choice(self.actions)
        else:
            actions_greed = []
            dict_temp = Q_temp[self.state]
            max_temp = max(dict_temp.values())
            for i in dict_temp:
                if(dict_temp[i] == max_temp):
                    actions_greed.append(i)
            actions_rd = []
            for i in self.actions:
                if(not (i in actions_greed)):
                    actions_rd.append(i)
            if(actions_rd == []):
                self.action = rd.choice(self.actions)
            else:
                if(rd.random() < greed_temp):
                    self.action = rd.choice(actions_greed)
                else:
                    self.action = rd.choice(actions_rd)

    def feedback(self, flag_temp):
        if(self.node_last == -1):
            return 0.0
        v_1 = [Pairs[self.node_curr][0] - Pairs[self.node_last][0], Pairs[self.node_curr][1] - Pairs[self.node_last][1]]
        v_2 = [Pairs[self.action][0] - Pairs[self.node_curr][0], Pairs[self.action][1] - Pairs[self.node_curr][1]]
        temp = (math.pow(v_1[0], 2) + math.pow(v_1[1], 2)) * (math.pow(v_2[0], 2) + math.pow(v_2[1], 2))
        #theta = math.acos((v_1[0] * v_2[0] + v_1[1] * v_2[1]) / math.pow(temp, 0.5))
        cos = (v_1[0] * v_2[0] + v_1[1] * v_2[1]) / math.pow(temp, 0.5)
        feedback_corner = cos * 10
        if(flag_temp == "corner"):
            return feedback_corner
        else:
            dis = math.pow(math.pow(Pairs[self.action][0] - Pairs[self.node_curr][0], 2) + math.pow(Pairs[self.action][1] - Pairs[self.node_curr][1], 2), 0.5)
            feedback_up = -dis * 1
            return feedback_corner * 0.2 + feedback_up

    def move(self):
        self.state += (self.action,)
        self.g[self.node_curr][self.action] = 0
        self.g[self.action][self.node_curr] = 0

    def Qmax(self, Q_temp, state_temp):
        if(Q_temp.get(state_temp, 0) == 0):
            return 0.0
        else:
            return max(Q_temp[state_temp].values())

    def move_plus(self, state_temp):
        self.state = state_temp
        len_temp = len(state_temp)
        for i in range(2,len_temp):
            self.g[state_temp[i]][state_temp[i - 1]] = 0
            self.g[state_temp[i - 1]][state_temp[i]] = 0

#数据输入
def input_data(file_path):
    global G
    global Pairs
    global Nodes
    file_file = open(file_path)
    file_csv = csv.reader(file_file, delimiter=' ')
    for line in file_csv:
        len_temp = len(line)
        if(len_temp == 1):
            Nodes = int(line[0])
            for i in range(Nodes):
                temp = []
                Pairs.append(temp)
                for j in range(Nodes):
                    temp.append(0)
                G.append(temp)
        elif(len_temp == 3):
            Pairs[int(line[0])] = [float(line[1]) + 30, float(line[2]) + 10]
        else:
            G[int(line[0])][int(line[1])] = 1
            G[int(line[1])][int(line[0])] = 1
    file_file.close()

#Q转弯
def Q_corner(state, graph, EPISODE):
    global Nodes
    global Pool
    Q = {}
    GREED = 0.3
    greed_add = (0.9 - GREED) / EPISODE
    if(Pool.get(state, 0) != 0):
        return Pool[state]
    while(EPISODE > 0):
        pri = Printer(state, graph)
        while(True):
            pri.get_node()
            pri.get_actions_corner()
            if(pri.actions == []):
                GREED += greed_add
                if(EPISODE == 2):
                    GREED = 1.0
                break
            pri.select_action(Q, GREED)
            if(Q.get(pri.state, 0) == 0):
                Q[pri.state] = {}
            Q[pri.state][pri.action] = pri.feedback("corner") + pri.Qmax(Q, pri.state + (pri.action,))
            pri.move()
        EPISODE -= 1
    Pool[state] = [pri.state, max(Q[state].values())]
    return Pool[state]

#Q启停
def Q_up(state, graph, feedback_temp, Answers_size):
    global Nodes
    Q = {}
    GREED = 0.3
    EPISODE = 100
    greed_add = (0.9 - GREED) / EPISODE
    time = 0
    Q_plt = []
    while(time < EPISODE):
        jum = Printer(state, graph)
        while(True):
            jum.get_node()
            jum.get_actions_up()
            if(jum.actions == []):
                GREED += greed_add
                if(time == EPISODE - 2):
                    GREED = 1.0
                break
            jum.select_action(Q, GREED)
            temp = Q_corner(jum.state + (jum.action,), jum.g, 200)
            if(Q.get(jum.state, 0) == 0):
                Q[jum.state] = {}
            Q[jum.state][jum.action] = jum.feedback("up")+ temp[1] + jum.Qmax(Q, temp[0])
            jum.move_plus(temp[0])
        Q_plt.append((max(Q[state].values()) if Q.get(state, 0) != 0 else 0) + feedback_temp)      #存储奖励的累计值, 三元运算
        time += 1
    #画图
    #plt.figure()
    #plt.plot(Q_plt)
    #plt.title(Answers_size)
    #plt.show()
    return jum.state, Q_plt[EPISODE - 1]         #返回一次搜寻的结果

#核心搜索函数
def Search(start):
    global G
    global Nodes
    global Pairs
    Answers_state = []
    Answers_q = []
    Answers_size = 50
    while(Answers_size > 0):
        temp = Q_corner((-1,start), G, 2000)
        for i in range(2, len(temp[0])):
            G[temp[0][i]][temp[0][i - 1]] = 0
            G[temp[0][i - 1]][temp[0][i]] = 0
        answer = Q_up(temp[0], G, temp[1], Answers_size)
        Answers_state.append(answer[0])
        Answers_q.append(answer[1])
        Answers_size -= 1
    plt.figure()
    plt.plot(Answers_q)
    plt.show()
    return Answers_state[Answers_q.index(max(Answers_q))]

#输出路线点
def get_path(state, g, layer):
    global Pairs
    route = [1]
    for i in range(len(state) - 1):
        A = state[i]
        B = state[i+1]
        ad(route, Pairs[A])
        route.append(Pairs[B])
        if(g[A][B] == 0):
            Plane[(layer, len(route)-3, len(route)-2)] = 1
        g[A][B] = 0
        g[B][A] = 0
    return route[1:]

def G_copy():
    global G
    g = []
    for i in G:
        g.append(list(i))
    return g

def ad(r, a):
    if(r[-1] != a):
        r.append(a)

def get_dis(a, b):
    temp = math.pow(a[0] - b[0], 2) + math.pow(a[1] - b[1], 2)
    return math.pow(temp, 0.5)

#保留小数位数
def standard():
    global Route
    for i in Route:
        for j in i:
            j[0] = Decimal(j[0]).quantize(Decimal('0.000'))
            j[1] = Decimal(j[1]).quantize(Decimal('0.000'))

#gcode部分
def gcode():
    global Route
    global Plane
    z = 0.2  #层厚
    t1 = 0.0699285714   #内部点的挤出率
    t2 = 0.0758928571   #轮廓点的挤出率
    A = 0
    txt = open('work/mult.gcode', mode='x')
    txt.write('G1 X24' + ' Y10 Z0.5 F300' + '\n')       #打印头从初始位置移动到此位置
    for i in range(18):    #立方体底座
        A += get_dis([i*4 + 24, 20], [i*4 + 24, 80]) * 0.2
        txt.write('G1 X' + str(i*4+24) + ' Y70 Z0.5 F1000 A' + str(Decimal(A).quantize(Decimal('0.00000'))) + '\n')
        A += get_dis([i*4 + 24, 80], [i*4 + 26, 80]) * 0.2
        txt.write('G1 X' + str(i*4+26) + ' Y70 Z0.5 F300 A' + str(Decimal(A).quantize(Decimal('0.00000'))) + '\n')
        A += get_dis([i*4 + 26, 80], [i*4 + 26, 20]) * 0.2
        txt.write('G1 X' + str(i*4+26) + ' Y10 Z0.5 F1000 A' + str(Decimal(A).quantize(Decimal('0.00000'))) + '\n')
        A += get_dis([i*4 + 26, 20], [i*4 + 28, 20]) * 0.2
        txt.write('G1 X' + str(i*4+28) + ' Y10 Z0.5 F300 A' + str(Decimal(A).quantize(Decimal('0.00000'))) + '\n')
    txt.write('G1 X' + str(Route[0][0][0]) + ' Y' + str(Route[0][0][1]) + ' Z0.5 F9000;travel move' + '\n')   #移动到第一个点
    for i in range(len(Route)):       #z层厚 t挤出率
        Z = Decimal(0.7+i*z).quantize(Decimal('0.000'))
        #txt.write('layer:' + str(i) + '\n')
        txt.write('M73 P' + str(Decimal((i*100) / len(Route)).quantize(Decimal('0.000'))) + '\n')
        #路线点
        for j in range(1, len(Route[i]), 1):
            if(Plane.get((i, j - 1, j), 0) == 0 ):
                A += get_dis(Route[i][j - 1], Route[i][j]) * t1
                txt.write('G1 X' + str(Route[i][j][0]) + ' Y' + str(Route[i][j][1]) + ' Z' + str(Z) + ' F4200' + ' A' + str(Decimal(A).quantize(Decimal('0.00000'))) + ';infill' + '\n')
            else:
                txt.write('G1 X' + str(Route[i][j][0]) + ' Y' + str(Route[i][j][1]) + ' Z' + str(Z) + ' F9000;travel move' + '\n')
                print(i,' ',"Plane：",j - 1,'  ',j)            #############
    txt.close()

#主函数
Start = 0
Route = []
Plane = {}
for i in range(1):
    print("当前是第",i,"层")
    G = []
    Pool = {}
    Pairs = []
    Nodes = 0
    input_data("data/data77913/test6.csv")
    g = G_copy()
    state = Search(Start)[1:]
    Route.append(get_path(state, g, i))
    Start = state[-1]

#保留小数位数
#生成gcode
standard()
gcode()


#!/usr/bin/python

import os
import stat
import re
import string
from xmllib import *

class TopicExtractor(XMLParser):
	def __init__(self, defaultTopic):
		XMLParser.__init__(self)
		self.topic=defaultTopic
		self.processingTopic=0

	def start_topic(self, attrs):
		self.processingTopic=1
		self.topic=self.topic+" - "

	def end_topic(self):
		self.processingTopic=0

	def get_topic(self):
		return self.topic

	def handle_data(self, data):
		if self.processingTopic:
			self.topic=self.topic+data

class Indexer:
	def __init__(self, tDir):
		self.theDict={}
		self.topDir=tDir
		self.depth=0
		self.files={}

	def process(self):
		self.processAux("")

	def compoundDir(self, tDir, stub):
		if stub == "":
			return tDir
		elif tDir == "":
			return stub
		else:
			return tDir+os.sep+stub

	def handleXML(self, theDir, dfrag, fname):
		self.files[self.depth].append(self.compoundDir(dfrag,fname))
		self.theDict[theDir]['xml'].append(fname)

	def handleBinary(self, theDir, fname):
		self.theDict[theDir]['bin'].append(fname)

	def handleDir(self, theDir, fname):
		self.theDict[theDir]['dir'].append(fname)

	def processAux(self, dFrag):
		self.depth=self.depth+1
		if not self.files.has_key(self.depth):
			self.files[self.depth]=[]
		thisDir=self.compoundDir(self.topDir, dFrag)
		os.chdir(thisDir)
		self.theDict[thisDir]={'xml': [], 'bin': [], 'dir': []}
		# print "Processing",thisDir," Depth",self.depth
		thisDirContents=os.listdir(thisDir)
		for fname in thisDirContents:
			if stat.S_ISDIR(os.stat(fname)[stat.ST_MODE]):
				if not re.match("^(CVS|images|search|photos|htdig|\.)", fname) and self.depth<4:
					self.processAux(self.compoundDir(dFrag,fname))
					self.handleDir(thisDir, fname)
					os.chdir(thisDir)
			else:
				# print "File",fname
				if re.match(".*\.xml$", fname):
					self.handleXML(thisDir, dFrag, fname)
				elif re.match(".*\.(jpe?g|JPG|gif|png|html)$",
							  fname):
					self.handleBinary(thisDir, fname)

		self.writeIndex(dFrag)
		self.depth=self.depth-1

	def grabTopic(self, dir, f, deftopic):
		xt=TopicExtractor(deftopic)
		fh=open("%s/%s" % (dir, f), "r")
		xt.feed(fh.read())
		fh.close()
		return xt.get_topic()

	def writeIndex(self,dFrag):
		thisDir=self.compoundDir(self.topDir, dFrag)
		if self.depth==3:
			# for each day link to that day
			mh=open("index.xml", "w")
			mh.write("<?xml version='1.0' encoding='iso-8859-1'?>\n")
			mh.write("<!DOCTYPE month>\n")
			mh.write("<month name=\"%s\">\n" % (dFrag))
			self.theDict[thisDir]['dir'].sort()
			for d in self.theDict[thisDir]['dir']:
				nd=self.compoundDir(thisDir, d)
				for f in self.theDict[nd]['xml']:
					topic=self.grabTopic(nd, f, d)
					mh.write("<day href=\"/%s/%s/%s\">" % \
									 (dFrag, d,	string.replace(f, "xml", "html")) \
									 + topic + "</day>\n")
			mh.write("</month>\n")
			mh.close()
		elif self.depth==2:
			mh=open("index.xml", "w")
			mh.write("<?xml version='1.0' encoding='iso-8859-1'?>\n")
			mh.write("<!DOCTYPE year>\n")
			mh.write( "<year name=\"%s\">\n" % (dFrag))
			for d in self.theDict[thisDir]['dir']:
				mh.write( "<month href=\"/%s/%s/index.html\">" % \
									(dFrag, d) + d + "</month>\n")
			mh.write("</year>\n")
			mh.close()
		elif self.depth==1:
			mh=open("nav.xml", "w")
			mh.write("<?xml version='1.0' encoding='iso-8859-1'?>\n")
			mh.write("<!DOCTYPE nav>\n<nav>\n")
			l=m.files[4]
			l.sort( lambda x, y: cmp(y, x) )
			for j in l[0:4]:
				mh.write( "<recent href=\"/%s\">%s</recent>\n" % \
							(string.replace(j, "xml", "html"),
							 j[0:(string.rfind(j, os.sep))]))

			self.theDict[thisDir]['dir'].sort( lambda x, y: cmp(y, x) )
			for d in self.theDict[thisDir]['dir']:
				mh.write("<year name=\"%s\">\n" % (d))
				nd=self.compoundDir(thisDir, d)
				self.theDict[nd]['dir'].sort( lambda x, y: cmp(y, x) )
				for f in self.theDict[nd]['dir']:
					mh.write( "<month href=\"/%s/%s/index.html\">" % (d, f) + d + \
										"/" + f	+ "</month>\n")
				mh.write( "</year>\n")
			mh.write("</nav>\n")
			mh.close()

if __name__ == '__main__':
	m=Indexer("/home/pants/public_html")
	m.process()


import logging
import pytest
from selenium.webdriver import Chrome, Firefox

from Utils.Helpers import Helpers
from Utils.config_reader import read_config_file
from Utils.constant import CONFIG_BROWSER, CONFIG_WAIT_TIME, CONFIG_CHROME_DRIVER_PATH
from Utils.folder_structure_builder import FolderStructureBuilder
from Utils.log_helper import LogHelper

DEFAULT_WAIT_TIME = 10
SUPPORTED_BROWSERS = ['chrome', 'firefox']

folder = FolderStructureBuilder()
folder.build_folder_structure()
logging = LogHelper.setup_logs()

@pytest.fixture(scope='session')
def read_config():
    return read_config_file()

@pytest.fixture(scope='session')
def config_browser(read_config):
    if CONFIG_BROWSER not in read_config:
        raise Exception('The config file doesnt contain "browser"')
    elif read_config[CONFIG_BROWSER] not in SUPPORTED_BROWSERS:
        raise Exception(f'"{read_config[CONFIG_BROWSER]}" is not supported')
    return read_config[CONFIG_BROWSER]

@pytest.fixture(scope='session')
def config_chrome_driver_path(read_config):
    if CONFIG_CHROME_DRIVER_PATH not in read_config:
        raise Exception('The config file doesnt contain the chromedriver path')
    else:
        return read_config[CONFIG_CHROME_DRIVER_PATH]

@pytest.fixture(scope='session')
def config_wait_time(read_config):
    return read_config[CONFIG_WAIT_TIME] if CONFIG_WAIT_TIME in read_config else DEFAULT_WAIT_TIME

@pytest.fixture(scope='session')
def browser(config_browser, config_chrome_driver_path, config_wait_time):
    if config_browser == 'chrome':
        driver = Chrome(config_chrome_driver_path)
    elif config_browser == 'firefox':
        driver = Firefox()
    else:
        raise Exception(f'"{read_config[CONFIG_BROWSER]}" is not supported')
    driver.implicitly_wait(config_wait_time)
    yield driver
    driver.quit()

@pytest.mark.tryfirst
def pytest_runtest_makereport(item, call, __multicall__):
    rep = __multicall__.execute()
    setattr(item, "rep_" + rep.when, rep)
    return rep

@pytest.fixture(scope='function', autouse=True)
def before_after_each_test(request, browser):
    logging.info(f'executing {request.node.name}')
    yield
    if request.node.rep_call.passed:
        Helpers.take_screenshot(browser, request.node.name)
        logging.info(f'Test Pass => {request.node.name}')
    elif request.node.rep_call.failed:
        yield
        logging.info(f'Test Failed => {request.node.name}')

@pytest.fixture(scope='class', autouse=True)
def before_after_each_class(request):
    module_name = request.module.__name__
    logging.info(f'==== Executing test in {module_name} class ====')
    yield
    logging.info(f'==== Completed executing test in {module_name} class ====')


#!/usr/bin/python3

import subprocess
import signal
import os

def kill_proc(pid):
    print("kill %d" % pid)
    # Kill process.
    os.kill(pid, signal.SIGTERM)

def close_flux():
    ps_str = subprocess.check_output(["ps", "aux"])
    ps_str = ps_str.decode()
    proc_list = ps_str.split('\n')
    flux_line = ''
    for l in proc_list:
        if "xflux" in l:
            flux_line = l
    if len(flux_line) > 0:
        flux_pid = int(flux_line.split()[1])
        print("flux_pid=%d" % flux_pid)
        kill_proc(flux_pid)

if __name__ == "__main__":
    close_flux()


# -*- coding: utf-8 -*-
"""
Created on Wed Mar 27 11:15:05 2019

@author: Dang Nhat Le

Unsupervising Assignment: Mobile App
"""

###############################################################################
# Importing, splitting data
###############################################################################

# Importing known libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Importing new libraries
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# import dataset
mob_app = pd.read_excel('finalExam_preparation_data.xlsx')

# Exploring datase
mob_app.describe()
mob_app.info()
mob_app.columns
mob_app.shape

###############################################################################
# PCA Method
###############################################################################

###############################################
# Step 1: Remove non-demographic data
###############################################
mob_app_drop = mob_app.iloc[:, 2:36]

mob_app_factors = mob_app_drop.drop(['q2r10'], axis = 1)    # thí há only value 0, then I terminate this column

"""
I also drop question 24, 25, and 26 since those question are like self evaluation.
"""

###############################################
# Step 2: Scale all new variables to equal variance
###############################################

scaler_mob = StandardScaler()

scaler_mob.fit(mob_app_factors)

MOB_Scaled = scaler_mob.transform(mob_app_factors)

########################
# Step 3: Run PCA without limiting the number of components
########################

mob_app_pca = PCA(n_components = None,
                           random_state = 508)

mob_app_pca.fit(MOB_Scaled)

PCA_Mob = mob_app_pca.transform(MOB_Scaled)

########################
# Step 4: Analyze the scree plot to determine how many components to retain
########################

fig, ax = plt.subplots(figsize=(10, 8))

features = range(mob_app_pca.n_components_)

plt.plot(features,
         mob_app_pca.explained_variance_ratio_,
         linewidth = 2,
         marker = 'o',
         markersize = 10,
         markeredgecolor = 'black',
         markerfacecolor = 'grey')

plt.title('Mobile Apps Survey Scree Plot')
plt.xlabel('PCA feature')
plt.ylabel('Explained Variance')
plt.xticks(features)
plt.show()

"""
Dang Le:
    I will choose only 5 components on the left side because their distance is
    far and easy to be explained while the rest on the right side is very closed
    indicating that their differences are not far; in other words, they are very
    similar.
"""

########################
# Step 5: Run PCA again based on the desired number of components
########################

PCA_Mob_New = PCA(n_components = 3,
                           random_state = 508)

PCA_Mob_New.fit(MOB_Scaled)

########################
# Step 6: Analyze factor loadings to understand principal components
########################

factor_mob_df = pd.DataFrame(pd.np.transpose(PCA_Mob_New.components_))

FACTOR_mob_df = factor_mob_df.set_index(mob_app_factors.columns[:]).round(3)

print(FACTOR_mob_df)

########################
# Step 7: Analyze factor strengths per survey taker
########################

MOB_pca_df = pd.DataFrame(PCA_Mob_New.transform(MOB_Scaled))

"""
Dataframe above shows how each survey taker responses to each component (group).
"""

########################
# Step 8: Rename your principal components and reattach demographic information
########################

MOB_pca_df.columns = ['seg 1',
                            'seg 2',
                            'seg 3']

final_pca_mob_df = pd.concat([mob_app.loc[ : , ['caseID', 'q1',
                                                'q48', 'q49',
                                                'q54', 'q56']],
                                              MOB_pca_df], axis = 1)

# Setting name for demographic informations
final_pca_mob_df = final_pca_mob_df.rename(index=str, columns = {'q1':'age',
                                                      'q48':'edu',
                                                      'q49':'status',
                                                      'q54':'race',
                                                      'q56':'income'})

"""
I will not reuse the question 50 since it has multiple columns; In addition,
    gender, children and hispanic/latino information will not be used. Because"
    Children has multiple columns and not neccessary.
    Hispanic could be included in race column as other race.
    Gender should not be a big matter for developing an app.

"""

# Renaming ages
age_names = {1 : 'Un 18',
                 2 : '18-24',
                 3 : '25-29',
                 4 : '30-34',
                 5 : '35-39',
                 6 : '40-44',
                 7 : '45-49',
                 8 : '50-54',
                 9 : '55-59',
                 10 : '60-64',
                 11 : '65&over'}

final_pca_mob_df['age'].replace(age_names, inplace = True)

# Renaming eduation column
edu_names = {1 : 'higschl',
                 2 : 'highschlgrad',
                 3 : 'college',
                 4 : 'collgrad',
                 5 : 'pgradstudy',
                 6 : 'pgraddegree'}

final_pca_mob_df['edu'].replace(edu_names, inplace = True)

# Renaming maritial status
sta_names = {1 : 'married',
                 2 : 'single',
                 3 : 'sig-partner',
                 4 : 'wid/divor'}

final_pca_mob_df['status'].replace(sta_names, inplace = True)

# Renaming race
race_names = {1 : 'White',
                 2 : 'Black',
                 3 : 'Asian',
                 4 : 'hawai/OPI',
                 5 : 'AmIndian',
                 6 : 'Other'}

final_pca_mob_df['race'].replace(race_names, inplace = True)

# Renaming income
income_names = {1 : '<10k',
                 2 : '10-14',
                 3 : '15-19',
                 4 : '20-29',
                 5 : '30-39',
                 6 : '40-49',
                 7 : '50-59',
                 8 : '60-69',
                 9 : '70-79',
                 10 : '80-89',
                 11 : '90-99',
                 12 : '100-124',
                 13 : '125-149',
                 14 : '>150k'}

final_pca_mob_df['income'].replace(income_names, inplace = True)

#########################
# Analyzing team 1
#########################

# Analyzing age
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'age',
            y =  'seg 1',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing status
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'status',
            y =  'seg 1',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing education
fig, ax = plt.subplots(figsize = (8, 6))
sns.boxplot(x = 'edu',
            y =  'seg 1',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing race
fig, ax = plt.subplots(figsize = (8, 6))
sns.boxplot(x = 'race',
            y =  'seg 1',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing income
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'income',
            y =  'seg 1',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

#########################
# Analyzing team 2
#########################

# Analyzing age
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'age',
            y =  'seg 2',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing status
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'status',
            y =  'seg 2',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing education
fig, ax = plt.subplots(figsize = (8, 6))
sns.boxplot(x = 'edu',
            y =  'seg 2',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing race
fig, ax = plt.subplots(figsize = (8, 6))
sns.boxplot(x = 'race',
            y =  'seg 2',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing income
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'income',
            y =  'seg 2',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

#########################
# Analyzing team 3
#########################

# Analyzing age
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'age',
            y =  'seg 3',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing status
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'status',
            y =  'seg 3',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing education
fig, ax = plt.subplots(figsize = (8, 6))
sns.boxplot(x = 'edu',
            y =  'seg 3',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing race
fig, ax = plt.subplots(figsize = (8, 6))
sns.boxplot(x = 'race',
            y =  'seg 3',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()

# Analyzing income
fig, ax = plt.subplots(figsize = (8, 4))
sns.boxplot(x = 'income',
            y =  'seg 3',
            data = final_pca_mob_df)

plt.ylim(-10, 9)
plt.tight_layout()
plt.show()


import inspect
from abc import ABC, abstractmethod
from typing import Callable, Iterable, NamedTuple

from ..engine import Edge, FunctionEdge, ImpureEdge
from ..exceptions import FieldError
from .decorators import RuntimeAnnotation
from .nodes import *
from .utils import replace_annotation

__all__ = (
    'TypedEdge', 'EdgeFactory',
    'Function', 'FunctionWrapper', 'FunctionBase',
    'Inverse', 'inverse', 'Impure', 'impure', 'Positional', 'positional'
)

class TypedEdge(NamedTuple):
    edge: Edge
    inputs: NodeTypes
    output: NodeType

class EdgeFactory(ABC):
    @abstractmethod
    def build(self, name: str) -> Iterable[TypedEdge]:
        """ Returns an iterable of edges that represent the factory's logic """

class FunctionBase(EdgeFactory, ABC):
    @staticmethod
    def _process_annotation(annotation, name, is_positional):
        # detect the node type
        if isinstance(annotation, NodeType):
            raise ValueError(f'Invalid argument "{name}" annotation ({annotation})')

        if is_positional:
            return AsOutput()
        # need the `isinstance` part for faulty annotations, such as np.array
        elif isinstance(annotation, type) and issubclass(annotation, NodeType):
            return annotation(name)
        elif is_private(name):
            return Parameter(name)

        return Default(name)

    @classmethod
    def extract_arguments(cls, func: Callable):
        signature = list(inspect.signature(func).parameters.values())
        args = []
        for idx, parameter in enumerate(signature):
            if parameter.default != parameter.empty:
                raise ValueError(
                    f'Function {func} has a default value for parameter {parameter.name}. '
                    'Default parameters are currently not supported.'
                )

            is_positional = idx == 0 and parameter.kind == parameter.POSITIONAL_ONLY
            if not is_positional and parameter.kind != parameter.POSITIONAL_OR_KEYWORD:
                raise TypeError(
                    f'The parameter "{parameter.name}" must be "positional or keyword", '
                    f'not {parameter.kind.name.lower()}'
                )

            args.append(replace_annotation(
                cls._process_annotation, parameter.annotation, parameter.name, is_positional
            ))

        return args

class Function(FunctionBase):
    func: Callable
    args: tuple
    kwargs: dict

    def __init__(*args, **kwargs):
        assert args
        assert len(args) >= 2
        self, func, *args = args
        assert callable(func)

        self.func = func
        self.args = tuple(args)
        self.kwargs = kwargs

    def build(self, name: str) -> Iterable[TypedEdge]:
        kwargs = sorted(self.kwargs.items())
        args = self.args + tuple(x[1] for x in kwargs)
        names = tuple(x[0] for x in kwargs)

        silent, inputs = [], []
        for idx, arg in enumerate(args):
            if isinstance(arg, Silent):
                silent.append(idx)
                arg = arg.node
            if isinstance(arg, str):
                arg = Default(arg)
            if not isinstance(arg, NodeType):
                raise ValueError(arg)
            if isinstance(arg, AsOutput):
                arg = Default(name)

            inputs.append(arg)

        yield TypedEdge(
            FunctionEdge(self.func, len(inputs), names, tuple(silent)),
            inputs, Default(name),
        )

    @classmethod
    def decorate(cls, func: Union[Callable, FunctionBase]) -> 'Function':
        if isinstance(func, RuntimeAnnotation):
            raise ValueError(f'The decorator of type {type(func)} must be at the top')
        return cls(func, *cls.extract_arguments(func))

class FunctionWrapper(FunctionBase, ABC):
    function: FunctionBase

    def __init__(*args, **kwargs):
        assert args
        assert len(args) >= 2
        self, func, *args = args
        if isinstance(func, EdgeFactory):
            assert not args
            assert not kwargs
        else:
            func = Function(func, *args, **kwargs)

        self.function = func

    @classmethod
    def decorate(cls, instance: Union[Callable, EdgeFactory]) -> 'FunctionWrapper':
        if not isinstance(instance, EdgeFactory):
            instance = Function.decorate(instance)
        return cls(instance)

    def build(self, name: str) -> Iterable[TypedEdge]:
        edge, = self.function.build(name)
        yield from self._wrap(*edge)

    @abstractmethod
    def _wrap(self, edge: Edge, inputs: NodeTypes, output: NodeType) -> Iterable[TypedEdge]:
        pass

class Inverse(FunctionWrapper):
    def _wrap(self, edge: Edge, inputs: NodeTypes, output: NodeType) -> Iterable[TypedEdge]:
        if isinstance(output, Default):
            output = InverseOutput(output.name)
        if not isinstance(output, InverseOutput):
            raise FieldError(f"The function can't be inverted, because its output is already of type {type(output)}")

        inputs = [
            replace_annotation(lambda a: InverseInput(a.name) if isinstance(a, Default) else a, x)
            for x in inputs
        ]
        yield TypedEdge(edge, inputs, output)

class Positional(FunctionWrapper):
    r"""
    Marks the first argument as positional.

    Can be used as an alternative to
    >>> def f(x, \, y):
    >>>     ...
    for older versions of Python.
    """

    def __init__(*args, **kwargs):
        assert args
        self, *args = args
        assert len(args) >= 1
        self._not_a_function(args[0])
        super(Positional, self).__init__(*args, **kwargs)

    @staticmethod
    def _not_a_function(func):
        if isinstance(func, EdgeFactory):
            raise TypeError(
                '"positional" can be used only for functions. '
                'If it is in a chain of decorators - it must be the lowest one'
            )

    @classmethod
    def decorate(cls, instance: Callable) -> 'FunctionWrapper':
        cls._not_a_function(instance)
        return cls(instance, *cls.extract_arguments(instance))

    def _wrap(self, edge: Edge, inputs: NodeTypes, output: NodeType) -> Iterable[TypedEdge]:
        if not inputs:
            raise ValueError('The "positional" can\'t be used with a function without arguments')

        inputs = [replace_annotation(lambda a: Default(output.name), inputs[0]), *inputs[1:]]
        yield TypedEdge(edge, inputs, output)

class Impure(FunctionWrapper):
    def _wrap(self, edge: Edge, inputs: NodeTypes, output: NodeType) -> Iterable[TypedEdge]:
        yield TypedEdge(ImpureEdge(edge), inputs, output)

inverse, positional, impure = Inverse.decorate, Positional.decorate, Impure.decorate


"""
Read and write swarm data
"""
import os
import numpy as np
import xarray as xr
import pandas as pd

from .utils import _read_parameters, _read_times, PARAMETERS_FILE

SWARM_BASENAME = "step_"

def read_mandyoc_swarm(path, parameters_file=PARAMETERS_FILE):
    """
    Read swarm files generated by MANDYOC and return the positions of the particles
    in time

    Parameters
    ----------
    path : str
        Path to the folder where the MANDYOC output files are located.
    parameters_file : str (optional)
        Name of the parameters file. It must be located inside the ``path`` directory.
        Default to ``"param_1.5.3.txt"``.

    Returns
    -------
    swarm : :class:`pandas.DataFrame`
        DataFrame containing the particles positions for every time step. The positions
        of the particles are given by ``x``, ``y`` and ``z`` in meters. The ``cc0`` is
        the number assigned to each particle belonging to a finite element. The ``time``
        is given in Ma. The index of the :class:`pandas.DataFrame` correspond to the
        step number.
    """
    # Determine the number of time steps and dimension of data
    parameters = _read_parameters(os.path.join(path, parameters_file))
    dimension = len(parameters["shape"])
    print_step = parameters["print_step"]
    max_steps = parameters["stepMAX"]
    steps, times = _read_times(path, print_step, max_steps)
    # Get swarm files
    swarm_files = [i for i in os.listdir(path) if SWARM_BASENAME in i]
    # Initialize the list of dataframes that will be concatenated
    dataframes = []
    # Read the data
    for i, (step, time) in enumerate(zip(steps, times)):
        # Determine the rank value on the first step and check it for following steps
        step_files = [
            i for i in swarm_files if "{}{}-".format(SWARM_BASENAME, step) in i
        ]
        if i == 0:
            n_rank = len(step_files)
        else:
            if len(step_files) != n_rank:
                raise ValueError(
                    "Invalid number of ranks '{}' for step '{}'".format(
                        len(step_files), step
                    )
                )
        # Read particles positions for the current step
        dataframes.append(
            _read_mandyoc_single_swarm(path, step, time, n_rank, dimension)
        )
    # Concatenate the dataframes
    swarm = pd.concat(dataframes)
    return swarm

def _read_mandyoc_single_swarm(path, step, time, n_rank, dimension):
    """
    Read swarm positions for a single time step from MANDYOC output files
    """
    x, y, z, cc0 = tuple(np.array([]) for i in range(4))
    for rank_i in range(n_rank):
        filename = "{}{}-rank_new{}.txt".format(SWARM_BASENAME, step, rank_i)
        if dimension == 2:
            x_rank, z_rank, cc0_rank = np.loadtxt(
                os.path.join(path, filename), unpack=True, usecols=(0, 1, 2)
            )
        elif dimension == 3:
            x_rank, y_rank, z_rank, cc0_rank = np.loadtxt(
                os.path.join(path, filename), unpack=True, usecols=(0, 1, 2, 3)
            )
        # Stack arrays in sequence horizontally
        cc0 = np.hstack((cc0, cc0_rank))
        x = np.hstack((x, x_rank))
        z = np.hstack((z, z_rank))
        if dimension == 3:
            y = np.hstack((y, y_rank))
    # Create a data frame for the current step
    data = {"x": x, "z": z, "cc0": cc0, "time": time}
    if dimension == 3:
        data["y"] = y
    df = pd.DataFrame(data=data, index=np.full_like(x, step, dtype=int))
    return df


from src.data import constants
from src.data.constants import Currency
from src.data.data_loader import DataLoader
from typing import List, Tuple, Union, NoReturn
from plotly.subplots import make_subplots
from dataclasses import dataclass, field

import plotly.graph_objects as go
import numpy as np
import dask.dataframe as dd
import logging
from datetime import datetime

log = logging.getLogger("Line plotter")

freq2label = {
    "D": "Daily",
    "H": "Hourly",
    "T": "Per Minute",
    "S": "Per Second"
}

@dataclass
class PlotCurrencyPair:
    base: Currency
    quote: Currency
    var: str
    freqs: List[Union[str, None]] = field(default_factory=lambda: ['D', 'H'])
    path: str = "data/raw/"

    def prepare_dataframes(self, df: dd.DataFrame) -> dd.DataFrame:
        dfs = []
        for freq in self.freqs:
            if freq in ['D', 'H', 'T', 'S']:
                log.debug(f"Resampling dataframe averaging each {freq}")
                df_processed = df.resample(freq).mean()
                dfs.append(df_processed)
            elif freq == None:
                log.debug("No resampling is also included.")
                dfs.append(df)
            else:
                raise NotImplementedError("This aggregation timeframe is not "
                                          "yet implemented")

        return dfs

    def show_dataframes(self, dfs: List[dd.DataFrame]) -> NoReturn:
        fig = make_subplots(
            rows=len(self.freqs), cols=1, shared_xaxes=True,
            subplot_titles=[constants.var2label[self.var].capitalize()] + \
                [""] * len(self.freqs[:-1]),
            vertical_spacing=0.12)
        fig.update_annotations(font_size=20)

        for i, df in enumerate(dfs, start=1):
            label = freq2label[self.freqs[i-1]] if self.freqs[i-1] else "No"
            fig.add_trace(
                go.Scatter(
                    x=df.index, y=df[self.var],
                    mode='lines',
                    name=label),
                row=i, col=1)
        fig.update_layout(
            title={
                'text': f"{self.base.value}/{self.quote.value}",
                "x": 0.1,
                "y": 0.95,
                "xanchor": "center",
                "yanchor": "top"
            },
            legend_title="Average",
            font=dict(family="Courier New, monospace", size=18)
        )
        fig.update_yaxes(title_text=self.quote.value,
                        title_font={"family": "Courier New, monospace", "size": 20},
                        title_standoff = 20)
        fig.update_xaxes(title_text="Date",
                        title_font={"family": "Courier New, monospace", "size": 20},
                        title_standoff = 15)
        fig.show()

    def run(
        self,
        period: Tuple[Union[str, datetime],
                      Union[str, datetime]] = None
    ) -> Tuple[np.array, List[str]]:
        # Get the data
        dl = DataLoader(self.base, self.quote, self.path)
        df_mid = dl.read(period)
        dfs = self.prepare_dataframes(df_mid)
        log.info(f"Data is prepared to be shown.")

        # Plot images
        self.show_dataframes(dfs)


import torch, torchdata, torchtext
from torch import nn
import torch.nn.functional as F
from pythainlp.tokenize import word_tokenize
import random, math, time
from datasets import load_dataset

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# print(device)

#make our work comparable if restarted the kernel
SEED = 1234
torch.manual_seed(SEED)
torch.backends.cudnn.deterministic = True

class MultiHeadAttentionLayer(nn.Module):
    def __init__(self, hid_dim, n_heads, dropout, device):
        super().__init__()
        self.hid_dim = hid_dim
        self.n_heads = n_heads
        self.head_dim = hid_dim // n_heads #make sure it's divisible....

        self.fc_q = nn.Linear(hid_dim,hid_dim)
        self.fc_k = nn.Linear(hid_dim,hid_dim)
        self.fc_v = nn.Linear(hid_dim,hid_dim)

        self.fc = nn.Linear(hid_dim, hid_dim)

        self.dropout = nn.Dropout(dropout)
        self.scale = torch.sqrt(torch.FloatTensor([self.head_dim])).to(device)

    def forward(self, q, k, v, mask = None):
        batch_size = q.shape[0]

        Q = self.fc_q(q)
        K = self.fc_k(k)
        V = self.fc_v(v)

        #Q, K, V = [b, l, h]
        #reshape them into head_dim
        #reshape them to [b, n_headm, l, head_dim]

        Q = Q.view(batch_size, -1, self.n_heads, self.head_dim).permute(0,2,1,3)
        K = K.view(batch_size, -1, self.n_heads, self.head_dim).permute(0,2,1,3)
        V = V.view(batch_size, -1, self.n_heads, self.head_dim).permute(0,2,1,3)
        #Q, K, V = [b, m_head, l, head_dim]

        #e = QK/sqrt(dk)
        e =  torch.matmul(Q, K.permute(0,1,3,2)) / self.scale
        #e = [b, n_heads, ql, kl]

        # torch.Size([64, 8, 50, 50])
        # torch.Size([64, 1, 1, 50, 256])

        if mask is not None:
            e = e.masked_fill(mask == 0, -1e10)

        a = torch.softmax(e, dim=-1)
        #a = [batch size, n_heads, ql, kl]

        #eV
        x = torch.matmul(self.dropout(a),V)
        #x : [b, n_heads, ql, head_di]

        x = x.permute(0, 2, 1, 3).contiguous()
        #x: [b, ql, n_heads, head_dim]

        #concat them together
        x = x.view(batch_size, -1, self.hid_dim)
        #x = [b, ql, h]

        x = self.fc(x)
        #x = [b, ql, h]

        return x, a

class PositionwiseFeedforwardLayer(nn.Module):

    def __init__(self, hid_dim, pf_dim, dropout):
        super().__init__()
        self.fc1 = nn.Linear(hid_dim, pf_dim)
        self.fc2 = nn.Linear(pf_dim, hid_dim)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        return self.fc2(self.dropout(torch.relu(self.fc1(x))))

class Decoder(nn.Module):
    def __init__(self, output_dim, hid_dim, n_layers, n_heads,
                 pf_dim, dropout, device, src_pad_idx,trg_pad_idx, max_length = 100):
        super().__init__()
        self.pos_emb = nn.Embedding(max_length, hid_dim)
        self.trg_emb = nn.Embedding(output_dim, hid_dim)
        self.scale = torch.sqrt(torch.FloatTensor([hid_dim])).to(device)
        self.dropout = nn.Dropout(dropout)
        self.layers = nn.ModuleList(
                            [
                            DecoderLayer(hid_dim, n_heads, pf_dim, dropout, device)
                            for _ in range(n_layers)
                            ]
                            )
        self.fc = nn.Linear(hid_dim, output_dim)
        self.device = device

        self.src_pad_idx = src_pad_idx
        self.trg_pad_idx = trg_pad_idx

    def make_src_mask(self, src):
        #src = [batch size, src len]
        src_mask = (src != self.src_pad_idx).unsqueeze(1).unsqueeze(2)
        #src_mask = [batch size, 1, 1, src len]
        return src_mask

    def make_trg_mask(self, trg):
        trg_mask = (trg != self.trg_pad_idx).unsqueeze(1).unsqueeze(2)
        #trg_mask : [batch size, 1, 1, trg len]

        trg_len = trg_mask.shape[-1]

        trg_sub_mask = torch.tril(torch.ones((trg_len, trg_len), device =self.device)).bool() #lower triangle
        #trg_sub_mask = [trg len, trg len]
        trg_mask = trg_mask & trg_sub_mask
        #trg_mask : [batch size, 1, trg len, trg len]
        return trg_mask
    def decode(self, trg, method='beam-search'):

        if method == 'beam-search':
            return self.beam_decode(trg)
        else:
            return self.greedy_decode(trg)
    def greedy_decode(self, trg): # Get the best prop? maybe

        prediction= self.forward(trg)
        prediction = prediction.squeeze(0)
        prediction = prediction.argmax(1)

        return prediction
    def forward(self, x):
        #src : = [batch size, trg len]
        #enc_src : hidden state from encoder = [batch size, src len, hid dim]
        #trg_mask = [batch size, 1, trg len, trg len]
        #src_mask = [batch size, 1, 1, src len]

        batch_size = x.shape[0]
        trg_len = x.shape[1]

        src_mask = self.make_trg_mask(x)

        #pos
        pos = torch.arange(0,trg_len).unsqueeze(0).repeat(batch_size, 1).to(self.device)
        #pos = [batch size, trg len]

        pos_emb = self.pos_emb(pos) #[batch size, trg len, hid dim]
        trg_emb = self.trg_emb(x) #[batch size, trg len, hid dim]

        x = pos_emb + trg_emb * self.scale #[batch size, trg len, hid dim]
        x = self.dropout(x)

        for layer in self.layers: #output, hidden
            trg, attention = layer(x, src_mask)
        #trg = [batch size, trg len, hid dim]
        #attention = [batch size, n heads, trg len, src len]

        output = self.fc(trg)
        #output = [batch size, trg len, output dim]

        return output, attention

class DecoderLayer(nn.Module):
    def __init__(self, hid_dim, n_heads, pf_dim, dropout, device):
        super().__init__()

        self.norm_ff = nn.LayerNorm(hid_dim) #second yellow box
        self.norm_maskedatt = nn.LayerNorm(hid_dim) #first red box

        self.self_attention = MultiHeadAttentionLayer(hid_dim, n_heads, dropout, device)
        self.ff = PositionwiseFeedforwardLayer(hid_dim, pf_dim, dropout)
        self.dropout = nn.Dropout(dropout)

    def forward(self, trg, trg_mask):
        #trg      : [b, l, h]
        #enc_src  : [b, sl, h]
        #trg_mask : [b, 1, tl, tl]
        #src_mask : [b, 1, 1, sl]

        #1st box : mask multi, add & norm
        _trg, attention = self.self_attention(trg, trg, trg, trg_mask) #Q, K, V
        _trg    = self.dropout(_trg)
        _trg    = trg + _trg
        trg     = self.norm_maskedatt(_trg)

        #2rd box : ff, add & norm
        _trg    = self.ff(trg)
        _trg    = self.dropout(_trg)
        _trg    = trg + _trg
        trg     = self.norm_ff(_trg)

        return trg, attention

def initialize_weights(m):
    if hasattr(m, 'weight') and m.weight.dim() > 1:
        nn.init.xavier_uniform_(m.weight.data)
def generate(prompt, max_seq_len, temperature, model, tokenizer, vocab, device, seed=None):
    if seed is not None:
        torch.manual_seed(seed)
    model.eval()
    tokens = tokenizer(prompt)
    indices = [vocab[t] for t in tokens]
    batch_size = 1
    # hidden = model.init_hidden(batch_size, device)
    with torch.no_grad():
        for i in range(max_seq_len):
            src = torch.LongTensor([indices]).to(device)
            prediction, hidden = model(src)

            # print(prediction.shape)
            #prediction: [batch size, seq len, vocab size]
            #prediction[:, -1]: [batch size, vocab size] #probability of last vocab

            probs = torch.softmax(prediction[:, -1] / temperature, dim=-1)
            prediction = torch.multinomial(probs, num_samples=1).item()

            while prediction == vocab['<unk>']: #if it is unk, we sample again
                prediction = torch.multinomial(probs, num_samples=1).item()

            if prediction == vocab['<eos>']:    #if it is eos, we stop
                break

            indices.append(prediction) #autoregressive, thus output becomes input

    itos = vocab.get_itos()
    tokens = [itos[i] for i in indices]
    return tokens

UNK_IDX, PAD_IDX, SOS_IDX, EOS_IDX = 0, 1, 2, 3
vocab_transform = torch.load("utils/transformer/vocab.pt")

output_dim  = len(vocab_transform)
hid_dim = 256
dec_layers = 12
dec_heads = 8
dec_pf_dim = 512
dec_dropout = 0.1

SRC_PAD_IDX = PAD_IDX
TRG_PAD_IDX = PAD_IDX

model = Decoder(output_dim,
              hid_dim,
              dec_layers,
              dec_heads,
              dec_pf_dim,
              dec_dropout,
              device,SRC_PAD_IDX,TRG_PAD_IDX).to(device)
model.apply(initialize_weights)

# prompt = 'ผมไปกินข้าว'
# max_seq_len = 30
# seed = 15648
# model.load_state_dict(torch.load('/content/drive/MyDrive/transformer/models_l/Decoder.pt', map_location=torch.device('cpu')))
# temperatures = [0.6789]

# for temperature in temperatures:
#     generation = generate(prompt, max_seq_len, temperature, model, word_tokenize,
#                           vocab_transform, device, seed)
#     print(str(temperature)+'\n'+''.join(generation)+'\n')
def prediction(text , model) :
    list_syn = []
    prompt = text
    max_seq_len = 30
    seed = 15648
    temperatures = [0.6789]
    model.load_state_dict(torch.load('utils/transformer/Decoder.pt', map_location=torch.device('cpu')))

    for temperature in temperatures:
        generation = generate(prompt, max_seq_len, temperature, model, word_tokenize,
                            vocab_transform, device, seed)
        a = ''.join(generation)
        if a not in list_syn :
            list_syn.append(a)
    return list_syn

# print(prediction("วันนี้", model))


"""
Ejercicio 03
Escribir un programa que lea un log de correo construya un histograma usando
un diccionario para contar cuántos mensajes se recibieron de cada dirección
de correo electrónico y visualice los resultados.
"""

try:
    fichero = open("C:/Users/migue/Documents/MEGA/Datos/Python/Diccionario/mbox-short.txt")
except IOError:
    print("No existe el archivo")

mail = dict()

for linea in fichero:
    if linea.startswith("From "):
        linea = linea.split()
        mail[linea[1]] = mail.get(linea[1],0) + 1

for email in mail:
    print(email, " : ", mail[email])


"""
5. Ну і традиційно - калькулятор :slightly_smiling_face: Повинна бути 1 функцiя, яка приймає 3 аргументи - один з яких операцiя, яку зробити!
Аргументи брати від юзера (можна по одному - окремо 2, окремо +, окремо 2; можна всі разом - типу 2 + 2).
Операції що мають бути присутні: +, -, *, /, %, //, **.
Не забудьте протестувати з різними значеннями на предмет помилок!"""

def calculate():
    try:
        num1 = int(input("Print a number: "))
        num2 = int(input("Print a number: "))
        op = input("Print an operator: ")
        operators = ["+", "-", "*", "/", "%", "//", "**"]
        if op not in operators:
            print("Something went wrong!")
        else:
            print(f"{num1} {op} {num2} =", end = " ")
            if op == "+":
                print(num1 + num2)
            elif op == "-":
                print(num1 - num2)
            elif op == "*":
                print(num1 * num2)
            elif op == "/":
                print(num1 / num2)
            elif op == "//":
                print(num1 // num2)
            elif op == "%":
                print(num1 % num2)
            elif op == "**":
                print(num1 ** num2)
    except ValueError:
        print("You didn't type a correct number!")
    except ZeroDivisionError:
        print("\nCan't divide by zero!!!")

calculate()


import numpy as np
from numpy import linalg as LA
import scipy
from scipy import stats
from scipy import special
import random
import math

class VA_LBK():
	def __init__(self, train_data_x, train_data_y, test_data_x, test_data_y, lr, initial_val, batch_size, latent_sample_size,epoch):
		self.train_data=train_data_x
		self.train_data_y=train_data_y
		self.test_data_x=test_data_x
		self.test_data_y=test_data_y
		self.lr=lr
		self.batch_size=batch_size
		self.latent_sample_size=latent_sample_size
		self.param_initial=initial_val
		self.epoch=epoch
		self.para_store={}

	def prepare_train_data(self):
		x=self.train_data
		(N,D)=x.shape
		pre=np.zeros((N,N,D))
		for i in range(N):
			for j in range(i+1):
				for k in range(D):
					if i!=j:
						pre[i,j,k]=pre[j,i,k]=(x[i,k]-x[j,k])**2
					else:
						pre[i,i,k]=(x[i,k])**2
		return(pre)

	def preprare_test_data(self, x_test):
		(n1,d)=x_test.shape
		n2=self.train_data.shape[0]
		pred=np.zeros((n1,n2,d))
		for i in range(n1):
			for j in range(n2):
				for k in range(d):
					pred[i,j,k]=(x_test[i,k]-self.train_data[j,k])**2
		return pred

	def kernel_LB(self, x, y, z, a, beta, alpha):
		y1=(1+np.dot(x,a))**beta
		y2=(1+np.dot(y,a))**beta
		y3=(1+np.dot(z,a))**beta
		cov=alpha*(y1+y2-y3-1)
		return(cov)

	def covariance_build(self,x_pre,a,beta, alpha):
		n=x_pre.shape[0]
		d=x_pre.shape[2]
		z_t=np.zeros(d)
		kernel=np.zeros((n,n))
		for i in range(n):
			for j in range(i+1):
				if i!=j:
					kernel[i,j]=kernel[j,i]=\
					self.kernel_LB(x_pre[i,i,:],x_pre[j,j,:],x_pre[i,j,:],a,beta, alpha)
				else:
					kernel[i,i]=self.kernel_LB(x_pre[i,i,:],x_pre[i,i,:],z_t,a,beta, alpha)
		return(kernel)

	def log_joint_distribution(self, K, a, p, sigma, sigma_0, y):
		tem=K+np.identity(K.shape[0])*(sigma*2+0.01)
		tem_inv=LA.pinv(tem)
		a_0=(a==0)
		a_1=(a>0)
		t_val=-np.log(LA.det(tem))-0.5*np.dot(y, tem_inv).dot(y)#-\
		#0.5*(np.sum(np.square(np.log(a[a_1])))+(np.log(sigma))**2)/sigma_0**2+np.sum(np.log(p[a_1]))
		#print(LA.det(tem),np.log(LA.det(tem)),t_val)
		return(t_val)

	def deri_a(self, mu, phi, p, a, t):
		if t==0:
			return([0.0,0.0, -1/np.min((1-p, 1-1e-5))], np.log(1-p))
		else:
			t=np.log(a)-mu
			d_mu=t/phi**2
			d_phi=-1.0/phi+t**2/4.0/phi**3
			d_p=1.0/np.max((p, 1e-5))
			q=-0.5*(np.log(2*np.pi)+2*np.log(phi)+t**2/phi**2)
			return([d_mu, d_phi, d_p], q)

	def deri_beta(self, beta, gam_1, gam_2):
		s1=np.log(gam_1+gam_2)-0.5/(gam_1+gam_2)
		d_gam_1=s1-np.log(gam_1)+0.5/gam_1+np.log(beta)
		d_gam_2=s1-np.log(gam_2)+0.5/gam_2+np.log(1-beta)
		c=scipy.special.beta(gam_1,gam_2)
		q=(gam_1-1)*np.log(beta)+(gam_2-1)*np.log(1-beta)-np.log(c)
		return([d_gam_1,d_gam_2],q)

	def deri_sigma(self, sigma, mu_s, phi_s):
		t=np.log(sigma)-mu_s
		d_mu_s=t/phi_s**2
		d_phi_s=-1.0/phi_s+t**2/phi_s**3/4
		q=-0.5*(np.log(2*np.pi)+2*np.log(phi_s)+t**2/phi_s**2)
		return([d_mu_s,d_phi_s],q)

	def sample_batch(self, X_pre, y_train):
		N=X_pre.shape[0]
		idx=random.sample(range(N),self.batch_size)
		x_sample=X_pre[idx,:][:,idx]
		y_sample=y_train[idx]
		return(x_sample, y_sample)

	def sample_latent_var(self, a_para, beta_para, sigma_para, alpha_para):
		D=len(a_para)
		a_sample=np.zeros((self.latent_sample_size,D,2))
		beta_sample=np.zeros(self.latent_sample_size)
		sigma_sample=np.zeros(self.latent_sample_size)
		alpha_sample=np.zeros(self.latent_sample_size)
		for i in range(self.latent_sample_size):
			beta_sample[i]=min(max(1e-2,scipy.stats.beta.rvs(beta_para[0],beta_para[1])),1-1e-2)
			sigma_sample[i]=np.exp(np.random.randn(1)*sigma_para[1]+sigma_para[0])
			alpha_sample[i]=max(1.0,np.exp(np.random.randn(1)*alpha_para[1]+alpha_para[0]))
			for j in range(D):
				a_sample[i,j,1]=(np.random.uniform()<a_para[j][2])
				if a_sample[i,j,1]:
					a_sample[i,j,0]=np.exp(np.random.randn(1)*a_para[j][1]+a_para[j][0])
				else:
					a_sample[i,j,0]=0
		return(a_sample,beta_sample,sigma_sample,alpha_sample)

	def deri_calculate(self, deri_para, log_para, log_joint):
		n_a=int(self.latent_sample_size/1.5)
		f=np.multiply(deri_para, (log_joint-log_para))
		tem=np.row_stack((f, deri_para))[:,range(n_a)]
		tem_cov=np.cov(tem)
		a_d=tem_cov[0,1]/max(tem_cov[1,1],1e-5)
		deri=np.average(f-a_d*deri_para)
		return(deri)

	def initiate_parameter(self):
		D=self.train_data.shape[1]
		a_para=np.array([self.param_initial['a_init'] for _ in range(D)])
		beta_para=np.array(self.param_initial['beta_init'])
		sigma_para=np.array(self.param_initial['sigma_init'])
		alpha_para=np.array(self.param_initial['alpha_para'])
		return(a_para, beta_para, sigma_para,alpha_para)

	def train(self):
		X_pre=self.prepare_train_data()
		d=self.train_data.shape[1]
		[rho, dec_percent, dec_step]=self.lr
		(a_para, beta_para, sigma_para, alpha_para)=self.initiate_parameter()
		sigma_0=sigma_para[1]
		for itr in range(self.epoch):
			if itr%dec_step==0:
				rho*=dec_percent
			#generate fitting points
			(x_pre_sample, y_sample)=self.sample_batch(X_pre, self.train_data_y)
			#print(x_pre_sample)
			(a_sample,beta_sample,sigma_sample,alpha_sample)=self.sample_latent_var(a_para, beta_para, sigma_para,alpha_para)
			#store temporary log_p
			tem_log_joint=np.zeros(self.latent_sample_size)
			a_para_deri=np.zeros((self.latent_sample_size,d,3))
			q_a=np.zeros((self.latent_sample_size,d))
			beta_para_deri=np.zeros((self.latent_sample_size,2))
			q_beta=np.zeros(self.latent_sample_size)
			sigma_para_deri=np.zeros((self.latent_sample_size,2))
			q_sigma=np.zeros(self.latent_sample_size)
			alpha_para_deri=np.zeros((self.latent_sample_size,2))
			q_alpha=np.zeros(self.latent_sample_size)
			#calculate all needed derivatives for each sample
			for i in range(self.latent_sample_size):
				K=self.covariance_build(x_pre_sample,a_sample[i,:,0],beta_sample[i],alpha_sample[i])
				tem_log_joint[i]=self.log_joint_distribution(K, a_sample[i,:,0], a_para[:,2], sigma_sample[i], sigma_0, y_sample)
				beta_para_deri[i,:],q_beta[i]=self.deri_beta(beta_sample[i], beta_para[0], beta_para[1])
				alpha_para_deri[i,:],q_alpha[i]=self.deri_sigma(alpha_sample[i], alpha_para[0], alpha_para[1])
				sigma_para_deri[i,:],q_sigma[i]=self.deri_sigma(sigma_sample[i], sigma_para[0], sigma_para[1])
				for j in range(d):
					a_para_deri[i,j,:],q_a[i,j]=self.deri_a(a_para[j,0],a_para[j,1], a_para[j,2], a_sample[i,j,0], a_sample[i,j,1])
			#updating each parameters:
			a_para_old=a_para.copy()
			beta_para_old=beta_para.copy()
			alpha_para_old=alpha_para.copy()
			sigma_para_old=sigma_para.copy()
			for j in range(d):
				t_0=rho*self.deri_calculate(a_para_deri[:,j,0], q_a[:,j], tem_log_joint)
				a_para[j,0]+=np.sign(t_0)*min(abs(t_0),0.1)
				t_1=rho*self.deri_calculate(a_para_deri[:,j,1], q_a[:,j], tem_log_joint)
				t_1=np.sign(t_1)*min(abs(t_1),0.1)
				a_para[j,1]=min(max(t_1+a_para[j,1],1e-5),0.25)
				t_2=rho*self.deri_calculate(a_para_deri[:,j,2], q_a[:,j], tem_log_joint)
				t_2=np.sign(t_2)*min(abs(t_2),0.05)
				a_para[j,2]=min(a_para[j,2]+t_2,1-1e-5)
				a_para[j,2]=max(1e-5, a_para[j,2])
			b_t_1=rho*self.deri_calculate(beta_para_deri[:,0], q_beta, tem_log_joint)
			b_t_1=np.sign(b_t_1)*min(abs(b_t_1),0.1)
			b_1=max(beta_para[0]+b_t_1,0.01)
			b_t_2=rho*self.deri_calculate(beta_para_deri[:,1], q_beta, tem_log_joint)
			b_t_2=np.sign(b_t_2)*min(abs(b_t_2),0.1)
			b_2=max(beta_para[1]+b_t_2,0.01)
			beta_para=np.array([b_1,b_2])
			s_t_1=rho*self.deri_calculate(sigma_para_deri[:,0], q_sigma, tem_log_joint)
			s_t_1=np.sign(s_t_1)*min(0.1,abs(s_t_1))
			sigma_para[0]=min(-1.0, sigma_para[0]+s_t_1)
			s_t_2=rho*self.deri_calculate(sigma_para_deri[:,1], q_sigma, tem_log_joint)
			s_t_2=np.sign(s_t_2)*min(abs(s_t_2),0.1)
			sigma_para[1]=min(max(sigma_para[1]+s_t_2,1e-5),0.1)

			alpha_t_1=rho*self.deri_calculate(alpha_para_deri[:,0], q_alpha, tem_log_joint)
			alpha_t_1=np.sign(alpha_t_1)*min(0.1,abs(alpha_t_1))
			alpha_para[0]=min(alpha_para[0]+alpha_t_1,1.0)
			alpha_t_2=rho*self.deri_calculate(alpha_para_deri[:,1], q_alpha, tem_log_joint)
			alpha_t_2=np.sign(alpha_t_2)*min(abs(alpha_t_2),0.1)
			alpha_para[1]=min(max(alpha_para[1]+alpha_t_2,1e-5),0.1)

			diff=np.sqrt((np.sum(np.square(a_para_old-a_para))+np.sum(np.square(beta_para_old-beta_para))+\
			np.sum(np.square(sigma_para_old-sigma_para))+np.sum(np.square(alpha_para_old-alpha_para)))/(a_para.shape[0]*3+4)/rho)
			print(itr,np.mean(tem_log_joint),diff,rho)
			if diff<0.005:
				break

		self.para_store['a_para']=a_para
		self.para_store['beta_para']=beta_para
		self.para_store['sigma_para']=sigma_para
		self.para_store['alpha_para']=alpha_para

	def post_para_estimate(self):
		post_estimation={}
		a=self.para_store['a_para']
		beta=self.para_store['beta_para']
		sigma=self.para_store['sigma_para']
		alpha=self.para_store['alpha_para']
		post_estimation['a']=np.multiply(a[:,2],np.exp(a[:,0]))
		post_estimation['beta']=beta[0]/(beta[0]+beta[1])
		post_estimation['sigma']=np.exp(sigma[0])
		post_estimation['alpha']=np.exp(alpha[0])
		return(post_estimation)

	def prediction_r_build(self, test_x, x_new_prepare, x_pre, a, beta, alpha):
		n1=x_new_prepare.shape[0]
		n2=x_pre.shape[0]
		r=np.zeros((n1,n2))
		for i in range(n1):
			for j in range(n2):
				r[i,j]=\
				self.kernel_LB(np.square(test_x[i,:]), x_pre[j,j,:], x_new_prepare[i,j,:], a, beta, alpha)
		return(r)

	def prediction(self, test_x):
		x_new_prepare=self.preprare_test_data(x_test)
		x_pre=self.prepare_train_data()
		post_estimation=self.post_para_estimate()
		r=self.prediction_r_build(test_x, x_new_prepare, x_pre, post_estimation['a'], post_estimation['beta'], post_estimation['alpha'])
		covariance=self.covariance_build(x_pre,post_estimation['a'], post_estimation['beta'], post_estimation['alpha'])
		inv=LA.pinv(covariance+np.identity(r.shape[1])*post_estimation['sigma']**2)
		y_pre=np.dot(np.dot(r,inv),self.train_data_y)
		return(y_pre)

	def prediction_average(self, test_x):
		a_para=self.para_store['a_para']
		beta_para=self.para_store['beta_para']
		sigma_para=self.para_store['sigma_para']
		alpha_para=self.para_store['alpha_para']
		x_new_prepare=self.preprare_test_data(x_test)
		x_pre=self.prepare_train_data()

		#print(x_pre_sample)
		(a_sample,beta_sample,sigma_sample,alpha_sample)=self.sample_latent_var(a_para, beta_para, sigma_para,alpha_para)
		f_pre=np.zeros((self.latent_sample_size,len(test_x)))
		for i in range(self.latent_sample_size):
			(x_pre_sample, y_sample)=self.sample_batch(x_pre, self.train_data_y)
			K=self.covariance_build(x_pre_sample,a_sample[i,:,0],beta_sample[i],alpha_sample[i])
			r=self.prediction_r_build(test_x, x_new_prepare, x_pre_sample, a_sample[i,:,0], beta_sample[i], alpha_sample[i])
			inv=LA.pinv(K+np.identity(len(K))*sigma_sample[i]**2)
			f_pre[i,:]=np.dot(np.dot(r,inv),y_sample)
		return(np.average(f_pre, axis=0))

np.random.seed(120)
train_data=np.loadtxt(open("x_train.txt"),delimiter=",")
x_0=train_data[0,:]
train_data=(train_data-x_0)[1:,:]
y=np.loadtxt(open("y_train.txt"),delimiter=",")
y_0=y[0]
y=(y[1:]-y_0)
x_test=np.loadtxt(open("x_test.txt"),delimiter=",")-x_0
y_test=np.loadtxt(open("y_test.txt"),delimiter=",")-y_0
init_val={'a_init':[2.0,0.25,0.3],'beta_init':[1,1],'sigma_init':[-2.0,0.1],'alpha_para':[0.0,0.25]}
test=VA_LBK(train_data_x=train_data, train_data_y=y, test_data_x=None, test_data_y=None, lr=[0.001, 0.95, 100], \
	batch_size=30, latent_sample_size=80, initial_val=init_val, epoch=6000)

#print(test.covariance_build(self,x_pre,a,beta))
test.train()
print(test.para_store)
y_pre=test.prediction(x_test)
print(np.std(y_pre-y_test))
y_pre_2=test.prediction_average(x_test)
print(np.std(y_pre_2-y_test))


from flask import request, jsonify
from flask.views import View
from sih.modules.api.exceptions import ApiError

class ApiView(View):

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

    @classmethod
    def register(cls, app, name, url_prefix, resource):
        view = cls.as_view(name, resource=resource)

        app.add_url_rule(url_prefix,
                         view_func=view,
                         methods=['GET', 'POST'])

        app.add_url_rule('{0}/<obj_id>'.format(url_prefix),
                         view_func=view,
                         methods=['GET', 'PUT', 'DELETE'],)

    def dispatch_request(self, obj_id=None):
        try:
            if obj_id is None:
                if request.method == 'POST':
                    return self.create()
                return self.list()

            if request.method == 'GET':
                return self.view(obj_id)
            elif request.method == 'PUT':
                return self.edit(obj_id)
            elif request.method == 'DELETE':
                return self.delete(obj_id)

        except ApiError as e:
            return jsonify({
                'message': str(e)
            }), e.code

    def request_data(self):
        data = request.get_json(silent=True)
        self.resource.validate_data(data)
        return data

    def list(self):
        args = request.args.copy()

        offset = int(args.pop('offset', 0))
        limit = int(args.pop('limit', self.resource.limit))

        if limit > self.resource.limit:
            limit = self.resource.limit

        objects = self.resource.get_object_list(filters=args,
                                                offset=offset, limit=limit)

        return jsonify({
            'data': [
                self.resource.short_representation(obj) for obj in objects
            ],
            'summary': {
                'total': self.resource.total_count(filters=args),
                'result_size': len(objects),
                'offset': offset
            }
        })

    def view(self, obj_id):
        obj = self.resource.get_object(obj_id)

        if obj is None:
            raise ApiError('Not found', 404)

        return jsonify(self.resource.full_representation(obj))

    def create(self):
        data = self.request_data()
        obj = self.resource.create_object(data)

        return jsonify(self.resource.full_representation(obj)), 201

    def edit(self, obj_id):
        obj = self.resource.get_object(obj_id)

        if obj is None:
            raise ApiError('Not found', 404)

        data = self.request_data()
        obj = self.resource.edit_object(obj, data)

        return jsonify(self.resource.full_representation(obj))

    def delete(self, obj_id):
        obj = self.resource.get_object(obj_id)

        if obj is None:
            raise ApiError(u'Not found', 404)

        self.resource.delete_object(obj)

        return '', 204


"""Config file for 7 elements Tangram puzzle."""

import math

# in 7 Tangram we always use all the elements
from enum import Enum, IntEnum

ELEMENT_NUM = 7
TANGRAM_S = 8.
PI = math.pi
SQRT_2 = 2 ** 0.5

# number of angles tried to place elements
# for example, 8 means every rotation is 2 * pi / 8 = pi / 4
ANGLE_NUM = 8

# total state number for each element
TRIANGLE_STATE = 3  # p0, p1, p2
SQUARE_STATE = 1  # p0
PARALLELOGRAM_STATE = 4  # p0, p1, inverse_p0, inverse_p1

RESULT_PATH = "result/"

class ConcaveConvexEnum(Enum):
    concave = 1
    convex = 2

class TangramElementEnum(IntEnum):
    large_triangle = 1
    square = 2
    parallelogram = 3
    medium_triangle = 4
    small_triangle = 5

TRIANGLE_ELEMENT_STATE_DIC = {
    TangramElementEnum.large_triangle: TRIANGLE_STATE,
    TangramElementEnum.medium_triangle: TRIANGLE_STATE,
    TangramElementEnum.small_triangle: TRIANGLE_STATE,
    TangramElementEnum.square: SQUARE_STATE,
    TangramElementEnum.parallelogram: PARALLELOGRAM_STATE
}

# standard size of elements in a set of Tangram, the first element is its area
STANDARD_SIZE = {
    TangramElementEnum.large_triangle: [2., 2 * SQRT_2, 2., 2.],
    TangramElementEnum.medium_triangle: [1., 2., SQRT_2, SQRT_2],
    TangramElementEnum.small_triangle: [0.5, SQRT_2, 1., 1.],
    TangramElementEnum.square: [1., 1., 1., 1., 1.],
    TangramElementEnum.parallelogram: [1., SQRT_2, 1., SQRT_2, 1.]
}

# colors for drawing elements of Tangram
COLORS = [
    (int(255. * i / ELEMENT_NUM),
     int(128. + 255. * i / ELEMENT_NUM) % 255,
     int(255. - 255. * i / ELEMENT_NUM))
    for i in range(ELEMENT_NUM)
]


import datetime

default_names = ["Akash", "Sagar", "John", "Jim"]
default_amounts = [100, 200, 300, 400]

unf_message = """
  Hi {name},
  This is messsage with {date} & {amount}
  Thank You!
"""

def make_messages(names, amounts):
  if len(names) == len(amounts):
    i = 0
    today = datetime.date.today()
    for name in names:
      new_msg = unf_message.format(
        name= name,
        date=today,
        amount=amounts[i]
      )
      i+=1
      print(new_msg)

make_messages(default_names, default_amounts)


"""
Combat Related Commands

"""

from calendar import c
from evennia import CmdSet
from commands.command import Command
from evennia.commands.default.muxcommand import MuxCommand
from server.utils import sub_old_ansi
from random import randint
from evennia import Command, InterruptCommand
from server.battle import roll_attack, check_valid_target, explode_tens, roll_to_string, check_successes, check_capabilities, copy_attack, do_roll
from evennia.utils.utils import inherits_from
from django.conf import settings
from world.combat.models import Weapon
from world.armor.models import ArmorMode, Capability

'''
constants set here for testing purposes
'''

DUEL_HP = 90
STANDARD_HP = 60

"""
Combat is a type of scene called a Showdown which can be initiated via a showdown command
"""

class ModeSwap(MuxCommand):
    """
    Swap armor modes.

    Usage:
        armor <name>

    Swapping to an armor mode.
    This will change your stats and the weapons that you have equipped.

    """
    key = "armor"
    aliases= "+armor"
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        #stubbed only
        errmsg = "Error, check help armor."
        caller= self.caller

        if not self.args:
            caller.msg("Swap to which armor?")

class CmdShowdown(Command):
    """
    Starts a showdown.

    Usage:
        showdown <name>
        showdown/boss
        showdown/end

    showdown with a single name challenges that person to a duel.
    showdown/boss begins a showdown with everyone in the room who is not
    set as observer.

    +showdown/end ends your current combat if you are a boss or duelist.

    This is currently not balanced for 2 on 1 or other configurations.
    A duel in progress can't be third-partied. However, multiple
    boss fights can be initiated in the same location.

    """

    key = "showdown"
    aliases= "+showdown"
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        '''
        doesn't function yet just stubbing out commands.

        to-do: test balance for other configurations.
        occupied check needs to sync with db in case of reset.

        '''
        errmsg = "You must supply a target, or choose +showdown/boss to attack everyone."

        occupied = False
        caller= self.caller
        room = caller.location

        if room.db.protector == "Staff" and not caller.check_permstring("builders"):
            caller.msg("You can't start a showdown here - it's protected by staff. Ask staff about using this room.")
            return
        if room.db.protector:
                caller.msg("This room has a +protector set, so make sure they were consulted about your combat if necessary.")
        if self.switches or self.args:
            if "boss" in self.switches:
                caller.msg("You start a boss fight in this location!")
                caller.location.msg_contents(caller.name + " has begun a Boss Showdown in this location!" )

                '''
                what needs to happen:
                Set HP based on the involved number of attackers
                check if the room has a protector, return a warning if it does.
                '''
            if "end" in self.switches:
                caller.db.hp = STANDARD_HP
                '''
                remove everyone's aimdice and bonus dice
                '''

        if not self.args:
            caller.msg(errmsg)
            return
        try:
            '''
            do-to: error check - is target a character? are they in the room?
            '''
            target = self.args
            caller.msg(f"You start a showdown with {target.name}.")
            target.msg(f"{caller.name} has challenged you a duel!")
            '''
            set duel HP
            '''
            target.db.hp = DUEL_HP
            caller.db.hp = DUEL_HP

            if not (occupied):
                occupied = True
                return
            else:
                caller.msg("That person is already in a duel.")
        except ValueError:
            caller.msg(errmsg)
            return

class CmdGMRoll(Command):
    """
    GM free rolls a certain amount of dice.

    Usage:
       gmroll <number from 1-10>

    This is for if you just need to roll D10s for whatever reason in a
    scene you may be running. Unlike most standard rolls, this roll does not
    have exploding 10s.

    To roll a die with an arbitrary amount of sides, see +roll.

    """

    key = "gmroll"
    aliases = ["+gmroll"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        caller = self.caller
        if not self.args:
            caller.msg("Roll how many dice?")
            return
        '''convert argument to a number'''
        args = self.args.lstrip()
        try:
            numdice = int(args)
            if not 1 <= numdice <=10:
                raise ValueError
        except ValueError:
            caller.msg("Number of dice must be an integer between 1 and 10.")
            raise InterruptCommand

        result = list(range(numdice))
        outputmsg = (f"{caller.name} does a GM roll: ")
        errmsg = "An error occured."
        for i in range(0, numdice):
            random = randint(1,10)
            result[i] = random
        successes = check_successes(result)
        outputmsg +=  roll_to_string(result)
        outputmsg += "\n" + str(successes) + " successes."
        try:
            caller.location.msg_contents(outputmsg, from_obj=caller)
        except ValueError:
            caller.msg(errmsg)
            return

class CmdRoll(Command):
    """
    Roll an arbitrary die.

    Usage:
       roll <number from 1-100>

    This will choose a random integer, depending on the size of the die you
    choose to roll. This is a purely random choice to be used for arbitrary
    decision making.

    Rolling a die other than 1d10 is not an official game mechanic or part of
    the combat system, but can sometimes be useful.

    """

    key = "roll"
    aliases = ["+roll"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        errmsg = "An error occured."
        caller = self.caller

        if not self.args:
            caller.msg("Roll what size die?")
            return
        '''convert argument to a number'''
        args = self.args.lstrip()
        try:
            dice = int(args)
            if not 1 <= dice <=100:
                raise ValueError
        except ValueError:
            self.msg("Please choose a die size as an integer between 1 and 100.")
            raise InterruptCommand

        result = randint(1,dice)
        name = caller.name
        try:
            message = (f"{name} rolls a D{dice} and rolls a {result}.")
            caller.location.msg_contents(message, from_obj=caller)

        except ValueError:
            caller.msg(errmsg)
            return

class CmdFlip(Command):
    """
    Flip a coin.

    Usage:
       +flip

    This command flips a coin, with a result of heads or tails.

    There are two uses for this command. One is of an OOC nature, when
    you may just be trying to choose between two outcomes. If you
    need to choose between more than two possible outcomes, see +roll.

    This command may also be used to indicate an IC flip of a coin, as
    in the opening round of a Battle and Chase sporting match, or for
    other dramatic reasons.

    Please note that when the coin flip mechanic is used IC, some characters
    do have the ability to cheat on the coin flip.

    """

    key = "flip"
    aliases = ["+flip"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        caller = self.caller
        errmsg = "An error occured."

        '''
        to do: cheating stuff.
        '''
        try:
            result = randint(0,1)
            if result == 1:
                str_result = "|rheads.|n"
            else:
                str_result = "|gtails.|n"
            outputmsg = (f"{caller.name} flips a coin in the air and it comes down {str_result}" )
            caller.location.msg_contents(outputmsg, from_obj=caller)
        except ValueError:
            caller.msg(errmsg)
            return

'''
holding this space, might not use this command

class CmdStatRoll(Command):
    """
    Stat roll an individual stat. Useful for a quick check.

    Usage:
      +statroll <stat>
      +statroll Aur

    """

    key = "+statroll"
    aliases = ["statroll"]
    help_category = "Dice"

    def func(self):

        errmsg = "An error occured."

        caller= self.caller

        if not self.args:
            caller.msg("Roll which stat?")
            return
        try:
            self.caller.msg("You Roll.")
        except ValueError:
            caller.msg(errmsg)
            return
'''

class CmdRollSkill(Command):
    """
    Roll a Stat + Skill combo.

    Usage:
        check <stat> + <skill>

    This allows any combination of rolls. Can be used to check any two stats.
    Useful in one-off confrontations, if trying to do something unusual, or
    if a particular roll is called by a GM in a Sequence.

    Currently it is not possible to check just a stat. Always choose
    which skill you want to roll. See news files for combo examples.

    """

    key = "check"
    aliases = ["+check"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        #todo: any bonus dice that need added might be added?

        caller = self.caller
        errmsg = "Wrong syntax. Please enter a valid stat and skill seperated by +."
        if not self.args:
            caller.msg(errmsg)
            return
        args = self.args
        try:
            stat, skill = args.split("+",1)
            stat = stat.strip()
            skill = skill.strip()
        except ValueError:
            caller.msg(errmsg)
            return

        errmsg = "An error occured. Contact staff to help debug this."

        try:
            stat_check = caller.get_a_stat(stat)
            skill_check = caller.get_a_skill(skill)

            # build the string

            result = do_roll(stat_check,skill_check)
            if len(result) == 0:
                caller.msg("Skill + stat combination invalid. Try again.")
                return
            else:
                result = explode_tens(result)
                successes = check_successes(result)
                str_result = roll_to_string(result)
                outputmsg = (f"{caller.name} rolls {stat} and {skill}: {str_result} \n" )
                outputmsg += (f"{successes} successes.")
                caller.location.msg_contents(outputmsg, from_obj=caller)

        except ValueError:
            caller.msg(errmsg)
            return

'''
+Aim - sacrifice a round for a higher chance of hitting next round.
+Charge - sacrifice around for a higher crit chance next round. If a charge crit hits
a weakness it does triple damage.
+Assist - sacrifice your round to add your dice to another player's roll.
+Heal (this has several varieties)
+Guard - sacrifice a round to counter/deflect
+Taunt - presence roll to do damage. Makes it slightly harder for target to
hit other people next round
+intimidate - presence roll to do damage. Makes it slightly harder for
target to hit you next round
+Persuade/+negotiate/+moralhighground - make a convince roll to do damage
'''

class CmdAim(Command):

    """

    Usage:
        aim

    Sacrifice a combat round for a higher chance of hitting next
    time you +attack.

    Only can be used in a Sequence or Showdown.

    An aim will be held until an +attack is used, or the
    Sequence/Showdown is over. If the scene ends before you
    +attack, the aiming action is lost.

    """

    key = "aim"
    aliases = ["+aim"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "An error occured."

        caller= self.caller

        if caller.db.aimdice == 1:
            caller.msg("You are already aiming!")

        '''
        future check: if the Sniper capability is present, stack Aim up to 3x
        '''

        try:
            caller.db.defending = 0
            caller.location.msg_contents(f"{caller.name} forfeits their turn to Aim.", from_obj=caller)
            caller.db.aimdice = 1
        except ValueError:
            caller.msg(errmsg)
            return
        '''
        todo: remember to clear out aimdice if combat ends
        '''

class CmdCharge(Command):

    """
    Usage:
        charge

    Sacrifice a combat round for a higher crit chance next round,
    provided your next action is an +attack.

    If a charge crit hits a weakness, it does triple damage.

    Only can be used in a Sequence or Showdown.

    A charge will be held until an +attack is used, or the
    Sequence/Showdown is over. If the scene ends before you
    +attack, the charge is lost.

    """

    key = "charge"
    aliases = ["+charge"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        '''
        doesn't function yet just stubbing out commands.
        '''
        errmsg = "An error occured."

        caller= self.caller

        if caller.db.chargedice == 1:
            caller.msg("You can't charge any more!")

        '''
        future check: if the Megablast capability is present, stack Charge up to 3x
        '''

        try:
            caller.db.defending = 0
            caller.location.msg_contents(f"{caller.name} is charging their shot!", from_obj=caller)
            caller.db.chargedice = 1
        except ValueError:
            caller.msg(errmsg)
            return

class CmdAttack(MuxCommand):
    """
    Attacking a particular target.

    Usage:
      attack <target>=<weapon>
      attack <target>

    This will allow you to attack a target with a weapon you have equipped.

    If you don't specify a weapon, this will use the same weapon you used
    last time you attacked, provided that weapon is still available.

    """

    key = "attack"
    aliases = ["+attack"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "Sorry, an error occured."
        caller= self.caller

        if not self.args:
            caller.msg("Attack who?")
            return
        weapon = self.rhs
        target = self.lhs
        bonus_dice = 0
        result = 0
        try:
            #any target?
            msg = "Target not found."
            if not target:
                caller.msg(msg)
                return

            #is it a character/valid target?
            target_ok = check_valid_target(target)
            if not target_ok:
                caller.msg(msg)
                return

            if not weapon:
                if caller.db.active_weapon:
                    weapon = caller.db.active_weapon
                #there should be a value there, but if there isn't,
                #eg, I've changed armors to a mode that doesn't have that weapon anymore
                else:
                    caller.msg("Specify a valid weapon to use.")
                    return

            char = self.caller.search(target, global_search=False)

            #if I attack I'm not defending
            caller.db.defending = 0
            target_defense = target.db.ten
            target_cap = check_capabilities(target)

            # don't need for now
            # attacker_cap = check_capabilities(caller)

            #to check: is the target in full defense?
            #if so, if target is defender, no damage can be done
            #otherwise, lower the potential to-hit
            full_defender = False
            if target.db.defending:
                for cap in target_cap:
                    if cap == "Defender":
                        full_defender = True

                if full_defender:
                    outputmsg = (f"{caller.name} tries to attack, but {target.name} is in full defense!" )
                    return
                else:
                    #right now defending gives 2x tenacity skill, may change
                    target_defense = int(target_defense * 2)

            #to check: is the target being defended by anyone else?
            #if so, high chance of redirecting this attack.
            #higher if you have bodyguard

            which_stat, which_skill = roll_attack(weapon)
            if which_stat == "random":
                rand1 = randint(1,10)
                rand2 = randint(1,10)
                result = do_roll(rand1,rand2)
            else:
                result = do_roll(which_stat,which_skill)
            # add aimdice to the to-hit
            if self.db.aimdice:
                bonus_dice = self.db.aimdice
                bonus = do_roll(bonus_dice,0)
                result = result + bonus
            str_result = str(result)
            dodge_roll = do_roll(target_defense,target.db.athletics)
            str_dodge = str(dodge_roll)

            caller.msg("You attack %s with %s." % str(char), weapon)
            outputmsg = (f"{caller.name} rolls to attack: {str_result} \n" )
            outputmsg += (f"{target.name} defends with: {str_dodge}." )
            caller.location.msg_contents(outputmsg, from_obj=caller)

            #still to do: types, damage

            '''
            You attack <person> with <weapon>
            Rolling <stat> plus <skill>: # # # # # #
            The attack hit <person>'s weakness! Critical hit!
            '''

        except ValueError:
            caller.msg(errmsg)
            return

class CmdTaunt(MuxCommand):

    """

    taunt <target>

    This type of assail makes a presence roll to do damage. Using this makes
    it slightly harder for your target to hit other people next round,
    but slightly easier to hit you.

    Only can be used in a Sequence or Showdown.

    """

    key = "taunt"
    aliases = ["+taunt"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "An error occured."
        caller= self.caller

        if not self.args:
            caller.msg("Taunt who?")
            return

        #check target is valid
        target = self.args.strip()
        char = self.caller.search(target, global_search=False)
        valid_target = check_valid_target(self, char)

        if not valid_target:
            caller.msg("Not a valid target.")
            return

        #calc highest of charisma, aura, tenacity, cunning
        stat = max(caller.db.chr, caller.db.aur, caller.db.ten, caller.db.cun)
        skill = caller.get_a_skill("presence")

        try:
            caller.db.defending = 0
            result = do_roll(stat, skill)
            str_result = roll_to_string(result)
            outputmsg = (f"{caller.name} rolls to taunt: {str_result}" )
            caller.location.msg_contents(outputmsg, from_obj=caller)
        except ValueError:
            caller.msg(errmsg)
            return

class CmdIntimidate(MuxCommand):

    """

    intimidate <target>

    This type of assail makes a presence roll to do damage. Using this makes
    it slightly harder for your target to hit you next round.

    Only can be used in a Sequence or Showdown.

    Only can be used once per target per Sequence/Showdown. The effect
    does not stack.

    """

    key = "intimidate"
    aliases = ["+intimidate", "spook", "+spook"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "An error occured."
        caller= self.caller

        if not self.args:
            caller.msg("Intimidate who?")
            return

        #check target is valid
        target = self.args.strip()
        char = self.caller.search(target, global_search=False)
        valid_target = check_valid_target(self, char)

        if not valid_target:
            caller.msg("Not a valid target.")
            return

        #calc highest of charisma, aura, power
        stat = max(caller.db.chr, caller.db.aur, caller.db.pow)

        skill = caller.get_a_skill("presence")

        try:
            caller.db.defending = 0
            result = do_roll(stat, skill)
            str_result = roll_to_string(result)
            outputmsg = (f"{caller.name} rolls to intimidate: {str_result}" )
            caller.location.msg_contents(outputmsg, from_obj=caller)
        except ValueError:
            caller.msg(errmsg)
            return

class CmdGuard(MuxCommand):

    """
    Usage:
        guard
        guard <target>

    Go fully defensive this round, making it quite a bit
    harder to be attacked or damaged, but at the cost of any
    meaningful action this turn.

    If guard is used on a target, this instead makes you
    more likely to hit, but less likely for that target to be hit.

    Choose wisely.

    The guard command has no effect on attempts to pursuade.

    If your character has the Defender capability, they will take
    no damage when in full guard.

    Only can be used in a Sequence or Showdown.

    """

    key = "guard"
    aliases = ["+guard"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "An error occured."
        caller= self.caller

        if not self.args:
            outputmsg = (f"{caller.name} goes into full defense." )
            caller.location.msg_contents(outputmsg, from_obj=caller)
            caller.db.defending = 1
            return
        try:
            self.caller.msg("You Roll.")
        except ValueError:
            caller.msg(errmsg)
            return

class CmdHeal(Command):

    """

    heal <target>

    Don't really know how to balance this yet, won't
    implement in early alpha.

    Only can be used in a Sequence or Showdown.

    """

    key = "heal"
    aliases = ["+heal"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "An error occured."
        caller= self.caller

        errmsg = "An error occured."
        caller= self.caller

        if not self.args:
            caller.msg("Heal who?")
            return

        #check target is valid
        target = self.args.strip()
        char = self.caller.search(target, global_search=False)
        valid_target = check_valid_target(self, char)

        if not valid_target:
            caller.msg("Not a valid target.")
            return

        if not self.args:
            caller.msg("Roll how many dice?")
            return
        try:
            self.caller.msg("You Roll.")
        except ValueError:
            caller.msg(errmsg)
            return

class CmdPersuade(Command):

    """
    Usage:
      persuade <target>

    This type of assail uses your convince skill to do damage to a target.

    Only can be used in a Sequence or Showdown.

    """

    key = "persuade"
    aliases = ["+persuade", "negotiate" ,"+negotiate", "moralhighground" , "+moralhighground"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):

        errmsg = "An error occured."
        caller= self.caller

        if not self.args:
            caller.msg("Heal who?")
            return

        #check target is valid
        target = self.args.strip()
        char = self.caller.search(target, global_search=False)
        valid_target = check_valid_target(self, char)

        if not valid_target:
            caller.msg("Not a valid target.")
            return

        '''
        todo: apply any bonus dice for pose or circumstance
        '''

        #calc highest of charisma, cunning, education
        stat = max(caller.db.chr, caller.db.cun, caller.db.edu)
        skill = caller.get_a_skill("convince")

        try:
            caller.db.defending = 0
            result = do_roll(stat, skill)
            str_result = roll_to_string(result)
            outputmsg = (f"{caller.name} rolls to persuade: {str_result}" )
            caller.location.msg_contents(outputmsg, from_obj=caller)
        except ValueError:
            caller.msg(errmsg)
            return

class CmdRollSet(MuxCommand):
    """
    Usage:
      rollset
      rollset/verbose
      rollset/basic

    Swap between die view modes. Setting rollset to 'verbose' will show all of the
    individual roles that lead to a die result. Setting to 'basic' will only show
    the final narrative result.

    +rollset on its own toggles between these two readout modes.

    """

    key = "rollset"
    aliases = ["+rollset"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        '''
        Doesn't function yet. Just sets the value to allow this to function in the future.
        '''
        errmsg = "A value error occured. Contact staff about this error."

        caller = self.caller

        '''
        rollset 1 is verbose. rollset 2 is basic.

        if there's no switch, check current value and toggle.
        '''

        if not self.switches:
            if caller.db.rollset == 1:
                caller.db.rollset = 2
                caller.msg("Set roll view type to basic.")
                return
            elif caller.db.rollset == 2:
                caller.db.rollset = 1
                caller.msg("Set roll view type to verbose.")
                return
            else:
                caller.msg(errmsg)

        '''
        had a switch, so just set the value
        '''

        if "verbose" in self.switches:
            caller.db.rollset = 1
            caller.msg("Set roll view type to verbose.")
            return
        elif "basic" in self.switches:
            caller.db.rollset = 2
            caller.msg("Set roll view type to basic.")
            return
        else:
            caller.msg("Not a valid choice. Choose verbose or basic.")
            return

class CmdWeaponCopy(MuxCommand):
    """
    Copy the weapon of your target.

    Usage:
      wcopy <target>

    If you have a weapon copy ability, this copies the weapon of the target.
    What weapon you copy depends on if you copy primarily ranged, or primarily melee weapons.
    This will be on your sheet as either Buster-Copy or Technique-Copy.

    Copied weapons will be listed on your weapon sheet automatically.

    """

    key = "wcopy"
    aliases = ["+wcopy", "buster","+buster"]
    help_category = "Dice"
    locks = "perm(Player))"

    def func(self):
        '''
        To-do: this command should not show up if you can't do it.
        check permission locks on how to achieve this.
        '''
        errmsg = "An error occured."

        caller= self.caller
        args = self.args
        caller.msg("Initiating weapon copy.")
        if not args:
            caller.msg("Copy whose weapon?")
            return
        try:

            char = caller.search(char, global_search=False)
            if not char:
                caller.msg("No target.")
                return
            if not inherits_from(char, settings.BASE_CHARACTER_TYPECLASS):
                caller.msg("No target.")
                return

            #process attack copy code
            new_weapon = copy_attack(char,caller)

        except ValueError:
            caller.msg(errmsg)
            return