from django.core.files.storage import Storage
from django.db import models

from urllib.request import urlopen
from django.core.files.temp import NamedTemporaryFile
from django.core.files import File
import requests
import os
from django.utils.deconstruct import deconstructible

import random
import string

from django.conf import settings
from kazoo.client import KazooClient, KazooState
import yaml
import logging
from django.contrib import admin

import hashlib

class FileEntry(models.Model):
    name = models.TextField()
    storage_1_ID = models.TextField()
    storage_2_ID = models.TextField()

    def __str__(self):
        return self.name

admin.site.register(FileEntry)

def randomString(stringLength=10):
    """Generate a random string of fixed length """
    letters = string.ascii_lowercase
    return ''.join(random.choice(letters) for i in range(stringLength))

#For sending and reading zookeeper values
def dict_to_bytes(the_dict):
    b = bytes(yaml.dump(the_dict), 'utf-8')
    return b

def bytes_to_dict(the_binary):
    d = yaml.load(the_binary)
    return d

logging.basicConfig(level=logging.DEBUG)

# Zookeeper Listener
def zklistener(state):
    if state == KazooState.LOST:
        print("Zookeeper Connection Lost")
    elif state == KazooState.SUSPENDED:
        print("Zookeeper Connection Suspended")
    else:
        print("Zookeeper Connected")

# Try until connecting to zookeeper
while True:
    try:
        # Connect to zookeeper
        zk = KazooClient(hosts=settings.ZOOCLIENTS)
        zk.start()

        # Listen to connection
        zk.add_listener(zklistener)

        # Add watcher for hashing key
        @zk.DataWatch("/storage")
        def watch_node(data, stat):
            settings.GLOBALS["hash_key"] = data.decode("utf-8")

        # Add watcher for storage hosts
        @zk.ChildrenWatch("/storage")
        def watch_children(children):
            if len(children) >0:
                hosts = {}
                for child in children:
                    temp_dict = bytes_to_dict(zk.get("/storage/"+child)[0])
                    host={temp_dict["ID"]:{'hostname' : temp_dict["hostname"], 'ext_url' : temp_dict["EXT_URL"]}}
                    hosts.update(host.copy())
                settings.GLOBALS["hosts"]=hosts
        break
    except:
        continue

@deconstructible
class ExternalStorage(Storage):
    def __init__(self, key=None):
        if not key:
            key = settings.GLOBALS["hash_key"]
    def _open(self, name, mode='rb'):

        print("\n\n\n\nOPENING WITH NAME = " + str(name) + "\n\n\n")

        # get url
        url = self.url(name=name,internal=True)
        # create temporary image
        img_temp = NamedTemporaryFile(delete=True)
        img_temp.write(urlopen(url).read())
        img_temp.flush()
        # return it
        return File(img_temp)

    # Store files in storage servers
    def _save(self, name, content):

        print("\n\n\n\nSAVING WITH NAME = " + str(name) + "\n\n\n")

        # open image
        data = content.open().read()
        # create content for http post request
        files = {'file': (name, data, "image/jpg", None)}
        # calculate security hash
        hash_object = hashlib.sha256(bytes(settings.GLOBALS["hash_key"], 'utf-8'))
        hash = hash_object.hexdigest()

        # Try to pick 2 random servers
        try:
            servers = random.sample(list(settings.GLOBALS["hosts"]), k=2)
            # Create file entry
            fileInstance = FileEntry(name=name,storage_1_ID=servers[0],storage_2_ID=servers[1])

            #send to second server
            hostname = settings.GLOBALS["hosts"][servers[1]]["hostname"]
            # generate storage server url
            url = "http://" + hostname + "/api/?hash=" + hash
            # send file to storage server
            requests.post(url, files=files)

        # Just use one
        except ValueError:
            servers = list(settings.GLOBALS["hosts"])[0]
            # Create file entry
            fileInstance = FileEntry(name=name,storage_1_ID=servers[0],storage_2_ID=None)

        finally:
            # send to first
            hostname = settings.GLOBALS["hosts"][servers[0]]["hostname"]
            # generate storage server url
            url = "http://" + hostname + "/api/?hash=" + hash
            # send files to storage server
            requests.post(url, files=files)
            # save file instance
            fileInstance.save()

        return name

    # Get url for image
    def url(self, name=None, internal=False):

        # print("\n\n\n\nFILE INSTANCE NAME = " + str(name)+"\n\n\n")

        # get file instance
        try:
            fileInstance = FileEntry.objects.get(name=name)
        except:
            return

        # get storage IDs for file
        ID=[fileInstance.storage_1_ID,fileInstance.storage_2_ID]

        # calculate security hash
        hash_object = hashlib.sha256(bytes(name + settings.GLOBALS["hash_key"], 'utf-8'))
        hash = hash_object.hexdigest()

        # Try to find external urls for each server ID
        urls=[]
        hostnames = []
        for i in ID:
            try:
                urls.append(settings.GLOBALS["hosts"][i]["ext_url"])
                hostnames.append(settings.GLOBALS["hosts"][i]["hostname"])
            except:
                continue

        # Select and return a url randomly
        try:
            ext_url = random.choice(urls)
            hostname = random.choice(hostnames)
            if internal:
                url = 'http://' + hostname+'/api/?image=' + name + '&hash=' + hash
            else :
                url = ext_url+'/api/?image=' + name + '&hash=' + hash
            return url
        except:
            return ""

    def generate_filename(self, filename="default_filename.jpg"):
        """
        Validate the filename by calling get_valid_name() and return a filename
        to be passed to the save() method.
        """
        # `filename` may include a path as returned by FileField.upload_to.
        dirname, filename = os.path.split(filename)
        return filename

    def exists(self,name):
        return False

    def path(self, name):
        return name

    def get_available_name(self, name, max_length=None):
        # generate random names and make sure there are no duplicates

        print("\n\n\n\nGETTING AVAILABLE NAME = " + str(name)+"\n\n\n")

        extension = name.split('.')[-1]
        rand_name = randomString(stringLength=20) + '.'+extension
        while len(FileEntry.objects.filter(name=rand_name)) > 0 :
            rand_name = randomString(stringLength=20) + '.'+extension
        return rand_name

    # Delete images from all servers they are saved
    def delete(self,name):
        # get file instance
        fileInstance = FileEntry.objects.get(name=name)
        # get storage IDs for file
        ID=[fileInstance.storage_1_ID, fileInstance.storage_2_ID]

        # calculate security hash
        hash_object = hashlib.sha256(bytes(settings.GLOBALS["hash_key"], 'utf-8'))
        hash = hash_object.hexdigest()

        for i in ID :
            if i is not None:
                host = settings.GLOBALS["hosts"][i]["hostname"]
                url = 'http://' + host + '/api/?image=' + name + '&hash=' + hash
                requests.delete(url)

        # Finaly delete file entry
        FileEntry.objects.get(name=name).delete()

        return name

    def size(self,name):
        return name


#!/usr/bin/python3
search_replace = __import__('1-search_replace').search_replace

my_list = [1, 2, 3, 4, 5, 4, 2, 1, 1, 4, 89]
new_list = search_replace(my_list, 2, 89)

print(new_list)
print(my_list)
import pycodestyle

def check_pep8_compliance(filename):
    style_guide = pycodestyle.StyleGuide()
    result = style_guide.check_files([filename])
    return result.total_errors

filename = "1-search_replace.py"  # Nom du fichier
num_errors = check_pep8_compliance(filename)

if num_errors == 0:
    print(f"The code in {filename} is PEP 8 compliant.")
else:
    print(f"{num_errors} PEP 8 violations found in {filename}.")


"""Script to fit the minibatch EM model."""
import argparse
import json
import time

import numpy as np
import torch

from deconv.gmm.online_deconv_gmm import OnlineDeconvGMM
from deconv.gmm.data import DeconvDataset

def fit_gaia_lim_em(datafile, output_prefix, K, batch_size, epochs, step_size, w_reg,
                    k_means_iters, lr_step, lr_gamma, use_cuda):
    data = np.load(datafile)

    if use_cuda:
        device = torch.device('cuda')
    else:
        device = torch.device('cpu')

    train_data = DeconvDataset(
        torch.Tensor(data['X_train']),
        torch.Tensor(data['C_train'])
    )

    val_data = DeconvDataset(
        torch.Tensor(data['X_val']),
        torch.Tensor(data['C_val'])
    )

    gmm = OnlineDeconvGMM(
        K,
        7,
        device=device,
        batch_size=batch_size,
        restarts=1,
        w=w_reg,
        step_size=step_size,
        epochs=epochs,
        k_means_iters=k_means_iters,
        lr_step=lr_step,
        lr_gamma=lr_gamma
    )

    start_time = time.time()
    gmm.fit(train_data, val_data=val_data, verbose=True)
    end_time = time.time()

    train_score = gmm.score_batch(train_data)
    val_score = gmm.score_batch(val_data)

    print('Training score: {}'.format(train_score))
    print('Val score: {}'.format(val_score))

    results = {
        'start_time': start_time,
        'end_time': end_time,
        'train_score': train_score,
        'val_score': val_score,
        'train_curve': gmm.train_ll_curve,
        'val_curve': gmm.val_ll_curve
    }

    json.dump(results, open(str(output_prefix) + '_results.json', mode='w'))
    torch.save(
        (gmm.weights, gmm.means, gmm.covars),
        output_prefix + '_params.pkl'
    )

if __name__ == '__main__':

    parser = argparse.ArgumentParser()

    parser.add_argument('-c', '--components', type=int)
    parser.add_argument('-b', '--batch-size', type=int)
    parser.add_argument('-e', '--epochs', type=int)
    parser.add_argument('-s', '--step-size', type=float)
    parser.add_argument('-w', '--w_reg', type=float)
    parser.add_argument('-k', '--k-means-iters', type=int)
    parser.add_argument('--lr-step', type=int)
    parser.add_argument('--lr-gamma', type=float)
    parser.add_argument('--use-cuda', action='store_true', help='Use GPU')
    parser.add_argument('datafile')
    parser.add_argument('output_prefix')

    args = parser.parse_args()

    fit_gaia_lim_em(
        args.datafile,
        args.output_prefix,
        args.components,
        args.batch_size,
        args.epochs,
        args.step_size,
        args.w_reg,
        args.k_means_iters,
        args.lr_step,
        args.lr_gamma,
        args.use_cuda
    )


import sys
sys.path.append('..')
import config
import zmq
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.lines import Line2D

config = config.config()

context2 = zmq.Context()
socket2 = context2.socket(zmq.SUB)
socket2.connect ("tcp://localhost:%s" % config.getPortAnalysisPublisher())
socket2.setsockopt(zmq.SUBSCRIBE, "")

class Scope:
    def __init__(self, ax,):
        self.ax = ax
        self.xdata = []
        self.ydata = []
        self.dot, = ax.plot(self.xdata,self.ydata,'go',markersize=5)

        self.ax.set_ylim(-1.0, 0)
        self.ax.set_xlim(-0.5, 0.5)
        self.count = 0

    def update(self):
        data = socket2.recv()
        (x,y,energy) = [float(i) for i in data.split()]
        if energy > 20.0:
          self.xdata += [x]
          self.ydata += [y]
          self.dot.set_ydata(self.ydata)
          self.dot.set_xdata(self.xdata)
          #plt.savefig("result_%05d.png" % self.count)
          self.count += 1
          plt.draw()

