# Some basic setup:
# Setup detectron2 logger
import datetime
import glob

import cv2
# import some common detectron2 utilities
from detectron2 import model_zoo
from detectron2.config import get_cfg
from detectron2.engine import DefaultPredictor
from detectron2.utils.logger import setup_logger
from tqdm import tqdm

from converts import convert_box, convert_keypoints, save_to_json, logger
# from visual import test_visual

config_path = '/home/sky/detectron2/configs/COCO-Keypoints/keypoint_rcnn_X_101_32x8d_FPN_3x.yaml'
checkpoint_path = '/home/sky/checkpoint/model_final_5ad38f.pkl'
rgb_path = '/home/sky/data/Thermal-pose_data_set/images/RGB_images'
thermal_path = '/home/sky/data/Thermal-pose_data_set/images/Thermal_images'

kp_thresh = 0.2

def covert_output_to_anno(predictions):
    """ Covert detectron2 output['instances'] into suitable annotation format.
    :param predictions: output['instances']
    :return annotation:
    """
    boxes = predictions.pred_boxes if predictions.has("pred_boxes") else None
    scores = predictions.scores if predictions.has("scores") else None
    classes = predictions.pred_classes if predictions.has("pred_classes") else None
    keypoints = predictions.pred_keypoints if predictions.has("pred_keypoints") else None

    # If no boxes were detected, return None.
    if boxes is not None:
        boxes = convert_box(boxes)
        num_instances = len(boxes)
        # Covert XYXY to XYHW
        boxes[:, 2] -= boxes[:, 0]
        boxes[:, 3] -= boxes[:, 1]
    else:
        return None

    # if num_instances is greater than 3 or ==0, means there is something wrong with the detector, return None
    if num_instances > 3 or num_instances == 0:
        return None

    if keypoints is not None:
        if num_instances:
            assert len(keypoints) == num_instances
        else:
            num_instances = len(keypoints)
        keypoints = convert_keypoints(keypoints)

    return boxes, classes, keypoints

def get_anno_dict():
    """Get COCO annotations from input images.
    :return:
    """
    logger.info("Generating prediction results into COCO format")
    coco_annotations = []
    coco_images = []

    cfg = get_cfg()
    cfg.merge_from_file(model_zoo.get_config_file('COCO-Keypoints/keypoint_rcnn_X_101_32x8d_FPN_3x.yaml'))
    cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.9
    cfg.MODEL.WEIGHTS = checkpoint_path

    predictor = DefaultPredictor(cfg)

    for file in tqdm(glob.glob('{}/*.jpg'.format(rgb_path))):
        im = cv2.imread(file)
        coco_image = {
            'id': file.rsplit('/')[-1].split('.')[0],  # Get image id from file name
            'width': im.shape[1],
            'height': im.shape[0],
            'file_name': file.rsplit('/')[-1],
        }
        coco_images.append(coco_image)

        outputs = predictor(im)
        res = covert_output_to_anno(outputs['instances'].to('cpu'))
        if res is None:
            continue
        else:
            boxes, classes, keypoints = res

        for box, category, keypoints_each in zip(boxes, classes, keypoints):
            # Create a new dict with COCO fields
            coco_annotation = {}

            # COCO requirement:
            #   linking annotations to images
            #   "id" field must start with 1
            coco_annotation['bbox'] = [round(float(x), 3) for x in box]
            coco_annotation['id'] = len(coco_annotations) + 1
            coco_annotation['image_id'] = coco_image['id']
            coco_annotation['category_id'] = category.item() + 1

            # Keypoints
            keypoints_list = [kp.item() for kp in keypoints_each.reshape(51, 1)]
            # If detected keypoints confident score is less than kp threshold, set that keypoint to 0. Otherwise set keypoints visibility to 2 (visible).
            for idx in range(2, len(keypoints_list), 3):
                if keypoints_list[idx] < kp_thresh:
                    keypoints_list[idx - 2], keypoints_list[idx - 1], keypoints_list[idx] = 0, 0, 0
                else:
                    keypoints_list[idx] = 2
                    keypoints_list[idx - 2] = int(keypoints_list[idx - 2])
                    keypoints_list[idx - 1] = int(keypoints_list[idx - 1])

            coco_annotation['keypoints'] = keypoints_list
            coco_annotation['num_keypoints'] = sum(kp > 0 for kp in keypoints_list[2::3])
            coco_annotation["iscrowd"] = 0

            coco_annotations.append(coco_annotation)

    info = {
        "date_created": str(datetime.datetime.now()),
        "description": "Automatically generated COCO json file in Thermal Images.",
    }
    coco_dict = {
        "info": info,
        "images": coco_images,
        "annotations": coco_annotations,
        "categories": [{"supercategory": "person", "id": 1, "name": "person",
                        "keypoints": ["nose", "left_eye", "right_eye", "left_ear", "right_ear", "left_shoulder",
                                      "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist",
                                      "left_hip", "right_hip", "left_knee", "right_knee", "left_ankle", "right_ankle"],
                        "skeleton": [[16, 14], [14, 12], [17, 15], [15, 13], [12, 13], [6, 12], [7, 13], [6, 7], [6, 8],
                                     [7, 9], [8, 10], [9, 11], [2, 3], [1, 2], [1, 3], [2, 4], [3, 5], [4, 6],
                                     [5, 7]]}],
        "licenses": None,
    }

    return coco_dict

if __name__ == '__main__':
    logger = setup_logger(name=__name__)
    json_path = '/home/sky/data/Thermal-pose_data_set/annotations/thermal_post_keypoints.json'
    coco_anno = get_anno_dict()
    save_to_json(coco_anno, json_path)


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

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

# 1.Pandas绘图,DataFrame绘图

# np.random.seed(100)
df = pd.DataFrame({'A': np.random.randn(365).cumsum(0),
                  'B': np.random.randn(365).cumsum(0) + 20,
                  'C': np.random.randn(365).cumsum(0) - 20},
                 index=pd.date_range('2017/1/1', periods=365))
print(df.head())
# df.plot()
# plt.show()

# df.plot('A', 'B', kind='scatter')
# plt.show()

# df.plot(kind='box')
# plt.show()

# df.plot(kind='hist', alpha=0.7)
# plt.show()
#
# df.plot(kind='kde')
# plt.show()

# # pandas.tools.plotting
#
# # 2. Seaborn绘图
import seaborn as sns
np.random.seed(100)
v1 = pd.Series(np.random.normal(0, 10, 1000), name='v1')
v2 = pd.Series(2 * v1 + np.random.normal(60, 15, 1000), name='v2')

np.random.seed(100)
v1 = pd.Series(np.random.normal(0, 10, 1000), name='v1')
v2 = pd.Series(2 * v1 + np.random.normal(60, 15, 1000), name='v2')

# # 通过matplotlib绘图
# plt.figure()
# plt.hist(v1, alpha=0.7, bins=np.arange(-50, 150, 5), label='v1')
# plt.hist(v2, alpha=0.7, bins=np.arange(-50, 150, 5), label='v2')
# plt.legend()
# plt.show()

plt.figure()
plt.hist([v1, v2], histtype='barstacked', normed=True)
v3 = np.concatenate((v1, v2))
sns.kdeplot(v3)
plt.show()

# # 使用seaborn绘图
# plt.figure()
# sns.distplot(v3)
# # plt.show()
#
#
# # 使用seaborn绘图
# plt.figure()
# sns.jointplot(v1, v2, alpha=0.4)
# # plt.show()
#
# # 使用seaborn绘图
# plt.figure()
# grid = sns.jointplot(v1, v2, alpha=0.4)
# grid.ax_joint.set_aspect('equal')
# plt.show()
#
# plt.figure()
# sns.jointplot(v1, v2, kind='hex')
# plt.show()
#
# plt.figure()
# sns.jointplot(v1, v2, kind='kde')
#
# iris = pd.read_csv('iris.csv')
# print(iris.head())
#
# sns.pairplot(iris, hue='Name', diag_kind='kde')
#
# plt.figure()
# plt.subplot(121)
# sns.swarmplot('Name', 'PetalLength', data=iris)
# plt.subplot(122)
# sns.violinplot('Name', 'PetalLength', data=iris)
# plt.show()


import os,argparse
from Bio import SeqIO
import gzip
import itertools

#os.chdir("/Users/zoliq/ownCloud/progs/PYTHON/mydata")
"""
prefixes = [x for x in os.listdir("./alignments") if x.endswith(".ali")]
#prefixes = ["PF00134_rp75", "PF02984_rp75"]
for prefix in prefixes:
	#os.system("hmmbuild {0}.hmm {0}.ali".format(prefix))
	os.system("hmmsearch -o {0}.result.txt --notextw --tblout {0}.table.txt --cpu 2 {0}.hmm hmmdb.fa".format(prefix, prefix))
"""

def make_clade_set(infilelist):
	"""Compares a subset of the MATOU database that contains unigenes with the given Pfam

	Input:		TSV with seqIDs (number-only) in the first column

	Returns:	Subset of infile contained in a seqID set

	"""
	if isinstance(infilelist, str):
		infilelist = infilelist.split(",")
	clade_set = set()
	for infile in infilelist:
		with open(infile, "rt") as f:
			for x in f:
				seqid = x.split("\t")[0]
				if seqid in hmmids_nt:
					clade_set.add(seqid)

	return clade_set

# def hmm_hits(genefile):
# 	#provide a set of all hmmer hits
# 	if genefile == "batch":
# 		files = [x for x in os.listdir(".") if x.endswith("table.txt")]
# 	else:
# 		files = genefile.split(",")
# 	files.sort()
# 	hmmids_nt = set()
# 	for file in files:
# 		with open(file) as f:
# 			for line in f:
# 				if "inclusion threshold" in line or "Domain annotation" in line:
# 					print("HMMER inclusion threshold reached, wrapping up...")
# 					break
# 				line = line.split()
# 				if len(line) < 9:
# 					continue
# 				if  line[0] != "#":
# 					item = line[8]
# 					if not item.startswith("MATOU"):
# 						print("Problem with line", " ".join(line))
# 					#modify item so that prodigal appendix is removed ==> gene ID
# 					#item = item[:item.rfind("_")]
# 					hmmids_nt.add(item)
#
# 	return hmmids_nt

