import urllib.request, tarfile, os, time
from bs4 import BeautifulSoup
import nltk.tokenize
import numpy as np
from collections import Counter

class DataSet:
    """
    A class to represent the entire data from the Reuters-21578 collection. Deals with downloading and unpacking the required files, then reading them in and storing the data for subsequent use by the classifiers. This is all done automatically with instantiation of the class.
    """
    def __init__(self):
        self.train_vectors = []  # will become a np array of binary vectors, each vector representing a document and each bit representing the presence of the term at that index in self.all_features in that particular document

        self.train_labels = []  # will become a np array of strings, representing the label of the document associated with that index in the training data

        self.test_vectors = []  # as self.train_vectors, on the test set
        self.test_labels = []  # as self.train_labels, on the test set

        self.all_features = []  # will become a list containing strings which are all the (normalised) terms occuring in any document in the collection, to be used as features

        self.all_labels = ["acq", "crude", "earn", "grain", "interest", "money-fx", "ship", "trade", "corn", "wheat"]  # these are the 10 most common classes in reuters, only documents in one or more of these classes will be selected into the sets

        self.train_body_raw = []  # list used to contain the raw text extracted from the body of each document in the training set, later tokenised, normalised, then these variables are set to None at the end of training
        self.test_body_raw = []  # as self.train_body_raw for the test set

        # begin creating the data set
        t0 = time.time()

       # get_reuters()

        self.parse_reuters_files()  # read in all the files, fill in train_labels, test_labels, train_body_raw, test_body_raw
        print("Parsed the Reuters files")

        self.extract_vocab()
        print("Extracted vocabulary of", len(self.all_features), "words")
        self.text_to_features()

        # done with these values now, so clear them
        self.train_body_raw = None
        self.test_body_raw = None

        print("Processing the data set took", time.time() - t0, "seconds")
        print("Training set distribution:", Counter(self.train_labels))
        print("Test set distribution:", Counter(self.test_labels))

    def parse_reuters_files(self):
        """
        Parse the reuters files.
        add to training set iff LEWISSPLIT="TRAIN";  TOPICS="YES", test set iff LEWISSPLIT="TEST"; TOPICS="YES"  - modification of the MODAPTE split, taking into account the 10 most common topics only
        """
        for file in os.listdir("./data/"):
            print("processing", file)
            with open("./data/" + file, "r", encoding="latin-1") as fin:
                contents = fin.read()

            soup = BeautifulSoup(contents, "html.parser")  # the data format of the reuters files approximates HTML close enough for this to be the simplest way to parse them and easily extract the relevant information

            docs = soup.find_all("reuters")  # each document in the file is contained within a "reuters" tag

            for doc in docs:
                # filter out the documents I don't  want in my sets: those with no topics at all, or topics that aren't the 10 most common
                if doc["topics"] == "NO":  # the TOPICS attribute in the REUTERS tag
                    continue

                topics_tag = doc.find_next("topics")

                relevant = True
                topics = topics_tag.find_all("d")
                for d in topics:
                    if d.string not in self.all_labels:
                        relevant = False
                        break
                if topics == [] or not relevant:  # There are a few documents which have no topics at all
                    continue

                # only relevant documents will get this far!
                body_tag = doc.find_next("body")
                if body_tag is None:  # there are a couple of instances of docs with no body, which are not useful here
                    continue
                body_text = body_tag.string

                # add the body of the text to the array that is the value for each of its topics in the appropriate dictionary
                if doc["lewissplit"] == "TRAIN":
                    for topic in topics:  # there may be more than one topic associated with each document
                        self.train_labels.append(topic.string)
                        self.train_body_raw.append(body_text)

                elif doc["lewissplit"] == "TEST":
                    for topic in topics:
                        self.test_labels.append(topic.string)
                        self.test_body_raw.append(body_text)

    def extract_vocab(self):
        """
        Tokenize & normalize raw body text extracted from Reuters files, add each of the normalised tokens from the training set to the vocabulary self.all_features
        """
        vocab_set = set()  # for collecting the unique vocabulary items

        # process the training set
        for i in range(len(self.train_body_raw)):
            tokenized = nltk.tokenize.word_tokenize(self.train_body_raw[i], language='english')
            normalized = [w.lower() for w in tokenized if
                          w.isalpha()]  # there are loads of numbers, these are essentially really rare words, so not helpful for classification.
            self.train_body_raw[i] = set(normalized)  # reduce whole body to only unique normalised tokens for efficiency
            for word in self.train_body_raw[i]:
                vocab_set.add(word)  # this is a set, ensures it contains only unique elements by definition

        # process the test set in identical fashion, but don't extract its vocabulary!
        for i in range(len(self.test_body_raw)):
            tokenized = nltk.tokenize.word_tokenize(self.test_body_raw[i], language='english')
            normalized = [w.lower() for w in tokenized if
                          w.isalpha()]
            self.test_body_raw[i] = set(normalized)

        self.all_features = list(vocab_set)

    def text_to_features(self):
        """
        Map from a set of "bag of words" items in a document, to a binary array, conceptually a feature vector, where the value of a bit at a certain index in the array indicates the presence of the item at that index in the vocabulary self.all_features
        """

        # make an zeros nparray of dimensions vocab_size, no_of_training/test_docs in self.train_features, self.test_features, since most of the values in the feature vector will be 0
        self.train_vectors = np.zeros((len(self.train_labels), len(self.all_features)), dtype=np.bool)
        self.test_vectors = np.zeros((len(self.test_labels), len(self.all_features)), dtype=np.bool)

        # process the training set
        for i in range(len(self.train_body_raw)):  # for all the docs
            for word in self.train_body_raw[i]:  # word in the doc bag-of-words
                index = self.all_features.index(word)  # find the index of that word in the features list
                self.train_vectors[i, index] = 1  # set the appropriate position in that doc's feature vector to 1

        # process the test set in the same way
        for i in range(len(self.test_body_raw)):
            for word in self.test_body_raw[i]:
                if word in self.all_features:  # there may be some words in the test set that arent in the training set
                    index = self.all_features.index(word)
                    self.test_vectors[i, index] = 1

def get_reuters():
	"""
	Download the Reuters-21578 data set archive and extract all the files.
	"""
	print("Downloading reuters-21578 from http://kdd.ics.uci.edu/databases/reuters21578/")
	tarfilepath = "reuters.tar.gz"

	# download the archive
	urllib.request.urlretrieve("http://kdd.ics.uci.edu/databases/reuters21578/reuters21578.tar.gz", tarfilepath)

	# extract the files from the downloaded archive # TODO check this works cross-OS
	if tarfile.is_tarfile(tarfilepath):
		tfile = tarfile.open("reuters.tar.gz", "r:gz")
		tfile.extractall("./data/")

	# tidy up the directory - keep only the required sgm files
	os.remove(tarfilepath)
	for root, dirs, files in os.walk("./data/"):
		for file in files:
			if not file.endswith(".sgm"):
				os.remove("./data/" + file)


import datetime, requests, sys, time, webapp2
sys.path.append('lib')
from matplotlib.path import Path
from constants import *
from userVars import *

seenList = []
seenRaidList = []
raidArea = Path(RAID_AREA, [ Path.MOVETO ] + [ Path.LINETO ] * (len(RAID_AREA) - 2) + [ Path.CLOSEPOLY ])

class Scan(Enum):
	RAID = 0
	RARE_MON = 1
	HIGH_MON = 2

def getDiscordString(type, obj):
	discordStrArray = []
	if type == Scan.RAID:
		if obj['pokemon_id'] == 0:
			discordStrArray = [
				'Level',
				obj['level'],
				'raid at',
				getGymName(obj),
				'starting at',
				getTimeString(obj['raid_start']) + '.'
			]
		else:
			discordStrArray = [
				getPokemonNameFromObj(obj),
				'raid at',
				getGymName(obj),
				'until',
				getTimeString(obj['raid_end']) + '.'
			]
			if obj['move1'] != 0 and obj['move2'] != 0:
				discordStrArray.append(getMoveName(obj['move1']) + ', ' + getMoveName(obj['move2']) + '.')
	else:
		discordStrArray.append(getPokemonNameFromObj(obj))
		if validIV(obj):
			discordStrArray.append(getIVPercentage(obj))
		if obj['cp'] != -1:
			str = '({} CP'.format(obj['cp'])
			if validIV(obj):
				# obj['level'] has not been trustworthy so figure it out ourselves
				# don't figure it out just to test other things first
				str += ' L{}'.format(obj['level'])
			discordStrArray.append(str + ')')
		discordStrArray += [
			'until',
			getTimeString(obj['despawn']),
			'at',
			getGoogleMapsURL(obj['lat'], obj['lng'])
		]
	return ' '.join(discordStrArray)

def getGoogleMapsURL(lat, lng):
	return 'http://maps.google.com/maps?q={},{}'.format(lat, lng)

def getIVPercentage(pok):
	return int(round(pok['attack'] + pok['defence'] + pok['stamina']) / 0.45, 0)

def getLocationName(obj):
	key = '{}{}'.format(obj['lat'], obj['lng'])
	if key in GYM_NAMES:
		return GYM_NAMES[key]
	else:
		return '{},{}'.format(obj['lat'], obj['lng'])

def getMoveName(mID):
	return MOVE_NAMES[mID]

def getPokemonName(pID):
	return POKEMON_NAMES[pID]

def getPokemonNameFromObj(pok):
	return getPokemonName(pok['pokemon_id']) + '' if pok['form'] == 0 else ' - {}'.format(pok['form']) # TODO: what is this for unown?

def getTimeString(utcTime):
	return datetime.datetime.fromtimestamp(int(utcTime)).strftime('%H:%M:%S')

def getURL():
	return 'https://sydneypogomap.com/query2.php?since=0&mons={}&bounds={}'.format(','.join(POKEMON.keys()), POKEMON_AREA)

def isHighIV(pok):
	if pok['pokemon_id'] in POKEMON:
		if POKEMON[pok['pokemon_id']] is not None and validIV(pok):
			return getIVPercentage(pok) >= POKEMON[pok['pokemon_id']]
	return False

def isRaidValuable(raid):
	return raid['level'] in RAIDS and (RAIDS[raid['level']] == None or raid['pokemon_id'] in RAIDS[raid['level']])

def isRaidWithinBoundaries(raid):
	return raidArea.contains_points([(raid['lat'], raid['lng'])])[0]

def isRare(pok):
	if pok['pokemon_id'] in POKEMON:
		return True

def postDiscord(type, obj):
	response = requests.post(
		url = WEBHOOKS[type],
		data = 'content=' + getDiscordString(type, obj)
	)

def validIV(pok):
	return pok['attack'] != -1 and pok['defence'] != -1 and pok['stamina'] != -1

class Clear(webapp2.RequestHandler):
	def get(self):
		global seenList
		global seenRaidList
		upperBound = int(time.time()) - 600 # 10 min buffer
		for pok in seenList:
			endTime = int(pok['despawn'])
			if endTime < upperBound:
				seenList.remove(pok)
		for raid in seenRaidList:
			endTime = int(raid['raid_end']) - 600
			if endTime < upperBound:
				seenRaidList.remove(raid)

