# Flask Web-Framework
from flask import Flask, request
from flask.templating import render_template
from flask_sqlalchemy import SQLAlchemy

# Standard Imports
from datetime import datetime, timedelta
import os
import glob
from random import randint, random
import math
import random

# Plots
import matplotlib.pyplot as plt

# Wordcloud
from wordcloud import WordCloud

# World Map
from pycountry_convert import country_name_to_country_alpha2
import pygal
from pygal.style import DarkStyle

#Natural Language Processing
import spacy
nlp = spacy.load('en_core_web_sm')
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation

################
# Config-Limits
# (prevent server shutdowns. Can be set to high numbers when running local)
#################

kws_speeches_max = 200
lda_speeches_max = 50

# Initializing the app and databases
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///bis_cb_speches_db_20_21.db'
app.config['SQLALCHEMY_BINDS'] = {
        "db2010": "sqlite:///bis_cb_speeches_db_10_clean.db",
        "db2011": "sqlite:///bis_cb_speeches_db_11_clean.db",
        "db2012": "sqlite:///bis_cb_speeches_db_12_clean.db",
        "db2013": "sqlite:///bis_cb_speeches_db_13_clean.db",
        "db2014": "sqlite:///bis_cb_speeches_db_14_clean.db",
        "db2015": "sqlite:///bis_cb_speeches_db_15_clean.db",
        "db2016": "sqlite:///bis_cb_speeches_db_16_clean.db",
        "db2017": "sqlite:///bis_cb_speeches_db_17_clean.db",
        "db2018": "sqlite:///bis_cb_speeches_db_18_clean.db",
        "db2019": "sqlite:///bis_cb_speeches_db_19_clean.db",
        "db2020": "sqlite:///bis_cb_speeches_db_20_clean.db",
        "db2021": "sqlite:///bis_cb_speeches_db_21_clean.db"}
db = SQLAlchemy(app)

#####################################
# Database Models for different years
#####################################

class Speeches2010(db.Model):
    __bind_key__ = "db2010"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2011(db.Model):
    __bind_key__ = "db2011"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2012(db.Model):
    __bind_key__ = "db2012"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2013(db.Model):
    __bind_key__ = "db2013"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2014(db.Model):
    __bind_key__ = "db2014"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2015(db.Model):
    __bind_key__ = "db2015"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2016(db.Model):
    __bind_key__ = "db2016"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2017(db.Model):
    __bind_key__ = "db2017"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2018(db.Model):
    __bind_key__ = "db2018"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2019(db.Model):
    __bind_key__ = "db2019"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2020(db.Model):
    __bind_key__ = "db2020"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

class Speeches2021(db.Model):
    __bind_key__ = "db2021"

    id = db.Column(db.String, primary_key=True)
    date = db.Column(db.Integer)
    author = db.Column(db.String)
    country = db.Column(db.String)
    title = db.Column(db.String)
    pdf = db.Column(db.String)

    def __repr__(self):
        return '<Speech %r>' % self.id

##########################
# Custom defined functions
##########################

def random_with_N_digits(n):
    # Used for randomized Image Paths to prevent browsers from showing old, cached plots
    range_start = 10**(n-1)
    range_end = (10**n)-1
    return randint(range_start, range_end)

def pagination(speeches):

    # Seperating the list of speeches from the search to chunks

    if len(speeches) > 25:
        speeches = speeches[0:25]

    speeches_list = []
    for i in range(math.ceil(len(speeches)/5)):
        ifive = i*5
        speeches_list.append(speeches[ifive:ifive+5])
    return speeches_list

def delete_old_wordclouds():
    # Search for all old worldclouds and delete them

    all_wordclouds = glob.glob("static/images/wordcloud*")
    for path in all_wordclouds:
        os.remove(path)

def create_new_wordCloud(speeches):
    # Generates a new wordcloud from a list of speeches, returns the file path

    delete_old_wordclouds()
    textt = "empty empty empty results"
    for speech in speeches:
        textt = textt + speech.pdf

    wordcloud = WordCloud().generate(textt)
    random_path = random_with_N_digits(5)
    new_wordcloud_path = "static/images/wordcloud" + str(random_path) + ".png"
    wordcloud.to_file(new_wordcloud_path)
    return new_wordcloud_path

def delete_old_timelines():
    # Searches for all old timelines and deletes them

    all_timelines = glob.glob("static/images/timeline*")
    for path in all_timelines:
        os.remove(path)

def create_new_timeline(speeches, keyword):
    # delete old timelines
    delete_old_timelines()
    plt.clf()
    # Prepares the data for the plot
    keys = []
    values = []
    for speech in speeches:
        # add the date of the speech and the count of hits
        keys.append(datetime.fromtimestamp(speech.date))
        values.append(speech.pdf.upper().count(keyword.upper()))

    # Plot creation and export
    random_path = random_with_N_digits(5)
    new_timeline_path = "static/images/timeline" + str(random_path) + ".png"
    plt.style.use("dark_background")
    plt.scatter(keys, values)
    plt.savefig(new_timeline_path, bbox_inches='tight')

    return new_timeline_path

def prepare_map_data(speeches, keyword):
    # Counts the number of hits for every speech and every country

    data = {}
    data_alpha = {}
    for speech in speeches:

        # if this country already exists in the list the current hitcount gets added to the value
        # if not it becomes a new entry
        # 1 gets added to the speech count

        if speech.country in data:
            data[speech.country][0] += speech.pdf.upper().count(keyword.upper())
            data[speech.country][1] += 1
        else:
            data[speech.country] = [0, 0]
            data[speech.country][0] += speech.pdf.upper().count(keyword.upper())
            data[speech.country][1] += 1

    for country in data:
        # Try to convert the country name into the Alpha2-Code
        # If it is successfull the country and its hit code gets added to the list
        # This list gets later passed to the Pygal Package to create the world map
        # The other list is used for the display of the top 3 countries

        try:
            cn_a2_code = country_name_to_country_alpha2(country).lower()
            data_alpha[cn_a2_code] = data[country][1]
        except:
            cn_a2_code = 'Unknown'

    return data, data_alpha

def delete_old_worldmaps():
    # Search for old worldmaps and delete them

    all_worldmaps = glob.glob("static/images/worldmap*")
    for path in all_worldmaps:
        os.remove(path)

def create_new_worldmaps(speeches, keyword):

    delete_old_worldmaps()

    # clear matplot from previous data
    plt.clf()

    # Call Data-Prep-Function and save the results
    dataDicts = prepare_map_data(speeches, keyword)
    data = dataDicts[1]
    top_countries = [(k, dataDicts[0][k]) for k in sorted(dataDicts[0], key=dataDicts[0].get, reverse=True)][0:3]

    # Create Pygal Map
    worldmap = pygal.maps.world.World(style=DarkStyle)
    worldmap.show_legend = False

    # Add the data to the map
    worldmap.title = 'Countries'
    worldmap.add('Frequencies', data)

    # Export as vector image
    random_path = random_with_N_digits(5)
    new_worldmap_path = "static/images/worldmap" + str(random_path) + ".svg"
    worldmap.render_to_file(new_worldmap_path)

    return new_worldmap_path, top_countries

def query_database_all_area(keyword, area, start, end):

    speeches = []

    if not start > 1293750000 or end < 1263337200:
        speeches.extend(Speeches2010.query.filter(Speeches2010.pdf.contains(
            keyword)).filter(Speeches2010.date > start).filter(Speeches2010.date < end).order_by(Speeches2010.date).all())

    if not start > 1325199600 or end < 1294095600:
        speeches.extend(Speeches2011.query.filter(Speeches2011.pdf.contains(
            keyword)).filter(Speeches2011.date > start).filter(Speeches2011.date < end).order_by(Speeches2011.date).all())

    if not start > 1355958000 or end < 1325458800:
        speeches.extend(Speeches2012.query.filter(Speeches2012.pdf.contains(
            keyword)).filter(Speeches2012.date > start).filter(Speeches2012.date < end).order_by(Speeches2012.date).all())

    if not start > 1388444400 or end < 1357167600:
        speeches.extend(Speeches2013.query.filter(Speeches2013.pdf.contains(
            keyword)).filter(Speeches2013.date > start).filter(Speeches2013.date < end).order_by(Speeches2013.date).all())

    if not start > 1418598000 or end < 1388962800:
        speeches.extend(Speeches2014.query.filter(Speeches2014.pdf.contains(
            keyword)).filter(Speeches2014.date > start).filter(Speeches2014.date < end).order_by(Speeches2014.date).all())

    if not start > 1451430000 or end < 1420758000:
        speeches.extend(Speeches2015.query.filter(Speeches2015.pdf.contains(
            keyword)).filter(Speeches2015.date > start).filter(Speeches2015.date < end).order_by(Speeches2015.date).all())

    if not start > 1475186400 or end < 1452466800:
        speeches.extend(Speeches2016.query.filter(Speeches2016.pdf.contains(
            keyword)).filter(Speeches2016.date > start).filter(Speeches2016.date < end).order_by(Speeches2016.date).all())

    if not start > 1514502000 or end < 1483657200:
        speeches.extend(Speeches2017.query.filter(Speeches2017.pdf.contains(
            keyword)).filter(Speeches2017.date > start).filter(Speeches2017.date < end).order_by(Speeches2017.date).all())

    if not start > 1545606000 or end < 1514847600:
        speeches.extend(Speeches2018.query.filter(Speeches2018.pdf.contains(
            keyword)).filter(Speeches2018.date > start).filter(Speeches2018.date < end).order_by(Speeches2018.date).all())

    if not start > 1577401200 or end < 1546815600:
        speeches.extend(Speeches2019.query.filter(Speeches2019.pdf.contains(
            keyword)).filter(Speeches2019.date > start).filter(Speeches2019.date < end).order_by(Speeches2019.date).all())

    if not start > 1609282800 or end < 1578265200:
        speeches.extend(Speeches2020.query.filter(Speeches2020.pdf.contains(
            keyword)).filter(Speeches2020.date > start).filter(Speeches2020.date < end).order_by(Speeches2020.date).all())

    if not start > 1626904800 or end < 1610060400:
        speeches.extend(Speeches2021.query.filter(Speeches2021.pdf.contains(
            keyword)).filter(Speeches2021.date > start).filter(Speeches2021.date < end).order_by(Speeches2021.date).all())

    # If too many speeches are returned, a random sample is taken
    # The size of this sample is defined at the start of the script
    # List size gets reduced to prevent server shutdowns due to (free) hosting limitations

    if len(speeches) > kws_speeches_max:
        speeches = random.sample(speeches, kws_speeches_max)

    speeches.sort(key=lambda speech: speech.date)
    speeches.reverse()

    return speeches