def hmm_hits_thresholded(genefile):
	"""Provides a set of thresholded hmmer hits;
	Expects one file from function "occurrence" but can work with multiple,
	e.g. to process entire pathways.

	Input		List of files as a ","-separated string

	Returns 	Set of seqIDs from HMMER hmmids_nt_filtered.

	"""
	if genefile == "batch":
		files = [x for x in os.listdir(".") if x.endswith("table.txt")]
	else:
		files = genefile.split(",")
	files.sort()
	multidomain = set()
	written = {} #move multidomain, written into the for loop to have domain-specific files
	for file in files:
		with open(file) as infile:
			for line in infile:
				if "inclusion threshold" in line or "Domain annotation" in line:
					print("HMMER inclusion threshold reached, wrapping up...")
					break
				line = line.split()
				if len(line) < 9:
					continue
				if  line[0] != "#":
					try:
						evalue = float(line[0])
						#seqname = line[8][:line[8].rfind("_")] #trim the prodigal appendix
						seqname = line[8].split("_")[1] #extract raw seqID
						#print(seqname)
						if seqname in written:
							pass
						elif evalue < 1: #which is the usual case for hits above inclusion threshold
							written[seqname] = line[8]
							multidomain.add(seqname)
						elif seqname in multidomain: #another weak domain found in the same seq
							written[seqname] = line[8]
						else: #when there is a weak domain in the target
							multidomain.add(seqname)
					except ValueError:
						pass
						#this is not a score table line
	return written

def writeseqs(fastadb, genefile, lineagefile):
	"""Writes a subset of MATOU database that were found as HMM hits

	Input:		List of SeqIDs

	Returns:	Writes a file

	"""
	#prepare a file list
	if genefile == "batch":
		files = [x for x in os.listdir(".") if x.endswith("table.txt")]
	else:
		files = genefile.split(",")
	files.sort()
	print("Files to be processed", ", ".join(files))

	global hmmids_nt
	hmmids_nt = hmm_hits_thresholded(genefile)
	if lineagefile != "":
		lineage_subset = make_clade_set(lineagefile)
		if len(lineage_subset) > 0:
			hmmids_nt_filtered = { x: hmmids_nt[x] for x in hmmids_nt.keys() if x in lineage_subset }
	else:
		hmmids_nt_filtered = hmmids_nt
	hmmids_aa = set(hmmids_nt_filtered.values())
	print(type(hmmids_aa))

	print("Total of {} hits found".format(len(hmmids_nt)))
	if lineagefile != "":
		print("Filtered hits: {}".format(len(hmmids_nt_filtered)))
	print("Examples:", [x for x in itertools.islice(hmmids_nt_filtered, 10)])
	print("Example seqids:", [x for x in itertools.islice(hmmids_aa, 10)])

	#filter seqs identified as hits
	print("Now to extract sequences from db file", fastadb)
	if len(files) == 1:
		#single file mode
		file = files[0]
		print("Processing for FASTA extraction:", file)
		outname = file.replace(".table.txt", "-dbhits.fasta")
		with open(file) as infile, open(outname, "w") as result:
			if fastadb.split(".")[-1] in ("fasta", "fas", "faa"):
				fastafile = SeqIO.parse(fastadb, "fasta")
				for seq in fastafile:
					if seq.name in hmmids_aa:
						result.write(">{}\n{}\n".format(seq.name, str(seq.seq).replace("*", "")))
			elif fastadb.endswith("gz"):
				with gzip.open(fastadb, "rt") as unzipped:
					for seq in SeqIO.parse(unzipped, "fasta"):
						if seq.name in hmmids_aa:
							result.write(">{}\n{}\n".format(seq.name, str(seq.seq).replace("*", "")))
			else:
				quit("fasta database invalid format")

	else:
		seq_d = {}
		print("Warning, script will run silently for a long time!")
		if fastadb.split(".")[-1] in ("fasta", "fas", "faa"):
			fastafile = SeqIO.parse(fastadb, "fasta")
			for seq in fastafile:
				if seq.name in hmmids_aa:
					seq_d[seq.name] = str(seq.seq).replace("*", "")
		elif fastadb.endswith("gz"):
			with gzip.open(fastadb, "rt") as fastafile:
				for seq in SeqIO.parse(fastafile, "fasta"):
					if seq.name in hmmids_aa:
						seq_d[seq.name] = str(seq.seq).replace("*", "")
		else:
			quit("fasta database invalid format")
		print("Total of {} sequences matched hits".format(len(seq_d.keys())))

		#filter results and export fasta
		for file in files:
			print("Processing for FASTA extraction:", file)
			multidomain = set()
			written = set() #move multidomain, written into the for loop to have domain-specific files
			name = file.replace(".table.txt", "-dbhits.fasta")
			with open(file) as infile, open(name, "w") as result:
				for line in infile:
					if "inclusion threshold" in line or "Domain annotation" in line:
						print("HMMER inclusion threshold reached, wrapping up...")
						break
					line = line.split()
					if len(line) < 9:
						continue
					if  line[0] != "#":
						#seqnames match between prodigal faa and hmmer hit hmmids_aa
						seqname = line[8]
						if seqname in hmmids_aa:
							result.write(">{}\n{}\n".format(seqname, seq_d[seqname]))
	print("Sequence extraction finished!")

def main():
	parser = argparse.ArgumentParser(description='How to use argparse')
	parser.add_argument('-f', '--infile', help='Fasta database file to process', default='/mnt/mokosz/home/zoli/proj/MATOU/MATOU-v1.prodigal.faa.gz')
	parser.add_argument('-l', '--lineage', help='Lineage filter', default='')
	parser.add_argument('-d', '--directory', help='Workdirectory', default='.')
	parser.add_argument('-g', '--genefile', help='Gene file', default='batch')
	parser.add_argument('-e', '--export_hits', help='Write HMMER hits as fasta', action='store_true')

	args = parser.parse_args()
	if args.directory != ".":
		os.chdir(args.directory)
	if args.export_hits:
		writeseqs(args.infile, args.genefile, args.lineage)

if __name__ == '__main__':
	main()


from django.test import TestCase

from pygipo.models import memoize, Dump

class TestMemoize(TestCase):

    @staticmethod
    def _get_xs():
        return [
            {'a': 23},
            {'b': 12}
        ]

    def test(self):
        dump = Dump.create()

        @memoize(entity='fooentity', dump=dump)
        def get_xs():
            return self._get_xs()

        xs1 = get_xs()
        xs2 = get_xs()

        for x1, x2 in zip(xs1, xs2):
            self.assertDictEqual(x1, x2)

        for rec, x in zip(dump.records, xs1):
            self.assertDictEqual(rec.json, x)

    def test_latest_dump(self):
        @memoize('barentity')
        def bars():
            return self._get_xs()

        xs1 = bars()
        xs2 = bars()

        for x1, x2 in zip(xs1, xs2):
            self.assertDictEqual(x1, x2)

        dump = Dump.objects.latest()
        for rec, x in zip(dump.records, xs1):
            self.assertDictEqual(rec.json, x)

    def test_no_unpack(self):
        @memoize('barentity', unpack=False)
        def bars():
            return self._get_xs()

        xs1 = bars()
        xs2 = bars()

        for x1, x2 in zip(xs1, xs2):
            self.assertDictEqual(x1, x2)

        dump = Dump.objects.latest()
        rec = dump.record_set.first()
        self.assertEqual(rec.json, xs1)


import pya

def merge():
    files = file2.split(",")
    opt = pya.LoadLayoutOptions()
    opt_oas = pya.SaveLayoutOptions()
    ly = pya.Layout()

    for file in files:
        lmap = ly.read(file1)

        ly = change_uid(ly)

        opt.set_layer_map(lmap, True)
        ly.read(file, opt)

        ly.write(output)

    for cells in ly.each_cell():
        ci = cells.cell_index()
        if "$" in cells.name:
            ly.delete_cell_rec(ci)

    opt_oas.set_format_from_filename(output)
    opt_oas.oasis_substitution_char=''
    ly.write(output, opt_oas)

def change_uid(lib):
    for cells in lib.each_cell():
        ci = cells.cell_index()
        if "xxxxyyyy" in cells.name:
            name = cells.name.replace("xxxxyyyy", user_id)
            lib.rename_cell(ci, name)
    return lib

if __name__ == "__main__":
    output = "caravel_" + user_id + ".oas"
    merge()


import pandas as pd
import cx_Oracle

# 오라클 연결 및 접속하기
def getConnection() :
    # 오라클 연결하기
    dsn = cx_Oracle.makedsn("localhost", 1521, "orcl")

    # 오라클 접속하기
    conn = cx_Oracle.connect("busan_06", "dbdb", dsn)
    return conn

# 커서 받기
def getCursor(conn) :
    cursor = conn.cursor()
    return cursor

# 접속정보 및 커서 반납하기
def dbClose(cursor, conn) :
    # 커서 반납 먼저
    cursor.close()
    # 마지막에 접속정보 반납
    conn.close()

### 딕셔너리 주문내역 전체조회
def getDBTest() :
    conn = getConnection()
    cursor = getCursor(conn)

    sql = """ SELECT * FROM cart """
    cursor.execute(sql)

    row = cursor.fetchall()

    dbClose(cursor, conn)

    return row

############# survey 테이블 생성하기 #############
def createTableSurvey() :
    conn = getConnection()
    cursor = getCursor(conn)

    sql = """Create Table survey
            (
                rnum number(15) not null,
                gender varchar2(20) not null,
                age number(15) not null,
                co_survey varchar2(50) not null,
                Constraint pk_rnum Primary key(rnum)
            )"""

    cursor.execute(sql)

    dbClose(cursor, conn)