class Pokemon(webapp2.RequestHandler):
	def get(self):
		global seenList
		response = requests.get(
			url = getUrl(),
			headers = { 'Referer': 'https://sydneypogomap.com/?forcerefresh' }
		)
		monList = response.json()
		if 'pokemons' not in monList:
			return
		for pok in monList['pokemons']:
			if not pok in seenList:
				seenList.append(pok)
				if isRare(pok):
					postDiscord(Scan.RARE_MON, pok)
				if isHighIV(pok):
					postDiscord(Scan.HIGH_MON, pok)

class Raids(webapp2.RequestHandler):
	def get(self):
		global seenRaidList
		response = requests.get(
			url = 'https://sydneypogomap.com/raids.php',
			headers = { 'Referer': 'https://sydneypogomap.com/gym.html' }
		)
		raidList = response.json()
		if 'raids' not in raidList:
			return
		for raid in raidList['raids']:
			if not raid in seenRaidList:
				seenRaidList.append(raid)
				if isRaidValuable(raid) and isRaidWithinBoundaries(raid):
					postDiscord(Scan.RAID, raid)

app = webapp2.WSGIApplication([
	('/clear', Clear),
	('/raids', Raids),
	('/mon', Pokemon)
])


# -*- coding: utf-8 -*-
from app import utils
from app.model import Base
from app.model.Base import STATUS_INVALID, STATUS_VALID
from peewee import MySQLDatabase, Model, BigIntegerField,CharField, BooleanField, \
                   DecimalField, IntegerField, TextField, DateField, DateTimeField, fn

from playhouse.shortcuts import model_to_dict, dict_to_model
from playhouse.flask_utils import FlaskDB
from datetime import datetime

# 学生管理
class Student(Base.BaseModel):
    class Meta:
        db_table = 'student'

    uid = CharField()
    nickname = CharField()
    name = CharField()
    sex  = IntegerField()
    province = CharField()
    city = CharField()
    country = CharField()
    urgent_contactor = CharField()
    urgent_mobile = CharField()
    birthday = DateField(default='1970-01-01')
    education = CharField()
    image_url = CharField()
    mentor_id = CharField()
    detailed = CharField()
    createtime = DateTimeField(default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    status = IntegerField(default=STATUS_VALID)

def GetStudents(page_num, item_per_page):
    count = Student.select().where(Student.status == STATUS_VALID).count()
    students = []
    print("total record nums: %d" %count)
    #memList = [model_to_dict(mem) for mem in Student.select().order_by(Student.id).paginate(page_num, item_per_page)]
    for mem in Student.select().where(Student.status == STATUS_VALID).order_by(Student.id).paginate(page_num, item_per_page):
        m = model_to_dict(mem)
        m = utils.Time2Str(m)
        m = utils.Decimal2Str(m)
        students.append(m)

    return count, students

def SearchStudentByUid(uid):
    record = Student.get_or_none(Student.uid == uid, Student.status == STATUS_VALID)
    r = model_to_dict(record)
    r = utils.Time2Str(r)
    r = utils.Decimal2Str(r)
    return r

def GetStdInfoById(sid):
    stdinfo = dict()
    record = Student.get_or_none(Student.id == sid, Student.status == STATUS_VALID)
    if record:
        r = model_to_dict(record)
        r = utils.Time2Str(r)
        r = utils.Decimal2Str(r)
        stdinfo['name'] = r['name']
        stdinfo['uid'] = r['uid']
        stdinfo['id'] = r['id']
        stdinfo['nickname'] = r['nickname']
        stdinfo['sex'] = r['sex']
        stdinfo['urgent_contactor'] = r['urgent_contactor']
        stdinfo['urgent_mobile'] = r['urgent_mobile']
        stdinfo['birthday'] = r['birthday']

    return stdinfo

def SearchStudentByName(page_num, item_per_page,name):
    count = Student.select().where(Student.name == name, Student.status == STATUS_VALID).count()
    students = []
    #memList = [model_to_dict(mem) for mem in Student.select().order_by(Student.id).paginate(page_num, item_per_page)]
    for mem in Student.select().where(Student.name == name, Student.status == STATUS_VALID).order_by(Student.id).paginate(page_num, item_per_page):
        m = model_to_dict(mem)
        m = utils.Time2Str(m)
        m = utils.Decimal2Str(m)
        students.append(m)

    return count, students

def GetStudentsInfoByName(name):
    stdsInfo = []
    for mem in Student.select().where(Student.name == name, Student.status == STATUS_VALID).order_by(Student.id):
        m = model_to_dict(mem)
        m = utils.Time2Str(m)
        m = utils.Decimal2Str(m)
        std_name_mobile = m['name'] + '_' + m['urgent_mobile']
        stdInfo = {'value':m['id'], 'label':std_name_mobile }
        stdsInfo.append(stdInfo)

    return stdsInfo

# create student
def CreateStudent(mDict):
    errcode = 1
    print("will create a new record")
    print(mDict)
    m = dict_to_model(Student, mDict)
    m.save()
    mem = Student.get_or_none(Student.nickname == mDict['nickname'], Student.status == STATUS_VALID)
    if mem:
        errcode = 0
    return errcode

def UpdateStudentByUid(mDict):
    errcode = 1
    m = Student.update(**mDict).where(Student.uid==mDict['uid']).execute()
    if m == 1:
        errcode = 0
    return errcode

def DeleteStudentByUid(uid,status=STATUS_INVALID):
    # 0 mean delete successfully
    errcode = 1
    m = Student.update(status=status).where(Student.uid==uid).execute()
    if m == 1:
        errcode = 0
    return errcode

if __name__ == '__main__':
    pass
    """
    create_table()
    for i in range(15):
        Insertstudent()
    #InsertStudent()
    #InsertUser()

    #for i in range(1,4):
    #    Getstudents(i, 5)

    # query student by student id
    mem = SearchstudentById(901527124)
    if mem:
        #print(mem)
        print('%d'%mem.id + "  " + mem.name)
    else:
        print("cannot find this student")

    # query student by memmber name, there may exit many records
    memList = SearchstudentByName('孙宇')
    if memList:
        for mem in memList:
            print("id: %d"%mem.id + "  studentid:%d"%mem.studentid + "  name:" + mem.name)
    else:
        print("cannot find any records")

    # delete a student
    #DeletestudentById(45481440)

    # update a memeber
    #UpdatestudentById(92596066)
    count, memItems = Getstudents(1, 5)
    print("total is : %d"%count)
    print(memItems)
    """


import os
from extract_features import calculate_and_save_features
from extract_features import load_image_features
from compare_features import compare_color_moments
from compare_features import compare_sifts
from extract_features import extract_img_features
import cv2

import operator

def grab_all_images(path):
    """
    Given a path, grab all of the .jpg files & calculate & save their features
    :param path:
    :return:
    """
    try:
        # Clean out any existing pickles for the output
        for file in os.listdir("output"):
            if file.endswith(".pkl"):
                # Clean out old pickles
                os.remove(os.path.join("output", file))
        for file in os.listdir(path):
            if file.endswith(".jpg"):
                print("Extracting features for {}".format(file))
                img_path = os.path.join(path, file)
                calculate_and_save_features(img_path)
                # print(os.path.join(path, file))
    except FileNotFoundError:
        raise FileNotFoundError(
            "Please ensure that the directory you specified exists")

def read_all_images():
    """
    Read all of the images in the output directory and return all
    of their features in a list
    :return: List of images features
    """
    images = []
    for file in os.listdir("./output"):
        if file.endswith(".pkl"):
            images.append(load_image_features(file))
    return images

def find_best_color_moment_image(base_img, images, k, feature):
    """
    Given a base image, find the k most similar images based on the color
    moment specified
    :param base_img: base image we want to compare to
    :param images: our list of images we are comparing against
    :param k: k most similar images
    :param feature: color moment feature: mean, std, or skew
    :return:
    """
    try:
        base_image_features = extract_img_features(base_img)
    except Exception:
        raise Exception("Could not find image. "
                        "Please make sure the image id is correct ie. Hand_0000002")
    color_moment_avgs = []
    for image in images:
        if image[3] == base_img:
            continue
        color_moment_avgs.append(
            (compare_color_moments(base_image_features[2], image[2], feature),
             image[3]))
    color_moment_avgs.sort(key=operator.itemgetter(0))

    rank = 1
    for color_moment in color_moment_avgs[:k]:
        result = cv2.imread(color_moment[1])
        result = cv2.resize(result, (400, 300))
        cv2.imshow("RANK {}: {}".format(rank, color_moment[1]), result)
        print("RANK {}: {} with an distance of {:4.2f}".format(
            rank, color_moment[1], color_moment[0]))
        rank += 1
    print("Press 0 on a window to close all images")
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def find_best_sift_image(base_img, images, k):
    """
    Given a base image, find the k most similar images based on the color
    moment specified
    :param base_img: base image we want to compare to
    :param images: our list of images we are comparing against
    :param k: k most similar images
    :return:
    """
    try:
        base_image_features = extract_img_features(base_img)
    except Exception:
        raise Exception("Could not find image. "
                        "Please make sure the image path is correct")
    base_image_obj = cv2.imread(base_img)
    sift_avgs = []
    for image in images:
        if image[3] == base_img:
            continue
        avg_dist, matches = compare_sifts(base_image_features[1], image[1],
                                          base_image_features[0], image[0])
        sift_avgs.append((avg_dist, matches, image))
    sift_avgs.sort(key=operator.itemgetter(0), reverse=True)

    rank = 1
    for sift_avg in sift_avgs[:k]:
        image_to_compare = cv2.imread(sift_avg[2][3])
        result = cv2.drawMatches(base_image_obj, base_image_features[0],
                                 image_to_compare, sift_avg[2][0], sift_avg[1], None)
        result = cv2.resize(result, (800, 300))
        cv2.imshow("RANK {}: {}".format(rank, sift_avg[2][3]), result)
        print("RANK {}: {} with a matching score of {:4.2f}%".format(rank, sift_avg[2][3], sift_avg[0]))
        rank += 1

    print("Press 0 on a window to close all images")
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == "__main__":
    # grab_all_images("./imgs")
    my_images = read_all_images()
    # find_best_color_moment_image("Hand_0000378.jpg.pkl",  my_images, 4, "std")
    find_best_sift_image("Hand_0000002.jpg.pkl", my_images, 4)


from argparse import ArgumentParser
import os
from mmdet.apis import inference_detector, init_detector, show_result_pyplot
import json
import numpy

def main():
    parser = ArgumentParser()
    # parser.add_argument('img', help='Image file')
    parser.add_argument('config', help='Config file')
    parser.add_argument('checkpoint', help='Checkpoint file')
    parser.add_argument(
        '--device', default='cuda:0', help='Device used for inference')
    parser.add_argument(
        '--score-thr', type=float, default=0.000000001, help='bbox score threshold')
    args = parser.parse_args()

    # build the model from a config file and a checkpoint file
    model = init_detector(args.config, args.checkpoint, device=args.device)
    # test a single image
    # import pdb;
    # pdb.set_trace()
    #

    test_img_dir="/home/dell/桌面/tile_round1_testA_20201231/tile_round1_testA_20201231/cam1/crop/"
    imgs_dir=os.listdir(test_img_dir)
    json_result=[]
    for img in imgs_dir:
        img_name=img
        img=test_img_dir+img
        result = inference_detector(model, img)
        # show the results
        show_result_pyplot(model,result,img,img_name,json_result=json_result,score_thr=args.score_thr)

    with open("/home/dell/桌面/guangdong/result_cam1.json", "w") as f:
        json.dump(json_result, f,cls=MyEncoder,indent=6)
    print("加载入文件完成...")

######################转换写入json类型
class MyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, numpy.integer):
            return int(obj)
        elif isinstance(obj, numpy.floating):
            return float(obj)
        elif isinstance(obj, numpy.ndarray):
            return obj.tolist()
        else:
            return super(MyEncoder, self).default(obj)