def query_database_area(keyword, area, start, end):
    speeches = []

    if not start > 1293750000 or end < 1263337200:
        speeches.extend(Speeches2010.query.filter(Speeches2010.pdf.contains(
            keyword)).filter(Speeches2010.date > start).filter(Speeches2010.date < end).filter(Speeches2010.country == area).order_by(Speeches2010.date).all())

    if not start > 1325199600 or end < 1294095600:
        speeches.extend(Speeches2011.query.filter(Speeches2011.pdf.contains(
            keyword)).filter(Speeches2011.date > start).filter(Speeches2011.date < end).filter(Speeches2011.country == area).order_by(Speeches2011.date).all())

    if not start > 1355958000 or end < 1325458800:
        speeches.extend(Speeches2012.query.filter(Speeches2012.pdf.contains(
            keyword)).filter(Speeches2012.date > start).filter(Speeches2012.date < end).filter(Speeches2012.country == area).order_by(Speeches2012.date).all())

    if not start > 1388444400 or end < 1357167600:
        speeches.extend(Speeches2013.query.filter(Speeches2013.pdf.contains(
            keyword)).filter(Speeches2013.date > start).filter(Speeches2013.date < end).filter(Speeches2013.country == area).order_by(Speeches2013.date).all())

    if not start > 1418598000 or end < 1388962800:
        speeches.extend(Speeches2014.query.filter(Speeches2014.pdf.contains(
            keyword)).filter(Speeches2014.date > start).filter(Speeches2014.date < end).filter(Speeches2014.country == area).order_by(Speeches2014.date).all())

    if not start > 1451430000 or end < 1420758000:
        speeches.extend(Speeches2015.query.filter(Speeches2015.pdf.contains(
            keyword)).filter(Speeches2015.date > start).filter(Speeches2015.date < end).filter(Speeches2015.country == area).order_by(Speeches2015.date).all())

    if not start > 1475186400 or end < 1452466800:
        speeches.extend(Speeches2016.query.filter(Speeches2016.pdf.contains(
            keyword)).filter(Speeches2016.date > start).filter(Speeches2016.date < end).filter(Speeches2016.country == area).order_by(Speeches2016.date).all())

    if not start > 1514502000 or end < 1483657200:
        speeches.extend(Speeches2017.query.filter(Speeches2017.pdf.contains(
            keyword)).filter(Speeches2017.date > start).filter(Speeches2017.date < end).filter(Speeches2017.country == area).order_by(Speeches2017.date).all())

    if not start > 1545606000 or end < 1514847600:
        speeches.extend(Speeches2018.query.filter(Speeches2018.pdf.contains(
            keyword)).filter(Speeches2018.date > start).filter(Speeches2018.date < end).filter(Speeches2018.country == area).order_by(Speeches2018.date).all())

    if not start > 1577401200 or end < 1546815600:
        speeches.extend(Speeches2019.query.filter(Speeches2019.pdf.contains(
            keyword)).filter(Speeches2019.date > start).filter(Speeches2019.date < end).filter(Speeches2019.country == area).order_by(Speeches2019.date).all())

    if not start > 1609282800 or end < 1578265200:
        speeches.extend(Speeches2020.query.filter(Speeches2020.pdf.contains(
            keyword)).filter(Speeches2020.date > start).filter(Speeches2020.date < end).filter(Speeches2020.country == area).order_by(Speeches2020.date).all())

    if not start > 1626904800 or end < 1610060400:
        speeches.extend(Speeches2021.query.filter(Speeches2021.pdf.contains(
            keyword)).filter(Speeches2021.date > start).filter(Speeches2021.date < end).filter(Speeches2021.country == area).order_by(Speeches2021.date).all())

    # If too many speeches are returned, a random sample is taken
    # The size of this sample is defined at the start of the script
    # List size gets reduced to prevent server shutdowns due to (free) hosting limitations

    if len(speeches) > kws_speeches_max:
        speeches = random.sample(speeches, kws_speeches_max)

    speeches.sort(key=lambda speech: speech.date)
    speeches.reverse()
    return speeches

def query_database(keyword=' ', area='all', start=(datetime.utcnow() - timedelta(days=30)).timestamp(), end=datetime.utcnow().timestamp()):

    # Convert the inputs of the dates to date objects

    try:
        start = datetime.fromisoformat(start).timestamp()
    except:
        start = (datetime.utcnow() - timedelta(days=30)).timestamp()

    try:
        end = datetime.fromisoformat(end).timestamp()
    except:
        end = datetime.utcnow().timestamp()

    # Check for specified area to query, or all get queried

    if area == 'all':
        speeches = query_database_all_area(keyword, area, start, end)
    else:
        speeches = query_database_area(keyword, area, start, end)

    return speeches

# Date filter
@app.template_filter('datefromint')
def format_date(int):
    # Custom filter to format the date object
    # Filter gets applied the jinja2-html template

    date = datetime.fromtimestamp(int)
    date_formatted = date.strftime('%d.%m.%Y')
    return date_formatted

################
# Keyword Search
################

@app.route('/', methods=['POST', 'GET'])
def index():
    if request.method == 'POST':
        ################
        # Search Request
        ################

        # Search parameters get collected
        keyword = request.form['keyword']
        area = request.form['area']
        startdate = request.form['startdate']
        enddate = request.form['enddate']

        # Database query and pagination
        speeches = query_database(keyword, area, startdate, enddate)
        speeches_list = pagination(speeches)

        # Plots and Maps creation
        new_wordcloud_path = create_new_wordCloud(speeches)
        new_timeline_path = create_new_timeline(speeches, keyword)
        map_results = create_new_worldmaps(speeches, keyword)
        new_worldmap_path = map_results[0]
        top_countries = map_results[1]

        img_paths = [new_wordcloud_path, new_timeline_path, new_worldmap_path]

        return render_template('index.html', speeches_count=len(speeches), speeches=speeches_list, top_countries=top_countries, img_paths=img_paths)

    if request.method == 'GET':
        #####################
        # Regular Pageload
        #####################

        # Results for default query (all areas, last 30 days)
        speeches = query_database()
        speeches_list = pagination(speeches)

        # Wordcloud can be created without a keyword
        new_wordcloud_path = create_new_wordCloud(speeches)

        # Wordcloud gets shown as placeholders for other plots
        img_paths = [new_wordcloud_path,
                     new_wordcloud_path, new_wordcloud_path]

        return render_template('index.html', speeches_count=len(speeches), speeches=speeches_list, img_paths=img_paths)

    else:
        # This case should never occur. Default query just in case

        speeches = query_database()
        return render_template('tour.html', speeches=speeches)

################
# Topic Modeling
################

def delete_old_tm_results():
    # Search for old scatterplots and delete them
    all_tm_results = glob.glob("static/images/tm_results*")
    for path in all_tm_results:
        os.remove(path)

def topic_modeling(speeches, num_comps):
    if len(speeches) > lda_speeches_max:
        speeches = random.sample(speeches, lda_speeches_max)
    # Setting up the Vectorizer
    cv = CountVectorizer(max_df=0.8, min_df=0.01, stop_words='english')
    dtm = cv.fit_transform([speech.pdf for speech in speeches])
    LDA = LatentDirichletAllocation(n_components=num_comps)
    LDA.fit(dtm)

    # Get the 15 Top words for each Topic
    topics = []
    for i,topic in enumerate(LDA.components_):
        topics.append([cv.get_feature_names()[index] for index in topic.argsort()[-15:]])

    # Prepare the Data for the Plot and overview
    topic_results = LDA.transform(dtm)
    color_names = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', 'tab:gray', 'tab:olive', 'tab:cyan']
    x = []
    y = []
    colors = []
    topic_counter = [0 for topic in enumerate(LDA.components_)]

    topic_percentages = [0 for topic in enumerate(LDA.components_)]
    index = 0
    for speech in speeches:

        # get the x value
        x.append(datetime.fromtimestamp(speech.date))
        # get the y value
        y.append(topic_results[index][topic_results[index].argmax()])
        # get the color (topic) and add one to the counter list for the topic
        topic_index = topic_results[index].argmax()
        colors.append(color_names[topic_index])
        topic_counter[topic_index] += 1
        index += 1

    # Count the counter lists, calculate the percentages and make them into a list.
    sum = 0
    for index in range(len(topic_counter)):
        sum += topic_counter[index]
    for index in range(len(topic_counter)):
        topic_percentages[index] = round((topic_counter[index] / sum) * 100, 1)

    # Sort the topics by their percentages
    topwords_and_percentages = []
    for index in range(len(topics)):
        percentage = topic_percentages[index]
        word_string = " ".join(list(reversed(topics[index])))
        # topwords_and_percentages.append([topic_percentages[index], list(reversed(topics[index]))])
        topwords_and_percentages.append([percentage, word_string, index])

    # Results in descending order
    topwords_and_percentages.sort()
    topwords_and_percentages.reverse()

    # Create the plot
    delete_old_tm_results()
    plt.clf()
    plt.style.use("dark_background")
    plt.scatter(x, y, c=colors, alpha=0.9)

    # Export as image
    random_path = random_with_N_digits(5)
    new_tm_results_path = "static/images/tm_results" + str(random_path) + ".png"
    plt.savefig(new_tm_results_path, bbox_inches='tight')

    return topwords_and_percentages, new_tm_results_path

@app.route('/topicmodeling', methods=['POST', 'GET'])
def topicmodeling():
    if request.method == 'POST':
        ############
        # TM-Request
        ############

        # Get request parameters
        try:
            number_topics = int(request.form['numbertopics'])
        except:
            number_topics = 3
        area = request.form['area']
        startdate = request.form['startdate']
        enddate = request.form['enddate']

        # Query database
        speeches = query_database(area=area, start=startdate, end=enddate)

        # Topic Modeling
        results = topic_modeling(speeches, num_comps=number_topics)
        topics = results[0]
        path = results[1]

        return render_template('topicmodeling.html', speeches_count=len(speeches), topics=topics, path=path)

    else:
        # Regular page load
        return render_template('topicmodeling.html')

#############
# Empty Pages
#############
@app.route('/tour', methods=['POST', 'GET'])
def tour():
    if request.method == 'POST':
        pass

    else:
        return render_template('tour.html')

@app.route('/impressum', methods=['POST', 'GET'])
def impressum():
    if request.method == 'POST':
        pass

    else:
        return render_template('impressum.html')

#############
# Main script
#############

if __name__ == "__main__":

    # Start the app
    app.run()


import numpy as np
from utils.utils import Utils
import pandas as pd
import sklearn.discriminant_analysis as disc
from utils.graphics import Graphics

class LDA:
    def __init__(self, t1, t2, categorical_mark, predictor_mark, predictor_var):
        self.t1 = t1
        self.t2 = t2
        Utils.replace_na_df(self.t1)
        Utils.replace_na_df(self.t2)

        self.var = np.array(t1.columns)
        print(self.var)
        self.var_categorical = self.var[0:categorical_mark]
        print(self.var_categorical)
        Utils.code(self.t1, self.var_categorical)
        Utils.code(self.t2, self.var_categorical)
        print(self.t1)
        print(self.t2)
        # Select the predictor variables and the discriminant variable
        self.var_p = self.var[0:predictor_mark]
        self.var_c = predictor_var
        print(self.var_p)
        print(self.var_c)

        self.x = self.t1[self.var_p].values
        print(self.x)
        self.y = self.t1[self.var_c].values
        print(self.y)

    def fit(self):
        self.lda_model = disc.LinearDiscriminantAnalysis()
        self.lda_model.fit(self.x, self.y)

        self.class_setBase = self.lda_model.predict(self.x)
        self.table_classificationB = pd.DataFrame(
            data={str(self.var_c[0]): self.y, 'prediction': self.class_setBase},
            index=self.t1.index)
        self.tabel_clasificationB_err = self.table_classificationB[self.y != self.class_setBase]
        self.n = len(self.y)
        self.n_err = len(self.tabel_clasificationB_err)
        self.degree_of_credence = (self.n - self.n_err) * 100 / self.n
        return self

    def apply(self):
        self.class_setTest = self.lda_model.predict(self.t2[self.var_p].values)
        table_of_classification = pd.DataFrame(
            data={'prediction': self.class_setTest},
            index=self.t2.index
        )
        self.g = self.lda_model.classes_
        self.q = len(self.g)
        self.mat_c = pd.DataFrame(data=np.zeros((self.q, self.q)), index=self.g, columns=self.g)
        for i in range(self.n):
            self.mat_c.loc[self.y[i], self.class_setBase[i]] += 1
        accuracy_groups = np.diag(self.mat_c) * 100 / np.sum(self.mat_c, axis=1)
        self.mat_c['Accuracy'] = accuracy_groups

        # Instances on the first 2 axes of discrimination
        self.u = self.lda_model.scalings_
        self.z = self.x @ self.u
        self.xc = self.lda_model.means_
        self.zc = self.xc @ self.u
        return self

    def get_results(self):
        return None

    def visualise(self):
        # Get the number of discriminant axes (number of columns in u)
        r = np.shape(self.u)[1]
        if r > 1:
            Graphics.scatter_discriminant(self.z[:, 0], self.z[:, 1], self.y, self.t1.index, self.zc[:, 0], self.zc[:, 1], self.g)
        for i in range(r):
            Graphics.distribution(self.z[:, i], self.y, self.g, axis=i)
        return self

    def show(self):
        Graphics.show()


