import logging
from typing import Dict

import bpy

from . import copy_as_mmd_settings
from .copy_as_mmd_settings import CopyAsMMDSettings

log = logging.getLogger(__name__)

# Keep all lowercase
VISEMES = {
    "ah": "あ",
    "ch": "い",
    "u": "う",
    "e": "え",
    "oh": "お",
}

MMD_SHAPEKEYS = {
    "blink happy": "笑い",
    "blink": "まばたき",
    "close><": "はぅ",
    "calm": "なごみ",
    "stare": "じと目",
    "wink": "ウィンク",
    "wink right": "ウインク右",
    "wink 2": "ウインク２",
    "wink 2 right": "ウインク２右",
    "cheerful": "にこり",
    "serious": "真面目",
    "upper": "上",
    "lower": "下",
    "anger": "怒り",
    "angry": "怒り",  # = anger
    "sadness": "困る",
    "sad": "困る",  # = sadness
}

def copy_shapekey(shapekey: bpy.types.ShapeKey, target: str):
    if (not shapekey
            or target is None
            or shapekey.name == target):
        return

    shapekey.value = 1
    bpy.ops.object.shape_key_add(from_mix=True)
    bpy.context.object.active_shape_key.name = target
    shapekey.value = 0

class DuplicateVisemeAsMmdShapekey(bpy.types.Operator):
    bl_idname = "mesh.duplicate_mmd_shapekeys"
    bl_label = "Duplicate Shape Keys With MMD Names"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context: bpy.types.Context):
        obj = context.object
        settings: CopyAsMMDSettings = obj.CopyAsMMDSettings
        shapekeys: Dict = obj.data.shape_keys.key_blocks

        copy_shapekey(shapekeys.get(settings.ah), VISEMES['ah'])
        copy_shapekey(shapekeys.get(settings.ch), VISEMES['ch'])
        copy_shapekey(shapekeys.get(settings.u), VISEMES['u'])
        copy_shapekey(shapekeys.get(settings.e), VISEMES['e'])
        copy_shapekey(shapekeys.get(settings.oh), VISEMES['oh'])

        # Text Separator Shapekey
        bpy.ops.object.shape_key_add(from_mix=False)
        bpy.context.object.active_shape_key.name = " ^ MMD Visemes / Other v"

        for (key, name) in copy_as_mmd_settings.SHAPEKEY_LIST:
            sk = getattr(settings, key)
            if sk:
                copy_shapekey(shapekeys.get(sk), MMD_SHAPEKEYS.get(name or key))

        return {'FINISHED'}

def menu_func(self, context):
    self.layout.operator(DuplicateVisemeAsMmdShapekey.bl_idname, text=DuplicateVisemeAsMmdShapekey.bl_label)

# Register and add to the "object" menu (required to also use F3 search "Simple Object Operator" for quick access)
def register():
    bpy.utils.register_class(DuplicateVisemeAsMmdShapekey)
    bpy.types.VIEW3D_MT_object.append(menu_func)

def unregister():
    bpy.utils.unregister_class(DuplicateVisemeAsMmdShapekey)
    bpy.types.VIEW3D_MT_object.remove(menu_func)

if __name__ == "__main__":
    register()


#!/usr/bin/env python3

import re
import sys

import requests

ip = sys.argv[1]

data = requests.get(f'http://{ip}:9171/_debug_toolbar/sse')
data = eval(data.text.split('\n')[2][5:])
print(data)
ids = list(map(lambda x: x[0], data))
print(ids)

for each in ids:
    r = requests.get(f'http://{ip}:9171/_debug_toolbar/{each}')
    print(re.findall('[A-Z0-9]{31}=', r.text), flush=True)


import sys
import numpy as np
import networkx as nx
from sklearn.preprocessing import normalize

# convergence criterion - when vector L1 norm drops below 10^(-6)
# (this is the same as the original RWR paper)
CONV_THRESHOLD = 0.000001

class RandomWalkWithRestartCore:

    def __init__(self,

        personalization_vector,
        G,
        restart_prob = 0.25):

        self.restart_prob = restart_prob
        self.personalization_vector = personalization_vector
        self.G = G

        self._build_matrix()

    def run(self):

        p_0 = self._set_up_p0()

        diff_norm = 1

        p_t = np.copy(p_0)

        while (diff_norm > CONV_THRESHOLD):
            # first, calculate p^(t + 1) from p^(t)
            p_t_1 = self._calculate_next_p(p_t, p_0)

            # calculate L1 norm of difference between p^(t + 1) and p^(t),
            # for checking the convergence condition
            diff_norm = np.linalg.norm(np.subtract(p_t_1, p_t), 1)

            # then, set p^(t) = p^(t + 1), and loop again if necessary
            # no deep copy necessary here, we're just renaming p
            p_t = p_t_1

        # now, generate and print a rank list from the final prob vector
        ranked_list = self._generate_rank_list(p_t)

        return ranked_list

    def _generate_prob_list(self, p_t, node_list):
        gene_probs = dict(zip(self.G.nodes(), p_t.tolist()))
        for node in node_list:
            yield node, gene_probs[node]

    def _generate_rank_list(self, p_t):
        gene_probs = zip(self.G.nodes(), p_t.tolist())

        for s in sorted(gene_probs, key=lambda x: x[1], reverse=True):
            yield s[0], s[1]

    def _calculate_next_p(self, p_t, p_0):

        epsilon = np.squeeze(np.asarray(np.dot(self.normalized_adjacency_matrix, p_t)))
        no_restart = epsilon * (1 - self.restart_prob)

        restart = p_0 * self.restart_prob

        return np.add(no_restart, restart)

    def _set_up_p0(self,):

        """ Set up and return the 0th probability vector. """
        p_0 = [0] * self.G.number_of_nodes()

        for source_id,score in self.personalization_vector.items():
            try:
                # matrix columns are in the same order as nodes in original nx
                # graph, so we can get the index of the source node from the OG
                source_index = list(self.G.nodes()).index(source_id)
                p_0[source_index] = score
            except ValueError:
                sys.exit("Source node {} is not in original graph. Exiting.".format(
                          source_id))
        return np.array(p_0)

    def _build_matrix(self):
        """ Build column-normalized adjacency matrix for each graph.
        NOTE: these are column-normalized adjacency matrices (not nx
              graphs), used to compute each p-vector
        """
        adjacency_matrix_not_normalized = nx.adjacency_matrix(self.G,)

        self.normalized_adjacency_matrix = self._normalize_cols(adjacency_matrix_not_normalized).todense()

    def _normalize_cols(self, matrix):
        """ Normalize the columns of the adjacency matrix """
        return normalize(matrix, norm='l1', axis=0)


import torch
import torch.nn as nn
import numpy as np
from tqdm import tqdm

from embedder import embedder
from evaluate import evaluate
from layers import GCN, InterDiscriminator

class HDI(embedder):
    def __init__(self, args):
        embedder.__init__(self, args)
        self.args = args
        self.coef_l = self.args.coef_layers
        self.criteria = nn.BCEWithLogitsLoss()

    def training(self):
        features = self.features.to(self.args.device)
        adj_list = [adj.to(self.args.device) for adj in self.adj_list]

        print("Started training...")
        print("The number of layers: {}".format(len(adj_list)))
        final_embs = []
        for n_adj, adj in enumerate(adj_list):
            print("Layer {}".format(n_adj))
            model = modeler(self.args.ft_size, self.args.hid_units).to(self.args.device)
            optimiser = torch.optim.Adam(model.parameters(), lr=self.args.lr)
            cnt_wait = 0
            best = 1e9
            for _ in tqdm(range(self.args.nb_epochs)):
                model.train()
                optimiser.zero_grad()

                # corruption function
                idx = np.random.permutation(self.args.nb_nodes)
                shuf_fts = features[idx, :].to(self.args.device)

                logits_e, logits_i, logits_j = model(features, shuf_fts, adj, self.args.sparse)

                # loss
                loss_e = self.get_loss(logits_e)
                loss_i = self.get_loss(logits_i)
                loss_j = self.get_loss(logits_j)
                loss = self.coef_l[0] * loss_e + self.coef_l[1] * loss_i + self.coef_l[2] * loss_j

                # early stop
                if loss < best:
                    best = loss
                    cnt_wait = 0
                    torch.save(model.state_dict(), 'saved_model/best_{}_{}_{}.pkl'.format(
                        self.args.dataset, self.args.embedder, n_adj))
                else:
                    cnt_wait += 1
                if cnt_wait == self.args.patience:
                    print("Early stopped!")
                    break

                loss.backward()
                optimiser.step()

            # get embedding
            model.eval()
            embeds = model.embed(features, adj, self.args.sparse)
            final_embs.append(embeds)

        # final evaluation
        print("Evaluating...")
        final_embs = torch.mean(torch.stack(final_embs), 0)   # average pooling
        macro_f1s, micro_f1s, k1 = evaluate(final_embs, self.idx_train, self.idx_val, self.idx_test, self.labels)
        return macro_f1s, micro_f1s, k1

    def get_loss(self, logits):
        """
        :param logits: [2, n_nodes]
        """
        n_nodes = logits.shape[1]
        lbl_1 = torch.ones(n_nodes)
        lbl_2 = torch.zeros(n_nodes)
        lbl = torch.stack((lbl_1, lbl_2))

        lbl = lbl.to(self.args.device)
        loss = self.criteria(logits, lbl)
        return loss

class modeler(nn.Module):
    def __init__(self, ft_size, hid_units):
        super(modeler, self).__init__()
        self.gcn = GCN(ft_size, hid_units)
        self.disc = InterDiscriminator(hid_units, ft_size)

    def forward(self, seq1, seq2, adj, sparse):
        # real
        h_1 = torch.squeeze(self.gcn(seq1, adj, sparse))
        c = torch.squeeze(torch.mean(h_1, 0))  # readout

        # negative
        h_2 = torch.squeeze(self.gcn(seq2, adj, sparse))

        # discriminator
        ret = self.disc(c, h_1, h_2, seq1, seq2)
        return ret

    # Detach the return variables
    def embed(self, seq, adj, sparse):
        h_1 = torch.squeeze(self.gcn(seq, adj, sparse))
        return h_1.detach()


import io
import requests