if __name__ == '__main__':
    main()


import matplotlib.pyplot as plt
import pandas as pd

population = pd.read_csv("API_SP.POP.TOTL_DS2_en_csv_v2_10576638.csv", skiprows=4, delimiter=",")
wealth = pd.read_csv("7197c8d1-6dea-4393-b1d8-c7b4662d6aab_Data.csv", delimiter=",")

popu2017 = pd.DataFrame(population, columns = ["Country Code","Country Name", "2017"])
gdp2017 = pd.DataFrame(wealth, columns = ["Country Code","Country Name", "2017 [YR2017]"])

gdp2017.rename(columns={"2017 [YR2017]":"GDP_2017"}, inplace=True)

gdp2017 = gdp2017[gdp2017.GDP_2017 != '..']

popugdp2017 = pd.merge(popu2017, gdp2017, on="Country Name")

popugdp2017.drop('Country Code_x', axis=1)

popugdp2017.rename(columns={"Country Code_y":"Code","2017":"Population_2017"}, inplace=True)

GDP = []
for item in popugdp2017["GDP_2017"]:
    GDP.append (float(item))

popugdp2017["GDP_2017"] = GDP

plt.scatter(popugdp2017["Population_2017"],popugdp2017["GDP_2017"]/popugdp2017["Population_2017"], c=popugdp2017["GDP_2017"] ,edgecolor="black", cmap = "Reds", s=popugdp2017["Population_2017"]/1000000, alpha=0.75)
plt.xscale("log")
plt.yscale("log")
plt.xlabel("Population")
plt.ylabel("Per Capita Income")
plt.title ("2017")

plt.show()


#callback.py

import cv2
import numpy as np

# Global variables
drawing = False
mode    = True
ix,iy   = -1, -1

# mouse callback function
def draw_circle(event,x,y, flags, param):
	global ix,iy,drawing,mode

	if event == cv2.EVENT_LBUTTONDOWN:
		drawing = True
		ix,iy   = x,y

	elif event == cv2.EVENT_MOUSEMOVE:
		if drawing == True:
			if mode == True:
				cv2.rectangle(cpy, (ix,iy), (x,y),(0,255,0), -1)
			else:
				cv2.circle(cpy, (x,y), 5, (0,0,255), -1)

	elif event == cv2.EVENT_LBUTTONUP:
		drawing = False
		if mode == True:
			cv2.rectangle(cpy, (ix,iy), (x,y), (0,255,0), -1)
		else:
			cv2.circle(cpy, (x,y), 5, (0,0,255), -1)

if __name__ == '__main__':
	img = np.zeros((512,512,3), np.uint8)
	cpy = img.copy()
	cv2.namedWindow('image')
	cv2.setMouseCallback('image',draw_circle)

	while True:
		cv2.imshow('image',cpy)
		k = cv2.waitKey(1) & 0xFF
		if k == ord('m'):
			mode = not mode
		if k == ord('r'):
			cpy = img.copy()
		elif k == 27:
			break

	cv2.destroyAllWindows()


from uuid import uuid4
from time import time
from database import Base, db_session
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
from sqlalchemy.orm import relationship

CONFIRMATION_EXPIRATION_DELTA =  1800

class ConfirmationModel(Base):
    __tablename__ = "confirmations"

    id = Column(String(50), primary_key=True)
    expire_at = Column(Integer, nullable=False)
    confirmed = Column(Boolean, nullable=False)
    user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
    user = relationship("UserModel")

    def __init__(self, user_id: int, **kwargs):
        super().__init__(**kwargs)
        self.user_id = user_id
        self.id = uuid4().hex
        self.expire_at = int(time()) + CONFIRMATION_EXPIRATION_DELTA
        self.confirmed = False

    @classmethod
    def find_by_id(cls, _id: str) -> "ConfirmationModel":
        return cls.query.filter_by(id=_id).first()

    @property
    def expired(self) -> bool:
        return time() > self.expire_at

    def force_to_expire(self) -> None:
        if not self.expired:
            self.expire_at = int(time())
            self.save_to_db()

    def save_to_db(self) -> None:
        db_session.add(self)
        db_session.commit()

    def delete_from_db(self) -> None:
        db_session.delete(self)
        db_session.commit()


import functools
import numpy as np
import regreg.api as rr
import copy
from selection.randomized.M_estimator import restricted_Mest
from selection.api import randomization

class CV(object):

    def __init__(self, loss, folds, lam_seq, objective_randomization=None, epsilon=None):

        (self.loss,
         self.folds,
         self.lam_seq,
         self.objective_randomization,
         self.epsilon) = (loss,
                          folds,
                          lam_seq,
                          objective_randomization,
                          epsilon)

        if self.objective_randomization is not None:
            if self.epsilon is None:
                X, _ = loss.data
                n = X.shape[0]
                self.epsilon = np.true_divide(1, np.sqrt(n))
        self.K = len(np.unique(self.folds))

    def CV_err(self,
               penalty,
               loss = None,
               residual_randomization = None,
               scale = None,
               solve_args = {'min_its':20, 'tol':1.e-1}):
        """
        Computes the non-randomized CV error and the one with added residual randomization
        """
        if loss is None:
            loss = copy.copy(self.loss)
        X, y = loss.data
        n, p = X.shape

        CV_err = 0
        CV_err_squared = 0

        if residual_randomization is not None:
            CV_err_randomized = 0
            CV_err_squared_randomized = 0
            if scale is None:
                scale = 1.

        for fold in np.unique(self.folds):
            test = self.folds == fold
            train = ~test

            loss_train = loss.subsample(train)
            loss_test = loss.subsample(test)
            X_test, y_test = X[test], y[test]
            n_test = y_test.shape[0]

            if self.objective_randomization is not None:
                randomized_train_loss = self.objective_randomization.randomize(loss_train, self.epsilon) # randomized train loss
                problem = rr.simple_problem(randomized_train_loss, penalty)
            else:
                problem = rr.simple_problem(loss_train, penalty)
            beta_train = problem.solve(**solve_args)

            #active = beta_train!=0
            #_beta_unpenalized = restricted_Mest(loss_train, active, solve_args=solve_args)
            #beta_full = np.zeros(p)
            #beta_full[active] = _beta_unpenalized

            _mu = lambda X, beta: loss_test.saturated_loss.mean_function(X.dot(beta))
            resid = y_test - _mu(X_test, beta_train)
            cur = (resid**2).sum() / n_test
            CV_err += cur
            CV_err_squared += (cur**2)

            if residual_randomization is not None:
                random_noise = scale * np.random.standard_normal(n_test)
                cur_randomized = ((resid + random_noise)**2).sum() / n_test
                CV_err_randomized += cur_randomized
                CV_err_squared_randomized += cur_randomized**2

        SD_CV = np.sqrt((CV_err_squared - ((CV_err**2)/self.K)) / float(self.K-1))
        if residual_randomization is not None:
            SD_CV_randomized = np.sqrt((CV_err_squared_randomized - (CV_err_randomized**2/self.K)) / (self.K-1))
            return CV_err, SD_CV, CV_err_randomized, SD_CV_randomized
        else:
            #print(CV_err, SD_CV)
            return CV_err, SD_CV

    def choose_lambda_CVr(self, scale = 1., loss=None):
        """
        Minimizes CV error curve without randomization and the one with residual randomization
        """
        if loss is None:
            loss = self.loss

        if not hasattr(self, 'scale'):
            self.scale = scale

        CV_curve = []
        X, _ = loss.data
        p = X.shape[1]
        for lam in self.lam_seq:
            penalty = rr.l1norm(p, lagrange=lam)
            # CV_curve.append(self.CV_err(penalty, loss) + (lam,))
            CV_curve.append(self.CV_err(penalty, loss, residual_randomization = True, scale = self.scale))

        CV_curve = np.array(CV_curve)
        CV_val = CV_curve[:,0]
        CV_val_randomized = CV_curve[:,2]
        lam_CV = self.lam_seq[np.argmin(CV_val)]
        lam_CV_randomized = self.lam_seq[np.argmin(CV_val_randomized)]

        SD_val = CV_curve[:,1]
        SD_val_randomized = CV_curve[:,3]
        return lam_CV, CV_val, SD_val, lam_CV_randomized, CV_val_randomized, SD_val_randomized

    def bootstrap_CVr_curve(self):
        """
        Bootstrap of CV error curve with residual randomization
        """

        def _boot_CV_curve(indices):
            X, y = self.loss.data
            n, p = X.shape
            folds_star = np.arange(n) % self.K
            np.random.shuffle(folds_star)
            loss_star = self.loss.subsample(indices)
            # loss_star = rr.glm.gaussian(X[indices,:], y[indices])
            result = self.choose_lambda_CVr(scale=self.scale, loss=loss_star)
            CV_val = result[1]
            return np.array(CV_val)

        def _boot_CVr_curve(indices):
            X, y = self.loss.data
            n, p = X.shape
            folds_star = np.arange(n) % self.K
            np.random.shuffle(folds_star)
            loss_star = self.loss.subsample(indices)
            #loss_star = rr.glm.gaussian(X[indices,:], y[indices])
            result = self.choose_lambda_CVr(scale=self.scale, loss=loss_star)
            CV_val_randomized = result[4]
            return np.array(CV_val_randomized)

        return _boot_CV_curve, _boot_CVr_curve

    def choose_lambda_CVR(self,  scale1=None, scale2=None, loss=None):
        """
        Minimizes CV error curve with additive randomization (CVR=CV+R1+R2=CV1+R2)
        """
        if loss is None:
            loss = copy.copy(self.loss)
        CV_curve = []
        X, _ = loss.data
        p = X.shape[1]
        for lam in self.lam_seq:
            penalty = rr.l1norm(p, lagrange=lam)
            #CV_curve.append(self.CV_err(penalty, loss) + (lam,))
            CV_curve.append(self.CV_err(penalty, loss))

        CV_curve = np.array(CV_curve)

        rv1, rv2 = np.zeros(self.lam_seq.shape[0]), np.zeros(self.lam_seq.shape[0])
        if scale1 is not None:
            randomization1 = randomization.isotropic_gaussian((self.lam_seq.shape[0],), scale=scale1)
            rv1 = np.asarray(randomization1._sampler(size=(1,)))
        if scale2 is not None:
            randomization2 = randomization.isotropic_gaussian((self.lam_seq.shape[0],), scale=scale2)
            rv2 = np.asarray(randomization2._sampler(size=(1,)))
        CVR_val = CV_curve[:,0]+rv1.flatten()+rv2.flatten()
        lam_CVR = self.lam_seq[np.argmin(CVR_val)] # lam_CVR minimizes CVR
        CV1_val = CV_curve[:,0]+rv1.flatten()

        SD = CV_curve[:,1]
        return lam_CVR, SD, CVR_val, CV1_val, self.lam_seq

    def bootstrap_CVR_curve(self, scale1=None, scale2=None):
        """
        Bootstrap of CVR=CV+R1+R2 and CV1=CV+R1 curves
        """
        def _bootstrap_CVerr_curve(indices):
            X, y = self.loss.data
            n, p = X.shape
            folds_star = np.arange(n) % self.K
            np.random.shuffle(folds_star)
            loss_star = self.loss.subsample(indices)
            #loss_star = rr.glm.gaussian(X[indices,:], y[indices])
            _, _, CVR_val, CV1_val, _ = self.choose_lambda_CVR(scale1, scale2, loss_star)
            return np.array(CVR_val), np.array(CV1_val)

        def _CVR_boot(indices):
            return _bootstrap_CVerr_curve(indices)[0]
        def _CV1_boot(indices):
            return _bootstrap_CVerr_curve(indices)[1]

        return _CVR_boot, _CV1_boot