# 설문 입력하기
def setSurveyInsert(pgender, page, pco_survey) :
    conn = getConnection()
    cursor = getCursor(conn)

    # rnum 자동 생성하기
    sql = """SELECT nvl(max(rnum)+1, 1) as max_no
                FROM survey"""
    cursor.execute(sql)
    rs_max_no = cursor.fetchone()
    no = rs_max_no[0]

    # 저장하기
    sql = """INSERT INTO survey(
                rnum, gender, age, co_survey
                ) values(
                    :rnum, :gender, :age, :co_survey
                )"""
    cursor.execute(sql,
                    rnum = no,
                    gender = pgender,
                    age = page,
                    co_survey = pco_survey)
    conn.commit()

    dbClose(cursor, conn)
    return "OK"

def getSurveyList() :
    conn = getConnection()
    cursor = getCursor(conn)

    sql = """ SELECT * FROM survey """
    cursor.execute(sql)

    row = cursor.fetchall()

    # 컬럼명 조회하기
    colname = cursor.description
    col = []
    for i in colname :
        col.append(i[0].lower())

    dbClose(cursor, conn)

    # 데이터 프레임에 조회 결과 넣기
    df = pd.DataFrame(row, columns = col)

    return df


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 23 11:51:16 2021

@author: michaeltown
"""

# NWAC data EDA analysis of the Heather Meadows and Pan Dome data

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

import os
import datetime as dt

def seasonFilter(x):

    if (x > 11) | (x < 3):
        return 'djf';
    elif (x >2) & (x <6 ):
        return 'mam';
    elif (x >5) & (x < 9):
        return 'jja';
    elif (x >8) & (x <12 ):
        return 'son';
    else:
        print('I do not recognize that month value. Returning NaN.');
        return np.nan;

# function to convert degF to degC
def convertFtoC(tf):
    return (tf-32)*5/9;

# function to convert mph to m/s
def convertwsMPHtoMS(ws):
    return ws*0.44704;

# function to convert in to mm
def convertprecipIntomm(p):
    return p*25.4;

def myHistFunc(x,ra,xll,xlu,yll,ylu,title,xlab,ylab,fileloc,filename):
    fig1 = plt.figure();
    plt.hist(x,bins = ra,color = 'blue',alpha = 0.5, density = True);
    plt.xlim([xll,xlu]);
    plt.ylim([yll,ylu]);
    plt.title(title);
    plt.ylabel(ylab);
    plt.xlabel(xlab);
    plt.text((xlu-xll)*2/3+xll,(ylu-yll)/2+yll,'n = '+str(len(x)));
    plt.text((xlu-xll)*2/3+xll,(ylu-yll)/2+yll-(ylu-yll)/10,'mean = '+str(np.round(np.mean(x),2)));
    plt.text((xlu-xll)*2/3+xll,(ylu-yll)/2+yll-2*(ylu-yll)/10,'stdev = '+str(np.round(np.std(x),2)));
    os.chdir(fileloc)
    fig1.savefig(filename+'.jpg')

# load the data framces
os.chdir('/home/michaeltown/work/metis/modules/linearRegressionWebScraping/data/');

pdDF = pd.read_csv('MtBaker-PanDome2014-2021.csv');
hmDF = pd.read_csv('MtBaker-HeatherMeadows2014-2021.csv');

# strip all columns of spaces and make all letters lowercase

pdDF.columns = pdDF.columns.str.replace(' ','').str.lower().str.replace('/','').str.replace('(','').str.replace(')','').str.replace(')','').str.replace('%','').str.replace('"','').str.replace('.','');
hmDF.columns = hmDF.columns.str.replace(' ','').str.lower().str.replace('/','').str.replace('(','').str.replace(')','').str.replace(')','').str.replace('%','').str.replace('"','').str.replace('.','');

# convert to pandas date/time
pdDF.datetimepst = pd.to_datetime(pdDF.datetimepst);
hmDF.datetimepst = pd.to_datetime(hmDF.datetimepst);

# prep the time series for daily, monthly, and seasonal composites - some conversions to SI units
pdDF['date'] = pd.to_datetime(pdDF.datetimepst.dt.date);
pdDF['month'] = pdDF.datetimepst.dt.month;
pdDF['year'] = pdDF.datetimepst.dt.year;
pdDF['season'] = pdDF.month.apply(seasonFilter);
pdDF['Tc'] = pdDF.temperaturedegf.apply(convertFtoC);
pdDF['precipitation'] = pdDF.precipitation.apply(convertprecipIntomm);
pdDF['wsAvgMs'] = pdDF.windspeedaveragemph.apply(convertwsMPHtoMS);
pdDF['wsMinMs'] = pdDF.windspeedminimummph.apply(convertwsMPHtoMS);
pdDF['wsMaxMs'] = pdDF.windspeedmaximummph.apply(convertwsMPHtoMS);

hmDF['date'] = pd.to_datetime(hmDF.datetimepst.dt.date);
hmDF['month'] = hmDF.datetimepst.dt.month;
hmDF['year'] = hmDF.datetimepst.dt.year;
hmDF['season'] = hmDF.month.apply(seasonFilter);
hmDF['Tc'] = hmDF.temperaturedegf.apply(convertFtoC);
hmDF['precipitation'] = hmDF.precipitation.apply(convertprecipIntomm);
hmDF['wsAvgMs'] = hmDF.windspeedaveragemph.apply(convertwsMPHtoMS);
hmDF['wsMinMs'] = hmDF.windspeedminimummph.apply(convertwsMPHtoMS);
hmDF['wsMaxMs'] = hmDF.windspeedmaximummph.apply(convertwsMPHtoMS);

# TODO in this space, please drop all the unnecessary columns

# plot the initial EDA histograms
fileLoc = '/home/michaeltown/work/metis/modules/linearRegressionWebScraping/figures/nwacFigures/';
myHistFunc(pdDF.Tc,range(-50,50,1),-50,50,0,0.15,'Temperature for Pan Dome, 5020 ft, Mt. Baker (2014-2021)','Temperature ($^\circ$C)'
           ,'Fraction',fileLoc,'Tc_panDomeMtBakerhist_2014-2021');

myHistFunc(pdDF.wsAvgMs,range(-2,30,1),-2,30,0,0.3,'Wind Speed for Pan Dome, 5020 ft, Mt. Baker (2014-2021)','Wind Speed (m/s)'
           ,'Fraction',fileLoc,'wsAvg_panDomeMtBakerhist_2014-2021');

myHistFunc(pdDF.winddirectiondeg,range(-0,361,1),-5,365,0,0.01,'WDir for Pan Dome, 5020 ft, Mt. Baker (2014-2021)','Wind Dir (deg)'
           ,'Fraction',fileLoc,'wdir_panDomeMtBakerhist_2014-2021');

# heather meadows
myHistFunc(hmDF.Tc,range(-50,50,1),-50,50,0,0.15,'Temperature for Heather Meadows, 4210 ft, Mt. Baker (2014-2021)','Temperature ($^\circ$C)'
           ,'Fraction',fileLoc,'Tc_heatherMeadowsMtBakerhist_2014-2021');

myHistFunc(hmDF.precipitation,np.arange(0,10,1),0,10,0,1,'Precip for Heather Meadows, 4210 ft, Mt. Baker (2014-2021)','Precip (mm)'
           ,'Fraction',fileLoc,'Precip_heatherMeadowsMtBakerhist_2014-2021');

#
#myHistFunc(pdDF.wsAvgMs,range(-2,30,1),-2,30,0,0.3,'Wind Speed for Heather Meadows, 4210 ft, Mt. Baker (2014-2021)','Wind Speed (m/s)'
#           ,'Fraction',fileLoc,'wsAvg_heatherMeadowsMtBakerhist_2014-2021');

# yearsNWAC = range(2014,2022,1);
months = range(1,13,1);
monthListH = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
monthList = ['01','02','03','04','05','06','07','08','09','10','11','12'];
monDictH = dict(zip(months,monthListH));
monDict = dict(zip(months,monthList));
yearsNWAC = range(2014,2022,1);

for y in yearsNWAC:

    for m in months:
        myHistFunc(pdDF[(pdDF.year==y)&(pdDF.month == m)].Tc,range(-50,50,1),-50,50,0,0.15,'T ($^\circ$C) for Pan Dome ('+monDictH[m]+', '+str(y)+') , 5020 ft, Mt. Baker (2014-2021)','Temperature ($^\circ$C)'
           ,'Fraction',fileLoc,'Tc_panDomeMtBakerhist_'+str(y)+monDict[m]);

        myHistFunc(pdDF[(pdDF.year==y)&(pdDF.month == m)].wsAvgMs,range(-2,30,1),-2,30,0,0.3,'WS for Pan Dome ('+monDictH[m]+', '+str(y)+'), 5020 ft, Mt. Baker (2014-2021)','Wind Speed (m/s)'
           ,'Fraction',fileLoc,'wsAvg_panDomeMtBakerhist_'+str(y)+monDict[m]);

        myHistFunc(pdDF[(pdDF.year==y)&(pdDF.month == m)].winddirectiondeg,range(-0,361,1),-5,365,0,0.10,'WDir for Pan Dome ('+monDictH[m]+', '+str(y)+'), 5020 ft, Mt. Baker (2014-2021)','Wind Dir (deg)'
           ,'Fraction',fileLoc,'wdir_panDomeMtBakerhist_'+str(y)+monDict[m]);

        myHistFunc(hmDF[(pdDF.year==y)&(pdDF.month == m)].Tc,range(-50,50,1),-50,50,0,0.15,'T ($^\circ$C) for Heath Mead ('+monDictH[m]+', '+str(y)+'), 4250 ft, Mt. Baker (2014-2021)','Temperature ($^\circ$C)'
           ,'Fraction',fileLoc,'Tc_heatherMeadowsMtBakerhist_'+str(y)+monDict[m]);

        myHistFunc(hmDF.precipitation[(pdDF.year==y)&(pdDF.month == m)],np.arange(0,10,1),0,10,0,1,'Precip for Heather Meadows, 4210 ft, Mt. Baker ('+monDictH[m]+', '+str(y)+')','Precip (mm)'
           ,'Fraction',fileLoc,'Precip_heatherMeadowsMtBakerhist_'+str(y)+monDict[m]);

# # group by date
# pdDFdateGmean = pdDF.groupby(['date'])['Tc','relativehumidity','wsAvgMs','winddirectiondeg'].mean();
# pdDFdateGstd = pdDF.groupby(['date'])['Tc','relativehumidity','wsAvgMs'].agg(np.std);
# pdDFdateGmax = pdDF.groupby(['date'])['Tc','relativehumidity','wsAvgMs'].max();
# pdDFdateGmin = pdDF.groupby(['date'])['Tc','relativehumidity','wsAvgMs'].max();

# pdDFdateGmean = pdDFdateGmean.unstack(level= 1);
# pdDFdateGstd = pdDFdateGstd.unstack(level = 1);
# pdDFdateGmax = pdDFdateGmax.unstack(level = 1);
# pdDFdateGmin = pdDFdateGmin.unstack(level = 1);

# pickle the data frames

pdDF.to_pickle("../data/panDomeDF2014-2021.pkl")
hmDF.to_pickle("../data/heatherMeadowsDF2014-2021.pkl")


from django.shortcuts import render
from apps.resume import models

# Create your views here.
def get_resume(request):
    general_info = models.GenericInformation.objects.all()[0]
    skills = models.Skill.objects.all()
    schools = models.EducationalInstitution.objects.all()

    return render(
        request=request,
        template_name='resume/resume.html',
        context= {
            "general" : general_info,
            "skills" : skills,
            "schools" : schools
            }
        )


"""
Author: Darren
Date: 19/03/2021