def grower_export(conn, date, organization_id, ckan_config):
    """Prints a message with the current time"""
    print("capture_export...")
    # check yearMonth (yyyy-mm) format with regex
    import re
    if not re.match(r'^\d{4}-\d{2}-\d{2}$', date):
      msg = f'date format error {date}';
      raise ValueError(msg)

    # check organization_id is int
    if not isinstance(organization_id, int):
      msg = f'organization_id must be int';
      raise ValueError(msg)

    import datetime
    # create a new file called 'temp.csv' in the current directory
    # date = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M")
    file_name = f'grower_{datetime.datetime.now().strftime("%Y-%m-%d-%H-%M")}.csv'

    # check if the resource are already in the CKAN
    # get the resource list from CKAN
   # get the resource list from CKAN
    url = f"{ckan_config['CKAN_DOMAIN']}/api/3/action/package_show?id={ckan_config['CKAN_DATASET_NAME_GROWER_DATA']}"
    print("url:", url)
    response = requests.get(url,
        headers={"X-CKAN-API-Key": ckan_config['CKAN_API_KEY']}
    )
    print ('response:', response)
    # throw an error if the resource is not found
    package_data = response.json()
    # print('pacage data:', package_data)
    id = package_data['result']['id']
    # e.g. 75aeeb9c-f671-408b-8b08-f24ec0edefb0
    # using Regex to check if the id is in the format of UUID
    import re
    if not re.match(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', id):
        raise ValueError('id format error:', id)
    resources = package_data['result']['resources']
    # go through the resource list
    for resource in resources:
        # check if the resource is already in the CKAN
        if resource['name'] == file_name:
            print('resource already in the CKAN')
            raise ValueError(f'resource {file_name} already in the CKAN')

    # create cursor
    cur = conn.cursor()
    # array of file names
    columns = ["id","first_name","last_name","email","phone","image_url", "registed_at"]
    sql = f"""
SELECT
  p.id,
  p.first_name,
  p.last_name,
  p.email,
  p.phone,
  p.image_url,
  created_at as registed_at
FROM
  planter p
LEFT JOIN
  planter_registrations pr
ON pr.planter_id = p.id
WHERE
  pr.created_at < '{date}'
  AND p.organization_id IN (
    select entity_id from getEntityRelationshipChildren({organization_id})
  )
ORDER BY p.id DESC
LIMIT 20;
        """;

    print("SQL:", sql)
    # execute query
    cur.execute(sql)
    # fetch all rows
    rows = cur.fetchall()
    lines = [','.join(columns)]
    # print rows
    print ("rows len:", len(rows))
    for row in rows:
        # join row elements with comma
        line = ",".join(str(v) for v in row)
        # add line to lines
        lines.append(line)
    print ("lines length:", len(lines))
    # close connection
    conn.close()

    print ("upload file")
    import urllib.request as urllib2
    import urllib
    import json
    import pprint
    import datetime

    try:
        # convert lines to file like object
        f = io.StringIO("\n".join(lines))
        url = f"{ckan_config['CKAN_DOMAIN']}/api/action/resource_create"
        print("url:", url)
        r = requests.post(url,
            data={
                "package_id": id,
                "url": "http://test.com/sample.csv",
                "name": file_name,
                'description': 'export grower data',
                'format': 'csv',
                'url_type': 'upload',
                'resource_type': 'file.upload',
                'mimetype': 'text/csv',
                'hash': '',
                'size': 0,
                'cache_url': '',
                'cache_last_updated': None,
                'webstore_last_updated': None,
                'webstore_url': None,
              },
            headers={"X-CKAN-API-Key": ckan_config['CKAN_API_KEY']},
            files={'upload': (file_name, f)}
            # files={'report.xls': f}
        )
        # read responce from server
        print ("r:", r)
        print ("r.text:", r.text)
    except urllib2.HTTPError as e:
        print('Error code: {0}'.format(e.code))
        print(e.read())
        raise e
    return "Done"


import gym
from gym import spaces
import pandas as pd
from IPython.display import display
from IPython.display import clear_output
import numpy as np
from loc import Location

class HunterWorldEnv(gym.Env):

    def __init__(self, agent, target, size=10, n_border=20, agent_locs=[]):
        self.size = size
        self.agent = agent
        self.target = target
        self.observation_space = spaces.Dict(
            {
                "agent": spaces.Box(0, np.array([size - 1, size - 1, 1]), dtype=int),
                "target": spaces.Box(0, size - 1, shape=(2,), dtype=int),
            }
        )
        self.action_space = spaces.Discrete(5)
        self._action_to_direction = {
            0: np.array([1, 0]),
            1: np.array([0, 1]),
            2: np.array([-1, 0]),
            3: np.array([0, -1]),
        }
        self.borders = self.create_borders(n_border, size, agent_locs)

    def create_borders(self, n, size, agent_locs):
        borders = []
        for i in range(n):
            loc = Location(np.random.randint(size), np.random.randint(size))
            while loc == self.agent.location or loc == self.target.location or loc in self.target.route or loc in agent_locs:
                loc = Location(np.random.randint(size), np.random.randint(size))
            borders.append(loc)
        return borders

    def _get_obs(self):
        agent = self.agent.get_state()
        target = self.target.get_state()
        desk = np.zeros((1, self.size + 2, self.size + 2))
        desk[0] = np.pad(self.render(), 1, constant_values=-1)
        obs = desk[:, self.agent.location.y:self.agent.location.y + 3,
                      self.agent.location.x:self.agent.location.x + 3]
        return {"agent": agent,
                "target": target,
                "state_bse": np.concatenate([agent, target]),
                "state_net": obs}

    def _get_info(self):
        return {"distance": self.agent.location.dist(self.target.location)}

    def reset(self):
        self.agent.reset()
        self.target.reset()
        observation = self._get_obs()
        info = self._get_info()
        return observation, info

    def step(self, action):
        if action == 4:
            if self.agent.location == self.target.location and self.agent.purpose == 0:
                if self.agent.attack > self.target.escape:
                    self.agent.purpose = 1
                    self.target.update()
                    return self._get_obs(), 1000, False, self._get_info()
                self.agent.attack += 0.1
                self.target.run()
                return self._get_obs(), 1000, False, self._get_info()
            return self._get_obs(), -500, False, self._get_info()

        direction = self._action_to_direction[action]
        new_loc = np.clip(self.agent.location.toNumpy() + direction, 0, self.size - 1)
        new_loc = Location(new_loc[1], new_loc[0])
        if new_loc not in self.borders:
            self.agent.location = new_loc

        observation = self._get_obs()
        info = self._get_info()
        reward = -info['distance']

        if self.agent.location == self.target.location and self.agent.purpose == 1:
            return observation, 1000, True, info

        return observation, reward, False, info

    def print(self):
        clear_output(wait=True)

        def cell_color(val):
            color = 'white'
            if val == 'A':
                color = 'blue'
            if val == 'T':
                color = 'green'
            if val == 'X':
                color = 'red'
            if val == 'O':
                color = 'yellow'
            if val == 'B':
                color = 'black'
            return 'color: %s' % color

        n = self.size
        desk = np.full((n, n), '.').astype(str)
        desk[self.agent.location.y, self.agent.location.x] = 'A'
        desk[self.target.location.y, self.target.location.x] = 'T' if self.agent.purpose == 0 else 'O'
        if self.agent.location == self.target.location and self.agent.purpose == 0:
            desk[self.agent.location.y, self.agent.location.x] = 'X'
        for border in self.borders:
            desk[border.y, border.x] = 'B'
        display(pd.DataFrame(desk).style.applymap(cell_color))

    def render(self):
        n = self.size
        desk = np.full((n, n), 0).astype(int)
        desk[self.agent.location.y, self.agent.location.x] = 1
        desk[self.target.location.y, self.target.location.x] = 2 if self.agent.purpose == 0 else 3
        if self.agent.location == self.target.location and self.agent.purpose == 0:
            desk[self.agent.location.y, self.agent.location.x] = 4
        for border in self.borders:
            desk[border.y, border.x] = 5
        return desk


from random import uniform
import numpy as np
import numba

"""
REFs:    M. Hopfensitz et al., "Multiscale Binarization of Gene Expression Data for Reconstructing Boolean Networks,"
        in IEEE/ACM Transactions on Computational Biology and Bioinformatics, vol. 9, no. 2, pp. 487-498, March-April 2012,
        doi: 10.1109/TCBB.2011.62.

        https://github.com/cran/Binarize/blob/master/src/binarizeBASCA.c    Author: Stefan Mundus
        https://github.com/cran/Binarize/blob/master/src/common.c           Author: Stefan Mundus

Algorithm to binarize a vector.
Steps:
    1. Compute a series of step functions (each function minimizes the eucledian distance between the new step function and the original data)
    2. Find strongest discontinuity in each step function
    3. Estimate location and variation of the strongest discontinuities
"""

"""
HELPER FUNCTIONS:
"""

@numba.jit(nopython=True)
def cost_ab(vect, a, b):
    """
    Calculates quadratic distance between original data points and mean of data points in range a to b inclusive
    """
    Yab = np.mean(vect[a:b + 1])
    # + 1 because we want to calculate the sum from a to b, with b inclusive
    return np.sum(((vect - Yab)**2)[a:b+1])

@numba.jit(nopython=True)
def init_cost_matrix(vect):
    N = len(vect)
    C = np.zeros( (N - 1, N), dtype = 'float64')
    C[0] = [cost_ab(vect, i, N-1) for i in range(0, N - 1 + 1)]
    return C

@numba.jit(nopython=True)
def calc_jump_height(vect, P, i, j):
    """
    Calculate jump height/size between data point Pij and Pij + 1, with P the matrix containing location of discontinuities.
    """
    N = len(vect) - 1
    if i == 0 and j > 0:
        return np.mean( vect[P[j, i] + 1:  P[j, i + 1] + 1] ) - np.mean( vect[0: P[j, i] +1] )
    elif i == j > 0:
        return np.mean( vect[P[j, i] + 1: N+1] ) - np.mean( vect[ P[j, i - 1] + 1: P[j, i] + 1] )
    elif i == j == 0:
        return np.mean(vect[  P[j, i] + 1: N +1 ]) - np.mean( vect[0: P[j, i]+1 ] )
    else:
        return np.mean(vect[P[j, i] + 1: P[j, i + 1] + 1]) - np.mean(vect[P[j, i - 1] + 1: P[j, i] + 1])

@numba.jit(nopython=True)
def calc_error(vect, P, i, j):
    """
    Calculate approximation error of a threshold at the discontinuity with respect to the original data
    This is the sum of the quadratic distances of all data points to the threshold z defined by the i-th discontinuity
    """
    N = len(vect)
    z = (vect[P[j, i]] + vect[P[j, i] + 1]) / 2
    return np.sum(((vect - z)**2)[0: N])

@numba.jit(nopython=True)
def moving_block_bootstrap(v):
    N = len(v)
    bootstrappedValues = np.zeros( (N), dtype = 'float64')
    bl = round(N**0.25) + 1
    sample_count = np.ceil(N / bl)
    m = N - bl

    index = 0

    for i in range(0, sample_count):
        rand = round(uniform(-0.5, m + 0.5))
        rand = rand if rand <= m else m

        for j in range(0, bl):
            if index >= N:
                break
            bootstrappedValues[index] = v[rand + j]
            index += 1
    return bootstrappedValues

@numba.jit(nopython=True)
def norm_dev_median(v, vect):
    N = len(vect)
    median_val = np.floor(np.median(v))
    dev = np.abs(v - median_val)
    mean_val = np.mean(dev)
    return mean_val/(N-1)

"""
MAIN FUNCTIONS
"""

@numba.jit(nopython=True)
def calc_cost_and_ind_matrix(vect):
    """
    Calculates the matrix C and ind
        C stores the cost of a step function having j intermediate (rows) discontinuities between data points i and N (columns)
        ind contains indicices of optimal break points of all step functions
    """
    N = len(vect)
    C = init_cost_matrix(vect)
    ind = np.zeros( (N - 2, N), dtype = 'int64')
    for j in range(1, N - 2 + 1):
        for i in range(0, N - j):
            cost_min = np.inf
            d_min = -1
            for d in range(i, N - j):
                cost = cost_ab(vect, i, d) + C[j - 1, d + 1]
                if cost < cost_min:
                    cost_min = cost
                    d_min = d
            C[j, i] = cost_min
            ind[j-1, i] = d_min
    return C, ind

@numba.jit(nopython=True)
def calc_P_matrix(ind):
    """
    Converts ind matrix from calc_cost_and_ind_matrix to a matrix with rows representing the number of discontinuities (1-based) and as values the location of the i-th ()
    """

    P = np.zeros( (len(ind), len(ind[0])), dtype = 'int64')
    for j in range(0, len(ind)):
        z = j
        P[j, 0] = ind[z, 0]
        if j > 0:
            z = z - 1
            for i in range(1, j + 1):
                P[j, i] = ind[z, int(P[j, i - 1]) + 1]
                z = z - 1
    return P

@numba.jit(nopython=True)
def calc_scores(vect, P):
    """
    Calculate the score of al step function discontinuities in P
    This score is the jump height divided by the approximation error
    """

    Q = np.zeros( (len(P), len(P[0])), dtype = 'float64')  # stores scores for each discontinuity
    # stores the score of the discontinuity with the maximum score for each step function
    Q_max = np.zeros( (len(P)), dtype = 'float64')
    # stores the index of the discontinuity with the maximum score for each step function
    ind_Q_max = np.zeros( (len(P)), dtype = 'int64')

    for j in range(0, len(P)):
        q_max = -1
        ind_q_max = -1
        for i in range(0, j + 1):
            # calculate jump height
            h = calc_jump_height(vect, P, i, j)
            e = calc_error(vect, P, i, j)
            q = h/e
            if q > q_max:
                q_max = q
                ind_q_max = P[j, i]
            Q[j, i] = q
        Q_max[j] = q_max
        ind_Q_max[j] = ind_q_max
    return Q, Q_max, ind_Q_max

@numba.jit(nopython=True)
def calc_threshold(vect, v):
    v_med = int(np.floor(np.median(v)))
    return (vect[v_med + 1] + vect[v_med]) / 2

@numba.jit(nopython=True)
def calc_P(v, vect, tau, n_samples):
    nom = norm_dev_median(v, vect)
    t_zero = tau - nom

    p = 1

    for i in range(0, n_samples):
        samples = moving_block_bootstrap(v)
        mdm = norm_dev_median(samples, vect)
        t_star = nom - mdm
        p += (t_star >= t_zero) * 1

    p /= (n_samples + 1)

    return p

@numba.jit(nopython=True)
def binarize(vect, tau=0.01, n_samples=999, calc_p=True, max_elements=100):
    # original step function is just the sorted vector
    vect_sorted = np.sort(vect)

    # if vector is too long, only use top features (scalability)
    if len(vect_sorted) > max_elements:
        vect_sorted = vect_sorted[0:max_elements]

    # step 1: Compute a series of step functions (each function minimizes the eucledian distance between the new step function and the original data)
    _, ind = calc_cost_and_ind_matrix(vect_sorted)
    P = calc_P_matrix(ind)

    # step 2: Find strongest discontinuity in each step function
    Q, _, v = calc_scores(vect_sorted, P)

    # step 3: Estimate location and variation of the strongest discontinuities
    threshold = calc_threshold(vect_sorted, v)
    #p_val = calc_P(v, vect_sorted, tau, n_samples) if calc_p else None

    binarized_measurements = [(val > threshold) * 1 for val in vect]

    return threshold, binarized_measurements


import math

from astropy import units as u
from speclite.filters import load_filter

import galcheat

SPECLITE_SURVEY_PREFIXES = {
    "DES": "decam2014",
    "Euclid_VIS": "Euclid",
    "HSC": "hsc2017",
    "LSST": "lsst2016",
}

def compute_zeropoint_mag(band_name, effective_area, exposure_time=1 * u.s):
    """Compute the zeropoint of a given filter with speclite"""
    speclite_filter = load_filter(band_name)
    zeropoint_counts = (
        speclite_filter.ab_zeropoint * effective_area * exposure_time
    ).decompose()
    zeropoint_mag = 2.5 * math.log10(zeropoint_counts) * u.mag
    return zeropoint_mag

def check_zeropoints(survey_name):
    """
    Compute the zeropoints with speclite and compare with current values

    Parameters
    ----------
    survey_name : str
        Name of the survey

    """
    if survey_name in SPECLITE_SURVEY_PREFIXES.keys():
        survey = galcheat.get_survey(survey_name)
        speclite_prefix = SPECLITE_SURVEY_PREFIXES[survey_name]

        print(f"-- {survey_name} --\t({speclite_prefix} in speclite)\n")
        print("filters |  speclite |  galcheat")
        print("------- | --------- | ---------")

        for filter_name in survey.available_filters:
            if filter_name == "IE":
                old_filter_name = "VIS"
            else:
                old_filter_name = filter_name
            speclite_filter_name = f"{speclite_prefix}-{old_filter_name}"
            speclite_zp = compute_zeropoint_mag(
                speclite_filter_name, survey.effective_area
            )

            galcheat_filter = survey.get_filter(filter_name)
            current_zp = galcheat_filter.zeropoint
            print(f"{filter_name:^7} | {speclite_zp:.2f} | {current_zp:.2f}")
    else:
        print(f"{survey_name} filters are not available in speclite")
    print("\n")

if __name__ == "__main__":
    print("\nChecking the zeropoints with speclite")
    print("-------------------------------------\n")
    for survey_name in galcheat.available_surveys:
        check_zeropoints(survey_name)


from neural_network import create_model_cnn
from neural_network import predict
from neural_network import cluster_data
from neural_network import create_scatter_plot
from spectrogram_creation import load_audio
from spectrogram_creation import get_spectrogram
import numpy as np

import sys
import os
import joblib
import pickle
import matplotlib.pyplot as plt
import random

def save_model_cnn(model, model_path):
    # Save the model to disk
    sys.stdout = open('NUL', 'w')
    joblib.dump(model, model_path)
    sys.stdout = sys.__stdout__

def load_model_cnn(model_path):
    print("Loading Model CNN...")
    # Load the model from disk
    sys.stdout = open('NUL', 'w')
    model = joblib.load(model_path)
    sys.stdout = sys.__stdout__
    print("Done!")

    return model

def create_and_save_predictions(filename:str):
    features_no = predict_all_in_directory('./data/no', './data/no/myvoice', 'no', 'dense_layer')
    features_yes = predict_all_in_directory('./data/yes', './data/yes/myvoice', 'yes', 'dense_layer')
    features = {**features_no, **features_yes}
    #print(features["0a9f9af7_nohash_0.wav"])

    # Save the dictionary to the file
    with open(filename, 'wb') as f:
        pickle.dump(features, f)
    return features

def load_predictions(filename:str):
    print("Loading Predictions...")
    # Load the dictionary from the file
    with open(filename, 'rb') as f:
        features = pickle.load(f)
    print("Done!")
    return features

def predict_by_wav(audio_path:str, img_path:str, output_layer=None):
    waveform, sample_rate = load_audio(audio_path)
    spectrogram, spect = get_spectrogram(waveform)

    plt.imsave(img_path, spectrogram.numpy(), cmap='gray')

    prediction = predict(model, img_path, output_layer)

    return prediction

def predict_all_in_directory(input_directory, output_directory, prefix:str, output_layer=None):
    # Make sure the output directory exists
    os.makedirs(output_directory, exist_ok=True)

    features = {}

    count = 0
    max_files = 100

    # Loop over all files in the input directory
    for filename in os.listdir(input_directory):
        # Ignore any files that aren't wav files
        if not filename.endswith('.wav'):
            continue

        # Construct the input and output file paths
        input_path = os.path.join(input_directory, filename)
        output_path = os.path.join(output_directory, f'{prefix}_{os.path.splitext(filename)[0]}.png')

        # Call the predict_by_wav function
        prediction = predict_by_wav(input_path, output_path, output_layer)
        features[prefix + "_" + filename] = prediction

        count += 1
        if max_files is not None and count >= max_files:
            break

    return features

# MAIN METHOD
if __name__ == '__main__':

    createCNN = True
    doPrediction = True
    doClustering = True

    model_path = 'model.joblib'

    # Step 0: PreProcess Data

    # Step 1: Create/Load the Convolutional Neural Network
    if (createCNN):
        # Create Model and save it
        model = create_model_cnn()
        save_model_cnn(model, model_path)
    else:
        # Load Model
        model = load_model_cnn(model_path)

    return

    # Step 2: Extract Features out of CNN for Clustering
    if (doPrediction):
        # Create Predictions and save them
        features = create_and_save_predictions("features.pickle")
    else:
        # Load Predictions
        features = load_predictions("features.pickle")
    # Get a random key from the dictionary
    random_key = random.choice(list(features.keys()))
    print(features[random_key])

    # Dictionary to List of values
    features = list(features.values())
    # Convert the features to a NumPy array
    features = np.array(features)
    # Reshape the array to have 2 dimensions
    features = features.reshape(features.shape[0], -1)

    # Step 3: Cluster Data
    if (doClustering):
        # Cluster Data
        cluster_data(features, 2)
        print("")
    else:
        # Load Model
        print("")


import os, builtins

from io import BytesIO
from typing import BinaryIO
from PIL import Image, CurImagePlugin
from PIL._binary import o8
from PIL._binary import o16le as o16
from PIL._binary import o32le as o32

_MAGIC_CUR = b"\0\0\2\0"

def _save_cur(im, fp, filename):
    fp.write(_MAGIC_CUR)  # (2+2)
    width, height = im.size

    hotspot = im.encoderinfo.get(
        "hotspot",
        (0, 0),
    )
    hotspotX = hotspot[0] / width
    hotspotY = hotspot[1] / height

    sizes = im.encoderinfo.get(
        "sizes",
        [(32, 32), (48, 48), (64, 64), (96, 96), (128, 128), (256, 256)],
    )
    frames = []
    for size in sorted(set(sizes)):
        if size[0] > width or size[1] > height or size[0] > 256 or size[1] > 256:
            continue

        if im.size == size:
            frames.append(im)
        else:
            # TODO: invent a more convenient method for proportional scalings
            frame = im.copy()
            frame.thumbnail(size, Image.Resampling.LANCZOS, reducing_gap=None)
            frames.append(frame)
    fp.write(o16(len(frames)))  # idCount(2)
    offset = fp.tell() + len(frames) * 16
    for frame in frames:
        width, height = frame.size
        # 0 means 256
        fp.write(o8(width if width < 256 else 0))  # bWidth(1)
        fp.write(o8(height if height < 256 else 0))  # bHeight(1)

        fp.write(b"\0")  # bColorCount(1)
        fp.write(b"\0")  # bReserved(1)

        fp.write(o16(round(hotspotX * width)))  # hotspotHorizontal(2)
        fp.write(o16(round(hotspotY * height)))  # hotspotVertical(2)

        image_io = BytesIO()
        frame.save(image_io, "png")
        image_io.seek(0)
        image_bytes = image_io.read()
        bytes_len = len(image_bytes)
        fp.write(o32(bytes_len))  # dwBytesInRes(4)
        fp.write(o32(offset))  # dwImageOffset(4)
        current = fp.tell()
        fp.seek(offset)
        fp.write(image_bytes)
        offset = offset + bytes_len
        fp.seek(current)

Image.register_save(CurImagePlugin.CurImageFile.format, _save_cur)

def _save_ani(fp: BinaryIO, frames, seconds_per_frame: float, hotspot):
    # RIFF struct
    fp.write(b"RIFF") # ID(4)
    riff_size_offset = fp.tell()
    fp.write(o32(0)) # headerSize(4)
    fp.write(b"ACON") # headerID(4)

    # 'anih' chunk
    fp.write(b"anih") # chunkHeader(4)
    fp.write(o32(36)) # chunkHeaderSize(4)

    fp.write(o32(36)) # headerSize(4)
    fp.write(o32(len(frames))) # numFrames(4)
    fp.write(o32(len(frames))) # numSteps(4)
    fp.write(o32(0)) # width(4)
    fp.write(o32(0)) # height(4)
    fp.write(o32(0)) # bitCount(4)
    fp.write(o32(0)) # numPlanes(4)
    fp.write(o32(round(seconds_per_frame * 60))) # displayRate(4)
    fp.write(o32(1)) # flags(4)

    # LIST struct
    fp.write(b"LIST") # ID(4)
    list_size_offset = fp.tell()
    fp.write(o32(0)) # headerSize(4)
    fp.write(b"fram") # headerID(4)

    for frame in frames:
        # 'icon' chunk
        image_io = BytesIO()
        frame.save(image_io, "cur", hotspot=hotspot)
        image_io.seek(0)
        image_bytes = image_io.read()

        fp.write(b"icon") # chunkHeader(4)
        fp.write(o32(len(image_bytes))) # chunkHeaderSize(4)
        fp.write(image_bytes)

        # padding
        if fp.tell() & 1:
            fp.write(o8(0))

    current = fp.tell()

    list_size = current - (list_size_offset + 4)
    fp.seek(list_size_offset)
    fp.write(o32(list_size))

    riff_size = current - (riff_size_offset + 4)
    fp.seek(riff_size_offset)
    fp.write(o32(riff_size))

def save_ani(filename, frames, seconds_per_frame: float, hotspot=(0,0)):
    created = not os.path.exists(filename)
    fp = builtins.open(filename, "w+b")
    try:
        _save_ani(fp, frames, seconds_per_frame, hotspot)
    except Exception:
        fp.close()
        if created:
            try:
                os.remove(filename)
            except PermissionError:
                pass
        raise
    fp.close()


import tweepy
from textblob import TextBlob
import pandas as pd
import numpy as np
import re
import matplotlib.pyplot as plt
import sys
plt.style.use('fivethirtyeight')

api_key = ""
api_secret_key = ""
access_token = ""
access_token_secret = ""

auth_handler = tweepy.OAuthHandler(consumer_key = api_key, consumer_secret = api_secret_key)
auth_handler.set_access_token(access_token, access_token_secret)

api = tweepy.API(auth_handler)

search_term = "Google"
tweet_amount = 100

tweets = tweepy.Cursor(api.search, q=search_term, lang='en').items(tweet_amount)

polarity = 0

for tweet in tweets:
    final_text = tweet.text.replace('RT', '')
    if final_text.startswith(' @'):
        position = final_text.index(':')
        final_text = final_text[position+2:]
    if final_text.startswith('@'):
        position = final_text.index(' ')
        final_text = final_text[position+2]
    analysis = TextBlob(final_text)
    polarity += analysis.polarity

print(polarity)


from typing import List

class Solution:
    def rankTeams(self, votes: List[str]) -> str:
        count = { v: [0] * len(votes[0]) + [v] for v in votes[0] }

        for vote in votes:
            for i, v in enumerate(vote):
                count[v][i] -= 1

        return ''.join(sorted(votes[0], key=count.get))

def main():
    sol = Solution()
    print(sol.rankTeams(["FVSHJIEMNGYPTQOURLWCZKAX","AITFQORCEHPVJMXGKSLNZWUY","OTERVXFZUMHNIYSCQAWGPKJL",
                         "VMSERIJYLZNWCPQTOKFUHAXG","VNHOZWKQCEFYPSGLAMXJIUTR","ANPHQIJMXCWOSKTYGULFVERZ",
                         "RFYUXJEWCKQOMGATHZVILNSP","SCPYUMQJTVEXKRNLIOWGHAFZ","VIKTSJCEYQGLOMPZWAHFXURN",
                         "SVJICLXKHQZTFWNPYRGMEUAO","JRCTHYKIGSXPOZLUQAVNEWFM","NGMSWJITREHFZVQCUKXYAPOL",
                         "WUXJOQKGNSYLHEZAFIPMRCVT","PKYQIOLXFCRGHZNAMJVUTWES","FERSGNMJVZXWAYLIKCPUQHTO",
                         "HPLRIUQMTSGYJVAXWNOCZEKF","JUVWPTEGCOFYSKXNRMHQALIZ","MWPIAZCNSLEYRTHFKQXUOVGJ",
                         "EZXLUNFVCMORSIWKTYHJAQPG","HRQNLTKJFIEGMCSXAZPYOVUW","LOHXVYGWRIJMCPSQENUAKTZF",
                         "XKUTWPRGHOAQFLVYMJSNEIZC","WTCRQMVKPHOSLGAXZUEFYNJI"]))
    print(sol.rankTeams(["BCA","CAB","CBA","ABC","ACB","BAC"]))
    print(sol.rankTeams(["ABC","ACB","ABC","ACB","ACB"]))
    print(sol.rankTeams(["WXYZ","XYZW"]))
    print(sol.rankTeams(["ZMNAGUEDSJYLBOPHRQICWFXTVK"]))

if __name__ == '__main__':
    main()


# https://www.hackerrank.com/challenges/itertools-product/problem

from itertools import product

a = list(input().split()) # [int(x) for x in input().split()]
num1 = [int(i) for i in a] #
b = list(input().split())
num2 = [int(i) for i in b]
c=list(product(num1,num2))
print(*c)


# @Time : 2022-10-02 10:53
# @Author : Phalange
# @File : 6193. 沙漏的最大总和.py
# @Software: PyCharm
# C'est la vie,enjoy it! :D
from typing import List

class Solution:
    def maxSum(self, grid: List[List[int]]) -> int:
        ans = 0
        m = len(grid)
        n = len(grid[0])
        for i in range(0,m-2):
            for j in range(0,n-2):
                tmp = sum(sum(rows[j:j+3]) for rows in grid[i:i+3]) - grid[i+1][j] - grid[i+1][j+2]
                ans = max(tmp,ans)

        return ans

grid = [[6,2,1,3],[4,2,1,5],[9,2,8,7],[4,1,2,9]]
print(Solution().maxSum(grid))


import errno
import json
import os

import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import scipy.misc
from scipy.ndimage import rotate
from scipy.stats import bernoulli

# Some useful constants
DRIVING_LOG_FILE = './ex_data/driving_log.csv'
IMG_PATH = './ex_data/'
STEERING_COEFFICIENT = 0.229

def crop(image, top_percent, bottom_percent):
    assert 0 <= top_percent < 0.5, 'top_percent should be between 0.0 and 0.5'
    assert 0 <= bottom_percent < 0.5, 'top_percent should be between 0.0 and 0.5'

    top = int(np.ceil(image.shape[0] * top_percent))
    bottom = image.shape[0] - int(np.ceil(image.shape[0] * bottom_percent))

    return image[top:bottom, :]

def resize(image, new_dim):
    return scipy.misc.imresize(image, new_dim)

def random_flip(image, steering_angle, flipping_prob=0.5):
    head = bernoulli.rvs(flipping_prob)
    if head:
        return np.fliplr(image), -1 * steering_angle
    else:
        return image, steering_angle

def random_gamma(image):
    gamma = np.random.uniform(0.4, 1.5)
    inv_gamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** inv_gamma) * 255
                      for i in np.arange(0, 256)]).astype("uint8")

    # apply gamma correction using the lookup table
    return cv2.LUT(image, table)