if __name__ == '__main__':
    from selection.tests.instance import gaussian_instance
    np.random.seed(1)
    n, p = 3000, 1000
    X, y, beta, nonzero, sigma = gaussian_instance(n=n, p=p, s=30, rho=0., sigma=1)
    loss = rr.glm.gaussian(X,y)
    lam_seq = np.exp(np.linspace(np.log(1.e-6), np.log(1), 30)) * np.fabs(np.dot(X.T,y)).max()
    K = 5
    folds = np.arange(n) % K
    CV_compute = CV(loss, folds, lam_seq)
    lam_CV, CV_val, SD_val, lam_CV_randomized, CV_val_randomized, SD_val_randomized = CV_compute.choose_lambda_CVr()
    #print("CV error curve (nonrandomized):", CV_val)

    minimum_CV = np.min(CV_val)
    lam_idx = list(lam_seq).index(lam_CV)
    SD_min = SD_val[lam_idx]
    lam_1SD = lam_seq[max([i for i in range(lam_seq.shape[0]) if CV_val[i] <= minimum_CV + SD_min])]

    #print(lam_CV, lam_1SD)
    import matplotlib.pyplot as plt
    plt.plot(np.log(lam_seq), CV_val)
    plt.show()


import sys
import json

from PySide.QtGui import *
import PySide.QtCore as Core

import DEFAULTS

# converts a tuple that holds rgb values into
# its respective hex value
def convert_color_to_hex(color):
    if type(color) == tuple:
        value = "#"
        for i in range(0, 3):
            value += str(hex(color[i]))[2:]
        return value
    else:
        raise TypeError("Color provided has to be a tuple.. got '{}' instead".format(str(type(color))))

# represents the canvas scene
class Scene(QGraphicsScene):
    def __init__(self, designer):
        super(Scene, self).__init__()

        with open("platforms.json") as filename:
            self.data = json.load(filename)

        # General attributes used by all tools
        self.designer = designer
        self.designer.canvas.setScene(self)
        self.outlinepen = QPen(QColor(convert_color_to_hex(DEFAULTS.BLACK)))
        self.design = None

        # Used by the placer tool
        self.snap_on = True
        self.snap_strength = 10
        self.shadow = None
        self.placer_selected_platform = None

        # Used by the selector tool
        self.hovered_over_platform = None
        self.selector_selected_platform = None
        self.selector_old_colors = {}  # stores the old color of the platform after the mouse is no longer on it
        self.selector_SELECTED_COLOR = '#990000'
        self.mouse_pressed = False
        self.prev_mouse_pos = None

        # General Initialization
        self.reset_design()
        self.initialize_scene()

    # function does the math that snaps a coordinate to the grid
    def snap_to_nearest(self, number):
        difference = number % self.snap_strength
        if difference <= 2:
            return number - difference
        else:
            return number + (self.snap_strength - difference)

    # takes in an x and a y which is given by a mouse event and
    # returns the new "snapped to" coordinates
    def get_snap_coordinates(self, x, y):

        if self.snap_on:
            x = self.snap_to_nearest(x)
            y = self.snap_to_nearest(y)

        return x, y

    # takes in an x and a y and returns a QPointF
    def return_pos(self, x, y):
        return Core.QPointF(x, y)

    # resets the dictionary that holds all of information about the design
    def reset_design(self):

        self.design = self.create_initial_design()

    def initialize_json_design(self):

        design = {
            "platforms": [],
            "rules": {}
        }

        return design

    def create_initial_design(self):
        default_design = self.initialize_json_design()
        self.add_initial_rules_to_design(default_design)
        self.add_platform_to_design(default_design,
                                    "FloorPlatform",
                                    0, DEFAULTS.world_size[1] - DEFAULTS.floor_height,
                                    default_design["rules"]["world-size"][0], default_design["rules"]["world-size"][1],
                                    DEFAULTS.platform_color)
        return default_design

    def add_initial_rules_to_design(self, design):

        design["rules"].update(
            {
                "background-color": DEFAULTS.SKY_BLUE,
                "world-size": DEFAULTS.world_size
            }
        )

    def add_rules_to_design(self, design, rules):

        design["rules"].update(rules)

    # removes all items from the list of canvas items and resets the dictionary
    # that holds the current design
    def remove_all_items(self):

        for item in self.items():
            self.removeItem(item)

        self.design = self.initialize_json_design()

    # takes in a dictionary filled with platform data and adds all of them
    # to the list of items being drawn by the canvas and also adding them
    # to the dictionary holding the data of the current design
    # this is useful for opening pre-existing files to edit them
    def add_all_items(self, new_data):

        self.add_rules_to_design(self.design, new_data["rules"])
        self.add_background()

        for platform in new_data["platforms"]:

            self.add_platform(platform["x"],
                              platform["y"],
                              platform["width"],
                              platform["height"],
                              convert_color_to_hex(tuple(platform["color"])))
            self.add_platform_to_design(self.design, platform["type"],
                                        platform["x"], platform["y"],
                                        platform["width"], platform["height"],
                                        platform["color"])

    # function that adds the default floor as to speed up the designing process
    def add_default_floor(self):

        # adding the default floor
        self.floor = QGraphicsRectItem(0, 0,
                                       self.design["rules"]["world-size"][0],
                                       self.design["rules"]["world-size"][1])
        self.floor.setPos(0, DEFAULTS.world_size[1] - DEFAULTS.floor_height)
        self.floor.setPen(self.outlinepen)
        self.floor.setBrush(QBrush(QColor(convert_color_to_hex(tuple(DEFAULTS.platform_color)))))
        self.addItem(self.floor)

    # adds the background to the list of items being drawn by the canvas
    def add_background(self):

        # sets the scene rect to the default world size, this should be changeable
        self.setSceneRect(0, 0, self.design["rules"]["world-size"][0], self.design["rules"]["world-size"][1])

        # add the background, this color will be easily changed
        self.background = QGraphicsRectItem(0, 0, self.design["rules"]["world-size"][0],
                                            self.design["rules"]["world-size"][1])
        self.background.setPen(self.outlinepen)
        self.background.setBrush(QBrush(QColor(convert_color_to_hex(tuple(self.design["rules"]["background-color"])))))
        self.addItem(self.background)

    def remove_floor(self):

        self.removeItem(self.floor)
        self.remove_floor_from_design()

    def remove_floor_from_design(self):

        platform_to_remove = None
        for platform in self.design["platforms"]:
            if platform["type"] == "FloorPlatform":
                platform_to_remove = platform
                break

        self.design["platforms"].remove(platform_to_remove)

    # initializes the canvas scene
    def initialize_scene(self):

        self.installEventFilter(self)

        self.add_background()
        self.add_default_floor()

    # function that is used to add the platform and it's data to the list of
    # items that is currently being displayed by the canvas scene
    def add_platform(self, x, y, width, height, color, return_platform=False):

        platform = QGraphicsRectItem(0, 0, width, height)
        platform.setPos(x, y)

        platform.setPen(self.outlinepen)
        platform.setBrush(QBrush(QColor(color)))
        self.addItem(platform)

        if return_platform:
            return platform
        else:
            return None

    # used to add the platform to the canvas scene when the mouse button is pressed
    def add_platform_to_scene(self, event, return_platform=False):

        if self.placer_selected_platform is None:
            return

        try:
            attributes = self.data["types"][self.placer_selected_platform]
        except KeyError:
            try:
                attributes = {
                    "width": int(self.designer.entered_width.text()),
                    "height": int(self.designer.entered_height.text()),
                    "color": DEFAULTS.platform_color
                }
            except ValueError:
                return

        pos = event.scenePos()

        x, y = self.get_snap_coordinates(int(pos.x()), int(pos.y()))

        platform = self.add_platform(x,
                                     y,
                                     attributes["width"],
                                     attributes["height"],
                                     convert_color_to_hex(tuple(attributes["color"])),
                                     return_platform=return_platform)

        if return_platform:
            return platform

    # handles the data and adds the platform that was placed to the
    # dictionary containing all information about the level that is
    # being currently built so that it can be exported later
    def add_platform_to_design(self, design, platform_type, x, y, width, height, color):

        x, y = self.get_snap_coordinates(x, y)

        design["platforms"].append(
            {
                "type": platform_type,
                "x": x,
                "y": y,
                "width": width,
                "height": height,
                "color": color
            }
        )

    # used by the placer tool to remove the last drawn platform
    # if the user did not decide to place it there
    def remove_shadow(self):
        if self.shadow is not None:
            self.removeItem(self.shadow)
            self.shadow = None

    # when a platform is dragged by the selector, this function will look for
    # the old platform in the current design and change its coordinates to
    # where the platform is currently placed on the canvas scene
    def adjust_selected_platform_coordinates(self, old_x, old_y):
        pos = self.selector_selected_platform.pos()

        for platform in self.design["platforms"]:
            if old_x == platform["x"] and old_y == platform["y"]:
                platform["x"] = pos.x()
                platform["y"] = pos.y()
                break

    # depending on what tool is selected the mouse move event function
    # will behave differently, so this is a series of conditionals looking
    # for which tool is being used and calling the appropriate behavior
    def mouseMoveEvent(self, event):
        if self.designer.tool == "Placer":
            self.mouse_move_placer_event(event)
        elif self.designer.tool == "Selector":
            self.mouse_move_selector_event(event)

    # depending on what tool is selected the mouse press event function
    # will behave differently, so this is a series of conditionals looking
    # for which tool is being used and calling the appropriate behavior
    def mousePressEvent(self, event):
        if self.designer.tool == "Placer":
            self.mouse_press_placer_event(event)
        elif self.designer.tool == "Selector":
            self.mouse_press_selector_event(event)
            self.mouse_pressed = True
            x, y = self.get_snap_coordinates(event.scenePos().x(), event.scenePos().y())
            self.prev_mouse_pos = self.return_pos(x, y)

    # waits for a mouse release event and applies the appropriate behavior based on
    # what tool is currently selected
    def mouseReleaseEvent(self, event):
        if self.designer.tool == "Selector":
            self.mouse_pressed = False
            self.prev_mouse_pos = None

    # mouse move event behavior for the placer tool
    def mouse_move_placer_event(self, event):
        self.remove_shadow()

        platform = self.add_platform_to_scene(event, return_platform=True)
        if platform is not None:
            platform.setOpacity(0.5)

        self.shadow = platform

    # mouse press event behavior for the placer tool
    def mouse_press_placer_event(self, event):
        if self.placer_selected_platform is not None:
            self.add_platform_to_scene(event)

            try:
                platform = self.data["types"][self.placer_selected_platform]
            except KeyError:
                try:
                    platform = {
                        "width": int(self.designer.entered_width.text()),
                        "height": int(self.designer.entered_height.text()),
                        "color": DEFAULTS.platform_color
                    }
                except ValueError:
                    return

            self.add_platform_to_design(self.design,
                                        self.placer_selected_platform,
                                        int(event.scenePos().x()),
                                        int(event.scenePos().y()),
                                        platform["width"],
                                        platform["height"],
                                        platform["color"])

    # restoring color to any potential platforms that the user hovered over but
    # is no longer hovering over
    def restore_color_to_other_platforms(self, platform):

        color_restore_conditions = [platform is not self.hovered_over_platform,
                                    self.hovered_over_platform is not None]

        if False not in color_restore_conditions:
            if not self.selector_old_colors[self.hovered_over_platform]["selected"]:
                color = self.selector_old_colors[self.hovered_over_platform]["color"]
                self.hovered_over_platform.setBrush(QBrush(QColor(color)))
                self.hovered_over_platform.setOpacity(1)
                del self.selector_old_colors[self.hovered_over_platform]
                self.hovered_over_platform = None

    # checking to see if the user is hovering over a new platform and then setting
    # it's color to red and its opacity to 0.5
    # function also keeps track of the platforms old color
    # so that it may be restored later
    def apply_hover_effect_onto_platform(self, platform):

        hover_action_conditions = [platform is not self.background,
                                   platform is not self.hovered_over_platform,
                                   platform is not self.selector_selected_platform]

        if False not in hover_action_conditions:
            self.hovered_over_platform = platform
            self.selector_old_colors.update(
                {
                    platform: {
                        "selected": False,
                        "color": convert_color_to_hex(platform.brush().color().getRgb())
                    }
                }
            )
            platform.setBrush(QBrush(QColor(self.selector_SELECTED_COLOR)))
            platform.setOpacity(0.5)

    # mouse move event behavior for the selector tool
    def mouse_move_selector_event(self, event):
        if not self.mouse_pressed:
            pos = event.scenePos()

            platform = self.itemAt(pos)

            self.restore_color_to_other_platforms(platform)
            self.apply_hover_effect_onto_platform(platform)
        else:
            self.drag_selected_platform(event)

    # allows you to drag the platform that was just selected to a new position
    def drag_selected_platform(self, event):
        if self.selector_selected_platform is not None:
            pos = event.scenePos()
            x, y = self.get_snap_coordinates(pos.x(), pos.y())

            old_x = self.selector_selected_platform.x()
            old_y = self.selector_selected_platform.y()

            mouse_displacement_x = x - self.prev_mouse_pos.x()
            mouse_displacement_y = y - self.prev_mouse_pos.y()

            self.selector_selected_platform.setPos(self.selector_selected_platform.x() + mouse_displacement_x,
                                                   self.selector_selected_platform.y() + mouse_displacement_y)

            self.adjust_selected_platform_coordinates(old_x, old_y)

            self.prev_mouse_pos = Core.QPointF(x, y)

    # deselects the selected platform by changing its color and opacity
    # back to normal and setting selected platform back to None
    # the delete action also gets disabled
    def deselect_selected_platform(self):
        color = self.selector_old_colors[self.selector_selected_platform]["color"]
        self.selector_selected_platform.setBrush(QBrush(QColor(color)))
        self.selector_selected_platform.setOpacity(1)
        del self.selector_old_colors[self.selector_selected_platform]
        self.selector_selected_platform = None
        self.designer.toggle_delete_action(False)

    # select the platform that the mouse is currently hovering over by
    # increasing it's opacity and keeping it that color until its deselected
    # the delete action also gets enabled
    def select_hovered_over_platform(self):
        self.selector_selected_platform = self.hovered_over_platform
        self.selector_selected_platform.setOpacity(0.65)
        self.selector_old_colors[self.selector_selected_platform]["selected"] = True
        self.hovered_over_platform = None
        self.designer.toggle_delete_action(True)

    # mouse press event behavior for the selector tool
    def mouse_press_selector_event(self, event):

        # deselect the last thing that was selected and restore its color
        if self.selector_selected_platform is not None:
            self.deselect_selected_platform()

        # if the mouse is hovering over a platform, select that platform
        if self.hovered_over_platform is not None:
            self.select_hovered_over_platform()

    # this is simply looking to see if the mouse has left the canvas
    # in order to remove any potential "shadows" or platforms that
    # are drawn on the canvas but were not actually placed anywhere
    def eventFilter(self, watched, event):
        if event.type() == Core.QEvent.Leave:
            if self.designer.tool == "Placer":
                self.remove_shadow()
            elif self.designer.tool == "Selector":
                if self.hovered_over_platform is not None:
                    self.select_hovered_over_platform()
                    self.deselect_selected_platform()
            return True
        else:
            return False