fig, ax = plt.subplots()
scope = Scope(ax)
plt.ion()
plt.show()

while 1:
  scope.update()


# My Approach
# Start from 0,0
# check 1x1, 2x2, 3x3, 4x4, 5x5 ,... at each index
# while checking each squares from each point make sure all elements are 1
# if all are 1, then save m or n in max = Math.max(max, M), as we have square of m x n, i,e m == n
# Optimisation - since we are doing top down approach
# before going to check if all cells are 1 in m x n sqaure, just validate if current (x,y), right
# and bottom are 1 or not,
# with this we can reduce several iterations
# Time Complexity - O ( (M x N)^2 ) ---- O( M^2 x N^2 )

# Bottom Up Approach
# Time Complexity - O(MxN + MxN) - O(MxN)
# Solution -

from ast import List
class Solution:
    def maximalSquare(self, matrix: List[List[str]]) -> int:
      ROW, COL = len(matrix), len(matrix[0])
      cache = {} # map each (r,c) -> maxLenght of square

      def _helper(r,c):
        # out of bound
        if r >= ROW or c >= COL:
          return 0

        if (r,c) not in cache:
          down = _helper(r,c+1)
          right = _helper(r+1,c)
          diag = _helper(r+1,c+1)

          # default value , either it will be 0 or 1
          cache[(r,c)] = 0
          if matrix[r][c] == "1":
            cache[(r,c)] = 1 + min(down,right,diag)
            # if any of 3 is 0, we will add 0
            # which will keep original value as 1 [ 1 only if matric[r][c] == "1"] else 0

        # Optimisation
        return cache[(r,c)]

      _helper(0,0)

      # squaring lenght
      return max(cache.values()) ** 2


import http
from datetime import datetime

from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity

from src.constants.permissions import WRITE_ACCESS, READ_ACCESS, ADMIN_ACCESS
from src.database.general_info.ads import Ads
from src.database.database_basis import db
from src.database.general_info.adgroups import Adgroups
from src.database.general_info.campaigns import Campaigns
from src.services.useful_funcs import EndpointManagingHelper
from src.services.validator import Validator

campaigns = Blueprint("campaigns", __name__, url_prefix="/api/v1/campaign")
validator = Validator()
helper = EndpointManagingHelper()

@campaigns.post("/add")
@jwt_required()
def add_campaign():
    schema = (
        ("campaign_name", "STRING", True),
        ("total_budget", "INTEGER", False),
        ("daily_budget", "INTEGER", False),
        ("status", "STRING", True),
    )
    enum_values = (("status", ("ENABLED", "DISABLED")),)
    unique_fields = ("campaign_name",)
    parameters = (
        "campaign_name",
        "total_budget",
        "daily_budget",
        "status",
    )
    try:
        validator.validate_types(schema, request.json)
        validator.validate_values(enum_values, request.json)
        validator.validate_unique(unique_fields, request.json, Campaigns)
        validator.validate_names(parameters, request.json)
    except Exception as error:
        return jsonify({"error": error.args}), http.HTTPStatus.BAD_REQUEST
    user = helper.get_user(get_jwt_identity())

    if not helper.check_user_permissions(user.advertiser_id, WRITE_ACCESS, "campaigns"):
        return jsonify({"message": "Access denied"}), http.HTTPStatus.UNAUTHORIZED

    campaign = Campaigns(
        advertiser_id=user.advertiser_id,
        campaign_name=request.json["campaign_name"],
        total_budget=request.json.get("total_budget", 0),
        daily_budget=request.json.get("daily_budget", 0),
        creation_date=datetime.utcnow(),
        status=request.json["status"],
    )
    db.session.add(campaign)
    db.session.commit()
    return (
        jsonify(
            {
                "message": "Campaign created",
                "campaign": {
                    "campaign_id": campaign.campaign_id,
                    "campaign_name": campaign.campaign_name,
                },
            }
        ),
        http.HTTPStatus.CREATED,
    )

@campaigns.get("/get")
@jwt_required()
def get_campaign():
    schema = (("campaign_id", "INTEGER", True),)
    params = ("campaign_id",)
    try:
        validator.validate_types(schema, request.json)
        validator.validate_names(params, request.json)
    except Exception as error:
        return jsonify({"error": error.args}), http.HTTPStatus.BAD_REQUEST
    advertiser_id = helper.get_user(get_jwt_identity()).advertiser_id

    if not helper.check_user_permissions(advertiser_id, READ_ACCESS, "campaigns"):
        return jsonify({"message": "Access denied"}), http.HTTPStatus.UNAUTHORIZED

    campaign = Campaigns.query.filter_by(
        campaign_id=request.json["campaign_id"], advertiser_id=advertiser_id
    ).first()
    if campaign:
        return (
            jsonify(
                {
                    "campaign_id": campaign.campaign_id,
                    "campaign_name": campaign.campaign_name,
                    "total_budget": campaign.total_budget,
                    "daily_budget": campaign.daily_budget,
                    "creation_date": campaign.creation_date,
                    "last_update_date": campaign.last_update_date,
                    "deletion_date": campaign.deletion_date,
                    "status": campaign.status,
                }
            ),
            http.HTTPStatus.OK,
        )
    else:
        return (
            jsonify(
                {
                    "error": f"There's no campaign with campaign_id {request.json['campaign_id']}"
                }
            ),
            http.HTTPStatus.BAD_REQUEST,
        )

@campaigns.get("/list")
@jwt_required()
def get_all_campaigns():
    advertiser_id = helper.get_user(get_jwt_identity()).advertiser_id

    if not helper.check_user_permissions(advertiser_id, READ_ACCESS, "campaigns"):
        return jsonify({"message": "Access denied"}), http.HTTPStatus.UNAUTHORIZED

    campaigns = Campaigns.query.filter_by(advertiser_id=advertiser_id)
    if campaigns.first():
        return (
            jsonify(
                [
                    {
                        "campaign_id": campaign.campaign_id,
                        "campaign_name": campaign.campaign_name,
                        "total_budget": campaign.total_budget,
                        "daily_budget": campaign.daily_budget,
                        "creation_date": campaign.creation_date,
                        "last_update_date": campaign.last_update_date,
                        "deletion_date": campaign.deletion_date,
                        "status": campaign.status,
                    }
                    for campaign in campaigns
                    if campaign.status != "DELETED"
                ]
            ),
            http.HTTPStatus.OK,
        )
    return jsonify(
        {"error": f"There are no campaigns for advertiser if {advertiser_id}."}
    )

@campaigns.post("/update")
@jwt_required()
def update_campaign():
    schema = (
        ("campaign_id", "INTEGER", True),
        ("total_budget", "INTEGER", False),
        ("daily_budget", "INTEGER", False),
        ("status", "STRING", False),
    )
    enum_values = (("status", ("ENABLED", "DISABLED")),)
    parameters = (
        "campaign_id",
        "total_budget",
        "daily_budget",
        "status",
    )
    immutable = ("campaign_id",)
    try:
        validator.validate_types(schema, request.json)
        validator.validate_values(enum_values, request.json)
        validator.validate_names(parameters, request.json)
    except Exception as error:
        return jsonify({"error": error.args}), http.HTTPStatus.BAD_REQUEST
    advertiser_id = helper.get_user(get_jwt_identity()).advertiser_id

    if not helper.check_user_permissions(advertiser_id, WRITE_ACCESS, "campaigns"):
        return jsonify({"message": "Access denied"}), http.HTTPStatus.UNAUTHORIZED

    campaign = Campaigns.query.filter_by(
        campaign_id=request.json["campaign_id"], advertiser_id=advertiser_id
    ).first()
    if not campaign:
        return (
            jsonify(
                {
                    "error": f"There's no campaign with campaign_id {request.json['campaign_id']}"
                }
            ),
            http.HTTPStatus.BAD_REQUEST,
        )
    if campaign.status == "DELETED":
        return jsonify(
            {"error": f"Campaign with {request.json['campaign_id']} id was deleted."}
        )
    for parameter in request.json:
        if parameter not in immutable:
            setattr(campaign, parameter, request.json[parameter])
    campaign.last_update_date = datetime.utcnow()
    db.session.commit()
    return (
        jsonify(
            {
                "message": "Campaign updated",
                "campaign": {
                    "campaign_id": campaign.campaign_id,
                    "campaign_name": campaign.campaign_name,
                },
            }
        ),
        http.HTTPStatus.OK,
    )

def delete_ads(adgroup_id):
    ads = Ads.query.filter_by(adgroup_id=adgroup_id)
    for ad in ads:
        ad.status = "DELETED"
        if not ad.deletion_date:
            ad.deletion_date = datetime.utcnow()
    db.session.commit()

def delete_adgroups(campaign_id):
    adgroups = Adgroups.query.filter_by(campaign_id=campaign_id)
    for adgroup in adgroups:
        adgroup.status = "DELETED"
        if not adgroup.deletion_date:
            adgroup.deletion_date = datetime.utcnow()
        delete_ads(adgroup.adgroup_id)
    db.session.commit()

@campaigns.post("/delete")
@jwt_required()
def delete_campaign():
    schema = (("campaign_id", "INTEGER", True),)
    parameters = ("campaign_id",)
    try:
        validator.validate_types(schema, request.json)
        validator.validate_names(parameters, request.json)
    except Exception as error:
        return jsonify({"error": error.args}), http.HTTPStatus.BAD_REQUEST
    advertiser_id = helper.get_user(get_jwt_identity()).advertiser_id

    if not helper.check_user_permissions(advertiser_id, ADMIN_ACCESS, "campaigns"):
        return jsonify({"message": "Access denied"}), http.HTTPStatus.UNAUTHORIZED

    campaign = Campaigns.query.filter_by(
        campaign_id=request.json["campaign_id"], advertiser_id=advertiser_id
    ).first()
    if not campaign:
        return (
            jsonify(
                {
                    "error": f"There's no campaign with campaign_id {request.json['campaign_id']}"
                }
            ),
            http.HTTPStatus.BAD_REQUEST,
        )
    campaign.deletion_date = datetime.utcnow()
    campaign.status = "DELETED"
    helper.lazy_delete(Campaigns)
    delete_adgroups(request.json["campaign_id"])
    return (
        jsonify(
            {
                "message": "Campaign deleted",
                "campaign": {"campaign_id": campaign.campaign_id},
            }
        ),
        http.HTTPStatus.OK,
    )

@campaigns.post("/undelete")
@jwt_required()
def undelete_campaign():
    schema = (("campaign_id", "INTEGER", True),)
    parameters = ("campaign_id",)
    try:
        validator.validate_types(schema, request.json)
        validator.validate_names(parameters, request.json)
    except Exception as error:
        return jsonify({"error": error.args}), http.HTTPStatus.BAD_REQUEST
    advertiser_id = helper.get_user(get_jwt_identity()).advertiser_id

    if not helper.check_user_permissions(advertiser_id, ADMIN_ACCESS, "campaigns"):
        return jsonify({"message": "Access denied"}), http.HTTPStatus.UNAUTHORIZED

    campaign = Campaigns.query.filter_by(
        advertiser_id=advertiser_id,
        campaign_id=request.json["campaign_id"],
        status="DELETED",
    ).first()
    if not campaign:
        return (
            jsonify(
                {
                    "error": f"There's no deleted campaign with id {request.json['campaign_id']}"
                }
            ),
            http.HTTPStatus.BAD_REQUEST,
        )
    campaign.deletion_date = None
    campaign.status = "ENABLED"
    db.session.commit()
    return (
        jsonify(
            {
                "message": "Campaign undeleted",
                "campaign": {"campaign_id": campaign.campaign_id},
            }
        ),
        http.HTTPStatus.OK,
    )