def random_shear(image, steering_angle, shear_range=200):
    rows, cols, ch = image.shape
    dx = np.random.randint(-shear_range, shear_range + 1)
    random_point = [cols / 2 + dx, rows / 2]
    pts1 = np.float32([[0, rows], [cols, rows], [cols / 2, rows / 2]])
    pts2 = np.float32([[0, rows], [cols, rows], random_point])
    dsteering = dx / (rows / 2) * 360 / (2 * np.pi * 25.0) / 6.0
    M = cv2.getAffineTransform(pts1, pts2)
    image = cv2.warpAffine(image, M, (cols, rows), borderMode=1)
    steering_angle += dsteering

    return image, steering_angle

def random_rotation(image, steering_angle, rotation_amount=15):
    angle = np.random.uniform(-rotation_amount, rotation_amount + 1)
    rad = (np.pi / 180.0) * angle
    return rotate(image, angle, reshape=False), steering_angle + (-1) * rad

def generate_new_image(image, steering_angle, top_crop_percent=0.35, bottom_crop_percent=0.1,
                       resize_dim=(64, 64), do_shear_prob=0.9):
    side = bernoulli.rvs(do_shear_prob)
    if side == 1:
        image, steering_angle = random_shear(image, steering_angle)

    image = crop(image, top_crop_percent, bottom_crop_percent)

    image, steering_angle = random_flip(image, steering_angle)

    image = random_gamma(image)

    image = resize(image, resize_dim)

    return image, steering_angle