# represents the main GUI window
class Designer(QWidget):
    def __init__(self, application):
        super(Designer, self).__init__()

        with open("platforms.json") as filename:
            self.data = json.load(filename)

        self.application = application
        self.filename = None
        self.canvas = None
        self.canvas_scene = None

        self.selection = []
        self.tool = "Placer"
        self.initialize_interface()

    # center the GUI on the desktop when it is first launched
    def center_screen(self):
        # get the geometry features of the desktop
        desktop_geometry = self.application.desktop().screenGeometry()
        # calculate new x and y values
        x = (desktop_geometry.width() - self.width()) / 2
        y = (desktop_geometry.height() - self.height()) / 2
        # move the main window to those values
        self.move(x, y)

    # export the current canvas design into a file with the passed in filename
    def export_level(self, filename):
        with open(filename, "w") as name:
            json.dump(self.canvas_scene.design, name, indent=4)

    # toggle the button selection, this function treats regular buttons like radio buttons
    def toggle_selection(self, button):
        # since a button has just been press, change any button that is
        # flat back to its default state
        for select in self.selection:
            if select.isFlat():
                select.setFlat(False)

        # set the button that was pressed to the flat state
        button.setFlat(True)

        # store the platform text of the selected platform type
        self.canvas_scene.placer_selected_platform = button.text()

        # keep the width and height entries disabled unless needed
        custom_list = ["CustomPlatform", "FloorPlatform"]
        self.entered_width.setEnabled(button.text() in custom_list)
        self.entered_height.setEnabled(button.text() in custom_list)

    # listens for the user to close the GUI and checks whether a save warning message should be applied
    def closeEvent(self, event):

        response = self.apply_save_warning_message()

        if response == QMessageBox.Cancel:
            event.ignore()
        else:
            event.accept()

    def add_button_to_box_layout(self, text, box_layout):
        button = QPushButton(text)
        button.setStyleSheet("padding: 20px;")
        # when the button is clicked, run a function that
        # takes in that button and toggles it appropriately
        button.clicked.connect(
            lambda b=button: self.toggle_selection(b)
        )
        # throw the button into the selection list to have
        # a reference to all generated buttons
        self.selection.append(button)
        box_layout.addWidget(button)

    # initializes the left frame which is composed of the prebuilt platform options
    def initialize_left_frame(self):

        # custom group box creation
        custom_section = QGroupBox()
        custom_button_layout = QVBoxLayout()
        self.add_button_to_box_layout("CustomPlatform", custom_button_layout)
        self.add_button_to_box_layout("FloorPlatform", custom_button_layout)
        custom_section.setLayout(custom_button_layout)

        # initialize a group box to place the platform buttons
        self.left_box = QGroupBox()
        # create a vertical box layout to layout the buttons in
        # the group box vertically and set it to the group box
        form = QVBoxLayout()
        self.left_box.setLayout(form)

        # for each type of platform, create a button and add it
        # to the vertical box layout
        for key in self.data["types"].keys():
            self.add_button_to_box_layout(str(key), form)

        # create a scrollable area
        scroll_area = QScrollArea()
        # set the scrollable area to be the group box
        scroll_area.setWidget(self.left_box)

        # getting the width of the respective scroll bar in
        # order to set the group box dimensions properly
        bar_width = scroll_area.verticalScrollBar().width()

        frame_height = DEFAULTS.screen_size[1]
        frame_width = self.left_box.width() + (bar_width / 2.22)

        # giving the left frame a fixed size so that it is not resizable
        # main goal is to never have a horizontal scrollbar and for the
        # group box to maintain a certain shape regardless of how many
        # platforms currently exist
        self.left_frame.setFixedSize(frame_width, frame_height)

        # defining a vertical layout for the scroll area since the scroll
        # area at this point contains the box widget
        layout = QVBoxLayout()

        custom_area = QFrame()
        custom_layout = QVBoxLayout()

        self.custom_entry = QWidget()
        entry_layout = QHBoxLayout()

        entry_layout.addWidget(QLabel("W: "))
        self.entered_width = QLineEdit()
        self.entered_width.setEnabled(False)
        entry_layout.addWidget(self.entered_width)

        entry_layout.addWidget(QLabel("H: "))
        self.entered_height = QLineEdit()
        self.entered_height.setEnabled(False)
        entry_layout.addWidget(self.entered_height)

        self.custom_entry.setLayout(entry_layout)

        custom_layout.addWidget(self.custom_entry)
        custom_layout.addWidget(custom_section)

        custom_area.setLayout(custom_layout)

        layout.addWidget(custom_area)
        layout.addWidget(scroll_area)

        # set the left frames layout to the vertical layout that contains
        # the scrollable area and all of it's contents
        self.left_frame.setLayout(layout)

    # initialize the canvas scene with all of its elements
    def initialize_canvas(self):

        self.canvas = QGraphicsView()

        bar_width = self.canvas.verticalScrollBar().height()
        bar_height = self.canvas.horizontalScrollBar().height()

        canvas_width = DEFAULTS.screen_size[0] + (bar_width / 1.25)
        canvas_height = DEFAULTS.screen_size[1] + (bar_height / 1.25)

        self.canvas.setFixedSize(canvas_width, canvas_height)
        self.canvas.setMouseTracking(True)
        self.canvas_scene = Scene(self)

        self.middle_layout.addWidget(self.canvas)

    # applies the necessary QFileDialog depending on the circumstances of the current design
    # and any loaded files. This function will return the response that the user chose so other
    # functions can choose how to act after the message box independently. This function will
    # return None if no warning message was necessary to appear
    def apply_save_warning_message(self):

        msgBox = QMessageBox()
        msgBox.setText("This level as been modified.")
        msgBox.setInformativeText("Do you want to save your changes?")
        msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
        msgBox.setDefaultButton(QMessageBox.Save)

        default_design = self.canvas_scene.create_initial_design()
        if self.filename is None and not self.canvas_scene.design == default_design:
            ret = msgBox.exec_()

            # open the save file dialog and then reset the scene
            if ret == QMessageBox.Save:
                self.save_as()

            return ret

        elif self.filename is None:
            return None

        else:
            with open(self.filename) as filename:
                data = json.load(filename)

            file_data, designer_data = json.dumps(data, sort_keys=True),\
                                       json.dumps(self.canvas_scene.design, sort_keys=True)

            if not file_data == designer_data:

                ret = msgBox.exec_()

                if ret == QMessageBox.Save:
                    self.save()

                return ret
            else:
                return None

    # the new file action, this will display the save warning message if it is appropriate
    # and then will proceed to reset the canvas scene and design if it should
    def new_file(self):
        response = self.apply_save_warning_message()

        # if the user did not cancel then reset the scene
        if not response == QMessageBox.Cancel:
            self.canvas_scene = Scene(self)
            self.filename = None
            self.canvas_scene.reset_design()
            self.canvas_scene.add_default_floor()
            self.setWindowTitle("Level Designer")
        else:
            pass

    # this lets the user open an existing file
    def open_file(self):

        response = self.apply_save_warning_message()
        if response == QMessageBox.Cancel:
            return

        filename_attributes = QFileDialog.getOpenFileName(
            self, "Open File", "../levels", selectedFilter="*.stg"
        )

        if filename_attributes[0] == "":
            return

        self.filename = filename_attributes[0]
        self.setWindowTitle("Level Designer - {}".format(self.filename))

        with open(self.filename) as name:
            new_level_data = json.load(name)

        self.canvas_scene.remove_all_items()
        self.canvas_scene.add_all_items(new_level_data)

    # saves the current file
    def save(self):
        if self.filename is None:
            self.save_as()
        else:
            self.export_level(self.filename)

    # opens the save as dialog to let the user save their design
    def save_as(self):

        filename_attributes = QFileDialog.getSaveFileName(
            self, "Save File", "../levels", selectedFilter="*.stg"
        )

        if filename_attributes[0] == "":
            return

        self.filename = filename_attributes[0]
        self.export_level(self.filename)
        self.setWindowTitle("Level Designer - {}".format(self.filename))

    # toggles snap on and off if the user clicks on 'snap on' or 'snap off' in the edit menu
    def toggle_snap(self, action):

        self.canvas_scene.snap_on = not self.canvas_scene.snap_on
        action.setChecked(self.canvas_scene.snap_on)

    # applies the newly selected snap if the user pressed "apply" on the snap adjustment window
    def snap_adjustment_window_allow_action(self, entry):

        self.canvas_scene.snap_strength = int(entry.text())
        self.snap_pop_up_window.close()

    # opens up the snap adjustment window to allow the user to modify the snap strength
    def snap_adjustment_window(self):

        self.snap_pop_up_window = QWidget()
        self.snap_pop_up_window.setWindowTitle("Snap Adjustment")

        overall_layout = QVBoxLayout()

        self.snap_pop_up_window.setLayout(overall_layout)

        display_layout = QHBoxLayout()
        display_frame = QWidget()
        display_frame.setLayout(display_layout)

        label = QLabel('Strength')
        entry = QLineEdit()
        entry.setText(str(self.canvas_scene.snap_strength))
        entry.setAlignment(Core.Qt.AlignHCenter)

        display_layout.addWidget(label)
        display_layout.addWidget(entry)

        action_layout = QHBoxLayout()
        action_frame = QWidget()
        action_frame.setLayout(action_layout)

        apply_button = QPushButton()
        apply_button.setText("Apply")
        apply_button.clicked.connect(lambda text=entry: self.snap_adjustment_window_allow_action(entry))

        cancel_button = QPushButton()
        cancel_button.setText("Cancel")
        cancel_button.clicked.connect(self.snap_pop_up_window.close)

        action_layout.addWidget(apply_button)
        action_layout.addWidget(cancel_button)

        overall_layout.addWidget(display_frame)
        overall_layout.addWidget(action_frame)

        self.snap_pop_up_window.show()

    def world_size_adjustment_window(self):

        self.world_size_pop_up_window = QWidget()
        self.world_size_pop_up_window.setWindowTitle("World Size Adjustment")

        overall_layout = QVBoxLayout()

        self.world_size_pop_up_window.setLayout(overall_layout)

        header_layout = QHBoxLayout()
        header_frame = QWidget()
        header_frame.setLayout(header_layout)

        main_label = QLabel("World Size")
        header_layout.addWidget(main_label)

        bottom_layout = QHBoxLayout()
        bottom_frame = QWidget()
        bottom_frame.setLayout(bottom_layout)

        bottom_left_layout = QVBoxLayout()
        bottom_left_frame = QWidget()
        bottom_left_frame.setLayout(bottom_left_layout)

        x_row_layout = QHBoxLayout()
        x_row_frame = QWidget()
        x_row_frame.setLayout(x_row_layout)

        x_label = QLabel("x: ")
        x_row_layout.addWidget(x_label)

        x_line_edit = QLineEdit()
        x_line_edit.setText(str(self.canvas_scene.design["rules"]["world-size"][0]))
        x_line_edit.setAlignment(Core.Qt.AlignHCenter)
        x_row_layout.addWidget(x_line_edit)

        bottom_left_layout.addWidget(x_row_frame)

        y_row_layout = QHBoxLayout()
        y_row_frame = QWidget()
        y_row_frame.setLayout(y_row_layout)

        y_label = QLabel("y: ")
        y_row_layout.addWidget(y_label)

        y_line_edit = QLineEdit()
        y_line_edit.setText(str(self.canvas_scene.design["rules"]["world-size"][1]))
        y_line_edit.setAlignment(Core.Qt.AlignHCenter)
        y_row_layout.addWidget(y_line_edit)

        bottom_left_layout.addWidget(y_row_frame)

        bottom_layout.addWidget(bottom_left_frame)

        resize_floor_check_button = QCheckBox("Resize Floor")
        resize_floor_check_button.setChecked(True)

        apply_button = QPushButton("Apply")
        apply_button.clicked.connect(lambda x=x_line_edit,
                                            y=y_line_edit,
                                            resize=resize_floor_check_button:
                                     self.adjust_world_size(x, y, resize))

        bottom_layout.addWidget(apply_button)

        overall_layout.addWidget(header_frame)
        overall_layout.addWidget(bottom_frame)
        overall_layout.addWidget(resize_floor_check_button)

        self.world_size_pop_up_window.show()

    def adjust_world_size(self, x_entry, y_entry, resize):

        self.canvas_scene.design["rules"]["world-size"] = [int(x_entry.text()), int(y_entry.text())]
        x, y, width, height = 0, 0, self.canvas_scene.design["rules"]["world-size"][0],\
                                    self.canvas_scene.design["rules"]["world-size"][1]

        self.canvas_scene.setSceneRect(x, y, width, height)
        self.canvas_scene.background.setRect(x, y, width, height)

        if resize.isChecked():
            self.canvas_scene.remove_floor()
            self.canvas_scene.add_default_floor()
            self.canvas_scene.add_platform_to_design(
                self.canvas_scene.design,
                "FloorPlatform",
                0, self.canvas_scene.design["rules"]["world-size"][1] - DEFAULTS.floor_height,
                width, height, DEFAULTS.platform_color
            )
        self.world_size_pop_up_window.close()

    def background_color_window(self):

        color = QColorDialog.getColor()
        if color == QColor():
            return
        else:
            self.canvas_scene.background.setBrush(QBrush(color))
            color_rgb = [color.red(), color.green(), color.blue()]
            self.canvas_scene.design["rules"]["background-color"] = color_rgb

    # deletes the platform that is selected by the selector from the canvas design
    def delete_selected_platform_from_design(self):

        pos = self.canvas_scene.selector_selected_platform.pos()

        item_to_delete = None
        for platform in self.canvas_scene.design["platforms"]:
            if pos.x() == platform["x"] and pos.y() == platform["y"]:
                item_to_delete = platform
                break

        self.canvas_scene.design["platforms"].remove(item_to_delete)

    # deletes the platform that is selected by the selector from the canvas scene and design
    def delete_selected_platform(self):

        self.canvas_scene.removeItem(self.canvas_scene.selector_selected_platform)
        self.delete_selected_platform_from_design()

    # enables the delete action only if a platform is selected
    def toggle_delete_action(self, enable_or_disable):

        for action in self.edit_menu.actions():
            if action.text() == "Delete":
                action.setEnabled(enable_or_disable)
                break

    # initializes the file menu and all of its actions
    def initialize_file_menu(self):

        self.file_menu = self.main_menu.addMenu('&File')

        new_action = QAction('New', self)
        new_action.triggered.connect(self.new_file)
        new_action.setShortcut('ctrl+n')

        open_action = QAction('Open', self)
        open_action.triggered.connect(self.open_file)
        open_action.setShortcut('ctrl+o')

        save_action = QAction('Save', self)
        save_action.triggered.connect(self.save)
        save_action.setShortcut('ctrl+s')

        save_as_action = QAction('Save As', self)
        save_as_action.triggered.connect(self.save_as)
        save_as_action.setShortcut('ctrl+shift+s')

        self.file_menu.addAction(new_action)
        self.file_menu.addAction(open_action)
        self.file_menu.addAction(save_action)
        self.file_menu.addAction(save_as_action)

    # initializes the edit menu and all of its actions
    def initialize_edit_menu(self):

        self.edit_menu = self.main_menu.addMenu('&Edit')

        snap_toggle = QAction('Snap On', self, checkable=True)
        snap_toggle.setChecked(True)
        snap_toggle.triggered.connect(lambda: self.toggle_snap(snap_toggle))

        snap_intensity_adjustment = QAction('Set Snap Strength', self)
        snap_intensity_adjustment.triggered.connect(self.snap_adjustment_window)

        background_color_adjustment = QAction('Change Background Color', self)
        background_color_adjustment.triggered.connect(self.background_color_window)
        background_color_adjustment.setShortcut("Ctrl+Shift+C")

        world_size_adjustment = QAction('Adjust World Size', self)
        world_size_adjustment.triggered.connect(self.world_size_adjustment_window)
        world_size_adjustment.setShortcut("Ctrl+Shift+W")

        delete = QAction('Delete', self)
        delete.triggered.connect(self.delete_selected_platform)
        delete.setShortcut("Ctrl+d")
        delete.setEnabled(False)

        self.edit_menu.addAction(snap_toggle)
        self.edit_menu.addAction(snap_intensity_adjustment)
        self.edit_menu.addAction(background_color_adjustment)
        self.edit_menu.addAction(world_size_adjustment)
        self.edit_menu.addAction(delete)

    def add_to_platforms_window(self):
        pass

    # initializes the config menu and all of its actions
    def initialize_config_menu(self):

        self.config_menu = self.main_menu.addMenu('&Config.')

        add_to_platforms = QAction('Add To Existing Platforms', self)
        add_to_platforms.triggered.connect(lambda: self.add_to_platforms_window)

        self.config_menu.addAction(add_to_platforms)

    # initializes the menu bar and adds it to the GUI
    def initialize_menubar(self):

        self.main_menu = QMenuBar()

        self.initialize_file_menu()
        self.initialize_edit_menu()
        self.initialize_config_menu()

        self.main_layout.addWidget(self.main_menu)

    # sets the type of tool that is selected, for both designer and the canvas
    def set_tool(self, action_type):

        self.tool = action_type
        self.canvas_scene.tool = action_type

    # toggles the previously selected action to disable it
    def toggle_old_action(self, new_action):

        if self.tool_action is None:
            pass
        else:
            old_action = self.tool_action
            self.tool_action = None
            old_action.trigger()
            self.tool_action = new_action

    # intended to abstract the common things that all
    # triggered actions share
    def toggle_action(self, action, action_type):

        self.toggle_old_action(action)
        if action.isChecked():
            self.set_tool(action_type)

        if action_type == "Placer":
            self.toggle_placer(action)
        elif action_type == "Selector":
            self.toggle_selector(action)

    # if the placer has just been checked, enable the platform list
    # on the left side of the screen, otherwise disable it
    def toggle_placer(self, placer):
        for button in self.selection:
            button.setFlat(False)

        self.canvas_scene.placer_selected_platform = None
        self.left_frame.setEnabled(placer.isChecked())

    # deselects the platform that is selected if it is selected
    def toggle_selector(self, selector):
        if self.canvas_scene.selector_selected_platform is not None:
            self.canvas_scene.deselect_selected_platform()

    # selected the initial tool that should be selected
    def initialize_starting_action(self, action):
        action.setChecked(True)
        self.tool_action = action

    # initializes the toolbar and all of its actions
    def initialize_toolbar(self):

        self.tool_bar = QToolBar()

        placer = QAction(QIcon('images/placer_icon.png'), 'Placer', self, checkable=True)
        placer.triggered.connect(lambda: self.toggle_action(placer, "Placer"))

        selector = QAction(QIcon('images/selector_icon.png'), 'Selector', self, checkable=True)
        selector.triggered.connect(lambda: self.toggle_action(selector, "Selector"))

        self.tool_bar.addAction(placer)
        self.tool_bar.addAction(selector)

        self.initialize_starting_action(placer)

        self.main_layout.addWidget(self.tool_bar)

    # initialize the general GUI
    def initialize_interface(self):

        # Set the window title
        self.setWindowTitle("Level Designer")
        # Set the gui icon
        self.setWindowIcon(QIcon('images/builder.jpg'))

        # create a shortcut that activates the close event
        QShortcut(QKeySequence("ctrl+q"), self, self.close)

        # Creating the layout for the MAIN WINDOW
        self.main_layout = QVBoxLayout()
        # Setting the main window to the main layout
        self.setLayout(self.main_layout)

        # Creating a middle frame that will hold a horizontal layout
        # This will be the container for the list of platforms on the
        # left and the canvas on the right
        self.middle_frame = QWidget()
        self.middle_layout = QHBoxLayout()
        # Setting the middle frames layout to a horizontal layout
        self.middle_frame.setLayout(self.middle_layout)

        # Creating the left frame that will hold a vertical layout
        # This is the specific container for the list of platforms
        # which will be placed into the middle layout
        self.left_frame = QWidget()
        # Initialize the left frame with the buttons
        self.initialize_left_frame()
        # Placing the left frame into the middle layout
        self.middle_layout.addWidget(self.left_frame)

        # initialize canvas
        self.initialize_canvas()

        # Initializing the menu bar
        self.initialize_menubar()

        # Initializing the tool bar
        self.initialize_toolbar()

        # Adding the middle frame into the main layout
        self.main_layout.addWidget(self.middle_frame)

        self.show()
        self.center_screen()