Solving https://adventofcode.com/2015/day/20

Infinite elves deliver to infinite houses numbered sequentially.
Each elf is assigned a number and a progression.
Elf e visits houses eh. E.g.
    elf 1 visits 1, 2, 3, 4, 5, 6, 7, 8, 9 ...
    elf 2 visits    2     4     6     8    ...
    elf 3 visits       3        6        9 ...

At each house h, elf e delivers 10x presents.  Thus:
house 1 gets 10, house 2 gets 30, house 3 gets 40...

Solution:
    My approach seems inefficient.  It takes ~30s for both parts.

Part 1:
    E.g. for house 6, we must determine all factors of 6.  Why?
    Because the factors are the elves that will visit this house.
    Thus, house 6 is visted by elves 1, 2, 3, and 6.

    Use a generator to get factors for next house.
    Use a map to multiply each factor by the per_elf number.

Part 2:
    Elves now have a limit on the number of houses they visit. (50.)
    So, we need to count the occurences of each factor (i.e. each elf visit).
    When each elf reaches its limit of visits, add them to an exclude list.
    Use set difference to remove these from factors returned.
    (Having the exclude list as a set rather than a list is MUCH faster!)
"""
import os
import time
from collections import defaultdict

SCRIPT_DIR = os.path.dirname(__file__)
INPUT_FILE = "input/input.txt"
SAMPLE_INPUT_FILE = "input/sample_input.txt"

TARGET = 36000000
MAX_HOUSES_PER_ELF = 50

def main():

    # Part 1
    gen = generate_presents_for_house(10)
    presents_dropped = 0
    house = 0
    while presents_dropped < TARGET:
        house, presents_dropped = next(gen)

    print(f"Part 1: House {house} = {presents_dropped}")

    # Part 2
    gen = generate_presents_for_house(11, MAX_HOUSES_PER_ELF)
    presents_dropped = 0
    house = 0
    while presents_dropped < TARGET:
        house, presents_dropped = next(gen)

    print(f"Part 2: House {house} = {presents_dropped}")

def generate_presents_for_house(per_elf_multiplier: int, elf_visit_limit: int = 0):
    """
    Generator function that returns the number of presents dropped at a given house.
    Each elf drops a certain number of presents at each house

    Args:
        per_elf_multiplier (int): Elves drop e*q presents per house, where e is elf number and q is the multiplier

    Yields:
        [tuple]: Current house number, total presents dropped at this house
    """
    house_num = 1
    factors_for_house = set()
    factors_counter = defaultdict(int)
    factors_to_exclude = set()

    while True:
        factors_for_house = get_factors(house_num)
        factors_for_house.difference_update(factors_to_exclude)

        for factor in factors_for_house:
            factors_counter[factor] += 1

            # if an elf has reached the limit, it won't do any more drops
            if elf_visit_limit and factors_counter[factor] >= elf_visit_limit:
                factors_to_exclude.add(factor)

        presents_dropped = sum(map(lambda x: (x * per_elf_multiplier), factors_for_house))

        # print(f"House {house_num} visited by: {factors_for_house[house_num]}")
        # print(f"Presents dropped: {presents_dropped}")
        # print(f"Factors counter: {factors_counter}")

        yield house_num, presents_dropped
        house_num += 1

def get_factors(num: int) -> set[int]:
    """
    Gets the factors for a given house number.
    Here, this determines the elves that visit each house.

    Args:
        num (int): the house number we want to get factors for

    Returns:
        set[int]: The set of factors (which represent elf numbers)
    """
    factors = set()

    # E.g. factors of 8 = 1, 2, 4, 8
    # Iterate from 1 to sqrt of 8, where %=0, i.e. 1 and 2
    # E.g. for i=1, we add factors 1 and 8
    #      for i=2, we add factors 2 and 4
    # Use a set to eliminate duplicates, e.g. if i is 4, we only want one 2
    for i in range(1, (int(num**0.5) + 1)):
        if num%i == 0:
            factors.add(i)
            factors.add(num//i)

    return factors

if __name__ == "__main__":
    t1 = time.perf_counter()
    main()
    t2 = time.perf_counter()
    print(f"Execution time: {t2 - t1:0.4f} seconds")


from time import time, strftime, gmtime

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt

from torchvision import datasets, transforms
from torch.optim.lr_scheduler import StepLR
from torchsummary import summary
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.metrics import ConfusionMatrixDisplay

def time_counter(func):
    def wrapper(*args, **kwargs):
        ts = time()
        result = func(*args, **kwargs)
        te = time()
        delta = te - ts
        print(f'{func.__name__} выполнялся {strftime("%H:%M:%S", gmtime(delta))}')
        return result
    return wrapper

def print_metrics_scores(scores: dict) -> None:
    print(f'confusion_matrix: \n{scores.get("confusion_matrix")}')
    print(f'classification_report: \n{scores.get("classification_report")}')

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 50, 3, 1)             # 3*3*1*50+50 = 500
        self.conv2 = nn.Conv2d(50, 20, 3, 1)            # 3*3*50*20+20 = 9020
        self.conv3 = nn.Conv2d(20, 8, 3, 1)            # 3*3*20*8+8 = 1448
        self.dropout1 = nn.Dropout(0.25)                # <- 0
        self.dropout2 = nn.Dropout(0.5)                 # <- 0
        self.fc1 = nn.Linear(200, 128)                  # <- 200*128+128 = 25728
        self.fc2 = nn.Linear(128, 10)                   # <- 128*10+10 = 1290
        self.batch_norm = torch.nn.BatchNorm1d(200)     # <- 200*2 = 400
                                                        # Total: 38386
    def forward(self, x):           # 200, 1, 28, 28
        x = self.conv1(x)           # 200, 50, 26, 26
        x = F.relu(x)               # 200, 50, 26, 26
        x = self.conv2(x)           # 200, 20, 24, 24
        x = F.relu(x)               # 200, 20, 24, 24
        x = F.max_pool2d(x, 2)      # 200, 20, 12, 12
        x = self.conv3(x)           # 200, 8, 10, 10
        x = F.relu(x)               # 200, 8, 10, 10
        x = F.max_pool2d(x, 2)      # 200, 8, 5, 5
        x = self.dropout1(x)        # 200, 8, 5, 5
        x = torch.flatten(x, 1)     # 200, 8*5*5 = 200
        x = self.batch_norm(x)      # 200, 200
        x = self.fc1(x)             # 200, 128
        x = F.relu(x)               # 200, 128
        x = self.dropout2(x)        # 200, 128
        output = self.fc2(x)        # 200, 10
        return output

def model_train(model, device, train_loader, optimizer, epoch, loss_fn):
    train_loss = 0
    correct = 0
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = loss_fn(output, target)
        train_loss += loss.item()
        pred = output.argmax(dim=1, keepdim=True)
        correct += pred.eq(target.view_as(pred)).sum().item()
        loss.backward()
        optimizer.step()
        if batch_idx % 100 == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch + 1, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
    train_loss /= len(train_loader.dataset)
    train_loss_list.append(train_loss)
    train_accuracy = correct / len(train_loader.dataset)
    train_accuracy_list.append(train_accuracy)

def model_test(model, device, test_loader, loss_fn):
    model.eval()
    test_loss = 0
    correct = 0
    all_target = []
    all_pred = []
    classification_metrics_dict = {}
    with torch.no_grad():
        for batch_idx_, (data, target) in enumerate(test_loader):
            data, target = data.to(device), target.to(device)
            output = model(data)
            # sum up batch loss
            test_loss += loss_fn(output, target).item()
            # get the index of the max log-probability
            pred = output.argmax(dim=1, keepdim=True)
            correct += pred.eq(target.view_as(pred)).sum().item()
            all_target = [*all_target, *target.tolist()]
            all_pred = [*all_pred, *pred.tolist()]
            if batch_idx_ == len(test_loader) - 1:
                target_names = ['cls 0', 'cls 1', 'cls 2', 'cls 3', 'cls 4',
                                'cls 5', 'cls 6', 'cls 7', 'cls 8', 'cls 9']
                all_target = torch.Tensor(all_target)
                all_pred = torch.Tensor(all_pred)
                classification_metrics_dict.update({
                    'confusion_matrix': confusion_matrix(all_target, all_pred),
                    'classification_report': classification_report(all_target, all_pred, target_names=target_names)
                })
                print_metrics_scores(classification_metrics_dict)
                disp = ConfusionMatrixDisplay(
                    confusion_matrix=classification_metrics_dict['confusion_matrix'],
                    display_labels=target_names
                )
                disp.plot()
                plt.savefig(f"Confusion_matrix.png")
                plt.close()

    test_loss /= len(test_loader.dataset)
    test_loss_list.append(test_loss)
    test_accuracy = correct / len(test_loader.dataset)
    test_accuracy_list.append(test_accuracy)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * test_accuracy))

@time_counter
def main():

    torch.manual_seed(1337)

    device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
    print(device)

    batch_size_ds = 200
    train_kwargs = {'batch_size': batch_size_ds}
    test_kwargs = {'batch_size': batch_size_ds}

    transform = transforms.Compose([
        transforms.ToTensor(),
    ])
    train_dataset = datasets.MNIST('./mnsit-dataset', train=True, download=True,
                              transform=transform)
    test_dataset = datasets.MNIST('./mnsit-dataset', train=False,
                              transform=transform)
    train_loader = torch.utils.data.DataLoader(train_dataset, **train_kwargs)
    test_loader = torch.utils.data.DataLoader(test_dataset, **test_kwargs)

    epochs = 5

    model = Net().to(device)
    optimizer = optim.Adadelta(model.parameters(), lr=0.1)
    loss_fn = torch.nn.CrossEntropyLoss()

    scheduler = StepLR(optimizer, step_size=1, gamma=0.5)
    for epoch in range(epochs):
        model_train(model, device, train_loader, optimizer, epoch, loss_fn)
        model_test(model, device, test_loader, loss_fn)
        scheduler.step()

    torch.save(model.state_dict(), "mnist_cnn.pt")
    print(f"# Params: {sum(p.numel() for p in model.parameters() if p.requires_grad)}")
    print(model)
    print(summary(model, input_size=(1, 28, 28)))

def plot_curve(title_: str, xlabel_: str, ylabel_: str,
               curve_list_1: list, curve_list_2: list, curve_label_1: str,
               curve_label_2: str, file_name: str) -> None:
    fig, ax = plt.subplots(figsize=(8, 8))
    plt.title(f'{title_}')
    plt.xlabel(f'{xlabel_}')
    plt.ylabel(f'{ylabel_}')
    ax.plot(np.arange(0, len(curve_list_1), 1), curve_list_1, "o-", label=curve_label_1)
    ax.plot(np.arange(0, len(curve_list_2), 1), curve_list_2, "o-", label=curve_label_2)
    ax.legend(loc="best")

    plt.savefig(f"{file_name}")
    plt.close()

if __name__ == '__main__':
    # Init lists
    train_loss_list = []
    test_loss_list = []
    train_accuracy_list = []
    test_accuracy_list = []

    main()

    # Plot results
    plot_curve('Loss function', 'Samples', 'Loss',
               train_loss_list, test_loss_list,
               "Train loss", "Test loss", "Loss.png")
    plot_curve('Loss function', 'Samples', 'Loss',
               train_loss_list, test_loss_list,
               "Log train loss", "Log test loss", "Loss_log.png")
    plot_curve('Accuracy curve', 'Epoch', 'Accuracy',
               train_accuracy_list, test_accuracy_list,
               "Train", "Test", "Accuracy curve.png")


import sys
from collections import defaultdict
input = sys.stdin.readline

N, M = map(int, input().split())
rooms = defaultdict(list)
player = defaultdict(list)

for _ in range(N):
    l, n = input().split()
    player[n] = int(l)

idx = 1
for n, l in player.items():
    for i, v in rooms.items():
        if len(v) == M:
            continue

        if player[v[0]]-10 <= l <= player[v[0]]+10:
            rooms[i].append(n)
            break
    else:
        rooms[idx].append(n)
        idx += 1

for k, v in t.items():
    print("Started!" if len(v) == M else "Waiting")
    v = sorted(v)
    for n in v:
        print(player[n], n)


# License: GNU Affero General Public License v3 or later
# A copy of GNU AGPL v3 should have been included in this software package in LICENSE.txt.

""" Results classes for the sideloader module
"""

import dataclasses
from typing import Any, Dict, List, Union

from antismash.common.secmet import Protocluster, Record, SubRegion, FeatureLocation
from antismash.common.secmet.features.protocluster import SideloadedProtocluster
from antismash.common.secmet.features.subregion import SideloadedSubRegion
from antismash.common.module_results import DetectionResults

@dataclasses.dataclass(frozen=True)
class SideloadSimple:
    """ A simple frozen container for the sideload-simple argument values """
    accession: str
    start: int
    end: int

def _qualifier_mapping(original: Dict[str, Any]) -> Dict[str, List[str]]:
    """ Converts a dictionary mapping strings to any type to
        a dictionary mapping strings to strings
    """
    result: Dict[str, List[str]] = {}
    for key, val in original.items():
        if isinstance(val, str):
            val = [val]
        else:
            val = list(map(str, val))
        result[key] = val
    return result

@dataclasses.dataclass(frozen=True, eq=True, order=True, unsafe_hash=True)
class Tool:
    """ A collection of details about the tool responsible for annotations """
    name: str
    version: str
    description: str
    configuration: Dict[str, List[str]]

    def __post_init__(self) -> None:
        for i in self.name:
            if not i.isalpha() and i not in "_- ":
                raise ValueError(f"invalid character in tool name: '{i}'")

    def to_json(self) -> Dict[str, Any]:
        """ Convert a Tool instance to JSON """
        return dataclasses.asdict(self)

    @classmethod
    def from_json(cls, raw: Dict[str, Any]) -> "Tool":
        """ Rebuild a Tool instance from JSON """
        return cls(
            str(raw["name"]),
            str(raw["version"]),
            str(raw.get("description", "")),
            _qualifier_mapping(raw.get("configuration", {})),
        )

class SubRegionAnnotation:
    """ A class for containing arbitrary data about a sideloaded subregion annotation """
    kind = "subregion"

    def __init__(self, start: int, end: int, label: str, tool: Tool, details: Dict[str, List[str]]) -> None:
        if end <= start:
            raise ValueError("area end must be greater than area start")
        self.start = start
        self.end = end
        self.label = label
        self.details = details
        assert isinstance(tool, Tool)
        self.tool = tool

    def __len__(self) -> int:
        return self.end - self.start

    def to_secmet(self) -> SideloadedSubRegion:
        """ Constructs a SideloadedSubRegion instance from the annotation """
        location = FeatureLocation(self.start, self.end)
        return SideloadedSubRegion(location, self.tool.name, label=self.label, extra_qualifiers=self.details)

    def to_json(self) -> Dict[str, Any]:
        """ Converts the annotation to JSON (separate from the JSON schema)"""
        result = dict(vars(self))
        result["tool"] = self.tool.to_json()
        return result

    @classmethod
    def from_json(cls, raw: Dict[str, Any]) -> "SubRegionAnnotation":
        """ Reconstructs an annotation from JSON (separate from the JSON schema)"""
        return cls(
            int(raw["start"]),
            int(raw["end"]),
            str(raw["label"]),
            Tool.from_json(raw["tool"]),
            _qualifier_mapping(raw.get("details", {})),
        )

    @classmethod
    def from_schema_json(cls, raw: Dict[str, Any], tool: Tool) -> "SubRegionAnnotation":
        """ Builds an instance from JSON matching the protocluster schema, along with a tool """
        raw["tool"] = tool.to_json()
        return cls.from_json(raw)

    def __eq__(self, other: Any) -> bool:
        if not isinstance(other, SubRegionAnnotation):
            return False
        return vars(self) == vars(other)

    def __str__(self) -> str:
        return f"Subregion({self.tool.name}, {self.start}-{self.end}, {self.label})"

class ProtoclusterAnnotation:
    """ A class for containing arbitrary data about a sideloaded protocluster annotation """
    kind = "protocluster"

    def __init__(self, core_start: int, core_end: int, product: str, tool: Tool, details: Dict[str, List[str]],
                 neighbourhood_left: int = 0, neighbourhood_right: int = 0) -> None:
        if core_end <= core_start:
            raise ValueError("area end must be greater than area start")
        if neighbourhood_left < 0 or neighbourhood_right < 0:
            raise ValueError("neighbourhoods must be annotated as absolute distances, not relative")
        if core_start - neighbourhood_left < 0:
            raise ValueError("neighbourhoods cannot extend out of a record")
        self.core_start = core_start
        self.core_end = core_end
        self.product = product
        assert isinstance(tool, Tool)
        self.tool = tool
        self.details = details
        self.neighbourhood_left = neighbourhood_left
        self.neighbourhood_right = neighbourhood_right

    @property
    def start(self) -> int:
        """ The start of the protocluster, including neighbourhood """
        return self.core_start - self.neighbourhood_left

    @property
    def end(self) -> int:
        """ The end of the protocluster, including neighbourhood """
        return self.core_end + self.neighbourhood_right

    @property
    def label(self) -> str:
        """ The product of the protocluster, for compatibility purposes """
        return self.product

    def __len__(self) -> int:
        return self.core_end + self.neighbourhood_right - self.start

    def to_json(self) -> Dict[str, Any]:
        """ Converts the annotation to JSON (separate from the JSON schema)"""
        res = dict(vars(self))
        res["tool"] = self.tool.to_json()
        return res

    def to_secmet(self) -> SideloadedProtocluster:
        """ Constructs a SideloadedProtocluster instance from the annotation """
        return SideloadedProtocluster(
            FeatureLocation(self.core_start, self.core_end),
            FeatureLocation(self.start, self.end),
            self.tool.name,
            self.product,
            neighbourhood_range=max(self.neighbourhood_left, self.neighbourhood_right),
        )

    @classmethod
    def from_json(cls, raw: Dict[str, Any]) -> "ProtoclusterAnnotation":
        """ Reconstructs an annotation from JSON (separate from the JSON schema)"""
        return cls(
            int(raw["core_start"]),
            int(raw["core_end"]),
            str(raw["product"]),
            Tool.from_json(raw["tool"]),
            _qualifier_mapping(raw.get("details", {})),
            int(raw.get("neighbourhood_left", 0)),
            int(raw.get("neighbourhood_right", 0)),
        )

    @classmethod
    def from_schema_json(cls, raw: Dict[str, Any], tool: Tool) -> "ProtoclusterAnnotation":
        """ Builds an instance from JSON matching the protocluster schema, along with a tool """
        raw["tool"] = tool.to_json()
        return cls.from_json(raw)

    def __eq__(self, other: Any) -> bool:
        if not isinstance(other, ProtoclusterAnnotation):
            return False
        return vars(self) == vars(other)

    def __str__(self) -> str:
        return f"Protocluster({self.tool.name}, {self.start}-{self.end}, {self.product})"

class SideloadedResults(DetectionResults):
    """ A wrapper allowing for different kinds of sideloaded annotations """
    schema_version = 1

    def __init__(self, record_id: str, subregions: List[SubRegionAnnotation],
                 protoclusters: List[ProtoclusterAnnotation]) -> None:
        super().__init__(record_id)
        self.subregions = subregions
        self.protoclusters = protoclusters

    def to_json(self) -> Dict[str, Any]:
        return {
            "record_id": self.record_id,
            "schema_version": self.schema_version,
            "protoclusters": [proto.to_json() for proto in self.protoclusters],
            "subregions": [sub.to_json() for sub in self.subregions],
        }

    @staticmethod
    def from_json(json: Dict[str, Any], record: Record) -> "SideloadedResults":
        if json["schema_version"] != SideloadedResults.schema_version:
            raise ValueError("Detection results have changed. No results can be reused.")

        assert json["record_id"] == record.id
        subs = [SubRegionAnnotation.from_json(sub) for sub in json["subregions"]]
        protos = [ProtoclusterAnnotation.from_json(proto) for proto in json["protoclusters"]]
        return SideloadedResults(json["record_id"], subs, protos)

    def get_areas(self) -> List[Union[ProtoclusterAnnotation, SubRegionAnnotation]]:
        """ Returns a list of all sideloaded annotations """
        areas: List[Union[ProtoclusterAnnotation, SubRegionAnnotation]] = []
        areas.extend(self.subregions)
        areas.extend(self.protoclusters)
        # sort consistently with secmet's region.get_sideloaded_areas()
        return sorted(areas, key=lambda x: (x.start, -len(x), x.tool.name))

    def get_predicted_subregions(self) -> List[SubRegion]:
        return [sub.to_secmet() for sub in self.subregions]

    def get_predicted_protoclusters(self) -> List[Protocluster]:
        return [proto.to_secmet() for proto in self.protoclusters]

    def add_to_record(self, record: Record) -> None:
        for subregion in self.subregions:
            record.add_subregion(subregion.to_secmet())
        for protocluster in self.protoclusters:
            record.add_protocluster(protocluster.to_secmet())


import os
import boto3
from botocore.client import Config
import datetime
from dotenv import load_dotenv
load_dotenv()

today = (datetime.datetime.today()).strftime("%Y-%m-%d")
prev_date = (datetime.datetime.today() - datetime.timedelta(days=1)).strftime("%Y-%m-%d")
print("Today :" , today)
print ("Cleaning for : " ,prev_date)

def main():

    s3 = boto3.resource('s3',
                    endpoint_url=os.getenv('ENDPOINT_URL'),
                    aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
                    aws_secret_access_key=os.getenv('AWS_ACCESS_SECRET'),
                    config=Config(signature_version='s3v4'),
                    region_name=os.getenv('REGION_NAME'))

    database_backup = s3.Bucket(os.getenv('AWS_BUCKET'))
    all_objects = []
    objects_to_delete = [];
    for folder in database_backup.objects.all():
        all_objects.append(folder.key)

    print("All Objects" , all_objects)
    for storage_object in all_objects:
        path,file = storage_object.split("/")
        todays_file = path + "/" + today
        if file.startswith(prev_date,0,10) and any(item.startswith(todays_file) for item in all_objects):
                print(folder.key , "Is eligible for delete.")
                objects_to_delete.append({'Key' : path + "/" + file})

    print("Eligible Objects for delete" , objects_to_delete)
    if objects_to_delete:
        database_backup.delete_objects(
            Delete={
                'Objects': objects_to_delete
            })

if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print("error occurred.",e)


import os
import tempfile
import unittest

import mock

from cloudlib import tests
from cloudlib import parse_ini

class TestConfigFileIni(unittest.TestCase):
    def setUp(self):
        self.logger_patched = mock.patch('cloudlib.parse_ini.logger.getLogger')
        self.logger = self.logger_patched.start()
        self.logger.return_value = tests.Logger()

        self.os_path_patched = mock.patch('cloudlib.parse_ini.os.path.exists')
        self.os_path = self.os_path_patched.start()
        self.os_path.return_value = True

        self.env_patched = mock.patch('cloudlib.parse_ini.os.getenv')
        self.env = self.env_patched.start()

        self.tempfile_patched = mock.patch('tempfile.mkstemp')
        self.tempfile = self.tempfile_patched.start()
        self.tempfile.return_value = ('flag', 'file')

        self.config = parse_ini.ConfigurationSetup()

    def tearDown(self):
        self.logger_patched.stop()
        self.os_path_patched.stop()
        self.env_patched.stop()
        self.tempfile_patched.stop()

    def test_sys_config(self):
        self.config.load_config(name='test')
        self.assertEqual(self.config.config_file, '/etc/test/test.ini')

    def test_sys_config_path(self):
        self.config.load_config(name='test', path='/test/test/test')
        self.assertEqual(self.config.config_file, '/test/test/test/test.ini')

    def test_sys_config_path_ext(self):
        self.config.load_config(name='test', path='/test/test/test', ext='cfg')
        self.assertEqual(self.config.config_file, '/test/test/test/test.cfg')

    def test_sys_config_path_strip_slash(self):
        self.config.load_config(name='test', path='/test/test/test/')
        self.assertEqual(self.config.config_file, '/test/test/test/test.ini')

    def test_sys_config_home(self):
        self.env.return_value = '/home/TestUser'
        self.config.load_config(name='test', home=True)
        self.assertEqual(self.config.config_file, '/home/TestUser/test.ini')

    def test_sys_config_home_ext(self):
        self.env.return_value = '/home/TestUser'
        self.config.load_config(name='test', home=True, ext='cfg')
        self.assertEqual(self.config.config_file, '/home/TestUser/test.cfg')

    def test_sys_config_ext(self):
        self.config.load_config(name='test', ext='cfg')
        self.assertEqual(self.config.config_file, '/etc/test/test.cfg')

    def test_sys_config_path_home_ext(self):
        self.config.load_config(
            name='test', path='/test/test/test', home=True, ext='cfg'
        )
        self.assertEqual(self.config.config_file, '/test/test/test/test.cfg')

    def test_sys_config_not_found(self):
        self.os_path.return_value = False
        self.assertRaises(
            IOError,
            self.config.load_config,
            name='test'
        )

    def test_sys_config_find_config_fail(self):
        self.os_path.return_value = False
        self.assertRaises(
            IOError,
            self.config._find_config,
            'test_file'
        )

    def test_sys_config_perms(self):
        stat = parse_ini.os.stat = mock.Mock()
        stat.return_value = tests.StatResult()
        self.config.config_file = '/test/path/config.ini'
        self.assertEqual(self.config.check_perms(), True)

    def test_sys_config_perms_fail(self):
        stat = parse_ini.os.stat = mock.Mock()
        stat.return_value = tests.StatResult()
        self.config.config_file = '/test/path/config.ini'
        self.assertRaises(
            SystemExit, self.config.check_perms, '0644,0444'
        )

    def _run_functional(self, section):
        flag, local_file = tempfile.mkstemp()
        try:
            with open(local_file, 'wb') as f:
                f.write(tests.CONFIG_FILE.encode('utf-8'))
            self.config.config_file = local_file
            args = self.config.config_args(section=section)
        except Exception as exp:
            self.fail('Failed: %s' % exp)
        else:
            self.assertFalse(args.get('false_value'))
            self.assertTrue(args.get('true_value'))
            self.assertTrue(isinstance(args.get('integer_value'), int))
            self.assertTrue(isinstance(args.get('string_value'), str))
        finally:
            os.remove(local_file)

    def test_sys_config_config_args_parse_default_section(self):
        self._run_functional(section='default')

    def test_sys_config_config_args_parse_other_section(self):
        self._run_functional(section='other_section')


# coding: utf-8

"""
Data Files Summary panel
------------------------