def get_next_image_files(batch_size=128):
    data = pd.read_csv(DRIVING_LOG_FILE)
    num_of_img = len(data)
    rnd_indices = np.random.randint(0, num_of_img, batch_size)

    image_files_and_angles = []
    for index in rnd_indices:
        rnd_image = np.random.randint(0, 3)
        if rnd_image == 0:
            img = data.iloc[index]['left'].strip()
            angle = data.iloc[index]['steering'] + STEERING_COEFFICIENT
            image_files_and_angles.append((img, angle))

        elif rnd_image == 1:
            img = data.iloc[index]['center'].strip()
            angle = data.iloc[index]['steering']
            image_files_and_angles.append((img, angle))
        else:
            img = data.iloc[index]['right'].strip()
            angle = data.iloc[index]['steering'] - STEERING_COEFFICIENT
            image_files_and_angles.append((img, angle))

    return image_files_and_angles

def generate_next_batch(batch_size=128):
    while True:
        X_batch = []
        y_batch = []
        images = get_next_image_files(batch_size)
        for img_file, angle in images:
            raw_image = plt.imread(IMG_PATH + img_file)
            raw_angle = angle
            new_image, new_angle = generate_new_image(raw_image, raw_angle)
            X_batch.append(new_image)
            y_batch.append(new_angle)

        assert len(X_batch) == batch_size, 'len(X_batch) == batch_size should be True'

        yield np.array(X_batch), np.array(y_batch)


# ライブラリのインポート
import streamlit as st
from PIL import Image

#サイドバーに表示させる
st.sidebar.header('画像から文字起こし')
# ファイルアップロード
upload_file = st.sidebar.file_uploader('↓ファイルをアップロードしてください',type=['png', 'jpg', 'gif', 'jpeg'])

# メイン画面
if upload_file is not None:
    image = Image.open(upload_file).convert('RGB')
    # st.write(image.width)
    # st.write(image.height)
    # st.image(image, use_column_width=True)

    # 画像サイズを格納
    lower = image.width
    upper = image.height

    # サイドバーに追加
    #  # 読み取り範囲の指定
    st.sidebar.write('↓画像の読み取り範囲を指定してください')
    # x座標（横軸）
    x1, x2 = st.sidebar.slider('横軸', 0.0, float(lower), (10.0, float(lower-10.0)))
    st.sidebar.write('左,右:',(x1, x2))
    # y座標（縦軸）
    y1, y2 = st.sidebar.slider('縦軸', 0.0, float(upper), (10.0, float(upper-10.0)))
    st.sidebar.write('上,下:',(y1, y2))

    image_crop = image.crop((x1, y1, x2, y2)).resize((1024,768))
    image_crop.save('sample.png')
    # st.write(image_crop.width)
    # st.write(image_crop.height)
    st.image(image_crop, use_column_width=True)

    # VISION API
    # サイドバーにボタンを追加
    if st.sidebar.button('文字起こし！'):

        #モジュールのインポート
        from google.cloud import vision
        from google.oauth2 import service_account
        # jsonの読み込み
        credentials = service_account.Credentials.from_service_account_info(st.secrets["gcp_service_account"])
        client = vision.ImageAnnotatorClient(credentials=credentials)

        # 画像の読み込み
        with open('sample.png', 'rb') as image_file:
            content = image_file.read()
            v_image = vision.Image(content=content)
            response = client.document_text_detection(image=v_image)
            texts = response.full_text_annotation.text
            st.write(texts)


from tencentcloud.ess.v20201111.models import CreateFlowSignReviewRequest, UserInfo

from api.common import get_client_instance
from config import Config