app = QApplication(sys.argv)
designer = Designer(app)
sys.exit(app.exec_())


# -*- coding: utf-8 -*-
import random
import time
import requests
from lxml import etree
from group import comment
from config import doubanurl
from util import doubanutil
from baiconfig import headers

if __name__ == "__main__":
    group_id = "699571"
    group_url = "https://www.douban.com/group/"+group_id+"/"
    r = requests.get(group_url, cookies=doubanutil.get_cookies(), headers=headers)
    group_topics_html = etree.HTML(r.text)
    group_topics = group_topics_html.xpath("//table[@class='olt']/tr[@class='']/td[@class='title']/a/@href")
    group_topics = group_topics[3:]
    print(group_topics)
    # print (r.text)
    for topic_url in group_topics:
        comment_topic_url = topic_url + "/add_comment"
        list_data = []
        list_data2 = []
        with open("D:\\douban\\DoubanAuto-master\\DoubanAuto-master\\data\\reponse.txt", "r", encoding="utf-8") as fr:
            list_data = fr.readlines()
            for i in list_data:
                temp_line = i.strip()  # 去除每行的\n
                list_data2.append(temp_line)
        print(list_data2)
        random_index = random.randint(0, len(list_data2) - 1)
        print(random_index)
        print(list_data2[random_index])

        comment_str = list_data2[random_index]
        print("顶帖:"+topic_url)
        comment_dict = comment.make_comment_dict(topic_url, comment_str)
        comment.comment_topic(comment_topic_url, comment_dict)
        random_sleep = random.randint(10, 50)
        time.sleep(random_sleep)