class BankAccount:
    all_Accounts = []
    def __init__(self, int_rate, balance = 0):
        self.balance = balance
        self.int_rate = int_rate
        BankAccount.all_Accounts.append(self)

    def deposit(self, amount):
        if amount > 0:
            self.balance += amount
            print(f"Deposit of: ${amount} was successful.")
        return self

    def withdraw(self, amount):
        if self.balance >= amount:
            self.balance -= amount
            print(f"Withdrawing: ${amount}")
        else:
            print(f"Insufficient funds. You attempted to withdraw ${amount} but only had ${self.balance} in your account. $5 overdraft fee has been applied and you still didn't get your money. Umadbro?")
            self.balance -= 5
        return self

    def display_account_info(self):
        print(f"Balance: ${self.balance}")
        return self

    def yield_interest(self):
        if self.balance > 0:
            self.balance = self.balance + (self.balance * self.int_rate)
            print(f"{self.int_rate*100}% Interest applied. New balance: ${self.balance}")
        return self

account1 = BankAccount(.04)
account2 = BankAccount(.05)

account1.deposit(500).deposit(200).deposit(1000).withdraw(200).display_account_info().yield_interest()
account2.deposit(150).deposit(100).withdraw(100).withdraw(50).withdraw(75).withdraw(50).yield_interest().display_account_info()

for accounts in BankAccount.all_Accounts:
    accounts.display_account_info()


import numpy as np

class Individual:
    def __init__(self, n_queens: int = 8) -> None:
        self.board_size = n_queens
        self.col_indices = np.random.choice(np.arange(0, n_queens), size=n_queens, replace=False)
        self.genes = np.zeros(shape=(n_queens, n_queens))
        self.fill_genes()

        self.max_fitness = (n_queens * (n_queens - 1)) / 2
        self.fitness = self.calculate_fitness()

    def calculate_fitness(self):
        return self.max_fitness - self._calculate_diagonal_collisions()

    def fill_genes(self):
        self.genes = np.zeros(shape=(self.board_size, self.board_size))

        for row, col in enumerate(self.col_indices):
            self.genes[row, col] = 1

    def __eq__(self, __o: object) -> bool:
        return __o.fitness == self.fitness

    def __gt__(self, __o: object) -> bool:
        return self.fitness > __o.fitness

    def _calculate_diagonal_collisions(self):
        self.fill_genes()
        rows, cols = np.where(self.genes == 1)
        diagonal_collides = 0

        for row, col in zip(rows, cols):
            # go to top right
            row_i = row
            col_i = col

            while row_i >= 0 and col_i < self.board_size:
                if self.genes[row_i, col_i] == 1 and (row != row_i and col_i != col):
                    diagonal_collides += 1

                row_i -= 1
                col_i += 1

            # go to bottom right
            row_i = row
            col_i = col

            while row_i < 8 and col_i < self.board_size:
                if self.genes[row_i, col_i] == 1 and (row != row_i and col_i != col):
                    diagonal_collides += 1

                row_i += 1
                col_i += 1

            # got to top left
            row_i = row
            col_i = col

            while row_i >= 0 and col_i >= 0:
                if self.genes[row_i, col_i] == 1 and (row != row_i and col_i != col):
                    diagonal_collides += 1

                row_i -= 1
                col_i -= 1

            # go to bottom left
            row_i = row
            col_i = col

            while row_i < self.board_size and col_i >= 0:
                if self.genes[row_i, col_i] == 1 and (row != row_i and col_i != col):
                    diagonal_collides += 1

                row_i += 1
                col_i -= 1

        return diagonal_collides

    def mutate(self) -> None:
        i, j = np.random.choice(np.arange(0, self.board_size), size=2, replace=False)

        val1 = self.col_indices[i]
        self.col_indices[i] = self.col_indices[j]
        self.col_indices[j] = val1
        self.fill_genes()

    def crossover(self, __0: object) -> object:
        split_point = np.random.randint(0, self.board_size)
        new_item = Individual(n_queens=self.board_size)

        new_item.genes[:split_point] = __0.genes[:split_point]
        new_item.genes[split_point:] = self.genes[split_point:]

        new_item.fill_genes()

        return new_item

    def print_fitness(self):
        print(f"Fitness: {self.fitness:.0f}/{self.max_fitness:.0f}")

    def print_board(self):
        self.fill_genes()
        print(self.genes.astype(int))
        print(self.col_indices)


"""
"""
import functools

import tensorflow as tf

def block(
        tensors,
        filters,
        stride,
        expansion,
        survival_rate,
        activation,
        normalization,
        initializer,
        scope_name):
    """
    """
    num_filters_in = tensors.shape[-1]

    identity_tensors = tensors

    with tf.variable_scope(scope_name):
        tensors = tf.layers.conv2d(
            tensors,
            filters=num_filters_in * expansion,
            kernel_size=1,
            strides=1,
            padding='same',
            activation=None,
            use_bias=False,
            kernel_initializer=initializer,
            name='head')

        tensors = normalization(tensors)

        tensors = activation(tensors)

        filter_weights = tf.get_variable(
            'depthwise_conv_filter',
            [3, 3, num_filters_in * expansion, 1],
            initializer=initializer,
            dtype=tf.float32)

        tensors = tf.nn.depthwise_conv2d(
            tensors,
            filter_weights,
            strides=[1, stride, stride, 1],
            padding='SAME',
            rate=[1, 1],
            name='depthwise_conv')

        tensors = normalization(tensors)

        tensors = activation(tensors)

        tensors = tf.layers.conv2d(
            tensors,
            filters=filters,
            kernel_size=1,
            strides=1,
            padding='same',
            activation=None,
            use_bias=False,
            kernel_initializer=initializer,
            name='tail')

        tensors = normalization(tensors)

        if stride == 1 and num_filters_in == filters:
            tensors = tf.add(tensors, identity_tensors)

            if survival_rate < 1.0:
                tensors = survival_rate * tensors

        tensors = activation(tensors)

    return tensors

def block_2(
        tensors,
        filters,
        stride,
        expansion,
        survival_rate,
        activation,
        normalization,
        initializer,
        scope_name):
    """
    """
    num_filters_in = tensors.shape[-1]

    identity_tensors = tensors

    with tf.variable_scope(scope_name):
        tensors = tf.layers.conv2d(
            tensors,
            filters=num_filters_in * expansion,
            kernel_size=1,
            strides=1,
            padding='same',
            activation=None,
            use_bias=False,
            kernel_initializer=initializer,
            name='head')

        tensors = normalization(tensors)

        tensors = activation(tensors)

        tensors = tf.layers.conv2d(
            tensors,
            filters=num_filters_in * expansion,
            kernel_size=3,
            strides=stride,
            padding='same',
            activation=None,
            use_bias=False,
            kernel_initializer=initializer,
            name='mid')

        tensors = normalization(tensors)

        tensors = activation(tensors)

        tensors = tf.layers.conv2d(
            tensors,
            filters=filters,
            kernel_size=1,
            strides=1,
            padding='same',
            activation=None,
            use_bias=False,
            kernel_initializer=initializer,
            name='tail')

        tensors = normalization(tensors)

        if stride == 1 and num_filters_in == filters:
            tensors = tf.add(tensors, identity_tensors)

            if survival_rate < 1.0:
                tensors = survival_rate * tensors

        tensors = activation(tensors)

    return tensors

def stochastic_block(
        tensors,
        stride,
        expansion,
        training,
        survival_rate,
        activation,
        normalization,
        initializer,
        scope_name):
    """
    """
    in_channels = tensors.shape[-1]

    filters = in_channels if stride == 1 else 2 * in_channels

    fn_block = functools.partial(
        block_2,
        tensors=tensors,
        filters=filters,
        stride=stride,
        expansion=expansion,
        activation=activation,
        normalization=normalization,
        initializer=initializer,
        scope_name=scope_name)

    # NOTE: pooling or keep alive
    if survival_rate >= 1.0 or stride != 1:
        return fn_block(survival_rate=1.0)

    # NOTE: take care of the issue on tf.cond
    #       https://github.com/tensorflow/tensorflow/issues/14699

    # NOTE: block for training
    with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE):
        survived_tensors = fn_block(survival_rate=1.0)

        survival_roll = tf.random_uniform(
            shape=[], minval=0.0, maxval=1.0, name='survival')

        survive = tf.less(survival_roll, survival_rate)

    with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE):
        test_tensors = fn_block(survival_rate=survival_rate)

    def train():
        return tf.cond(survive, lambda: survived_tensors, lambda: tensors)

    def test():
        return test_tensors

    return tf.cond(training, train, test)

def build_model(images, strokes, lengths, labels, training):
    """
    """
    activation = tf.nn.relu

    normalization = functools.partial(
        tf.contrib.layers.batch_norm, is_training=training)

    initializer = tf.truncated_normal_initializer(stddev=0.02)

    resnets_block = functools.partial(
        stochastic_block,
        stride=1,
        expansion=1,
        training=training,
        activation=activation,
        normalization=normalization,
        initializer=initializer)

    pooling_block = functools.partial(
        stochastic_block,
        stride=2,
        expansion=1,
        training=training,
        survival_rate=1.0,
        activation=activation,
        normalization=normalization,
        initializer=initializer)

    tensors = images

    tensors = tf.layers.conv2d(
        tensors,
        filters=64,
        kernel_size=3,
        strides=2,
        padding='same',
        activation=None,
        use_bias=False,
        kernel_initializer=initializer,
        name='conv_in')

    tensors = normalization(tensors)

    tensors = activation(tensors)

    tensors = resnets_block(tensors, scope_name='r00', survival_rate=1.0)
#   tensors = resnets_block(tensors, scope_name='r01', survival_rate=0.9)
#   tensors = resnets_block(tensors, scope_name='r02', survival_rate=0.8)
#   tensors = resnets_block(tensors, scope_name='r03', survival_rate=0.7)
#   tensors = resnets_block(tensors, scope_name='r04', survival_rate=0.6)
#   tensors = resnets_block(tensors, scope_name='r05', survival_rate=0.5)

    tensors = pooling_block(tensors, scope_name='p10')
    tensors = resnets_block(tensors, scope_name='r10', survival_rate=1.0)
#   tensors = resnets_block(tensors, scope_name='r11', survival_rate=0.9)
#   tensors = resnets_block(tensors, scope_name='r12', survival_rate=0.8)
#   tensors = resnets_block(tensors, scope_name='r13', survival_rate=0.7)
#   tensors = resnets_block(tensors, scope_name='r14', survival_rate=0.6)
#   tensors = resnets_block(tensors, scope_name='r15', survival_rate=0.5)

    tensors = pooling_block(tensors, scope_name='p20')
    tensors = resnets_block(tensors, scope_name='r20', survival_rate=1.0)