def create_flow_sign_review(operator_user_id, flow_id, review_type, review_message):

    # 构造客户端调用实例
    client = get_client_instance(
        Config.secret_id,
        Config.secret_key,
        Config.endpoint)

    # 构造请求体
    req = CreateFlowSignReviewRequest()

    # 调用方用户信息，参考通用结构
    user_info = UserInfo()
    user_info.UserId = operator_user_id
    req.Operator = user_info

    req.FlowId = flow_id

    req.ReviewType = review_type

    req.ReviewMessage = review_message

    response = client.CreateFlowSignReview(req)
    return response

if __name__ == '__main__':
    """
    提交企业签署流程审批结果调用样例
    """

    try:
        _flow_id = '********************************'

        _review_type = '********************************'

        _review_message = '********************************'

        resp = create_flow_sign_review(Config.operator_user_id, _flow_id, _review_type, _review_message)
        print(resp)
    except Exception as e:
        print(e)


#   Nome: Pedro Victor Rodrigues de Carvalho
#   Matrícula: 17/0113043
#   Universidade de Brasília, 2º semestre de 2018
#   Curso: Engenharia de Computação
#   Matéria: Introdução ao Processamento de Imagens
#   Professor: Alexandre Zaghetto

#   Segunda parte do Assignment 1: Rotulação de componentes conectados em imagem binária
#   Linguagem de programação: Python 3

import cv2
import numpy as np

# --------------------
#   Start of functions

#   The placeNewLabel function simply gives a new value to a position in the label matrix.
def placeNewLabel(matrix, x, y, value):
    matrix[x, y] = value

#       The placeExistingLabel function uses a string its caller supplies as a directive to which neighbour's label
#   should be placed in the current pixel.
def placeExistingLabel(matrix, x, y, string):
    if string == "left":
        matrix[x, y] = matrix[x - 1, y]
    else:
        matrix[x, y] = matrix[x, y - 1]

#       The compareTopLeftLabel function tests if the top and the left neighbours' labels are equal and returns
#   accordingly.
def compareTopLeftLabel(matrix, x, y):
    if matrix[x - 1, y] != matrix[x, y - 1]:
        return 1
    else:
        return 0

#   The establishLabelEquivalence function saves a determined equivalence in an array for future reference.
def establishLabelEquivalence(matrix, x, y, equivalences):
    value1 = matrix[x, y]  # Preference for smaller values of labels.
    value2 = matrix[x, y - 1]
    if value1 < value2:
        equivalences[value2] = value1
    else:
        equivalences[value1] = value2

#      The countsArrayElements function simply counts how many elements in the supplied array are bigger than zero and
#   returns the number of elements found.
def countsArrayElements(array):
    counter = 0
    for i in range(0, array.__len__()):
        if array[i] > 0:
            counter += 1
    return counter

#   The countLabels function used to be in the main program, but since it is used twice it was made to be a function.
def countLabels(img):                                                           # Adds 1px wide border to top and left.
    borderedImage = cv2.copyMakeBorder(img, 1, 0, 1, 0, cv2.BORDER_CONSTANT, value=[255, 255, 255])
    labelMatrix = np.zeros((borderedImage.shape[0], borderedImage.shape[1]), dtype=int)  # Initiates label matrix w/ 0s.
    labelCounter = 1  # Initiates label counter.
    labelEquivalenceArray = [-1] * 501  # Initiates equivalence array with 500 zeroes.

    for y in range(1, borderedImage.shape[1]):          # For every pixel in the image:
        for x in range(1, borderedImage.shape[0]):      # Horizontal scan (whole lines first each time)
            if borderedImage[x, y, 0] == 0:             # If pixel(x, y) is black, then:
                leftpx = borderedImage[x - 1, y, 0]     # Process its top and left neighbours.
                toppx = borderedImage[x, y - 1, 0]

                if (leftpx == 255) and (toppx == 255):  # If both neighbours are white, place new label in pixel(x, y).
                    placeNewLabel(labelMatrix, x, y, labelCounter)
                    labelCounter += 1

                elif (leftpx == 0) != (toppx == 0):     # Else, if only one is black, place its label in pixel(x, y).
                    if leftpx == 0:
                        placeExistingLabel(labelMatrix, x, y, "left")
                    else:
                        placeExistingLabel(labelMatrix, x, y, "top")

                elif leftpx == 0 and toppx == 0:        # Else, if both are black, then:
                    placeExistingLabel(labelMatrix, x, y, "top")  # Label it as one of them (top preference)
                    if compareTopLeftLabel(labelMatrix, x, y):  # If their labels are different, make them be
                        establishLabelEquivalence(labelMatrix, x, y, labelEquivalenceArray)  # equivalent.

#   The number of connected components is equal to the total number of labels minus the number of label equivalences.
    return labelMatrix.max() - countsArrayElements(labelEquivalenceArray)

#   End of functions
# ------------------------
#   Start of main program

#   Connected components labeling
image = cv2.imread("spots.tif")  # Loads image.
print("Total number of labels: ", countLabels(image))  # Prints the number of connected black components in image.

#   Hole labeling
image = cv2.bitwise_not(image)  # Inverts image's binary colors so that holes are black and other components are white.
#   The number of holes is equal to the number of labels -1 because the background is now considered a label.
print("Total number of holes: ", countLabels(image) - 1)  # Prints the number of black connected components in image.

#   End of main program


from django.shortcuts import render, get_object_or_404
from django.http import Http404
from .models import Player, Volume, Gig

def index(request):
	players = Player.objects.order_by('name')
	volumes = Volume.objects.order_by('name')
	return render(request, 'music/index.html', {'players': players, 'volumes': volumes})

def volume(request, slug):
	le_volume = get_object_or_404(Volume, slug=slug)
	all_volumes = Volume.objects.order_by('name')
	presave_volume = all_volumes.filter(status='d').exclude(pre_order__exact="")

	if le_volume.status == "p" or request.user.is_staff:
		return render(request, 'music/volume_page.html', {'volume': le_volume, 'volumes': all_volumes, 'presave_volume': presave_volume})
	else:
		raise Http404()

def contact_gigs(request):
	gigs = Gig.objects.all()
	gigs = sorted(gigs, key=lambda x: x.gig_date_filter())
	volumes = Volume.objects.order_by('name')
	return render(request, 'music/contact_gigs.html', {'gigs': gigs, 'volumes': volumes})

def memes(request):
	volumes = Volume.objects.order_by('name')
	return render(request, 'music/memes.html', {'volumes': volumes})


from django.shortcuts import render, redirect, HttpResponse
from django.contrib.auth.decorators import login_required
from crm import models
from crm.forms import CustomerForm, StudentEnrollmentForm
from django.db.utils import IntegrityError
import json, os
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from django.utils.timezone import datetime

@login_required
def dashboard(request):
    """首页"""
    return render(request, 'crm/dashboard.html')

@login_required
def student_enrollment(request):
    """销售分配学员班级，并生成报名链接"""
    customer_data = models.CustomerInfo.objects.all()
    class_list_data = models.ClassList.objects.all()
    if request.method == "POST":
        customer_id = request.POST.get('customer_id')  # 客户
        class_grade_id = request.POST.get('class_grade_id')  # 班级
        consultant_id = request.user.id  # 课程顾问

        try:
            enrollment_obj = models.StudentEnrollment.objects.create(
                customer_id=customer_id,
                class_grade_id=class_grade_id,
                consultant_id=consultant_id
            )
        except IntegrityError as e:
            enrollment_obj = models.StudentEnrollment.objects.get(customer_id=customer_id,
                                                                  class_grade_id=class_grade_id)

            # 是否同意协议，是则跳转，否则
            if enrollment_obj.contract_agreed:
                return redirect('/crm/student_enrollment/%s/contract_audit/' % enrollment_obj.id)

        # 生成报名链接，传递给前端，销售复制发送给学员填写报名信息
        enrollment_links = 'http://localhost:8002/crm/enrollment/%s/' % enrollment_obj.id

    return render(request, 'crm/student_enrollment.html', locals())

@login_required
def contract_audit(request, enrollment_id):
    """
    合同审核，销售对学员填写的报名表，签署的合同进行审核
    审核通过则跳转到修改页面： http://127.0.0.1:8002/kingadmin/crm/customerinfo/1/change/
    :param request:
    :param enrollment_id:
    :return:
    """
    enrollment_obj = models.StudentEnrollment.objects.get(id=enrollment_id)

    if request.method == 'POST':
        print(request.POST)
        student_enrollment_form = StudentEnrollmentForm(instance=enrollment_obj, data=request.POST)
        if student_enrollment_form.is_valid():
            student_enrollment_form.save()

            # 学员对象
            stu_obj = models.Student.objects.get_or_create(customer=enrollment_obj.customer)[0]
            stu_obj.class_grades.add(enrollment_obj.class_grade_id)  # 将学员添加到相应班级
            stu_obj.save()

            # 更改报名状态
            enrollment_obj.customer.status = 1
            enrollment_obj.customer.save()

            # 合同审核时间
            enrollment_obj.contract_approved_date = datetime.now()
            enrollment_obj.save()

            print(enrollment_obj.customer.status)

            return redirect('http://127.0.0.1:8002/kingadmin/crm/customerinfo/%s/change/' % enrollment_obj.customer.id)
    else:
        customer_form = CustomerForm(instance=enrollment_obj.customer)
        student_enrollment_form = StudentEnrollmentForm(instance=enrollment_obj)

    return render(request, 'crm/contract_audit.html', locals())

@login_required
def enrollment(request, enrollment_id):
    """
    学员报名链接地址
    :param request:
    :return:
    """
    enrollment_obj = models.StudentEnrollment.objects.get(id=enrollment_id)

    # 如果学员已经报名并填写了合同，那么再访问这个页面时，应该显示
    if enrollment_obj.contract_agreed:
        return HttpResponse('你已经报名，你耐心等待审核！')

    if request.method == 'POST':
        customer_form = CustomerForm(instance=enrollment_obj.customer, data=request.POST)
        # print('form err', customer_form.errors, customer_form.cleaned_data)
        if customer_form.is_valid():
            customer_form.save()

            enrollment_obj.contract_agreed = True  # 合同协议变为 True
            enrollment_obj.contract_signed_date = datetime.now()  # 合同签署时间
            enrollment_obj.save()  # 保存

            return HttpResponse('你已成功提交报名表，请等待审核！')
        print('form err: ', customer_form.errors)

    else:
        customer_form = CustomerForm(instance=enrollment_obj.customer)

    return render(request, 'crm/enrollment.html', locals())

@csrf_exempt
def enrollment_fileupload(request, enrollment_id):
    """
    接收学员上传的证件
    :param request:
    :param enrollment_id:
    :return:
    """

    ret = {'status': False, 'error': None, 'message': None}

    # 文件对象
    file_obj = request.FILES.get('file')
    print(file_obj)

    # 上传文件存储路径，根据报名链接序号创建相应文件夹，以此不会冲突
    path = os.path.join(settings.CRM_FILE_UPLOAD_DIR, enrollment_id)

    if not os.path.exists(path):
        os.mkdir(path)

    # 如果这个目录下文件数量大于 2 ，就限制其上传
    if len(os.listdir(path)) <= 2:
        with open(os.path.join(path, file_obj.name), 'wb') as f:
            for chunks in file_obj.chunks():
                f.write(chunks)
                ret['status'] = True
                ret['message'] = '上传成功！'

    else:
        ret['error'] = '最多只能上传两个文件！'

    return HttpResponse(json.dumps(ret))


import collections
from typing import Union, Optional, Set, List, Dict, Tuple

from blspy import AugSchemeMPL
from chiabip158 import PyBIP158
from clvm.casts import int_from_bytes