"""
@ author: S.J.Huang
"""

from keras.models import Sequential
from keras.preprocessing.image import img_to_array, array_to_img
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense,Dropout,Flatten,Conv2D,MaxPooling2D,BatchNormalization

import os
import pandas as pd
import numpy as np
import csv
import utils.mnist_reader as mnist_reader
import argparse

def CNN_model():
    model = Sequential()
    model.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same',
                    activation ='relu', input_shape = (28,28,1)))
    model.add(Conv2D(filters = 64, kernel_size = (5,5),padding = 'Same',
                    activation ='relu'))
    model.add(BatchNormalization())
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(filters = 64, kernel_size = (5,5),padding = 'Same',
                    activation ='relu'))
    model.add(Conv2D(filters = 64, kernel_size = (5,5),padding = 'Same',
                    activation ='relu'))
    model.add(BatchNormalization())
    model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(filters = 96, kernel_size = (3,3),padding = 'Same',
                    activation ='relu'))
    model.add(Conv2D(filters = 96, kernel_size = (3,3),padding = 'Same',
                    activation ='relu'))
    model.add(BatchNormalization())
    model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512, activation = "relu"))
    model.add(BatchNormalization())
    model.add(Dropout(0.25))
    model.add(Dense(512, activation = "relu"))
    model.add(BatchNormalization())
    model.add(Dropout(0.5))
    model.add(Dense(10, activation = "softmax"))

    return model

def parse_args() -> argparse:
    parser = argparse.ArgumentParser()
    parser.add_argument('--gpu',                default='0', type=str)
    return parser.parse_args()

if __name__ == "__main__":
    args = parse_args()
    os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
    os.environ["CUDA_VISIBLE_DEVICES"] = args.gpu
    # -------- Read data ---------#
    train_x, train_t = mnist_reader.load_mnist('data/fashion', kind='train')
    test_x, test_t = mnist_reader.load_mnist('data/fashion', kind='t10k')

    # ------ Preprocess data -----#
    x_train = train_x.reshape(train_x.shape[0], 28, 28, 1).astype('float32')
    x_train_norm = x_train / 255.0
    t_train_onehot = np_utils.to_categorical(train_t)

    x_test = test_x.reshape(test_x.shape[0], 28, 28, 1).astype('float32')
    x_test_norm = x_test / 255.0

    # ------- Model training----- #
    model = CNN_model()
    model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
    train_history = model.fit(x=x_train_norm, y=t_train_onehot,
                            epochs=100, batch_size=300, verbose=1)
    # train_history = model.fit(x=x_train_norm, y=t_train_onehot, epochs=20, batch_size=600, verbose=1)
    # y_test = model.predict_classes(x_test_norm)
    y_test = model.predict(x_test_norm)

    arg_ytest = np.argmax(y_test, axis=1) # we can use this code for one-hot encoding
    acc = np.sum(arg_ytest == test_t) / len(arg_ytest)  # count correct prediction
    print("accuracy is {}".format(acc))

    # with open('answer.csv', 'w', newline='') as csvfile:
    #     writer = csv.writer(csvfile)
    #     writer.writerow(['id', 'label'])
    #     for i in range(len(y_test)):
    #         writer.writerow((i, y_test[i]))
    #     print("Answer is saved in csv.")


import wikipedia as wp
import wptools
from symbol_scanner.word_score import get_best_match
import re
import pycountry

def get_page(page_search):
    lang_codes = ['en', 'de', 'es', 'fr']
    for lang in lang_codes:
        try:
            return wptools.page(
                page_search, lang=lang, silent=True, verbose=False
            ).get_parse()
        except:
            try:
                wp.set_lang(lang)
                search = wp.search(page_search)
                if search:
                    idx, score = get_best_match(page_search, search)
                    if score > 0.75:
                        return wptools.page(
                            search[idx], lang=lang, silent=True, verbose=False
                        ).get_parse()
            except:
                pass
    return None

def get_infobox(page_search):
    page = get_page(page_search)
    if page:
        return page.data.get('infobox', None)
    return None

def get_infobox_items(page_search):
    infobox = get_infobox(page_search)
    if not infobox:
        return None
    founded = infobox.get('foundation', '')
    founded = re.findall(r'\d{4}', founded)
    if not founded:
        founded = infobox.get('founded', '')
        founded = re.findall(r'\d{4}', founded)
    employees_str = (
        infobox.get('num_employees', '').replace(',', '').replace('.', '')
    )
    employees_items = re.findall(r'\d+', employees_str)
    loc = infobox.get('location_country', '')
    if not loc:
        loc = infobox.get('hq_location_country', '')
    if not loc:
        loc = infobox.get('location', '')
    locs = get_countries(loc if loc else str(infobox))
    if locs:
        loc = locs[0]
    if employees_items:
        employees = int(employees_items[0])
    if founded:
        founded = int(min(founded))
    industry = re.findall(
        r'\[[a-zA-Z_ ]+\|([a-zA-Z_ ]+)\]', infobox.get('industry', '')
    )
    if not industry:
        industry = re.findall(
            r'\[\[([a-zA-Z_ ]+)\]\]', infobox.get('industry', '')
        )
    symbols = re.findall(r'{{([a-zA-Z_: ]+)}}', infobox.get('traded_as', ''))
    if not symbols:
        symbols = re.findall(
            r'{{([a-zA-Z_| ]+)}}', infobox.get('traded_as', '')
        )
    return founded, employees, loc, industry, symbols