# -*- coding: utf-8 -*-
#by liangwenhao
#第 0005 题：你有一个目录，装了很多照片，把它们的尺寸变成都不大于 iPhone5 分辨率的大小。

from PIL import Image, ImageOps
import os, os.path

L = [ x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.jpg' ]
#os.path.splitext(path) 分离文件名与扩展名；默认返回(fname,fextension)元组，可做分片操作

for x in L:
    img = Image.open(x)#创建image对象
    xsize, ysize = img.size#获取高宽
    xsize = 500#设定高
    ysize = ysize * 500 // xsize#设定宽
    img = ImageOps.fit(img,(xsize,ysize))#修改尺寸
    img.save("out"+x)#保存


# from https://github.com/bast/somepackage/blob/master/setup.py
from setuptools import setup, find_packages

import os
import sys

_here = os.path.abspath(os.path.dirname(__file__))

if sys.version_info[0] < 3:
    with open(os.path.join(_here, 'README.md')) as f:
        long_description = f.read()
else:
    with open(os.path.join(_here, 'README.md'), encoding='utf-8') as f:
        long_description = f.read()

version = {}
with open(os.path.join(_here, 'grid', 'version.py')) as f:
    exec(f.read(), version)

setup(
    name='p_grid',
    version=version['__version__'],
    description=('Simple python grid'),
    long_description=long_description,
    author='Yoieh',
    author_email='yoieh@live.se',
    url='https://github.com/yoieh/p_grid',
    packages=find_packages("src"),
    package_dir={"": "src"},
    license="MIT",
    install_requires=_here.joinpath("requirements.txt").read_text().split(
        "\n"),
)


# for adding strings and no. with formula.
a=663
c=8307399011
b='''my house no is {} at houising board colony hisar.
My mobile no. is {}.'''
print(b.format(a,c))

# sepicifying the position of strings
# positon start form 0.
f='''today at {1} of {4} {2}. i buy {3} packs of {0}'''
x='pizza'
y="10"
z="2021"
d="5"
e="6"
print(f.format(x,y,z,d,e))


'''
Created on Oct 28, 2013

@author: J.Akeret, S. Birrer
'''
from __future__ import print_function, division, absolute_import, unicode_literals

import numpy
#import schwimmbad
from schwimmbad import MPIPool
#from emcee.mpi_pool import MPIPool

from mpipso.pso import ParticleSwarmOptimizer
import sys

class MpiParticleSwarmOptimizer(ParticleSwarmOptimizer):
    """
    PSO with support for MPI to distribute the workload over multiple nodes
    """

    def __init__(self, func, low, high, particleCount=25, threads=1):
        self.threads = threads
        pool = MPIPool()
        if not pool.is_master():
            pool.wait()
            sys.exit(0)
        ParticleSwarmOptimizer.__init__(self, func, low, high, particleCount=particleCount, pool=pool)

    def _converged(self, it, p, m, n):

        if self.is_master():
            converged = super(MpiParticleSwarmOptimizer, self)._converged(it, p, m, n)
        else:
            converged = False
        converged = self.mpiBCast(converged)
        return converged

    def _get_fitness(self, swarm):

        mpiSwarm = self.mpiBCast(swarm)
        pos = numpy.array([part.position for part in mpiSwarm])
        results = self.pool.map(self.func, pos)
        lnprob = numpy.array([l[0] for l in results])
        for i, particle in enumerate(swarm):
            particle.fitness = lnprob[i]
            particle.position = pos[i]

    def is_master(self):
        return self.pool.is_master()

    def isMaster(self):
        return self.is_master()

    def mpiBCast(self, value):
        """
        Mpi bcasts the value and Returns the value from the master (rank = 0).
        """
        #getLogger().debug("Rank: %s, pid: %s MpiPool: bcast", MPI.COMM_WORLD.Get_rank(), os.getpid())

        return self.pool.comm.bcast(value)
        #return MPI.COMM_WORLD.bcast(value)


from flask import Blueprint, render_template, redirect, request, flash, url_for
import hashlib
from flask import make_response
import xml.etree.ElementTree as ET

wechat = Blueprint(
      "wechat", __name__, template_folder="../templates", static_folder="../static")

WX_TOKEN = 'duansq'

@wechat.route("/wechat_api/", methods=['GET', 'POST'])
def index():
   if request.method == 'GET':
      token = WX_TOKEN
      data = request.args
      signature = data.get('signature', '')
      timestamp = data.get('timestamp', '')
      nonce = data.get('nonce', '')
      echostr = data.get('echostr', '')
      s = sorted([timestamp, nonce, token])
      # 字典排序
      s = ''.join(s)
      if hashlib.sha1(s.encode('utf-8')).hexdigest() == signature:
         # 判断请求来源，并对接受的请求转换为utf-8后进行sha1加密
         response = make_response(echostr)
         return response

def message_del(content):
   # 次数是自定义的消息处理函数，自由发挥
   if "baidu" in content:
      message = "www.baidu.com"
   elif "金牛" in content:
      message = "贪财好色小心眼"
   else:
      message = "我不知道！"
   return message


def quick_sort(u, initial, final):
   if final - initial <= 0:  # partitioned list has cardinality of 1, by definition sorted
      return True
   pivot_index = partition(u, initial, final)  # sort & obtain the index to split u
   quick_sort(u, initial, pivot_index - 1)  # recursivly repeat for each half of u still unsorted about p_index
   quick_sort(u, pivot_index + 1, final)
   return True

def partition(u, initial, final):
   pivot_value = u[final]
   lowest = i = initial
   while i != final:
      while u[lowest] <= pivot_value and lowest < final:
         lowest += 1
      i = lowest
      while u[i] > pivot_value and i < final:
         i += 1
      swap = u[lowest]
      u[lowest] = u[i]
      u[i] = swap
   return lowest

def hanoi(n, start, middle, final):
   if n <= 0:
      return True
   hanoi(n - 1, start, final, middle)  # move to midde
   final.append(start.pop())  # append to final
   hanoi(n - 1, middle, start, final)  # move from middle to final
   print(start, middle, final)
   return True

def helper_test_quick_sort():  # testing function for quicksort - technically not a helper function
   print("\nQUICK SORT")
   v1 = [10,9,8,7,6,5,4,3,2,1,0]  # test cases
   v2 = [100,1,1000,9,8,7,2,2000,10]
   v3 = [100,10,1000,9,8,7,2,6,5,2,3,1]
   expect = ["[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]",  # hand-sorted answers
   "[1, 2, 7, 8, 9, 10, 100, 1000, 2000]",
   "[1, 2, 2, 3, 5, 6, 7, 8, 9, 10, 100, 1000]"]
   test_lists = [v1, v2, v3]
   for i in range(0, len(test_lists), 1):  # test the 3 test cases w/ fancy output
      test = list(test_lists[i])
      print("Input:", test)
      quick_sort(test, 0, len(test) - 1)
      print("Answer:", expect[i])
      print("Output:", test, "\n")
   return True

def helper_test_hanoi():  # testing function for hanoi - technically not a helper function
   print("\nBefore HANOI:")
   start_tower = [i for i in range(5)]  # generate a start tower
   middle_tower = []
   final_tower = []
   print("Starting Tower:", start_tower)  # middle and final should be empty
   print("Middle Tower:", middle_tower)
   print("Final Tower:", final_tower)
   hanoi(len(start_tower), start_tower, middle_tower, final_tower)  # hanoi from start to final
   print("\nAfter HANOI:")  # start and middle should be empty
   print("Starting Tower:", start_tower)
   print("Middle Tower:", middle_tower)
   print("Final Tower:", final_tower)
   return True

def main():
   helper_test_quick_sort()
   helper_test_hanoi()
   return True

main()


from datetime import datetime

import pandas as pd

# Завантаження даних
csv_filename = f"currency_data/combined_data_currency_{datetime.today().date()}.csv"

# Read CSV file, treating missing values as 0 in the sentiment column
currency_data = pd.read_csv(
    csv_filename,
    skiprows=[0],
    names=[
        "Data",
        "Open",
        "High",
        "Low",
        "Close",
        "Adj Close",
        "Volume",
        "Currency",
        "sentiment",
    ],
    dtype={
        "Open": float,
        "High": float,
        "Low": float,
        "Close": float,
        "Adj Close": float,
        "Volume": int,
        "sentiment": float,  # Change the dtype to float to handle potential NaN values
    },
    na_values={"sentiment": 0},  # Specify how NaN values are represented in the CSV
)
currency_data["Data"] = pd.to_datetime(currency_data["Data"])

# Розрахунок технічних індикаторів для кожної валютної пари
def calculate_technical_indicators(data):
    data["SMA_50"] = data["Close"].rolling(window=50).mean()
    data["SMA_200"] = data["Close"].rolling(window=200).mean()
    data["RSI"] = 100 - (
        100 / (1 + data["Close"].pct_change().rolling(window=14).mean())
    )
    data["MACD"] = (
        data["Close"].ewm(span=12, adjust=False).mean()
        - data["Close"].ewm(span=26, adjust=False).mean()
    )
    data["Signal_Line"] = data["MACD"].ewm(span=9, adjust=False).mean()
    data["Bollinger_Band_Upper"] = (
        data["Close"].rolling(window=20).mean()
        + 2 * data["Close"].rolling(window=20).std()
    )
    data["Bollinger_Band_Lower"] = (
        data["Close"].rolling(window=20).mean()
        - 2 * data["Close"].rolling(window=20).std()
    )
    return data

# Застосування функції до кожної валютної пари
currency_data = (
    currency_data.groupby("Currency")
    .apply(calculate_technical_indicators)
    .reset_index(drop=True)
)

# Вибірка необхідних стовпців для збереження
selected_columns = [
    "Data",
    "Open",
    "High",
    "Low",
    "Close",
    "Adj Close",
    "Volume",
    "Currency",
    "sentiment",
    "SMA_50",
    "SMA_200",
    "RSI",
    "MACD",
    "Signal_Line",
    "Bollinger_Band_Upper",
    "Bollinger_Band_Lower",
]

# Збереження оновленого DataFrame без перших двох стовпців
currency_data[selected_columns].to_csv(
    f"currency_data/currency_data_with_all_indicators_{datetime.today().date()}.csv",
    index=False,
)


import sys
sys.stdin = open("problem_4.txt", "r")

T = int(input())
for tc in range(1, T+1):
    N = int(input())
    n = list(map(int, input().split()))
    asc_list = n[:]
    des_list = n[:]
    for j in range(len(n)-1):
        min_idx = j
        for k in range(j+1, len(n)):
            if asc_list[min_idx] > asc_list[k]:
                min_idx = k
        asc_list[j], asc_list[min_idx] = asc_list[min_idx], asc_list[j]              # 여기서 indent가 두번 들어갔었음.

    for j in range(len(n)-1):
        max_idx = j
        for k in range(j+1, len(n)):
            if des_list[max_idx] < des_list[k]:
                max_idx = k
        des_list[j], des_list[max_idx] = des_list[max_idx], des_list[j]
    # print(asc_list)
    asc_list_cut = asc_list[0:len(asc_list)//2]
    des_list_cut = des_list[0:len(des_list)//2]
    result = []
    for i in range(5):
        result.append(des_list_cut[i])
        result.append(asc_list_cut[i])
    print(f'#{tc}', *result)
    # print(*result)


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

"""
This file is part of OpenSesame.

OpenSesame is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

OpenSesame is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with OpenSesame.  If not, see <http://www.gnu.org/licenses/>.
"""
from libopensesame.py3compat import *
import random
import math
import warnings
# The classes below are unused, but imported so that they are available in the
# workspace.
from openexp.canvas_elements import (Rect, Line, Text, Ellipse, Circle,
                                     FixDot, Gabor, NoisePatch, Image, Arrow,
                                     Polygon)
from libopensesame.widgets.widget_factory import (Label, Button, ImageWidget,
                                                  ImageButton, TextInput,
                                                  RatingScale, Checkbox)

# Factory functions
def Experiment(osexp_path=None, log_path='defaultlog.csv', fullscreen=False,
               subject_nr=0, **kwargs):
    """A factory function that creates a new `Experiment` object. This is only
    useful when implementing an experiment entirely through a Python script,
    rather than through the user interface.

    Parameters
    ----------
    osexp_path : str or Path or None, optional
        If a path to an `.osexp` file is specified, this file is opened and
        can be run directly by calling `Experiment.run()`. If no experiment
        file is specified, an empty experiment is initialized.
    log_path : str or Path, optional
    fullscreen : bool, optional
    subject_nr : int, optional
    kwargs : dict, optional
        Optional keyword arguments that are interpreted as experimental
        variables. The main use of this is to specify the backend through
        the `canvas_backend` keyword.

    Examples
    --------
    To implement an experiment fully programmatically:

    ~~~ .python
    from libopensesame.python_workspace_api import (
        Experiment, Canvas, Text, Keyboard)
    exp, win, clock, log = Experiment(canvas_backend='legacy')
    c = Canvas()
    c += Text('Press any key')
    c.show()
    kb = Keyboard()
    kb.get_key()
    exp.end()
    ~~~

    To load an experiment file and run it:

    ~~~ .python
    from libopensesame.python_workspace_api import Experiment
    exp, win, clock, log = Experiment(osexp_path='my_experiment.osexp',
                                      subject_nr=2)
    exp.run()
    ~~~

    Returns
    -------
    tuple
        An (exp, win, clock, log) tuple corresponding to the Experiment,
        window handle (backend-specific), Clock, and Log objects.
    """
    global experiment
    from libopensesame.experiment import Experiment as RuntimeExperiment
    if osexp_path is None:
        from libopensesame.syntax import Syntax
        syntax = Syntax(None)
        string = '\n'.join([syntax.create_cmd('set', [key, value])
                            for key, value in kwargs.items()])
    else:
        string = osexp_path
    experiment = RuntimeExperiment(experiment_path=osexp_path,
                                   logfile=log_path, fullscreen=fullscreen,
                                   subject_nr=subject_nr, string=string)
    experiment.init_random()
    experiment.init_display()
    experiment.init_clock()
    experiment.init_sound()
    experiment.init_log()
    return experiment, experiment.window, experiment.clock, experiment.log

def Form(*args, **kwargs):
    r"""A factory function that creates a new `Form` object. For a
    description
    of possible keywords, see:

    - %link:manual/forms/widgets%

    Returns
    -------
    canvas
        A `Form` object.

    Examples
    --------
    >>> form = Form()
    >>> label = Label(text='label')
    >>> button = Button(text='Ok')
    >>> form.set_widget(label, (0,0))
    >>> form.set_widget(button, (0,1))
    >>> form._exec()
    """
    from libopensesame.widgets import form
    return form(experiment, **kwargs)

def Canvas(auto_prepare=True, **style_args):
    r"""A factory function that creates a new `Canvas` object. For a
    description of possible keywords, see:

    - %link:manual/python/canvas%

    Returns
    -------
    canvas
        A `Canvas` object.

    Examples
    --------
    >>> my_canvas = Canvas(color=u'red', penwidth=2)
    >>> my_canvas.line(-10, -10, 10, 10)
    >>> my_canvas.line(-10, 10, 10, -10)
    >>> my_canvas.show()
    """
    from openexp.canvas import Canvas
    return Canvas(experiment, auto_prepare=auto_prepare, **style_args)

def Keyboard(**resp_args):
    r"""A factory function that creates a new `Keyboard` object. For a
    description of possible keywords, see:

    - %link:manual/python/keyboard%

    Returns
    -------
    keyboard
        A `Keyboard` object.

    Examples
    --------
    >>> my_keyboard = Keyboard(keylist=[u'a', u'b'], timeout=5000)
    >>> key, time = my_keyboard.get_key()
    """
    from openexp.keyboard import Keyboard
    return Keyboard(experiment, **resp_args)

def Mouse(**resp_args):
    r"""A factory function that creates a new `Mouse` object. For a
    description
    of possible keywords, see:

    - %link:manual/python/mouse%

    Returns
    -------
    mouse
        A `mouse` object.

    Examples
    --------
    >>> my_mouse = Mouse(keylist=[1,3], timeout=5000)
    >>> button, time = my_mouse.get_button()
    """
    from openexp.mouse import Mouse
    return Mouse(experiment, **resp_args)

def Sampler(src, **playback_args):
    r"""A factory function that creates a new `Sampler` object. For a
    description of possible keywords, see:

    - %link:manual/python/sampler%

    Returns
    -------
    sampler
        A SAMPLER object.

    Examples
    --------
    >>> src = pool['bark.ogg']
    >>> my_sampler = Sampler(src, volume=.5, pan='left')
    >>> my_sampler.play()
    """
    from openexp.sampler import Sampler
    return Sampler(experiment, src, **playback_args)

# Miscellaneous API	functions

def Synth(osc="sine", freq=440, length=100, attack=0, decay=5):
    r"""A factory function that synthesizes a sound and returns it as a
    `Sampler` object.

    Parameters
    ----------
    osc : str, unicode, optional
        Oscillator, can be "sine", "saw", "square" or "white_noise".
    freq : str, unicode, int, float, optional
        Frequency, either an integer value (value in hertz) or a string ("A1",
        "eb2", etc.).
    length : int, float, optional
        The length of the sound in milliseconds.
    attack : int, float, optional
        The attack (fade-in) time in milliseconds.
    decay : int, float, optional
        The decay (fade-out) time in milliseconds.

    Returns
    -------
    sampler
        A SAMPLER object.

    Examples
    --------
    >>> my_sampler = Synth(freq=u'b2', length=500)
    """
    from openexp.synth import Synth
    return Synth(experiment, osc=osc, freq=freq, length=length, attack=attack,
                 decay=decay)

def copy_sketchpad(name):
    r"""Returns a copy of a `sketchpad`'s canvas.

    Parameters
    ----------
    name : str, unicode
        The name of the `sketchpad`.

    Returns
    -------
    canvas
        A copy of the `sketchpad`'s canvas.

    Examples
    --------
    >>> my_canvas = copy_sketchpad('my_sketchpad')
    >>> my_canvas.show()
    """
    c = Canvas()
    c.copy(experiment.items[name].canvas)
    return c

def reset_feedback():
    r"""Resets all feedback variables to their initial state.

    Examples
    --------
    >>> reset_feedback()
    """
    experiment.reset_feedback()

def set_subject_nr(nr):
    r"""Sets the subject number and parity (even/ odd). This function is called
    automatically when an experiment is started, so you only need to call it
    yourself if you overwrite the subject number that was specified when the
    experiment was launched.

    Parameters
    ----------
    nr : int
        The subject nr.

    Examples
    --------
    >>> set_subject_nr(1)
    >>> print('Subject nr = %d' % var.subject_nr)
    >>> print('Subject parity = %s' % var.subject_parity)
    """
    experiment.set_subject(nr)

def sometimes(p=.5):
    r"""Returns True with a certain probability. (For more advanced
    randomization, use the Python `random` module.)

    Parameters
    ----------
    p : float, optional
        The probability of returning True.

    Returns
    -------
    bool
        True or False

    Examples
    --------
    >>> if sometimes():
    >>>         print('Sometimes you win')
    >>> else:
    >>>         print('Sometimes you loose')
    """
    if (not isinstance(p, float) and not isinstance(p, int)) or p < 0 or p > 1:
        raise ValueError(
            f'p should be a numeric value between 0 and 1, not {p}')
    return random.random() < p

def pause():
    r"""Pauses the experiment."""
    experiment.pause()

def register_cleanup_function(fnc):
    r"""Registers a clean-up function, which is executed when the experiment
    ends. Clean-up functions are executed at the very end, after the display,
    sound device, and log file have been closed. Clean-up functions are also
    executed when the experiment crashes.

    Examples
    --------
    >>> def my_cleanup_function():
    >>>         print(u'The experiment is finished!')
    >>> register_cleanup_function(my_cleanup_function)
    """
    experiment.cleanup_functions.append(fnc)

def xy_from_polar(rho, phi, pole=(0, 0)):
    r"""Converts polar coordinates (distance, angle) to Cartesian coordinates
    (x, y).

    Parameters
    ----------
    rho : float
        The radial coordinate, also distance or eccentricity.
    phi : float
        The angular coordinate. This reflects a clockwise rotation in degrees
        (i.e. not radians), where 0 is straight right.
    pole : tuple, optional
        The reference point.

    Returns
    -------
    tuple
        An (x, y) coordinate tuple.

    Examples
    --------
    >>> # Draw a cross
    >>> x1, y1 = xy_from_polar(100, 45)
    >>> x2, y2 = xy_from_polar(100, -45)
    >>> c = Canvas()
    >>> c.line(x1, y1, -x1, -y1)
    >>> c.line(x2, y2, -x2, -y2)
    >>> c.show()
    """
    try:
        rho = float(rho)
    except:
        raise TypeError('rho should be numeric in xy_from_polar()')
    try:
        phi = float(phi)
    except:
        raise TypeError('phi should be numeric in xy_from_polar()')
    phi = math.radians(phi)
    ox, oy = parse_pole(pole)
    x = rho * math.cos(phi) + ox
    y = rho * math.sin(phi) + oy
    return x, y

def xy_to_polar(x, y, pole=(0, 0)):
    r"""Converts Cartesian coordinates (x, y) to polar coordinates (distance,
    angle).

    Parameters
    ----------
    x : float
        The X coordinate.
    y : float
        The Y coordinate.
    pole : tuple, optional
        The reference point.

    Returns
    -------
    tuple
        An (rho, phi) coordinate tuple. Here, `rho` is the radial coordinate,
        also distance or eccentricity. `phi` is the angular coordinate in
        degrees (i.e. not radians), and reflects a counterclockwise rotation,
        where 0 is straight right.

    Examples
    --------
    >>> rho, phi = xy_to_polar(100, 100)
    """
    try:
        x = float(x)
    except:
        raise TypeError('x should be numeric in xy_to_polar()')
    try:
        y = float(y)
    except:
        raise TypeError('y should be numeric in xy_to_polar()')
    ox, oy = parse_pole(pole)
    dx = x-ox
    dy = y-oy
    rho = math.sqrt(dx**2 + dy**2)
    phi = math.degrees(math.atan2(dy, dx))
    return rho, phi

def xy_distance(x1, y1, x2, y2):
    r"""Gives the distance between two points.

    Parameters
    ----------
    x1 : float
        The x coordinate of the first point.
    y1 : float
        The y coordinate of the first point.
    x2 : float
        The x coordinate of the second point.
    y2 : float
        The y coordinate of the second point.

    Returns
    -------
    float
        The distance between the two points.
    """
    try:
        x1 = float(x1)
        y1 = float(y1)
        x2 = float(x2)
        y2 = float(y2)
    except:
        raise TypeError('Coordinates should be numeric in xy_distance()')
    return math.sqrt((x1-x2)**2+(y1-y2)**2)

def xy_circle(n, rho, phi0=0, pole=(0, 0)):
    r"""Generates a list of points (x,y coordinates) in a circle. This can be
    used to draw stimuli in a circular arrangement.

    Parameters
    ----------
    n : int
        The number of x,y coordinates to generate.
    rho : float
        The radial coordinate, also distance or eccentricity, of the first
        point.
    phi0 : float, optional
        The angular coordinate for the first coordinate. This is a
        counterclockwise rotation in degrees (i.e. not radians), where 0 is
        straight right.
    pole : tuple, optional
        The reference point.

    Returns
    -------
    list
        A list of (x,y) coordinate tuples.

    Examples
    --------
    >>> # Draw 8 rectangles around a central fixation dot
    >>> c = Canvas()
    >>> c.fixdot()
    >>> for x, y in xy_circle(8, 100):
    >>>         c.rect(x-10, y-10, 20, 20)
    >>> c.show()
    """
    try:
        n = int(n)
        if n < 0:
            raise ValueError()
    except (ValueError, TypeError):
        raise ValueError('n should be a non-negative integer in xy_circle()')
    try:
        phi0 = float(phi0)
    except (ValueError, TypeError):
        raise TypeError('phi0 should be numeric in xy_circle()')
    l = []
    for i in range(n):
        l.append(xy_from_polar(rho, phi0, pole=pole))
        phi0 += 360./n
    return l

def xy_grid(n, spacing, pole=(0, 0)):
    r"""Generates a list of points (x,y coordinates) in a grid. This can be
    used to draw stimuli in a grid arrangement.

    Parameters
    ----------
    n : int, tuple
        An `int` that indicates the number of columns and rows, so that `n=2`
        indicates a 2x2 grid, or a (n_col, n_row) `tuple`, so that `n=(2,3)`
        indicates a 2x3 grid.
    spacing : float
        A numeric value that indicates the spacing between cells, or a
        (col_spacing, row_spacing) tuple.
    pole : tuple, optional
        The reference point.

    Returns
    -------
    list
        A list of (x,y) coordinate tuples.

    Examples
    --------
    >>> # Draw a 4x4 grid of rectangles
    >>> c = Canvas()
    >>> c.fixdot()
    >>> for x, y in xy_grid(4, 100):
    >>>         c.rect(x-10, y-10, 20, 20)
    >>> c.show()
    """
    try:
        n_col, n_row = n
    except:
        n_col = n_row = n
    try:
        n_col = int(n_col)
        n_row = int(n_row)
        assert(n_col >= 0)
        assert(n_row >= 0)
    except:
        raise ValueError('n should be a non-negative integer or a tuple of '
                         'two non-negative integers in xy_grid()')
    try:
        s_col, s_row = spacing
    except:
        s_col = s_row = spacing
    try:
        s_col = float(s_col)
        s_row = float(s_row)
        assert(s_col >= 0)
        assert(s_row >= 0)
    except:
        raise ValueError('spacing should be a non-negative numeric or a '
                         'tuple of two non-negative numerics in xy_grid()')
    pole = parse_pole(pole)
    l = []
    for row in range(n_row):
        y = (row - (n_row-1) / 2.) * s_row + pole[1]
        for col in range(n_col):
            x = (col - (n_col-1) / 2.) * s_col + pole[0]
            l.append((x, y))
    return l

def xy_random(n, width, height, min_dist=0, pole=(0, 0)):
    r"""Generates a list of random points (x,y coordinates) with a minimum
    spacing between each pair of points. This function will raise an
    Exception when the coordinate list cannot be generated,  typically because
    there are too many points, the min_dist is set too high, or the width or
    height are set too low.

    Parameters
    ----------
    n : int
        The number of points to generate.
    width : float
        The width of the field with random points.
    height : float
        The height of the field with random points.
    min_dist : float, optional
        The minimum distance between each point.
    pole : tuple, optional
        The reference point.

    Returns
    -------
    list
        A list of (x,y) coordinate tuples.

    Examples
    --------
    >>> # Draw a 50 rectangles in a random grid
    >>> c = Canvas()
    >>> c.fixdot()
    >>> for x, y in xy_random(50, 500, 500, min_dist=40):
    >>>         c.rect(x-10, y-10, 20, 20)
    >>> c.show()
    """
    try:
        n = int(n)
        if n < 0:
            raise ValueError()
    except (ValueError, TypeError):
        raise ValueError('n should be a non-negative integer in xy_circle()')
    try:
        width = float(width)
    except:
        raise TypeError('width should be numeric in xy_random()')
    try:
        height = float(height)
    except:
        raise TypeError('height should be numeric in xy_random()')
    try:
        min_dist = float(min_dist)
    except:
        raise TypeError('min_dist should be numeric in xy_random()')
    pole = parse_pole(pole)
    max_try = 1000
    for t1 in range(max_try):
        l = []
        for i in range(n):
            for t2 in range(max_try):
                x1 = (random.random()-.5)*width + pole[0]
                y1 = (random.random()-.5)*height + pole[1]
                for x2, y2 in l:
                    if xy_distance(x1, y1, x2, y2) < min_dist:
                        break
                else:
                    # Point does not collide, so add to the list
                    l.append((x1, y1))
                    break
            else:
                # All level-2 tries have failed, so break to start a new level-1
                # try.
                break
        else:
            # All points have been successfully added, so return the list
            return l
    # All level-1 tries have failed
    raise RuntimeError('Failed to generate random coordinates in xy_random()')

# Helper functions that are not part of the public API

def parse_pole(pole):
    try:
        ox = float(pole[0])
        oy = float(pole[1])
        assert(len(pole) == 2)
    except:
        raise ValueError('pole should be a tuple (or similar) of length '
                         'with two numeric values')
    return ox, oy

def set_aliases():
    # Non PEP-8 alias for backwards compatibility
    global canvas, sampler, synth, keyboard, mouse
    canvas = Canvas
    sampler = Sampler
    synth = Synth
    keyboard = Keyboard
    mouse = Mouse


from   Tkinter import *
import Pmw, AppShell, math, time, string, marshal
from cursornames import *
from toolbarbutton import ToolBarButton
from tkFileDialog import *

transDict = { 'bx': 'boundX', 'by': 'boundY',
              'x':  'adjX',   'y':  'adjY',
              'S':  'uniqueIDINT' }

class Draw(AppShell.AppShell):
    usecommandarea = 1
    appname        = 'Drawing Program - Version 4'
    frameWidth     = 840
    frameHeight    = 600

    def createButtons(self):
        self.buttonAdd('Postscript',
              helpMessage='Save current drawing (as PostScript)',
              statusMessage='Save drawing as PostScript file',
              command=self.ipostscript)
        self.buttonAdd('Refresh', helpMessage='Refresh drawing',
              statusMessage='Redraw the screen', command=self.redraw)
        self.buttonAdd('Close', helpMessage='Close Screen',
              statusMessage='Exit', command=self.close)

    def createBase(self):
        self.toolbar = self.createcomponent('toolbar', (), None,
                  Frame, (self.interior(),), background="gray90")
        self.toolbar.pack(fill=X)

        self.canvas = self.createcomponent('canvas', (), None,
                  Canvas, (self.interior(),), background="white")
        self.canvas.pack(side=LEFT, expand=YES, fill=BOTH)

        Widget.bind(self.canvas, "<Button-1>", self.mouseDown)
        Widget.bind(self.canvas, "<Button1-Motion>", self.mouseMotion)
        Widget.bind(self.canvas, "<Button1-ButtonRelease>", self.mouseUp)
        self.root.bind("<KeyPress>", self.setRegular)
        self.root.bind("<KeyRelease>", self.setRegular)

    def setRegular(self, event):
        if event.type == '2' and event.keysym == 'Shift_L':
            self.regular = TRUE
        else:
            self.regular = FALSE

    def createMenus(self):
        self.menuBar.deletemenuitems('File')
        self.menuBar.addmenuitem('File', 'command', 'New drawing',
                                 label='New', command=self.newDrawing)
        self.menuBar.addmenuitem('File', 'command', 'Open drawing',
                                 label='Open...', command=self.openDrawing)
        self.menuBar.addmenuitem('File', 'command', 'Save drawing',
                                 label='Save', command=self.saveDrawing)
        self.menuBar.addmenuitem('File', 'command', 'Save drawing',
                                 label='SaveAs...', command=self.saveAsDrawing)
        self.menuBar.addmenuitem('File', 'separator')
        self.menuBar.addmenuitem('File', 'command', 'Exit program',
                                 label='Exit', command=self.quit)

    def createTools(self):
        self.func      = {}
        self.transFunc = {}
        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif',
                      width=10, state='disabled')
        for key, func, balloon in [
                ('pointer', None,                'Edit drawing'),
                ('draw',    self.drawFree,       'Draw freehand'),
                ('smooth',  self.drawSmooth,     'Smooth freehand'),
                ('line',    self.drawLine,       'Rubber line'),
                ('rect',    self.drawRect,       'Unfilled rectangle'),
                ('frect',   self.drawFilledRect, 'Filled rectangle'),
                ('oval',    self.drawOval,       'Unfilled oval'),
                ('foval',   self.drawFilledOval, 'Filled oval')]:
            ToolBarButton(self, self.toolbar, key, '%s.gif' % key,
                          command=self.selectFunc, balloonhelp=balloon,
                               statushelp=balloon)
            self.func[key]       = func
            self.transFunc[func] = key

    def createLineWidths(self):
        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
                      state='disabled')
        for width in ['1', '3', '5']:
            ToolBarButton(self, self.toolbar, width, 'tline%s.gif' %
                  width, command=self.selectWidth,
                  balloonhelp='%s pixel linewidth' % width,
                  statushelp='%s pixel linewidth' % width)

    def createLineColors(self):
        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
                      state='disabled')
        for color in ['black', 'white', 'gray','green',
                      'blue', 'red', 'orange','yellow', 'brown']:
            ToolBarButton(self, self.toolbar, color, 'linecolor.gif',
                  bg=color, command=self.selectForeground,
                  balloonhelp='Draw %s outline' % color,
                  statushelp='Outline will be drawn in %s' % color)

    def createFillColors(self):
        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
                      state='disabled')
        for color in ['black', 'white', 'gray','green',
                      'blue', 'red', 'orange','yellow', 'brown']:
            ToolBarButton(self, self.toolbar, color, 'fillcolor.gif',
                  bg=color, command=self.selectBackground,
                  balloonhelp='Use %s fill color' % color,
                  statushelp='Object will be filled with %s' % color)

    def createPatterns(self):
        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
                      state='disabled')
        for pattern in [None, 'gray12.bmp', 'gray25.bmp',
                        'gray50.bmp', 'gray75.bmp']:
            ToolBarButton(self, self.toolbar, pattern, pattern,
                  command=self.selectPattern,
                  balloonhelp='Stipple pattern',
                  statushelp='Stipple pattern applied to fill')

    def selectFunc(self, tag):
        self.curFunc = self.func[tag]
        if self.curFunc:
            self.canvas.config(cursor='crosshair')
        else:
            self.canvas.config(cursor='arrow')

    def selectWidth(self, tag):
        self.lineWidth = string.atoi(tag)

    def selectBackground(self, tag):
        self.background = tag

    def selectForeground(self, tag):
        self.foreground = tag

    def selectPattern(self, tag):
        if tag:
            self.fillStyle='@icons/%s' % tag
        else:
            self.fillStyle = tag

    def mouseDown(self, event):
        self.curObject = None
        self.canvas.dtag('drawing')
        self.lineData = []
        self.lastx = self.startx = self.canvas.canvasx(event.x)
        self.lasty = self.starty = self.canvas.canvasy(event.y)
        self.uniqueID = 'S*%d' % self.serial
        self.serial = self.serial + 1
        if not self.curFunc:
            if event.widget.find_withtag(CURRENT):
                tags = self.canvas.gettags(CURRENT)
                for tag in tags:
                    if tag[:2] == 'S*':
                        objectID = tag
                if 'grabHandle' in tags:
                    self.inGrab      = TRUE
                    self.releaseGrab = FALSE
                    self.uniqueID    = objectID
                else:
                    self.inGrab = FALSE
                    self.addGrabHandles(objectID, 'grab')
                    self.canvas.config(cursor='fleur')
                    self.uniqueID = objectID
        else:
            self.canvas.delete("grabHandle")
            self.canvas.dtag("grabHandle")
            self.canvas.dtag("grab")

    def mouseMotion(self, event):
        curx = self.canvas.canvasx(event.x)
        cury = self.canvas.canvasy(event.y)
        prevx = self.lastx
        prevy = self.lasty
        if not self.inGrab and self.curFunc:
            self.lastx = curx
            self.lasty = cury
            if self.regular and self.curFunc in \
                   [self.func['oval'], self.func['rect'],
                    self.func['foval'],self.func['frect']]:
                dx         = self.lastx - self.startx
                dy         = self.lasty - self.starty
                delta = max(dx, dy)
                self.lastx = self.startx + delta
                self.lasty = self.starty + delta
            self.curFunc(self.startx, self.starty, self.lastx,
                 self.lasty, prevx, prevy, self.foreground,
                 self.background, self.fillStyle, self.lineWidth,None)
        else:
            if self.inGrab:
                self.canvas.delete("grabbedObject")
                self.canvas.dtag("grabbedObject")
                tags = self.canvas.gettags(CURRENT)
                for tag in tags:
                    if '*' in tag:
                        key, value = string.split(tag, '*')
                        var = transDict[key]
                        setattr(self, var, string.atoi(value))
                self.uniqueID = 'S*%d' % self.uniqueIDINT
                x1, y1, x2, y2, px, py, self.growFunc, \
                   fg, bg, fill, lwid, ld= self.objects[self.uniqueID]
                if self.boundX == 1 and self.adjX:
                    x1 =  x1 + curx-prevx
                elif self.boundX == 2 and self.adjX:
                    x2 =  x2 + curx-prevx
                if self.boundY == 1 and self.adjY:
                    y1 = y1 + cury-prevy
                elif self.boundY == 2 and self.adjY:
                    y2 = y2 + cury-prevy
                self.growFunc(x1,y1,x2,y2,px,py,fg,bg,fill,lwid,ld)
                self.canvas.addtag_withtag("grabbedObject",
                                           self.uniqueID)
                self.storeObject(x1,y1,x2,y2,px,py,self.growFunc,
                                 fg,bg,fill,lwid,ld)
                self.lastx = curx
                self.lasty = cury
            else:
                self.canvas.move('grab', curx-prevx, cury-prevy)
                self.lastx = curx
                self.lasty = cury

    def mouseUp(self, event):
        self.prevx = self.lastx
        self.prevy = self.lasty
        self.lastx = self.canvas.canvasx(event.x)
        self.lasty = self.canvas.canvasy(event.y)

        if self.curFunc:
            if self.regular and self.curFunc in \
                   [self.func['oval'], self.func['rect'],
                    self.func['foval'],self.func['frect']]:
                dx = self.lastx - self.startx
                dy = self.lasty - self.starty
                delta = max(dx, dy)
                self.lastx = self.startx + delta
                self.lasty = self.starty + delta
            self.curFunc(self.startx, self.starty, self.lastx,
                 self.lasty, self.prevx, self.prevy, self.foreground,
                 self.background, self.fillStyle, self.lineWidth,
                 self.lineData)
            self.inGrab      = FALSE
            self.releaseGrab = TRUE
            self.growFunc    = None
            self.storeObject(self.startx, self.starty, self.lastx,
                 self.lasty, self.prevx, self.prevy, self.curFunc,
                 self.foreground, self.background, self.fillStyle,
                 self.lineWidth, self.lineData)
        else:
            if self.inGrab:
                tags = self.canvas.gettags(CURRENT)
                for tag in tags:
                    if '*' in tag:
                        key, value = string.split(tag, '*')
                        var = transDict[key]
                        setattr(self, var, string.atoi(value))
                x1,y1,x2,y2, px, py, self.growFunc, \
                    fg,bg,fill,lwid,ld = self.objects[self.uniqueID]
                if self.boundX == 1 and self.adjX:
                    x1 =  x1 + self.lastx-self.prevx
                elif self.boundX == 2 and self.adjX:
                    x2 =  x2 + self.lastx-self.prevx
                if self.boundY == 1 and self.adjY:
                    y1 = y1 + self.lasty-self.prevy
                elif self.boundY == 2 and self.adjY:
                    y2 = y2 + self.lasty-self.prevy
                self.growFunc(x1,y1,x2,y2,px,py,fg,bg,fill,lwid,ld)
                self.storeObject(x1,y1,x2,y2,px,py,self.growFunc,
                                 fg,bg,fill,lwid,ld)
                self.addGrabHandles(self.uniqueID, self.uniqueID)
            if self.selObj:
                self.canvas.itemconfig(self.selObj,
                                       width=self.savedWidth)
        self.canvas.config(cursor='arrow')

    def addGrabHandles(self, objectID, tag):
        self.canvas.delete("grabHandle")
        self.canvas.dtag("grabHandle")
        self.canvas.dtag("grab")
        self.canvas.dtag("grabbedObject")

        self.canvas.addtag("grab", "withtag", CURRENT)
        self.canvas.addtag("grabbedObject", "withtag", CURRENT)
        x1,y1,x2,y2 = self.canvas.bbox(tag)
        for x,y, curs, tagBx, tagBy, tagX, tagY in [
                (x1,y1,TLC,            'bx*1','by*1','x*1','y*1'),
                (x2,y1,TRC,            'bx*2','by*1','x*1','y*1'),
                (x1,y2,BLC,            'bx*1','by*2','x*1','y*1'),
                (x2,y2,BRC,            'bx*2','by*2','x*1','y*1'),
                (x1+((x2-x1)/2),y1,TS, 'bx*0','by*1','x*0','y*1'),
                (x2,y1+((y2-y1)/2),RS, 'bx*2','by*0','x*1','y*0'),
                (x1,y1+((y2-y1)/2),LS, 'bx*1','by*0','x*1','y*0'),
                (x1+((x2-x1)/2),y2,BS, 'bx*0','by*2','x*0','y*1')]:
            ghandle = self.canvas.create_rectangle(x-2,y-2,x+2,y+2,
                      outline='black', fill='black', tags=('grab',
                      'grabHandle','%s'%tagBx,'%s'%tagBy,'%s'%tagX,
                      '%s'%tagY,'%s'%objectID))
            self.canvas.tag_bind(ghandle, '<Any-Enter>',
                      lambda e, s=self, c=curs: s.setCursor(e,c))
            self.canvas.tag_bind(ghandle, '<Any-Leave>',
                                 self.resetCursor)
            self.canvas.lift("grab")

    def setCursor(self, event, cursor):
        self.savedCursor = self.canvas.cget('cursor')
        self.canvas.config(cursor=cursor)

    def resetCursor(self, event):
        if self.releaseGrab and self.savedCursor:
            self.canvas.config(cursor=self.savedCursor)

    def drawLine(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.canvas.delete(self.curObject)
        self.curObject = self.canvas.create_line(x,y,x2,y2,
                tags=self.uniqueID, fill=fg,stipple=fillp,width=wid)

    def drawFree(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.drawFreeSmooth(x,y,x2,y2,x3,y3,FALSE,fg,bg,fillp,wid,ld)

    def drawSmooth(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.drawFreeSmooth(x,y,x2,y2,x3,y3,TRUE,fg,bg,fillp,wid,ld)

    def drawFreeSmooth(self,x,y,x2,y2,x3,y3,smooth,fg,bg,fillp,
                       wid,ld):
        if not ld:
            for coord in [[x3, y3, x2, y2], [x2, y2]][smooth]:
                self.lineData.append(coord)
                ild = self.lineData
        else:
            ild = ld
        if len(ild) > 2:
            self.curObject = self.canvas.create_line(ild, fill=fg,
              stipple=fillp,tags=self.uniqueID,width=wid,smooth=smooth)

    def drawRect(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.drawFilledRect(x,y,x2,y2,x3,y3,fg,'',fillp,wid,ld)

    def drawFilledRect(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.canvas.delete(self.curObject)
        self.curObject = self.canvas.create_rectangle(x,y,x2,y2,
                   tags=self.uniqueID,outline=fg,fill=bg,
                   stipple=fillp, width=wid)

    def drawOval(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.drawFilledOval(x,y,x2,y2,x3,y3,fg,'',fillp,wid,ld)

    def drawFilledOval(self,x,y,x2,y2,x3,y3,fg,bg,fillp,wid,ld):
        self.canvas.delete(self.curObject)
        self.curObject = self.canvas.create_oval(x,y,x2,y2,
                   tags=self.uniqueID,outline=fg,fill=bg,
                   stipple=fillp,width=wid)

    def storeObject(self, x1,y1,x2,y2,px,py,func,fg,bg,fill,lwid,ld):
        self.objects[self.uniqueID] = ( x1,y1,x2,y2,px,py,func,fg,bg,
                                        fill,lwid,ld )

    def redraw(self):
        # **** Delete all tags in canvas first ****
        self.canvas.delete(ALL)
        keys = self.objects.keys()
        keys.sort()
        for key in keys:
            startx, starty, lastx, lasty, prevx, prevy, func, \
                    fg, bg, fill, lwid , ld= self.objects[key]
            self.curObject = None
            self.uniqueID = key
            func(startx, starty, lastx, lasty, prevx, prevy,
                 fg, bg, fill, lwid, ld)

    def newDrawing(self):
        self.canvas.delete(ALL)
        self.initData()

    def openDrawing(self):
        ofile = askopenfilename(filetypes=[("PTkP Draw", "ptk"),
                                           ("All Files", "*")])
        if ofile:
            self.currentName = ofile
            self.initData()
            fd = open(ofile)
            items = marshal.load(fd)
            for i in range(items):
                self.uniqueID, x1,y1,x2,y2,px,py,cfunc, \
                     fg,bg,fill,lwid,ld = marshal.load(fd)
                self.storeObject(x1,y1,x2,y2,px,py,self.func[cfunc],
                                 fg,bg,fill,lwid,ld)
            fd.close()
        self.redraw()

    def saveDrawing(self):
        self.doSave()

    def saveAsDrawing(self):
        ofile = asksaveasfilename(filetypes=[("PTkP Draw", "ptk"),
                                             ("All Files", "*")])
        if ofile:
            self.currentName = ofile
            self.doSave()

    def doSave(self):
        fd = open(self.currentName, 'w')
        keys = self.objects.keys()
        keys.sort()
        marshal.dump(len(keys), fd)
        for key in keys:
            startx, starty, lastx, lasty, prevx, prevy, func, \
                    fg, bg, fill, lwid , ld= self.objects[key]
            cfunc = self.transFunc[func]
            marshal.dump((key, startx, starty, lastx, lasty, prevx, \
                          prevy, cfunc, fg, bg, fill, lwid , ld), fd)
        fd.close()

    def initData(self):
        self.curFunc     = self.drawLine
        self.growFunc    = None
        self.curObject   = None
        self.selObj      = None
        self.lineData   = []
        self.savedWidth  = 1
        self.savedCursor = None
        self.objects     = {}       # Now a dictionary
        self.foreground  = 'black'
        self.background  = 'white'
        self.fillStyle   = None
        self.lineWidth   = 1
        self.serial      = 1000
        self.regular     = FALSE
        self.inGrab      = FALSE
        self.releaseGrab = TRUE
        self.currentName = 'Untitled'

    def ipostscript(self):
        postscript = self.canvas.postscript()
        fd = open('drawing.ps', 'w')
        fd.write(postscript)
        fd.close()

    def close(self):
        self.quit()

    def createInterface(self):
        AppShell.AppShell.createInterface(self)
        self.createButtons()
        self.initData()
        self.createMenus()
        self.createBase()
        self.createTools()
        self.createLineWidths()
        self.createLineColors()
        self.createFillColors()
        self.createPatterns()

if __name__ == '__main__':
    draw = Draw()
    draw.run()


import copy
from IPython import embed
import pandas as pd

def update_elos_and_gen_brier(args):
    '''
    Designed to be applied to df of matches, requires global RATINGS_DF with latest ELOS
    Unpacks 'args' to make player_1, player_2,k_factor,outcome,surface
    Updates the global RATINGS_DF, given a single game + k-factor as side effect.
    Also returns  rating_1, rating_2, e1, brier, which should be unpacked and added to df rowwise
    '''
    player_1, player_2,k_factor,outcome, match_surface = args
    rating_1 = RATINGS_DF[match_surface][player_1]
    rating_2 = RATINGS_DF[match_surface][player_2]

    q1 =10.0 ** (rating_1/400)
    q2 =10.0 ** (rating_2/400)
    e1 = q1/(q1+q2)
    e1_diff = outcome-e1

    for surface_rat in ['Grass','Hard','Clay']:
        RATINGS_DF[surface_rat][player_1] += (e1_diff*k_factor*SURFACE_MATRIX[match_surface][surface_rat])
        RATINGS_DF[surface_rat][player_1] -= (e1_diff*k_factor*SURFACE_MATRIX[match_surface][surface_rat])

    #measure performance of prediction vs actual win/loss draw. Brier change = square of prediction error.
    brier =  (outcome - e1)**2
    return rating_1, rating_2, e1, brier

def calc_brier_and_elos(matches_df,params,brier_sum_only):
    '''
    Designed to be applied to entire dataframe of matches - needs matches df to have columns:
        'Player 1' - str
        'Player 2' - str
        'Outcome' - int O/1

    params = list: unpkacked to make to make the following params
        k_factor int - how fast should ratings update given wins?
        grass_hard - how much should wins on grass influence hard court ratings and vica versa?
        grass_clay - as above for clay and grass
        hard_clay - as above for hard and clay

    brier_sum_only - should it return only the sum of squared prediction errors, or the entire frame?
    (set to true if optimising hyperparamters 'params')
    '''

    k_factor, grass_hard, grass_clay, clay_hard = params

    uniq_players = matches_df['Player 1'].append(matches_df['Player 2']).unique()

    #(1a) Make global ratings DF - unique list of players with starting rating 1200 on every surface

    global RATINGS_DF
    RATINGS_DF = pd.DataFrame(index=uniq_players)
    for surface in ['Grass','Hard','Clay']:
        RATINGS_DF[surface] = 1200

    #(1b) Make global map of rating update ratios
    global SURFACE_MATRIX
    SURFACE_MATRIX = {}
    SURFACE_MATRIX['Grass']={'Grass':1,'Hard':grass_hard,'Clay':grass_clay}
    SURFACE_MATRIX['Hard']={'Grass':grass_hard,'Hard':1,'Clay':clay_hard}
    SURFACE_MATRIX['Clay']={'Grass':grass_clay,'Hard':clay_hard,'Clay':1}

    matches_df['K Factor'] = k_factor

   #(2) Apply update_elos_and_gen_brier to every column (see function for details)

    #Ratings are elos BEFORE game of both players on particular surface
    #E 1 is chance of 1st player winning
    #Brier is squared predition error
    matches_df[['Rating 1','Rating 2','E 1','Brier']] = matches_df[['Player 1','Player 2','K Factor','Outcome','Surface']].apply(update_elos_and_gen_brier,axis=1).apply(pd.Series)

    #(3) Return either entier dataframe, or prediciton errors
    if brier_sum_only:
        #Check correlation factors are greater than zero
        if min(grass_hard,grass_clay,clay_hard) < 0:
            return 1e10 + min(grass_hard,grass_clay,clay_hard)

        #Check correlation factors are less than 1
        if max(grass_hard,grass_clay,clay_hard) > 1:
            return 1e10 - max(grass_hard,grass_clay,clay_hard)

        return matches_df['Brier'].sum()
    else:
        return matches_df


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

import json
import requests

url = "https://api.librepcb.org/api/v1/libraries/v0.1"
content = json.loads(requests.get(url).content.decode("UTF-8"))
assert content["next"] is None

libraries = content["results"]
symbols = 0
packages = 0
components = 0
devices = 0
for library in libraries:
    symbols += int(library["symbols"])
    packages += int(library["packages"])
    components += int(library["components"])
    devices += int(library["devices"])

print("Libraries: {}".format(len(libraries)))
print("Symbols: {}".format(symbols))
print("Packages: {}".format(packages))
print("Components: {}".format(components))
print("Devices: {}".format(devices))
print("Total: {}".format(symbols + packages + components + devices))


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

# Scrapy settings for google_shopping project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
#     http://doc.scrapy.org/en/latest/topics/settings.html
#
import os

BOT_NAME = 'google_shopping'

SPIDER_MODULES = ['google_shopping.spiders']
NEWSPIDER_MODULE = 'google_shopping.spiders'

# Delay between requests not to be blocked (seconds).
DOWNLOAD_DELAY = 2

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:35.0) Gecko/20100101 Firefox/35.0'

ITEM_PIPELINES = {
    'google_shopping.pipelines.GoogleShoppingPipeline': 200,
}

# Retry many times since proxies often fail
RETRY_TIMES = 10
# Retry on most error codes since proxies fail for different reasons
RETRY_HTTP_CODES = [500, 503, 504, 400, 403, 404, 408]

# Disable CrawleraMiddleware and enable 3 lines bellow it to switch on using proxies list
DOWNLOADER_MIDDLEWARES = {
    #'google_shopping.custom_middlewares.CustomCrawleraMiddleware': 600
    #'scrapy.contrib.downloadermiddleware.retry.RetryMiddleware': 100,
    #'google_shopping.custom_middlewares.RandomProxy': 90,
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 110,
}

PROXY_LIST_URL = 'https://d3s763n0ugqswt.cloudfront.net/proxy.txt'
#PROXY_LIST_URL = 'http://localhost/proxies.txt'

# Path to directory which should contain all xml files
PRODUCT_PATH = os.path.join(os.path.dirname(__file__), "products")

# Clawlera configuration
CRAWLERA_URL = 'http://paygo.crawlera.com:8010'
CRAWLERA_ENABLED = True
CRAWLERA_USER = 'rcouraud'
CRAWLERA_PASS = 'FEf3zwVsNz'
# CONCURRENT_REQUESTS = 32
# CONCURRENT_REQUESTS_PER_DOMAIN = 32
AUTOTHROTTLE_ENABLED = False
DOWNLOAD_TIMEOUT = 600

# Delay time for response code 503
DELAY_TIME = 12*60

#
CONCURRENT_REQUESTS_PER_IP = 8

# Directory where stores information for restarting the scraper.
JOBDIR = os.path.join(os.path.dirname(__file__), "google_products")

# PickleDB settings
PICKLEDB_NAME = os.path.join(os.path.dirname(__file__), "PickleDB.db")
BANNED_COUNT_KEY = "banned_count"

# Number of banned requests before stopping the scraper.
ALLOWED_BANNED_REQUESTS_NUMBER = 20

# Number of pages for scraping
NUMBER_OF_PAGE = 2
#
# LOG_ENABLED = True
# LOG_FILE = os.path.join(os.path.dirname(__file__), "scraper.log")
# LOG_LEVEL = 'WARNING'


from termcolor import colored
import copy

class Board:

    def __init__(self, map_type):
        self.map_type = map_type
        self.width = len(map_type[0])
        self.height = len(map_type)
        self.board = self.generate_board(map_type)

    def generate_board(self, map_type):
        board = copy.deepcopy(map_type)
        for y in range(self.height):
            for x in range(self.width):
                if board[y][x] == 1:
                    board[y][x] = '.'
        return board

    def display(self):
        for i in range(self.width):
            print(chr(i + 97), end=' ')
        print()
        for y in range(self.height):
            for x in range(self.width):
                element = self.board[y][x]
                if type(element) is dict: # Si l'élèment est un dictionnaire, alors c'est un bloc d'une shape
                    print(colored(element["content"], element["color"]), end=' ')
                elif element == 2:
                    print(" ", end=' ')
                else:
                    print(element, end=' ')
            print(chr(y + 65))
        print()

    def update(self, shapes):
        solid_square = chr(int('0x25A0', 0)) # Hex for solid square unicode character
        self.board = self.generate_board(self.map_type)
        for shape in shapes:
            for coordinates in shape.blocks:
                x = shape.x + coordinates[0]
                y = shape.y - coordinates[1]
                self.board[y][x] = {
                    "content": solid_square,
                    "color": shape.color
                }


import chaospy as cp
import numpy as np
from scipy import special

dim = 3  # <100
samples = 20  # <10**6
order = 2 # <20
size = 20 # <10**5

class normal(cp.SimpleDistribution):
    """stripped down normal distribution."""
    def _cdf(self, x):
        return special.ndtr(x)
    def _lower(self):
        return -7.5
    def _upper(self):
        return 7.5

def test_dist():
    dist = [cp.Normal()]
    for d in range(dim-1):
        dist.append(cp.Normal(dist[-1]))
    dist = cp.J(*dist)
    out = dist.sample(samples)
    out = dist.fwd(out)
    out = dist.inv(out)

def test_quasimc():
    dist = [cp.Normal()]
    for d in range(dim-1):
        dist.append(cp.Normal(dist[-1]))
    dist = cp.J(*dist)
    dist.sample(samples, "H")
    dist.sample(samples, "M")
    dist.sample(samples, "S")

# def test_approx_dist():
#     dist = [normal()]
#     for d in range(dim-1):
#         dist.append(normal() + dist[-1])
#     dist = cp.J(*dist)
#     out = dist.sample(samples)
#     out = dist.fwd(out)
#     out = dist.inv(out)

def test_orthogonals():
    dist = cp.Iid(cp.Normal(), dim)
    cp.expansion.gram_schmidt(order, dist)
    cp.expansion.stieltjes(order, dist)
    cp.expansion.cholesky(order, dist)

def test_quadrature():
    dist = cp.Iid(cp.Normal(), dim)
    gq = cp.generate_quadrature
    nodes, weights = gq(order, dist, rule="C")
    nodes, weights = gq(order, dist, rule="E")
    nodes, weights = gq(order, dist, rule="G")
    nodes, weights = gq(order, dist, rule="C", sparse=True)
    nodes, weights = gq(order, dist, rule="E", sparse=True)
    nodes, weights = gq(order, dist, rule="G", sparse=True)

def test_approx_quadrature():
    dist = cp.Iid(normal(), dim)
    nodes, weights = cp.generate_quadrature(order, dist, rule="C")

def test_integration():
    dist = cp.Iid(cp.Normal(), dim)
    orth, norms = cp.expansion.stieltjes(order, dist, retall=1)
    gq = cp.generate_quadrature
    nodes, weights = gq(order, dist, rule="C")
    vals = np.zeros((len(weights), size))
    cp.fit_quadrature(orth, nodes, weights, vals, norms=norms)

def test_regression():
    dist = cp.Iid(cp.Normal(), dim)
    orth, norms = cp.expansion.stieltjes(order, dist, retall=1)
    data = dist.sample(samples)
    vals = np.zeros((samples, size))
    cp.fit_regression(orth, data, vals)

def test_descriptives():
    dist = cp.Iid(cp.Normal(), dim)
    orth = cp.expansion.stieltjes(order, dist)
    cp.E(orth, dist)
    cp.Var(orth, dist)
    cp.Cov(orth, dist)


from datetime import *
import wechatsogou
from docx import Document
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import Inches

import requests
import datetime,time,random,re
import json
import  pandas as pd
from bs4 import BeautifulSoup
from queue import Queue       #线程
from threading import Thread  #线程
from pyquery import PyQuery as pq
from PIL import Image

# # 特定文章爬取
# def get_articles(headline=True, original=True, timedel=1, add_account=None,url=''):
#
#     ws_api = wechatsogou.WechatSogouAPI(captcha_break_time=3)
#
#     url='http://mp.weixin.qq.com/profile?src=3&timestamp=1587698474&ver=1&signature=ORCd7eeKinB3Aq1pFv-9KgIKY7*9B7BQnAN-SDDy6bm**Q*GPj4IAuIOhkouWao5xcV7GyQdocV*icyq0-ypMQ=='
#     html=ws_api.get_article_content(url, del_qqmusic=True, del_mpvoice=True, unlock_callback=None,
#                         identify_image_callback=None, hosting_callback=None, raw=True)
#
#     return html
#
#
#
# if __name__ == "__main__":
#     html = get_articles(timedel=1)
#     print(html)
#
#     with open('', 'w',encoding='utf-8') as f:
#         f.write(html)

# ws_api = wechatsogou.WechatSogouAPI(captcha_break_time=3)

# # 查找公众号
# infos=ws_api.search_gzh('爱数')
# for info in infos:
#     print(info)

#获得公众号的详细介绍
# aishu_url='http://mp.weixin.qq.com/profile?src=3&timestamp=1587704655&ver=1&signature=hoaJwjf9KGoR-CD6263JqRwSaL-tmiYNs04pZWwIEZhtGgeOirTPoMY9RIkHMFIsI2HvCb6GHV53orohmpwzPQ=='
# a=['爱数','36氪']
# for c in a:
#     info=ws_api.get_gzh_info(c)
#     if '爱数' in info.values():
#         info=info
#     else: info={}
#     print(info)

#关键字搜索
# keys=ws_api.get_sugg('爱数')
# for key in keys:
#     print(key)

#搜索和“爱数”这个关键字相关的，公众号文章
# articles=ws_api.search_article('爱数')
# print(articles)
# for article in articles:
#     print(article)

#获得历史文章,搜狗已经悄悄的停用了。
# his_articles=ws_api.get_gzh_article_by_history('爱数')
# print(his_articles)
# for article in his_articles:
#     print(article)

#搜索和“爱数”这个关键字相关的，公众号文章
# articles=ws_api.get_article_content('爱数')
# print(articles)
# for article in articles:
#     print(article)
#

# class WeChat():
#     def __init__(self):
#         self.session = requests.session()
#         self.session.verify = False
#
#

class sougou_login(object):

    def __init__(self):
        self.session = requests.session()

        self.token = ''
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
            'Host': 'account.sogou.com',
            'Connection': 'keep-alive',
            'Referer': 'https://weixin.sogou.com/', }

##h获取二维码
    def get_code(self):
        url = 'https://open.weixin.qq.com/connect/qrconnect?appid=wx6634d697e8cc0a29&scope=snsapi_login&response_type=code&redirect_uri=https%3A%2F%2Faccount.sogou.com%2Fconnect%2Fcallback%2Fweixin'
        url_base = 'https://open.weixin.qq.com' #验证码图片

        response = self.session.get(url,headers= self.headers, verify=False)
        data = response.content.decode('utf-8')
        soup = BeautifulSoup(data, 'lxml')  # 转换成lxml,可以用bs4解析
        img_src=soup.select_one('div[class="wrp_code"] img')

        img_link=url_base+img_src.get('src')

        response = requests.session().get(img_link)  #弹出登录二维码
        with open('image.jpg', 'wb') as f:
            f.write(response.content)
        image = Image.open('image.jpg')
        image.show()
        print('请使用微信扫描二维码登录:')

    #检查登录结果，status=1代表成功
    def check_login(self):
        # while True:
        time.sleep(15)
        checkUrl = 'https://lp.open.weixin.qq.com/connect/l/qrconnect?uuid=001m42OEtFn8ga23&_=1589507541224'

        checkResponse =  self.session.get(checkUrl, headers= self.headers, verify=False)
        check = json.loads(checkResponse.text)
        print (check)
        print(check["status"])

        return check["status"]

        print('session.cookies:', self.session.cookies)
        cookieDict = response.cookies.get_dict()
        print('cookieDict:', cookieDict)
        cookie = ''
        for key, value in cookieDict.items():
            cookie += key + '=' + value + ';'
        print('cookie:',cookie)

        return  cookie

    cookie=get_code()

    print('cookie:',cookie)

login=sougou_login()
login.get_code()
print("session.cookies:", login.session.cookies, '\n')


import asyncio
from pyjamas_core.util import Input, Output, Property
from pyjamas_core.supermodel import Supermodel

class Model(Supermodel):
    """
        takes something as input and returns it as output the following run
    """

    def __init__(self, uuid, name: str):
        super(Model, self).__init__(uuid, name)

        self.inputs['to_store'] = Input('To Store')
        self.outputs['stored'] = Output('Stored')

        self.stored = 0

    async def func_peri(self, prep_to_peri=None):

        self.set_output('stored',self.stored)

        self.stored = await self.get_input('to_store')


from typing import List, Union

import numpy as np
import torch

class MetricsAccumulator:
    '''
    Utility class for metrics accumulation and averaging
    '''

    def __init__(self):
        self.data = {}

    def reset(self):
        self.data = {}

    def to_numpy(self, item):

        # Convert torch tensors to numpy
        if torch.is_tensor(item):
            return item.detach().cpu().numpy()

        # Converts recursively
        if isinstance(item, list) or isinstance(item, tuple):
            new_item = []
            for current_item in item:
                new_item.append(self.to_numpy(current_item))
            new_item = np.stack(new_item, axis=0)
            return new_item

        return item

    def add(self, key: str, value: Union[np.ndarray, torch.Tensor, List]):
        '''
        Adds value to the set of values represented by key

        :param key: The key to associate to the current values
        :param value: (size, ...) tensor or array with the values to store.
                      Alternatively arbitrarily nested list of the above
        :return:
        '''

        value = self.to_numpy(value)

        if not key in self.data:
            self.data[key] = []

        self.data[key].append(value)

    def pop(self, key: str, dim=0):
        '''
        Obtains a tensor with all the concatenated values corresponding to a key
        Eliminates the key

        :param key: The key for which to retrieve the values
        :return: tensor with all the values concatenated along dimension dim
        '''

        if key not in self.data:
            raise Exception(f"Key '{key}' is not presetn")

        result = np.concatenate(self.data[key], axis=dim)
        del self.data[key]
        return result


import json
import os
import logging

import boto3
from bookstore_orm_objects import Base
from bookstore_utils import create_db_engine
from crhelper import CfnResource

logger = logging.getLogger(__name__)
cfn_helper = CfnResource(json_logging=False, log_level="DEBUG", boto_level="CRITICAL")
db_secret_name = os.getenv('AURORA_DB_SECRET_NAME')
db_proxy_endpoint = os.getenv('AURORA_DB_PROXY_ENDPOINT')
secrets_client = boto3.client('secretsmanager')

# Get DB credentials from AWS Secrets Manager
def get_db_secrets():
    """
    Return the secret string as a dictionary for secret name SECRET_NAME.
    """
    secret_response = secrets_client.get_secret_value(SecretId=db_secret_name)
    secrets = json.loads(secret_response['SecretString'])
    return secrets

@cfn_helper.create
@cfn_helper.update
def create(event, context):
    """
    DB Schema creation/update Lambda function entry point
    """
    global resource_id

    logger.info(f'Retrieving database access information from Secrets Manager\'s secret: "{db_secret_name}"')
    secrets = get_db_secrets()
    db_name = secrets['dbname']
    db_conn_string = f"postgresql://{secrets['username']}:{secrets['password']}@{db_proxy_endpoint}:{secrets['port']}/{db_name}?sslmode=require"

    logger.info(f'Creating SQLAlchemy database engine for database: "{db_name}"')
    engine = create_db_engine(db_conn_string)

    logger.info(f'Creating or Updating DB schema for database: "{db_name}"')
    Base.metadata.create_all(engine)

    return f'{db_name}-schema'

@cfn_helper.delete
def no_op(event, context):
    """
    Needed for the custom resource to delete properly.
    """
    logger.info('No action required when deleting this resource')

def lambda_handler(event, context):
    """
    Lambda entry point.
    """
    cfn_helper(event, context)


# Classes and objects
class Stock:
    def __init__(self, ticker, price):
        self.ticker = ticker
        self.price = price
    def display(self):
        print(f"Stock: {self.ticker}, Price: ${self.price}")
apple = Stock("AAPL", 150)
apple.display()

# Modules and packages (Assuming a module 'example_module' exists)
# from example_module import example_function
# example_function()

# Exceptions
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")


from spy.core import Instruction

# Add Dead Code Elimination
def dce(program):
    "Converts unused instructions into NOP"
    used_vars = [var for op, var, _ in program if op == Instruction.JNZ] + [0]
    program2 = []
    for op, var, val in program:
        if op in (Instruction.INC, Instruction.DEC, Instruction.JNZ):
            if var not in used_vars:
                op, var, val = Instruction.NOP, 0, 0
        program2.append((op, var, val))
    return program2

# Add Instruction Reordering
    # DEC goes *before* INC, because:
    # dec, dec, dec, inc does: 1 for input x < 4, x - 2 for x >= 4
    # inc, dec, dec, dec does: 0 for input x < 3, x - 2 for x >= 3

# Add Instruction Compression
    # between keypoints (TAGs and JNZs), compress all the INCs and DECs into
    # single instructions

def register_relocation(program):
    "Relocates vars to consecutive numbers"
    xstack, zstack = [], []
    program2 = []
    for op, var, val in program:
        if var != 0:
            # reordering
            stack = xstack if var > 0 else zstack
            var = abs(var)
            if var not in stack:
                stack.append(var)
            # rewriting
            var = stack.index(var) + 1
            if stack is zstack:
                var = (1 << 15) | var
        program2.append((op, var, val))
    return program2