from src.consensus.block_rewards import (
    calculate_pool_reward,
    calculate_base_farmer_reward,
)
from src.consensus.blockchain_interface import BlockchainInterface
from src.consensus.coinbase import create_pool_coin, create_farmer_coin
from src.consensus.constants import ConsensusConstants
from src.consensus.find_fork_point import find_fork_point_in_chain
from src.consensus.block_root_validation import validate_block_merkle_roots
from src.consensus.network_type import NetworkType
from src.full_node.block_store import BlockStore
from src.consensus.blockchain_check_conditions import blockchain_check_conditions_dict
from src.full_node.coin_store import CoinStore
from src.consensus.cost_calculator import calculate_cost_of_program, CostResult
from src.consensus.block_record import BlockRecord
from src.types.blockchain_format.coin import Coin
from src.types.coin_record import CoinRecord
from src.types.announcement import Announcement
from src.types.condition_opcodes import ConditionOpcode
from src.types.condition_var_pair import ConditionVarPair
from src.types.full_block import FullBlock, additions_for_npc, announcements_for_npc
from src.types.name_puzzle_condition import NPC
from src.types.blockchain_format.sized_bytes import bytes32
from src.types.unfinished_block import UnfinishedBlock
from src.util.condition_tools import pkm_pairs_for_conditions_dict
from src.util.errors import Err
from src.util.hash import std_hash
from src.util.ints import uint64, uint32

import logging

log = logging.getLogger(__name__)

async def validate_block_body(
    constants: ConsensusConstants,
    blocks: BlockchainInterface,
    block_store: BlockStore,
    coin_store: CoinStore,
    peak: Optional[BlockRecord],
    block: Union[FullBlock, UnfinishedBlock],
    height: uint32,
    cached_cost_result: Optional[CostResult] = None,
    fork_point_with_peak: Optional[uint32] = None,
) -> Tuple[Optional[Err], Optional[CostResult]]:
    """
    This assumes the header block has been completely validated.
    Validates the transactions and body of the block. Returns None for the first value if everything
    validates correctly, or an Err if something does not validate. For the second value, returns a CostResult
    if validation succeeded, and there are transactions
    """
    if isinstance(block, FullBlock):
        assert height == block.height
    prev_transaction_block_height: uint32 = uint32(0)

    # 1. For non block blocks, foliage block, transaction filter, transactions info, and generator must be empty
    # If it is a block but not a transaction block, there is no body to validate. Check that all fields are None
    if block.foliage.foliage_transaction_block_hash is None:
        if (
            block.foliage_transaction_block is not None
            or block.transactions_info is not None
            or block.transactions_generator is not None
        ):
            return Err.NOT_BLOCK_BUT_HAS_DATA, None
        return None, None  # This means the block is valid

    # 2. For blocks, foliage block, transaction filter, transactions info must not be empty
    if (
        block.foliage_transaction_block is None
        or block.foliage_transaction_block.filter_hash is None
        or block.transactions_info is None
    ):
        return Err.IS_TRANSACTION_BLOCK_BUT_NO_DATA, None

    # keeps track of the reward coins that need to be incorporated
    expected_reward_coins: Set[Coin] = set()

    # 3. The transaction info hash in the Foliage block must match the transaction info
    if block.foliage_transaction_block.transactions_info_hash != std_hash(block.transactions_info):
        return Err.INVALID_TRANSACTIONS_INFO_HASH, None

    # 4. The foliage block hash in the foliage block must match the foliage block
    if block.foliage.foliage_transaction_block_hash != std_hash(block.foliage_transaction_block):
        return Err.INVALID_FOLIAGE_BLOCK_HASH, None

    # 5. The prev generators root must be valid
    # TODO(straya): implement prev generators

    # 4. The foliage block hash in the foliage block must match the foliage block
    if block.foliage.foliage_transaction_block_hash != std_hash(block.foliage_transaction_block):
        return Err.INVALID_FOLIAGE_BLOCK_HASH, None

    # 7. The reward claims must be valid for the previous blocks, and current block fees
    if height > 0:
        # Add reward claims for all blocks from the prev prev block, until the prev block (including the latter)
        prev_transaction_block = blocks.block_record(block.foliage_transaction_block.prev_transaction_block_hash)
        prev_transaction_block_height = prev_transaction_block.height

        assert prev_transaction_block.fees is not None
        pool_coin = create_pool_coin(
            prev_transaction_block.height,
            prev_transaction_block.pool_puzzle_hash,
            calculate_pool_reward(prev_transaction_block.height),
        )
        farmer_coin = create_farmer_coin(
            prev_transaction_block.height,
            prev_transaction_block.farmer_puzzle_hash,
            uint64(calculate_base_farmer_reward(prev_transaction_block.height) + prev_transaction_block.fees),
        )
        # Adds the previous block
        expected_reward_coins.add(pool_coin)
        expected_reward_coins.add(farmer_coin)

        # For the second block in the chain, don't go back further
        if prev_transaction_block.height > 0:
            curr_b = blocks.block_record(prev_transaction_block.prev_hash)
            while not curr_b.is_transaction_block:
                expected_reward_coins.add(
                    create_pool_coin(
                        curr_b.height,
                        curr_b.pool_puzzle_hash,
                        calculate_pool_reward(curr_b.height),
                    )
                )
                expected_reward_coins.add(
                    create_farmer_coin(
                        curr_b.height,
                        curr_b.farmer_puzzle_hash,
                        calculate_base_farmer_reward(curr_b.height),
                    )
                )
                curr_b = blocks.block_record(curr_b.prev_hash)

    if set(block.transactions_info.reward_claims_incorporated) != expected_reward_coins:
        return Err.INVALID_REWARD_COINS, None

    removals: List[bytes32] = []
    coinbase_additions: List[Coin] = list(expected_reward_coins)
    additions: List[Coin] = []
    announcements: List[Announcement] = []
    npc_list: List[NPC] = []
    removals_puzzle_dic: Dict[bytes32, bytes32] = {}
    cost: uint64 = uint64(0)

    if height <= constants.INITIAL_FREEZE_PERIOD and block.transactions_generator is not None:
        return Err.INITIAL_TRANSACTION_FREEZE, None

    if constants.NETWORK_TYPE == NetworkType.MAINNET:
        if block.transactions_generator is not None:
            if len(bytes(block.transactions_generator)) > constants.MAX_GENERATOR_SIZE:
                return Err.PRE_SOFT_FORK_MAX_GENERATOR_SIZE, None
            else:
                return None, None
        return None, None
    else:
        # 6. The generator root must be the tree-hash of the generator (or zeroes if no generator)
        if block.transactions_generator is not None:
            if block.transactions_generator.get_tree_hash() != block.transactions_info.generator_root:
                return Err.INVALID_TRANSACTIONS_GENERATOR_ROOT, None
        else:
            if block.transactions_info.generator_root != bytes([0] * 32):
                return Err.INVALID_TRANSACTIONS_GENERATOR_ROOT, None

        if block.transactions_generator is not None:
            # Get List of names removed, puzzles hashes for removed coins and conditions crated
            if cached_cost_result is not None:
                result: Optional[CostResult] = cached_cost_result
            else:
                result = calculate_cost_of_program(block.transactions_generator, constants.CLVM_COST_RATIO_CONSTANT)
            assert result is not None
            cost = result.cost
            npc_list = result.npc_list

            # 8. Check that cost <= MAX_BLOCK_COST_CLVM
            if cost > constants.MAX_BLOCK_COST_CLVM:
                return Err.BLOCK_COST_EXCEEDS_MAX, None
            if result.error is not None:
                return Err(result.error), None

            for npc in npc_list:
                removals.append(npc.coin_name)
                removals_puzzle_dic[npc.coin_name] = npc.puzzle_hash

            additions = additions_for_npc(npc_list)
            announcements = announcements_for_npc(npc_list)
        else:
            result = None

        # 9. Check that the correct cost is in the transactions info
        if block.transactions_info.cost != cost:
            return Err.INVALID_BLOCK_COST, None

        additions_dic: Dict[bytes32, Coin] = {}
        # 10. Check additions for max coin amount
        # Be careful to check for 64 bit overflows in other languages. This is the max 64 bit unsigned integer
        for coin in additions + coinbase_additions:
            additions_dic[coin.name()] = coin
            if coin.amount > constants.MAX_COIN_AMOUNT:
                return Err.COIN_AMOUNT_EXCEEDS_MAXIMUM, None

        # 11. Validate addition and removal roots
        root_error = validate_block_merkle_roots(
            block.foliage_transaction_block.additions_root,
            block.foliage_transaction_block.removals_root,
            additions + coinbase_additions,
            removals,
        )
        if root_error:
            return root_error, None

        # 12. The additions and removals must result in the correct filter
        byte_array_tx: List[bytes32] = []

        for coin in additions + coinbase_additions:
            byte_array_tx.append(bytearray(coin.puzzle_hash))
        for coin_name in removals:
            byte_array_tx.append(bytearray(coin_name))

        bip158: PyBIP158 = PyBIP158(byte_array_tx)
        encoded_filter = bytes(bip158.GetEncoded())
        filter_hash = std_hash(encoded_filter)

        if filter_hash != block.foliage_transaction_block.filter_hash:
            return Err.INVALID_TRANSACTIONS_FILTER_HASH, None

        # 13. Check for duplicate outputs in additions
        addition_counter = collections.Counter(_.name() for _ in additions + coinbase_additions)
        for k, v in addition_counter.items():
            if v > 1:
                return Err.DUPLICATE_OUTPUT, None

        # 14. Check for duplicate spends inside block
        removal_counter = collections.Counter(removals)
        for k, v in removal_counter.items():
            if v > 1:
                return Err.DOUBLE_SPEND, None

        # 15. Check if removals exist and were not previously spent. (unspent_db + diff_store + this_block)
        if peak is None or height == 0:
            fork_h: int = -1
        elif fork_point_with_peak is not None:
            fork_h = fork_point_with_peak
        else:
            fork_h = find_fork_point_in_chain(blocks, peak, blocks.block_record(block.prev_header_hash))

        if fork_h == -1:
            coin_store_reorg_height = -1
        else:
            last_block_in_common = await blocks.get_block_record_from_db(blocks.height_to_hash(uint32(fork_h)))
            assert last_block_in_common is not None
            coin_store_reorg_height = last_block_in_common.height

        # Get additions and removals since (after) fork_h but not including this block
        additions_since_fork: Dict[bytes32, Tuple[Coin, uint32]] = {}
        removals_since_fork: Set[bytes32] = set()
        coinbases_since_fork: Dict[bytes32, uint32] = {}

        if height > 0:
            curr: Optional[FullBlock] = await block_store.get_full_block(block.prev_header_hash)
            assert curr is not None

            while curr.height > fork_h:
                removals_in_curr, additions_in_curr = curr.tx_removals_and_additions()
                for c_name in removals_in_curr:
                    removals_since_fork.add(c_name)
                for c in additions_in_curr:
                    additions_since_fork[c.name()] = (c, curr.height)

                for coinbase_coin in curr.get_included_reward_coins():
                    additions_since_fork[coinbase_coin.name()] = (coinbase_coin, curr.height)
                    coinbases_since_fork[coinbase_coin.name()] = curr.height
                if curr.height == 0:
                    break
                curr = await block_store.get_full_block(curr.prev_header_hash)
                assert curr is not None

        removal_coin_records: Dict[bytes32, CoinRecord] = {}
        for rem in removals:
            if rem in additions_dic:
                # Ephemeral coin
                rem_coin: Coin = additions_dic[rem]
                new_unspent: CoinRecord = CoinRecord(
                    rem_coin,
                    height,
                    uint32(0),
                    False,
                    (rem in coinbases_since_fork),
                    block.foliage_transaction_block.timestamp,
                )
                removal_coin_records[new_unspent.name] = new_unspent
            else:
                unspent = await coin_store.get_coin_record(rem)
                if unspent is not None and unspent.confirmed_block_index <= coin_store_reorg_height:
                    # Spending something in the current chain, confirmed before fork
                    # (We ignore all coins confirmed after fork)
                    if unspent.spent == 1 and unspent.spent_block_index <= coin_store_reorg_height:
                        # Check for coins spent in an ancestor block
                        return Err.DOUBLE_SPEND, None
                    removal_coin_records[unspent.name] = unspent
                else:
                    # This coin is not in the current heaviest chain, so it must be in the fork
                    if rem not in additions_since_fork:
                        # Check for spending a coin that does not exist in this fork
                        # TODO: fix this, there is a consensus bug here
                        return Err.UNKNOWN_UNSPENT, None
                    new_coin, confirmed_height = additions_since_fork[rem]
                    new_coin_record: CoinRecord = CoinRecord(
                        new_coin,
                        confirmed_height,
                        uint32(0),
                        False,
                        (rem in coinbases_since_fork),
                        block.foliage_transaction_block.timestamp,
                    )
                    removal_coin_records[new_coin_record.name] = new_coin_record

                # This check applies to both coins created before fork (pulled from coin_store),
                # and coins created after fork (additions_since_fork)>
                if rem in removals_since_fork:
                    # This coin was spent in the fork
                    return Err.DOUBLE_SPEND, None

        removed = 0
        for unspent in removal_coin_records.values():
            removed += unspent.coin.amount

        added = 0
        for coin in additions:
            added += coin.amount

        # 16. Check that the total coin amount for added is <= removed
        if removed < added:
            return Err.MINTING_COIN, None

        fees = removed - added
        assert_fee_sum: uint64 = uint64(0)

        for npc in npc_list:
            if ConditionOpcode.RESERVE_FEE in npc.condition_dict:
                fee_list: List[ConditionVarPair] = npc.condition_dict[ConditionOpcode.RESERVE_FEE]
                for cvp in fee_list:
                    fee = int_from_bytes(cvp.vars[0])
                    assert_fee_sum = assert_fee_sum + fee

        # 17. Check that the assert fee sum <= fees
        if fees < assert_fee_sum:
            return Err.RESERVE_FEE_CONDITION_FAILED, None

        # 18. Check that the assert fee amount < maximum coin amount
        if fees > constants.MAX_COIN_AMOUNT:
            return Err.COIN_AMOUNT_EXCEEDS_MAXIMUM, None

        # 19. Check that the computed fees are equal to the fees in the block header
        if block.transactions_info.fees != fees:
            return Err.INVALID_BLOCK_FEE_AMOUNT, None

        # 20. Verify that removed coin puzzle_hashes match with calculated puzzle_hashes
        for unspent in removal_coin_records.values():
            if unspent.coin.puzzle_hash != removals_puzzle_dic[unspent.name]:
                return Err.WRONG_PUZZLE_HASH, None

        # 21. Verify conditions
        # create hash_key list for aggsig check
        pairs_pks = []
        pairs_msgs = []
        for npc in npc_list:
            assert height is not None
            unspent = removal_coin_records[npc.coin_name]
            error = blockchain_check_conditions_dict(
                unspent,
                announcements,
                npc.condition_dict,
                prev_transaction_block_height,
                block.foliage_transaction_block.timestamp,
            )
            if error:
                return error, None
            for pk, m in pkm_pairs_for_conditions_dict(npc.condition_dict, npc.coin_name):
                pairs_pks.append(pk)
                pairs_msgs.append(m)

        # 22. Verify aggregated signature
        # TODO: move this to pre_validate_blocks_multiprocessing so we can sync faster
        if not block.transactions_info.aggregated_signature:
            return Err.BAD_AGGREGATE_SIGNATURE, None

            # noinspection PyTypeChecker
        if not AugSchemeMPL.aggregate_verify(pairs_pks, pairs_msgs, block.transactions_info.aggregated_signature):
            return Err.BAD_AGGREGATE_SIGNATURE, None

        return None, result