def get_countries(mystr):
    items = filter(
        lambda x: x in mystr, map(lambda cou: cou.name, pycountry.countries)
    )
    return list(items)


import functools as ft

import tensorflow as tf
import tensorflow_probability as tfp

import src.bnn.bnn as bnn_fn

def pre_train_nn(X_train, y_train, nodes_per_layer, epochs=100):
    """Pre-train NN to get good starting point for HMC.

    Args:
        nodes_per_layer (list): the number of nodes in each dense layer
        X_train (Tensor or np.array): training samples
        y_train (Tensor or np.array): training labels

    Returns:
        Tensor: list of tensors specifying the weights of the trained network
        model: Keras Sequential model
    """
    last_layer = nodes_per_layer.pop(-1)
    model = tf.keras.Sequential()
    model.add(tf.keras.Input(nodes_per_layer.pop(0)))
    for units in nodes_per_layer:
        model.add(tf.keras.layers.Dense(units, activation="relu"))
    model.add(tf.keras.layers.Dense(last_layer, activation="linear"))

    model.compile(loss="mse", optimizer="adam")
    model.fit(X_train, y_train, epochs=epochs, verbose=0)
    return [tf.convert_to_tensor(w) for w in model.get_weights()], model

def trace_fn(current_state, kernel_results, summary_freq=10, callbacks=[]):
    """Can be passed to the HMC kernel to obtain a trace of intermediate
    kernel results and histograms of the network parameters in Tensorboard.
    """
    step = kernel_results.step
    with tf.summary.record_if(tf.equal(step % summary_freq, 0)):
        for idx, tensor in enumerate(current_state, 1):
            count = str(int(idx / 2) + 1)
            name = "weights_" if idx % 2 == 0 else "biases_" + count
            tf.summary.histogram(name, tensor, step=step)
        return kernel_results, [cb(*current_state) for cb in callbacks]

# @tf.function
def sample_chain(*args, **kwargs):
    """Compile static graph for tfp.mcmc.sample_chain.
    Since this is bulk of the computation, using @tf.function here
    significantly improves performance (empirically about ~5x).
    """
    return tfp.mcmc.sample_chain(*args, **kwargs)

def run_hmc(
    target_log_prob_fn,
    step_size=.0001,
    num_leapfrog_steps=1000,
    num_burnin_steps=500,
    num_results=100,
    current_state=None,
    resume=None,
    log_dir="logs/hmc/",
    sampler="hmc",
    step_size_adapter="dual",
    **kwargs,
):
    """Creates an adaptive HMC kernel and generates a Markov chain of length num_results
    by performing gradient-informed Hamiltonian Monte Carlo transitions. Either the new
    or current position in parameter space is appended to the chain after each transition
    depending on a Metropolis accept/reject.

    Args:
        target_log_prob_fn {callable}: Determines the stationary distribution
        the Markov chain should converge to.

    Returns:
        burnin(s), chain(s), trace, final_kernel_result: Discarded samples generated during warm-up,
        the Markov chain(s), the trace generated by trace_fn and the kernel results of the last step
        (in case the computation needs to be resumed).
    """
    err = "Either current_state or resume is required when calling run_hmc"
    assert current_state is not None or resume is not None, err

    summary_writer = tf.summary.create_file_writer(log_dir)

    step_size_adapter = {
        "simple": tfp.mcmc.SimpleStepSizeAdaptation,
        "dual_averaging": tfp.mcmc.DualAveragingStepSizeAdaptation,
    }[step_size_adapter]
    if sampler == "nuts":
        kernel = tfp.mcmc.NoUTurnSampler(target_log_prob_fn, step_size=step_size)
        adaptive_kernel = step_size_adapter(
            kernel,
            num_adaptation_steps=num_burnin_steps,
            step_size_setter_fn=lambda pkr, new_step_size: pkr._replace(
                step_size=new_step_size
            ),
            step_size_getter_fn=lambda pkr: pkr.step_size,
            log_accept_prob_getter_fn=lambda pkr: pkr.log_accept_ratio,
        )
    elif sampler == "hmc":
        kernel = tfp.mcmc.HamiltonianMonteCarlo(
            target_log_prob_fn,
            step_size=step_size,
            num_leapfrog_steps=num_leapfrog_steps,
        )
        adaptive_kernel = step_size_adapter(
            kernel, num_adaptation_steps=num_burnin_steps
        )

    if resume:
        prev_chain, prev_trace, prev_kernel_results = resume
        step = len(prev_chain)
        current_state = tf.nest.map_structure(lambda chain: chain[-1], prev_chain)
    else:
        prev_kernel_results = adaptive_kernel.bootstrap_results(current_state)
        step = 0

    tf.summary.trace_on(graph=True, profiler=False)
    ########
    print('Will sample chain')
    #######
    chain, trace, final_kernel_results = sample_chain(
        kernel=adaptive_kernel,
        current_state=current_state,
        previous_kernel_results=prev_kernel_results,
        num_results=num_results + num_burnin_steps,
        trace_fn=ft.partial(trace_fn, summary_freq=20),
        return_final_kernel_results=True,
        **kwargs,
    )

    with summary_writer.as_default():
        tf.summary.trace_export(name="hmc_trace", step=step)
    summary_writer.close()

    if resume:
        chain = nest_concat(prev_chain, chain)
        trace = nest_concat(prev_trace, trace)
    burnin, samples = zip(*[(t[:-num_results], t[-num_results:]) for t in chain])
    return burnin, samples, trace, final_kernel_results

def predict_from_chain(chain, X_test, uncertainty="aleatoric+epistemic"):
    """Takes a Markov chain of NN configurations and does the actual
    prediction on a test set X_test including aleatoric and optionally
    epistemic uncertainty estimation.
    """
    err = f"unrecognized uncertainty type: {uncertainty}"
    assert uncertainty in ["aleatoric", "aleatoric+epistemic"], err

    if uncertainty == "aleatoric+epistemic":
        restructured_chain = [
            [tensor[i] for tensor in chain] for i in range(len(chain[0]))
        ]

        def predict_from_sample(sample):
            post_weights, post_biases = sample[::2], sample[1::2]
            post_model = bnn_fn.build_network(post_weights, post_biases)
            y_pred = post_model(X_test, training=False)
            return y_pred

        y_pred_mc_samples = [predict_from_sample(sample) for sample in restructured_chain]

        '''y_pred, y_var_epist = tf.nn.moments(
            tf.convert_to_tensor(y_pred_mc_samples), axes=0
        )'''
        #y_var_aleat = tf.reduce_mean(tf.convert_to_tensor(y_var_mc_samples), axis=0)
        #y_var_tot = y_var_epist + y_var_aleat
        return y_pred_mc_samples

def hmc_predict(
    weight_prior, bias_prior, init_state, X_train, y_train, X_test, y_test=None, **kwds
):
    """Top-level function that ties together run_hmc and predict_from_chain by accepting
    a train and test set plus parameter priors to construct the BNN's log probability
    function given the training data X_train, y_train.
    """
    default = dict(
        step_size_adapter="dual_averaging"
    )
    kwds = {**default, **kwds}
    bnn_log_prob_fn = bnn_fn.target_log_prob_fn_factory(
        weight_prior, bias_prior, X_train, y_train
    )
    print('Created log prob fn')
    burnin, samples, trace, final_kernel_results = run_hmc(
        bnn_log_prob_fn, current_state=init_state, **kwds
    )
    print('run_hmc COMPLETE')
    y_pred = predict_from_chain(samples, X_test)
    return y_pred,trace, final_kernel_results,samples

def nest_concat(*args, axis=0):
    """Utility function for concatenating a new Markov chain or trace with
    older ones when resuming a previous calculation.
    """
    return tf.nest.map_structure(lambda *parts: tf.concat(parts, axis=axis), *args)

def ess(chains, **kwargs):
    """Measure effective sample size of Markov chain(s).

    Arguments:
        chains {Tensor or list of Tensors}: If list, first
            dimension should index identically distributed states.
    """
    return tfp.mcmc.effective_sample_size(chains, **kwargs)

def r_hat(tensors):
    """See https://tensorflow.org/probability/api_docs/python/tfp/mcmc/potential_scale_reduction.
    """
    return [tfp.mcmc.diagnostic.potential_scale_reduction(t) for t in tensors]

def get_num_chains(target_log_prob_fn, current_state):
    """Check how many chains your kernel thinks it's dealing
    with. Can help with debugging.
    """
    return tf.size(target_log_prob_fn(*current_state)).numpy()


import time
from selenium import webdriver

#open chrome
chrome = "C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe"
driver = webdriver.Chrome(chrome)
driver.implicitly_wait(10)

#open the target url
driver.get('https://www.51job.com/')
ele = driver.find_element_by_id('kwdselectid')
ele.clear()
ele.send_keys('python')
res = driver.find_element_by_css_selector('body > div.content > div > div.fltr.radius_5 > div > button').click()
info = driver.find_elements_by_css_selector('#resultList div[class=el]')
print(info)

# driver.quit()


import asyncio
import aiohttp
import os, time, sys

# 20 个国家的 Country Code 列表
POP20CC = ('AA AC AG AJ AM AN AO AQ AR AS '
           'AU AX BA BB BF BH BG BK CH WZ').split()

# 创建保存图片的目录
if not os.path.isdir('flags_img'):
    os.makedirs('flags_img')
IMG_DIR = os.path.join(os.getcwd(), 'flags_img')

async def get_flag(cc):
    url_tmp = ('https://www.cia.gov/library/publications/'
        'the-world-factbook/attachments/flags/{}-flag.gif')
    async with aiohttp.ClientSession() as session:
        async with session.get(url_tmp.format(cc)) as resp:
            print('----------------------')
            print(await resp.text())
    async with aiohttp.request('GET', url_tmp.format(cc)) as r:
        resp = await r.text(encoding='UNICODE')
    image = await resp.read()
    return image

@asyncio.coroutine
def download_one(cc):
    image = yield from get_flag(cc)
    path = os.path.join(IMG_DIR, '{}.png'.format(cc))
    with open(path, 'wb') as f:
        f.write(response.content)
    print(cc, end=' ', flush=True)
    return cc

def main(cc_list):
    start_time = time.time()
    loop = asyncio.get_event_loop()
    tasks = [download_one(cc) for cc in cc_list]
    wait_coro = asyncio.wait(tasks)
    res, _ = loop.run_until_complete(wait_coro)
    end_time = time.time()
    print('\n下载 {} 个国旗，耗时 {:.2f} 秒。'.format(
        len(cc_list), end_time - start_time))

if __name__ == '__main__':
    main(POP20CC)