#   tensors = resnets_block(tensors, scope_name='r21', survival_rate=0.9)
#   tensors = resnets_block(tensors, scope_name='r22', survival_rate=0.8)
#   tensors = resnets_block(tensors, scope_name='r23', survival_rate=0.7)
#   tensors = resnets_block(tensors, scope_name='r24', survival_rate=0.6)
#   tensors = resnets_block(tensors, scope_name='r25', survival_rate=0.5)

    tensors = pooling_block(tensors, scope_name='p30')
#   tensors = resnets_block(tensors, scope_name='r31', survival_rate=0.95)
    tensors = resnets_block(tensors, scope_name='r32', survival_rate=0.90)
#   tensors = resnets_block(tensors, scope_name='r33', survival_rate=0.85)
    tensors = resnets_block(tensors, scope_name='r34', survival_rate=0.80)
#   tensors = resnets_block(tensors, scope_name='r35', survival_rate=0.75)
    tensors = resnets_block(tensors, scope_name='r36', survival_rate=0.70)
#   tensors = resnets_block(tensors, scope_name='r37', survival_rate=0.65)
    tensors = resnets_block(tensors, scope_name='r38', survival_rate=0.60)
#   tensors = resnets_block(tensors, scope_name='r39', survival_rate=0.55)
    tensors = resnets_block(tensors, scope_name='r3a', survival_rate=0.50)

    tensors = tf.layers.conv2d(
        tensors,
        filters=1360,
        kernel_size=1,
        strides=1,
        padding='same',
        activation=None,
        use_bias=False,
        kernel_initializer=initializer,
        name='block_final')

    tensors = normalization(tensors)

    tensors = activation(tensors)

    tensors = tf.reduce_mean(tensors, axis=[1, 2])

    # NOTE: flatten for fc
    tensors = tf.layers.flatten(tensors)

    # NOTE:
    logits = tf.layers.dense(
        tensors,
        units=340,
        activation=None,
        use_bias=True,
        kernel_initializer=initializer,
        name='final')

    loss = tf.losses.sparse_softmax_cross_entropy(
        labels,
        logits,
        reduction=tf.losses.Reduction.SUM_OVER_BATCH_SIZE)

    return {
        'images': images,
        'labels': labels,
        'strokes': strokes,
        'lengths': lengths,
        'logits': logits,
        'loss': loss,
    }


"""
## WORK IN PROGRESS

## Installation
Save script in Maya's script folder.

## Execute as python
import copy_paste_attributes
copy_paste_attributes.create()
"""

import maya.OpenMayaUI as omui
import maya.api.OpenMaya as om
import pymel.core as pm
import collections
import json
import sys
import os

qt_version = 5
try:
    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtWidgets import *
    from shiboken2 import wrapInstance
except ImportError:
    from PySide.QtCore import *
    from PySide.QtGui import *
    from shiboken import wrapInstance
    qt_version = 4

window = None

def get_main_maya_window():
    ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(ptr), QMainWindow)

def create():
    global window
    if window is None:
        window = CopyPasteAttributes(parent=get_main_maya_window())
    window.show()  # show the window
    window.raise_()  # raise it on top of others
    window.activateWindow()  # set focus to it

def delete():
    global window
    if window is not None:
        sys.stdout.write('# Deleting %s' % window.objectName())
        window.delete_instance()
        window = None

class CopyPasteAttributes(QMainWindow):
    def __init__(self, parent):
        super(CopyPasteAttributes, self).__init__(parent)

        # setup window
        self.parent = parent

        self.setWindowTitle('Copy/Paste Attributes')
        self.window_name = 'CopyPasteAttributesObj'
        self.setObjectName(self.window_name)

        self.setMinimumWidth(350)
        self.setMaximumWidth(1000)

        if os.name == 'nt':  # windows platform
            self.setWindowFlags(Qt.Window)
        else:
            self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)

        self.setProperty("saveWindowPref", True)

        self.clipboard = None
        self.json_data = ""

        self.create_window()

    def keyPressEvent(self, event):
        pass  # prevent key press events to propagate to maya

    def hideEvent(self, event):
        if not self.isMinimized():
            self.close_window()

    def close_window(self):
        self.close()

    def show_window(self, *args):
        self.show()
        self.raise_()
        self.activateWindow()

    def create_window(self, *args):
        main_widget = QWidget()
        self.setCentralWidget(main_widget)

        main_layout = QVBoxLayout(main_widget)
        main_layout.setContentsMargins(6, 6, 6, 6)

        self.setStyleSheet(
            'QLabel { min-width: 100px; min-height: 20px; }'
            'QLabel:disabled { background-color: none; }'
            'QLineEdit { min-height: 20px; padding: 0 3px; border-radius: 2px; }'
            'QLineEdit:disabled { color: rgb(128,128,128); background-color: rgb(64,64,64); }'
            'QPushButton { padding: 0 6px; border-radius: 0px; background-color: rgb(93,93,93); height: 26px }'
            'QPushButton:hover { background-color: rgb(112,112,112); }'
            'QPushButton:pressed { background-color: rgb(29,29,29); }'
        )

        # copy button layout
        self.copy_layout = QHBoxLayout()
        self.copy_button = QPushButton('Copy Selected Attributes')
        self.copy_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.connect(self.copy_button, SIGNAL('clicked()'), self.copy_button_clicked)
        self.copy_layout.addWidget(self.copy_button)

        # paste buttons layout
        self.paste_layout = QHBoxLayout()
        self.paste_name_button = QPushButton('Paste by Name')
        self.paste_name_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.connect(self.paste_name_button, SIGNAL('clicked()'), self.paste_name_button_clicked)
        self.paste_order_button = QPushButton('Paste by Selected Order')
        self.paste_order_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.connect(self.paste_order_button, SIGNAL('clicked()'), self.paste_order_button_clicked)
        self.paste_layout.addWidget(self.paste_name_button)
        self.paste_layout.addWidget(self.paste_order_button)

        # data layout
        self.data_layout = QHBoxLayout()
        self.data_label = QLabel('Copy Data:')
        self.data_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.data_line = QLineEdit()
        self.data_line.setText(self.json_data)
        self.data_line.setReadOnly(True)
        self.data_line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.data_layout.addWidget(self.data_label)
        self.data_layout.addWidget(self.data_line)

        # paste data layout
        self.paste_data_layout = QHBoxLayout()
        self.paste_data_label = QLabel('Optional Data:')
        self.paste_data_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.paste_data_line = QLineEdit()
        self.paste_data_line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        self.paste_data_line.setPlaceholderText('Paste text from "Copy Data"')
        self.paste_data_layout.addWidget(self.paste_data_label)
        self.paste_data_layout.addWidget(self.paste_data_line)

        # add layouts to inner layout, and inner layout to main layout
        inner_layout = QVBoxLayout()
        inner_layout.addLayout(self.copy_layout)
        inner_layout.addLayout(self.data_layout)
        inner_layout.addLayout(self.create_separator_layout())
        inner_layout.addLayout(self.paste_layout)
        inner_layout.addLayout(self.paste_data_layout)
        inner_layout.addStretch()

        main_layout.addLayout(inner_layout)

    def copy_button_clicked(self):
        clipboard = self.copy_channelbox_attributes()

        if clipboard:
            self.clipboard = clipboard
            self.json_data = json.dumps(self.clipboard)
            self.data_line.setText(self.json_data)

    def paste_name_button_clicked(self):
        pass

    def paste_order_button_clicked(self):
        pass

    @staticmethod
    def copy_channelbox_attributes():
        # copy values from selected main and shape attributes
        main_channels = pm.channelBox('mainChannelBox', q=True, selectedMainAttributes=True)
        shape_channels = pm.channelBox('mainChannelBox', q=True, selectedShapeAttributes=True)
        # input_attr = pm.channelBox('mainChannelBox', q=True, selectedHistoryAttributes=True)
        # output_attr = pm.channelBox('mainChannelBox', q=True, selectedOutputAttributes=True)

        clipboard = collections.OrderedDict()
        for obj in pm.ls(orderedSelection=True):
            main_attr = {}
            shape_attr = {}

            if main_channels:
                for at in main_channels:
                    if pm.hasAttr(obj, at):
                        main_attr[str(at)] = pm.getAttr(obj + '.' + at)

            shape_node = obj.getShape()
            if shape_channels:
                for at in shape_channels:
                    if pm.hasAttr(obj, at):
                        shape_attr[str(at)] = pm.getAttr(shape_node + '.' + at)

            clipboard[str(obj.fullPath())] = {'main_attributes': main_attr, 'shape_attributes': shape_attr}

        return clipboard

    @staticmethod
    def paste_channelbox_attributes(data=None, objects=None):
        if not data:
            pm.warning('Nothing to paste from.')
            return

        for obj in objects:
            for k, cat in data.iteritems():
                for at, value in cat['main_attributes'].iteritems():
                    if pm.hasAttr(obj, at):
                        pm.setAttr(obj + '.' + at, float(value))

                shape_node = obj.getShape()
                if shape_node:
                    for at, value in cat['shape_attributes'].iteritems():
                        if pm.hasAttr(shape_node, at):
                            pm.setAttr(shape_node + '.' + at, float(value))

    @staticmethod
    def create_separator_layout():
        layout = QHBoxLayout()
        frame = QFrame()
        frame.setFrameShape(QFrame.HLine)
        layout.addWidget(frame)
        return layout


import numpy as np
import gm2fr.src.constants as const
import scipy.optimize as opt

from gm2fr.src.WiggleModels import *
import matplotlib.pyplot as plt
import gm2fr.src.style as style
style.set_style()

# ==============================================================================