import os
import sys
import types
import weakref
import logging
import datetime
import warnings
import traceback
import functools

from . import _registered_callbacks
from .vendor import six

def inrange(number, base, offset=0.5):
    r"""Evaluate whether `number` is within `base` +- `offset`

    Lower bound is *included* whereas upper bound is *excluded*
    so as to allow for ranges to be stacked up against each other.
    For example, an offset of 0.5 and a base of 1 evenly stacks
    up against a base of 2 with identical offset.

    Arguments:
        number (float): Number to consider
        base (float): Center of range
        offset (float, optional): Amount of offset from base

    Usage:
        >>> inrange(0, base=1, offset=0.5)
        False
        >>> inrange(0.4, base=1, offset=0.5)
        False
        >>> inrange(1.4, base=1, offset=0.5)
        True
        >>> # Lower bound is included
        >>> inrange(0.5, base=1, offset=0.5)
        True
        >>> # Upper bound is excluded
        >>> inrange(1.5, base=1, offset=0.5)
        False

    """

    return (base - offset) <= number < (base + offset)

class MessageHandler(logging.Handler):
    def __init__(self, records, *args, **kwargs):
        # Not using super(), for compatibility with Python 2.6
        logging.Handler.__init__(self, *args, **kwargs)
        self.records = records

    def emit(self, record):
        self.records.append(record)

def extract_traceback(exception):
    """Inject current traceback and store in exception"""
    exc_type, exc_value, exc_traceback = sys.exc_info()
    exception.traceback = traceback.extract_tb(exc_traceback)[-1]
    del(exc_type, exc_value, exc_traceback)

def time():
    """Return ISO formatted string representation of current UTC time."""
    return '%sZ' % datetime.datetime.utcnow().isoformat()

class ItemList(list):
    """List with keys

    Raises:
        KeyError is item is not in list

    Example:
        >>> Obj = type("Object", (object,), {})
        >>> obj = Obj()
        >>> obj.name = "Test"
        >>> l = ItemList(key="name")
        >>> l.append(obj)
        >>> l[0] == obj
        True
        >>> l["Test"] == obj
        True
        >>> try:
        ...   l["NotInList"]
        ... except KeyError:
        ...   print(True)
        True
        >>> obj == l.get("Test")
        True
        >>> l.get("NotInList") == None
        True

    """

    def __init__(self, key, object=list()):
        super(ItemList, self).__init__(object)
        self.key = key

    def __getitem__(self, index):
        if isinstance(index, int):
            return super(ItemList, self).__getitem__(index)

        for item in self:
            if getattr(item, self.key) == index:
                return item

        raise KeyError("%s not in list" % index)

    def get(self, key, default=None):
        try:
            return self.__getitem__(key)
        except KeyError:
            return default

class classproperty(object):
    def __init__(self, getter):
        self.getter = getter

    def __get__(self, instance, owner):
        return self.getter(owner)

def log(cls):
    """Decorator for attaching a logger to the class `cls`

    Loggers inherit the syntax {module}.{submodule}

    Example
        >>> @log
        ... class MyClass(object):
        ...     pass
        >>>
        >>> myclass = MyClass()
        >>> myclass.log.info('Hello World')

    """

    module = cls.__module__
    name = cls.__name__

    # Package name appended, for filtering of LogRecord instances
    logname = "pyblish.%s.%s" % (module, name)
    cls.log = logging.getLogger(logname)

    # All messages are handled by root-logger
    cls.log.propagate = True

    return cls

def parse_environment_paths(paths):
    """Given a (semi-)colon separated string of paths, return a list

    Example:
        >>> import os
        >>> parse_environment_paths("path1" + os.pathsep + "path2")
        ['path1', 'path2']
        >>> parse_environment_paths("path1" + os.pathsep)
        ['path1', '']

    Arguments:
        paths (str): Colon or semi-colon (depending on platform)
            separated string of paths.

    Returns:
        list of paths as string.

    """

    paths_list = list()

    for path in paths.split(os.pathsep):
        paths_list.append(path)

    return paths_list

def get_formatter():
    """Return a default Pyblish formatter for logging

    Example:
        >>> import logging
        >>> log = logging.getLogger("myLogger")
        >>> handler = logging.StreamHandler()
        >>> handler.setFormatter(get_formatter())

    """

    formatter = logging.Formatter(
        '%(asctime)s - '
        '%(levelname)s - '
        '%(name)s - '
        '%(message)s',
        '%H:%M:%S')
    return formatter

def setup_log(root='pyblish', level=logging.DEBUG):
    """Setup a default logger for Pyblish

    Example:
        >>> log = setup_log()
        >>> log.info("Hello, World")

    """

    formatter = logging.Formatter("%(levelname)s - %(message)s")
    handler = logging.StreamHandler()
    handler.setFormatter(formatter)

    log = logging.getLogger(root)
    log.propagate = True
    log.handlers[:] = []
    log.addHandler(handler)

    log.setLevel(level)

    return log

def main_package_path():
    """Return path of main pyblish package"""
    lib_py_path = sys.modules[__name__].__file__
    package_path = os.path.dirname(lib_py_path)
    return package_path

def emit(signal, **kwargs):
    """Trigger registered callbacks

    Keyword arguments are passed from caller to callee.

    Arguments:
        signal (string): Name of signal emitted

    Example:
        >>> import sys
        >>> def mycallback(data):
        ...     sys.stdout.write(str(data))
        ...
        >>> register_callback("mysignal", mycallback)
        ...
        >>> emit("mysignal", data={"something": "cool"})
        {'something': 'cool'}

    """

    for callback in _registered_callbacks.get(signal, {}).values():
        try:
            callback(**kwargs)

        except ReferenceError:
            # Ignore end-of-life references
            pass

        except Exception:
            file = six.StringIO()
            traceback.print_exc(file=file)
            sys.stderr.write(file.getvalue())
            # Why the roundabout through StringIO?
            #
            # tests.lib.captured_stderr attempts to capture stderr
            # but doing so with plain print_exc() results in a type
            # error in Python 3. I'm not confident in Python 3 unicode
            # handling so there is likely a better way to solve this.
            #
            # TODO(marcus): Make it prettier

def register_callback(signal, callback):
    """Register a new callback

    Arguments:
        signal (string): Name of signal to register the callback with.
        callback (func): Function to execute when a signal is emitted.

    Raises:
        ValueError if `callback` is not callable.

    """

    if not hasattr(callback, "__call__"):
        raise ValueError("%s must be callable" % callback)

    if signal not in _registered_callbacks:
        # Need to store in a dictionary so as to
        # enable removal via deregister_callback,
        # since the actual function is not comparable
        # to its weak reference equivalent.

        _registered_callbacks[signal] = weakref.WeakValueDictionary()

    name = callback.__name__
    callbacks = _registered_callbacks[signal]

    if name in callbacks:
        raise ValueError(
            "Callback by this name already registered: \"%s\"" % name
        )

    # Use weak reference such that connected callbacks
    # can safely be garbage collected without interference
    # from observers.
    callbacks[name] = callback

def deregister_callback(signal, callback):
    """Deregister a callback

    Arguments:
        signal (string): Name of signal to deregister the callback with.
        callback (func): Function to execute when a signal is emitted.

    Raises:
        KeyError on missing signal or callback

    """

    _registered_callbacks[signal].pop(callback.__name__)

    # Erase empty member
    if not _registered_callbacks[signal]:
        _registered_callbacks.pop(signal)

def deregister_all_callbacks():
    """Deregisters all callback"""

    _registered_callbacks.clear()

def registered_callbacks():
    """Returns registered callbacks"""

    return list(_registered_callbacks.keys())

def deprecated(func):
    """Deprecation decorator

    Attach this to deprecated functions or methods.

    """

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        if sys.version_info[0] == 2:
            warnings.warn_explicit(
                "Call to deprecated function %s." % func.__name__,
                category=DeprecationWarning,
                filename=func.func_code.co_filename,
                lineno=func.func_code.co_firstlineno + 1)
        return func(*args, **kwargs)
    return wrapper