Implements panel with data files summary.
"""

import os.path as osp

from PyQt5 import Qt as Q

from ...common import (bold, common_filters, external_file, external_files,
                       get_file_name, is_reference, load_icon, preformat,
                       translate)
from ...datamodel import FileAttr, synchronize
from .. import Context, NodeType, check_selection
from ..actions import OpenWithAction, OnFileAction
from ..controller import Controller
from ..widgets import TitleWidget
from .objects import File

__all__ = ["DataFilesSummary"]

# note: the following pragma is added to prevent pylint complaining
#       about functions that follow Qt naming conventions;
#       it should go after all global functions
# pragma pylint: disable=invalid-name

UnitRole = Q.Qt.UserRole
StageRole = Q.Qt.UserRole + 1
FilenameRole = Q.Qt.UserRole + 2
SortRole = Q.Qt.UserRole + 3

class DataFilesSummary(Q.QWidget):
    """
    Widget displaying unified list of files from all stages in current case.

    Through the context menu, user can open that file in an app or go to its directory.
    Additionally, when listing files for Current Case, user can update a file's path.
    """

    Edit = 1
    OpenWith = 2
    BrowseDirectory = 3
    PostProcess = 4

    def __init__(self, astergui, parent):
        """
        Create view.

        Arguments:
            astergui (asterstudy.gui.astergui.AsterGui): *AsterGui* instance.
            parent (Q.QWidget): Parent widget.
        """
        super().__init__(parent)
        self.setObjectName('DataFilesSummary')

        self._astergui = astergui
        self._actions = {}

        # initialize layout
        layout = Q.QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        # panel title
        layout.addWidget(TitleWidget(translate("DataFiles", "Data Files Summary"), self))

        # files model
        self._model = _FilesModel(0, 4)
        proxy_model = Q.QSortFilterProxyModel()
        proxy_model.setSourceModel(self._model)
        proxy_model.setSortRole(SortRole)

        # files view
        self._tree = Q.QTreeView(self)
        self._tree.setObjectName('DataFilesSummary_Tree')
        self._tree.setModel(proxy_model)
        self._tree.setRootIsDecorated(False)
        self._tree.setSortingEnabled(True)
        self._tree.setEditTriggers(Q.QAbstractItemView.NoEditTriggers)
        self._tree.setItemDelegate(_EditingDelegate(self._tree, self._astergui))
        self._tree.setContextMenuPolicy(Q.Qt.CustomContextMenu)
        self._tree.doubleClicked.connect(self._edit)
        self._tree.customContextMenuRequested.connect(self._show_context_menu)
        self._tree.header().setSectionsMovable(False)
        self._tree.header().setSectionResizeMode(Q.QHeaderView.ResizeToContents)
        layout.addWidget(self._tree)

        # actions
        # - <Edit>
        action = Q.QAction(translate("DataFiles", "Edit..."), self)
        action.setIcon(load_icon('as_pic_edit_file.png'))
        action.setToolTip(translate("DataFiles", "Edit"))
        action.setStatusTip(translate("DataFiles", "Edit file path"))
        action.setShortcut('F4')
        action.setShortcutContext(Q.Qt.WidgetWithChildrenShortcut)
        action.triggered.connect(self._edit)
        action.setEnabled(False)
        self._actions[self.Edit] = action
        # - <Open With>
        action = OpenWithAction(self, self._astergui.main_window)
        action.setEnabled(False)
        self._actions[self.OpenWith] = action
        # - post-process in the results tab
        action = OnFileAction(translate("AsterStudy", "Post-process"),
                              self,
                              self._astergui.showResultsFile)
        action.setToolTip(translate("AsterStudy", "Post-process"))
        action.setStatusTip(translate("AsterStudy",
                                      "Post-process the result the Results tab"))
        action.setIcon(load_icon("as_pic_open_in_paravis.png"))
        self._actions[self.PostProcess] = action
        # - <Browse Directory>
        action = Q.QAction(translate("DataFiles", "Browse Directory"), self)
        action.setToolTip(translate("DataFiles", "Browse directory"))
        action.setStatusTip(translate("DataFiles", "Show selected file in the explorer"))
        action.triggered.connect(self._browse_directory)
        action.setEnabled(False)
        self._actions[self.BrowseDirectory] = action
        # add actions to this widget to access their via shortcuts
        self.addActions(self._actions.values())

    def setSelection(self, objs):
        """
        Select given objects.

        Arguments:
            objs (list[Entity]): Objects being selected.
        """
        # If user has selected exactly one case, we should show file list for this case.
        # Otherwise, we should show nothing.
        # This function is called from ``Workspace.setSelected()`` or ``update()``.

        if check_selection(objs, size=1, typeid=NodeType.Case):
            study = self._astergui.study()
            case = study.node(objs[0])

            # enable / disable actions
            is_editable = (case is study.history.current_case)
            self._actions[self.Edit].setEnabled(is_editable)
            self._actions[self.OpenWith].setEnabled(is_editable)
            self._actions[self.PostProcess].setEnabled(True)
            self._actions[self.BrowseDirectory].setEnabled(True)

            # intialize create temporary files model from case
            tmp_model = Q.QStandardItemModel(0, 1)
            for stage in case.stages:
                for unit in stage.handle2info:
                    item = DataFileItem(stage, unit)
                    item.setEditable(is_editable)
                    tmp_model.appendRow(item)

            # update files model by syncing it with temporary model
            synchronize(
                tmp_model.invisibleRootItem(),
                self._model.invisibleRootItem(),
                _DataFilesSummaryTreeData())

            # re-sort files view
            self._tree.sortByColumn(1, Q.Qt.AscendingOrder)

        else:
            # clear files model
            self._model.clear()

    @Q.pyqtSlot()
    def update(self):
        """
        Update view.
        """
        # just call `setSelection()` with current selection
        self.setSelection(self._astergui.view(Context.Cases).selection())

    @Q.pyqtSlot(Q.QPoint)
    def _show_context_menu(self, pos):
        """
        Show context menu for a file.

        Arguments:
            pos (QPoint): Cursor position.
        """
        index = self._tree.indexAt(pos)  # type: Q.QModelIndex
        if index.isValid():
            index = index.sibling(index.row(), 1) # get model index for second column
            file_name = index.data(FilenameRole) # type: str

            menu = Q.QMenu(self)

            menu.addAction(self._actions[self.Edit])
            menu.setDefaultAction(self._actions[self.Edit])
            menu.addSeparator()

            if file_name:
                self._actions[self.OpenWith].setFileName(file_name)
                self._actions[self.PostProcess].setFileName(file_name)
                menu.addAction(self._actions[self.OpenWith])
                menu.addAction(self._actions[self.PostProcess])
                menu.addAction(self._actions[self.BrowseDirectory])

            menu.popup(self._tree.viewport().mapToGlobal(pos))

    @Q.pyqtSlot()
    def _edit(self):
        """Open editor for selection file item."""
        index = self._tree.currentIndex()  # type: Q.QModelIndex
        index = index.sibling(index.row(), 1) # get model index for second column
        if index.flags() & Q.Qt.ItemIsEditable:
            self._tree.edit(index) # activate in-place editing

    @Q.pyqtSlot()
    def _browse_directory(self):
        """
        Launch file manager on the selected file's directory.
        """
        index = self._tree.currentIndex()  # type: Q.QModelIndex
        file_name = index.data(FilenameRole) # type: str
        directory = osp.dirname(file_name)
        Q.QDesktopServices.openUrl(Q.QUrl(directory))

class DataFileItem(Q.QStandardItem):
    """
    Item representing a data file.
    """

    def __init__(self, stage=None, unit=None):
        """
        Create item.

        Arguments:
            file (asterstudy.gui.datafiles.objects.File): File helper.
        """
        super().__init__()
        self.stage = stage
        self.unit = unit

    def __eq__(self, other):
        return isinstance(other, DataFileItem) and \
            self.stage.uid == other.stage.uid and self.unit == other.unit

    @classmethod
    def clone(cls, other):
        """Create a copy of this item."""
        item = cls(other.stage, other.unit)
        item.setEditable(other.isEditable())
        return item

    def copy_from(self, other):
        """Update this item from reference one.."""
        self.stage = other.stage
        self.unit = other.unit
        self.setEditable(other.isEditable())
        self.emitDataChanged()

    def data(self, role=Q.Qt.UserRole+1):
        """
        Provide readable filename as item's text, and full details as tooltip.
        """
        info = self.stage.handle2info.get(self.unit)
        path = info is not None and info.filename

        if role in (Q.Qt.DisplayRole, SortRole,):
            return _file_title(path, info and info.embedded)

        if role in (Q.Qt.ToolTipRole,):
            if not path:
                path = "<{}>".format(translate("DataFiles", "undefined"))
            if self.stage and path:
                tooltip = []
                tooltip.append(bold(NodeType.value2str(NodeType.Stage)) + ": " + self.stage.name)
                tooltip.append(bold(NodeType.value2str(NodeType.Unit)) + ": " + path)
                return preformat('<br/>'.join(tooltip))

        if role in (Q.Qt.BackgroundRole,):
            if not path:
                return Q.QBrush(Q.Qt.yellow)

        if role in (Q.Qt.ForegroundRole,):
            if not path:
                return Q.QBrush(Q.Qt.red)

        if role in (Q.Qt.SizeHintRole,):
            fm = Q.QFontMetrics(self.font())
            return Q.QSize(fm.width(self.text()) + 50, 18)

        if role in (UnitRole,): # unit
            return self.unit

        if role in (StageRole,): # stage
            return self.stage

        if role in (FilenameRole,): # filename
            return info and info.filename

        return super().data(role)

class _DataFilesSummaryTreeData:
    """
    Implementation of `tree_data` for `synchronize()`.
    """

    def is_equal(self, src, dst): # pragma pylint: disable=no-self-use
        """
        Arguments:
            src (Q.QStandardItem)
            dst (DataFileItem)

        Returns:
            bool
        """
        if isinstance(src, DataFileItem):
            return src == dst
        return True # for invisible root items

    def create_item(self, src): # pragma pylint: disable=no-self-use
        """
        Arguments:
            src (Q.QStandardItem)

        Returns:
            DataFileItem
        """
        if isinstance(src, DataFileItem):
            return DataFileItem.clone(src)
        return DataFileItem() # should not get here

    def update_item(self, src, dst): # pragma pylint: disable=no-self-use
        """
        Arguments:
            src (DataFileItem)
            dst (DataFileItem)
        """
        if isinstance(src, DataFileItem) and isinstance(dst, DataFileItem):
            dst.copy_from(src)

    def get_src_children(self, src): # pragma pylint: disable=no-self-use
        """
        Arguments:
            src (DataFileItem)

        Returns:
            list[DataFileItem]
        """
        return [src.child(i) for i in range(src.rowCount())]

    def get_dst_children(self, dst): # pragma pylint: disable=no-self-use
        """
        Arguments:
            dst (DataFileItem)

        Returns:
            list[DataFileItem]
        """
        return [dst.child(i, 1) for i in range(dst.rowCount())]

    def replace_dst_children(self, dst, children): # pragma pylint: disable=no-self-use
        """
        Arguments:
            dst (DataFileItem)
            children (list[DataFileItem])
        """
        # Remove items that are not present in new list
        # Also, remember which ones are present
        existing_children = []
        for i in reversed(range(dst.rowCount())):
            child = dst.child(i, 1)
            if child not in children:
                dst.removeRow(i)
            else:
                existing_children.append(child)

        # Add items from new list that weren't present in list before
        for i, child in enumerate(children):
            if child not in existing_children:
                unit = child.unit
                unit_item = Q.QStandardItem(str(unit))
                unit_item.setData(unit, SortRole)
                stage = child.stage
                stage_item = Q.QStandardItem(stage.name)
                stage_item.setData(stage.name, SortRole)
                attr = stage.handle2info[unit].attr if unit in stage.handle2info else FileAttr.No
                attr_item = Q.QStandardItem(FileAttr.value2str(attr))
                attr_item.setData(FileAttr.value2str(attr), SortRole)
                dst.insertRow(i, [unit_item, child, stage_item, attr_item])

class _EditingWidget(Q.QWidget):
    """
    Simple widget for selecting a file.

    User can either select an existing file from combobox or open a dialog for choosing a new one.
    Actual logic is implemented in ``__EditingDelegate``.
    """
    def __init__(self, parent):
        """
        Arguments:
            parent (Q.QWidget)
        """
        super().__init__(parent)
        self.setObjectName('DataFilesSummary_EditingWidget')

        layout = Q.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)

        self.combobox = Q.QComboBox(self)
        self.combobox.setObjectName('DataFilesSummary_EditingWidget_ComboBox')
        self.combobox.setFocusPolicy(Q.Qt.NoFocus)
        layout.addWidget(self.combobox, 1)

        self.button = Q.QToolButton(self)
        self.button.setObjectName('DataFilesSummary_EditingWidget_Button')
        self.button.setText('...')
        self.button.setFocusPolicy(Q.Qt.NoFocus)
        layout.addWidget(self.button, 0)

    def keyPressEvent(self, event):
        """Redefined from *QWidget*."""
        if not getattr(self, "in_key_press", False):
            setattr(self, "in_key_press", True)
            Q.QApplication.instance().sendEvent(self.combobox, event)
            delattr(self, "in_key_press")

class _EditingDelegate(Q.QStyledItemDelegate):
    """
    Uses ``_EditingWidget`` for inline editing of a ``File``.
    When user selects a new file (with Open File dialog),
    this delegate adds the file to the datamodel.
    """
    def __init__(self, tree, astergui):
        """
        Arguments:
            tree (Q.QTreeView)
            astergui (asterstudy.gui.astergui.AsterGui)
        """
        super().__init__()
        self._tree = tree
        self._astergui = astergui

    def createEditor(self, parent, option, index): # pylint: disable=unused-argument,no-self-use
        """
        Arguments:
            parent (Q.QWidget)
            option (Q.QStyleOptionViewItem)
            index (Q.QModelIndex)

        Returns:
            _EditingWidget
        """
        stage = index.data(StageRole)  # type: Stage
        case = stage.parent_case

        widget = _EditingWidget(parent)
        widget.button.clicked.connect(self._onButtonClicked)

        model = _ComboModel(widget)

        # Add all current known files
        for stage in case.stages:
            for info in stage.handle2info.values():
                model.addItem(info.filename, _file_title(info.filename, info.embedded))

        # Add all known external files
        for uid in external_files():
            model.addItem(uid, external_file(uid))

        widget.combobox.setModel(model)
        return widget

    def setEditorData(self, widget, index): # pylint: disable=no-self-use
        """
        Arguments:
            widget (_EditingWidget)
            index (Q.QModelIndex)
        """
        stage = index.data(StageRole)  # type: Stage
        unit = index.data(UnitRole)  # type: int
        info = stage.handle2info[unit]
        widget.combobox.attr = info.attr
        for i in range(widget.combobox.count()):
            path = widget.combobox.itemData(i, Q.Qt.ToolTipRole)  # type: str
            if path == info.filename:
                widget.combobox.setCurrentIndex(i)
                break
        else:
            widget.combobox.setCurrentIndex(-1) # undefined filename

    def setModelData(self, widget, model, index): # pylint: disable=no-self-use,unused-argument
        """
        Arguments:
            widget (_EditingWidget)
            model (PyQt5.QtCore.QStandardItemModel.QStandardItemModel)
            index (PyQt5.QtCore.QModelIndex.QModelIndex)
        """
        path = widget.combobox.currentData(Q.Qt.ToolTipRole)  # type: str
        stage = index.data(StageRole)  # type: Stage
        unit = index.data(UnitRole)  # type: int
        info = stage.handle2info[unit]
        study_dir = stage.model.tmpdir

        if path and path != info.filename:
            if self._astergui.prepare_for_new_operation():
                operation = translate("DataFiles", "Change file path")
                ctr = Controller(operation, self._astergui)
                # Update actual file
                is_embedded = not is_reference(path) and osp.dirname(path) == study_dir
                current_file = File(stage, unit)
                current_file.filename = path
                current_file.embedded = is_embedded
                # Commit changes to data model
                ctr.controllerCommit()
                self._astergui.study().commit(operation)
                # Update GUI
                self._astergui.update()

    @Q.pyqtSlot()
    def _onButtonClicked(self):
        """
        Open file dialog and select a new file.
        Put its name to the combobox.
        """
        widget = self.sender().parent()  # type: _EditingWidget
        path = widget.combobox.currentData(Q.Qt.ToolTipRole)  # type: str
        attr = widget.combobox.attr  # type: str

        # Show file selection dialog
        title = translate("DataFiles", "Select File")
        file_name = path if not is_reference(path) else None
        mode = 0 if (attr & ~FileAttr.Named) == 2 else 1
        filters = common_filters()
        file_name = get_file_name(mode, widget, title, file_name, filters)

        if file_name:
            # Add an item to combo box if necessary
            widget.combobox.model().addItem(file_name)
            # Select an item in combo box
            for i in range(widget.combobox.count()):
                path = widget.combobox.itemData(i, Q.Qt.ToolTipRole)  # type: str
                if path == file_name:
                    widget.combobox.setCurrentIndex(i)
                    break
            self.commitData.emit(widget)
            self.closeEditor.emit(widget, Q.QAbstractItemDelegate.SubmitModelCache)

class _FilesModel(Q.QStandardItemModel):
    """Helper model to manage list of data files in the *Data Files Summary* panel."""

    def headerData(self, section, orientation, role=Q.Qt.DisplayRole):
        """Redefined from *QStandardItemModel*."""
        headers = {0: translate("DataFiles", "Unit"),
                   1: translate("DataFiles", "Filename"),
                   2: translate("DataFiles", "Stage"),
                   3: translate("DataFiles", "Mode")}

        if orientation == Q.Qt.Horizontal and role in (Q.Qt.DisplayRole,):
            return headers.get(section)
        return super().headerData(section, orientation, role)

class _ComboModel(Q.QSortFilterProxyModel):
    """Helper model to show list of unique file names in selection combo."""

    def __init__(self, parent):
        """Create model."""
        super().__init__(parent)
        source_model = Q.QStandardItemModel(parent)
        self.setSourceModel(source_model)
        self.sort(0, Q.Qt.AscendingOrder)

    def addItem(self, path, title=None):
        """Add item to model."""
        source_model = self.sourceModel()
        if path and not source_model.findItems(path, Q.Qt.MatchExactly, 1):
            if not title:
                title = osp.basename(path)
            item0 = Q.QStandardItem(title)
            item0.setData(path, Q.Qt.ToolTipRole) # tooltip
            item1 = Q.QStandardItem(path) # for search
            source_model.appendRow([item0, item1])

def _file_title(file_name, is_embedded=False):
    """
    Returns nice title for the file's item in a list, such as a tree or a combobox.

    For a normal file, renders its basename.
    For an embedded file, renders its external name and adds "(embedded)" after the name.
    For an empty filename, renders <undefined>.

    Arguments:
        file (File):

    Returns:
        str
    """
    if file_name:
        if is_reference(file_name):
            title = external_file(file_name)
        else:
            title = osp.basename(file_name)
    else:
        title = '<{}>'.format(translate("DataFiles", "undefined"))

    if is_embedded:
        title += ' ({})'.format(translate("DataFiles", "embedded"))

    return title


#!/usr/bin/env python

import numpy as np
from scipy.integrate import quad, dblquad, odeint
import matplotlib.pyplot as plt

k1 = 1.816e-5 		#s-1	212_P = 212_Bi + beta-
k2 = 6.931e-5		#s-1	212_Bi = 208_Tl + alpha
k3 = 1.232e-4		#s-1	212_Bi = 212_Po +beta-
k4 = 3.851e-3		#s-1	208_Tl = 208_Pb + beta-
k5 = 2.310		#s-1	212_Po = 208_Pb + alpha

P_0, Bi_0, Tl_0, Po_0, Pb_0 = 1, 0, 0, 0, 0
decay_in = P_0, Bi_0, Tl_0, Po_0, Pb_0

t = np.linspace(0, 3e5, 10**2)

def ddt(conc, t):
	P, Bi, Tl, Po, Pb = conc
	dP = -k1*P
	dBi = k1*P - k2*Bi - k3*Bi
	dTl = k2*Bi - k4*Tl
	dPo = k3*Bi - k5*Po
	dPb = k4*Tl + k5*Po

	return dP, dBi, dTl, dPo, dPb

P, Bi, Tl, Po, Pb = odeint(ddt, decay_in, t).T
#print(P, Bi, Tl, Po, Pb)

fig=plt.figure()
ax = fig.add_subplot(111)

ax.plot(t, P, label='$\mathrm{^{212}Pb}$')
ax.plot(t, Bi,label='$\mathrm{^{212}Bi}$')
ax.plot(t, Tl,label='$\mathrm{^{208}Tl}$')
ax.plot(t, Po,label='$\mathrm{^{212}Po}$')
ax.plot(t, Pb,label='$\mathrm{^{208}Pb}$')
ax.plot(t, P_0*(1-np.exp(-k1*t)), label='approx $\mathrm{^{208}Pb}$')
ax.set_xlabel('t / s')
ax.set_ylabel('concentration')
ax.grid(ls='--', lw=0.5)
ax.set_title('Concentration x time for $\mathrm{^{212}P}$ decay')
plt.legend()
plt.show()