class WiggleFit:

  # ============================================================================

  def __init__(
    self,
    signal,
    model = "five", # wiggle fit model ("two" / "five" / "nine")
    start = 30,     # fit start time (us)
    end = 650,      # fit end time (us)
    n = 0.108       # the n-value, if known, helps inform CBO frequency seed
  ):

    # Finely-binned signal data for the fast rotation signal.
    self.fine_signal = signal.copy()

    # Fit options.
    self.start = start
    self.end = end
    self.n = n

    self.group = int((const.info["T"].magic * 1E-3) // self.fine_signal.width)
    self.coarse_signal = self.fine_signal.copy().rebin(self.group, discard = True).mask((self.start, self.end))

    # Ensure the errors are all non-zero.
    self.fine_signal.errors[self.fine_signal.errors == 0] = 1
    self.coarse_signal.errors[self.coarse_signal.errors == 0] = 1

    self.models = []
    if model == "two":
      self.models.append(TwoParameter())
    if model == "five":
      self.models.append(TwoParameter())
      self.models.append(FiveParameter())
    if model == "nine":
      self.models.append(TwoParameter())
      self.models.append(FiveParameter())
      self.models.append(NineParameter(n))
    if len(self.models) == 0:
      raise ValueError(f"Wiggle fit model '{model}' not recognized.")

    self.models[0].seeds[0] = self.coarse_signal.heights[0] # set better seed for parameter N
    self.model = None

    # Fit results.
    self.fit_result = None
    self.fine_result = None

  # ============================================================================

  def results(self):
    return self.model.results(prefix = "wg")

  def fit(self):

    # Iterate through the models, updating fit seeds each time.
    for model in self.models:

      # Update the new seeds with the latest fit's results.
      if self.model is not None:
        model.seeds[:len(self.model.p_opt)] = self.model.p_opt

      # Divide out the optimal 2-parameter fit, then fit just the omega_a wiggle to obtain initial seeds.
      if type(model) is FiveParameter:
        wiggle_part = self.coarse_signal.heights / self.model.eval(self.coarse_signal)
        p_opt, p_cov = opt.curve_fit(model.five, self.coarse_signal.centers, wiggle_part, p0 = model.seeds[2:], maxfev = 100000)
        model.seeds[2:] = p_opt

      # Divide out the optimal 5-parameter fit, then fit just the CBO wiggle to obtain initial seeds.
      if type(model) is NineParameter:
        cbo_part = self.coarse_signal.heights / self.model.eval(self.coarse_signal)
        p_opt, p_cov = opt.curve_fit(model.nine, self.coarse_signal.centers, cbo_part, p0 = model.seeds[5:], maxfev = 100000)
        model.seeds[5:] = p_opt

      # Fit the entire model, with all parameters floating from initial seeds.
      model.fit(self.coarse_signal)

      # Calculate the best fit and residuals.
      self.fit_result = model.eval(self.coarse_signal.centers)

      # Status update.
      model.print()

      self.model = model

    # Evaluate the finely-binned fit result.
    self.fine_result = self.model.eval(self.fine_signal) / self.group

# ==============================================================================

  # Plot the wiggle fit.
  def plot(self, output):

    if output is not None:

      # Time used to wrap the plot around.
      modTime = 102.5

      # Calculate the indices (exclusive) at which a wrap occurs.
      breaks = np.nonzero(np.diff(self.coarse_signal.centers % modTime) < 0)[0] + 1

      # Split the signal data into a list of chunks, one for each wrap.
      times = np.split(self.coarse_signal.centers, breaks)
      signals = np.split(self.coarse_signal.heights, breaks)
      errors = np.split(self.coarse_signal.errors, breaks)

      # Plot each wrapped chunk of the data and fit.
      for i, (time, signal, error) in enumerate(zip(times, signals, errors)):
        style.errorbar(time % modTime, signal, error, c = "C0", zorder = 0)
        plt.plot(time % modTime, self.model.eval(time), c = "C1")

      # Set a logarithmic vertical scale.
      plt.yscale("log")

      # Axis labels.
      style.ylabel("Counts / 149 ns")
      style.xlabel("Time mod 102.5 us")

      # Annotate the fit quality.
      style.databox(
        style.Entry(self.model.chi2_ndf, r"\chi^2/\mathrm{ndf}"),
        style.Entry(self.model.p_value, "p")
      )

      # Save and clear.
      plt.savefig(output)
      plt.clf()

# ==============================================================================

  # Plot the raw positron signal.
  def plot_fine(self, output, endTimes):

    if output is not None:

      # Plot the signal.
      plt.plot(self.fine_signal.centers, self.fine_signal.heights)

      self.fine_signal.plot(errors = False, skip = 10)

      # Label the axes.
      style.xlabel(r"Time ($\mu$s)")
      style.ylabel("Intensity")

      # Plot the early-time contamination.
      plt.xlim(0, 5)
      plt.ylim(0, None)

      pdf = style.make_pdf(f"{output}/RawSignal.pdf")
      pdf.savefig()

      # Save the figure over a range of time axis limits (in us).
      for end in endTimes:

        # Set the time limits.
        plt.xlim(4, end)

        # Update the intensity limits.
        view = self.fine_signal.heights[(self.fine_signal.centers >= 4) & (self.fine_signal.centers <= end)]
        plt.ylim(0, np.max(view))

        # Save the figure.
        pdf.savefig()

      # Clear the figure.
      plt.clf()
      pdf.close()


import random
Boys = ['ali', 'reza', 'yasin', 'benyamin', 'mehrdad', 'sajjad', 'aidin', 'shahin']
Girls = ['sara', 'zari', 'neda', 'homa', 'eli', 'goli', 'mary', 'mina']
Couples = []
while len(Boys) != 0 :
    Couple = []
    boy = random.choice(Boys)
    Couple.append(boy)
    girl = random.choice(Girls)
    Couple.append(girl)
    Boys.pop(Boys.index(boy))
    Girls.pop(Girls.index(girl))
    Couples.append(Couple)

print(Couples)


from flask import render_template, g
import sqlite3
from contextlib import closing
from app import app

app.config.from_object('config')

def connect_db():
    return sqlite3.connect(DATABASE)

def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql', mode='r') as f:
            db.cursor().executescript(f.read())
        db.commit()

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    db = getattr(g, 'db', None)
    if db is not None:
        db.close()

@app.route('/')
@app.route('/index')
def index():
    return render_template('index.html',
                           title='Cookr')

@app.route('/view_foods')
def view_foods():
    cur = g.db.execute('SELECT name, "group" FROM food ORDER BY name')
    entries = [dict(name=row[0], group=row[1]) for row in cur.fetchall()]
    return render_template('view_foods.html', title="Cookr", entries=entries)

@app.route('/view_recipes')
def view_recipes():
    cur = g.db.execute('''SELECT name, description, instructions
                          FROM recipe
                          ORDER BY id''')
    entries = [dict(name=row[0], description=row[1],
               instructions=row[2]) for row in cur.fetchall()]
    return render_template('view_recipes.html', title="Cookr", entries=entries)

'''
@app.route('/add_food', methods=['POST'])
def add_food():
    g.db.execute('INSERT INTO entries (title, text) VALUES (?, ?)',
                 [request.form['title'], request.form['text']])
    g.db.commit()
    flash('New entry was successfully posted')
    return redirect(url_for('show_entries'))

@app.route('/add_recipes', methods=['POST'])
def add_recipe():
    g.db.execute('INSERT INTO entries (title, text) VALUES (?, ?)',
                 [request.form['title'], request.form['text']])
    g.db.commit()
    flash('New entry was successfully posted')
    return redirect(url_for('show_entries'))'''


from fastapi import APIRouter, Depends, FastAPI, HTTPException,status
from sqlalchemy.orm import Session
from typing import List
from auth import get_current_user

from database import engine, get_db
import model, schema
model.Base.metadata.create_all(bind=engine)

app = FastAPI()

router=APIRouter(
    prefix="/todo",
    )

@router.get("/",status_code=200,response_model=List[schema.TodoGet])
async def read_all_todo(user=Depends(get_current_user),db:Session=Depends(get_db)):
    db_todos=db.query(model.Todo).filter(model.Todo.user_id==user.id).all()
    print(f'db todos are {db_todos}')
    db_json=[db_todo for db_todo in db_todos]
    return db_json

@router.get("/{todo_id}",status_code=200)
async def read_todo(todo_id: int, user:schema.UserOut = Depends(get_current_user),db: Session= Depends(get_db)):
    db_todo = db.query(model.Todo).filter(model.Todo.user_id == user.id, model.Todo.id == todo_id).first()
    if not db_todo:
        raise HTTPException(
            status_code= status.HTTP_404_NOT_FOUND,
            detail= f"Item with {id} not found"
        )
    return db_todo

@router.post("/")
async def post_todos(task:schema.TodoCreate,user:schema.UserOut = Depends(get_current_user), db: Session = Depends(get_db)):
    user_id = db.query(model.Todo).filter(model.Todo.user_id == user.id).first()
    if user_id:
        raise HTTPException(detail="Item already exist")
    user_todo = model.Todo(
        id = task.id,
        task = task.task,
        minutes = task. minutes,
        user_id = user.id
    )
    db.add(user_todo)
    db.commit()
    db.refresh(user_todo)
    return user_todo

@router.put("/{task_id}", status_code= status.HTTP_201_CREATED)
async def update_todo(task_id: int, task:schema.TodoGet,user:schema.UserOut = Depends(get_current_user), db: Session = Depends(get_db)):
    user = db.query(model.Todo).filter(model.Todo.user_id == user.id, model.Todo.id == task_id)
    user_id = user.id
    if not user_id:
        raise HTTPException(
            status_code= status.HTTP_404_NOT_FOUND,
            detail= f"Item with id {task_id} not found"
        )
    update_todo = user.update(task.dict(), synchronize_session = False)
    db.commit()
    return user

@router.delete("/{task_id}")
async def delete_todo(task_id : int, task : schema.TodoGet, user: schema.UserOut = Depends(get_current_user), db : Session = Depends(get_db)):
    db_todo = db.query(model.Todo).filter(model.Todo.user_id == user.id, model.Todo.id == task_id)
    if db_todo is None:
        raise HTTPException(status_code=400,detail="Task not found")
    db.delete(db_todo)
    db.commit()
    return db_todo


#!/usr/bin/env python2

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.layout import Layout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.properties import NumericProperty, OptionProperty, VariableListProperty
from kivy.graphics import *

from pdb import set_trace

from dragndrop import DragNDropWidget

class FArgument(Widget):
	"""
	the argument section of an fBlock
	"""
	def __init__(self, text="__", **kwargs):
		self.name = text
		super(self.__class__,self).__init__(**kwargs)
		with self.canvas:
			Color(0.6,0.4,0.4)
			self.bg = Rectangle(size=self.size, pos=self.pos)
		self.layout = BoxLayout(padding=[10,10,10,10])
		self.textbox = TextInput(text=self.name)
		self.layout.add_widget(self.textbox)
		self.add_widget(self.layout)
		self.bind(size=self.redoLayout, pos=self.redoLayout)
		self.textbox.bind(text=self.updateText)

	def redoLayout(self, instance, value):
		self.bg.size = self.size
		self.bg.pos = self.pos
		self.layout.size = self.size
		self.layout.pos = self.pos

	def updateText(self, instance, value):
		self.name = self.textbox.text

	def __repr__(self):
		return self.name

class FName(Widget):
	"""
	the name of an fBlock
	"""
	def __init__(self, fName, **kwargs):
		self.fName = fName
		super(FName, self).__init__(**kwargs)
		with self.canvas:
			Color(0.4,0.4,0.4, 0.4)
			self.bg = Rectangle(size=self.size, pos=self.pos)
		self.label = Label(text=self.fName, padding=[-FLayout.blockIndent, 0])
		self.add_widget(self.label)
		self.bind(size=self.redoLayout, pos=self.redoLayout)

	def redoLayout(self, instance, value):
		try:
			self.bg.pos = (self.pos[0], self.pos[1]-(self.parent.calculateHeight()-self.height))
			self.bg.size = (self.parent.calculateWidth(), self.parent.calculateHeight())
		except AttributeError:
			self.bg.pos = self.pos
			self.bg.size = self.size
		self.label.size = self.size
		self.label.text_size = self.size

		self.label.pos = self.pos

	def __repr__(self):
		return self.fName

	def __str__(self):
		return 'FName'

class FLayout(Layout, DragNDropWidget):
	'''Box layout class. See module documentation for more information.
	'''

	droppable_zone_objects = []#list of all the objects that this can be dropped into
	nameHeight = 50
	argHeight = nameHeight
	blockWidth = 100
	blockIndent = 10

	spacing = NumericProperty(0)
	'''Spacing between children, in pixels.

	:data:`spacing` is a :class:`~kivy.properties.NumericProperty`, default to
	0.
	'''

	padding = VariableListProperty([0, 0, 0, 0])
	'''Padding between layout box and children: [padding_left, padding_top,
	padding_right, padding_bottom].

	padding also accepts a two argument form [padding_horizontal,
	padding_vertical] and a one argument form [padding].

	.. versionchanged:: 1.7.0

	Replaced NumericProperty with VariableListProperty.

	:data:`padding` is a :class:`~kivy.properties.VariableListProperty`, default to
	[0, 0, 0, 0].

	'''

	def __init__(self, fNameString=None, fArgStrings=[], nArguments=0, rootLayout = None, **kwargs):
		self.neededWidthCache = None
		self.neededHeightCache = None
		self.fName = None
		self.fArgs = []
		super(FLayout, self).__init__(**kwargs)
		self.bind(
			spacing=self._trigger_layout,
			padding=self._trigger_layout,
			children=self._update_children,
			parent=self._trigger_layout,
			size=self._trigger_layout,
			pos=self._trigger_layout
		)

		if fNameString:
			self.add_widget(FName(fNameString))

		if nArguments and fArgStrings and nArgs < len(fArgStrings):
			raise ValueError('you passed more arguments that you said your function could take')

		#adds nArguments, or the given arguments, to the fBlock widget
		self.nArguments = max(nArguments, len(fArgStrings))
		for i in range(self.nArguments):
			try:
				self.fArgs.append(FArgument(fArgStrings[i]))
			except IndexError:
				self.fArgs.append(FArgument())

		map(lambda x: self.add_widget(x, forceAdd=True), self.fArgs)

		self.rootLayout = rootLayout
		self._transient = False
		self.drop_func = self.dropOnTarget

	def __repr__(self):
		return repr(self.fName)+'('+','.join(map(repr,self.fArgs))+')'

	def isRoot(self):
		return self.parent is self.rootLayout

	def getRootFLayouts(self):
		return [widget for widget in self.rootLayout.children if widget.__class__ is FLayout]

	def getRootFLayout(self): #yay recursion
		return self if self.isRoot else self.parent.getRootFLayout()

	def _update_children(self, instance, value):
		self._invalidateSizeCache()
		self._trigger_layout(instance, value)
		self.updateDropZones()

	def updateDropZones(self):
		#"Functional programming can be concise, logical, and easy-to-read" -- someone who didn't read the next line
		FLayout.droppable_zone_objects = [self.rootLayout]+reduce(lambda listOfDropZones, rootFLayout: listOfDropZones+rootFLayout._getDropZones(), self.getRootFLayouts(), [])

	def _getDropZones(self):
		#returns a list of all the widgets that this can be dropped into
		dropZones = []
		for child in self.children:
			if (
				(child.__class__ is FName and not self.isRoot())
			or
				(child.__class__ is FArgument)
			):
				dropZones.append(child)
			elif child.__class__ is FLayout:
				dropZones += child._getDropZones()
		return dropZones

	def do_layout(self, *largs):
		# optimize layout by preventing looking at the same attribute in a loop
		len_children = len(self.children)
		if len_children == 0:
			return
		selfx = self.x
		selfy = self.y
		selfw = self.width
		selfh = self.height
		padding_left = self.padding[0]
		padding_top = self.padding[1]
		padding_right = self.padding[2]
		padding_bottom = self.padding[3]
		spacing = self.spacing
		padding_x = padding_left + padding_right
		padding_y = padding_top + padding_bottom

		y = padding_bottom

		for child in self.children:

			if child.__class__ is FLayout:
				childHeight = child.calculateHeight()
			elif child.__class__ is FName:
				childWidth = self.calculateWidth()
				childHeight = self.nameHeight
			elif child.__class__ is FArgument:
				childWidth = self.calculateWidth()-self.blockIndent
				childHeight = self.argHeight
			else:
				raise Exception("tried to add a ",child.__class__,"to an FLayout")

			childX = selfx + padding_left
			childY = selfy + y

			if child.__class__ in (FLayout, FArgument):
				childX += self.blockIndent

			child.x = childX
			child.y = childY
			if child.__class__ is not FLayout:
				child.width = childWidth
			child.height = childHeight
			y += childHeight + spacing

		try:
			self.parent.do_layout()
		except AttributeError:
			pass

		self.width = self.calculateWidth()
		self.height = self.calculateHeight()

	def calculateHeight(self):
		if self.neededHeightCache is None:
			neededHeight = 0
			for child in self.children:
				if child.__class__ is FLayout:
					neededHeight += child.calculateHeight()
				elif child.__class__ is FName:
					neededHeight += self.nameHeight
				elif child.__class__ is FArgument:
					neededHeight += self.argHeight
			self.neededHeightCache = neededHeight
		return self.neededHeightCache

	def calculateWidth(self):
		if self.neededWidthCache is None:
			neededWidths = []
			for child in self.children:
				if child.__class__ is FLayout:
					neededWidths.append(self.blockIndent+child.calculateWidth())
				elif child.__class__ is FName:
					neededWidths.append(self.blockIndent+self.blockWidth)
				elif child.__class__ is FArgument:
					neededWidths.append(self.blockIndent+self.blockWidth)
			self.neededWidthCache = max(neededWidths)
		return self.neededWidthCache

	def _invalidateSizeCache(self):
		self.neededHeightCache = None
		self.neededWidthCache = None
		try:
			self.parent._invalidateSizeCache()
		except AttributeError:
			pass

	def replaceArgument(self, argToAdd, argToReplace):
		#delete an argument and add another one at the old index (used when dropping something over another text box)
		self.fArgs[self.fArgs.index(argToReplace)] = argToAdd
		childrenIndex = self.children.index(argToReplace)
		self.remove_widget(argToReplace, forceRemove=True)
		self.add_widget(argToAdd, childrenIndex, forceAdd=True)

	def add_widget(self, widget, index=0, forceAdd=False):
		if widget.__class__ is FName:
			if self.fName:
				self.remove_widget(self.fName)
			self.fName = widget
			index = -1
		elif isinstance(widget, (FArgument, FLayout)):
			if not forceAdd:
				raise ValueError('you can\'t manually add/remove arguments. Use replaceArgument instead!')
		widget.bind(pos_hint=self._trigger_layout)
		self._invalidateSizeCache()
		return super(FLayout, self).add_widget(widget, index)

	def remove_widget(self, widget, forceRemove=False):
		if widget.__class__ is FName:
			self.fName = None
		elif isinstance(widget, FArgument):
			if not forceRemove:
				raise ValueError('you can\'t manually add/remove arguments. Use replaceArgument instead!')
		elif isinstance(widget, FLayout):
			if not forceRemove:
				widget._replacement = FArgument()
				return self.replaceArgument(widget._replacement, widget)
		widget.unbind(
			pos_hint=self._trigger_layout)
		self._invalidateSizeCache()
		return super(FLayout, self).remove_widget(widget)

	def setName(self):
		#TODO:
		pass

	def addArgument(self):
		#TODO:
		pass

	def on_touch_down(self, touch):

		if self.fName and self.fName.collide_point(touch.x, touch.y): #we only handle the touch if it's over our Name. Making the Name object handle the touch itself
														#might seem more sensible but I promise it's not. :)
			if not self.isRoot():
				print("need to deparent and stuff")
			else:
				print("I AM ROOT")

			DragNDropWidget.on_touch_down(self, touch)
		else:
			#this make the touch bubble to some other widget. maybe touch.bubble() would be a less retarded syntax, Kivy folks?
			return Widget.on_touch_down(self, touch)

	def dropOnTarget(self, widgetToReplace):
		self._replacement = None
		self._transient = False
		if widgetToReplace is self.rootLayout:
			self.parent.remove_widget(self)
			self.rootLayout.add_widget(self)
		else :
			if widgetToReplace.__class__ is FName:
				if widgetToReplace.parent.isRoot():
					raise Exception('tried to replace the root layout, this should be impossible as it shouldn\'t be a drop target')
				widgetToReplace = widgetToReplace.parent

			if widgetToReplace.__class__ in (FArgument, FLayout):
				fBlockParent = widgetToReplace.parent
				self.parent.remove_widget(self)
				fBlockParent.replaceArgument(self, widgetToReplace)

if __name__ == '__main__':
	class TestApp(App):
		def build(self):

			fTest = FLayout("hello()", ["arg1", "arg2"], pos=(50,50))

			fSubTest = FLayout("subfunctionlonglonglong", ["arg1_1", "arg1_2", "arg1_3"])

			fSubSubTest = FLayout("subsubfunc()", ["arg3_1", "arg3_2", "arg3_3"])

			fSubTest.replaceArgument(fSubSubTest, fSubTest.fArgs[1])

			fTest.replaceArgument(fSubTest, fTest.fArgs[0])

			print("fTest is root: ",fTest.isRoot())
			print("fSubTest is root: ",fSubTest.isRoot())
			print("fSubSubTest is root: ",fSubSubTest.isRoot())

			print("root layouts:", fSubTest.getRootFLayouts())

			return fTest

	TestApp().run()


import numpy as np
from tqdm import tqdm
import os
import shutil
import time
import torch

import scipy
import math

def db_augmentation(query_vecs, reference_vecs, sim_mat, top_k=10):
    """
    Database-side feature augmentation (DBA)
    Albert Gordo, et al. "End-to-end Learning of Deep Visual Representations for Image Retrieval,"
    International Journal of Computer Vision. 2017.
    https://link.springer.com/article/10.1007/s11263-017-1016-8
    """
    print("DBAing...")
    start_time = time.time()
    query_vecs, reference_vecs = np.array(query_vecs), np.array(reference_vecs)

    weights = np.logspace(0, -2., top_k+1)

    # Query augmentation
    _,indices = sim_mat.topk(12, largest=False)

    top_k_ref = reference_vecs[indices[:, :top_k], :]
    query_vecs = np.tensordot(weights, np.concatenate([np.expand_dims(query_vecs, 1), top_k_ref], axis=1), axes=(0, 1))
    # Reference augmentation
    if type(query_vecs) is np.ndarray:
        query_vecs = torch.from_numpy(query_vecs)

    print('=> DBA in {:.2f} seconds'.format(time.time() - start_time))
    return query_vecs

def average_query_expansion(query, gallery, dis, top_k=1):
    """
    Average Query Expansion (AQE)
    Ondrej Chum, et al. "Total Recall: Automatic Query Expansion with a Generative Feature Model for Object Retrieval,"
    International Conference of Computer Vision. 2007.
    https://www.robots.ox.ac.uk/~vgg/publications/papers/chum07b.pdf
    """
    print("AQEing...")
    start_time = time.time()
    if type(dis) is np.ndarray:
        dis = torch.from_numpy(dis)

    _,sorted_index = dis.topk(4, largest=False)
    sorted_index = sorted_index[:, :top_k]
    sorted_index = sorted_index.reshape(-1)
    requery = gallery[sorted_index].view(query.shape[0], -1, query.shape[1]).sum(dim=1)
    requery = (requery + query)/ (top_k + 1 )
    query = requery
    print('=> AQE in {:.2f} seconds'.format(time.time() - start_time))
    return query

def average_query_expansion_gallery(query, gallery,dis, top_k=1):
    # # Reference augmentation

    print("AQEing in gallery...")
    start_time = time.time()
    if type(dis) is np.ndarray:
        dis = torch.from_numpy(dis)

    _,sorted_index = dis.topk(4, largest=False)
    sorted_index = sorted_index[:, 1:top_k+1]

    sorted_index = sorted_index.reshape(-1)
    regallery = gallery[sorted_index].view(gallery.shape[0], -1, gallery.shape[1]).sum(dim=1)
    regallery = (regallery + gallery)/ (top_k + 1 )
    print('=> AQE in {:.2f} seconds'.format(time.time() - start_time))
    return regallery

def fast_kr_sparse(q_g_dist, q_q_dist, g_g_dist, k1=15, k2=3, lambda_value=0.3):
    # The following naming, e.g. gallery_num, is different from outer scope.
    # Don't care about it.
    print("fast Reranking")
    start_time = time.time()
    end_time = time.time()

    query_num = q_g_dist.shape[0]
    gallery_num = q_g_dist.shape[0] + q_g_dist.shape[1]
    all_num = gallery_num

    g_q_dist = q_g_dist.t().clone()

    topk = max(k1 + 1, k2)

    all_initial_rank_list = []
    batch_size = 128
    original_dist_batch = torch.zeros(batch_size, len(q_q_dist)+len(g_g_dist))
    total_num = math.ceil(len(q_q_dist) / float(batch_size))
    for i in tqdm(range(total_num)):
        left_id = i * batch_size
        right_id = min((i+1) * batch_size, len(q_q_dist))
        batch_len = right_id - left_id
        original_dist_batch_tmp = original_dist_batch[:batch_len]
        original_dist_batch_tmp[:, :len(q_q_dist)] = q_q_dist[left_id:right_id]
        original_dist_batch_tmp[:, len(q_q_dist):] = q_g_dist[left_id:right_id]
        original_dist_batch_tmp = original_dist_batch_tmp ** 2
        m, _ = original_dist_batch_tmp.max(1)
        original_dist_batch_tmp = original_dist_batch_tmp / m.reshape(-1, 1)
        q_q_dist[left_id:right_id] = original_dist_batch_tmp[:, :len(q_q_dist)]
        q_g_dist[left_id:right_id] = original_dist_batch_tmp[:, len(q_q_dist):]
        _, initial_rank = original_dist_batch_tmp.topk(topk, largest=False)
        all_initial_rank_list.append(initial_rank)

    total_num = math.ceil(len(g_g_dist) / float(batch_size))
    for i in tqdm(range(total_num)):
        left_id = i * batch_size
        right_id = min((i+1) * batch_size, len(g_g_dist))
        batch_len = right_id - left_id
        original_dist_batch_tmp = original_dist_batch[:batch_len]
        original_dist_batch_tmp[:, :len(q_q_dist)] = g_q_dist[left_id:right_id]
        original_dist_batch_tmp[:, len(q_q_dist):] = g_g_dist[left_id:right_id]
        original_dist_batch_tmp = original_dist_batch_tmp ** 2
        m, _ = original_dist_batch_tmp.max(1)
        original_dist_batch_tmp = original_dist_batch_tmp / m.reshape(-1, 1)
        g_q_dist[left_id:right_id] = original_dist_batch_tmp[:, :len(q_q_dist)]
        g_g_dist[left_id:right_id] = original_dist_batch_tmp[:, len(q_q_dist):]
        _, initial_rank = original_dist_batch_tmp.topk(topk, largest=False)
        all_initial_rank_list.append(initial_rank)

    initial_rank = torch.cat(all_initial_rank_list)
    initial_rank = initial_rank.numpy()

    V = scipy.sparse.lil_matrix((all_num, all_num))
    print('prepare time: {:.2f}'.format(time.time() - end_time))

    original_dist_for_1 = np.zeros(gallery_num)
    for i in tqdm(range(all_num)):
        # k-reciprocal neighbors
        forward_k_neigh_index = initial_rank[i,:k1+1]
        backward_k_neigh_index = initial_rank[forward_k_neigh_index,:k1+1]
        fi = np.where(backward_k_neigh_index==i)[0]
        k_reciprocal_index = forward_k_neigh_index[fi]
        k_reciprocal_expansion_index = k_reciprocal_index
        for j in range(len(k_reciprocal_index)):
            candidate = k_reciprocal_index[j]
            candidate_forward_k_neigh_index = initial_rank[candidate,:int(np.around(k1/2.))+1]
            candidate_backward_k_neigh_index = initial_rank[candidate_forward_k_neigh_index,:int(np.around(k1/2.))+1]
            fi_candidate = np.where(candidate_backward_k_neigh_index == candidate)[0]
            candidate_k_reciprocal_index = candidate_forward_k_neigh_index[fi_candidate]
            if len(np.intersect1d(candidate_k_reciprocal_index,k_reciprocal_index))> 2./3*len(candidate_k_reciprocal_index):
                k_reciprocal_expansion_index = np.append(k_reciprocal_expansion_index,candidate_k_reciprocal_index)

        k_reciprocal_expansion_index = np.unique(k_reciprocal_expansion_index)
        if i < len(q_q_dist):
            original_dist_for_1[:len(q_q_dist)] = q_q_dist[i]
            original_dist_for_1[len(q_q_dist):] = q_g_dist[i]
        else:
            j = i - len(q_q_dist)
            original_dist_for_1[:len(q_q_dist)] = g_q_dist[j]
            original_dist_for_1[len(q_q_dist):] = g_g_dist[j]

        weight = np.exp(-original_dist_for_1[k_reciprocal_expansion_index])
        V[i,k_reciprocal_expansion_index] = 1.*weight/np.sum(weight)

    end_time = time.time()
    if k2 != 1:
        X_list = []
        Y_list = []
        V_list = []
        array_buffer = np.zeros((k2, all_num))
        for i in tqdm(range(all_num)):
            V[initial_rank[i,:k2]].toarray(out=array_buffer)
            m = array_buffer.mean(axis=0)
            y = np.where(m)[0]
            x = np.zeros_like(y)
            x[:] = i
            v = m[y]
            X_list.append(x)
            Y_list.append(y)
            V_list.append(v)
        X = np.concatenate(X_list)
        Y = np.concatenate(Y_list)
        V = np.concatenate(V_list)
        V = scipy.sparse.csr_matrix((V, (X, Y)), shape=(all_num, all_num)).tolil()
    del initial_rank
    print('qe time: {:.2f}'.format(time.time() - end_time))

    V_t = V.transpose()
    invIndex = []
    for i in tqdm(range(gallery_num)):
        invIndex.append(V_t[i].nonzero()[1])

    jaccard_dist = np.zeros((len(q_q_dist), len(g_g_dist)),dtype = np.float32)

    temp_min = np.zeros(gallery_num,dtype=np.float32)
    for i in tqdm(range(query_num)):
        temp_min[:] = 0
        indNonZero = V[i].nonzero()[1]
        indImages = [invIndex[ind] for ind in indNonZero]
        for j in range(len(indNonZero)):
            t1 = V[i,indNonZero[j]]
            t2 = V[indImages[j],indNonZero[j]].toarray().reshape(-1)
            temp_min[indImages[j]] = temp_min[indImages[j]]+ np.minimum(t1, t2)
        temp_min = 1-temp_min/(2.-temp_min)
        jaccard_dist[i] = temp_min[len(q_q_dist):]

    new_q_g = jaccard_dist*(1-lambda_value) + q_g_dist.numpy()*lambda_value
    del V
    del jaccard_dist
    print('=> k-reciprocal in {:.2f} seconds'.format(time.time() - start_time))
    return torch.from_numpy(new_q_g)


import logging
import numpy as np
from PIL import Image
from torch.utils.data import Dataset
from torchvision import transforms
from utils.data import iOA
import torch
import random

class DataManager(object):
    def __init__(self, dataset_name, shuffle, seed, init_cls, increment):
        self.dataset_name = dataset_name
        self._setup_data(dataset_name, shuffle, seed)
        assert init_cls <= len(self._class_order), "No enough classes."
        self._increments = [init_cls]
        while sum(self._increments) + increment < len(self._class_order):
            self._increments.append(increment)
        offset = len(self._class_order) - sum(self._increments)
        if offset > 0:
            self._increments.append(offset)

    @property
    def nb_tasks(self):
        return len(self._increments)

    def get_task_size(self, task):
        return self._increments[task]

    def get_total_classnum(self):
        return len(self._class_order)

    def get_dataset(
        self, indices, source, mode, appendent=None, ret_data=False, m_rate=None
    ):
        if source == "train":
            x,y,y2,y3 = self._train_data, self._train_L3,self._train_L2,self._train_L1
        elif source == "test":
            x,y,y2,y3 = self._test_data, self._test_L3, self._test_L2,self._test_L1
        else:
            raise ValueError("Unknown data source {}.".format(source))

        if mode == "train":
            trsf = transforms.Compose([*self._train_trsf, *self._common_trsf])
        elif mode == "flip":
            trsf = transforms.Compose(
                [
                    *self._test_trsf,
                    #transforms.RandomHorizontalFlip(p=1.0),
                    *self._common_trsf,
                ]
            )
        elif mode == "test":
            trsf = transforms.Compose([*self._test_trsf, *self._common_trsf])
        else:
            raise ValueError("Unknown mode {}.".format(mode))

        data, L3,L2,L1 = [], [],[],[]
        for idx in indices:
            if m_rate is None:
                class_data, class_L3 , class_L2, class_L1  = self._select(
                    x,y,y2,y3, low_range=idx, high_range=idx + 1
                )
            else:
                class_data, class_L3, class_L2 , class_L1  = self._select_rmm(
                    x,y,y2,y3, low_range=idx, high_range=idx + 1, m_rate=m_rate
                )
            data.append(class_data)
            L3.append(class_L3)
            L2.append(class_L2)
            L1.append(class_L1)

        if appendent is not None and len(appendent) != 0:
            appendent_data, appendent_L3,appendent_L2,appendent_L1 = appendent
            data.append(appendent_data)
            L3.append(appendent_L3)
            L2.append(appendent_L2)
            L1.append(appendent_L1)

        data, L3, L2, L1 = np.concatenate(data), np.concatenate(L3),np.concatenate(L2),np.concatenate(L1)

        #suffix = datetime.datetime.now().strftime("%H%M%S")
        #output_path1= "".join([base,suffix,'data.pickle'])

        #with open(output_path1, 'wb') as f:
        #    pickle5.dump(np.concatenate(data), f)

        if ret_data:
            return data, L3,L2,L1, DummyDataset(data, L3,L2,L1, trsf, self.use_path)
        else:
            return DummyDataset(data, L3,L2,L1, trsf, self.use_path)

    def get_dataset_with_split(
        self, indices, source, mode, appendent=None, val_samples_per_class=0
    ):
        if source == "train":
            x, y,y2,y3 = self._train_data, self._train_L3, self._train_L2, self._train_L1
        elif source == "test":
            x, y,y2,y3 = self._test_data, self._test_L3, self._test_L2, self._test_L1
        else:
            raise ValueError("Unknown data source {}.".format(source))

        if mode == "train":
            trsf = transforms.Compose([*self._train_trsf, *self._common_trsf])
        elif mode == "test":
            trsf = transforms.Compose([*self._test_trsf, *self._common_trsf])
        else:
            raise ValueError("Unknown mode {}.".format(mode))

        train_data, train_L3, train_L2, train_L1 = [], [],[],[]
        val_data, val_L3, val_L2, val_L1 = [], [],[],[]
        for idx in indices:
            class_data, class_L3,class_L2,class_L1 = self._select(
                x, y,y2,y3, low_range=idx, high_range=idx + 1
            )
            val_indx = np.random.choice(
                len(class_data), val_samples_per_class, replace=False
            )
            train_indx = list(set(np.arange(len(class_data))) - set(val_indx))
            val_data.append(class_data[val_indx])
            val_L3.append(class_L3[val_indx])
            val_L2.append(class_L2[val_indx])
            val_L1.append(class_L1[val_indx])

            train_data.append(class_data[train_indx])
            train_L3.append(class_L3[train_indx])
            train_L2.append(class_L2[train_indx])
            train_L1.append(class_L1[train_indx])

        if appendent is not None:
            appendent_data, appendent_L3,appendent_L2,appendent_L1 = appendent
            for idx in range(0, int(np.max(appendent_L3)) + 1):
                append_data, append_L3,append_L2,append_L1 = self._select(
                    appendent_data, appendent_L3,appendent_L2,appendent_L1,low_range=idx, high_range=idx + 1
                )
                val_indx = np.random.choice(
                    len(append_data), val_samples_per_class, replace=False
                )
                train_indx = list(set(np.arange(len(append_data))) - set(val_indx))
                val_data.append(append_data[val_indx])
                val_L3.append(append_L3[val_indx])
                val_L2.append(append_L2[val_indx])
                val_L1.append(append_L1[val_indx])

                train_data.append(append_data[train_indx])
                train_L3.append(append_L3[train_indx])
                train_L2.append(append_L2[train_indx])
                train_L1.append(append_L1[train_indx])

        train_data, train_L3, train_L2, train_L1 = np.concatenate(train_data), np.concatenate(
            train_L3) , np.concatenate(train_L2) , np.concatenate(train_L1)

        val_data, val_L3, val_L2,val_L1 = np.concatenate(val_data), np.concatenate(val_L3),
        np.concatenate(val_L2), np.concatenate(val_L1)

        return DummyDataset(
            train_data, train_L3,train_L2,train_L1, trsf, self.use_path
        ), DummyDataset(val_data, val_L3,val_L2,val_L1,  trsf, self.use_path)

    def _setup_data(self, dataset_name, shuffle, seed):
        idata = _get_idata(dataset_name)
        idata.download_data()

        # Data
        self._train_data, self._train_L3 , self._train_L2 , self._train_L1= idata.train_data, idata.train_L3, idata.train_L2, idata.train_L1
        self._test_data, self._test_L3, self._test_L2 ,self._test_L1= idata.test_data, idata.test_L3, idata.test_L2, idata.test_L1
        self.use_path = idata.use_path

        # Transforms
        self._train_trsf = idata.train_trsf
        self._test_trsf = idata.test_trsf
        self._common_trsf = idata.common_trsf

        # Order

        order = [i for i in range(len(np.unique(self._train_L3)))]
        if shuffle:
            np.random.seed(seed)
            order = np.random.permutation(len(order)).tolist()
        else:
            order = idata.class_order
        self._class_order = order
        logging.info(self._class_order)

        # Map indices
        self._train_L3 = _map_new_class_index(
            self._train_L3, self._class_order
        )
        self._test_L3 = _map_new_class_index(self._test_L3, self._class_order)

    def _select(self, x, y,y2,y3, low_range, high_range):
        idxes = np.where(np.logical_and(y >= low_range, y < high_range))[0]
        return x[idxes], y[idxes] ,y2[idxes],y3[idxes]

    def _select_rmm(self, x, y,y2,y3, low_range, high_range, m_rate):
        assert m_rate is not None
        if m_rate != 0:
            idxes = np.where(np.logical_and(y >= low_range, y < high_range))[0]
            selected_idxes = np.random.randint(
                0, len(idxes), size=int((1 - m_rate) * len(idxes))
            )
            new_idxes = idxes[selected_idxes]
            new_idxes = np.sort(new_idxes)
        else:
            new_idxes = np.where(np.logical_and(y >= low_range, y < high_range))[0]
        return x[new_idxes], y[new_idxes] ,y2[new_idxes],y3[new_idxes]

    def getlen(self, index):
        y = self._train_L3
        return np.sum(np.where(y == index))

class DummyDataset(Dataset):
    def __init__(self, images, L3,L2,L1, trsf, use_path=False):
        assert len(images) == len(L3), "Data size error!"
        self.images = images
        self.L3 = L3
        self.L2 = L2
        self.L1 = L1
        self.trsf = trsf
        self.use_path = use_path

    def __len__(self):
        return len(self.images)

    def __getitem__(self, idx):
        if self.use_path:
            image = self.trsf(pil_loader(self.images[idx]))
        else:
            image = self.trsf(Image.fromarray(self.images[idx]))
        label = self.L3[idx]
        L2= self.L2[idx]
        L1 = self.L1[idx]

        return idx, image, label,L2,L1

def _map_new_class_index(y, order):
    return np.array(list(map(lambda x: order.index(x), y)))

def _get_idata(dataset_name):
    name = dataset_name.lower()
    if name == "ioa":
        return iOA()
    else:
        raise NotImplementedError("Unknown dataset {}.".format(dataset_name))

def pil_loader(path):
    """
    Ref:
    https://pytorch.org/docs/stable/_modules/torchvision/datasets/folder.html#ImageFolder
    """
    # open path as file to avoid ResourceWarning (https://github.com/python-pillow/Pillow/issues/835)
    with open(path, "rb") as f:
        img = Image.open(f)
        return img.convert("RGB")

def accimage_loader(path):
    """
    Ref:
    https://pytorch.org/docs/stable/_modules/torchvision/datasets/folder.html#ImageFolder
    accimage is an accelerated Image loader and preprocessor leveraging Intel IPP.
    accimage is available on conda-forge.
    """
    import accimage

    try:
        return accimage.Image(path)
    except IOError:
        # Potentially a decoding problem, fall back to PIL.Image
        return pil_loader(path)

def default_loader(path):
    """
    Ref:
    https://pytorch.org/docs/stable/_modules/torchvision/datasets/folder.html#ImageFolder
    """
    from torchvision import get_image_backend

    if get_image_backend() == "accimage":
        return accimage_loader(path)
    else:
        return pil_loader(path)


# Get latest realease from huanghongxun/HMCL, get download url
import requests

from . import keybase

ghproxy = keybase.ghproxy

def get_latest_release(ext="exe"):
    # ext = 'exe' or 'jar' or 'sh'
    url = "https://api.github.com/repos/huanghongxun/HMCL/releases/latest"
    r = requests.get(url)
    if r.status_code == 200:
        for asset in r.json()["assets"]:
            if asset["name"].endswith(ext):
                return ghproxy + asset["browser_download_url"]
    return None

if __name__ == "__main__":
    print(get_latest_release("exe"))


import cv2
import numpy as np
import datetime
import os
import random

import sys
sys.path.append("..")
from cores import Options
from util import util
from util import image_processing as impro

opt = Options()
opt.parser.add_argument('--datadir',type=str,default=' ', help='your images dir')
opt.parser.add_argument('--savedir',type=str,default='../datasets/draw/face', help='')
opt = opt.getparse()

mask_savedir = os.path.join(opt.savedir,'mask')
img_savedir = os.path.join(opt.savedir,'origin_image')
util.makedirs(mask_savedir)
util.makedirs(img_savedir)

filepaths = util.Traversal(opt.datadir)
filepaths = util.is_imgs(filepaths)
random.shuffle(filepaths)
print('find image:',len(filepaths))

# mouse callback function
drawing = False # true if mouse is pressed
ix,iy = -1,-1
brushsize = 20
def draw_circle(event,x,y,flags,param):
    global ix,iy,drawing,brushsize

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

    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing == True:
            cv2.circle(img_drawn,(x,y),brushsize,(0,255,0),-1)

    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        cv2.circle(img_drawn,(x,y),brushsize,(0,255,0),-1)

def makemask(img_drawn):
    # starttime = datetime.datetime.now()
    mask = np.zeros(img_drawn.shape, np.uint8)
    for row in range(img_drawn.shape[0]):
        for col in range(img_drawn.shape[1]):
            # if (img_drawn[row,col,:] == [0,255,0]).all(): #too slow
            if img_drawn[row,col,0] == 0:
                if img_drawn[row,col,1] == 255:
                    if img_drawn[row,col,2] == 0:
                        mask[row,col,:] = [255,255,255]
    return mask

cnt = 0
for file in filepaths:
    try:
        cnt += 1
        img = impro.imread(file,loadsize=512)
        img_drawn = img.copy()
        cv2.namedWindow('image')
        cv2.setMouseCallback('image',draw_circle) #MouseCallback
        while(1):

            cv2.imshow('image',img_drawn)
            k = cv2.waitKey(1) & 0xFF
            if k == ord('s'):

                img_drawn = impro.resize(img_drawn,256)
                mask = makemask(img_drawn)
                cv2.imwrite(os.path.join(mask_savedir,os.path.splitext(os.path.basename(file))[0]+'.png'),mask)
                cv2.imwrite(os.path.join(img_savedir,os.path.basename(file)),img)
                print('Saved:',os.path.join(mask_savedir,os.path.splitext(os.path.basename(file))[0]+'.png'),mask)
                # cv2.destroyAllWindows()
                print('remain:',len(filepaths)-cnt)
                brushsize = 20
                break
            elif k == ord('a'):
                brushsize -= 5
                if brushsize<5:
                    brushsize = 5
                print('brushsize:',brushsize)
            elif k == ord('d'):
                brushsize += 5
                print('brushsize:',brushsize)
            elif k == ord('w'):
                print('remain:',len(filepaths)-cnt)
                break
    except Exception as e:
        print(file,e)


import os
import re
from PySide6.QtGui import QFontDatabase
from PySide6.QtWidgets import QLabel, QVBoxLayout
from PySide6.QtCore import Qt
from telethon.tl.patched import Message
from telethon.tl.types import User
from src.config import MESSAGE_NAME, VIDEO_MESSAGE_PATH, VIDEO_MESSAGE_THUMB_SIZE

class TextMessage(QLabel):
    user: User = None
    message: Message = None

    def __init__(self,
                 parent,
                 user: User,
                 message: Message) -> None:
        self.user = user
        self.message = message
        super().__init__(parent)
        self.load_ui()

    def load_ui(self):
        self.add_text()

    def add_text(self):

        font = QFontDatabase.systemFont(QFontDatabase.FixedFont)
        font.setPointSizeF(15)
        self.setFont(font)
        # tl.setFont(font)
        self.setObjectName(MESSAGE_NAME)
        self.setTextFormat(Qt.TextFormat.MarkdownText)

        text = self.message.text

        if '\n**' in text:
            text = re.sub('\n+\*\*', '**\n\n', text)

        self.setText(text)
        self.setWordWrap(True)
        # self.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.setMargin(5)
        self.adjustSize()