if sys.version_info < (3, 4):
    class _WeakRef(object):
        def __init__(self, func):
            try:
                if func.__self__ is not None:
                    self._instance = weakref.ref(func.__self__)
                else:
                    # Unbound method
                    self._instance = None

                self._func = weakref.ref(func.__func__)
                self._class = weakref.ref(func.__class__)

            except AttributeError:
                # Not a method
                self._instance = None
                self._class = None
                self._func = weakref.ref(func)

        def __call__(self):
            if self._is_dead():
                return None

            if self._instance is None:
                return self._func()

            return types.MethodType(self._func(), self._instance())

        def _is_dead(self):
            """Is the reference dead?

            Returns True if the referenced callable was a bound method and
            the instance no longer exists. Otherwise, return False.

            Usage:
                >>> class Object(object):
                ...   def func(self):
                ...     pass
                ...
                >>> o = Object()
                >>> weak_func = WeakRef(o.func)
                >>> weak_func._is_dead()
                False
                >>> del(o)
                >>> weak_func._is_dead()
                True

            """

            return self._instance is not None and self._instance() is None

else:
    # Python 3.4 upwards implement weakref.WeakMethod
    class _WeakRef:
        def __init__(self, func):
            try:
                func.__self__
                self._func = weakref.WeakMethod(func)
            except AttributeError:
                self._func = weakref.ref(func)

        def __call__(self):
            return self._func()

class WeakRef(_WeakRef):
        """Alternative weak reference with support for instancemethods

        Usage:
            >>> import weakref
            >>> class MyClass(object):
            ...   def func(self):
            ...     pass
            ...
            >>> inst = MyClass()
            >>> ref = weakref.ref(inst.func)
            >>> ref() is None
            True
            >>> ref = WeakRef(inst.func)
            >>> ref() is None
            False

        """

        def __eq__(self, other):
            """Compare weak references against each other

            Example:
                >>> def func_a():
                ...   pass
                ...
                >>> def func_b():
                ...   pass
                ...
                >>> weak_a1 = WeakRef(func_a)
                >>> weak_a2 = WeakRef(func_a)
                >>> weak_b = WeakRef(func_b)
                >>> weak_a1 == weak_a2
                True
                >>> weak_b == weak_a1
                False

            """

            try:
                return type(self) is type(other) and self() == other()
            except:
                return False

        def __ne__(self, other):
            return not self == other


###
# Programmers: David Landsman, Aaron Nahum
# File name: SQLWrapper.py
# Description: Contains methods for easily working with the database.
###

import sqlite3
import Course
import Student

class SQLWrapper:
    def __init__(self):
        '''Initialize SQLWrapper.'''
        # Create a database file
        self.con = sqlite3.connect('timetable.db')
        # Connect to the database (locally)
        self.cursor = self.con.cursor()

    def createStudentsTable(self):
        """
        Creates a table to store student data
        """
        statement = "CREATE TABLE IF NOT EXISTS Students (studentId INTEGER, grade INTEGER, selectedCourses TEXT, password TEXT, finalCourses TEXT)"
        self.cursor.execute(statement)
        self.con.commit()

    def createCoursesTable(self):
        """
        Creates a courses table
        """
        statement = "CREATE TABLE IF NOT EXISTS Courses (courseId INTEGER, name TEXT, priority INTEGER)"
        self.cursor.execute(statement)
        self.con.commit()

    def generateCourses(self):
        """
        Generates courses for the courses table
        """
        # Check if courses aren't already generated
        if len(self.getAllCourses()) > 0:
            return

        Courses = ["English", "Math", "Comp Sci", "Entrepreneurship",
               "Accounting", "History", "Geography", "Music",
               "Religion"] #List of Courses

        #Adds courses with different priorities
        i = 0
        for i in range (0,2):
            self.addCourse(i + 1, Courses[i], 3)
        for i in range (0,5):
            self.addCourse(i + 3, Courses[i+2], 2)
        for i in range (0,2):
            self.addCourse(i+8, Courses[i+7],1)

    def addStudent(self, studentId, grade, password):
        """ (int, int, str) -> (none)

        Adds a student into the database
        """
        statement = "INSERT INTO Students VALUES (%s, %s, '%s', '%s', '%s')" % (studentId, grade, None, password, None)
        self.cursor.execute(statement)
        self.con.commit()

    def addStudentCourses (self, studentId, selectedCourses):
        """ (int, list) -> (none)

        Adds all courses that the Student chose
        """
        # Use a string representation of the selectedCourses list to store it in the database
        statement = 'UPDATE Students SET selectedCourses = "%s" WHERE studentId = %s' % (repr(selectedCourses), studentId)
        self.cursor.execute(statement)
        self.con.commit()

    def addFinalCourses(self, studentId, finalCourses):
        """ (int, list) -> (none)

        Adds final timetable to Student.
        """
        statement = 'UPDATE Students SET finalCourses = "%s" WHERE studentId = %s' % (repr(finalCourses), studentId)
        self.cursor.execute(statement)
        self.con.commit()

    def addCourse(self, courseId, name, priority):
        """ (int, str, int) -> (none)

        Adds a course to the Students selected courses
        """
        statement = "INSERT INTO Courses VALUES (%s, '%s', %s)" % (courseId, name, priority)
        self.cursor.execute(statement)
        self.con.commit()

    def deleteStudent(self, studentId):
        """ (str) -> (none)

        Deletes a student from a selected course
        """
        statement = "DELETE FROM Students WHERE studentId = %s" % (studentId)
        self.cursor.execute(statement)
        self.con.commit()

    def getCourse(self, courseId):
        """ (int) -> (Course)

        Gets a course with the given id
        """
        statement = "SELECT * FROM Courses WHERE courseId = %s" % (courseId)
        self.cursor.execute(statement)
        # Retrieve a single course and return it
        row = self.cursor.fetchone()
        if row != None:
            return self.parseCourse(row)
        else:
            return None

    def getAllCourses(self):
        """
        Gets all courses
        """
        statement = "SELECT * FROM Courses"
        self.cursor.execute(statement)
        courses = []
        # Retrieve all courses and create a list of Course (model) objects and return it
        rows = self.cursor.fetchall()
        if rows == None:
            return None
        for row in rows:
            courses.append(self.parseCourse(row))
        return courses

    def getStudent(self, studentId):
        """ (int) -> (Student)

        Gets a student with the given id
        """
        statement = "SELECT * FROM Students WHERE studentId = %s" % (studentId)
        self.cursor.execute(statement)
        # Retrieve a single student and return it
        row = self.cursor.fetchone()
        if row != None:
            return self.parseStudent(row)
        else:
            return None

    def getAllStudents(self):
        """
        Gets all students
        """
        statement = "SELECT * FROM Students"
        self.cursor.execute(statement)
        students = []
        # Retrieve all students and create a list of Student (model) objects and return it
        rows = self.cursor.fetchall()
        if rows == None:
            return None
        for row in rows:
            students.append(self.parseStudent(row))
        return students

    def parseStudent(self, row):
        return Student.Student(row[0], row[1], row[2], row[3], row[4])

    def parseCourse(self, row):
        return Course.Course(row[0], row[1], row[2])


# import imageio
#
# imageio.plugins.ffmpeg.download()
# # import win_unicode_console
#
# win_unicode_console.enable()
import sys, os
from PyQt5.QtCore import *
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit, QLabel,QTextEdit,
                             QApplication, QFileDialog,QProgressBar)
from moviepy.video.io.VideoFileClip import VideoFileClip
from run4in1_video_cut import run4in1,run4in1_thread
from PyQt5.QtGui import QTextCursor

import threading
import multiprocessing

class Stream(QObject):
    """Redirects console output to text widget."""
    newText = pyqtSignal(str)

    def write(self, text):
        self.newText.emit(str(text))
        QApplication.processEvents()

class login(QWidget):
    def __init__(self):
        super(login, self).__init__()
        self.initUI()
        self.is_running = 0 # 0没在运行；1在运行
        self.save_file_names = [] #要执行的视频文件list
        # self.t1
        # Custom output stream.
        sys.stdout = Stream(newText=self.onUpdateText)

    def onUpdateText(self, text):
        """Write console output to text widget."""
        cursor = self.textEdit.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.textEdit.setTextCursor(cursor)
        self.textEdit.ensureCursorVisible()

    def closeEvent(self, event):
        """Shuts down application on close."""
        # Return stdout to defaults.
        sys.stdout = sys.__stdout__
        super().closeEvent(event)

    def initUI(self):
        # 源文件选择按钮和选择编辑框
        self.source_btn = QPushButton('选择源文件', self)
        self.source_btn.move(30, 30)
        self.source_btn.resize(60, 30)
        self.source_btn.clicked.connect(self.select_source)
        self.source_le = QLineEdit(self)
        self.source_le.move(120, 30)
        self.source_le.resize(450, 30)

        # 存储文件选择按钮和选择编辑框
        self.target_btn = QPushButton('选择保存路径', self)
        self.target_btn.move(30, 90)
        self.target_btn.resize(60, 30)
        self.target_btn.clicked.connect(self.select_target)
        self.target_le = QLineEdit(self)
        self.target_le.move(120, 90)
        self.target_le.resize(450, 30)

        # 保存按钮，调取数据增加函数等
        self.save_btn = QPushButton('开始', self)
        self.save_btn.move(30, 210)
        self.save_btn.resize(140, 30)
        self.save_btn.clicked.connect(self.addNum)

        # 执行成功返回值显示位置设置
        self.result_le = QLabel(self)
        self.result_le.move(30, 270)
        self.result_le.resize(340, 30)

        self.progressBar = QProgressBar(self)
        self.progressBar.setGeometry(QRect(250, 210, 361, 23))
        self.progressBar.setProperty("value", 0)
        self.progressBar.setObjectName("progressBar")

        self.textEdit = QTextEdit(self, readOnly=True)
        self.textEdit.setGeometry(QRect(30, 300, 500, 200))
        self.textEdit.setObjectName("textEdit")

        # 整体界面设置
        self.setGeometry(400, 400, 800, 600)
        self.setWindowTitle('视频剪切')  # 设置界面标题名
        self.show()

    # 打开的视频文件名称
    def select_source(self):
        open_dic = "C:/Users/29125/PycharmProjects/video4in1"
        self.targets, fileType = QFileDialog.getOpenFileNames(self, "选择源文件", open_dic)
        self.source_le.setText(str(self.targets))

        # target, fileType = QFileDialog.getSaveFileName(self, "选择保存路径", self.source_le.text())
        self.save_file_names = []
        for target in self.targets:
            target_list = list(target)
            nPos = target.rindex('.')
            target_list.insert(nPos, '_4in1')
            target2 = ''.join(target_list)
            # self.target_le.setText(str(target2))
            self.save_file_names.append(target2)
    # 保存的视频文件名称，要写上后缀名
    def select_target(self):
        # target, fileType = QFileDialog.getSaveFileName(self, "选择保存路径", "C:/Users/29125/PycharmProjects/video4in1")
        open_dic = "C:/Users/29125/PycharmProjects/video4in1"
        target = QFileDialog.getExistingDirectory(self, "选择保存路径", open_dic)
        self.target_le.setText(str(target))

    def addNum(self):
        print('执行操作的文件数量：',len(self.save_file_names))
        target = self.target_le.text().strip()  # 获取剪切后视频保存的文件夹

        for i, exec_file in enumerate(self.save_file_names):
            QApplication.processEvents()
            run4in1(self.targets[i], exec_file)
            print(i + 1, "/", len(self.save_file_names), " 完成！")
            self.progressBar.setValue((i+1) / len(self.save_file_names) * 100)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = login()
    sys.exit(app.exec_())