#!/usr/bin/python
# -*- coding: utf-8 -*-
# vi: ts=4 sw=4

import pickle
from ..Protocols import *

from scipy.spatial.distance import cdist
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans, MeanShift, estimate_bandwidth, AffinityPropagation, SpectralClustering # Clustering methods
from sklearn.decomposition import PCA

import skimage

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.patches as patches

class cluster(ProtocolMultiple):

    def __init__(self, name='cluster', **kwargs):

        self.name = self.__class__.__name__ if name is None else name

        self.default_ext = '.pkl'
        self.run_args = {
                        'file_extension' : '.pkl',
                        'force' : False,
                        'verbosity' : 3,
                        'num_jobs' : None,
                        'num_clusters' : 20,
                        'cluster_method' : 'kmeans', # 'affinity', 'kmeans', 'meanshift'
                        'features' : 'all', # 'shape', 'color', 'all'
                        'feature_normed_range' : [-2, +2], # range for plotting the normed features
                        'bbox_pad' : 0.5,
                        'image_contrast' : (0, 1),
                        'image_contrast_trim' : None,
                        'overlays' : 3,
                        }
        self.run_args.update(kwargs)

        # WARNING: This association of features names is hard-coded, and is thus contingent
        # on the current implementation of Protocols.py>flake_analysis
        self.feature_names_color = [
            'g contrast',
            'v contrast',
            'gray',
            'gray std',
            'H',
            'S',
            'V',
            'H std',
            'S std',
            'V std',
            'R',
            'G',
            'B',
            'R std',
            'G std',
            'B std',
            'entropy'
            ]
        self.feature_names_color = self.feature_names_color + ['{}_inner'.format(f) for f in self.feature_names_color]

        self.feature_names_shape = ['P/A'] + ['hist {}'.format(i) for i in range(15)] + ['fractal dimension']

    def load_flakes(self, datas, **run_args):
        flakes = []
        for data in datas:
            with open(data.infile, 'rb') as fin:
                saved = pickle.load(fin) # 'res_map', 'image_labelmap', 'flakes'
                if len(flakes)==0:
                    h, w = saved['res_map'].shape

                for flake in saved['flakes']:
                    flakes.append(flake)
                    #self.print_structure(flake)

                if run_args['verbosity']>=5:
                    print('      {} flakes added from image {}'.format(len(saved['flakes']), data.infile))

        return flakes

    def load_flakes_parallel(self, datas, **run_args):
        # Parallelize loading
        # Doesn't seem to actually run faster (likely I/O limited)
        from joblib import Parallel, delayed
        import itertools

        flakes = Parallel(n_jobs=run_args['num_jobs'])(delayed(self.load_flake_pkl)(data.infile) for data in datas)
        flakes = list(itertools.chain.from_iterable(flakes))

        return flakes

    def load_flake_pkl(self, infile):
        with open(infile, 'rb') as fin:
            flakes = pickle.load(fin)['flakes']
        return flakes

    def load_features(self, flakes, **run_args):

        if run_args['features']=='all':
            features = [ np.concatenate([flake['flake_color_fea'], flake['flake_shape_fea']]) for flake in flakes ]

            if 'flake_color_fea_names' in flakes[0]:
                self.feature_names_color = flakes[0]['flake_color_fea_names']
            if 'flake_shape_fea_names' in flakes[0]:
                self.feature_names_shape = flakes[0]['flake_shape_fea_names']

            self.feature_names = self.feature_names_color + self.feature_names_shape

        else:
            features = [ flake['flake_{}_fea'.format(run_args['features'])] for flake in flakes ]

            if run_args['features']=='color':
                if 'flake_color_fea_names' in flakes[0]:
                    self.feature_names = flakes[0]['flake_color_fea_names']
                else:
                    self.feature_names = self.feature_names_color

            elif run_args['features']=='shape':
                if 'flake_shape_fea_names' in flakes[0]:
                    self.feature_names = flakes[0]['flake_shape_fea_names']
                else:
                    self.feature_names = self.feature_names_shape

            else:
                if 'flake_{}_fea_names'.format(run_args['features']) in flakes[0]:
                    self.feature_names = flakes[0]['flake_{}_fea_names'.format(run_args['features'])]
                else:
                    self.feature_names = []

        return np.asarray(features)

    def load_clustering(self, basename, output_dir='./', features_rescaled=None, **run_args):
        # Load data aggregated from the "cluster" protocol into a cluster.pkl file
        savefile = self.get_outfile(basename, output_dir, ext=run_args['file_extension'])
        if os.path.exists(savefile):
            with open(savefile, 'rb') as fin:
                clustering = pickle.load(fin)
        else:
            savefile = self.get_outfile(basename, output_dir+'/../cluster/', ext=run_args['file_extension'])
            if os.path.exists(savefile):
                with open(savefile, 'rb') as fin:
                    clustering = pickle.load(fin)
            elif features_rescaled is not None:
                # Manually recompute some minimal aspects of clustering
                # Note: This mostly exists so that select_flakes.run has access to this information
                # even if cluster.run has never been run (and thus cluster.pkl doesn't exist).
                clustering = {}
                vmin, vmax = run_args['feature_normed_range']
                distributions, dist_bin_edges = np.apply_along_axis(lambda x: np.histogram(x, bins=50, range=[vmin,vmax], density=True), 0, features_rescaled)
                clustering['distributions'] = distributions
                clustering['dist_bin_edges'] = dist_bin_edges

            else:
                print("Error in cluster.load_clustering: we don't have access to clustering information.")

        return clustering

    @run_default
    def run(self, datas, output_dir, basename, **run_args):

        results = {}
        clustering = {} # Save results of clustering operation

        # Aggregate results
        ########################################
        flakes = self.load_flakes(datas, **run_args)
        if run_args['verbosity']>=4:
            print('  {:,d} flakes identified in {:d} images'.format(len(flakes), len(datas)))

        features_orig = self.load_features(flakes, **run_args)

        # Clustering
        ########################################
        rescale = StandardScaler()
        features = rescale.fit_transform(features_orig)

        if run_args['verbosity']>=4:
            print("  Clustering {:,d} flakes using '{}'".format(len(flakes), run_args['cluster_method']))

        start = time.time()

        n_jobs = run_args['num_jobs'] if 'num_jobs' in run_args else -1

        if run_args['cluster_method']=='kmeans':
            cluster_result = KMeans(n_clusters=run_args['num_clusters'], random_state=0, n_jobs=n_jobs).fit(features)

        elif run_args['cluster_method']=='meanshift':
            bandwidth = estimate_bandwidth(features, quantile=0.1)#, n_samples=int(features.shape[0]/10))
            cluster_result = MeanShift(bandwidth=bandwidth, bin_seeding=True, n_jobs=n_jobs).fit(features)

        elif run_args['cluster_method']=='affinity':
            cluster_result = AffinityPropagation().fit(features)

        elif run_args['cluster_method']=='spectral':
            cluster_result = SpectralClustering(n_clusters=run_args['num_clusters'], n_jobs=n_jobs).fit(features)

        else:
            print("ERROR: clustering method '{}' not recognized.".format(run_args['cluster_method']))
            raise NotImplementedError

        clustering['cluster_result'] = cluster_result
        results['cluster_runtime'] = time.time()-start
        results['cluster_method'] = run_args['cluster_method']

        # Assignments are unsorted by default
        assignment = cluster_result.labels_
        results['num_clusters'] = len(np.unique(assignment))
        clustering['assignment'] = assignment # Label ids for each flake, saying what cluster it belongs to [unsorted indexing]

        if run_args['verbosity']>=4:
            print("    clustering took {:.1f}s ({:d} clusters)".format(results['cluster_runtime'], results['num_clusters']))

        # Sort clusters into a sensible order
        consider_features = np.asarray([flake['flake_color_fea'][:2] for flake in flakes]) # Grayscale and V contrast

        # The average for each cluster gives the position for the center of that cluster (in the feature space)
        central_features = np.zeros([results['num_clusters'], consider_features.shape[1]])
        for i in range(results['num_clusters']):
             cluster_i = np.nonzero(assignment==i)[0]
             central_features[i,:] = np.mean(consider_features[cluster_i, :])
        clustering['sort_indices'] = np.argsort(np.abs(central_features).sum(1))
        clustering['unsort2sort'] = np.unique(clustering['sort_indices'], return_index=True)[1]

        clustering['cluster_centers'] = cluster_result.cluster_centers_[clustering['sort_indices']] # in (normed) feature space coordinates [sorted indexing]
        clustering['cluster_centers_orig'] = rescale.inverse_transform(clustering['cluster_centers']) # in (original) feature space coordinates [sorted indexing]
        clustering['cluster_center_distances'] = cdist(clustering['cluster_centers'], clustering['cluster_centers']) # in (normed) feature space coordinates [sorted indexing]

        # Compute additional things
        ########################################
        # The distribution (histogram) for each feature dimension
        # Since these are normed they should look somewhat Gaussian
        vmin, vmax = run_args['feature_normed_range']
        distributions, dist_bin_edges = np.apply_along_axis(lambda x: np.histogram(x, bins=50, range=[vmin,vmax], density=True), 0, features)
        clustering['distributions'] = distributions
        clustering['dist_bin_edges'] = dist_bin_edges

        # Output results
        ########################################

        # Save cluster results
        outfile = self.get_outfile(basename, output_dir, ext=run_args['file_extension'])
        results['files_saved'] = [
            { 'filename': '{}'.format(outfile) ,
             'description' : 'results of cluster analysis' ,
             'type' : 'data'
            } ,
            ]
        with open(outfile, 'wb') as fout:
            pickle.dump(clustering, fout)

        # Output images
        if run_args['verbosity']>=4:
            print('  Generating PCA 3D projection')

        # Pick a color for each cluster
        norm = mpl.colors.Normalize(vmin=0, vmax=results['num_clusters']-1)
        cmap = mpl.cm.jet
        #cmap = cmap_vge
        m = mpl.cm.ScalarMappable(norm=norm, cmap=cmap)
        cluster_colors = [m.to_rgba(index) for index in range(results['num_clusters'])]

        pca = PCA(n_components=3)
        coordinates = pca.fit_transform(features)
        outfile = self.get_outfile(basename, output_dir, ext='-{}.png'.format(run_args['cluster_method']))
        self.plot_pca(outfile, coordinates, assignment, cluster_colors, **run_args)

        if run_args['verbosity']>=4:
            print('  Generating map of distances')

        outfile = self.get_outfile('distances', output_dir, ext='-{}.png'.format(run_args['cluster_method']))
        self.plot_distances(outfile, clustering['cluster_center_distances'], cluster_colors, **run_args)

        if run_args['verbosity']>=4:
            print('  Generating cluster images')

        self.plot_clusters(output_dir, clustering['cluster_centers'], clustering['cluster_centers_orig'], clustering['sort_indices'], distributions, dist_bin_edges, flakes, features, assignment, rescale=rescale, **run_args)

        return results

    def plot_pca(self, outfile, coordinates, assignment, cluster_colors, **run_args):

        flake_colors = [cluster_colors[index] for index in assignment]

        # Centroid of each cluster (in PCA coordinates)
        num_clusters = np.max(assignment)+1
        cluster_coordinates = np.zeros([num_clusters, coordinates.shape[1]])
        for i in range(num_clusters):
             cluster_i = np.nonzero(assignment==i)[0]
             cluster_coordinates[i,:] = np.mean(coordinates[cluster_i,:], axis=0)
        cluster_index = range(cluster_coordinates.shape[0])

        plt.rcParams['xtick.labelsize'] = 8
        plt.rcParams['ytick.labelsize'] = 8
        plt.rcParams['axes.labelsize'] = 12
        plt.rcParams['lines.markersize'] = 5

        cmap = run_args['cmap'] if 'cmap' in run_args else 'jet'
        alpha = 0.12

        self.fig = plt.figure(figsize=(10,10))
        self.fig.subplots_adjust(left=0.08, right=0.95, bottom=0.08, top=0.95, hspace=0.15, wspace=0.15)

        self.ax = self.fig.add_subplot(2,2,2 , projection='3d')
        self.ax.scatter(coordinates[:,0], coordinates[:,1], coordinates[:,2], c=flake_colors, alpha=0.3)
        self.ax.set_xlabel('$\mathrm{PCA}_1$', labelpad=-4)
        self.ax.set_ylabel('$\mathrm{PCA}_2$', labelpad=-4)
        self.ax.set_zlabel('$\mathrm{PCA}_3$', labelpad=-2)
        self.ax.tick_params(axis='both', which='major', pad=-1)
        self.ax.view_init(elev=30, azim=45-90)

        self.ax = self.fig.add_subplot(2,2,1)
        self.ax.scatter(coordinates[:,0], coordinates[:,2], c=flake_colors, edgecolors=None, alpha=alpha)
        self.ax.set_xlabel('$\mathrm{PCA}_1$')
        self.ax.set_ylabel('$\mathrm{PCA}_3$')
        self.overlay_cluster_number(cluster_coordinates, cluster_index, 0, 2, cluster_colors)
        xi, xf, yi, yf = self.ax.axis()
        self.ax.text(xi,yf, '{:,d} flakes in {} clusters'.format(len(assignment), len(cluster_colors)), size=10, verticalalignment='top', horizontalalignment='left', alpha=0.5)

        self.ax = self.fig.add_subplot(2,2,3)
        self.ax.scatter(coordinates[:,0], coordinates[:,1], c=flake_colors, cmap=cmap, edgecolors=None, alpha=alpha)
        self.ax.set_xlabel('$\mathrm{PCA}_1$')
        self.ax.set_ylabel('$\mathrm{PCA}_2$')
        self.overlay_cluster_number(cluster_coordinates, cluster_index, 0, 1, cluster_colors)

        self.ax = self.fig.add_subplot(2,2,4)
        self.ax.scatter(coordinates[:,2], coordinates[:,1], c=flake_colors, cmap=cmap, edgecolors=None, alpha=alpha)
        self.ax.set_xlabel('$\mathrm{PCA}_3$')
        self.ax.set_ylabel('$\mathrm{PCA}_2$')
        self.overlay_cluster_number(cluster_coordinates, cluster_index, 2, 1, cluster_colors)

        plt.savefig(outfile, dpi=300)
        plt.close()

    def overlay_cluster_number(self, cluster_coordinates, cluster_index, coord1, coord2, cluster_colors):

        r = 0.3 # r=1 means no fade (strong color), r=0 means fully faded (appears white)
        cluster_colors_a = [ [ 1-(1-c[0])*r, 1-(1-c[1])*r, 1-(1-c[2])*r, c[3]] for c in cluster_colors]
        self.ax.scatter(cluster_coordinates[:,coord1], cluster_coordinates[:,coord2], s=25, c=cluster_colors_a, edgecolor=cluster_colors, alpha=1)

        for i in range(cluster_coordinates.shape[0]):
            self.ax.text(cluster_coordinates[i, coord1], cluster_coordinates[i, coord2], '{}'.format(i), size=3, horizontalalignment='center', verticalalignment='center')

    def plot_distances(self, outfile, cluster_center_distances, cluster_colors, plot_buffers=[0.15,0.05,0.15,0.05], **run_args):

        plt.rcParams['xtick.labelsize'] = 15
        plt.rcParams['ytick.labelsize'] = 15
        plt.rcParams['axes.labelsize'] = 20
        plt.rcParams['lines.markersize'] = 5

        self.fig = plt.figure( figsize=(8,8), facecolor='white' )
        left_buf, right_buf, bottom_buf, top_buf = plot_buffers
        fig_width = 1.0-right_buf-left_buf
        fig_height = 1.0-top_buf-bottom_buf
        self.ax = self.fig.add_axes( [left_buf, bottom_buf, fig_width, fig_height] )

        #plt.figtext(0,1, 'distances between clusters (in the feature space)', size=15, verticalalignment='top', horizontalalignment='left')
        self.ax.imshow(cluster_center_distances, cmap='viridis')

        self.ax.set_xlabel('cluster index')
        self.ax.set_ylabel('cluster index')

        xi, xf, yi, yf = self.ax.axis()

        s = 0.02
        n = len(cluster_colors)
        self.axt = self.fig.add_axes( [left_buf, bottom_buf+fig_height, fig_width, s] )
        self.axt.scatter(range(n), np.ones(n), c=cluster_colors)
        if n<160:
            for i in range(n):
                self.axt.text(i, 1, '{}'.format(i), size=4, horizontalalignment='center', verticalalignment='center')
        self.axt.axis([xi, xf, 0, 2])

        self.axt.axes.get_xaxis().set_visible(False)
        self.axt.axes.get_yaxis().set_visible(False)

        self.axr = self.fig.add_axes( [left_buf+fig_width, bottom_buf, s, fig_height] )
        self.axr.scatter(np.ones(n), range(n), c=cluster_colors)
        if n<80:
            for i in range(n):
                self.axr.text(1, i, '{}'.format(i), size=4, horizontalalignment='center', verticalalignment='center')
        self.axr.axis([0, 2, yi, yf])

        self.axr.axes.get_xaxis().set_visible(False)
        self.axr.axes.get_yaxis().set_visible(False)

        plt.savefig(outfile, dpi=300)

    def plot_clusters(self, output_dir, cluster_centers, cluster_centers_orig, sort_indices, distributions, dist_bin_edges, flakes, flake_features, assignment, rescale=None, plot_buffers=[0.01,0.0,0.0,0.045], **run_args):

        plt.rcParams['xtick.labelsize'] = 15
        plt.rcParams['ytick.labelsize'] = 15
        plt.rcParams['axes.labelsize'] = 20
        plt.rcParams['lines.markersize'] = 5

        #for i, feature_vector in enumerate(cluster_centers[:1]): # for testing
        for i, feature_vector in enumerate(cluster_centers):

            # i # [sorted indexing]
            # feature_vector # in (normed) feature space coordinates [sorted indexing]
            feature_vector_orig = cluster_centers_orig[i] # in (original) feature space coordinates [sorted indexing]

            i_before_sort = sort_indices[i] # [unsorted indexing]

            cluster_i = np.nonzero(assignment==i_before_sort)[0] # indices [in unsorted indexing] of all flakes matching this cluster
            flakes_cluster = np.asarray(flakes)[cluster_i] # flakes matching this cluster
            features_cluster = flake_features[cluster_i] # feature vectors matching this cluster

            self.plot_cluster(output_dir, '{:03d}'.format(i), feature_vector, feature_vector_orig, flakes_cluster, features_cluster, distributions, dist_bin_edges, rescale=rescale, plot_buffers=plot_buffers, **run_args)

    def plot_cluster(self, output_dir, cluster_name, feature_vector, feature_vector_orig, flakes_cluster, features_cluster, distributions, dist_bin_edges, rescale=None, plot_buffers=[0.01,0.0,0.0,0.045], **run_args):
        ''' Outputs an image showing representative flakes for this cluster.

        flakes_cluster, features_cluster : The subset of flakes (and their features) for this cluster.
        feature_vector, feature_vector_orig : The centroid of this cluster (average of features).
        distributions, dist_bin_edges : The feature distributions (for all flakes).
        '''

        num_flakes = len(flakes_cluster)

        # Sort flakes by their distance from the cluster centroid (which is located at position "feature_vector")
        distances = cdist(features_cluster, [feature_vector], metric='euclidean')[:,0]
        sort_indices = np.argsort(distances)
        flakes_cluster = flakes_cluster[sort_indices]
        features_cluster = features_cluster[sort_indices]
        distances = distances[sort_indices]

        if run_args['verbosity']>=5:
            print('    image for cluster {} ({:,d} flakes)'.format(cluster_name, num_flakes))

        # Output a summary (central, generic, peripheral)
        ########################################
        self.fig = plt.figure( figsize=(8,8), facecolor='white' )
        fea_w, fea_h = 0.04, 0.95 # Size of features graphs in sidebar

        plt.figtext(0,1, 'cluster {} ({:,d} flakes)'.format(cluster_name, num_flakes), size=20, verticalalignment='top', horizontalalignment='left')

        # Sidebar that shows the feature vector for the centroid of this cluster
        self._plot_cluster_sidebar(feature_vector, feature_vector_orig, features_cluster, distributions, dist_bin_edges, fea_w=fea_w, fea_h=fea_h, **run_args)

        # Images of example flakes for this cluster
        self._plot_cluster_main(flakes_cluster, distances, fea_w=fea_w, fea_h=fea_h, plot_buffers=plot_buffers, **run_args)

        outfile = os.path.join(output_dir, 'cluster-{}-{}.png'.format(run_args['cluster_method'], cluster_name))
        plt.savefig(outfile, dpi=300)
        plt.close(self.fig.number)

        if 'output_all' in run_args and run_args['output_all']:
            # Output a summary (central, generic, peripheral)
            ########################################
            nrows, ncols = 8, 7
            num_per_page = nrows*ncols
            num_pages = int(np.ceil(num_flakes/num_per_page))
            for page in range(num_pages):

                num_this_page = num_per_page
                if page==(num_pages-1): # Last page
                    num_this_page = num_flakes - (num_pages-1)*num_per_page

                idx_start = page*num_per_page
                idx_end = idx_start+num_this_page

                if run_args['verbosity']>=5:
                    print('    page {:d} for cluster {} ({:,d}/{:,d} flakes)'.format(page+1, cluster_name, num_this_page, num_flakes))

                self.fig = plt.figure( figsize=(8,8), facecolor='white' )
                plt.figtext(0,1, 'cluster {} ({:,d}/{:,d} flakes)'.format(cluster_name, num_this_page, num_flakes), size=20, verticalalignment='top', horizontalalignment='left')

                # Sidebar that shows the feature vector for the centroid of this cluster
                if rescale is not None:
                    # Since we have access to the scaling between original coordinates for feature vector
                    # and the rescale coordinates (avg=0, std=1), we can compute the sidebar for just the
                    # flakes being displayed.

                    # There are two equivalent ways to get the information for this subset of flakes (this page of results)

                    # Method 1: Load features_orig for these flakes, and transform them
                    #flakes_page = flakes_cluster[idx_start:idx_end]
                    #features_orig = self.load_features(flakes_page, **run_args)
                    #features_rescaled = rescale.transform(features_orig)

                    # Method 2: Select subset of rescaled features, and inverse_transform them
                    features_rescaled = features_cluster[idx_start:idx_end]
                    features_orig = rescale.inverse_transform(features_rescaled)

                    # Compute centroid for this subset of flakes (this page of results)
                    feature_vector_orig = np.average(features_orig, axis=0)
                    feature_vector = rescale.transform( [feature_vector_orig] )[0]

                    self._plot_cluster_sidebar(feature_vector, feature_vector_orig, features_rescaled, distributions, dist_bin_edges, fea_w=fea_w, fea_h=fea_h, **run_args)

                else:
                    self._plot_cluster_sidebar(feature_vector, feature_vector_orig, features_cluster, distributions, dist_bin_edges, fea_w=fea_w, fea_h=fea_h, **run_args)

                self._plot_cluster_page(idx_start, flakes_cluster, distances, fea_w, fea_h, plot_buffers, nrows, ncols, **run_args)

                outfile = os.path.join(output_dir, 'cluster-{}-page{:03d}.png'.format(run_args['cluster_method'], page+1))
                plt.savefig(outfile, dpi=300)
                plt.close(self.fig.number)

    def _plot_cluster_page(self, idx, flakes_cluster, distances, fea_w, fea_h, plot_buffers, nrows, ncols, **run_args):

        # The total area we have available for plotting flakes
        left_buf, right_buf, bottom_buf, top_buf = plot_buffers
        left_buf += fea_w*( 2.2 + 2.3 )
        fig_width = 1.0-right_buf-left_buf
        fig_height = 1.0-top_buf-bottom_buf

        w = fig_width/ncols
        ystart = bottom_buf+fig_height
        for irow in range(nrows):
            for icol in range(ncols):
                ax_pos = [left_buf+icol*w, ystart-(irow+1)*w, w, w]
                if idx<len(flakes_cluster):
                    self._plot_flake_image(ax_pos, flakes_cluster[idx], distances[idx], **run_args)
                idx += 1

    def _plot_cluster_main(self, flakes_cluster, distances, fea_w, fea_h, plot_buffers, **run_args):

        # The total area we have available for plotting flakes
        left_buf, right_buf, bottom_buf, top_buf = plot_buffers
        left_buf += fea_w*( 2.2 + 2.3 )
        fig_width = 1.0-right_buf-left_buf
        fig_height = 1.0-top_buf-bottom_buf
        #self.ax = self.fig.add_axes( [left_buf, bottom_buf, fig_width, fig_height] )

        # Central flakes
        nrows, ncols = 3, 7
        w = fig_width/ncols
        idx = 0
        ystart = bottom_buf+fig_height
        plt.figtext(left_buf, ystart, 'central', size=8, verticalalignment='bottom', horizontalalignment='left')
        for irow in range(nrows):
            for icol in range(ncols):
                ax_pos = [left_buf+icol*w, ystart-(irow+1)*w, w, w]
                if idx<len(flakes_cluster):
                    self._plot_flake_image(ax_pos, flakes_cluster[idx], distances[idx], **run_args)
                idx += 1

        # Generic flakes
        if idx<len(flakes_cluster):
            ystart = ystart-nrows*w - 0.015
            #nrows, ncols = 2, 6
            w = fig_width/ncols
            idx = max( int( np.clip( len(flakes_cluster)/2, idx, len(flakes_cluster)-nrows*ncols ) ), idx )
            plt.figtext(left_buf, ystart, 'generic', size=8, verticalalignment='bottom', horizontalalignment='left')
            for irow in range(nrows):
                for icol in range(ncols):
                    ax_pos = [left_buf+icol*w, ystart-(irow+1)*w, w, w]
                    if idx<len(flakes_cluster):
                        self._plot_flake_image(ax_pos, flakes_cluster[idx], distances[idx], **run_args)
                    idx += 1

        # Peripheral flakes
        if idx<len(flakes_cluster):
            ystart = ystart-nrows*w - 0.015
            nrows, ncols = 2, 7
            w = fig_width/ncols
            idx = max( len(flakes_cluster)-nrows*ncols, idx )
            plt.figtext(left_buf, ystart, 'peripheral', size=8, verticalalignment='bottom', horizontalalignment='left')
            for irow in range(nrows):
                for icol in range(ncols):
                    ax_pos = [left_buf+icol*w, ystart-(irow+1)*w, w, w]
                    if idx<len(flakes_cluster):
                        self._plot_flake_image(ax_pos, flakes_cluster[idx], distances[idx], **run_args)
                    idx += 1

    def _plot_cluster_sidebar(self, feature_vector, feature_vector_orig, features_cluster, distributions, dist_bin_edges, fea_w, fea_h, **run_args):
        # Sidebar that shows the feature vector for the centroid of this cluster

        vmin, vmax = run_args['feature_normed_range']

        self.ax = self.fig.add_axes( [0.0, 0, fea_w, fea_h] )

        vector = np.asarray([feature_vector]).transpose()
        self.ax.imshow(vector, cmap='inferno', aspect='auto', vmin=vmin, vmax=vmax)
        self.ax.set_xticklabels([])
        self.ax.set_yticklabels([])

        xi, xf, yi, yf = self.ax.axis()
        if len(feature_vector)<80:
            for ifea, fea in enumerate(feature_vector):
                if fea<0:
                    color = 'white'
                else:
                    color = 'k'
                self.ax.text((xi+xf)*0.5, ifea, '{:.2f}'.format(fea), color=color, size=8, verticalalignment='center', horizontalalignment='center')

                self.ax.text(xf, ifea, '{:.3g}'.format(feature_vector_orig[ifea]), size=6, verticalalignment='center', horizontalalignment='left')

                # Miniature histogram (of the entire distribution)
                axc = self.fig.add_axes( [fea_w*2.2, fea_h-(ifea+1)*fea_h/len(feature_vector), fea_w*2.3, fea_h/len(feature_vector)] )
                w = dist_bin_edges[ifea][1]-dist_bin_edges[ifea][0]
                axc.bar( dist_bin_edges[ifea][:-1]+0.5*w, distributions[ifea], width=w, color='b', alpha=0.3 )
                plt.xlim(vmin,vmax)

                # Overlay the histogram for this cluster
                distribution, dist_bin_edge = np.histogram(features_cluster[:,ifea], bins=50, range=[vmin,vmax], density=True)
                distribution *= np.max(distributions[ifea])/np.max(distribution)
                #axc.bar( dist_bin_edge[:-1]+0.5*w, distribution, width=w, color='purple', alpha=0.2 )
                axc.plot( dist_bin_edge[:-1]+0.5*w, distribution, '-', color='purple', linewidth=0.8, alpha=0.3 )

                axc.axvline(fea, color='purple', linewidth=1)
                if fea<vmin:
                    axc.axvline(vmin, color='purple', linewidth=4)
                elif fea>vmax:
                    axc.axvline(vmax, color='purple', linewidth=4)

                axc.axes.get_xaxis().set_visible(False)
                axc.axes.get_yaxis().set_visible(False)

                if len(self.feature_names)==len(feature_vector):
                    axc.text(vmin, np.max(distributions[ifea]), self.feature_names[ifea], size=4, verticalalignment='top', horizontalalignment='left', alpha=0.25)
                axc.text(vmax, np.max(distributions[ifea]), '{:d}'.format(ifea), size=4, verticalalignment='top', horizontalalignment='right', alpha=0.25)

    def _plot_flake_image(self, ax_pos, flake_i, distance, **run_args):

        # Load parent image
        filename = flake_i['infile'].replace('\\', '/') # String replace in case files were saved on another platform.
        img = plt.imread(filename)
        h, w, c = img.shape

        # Define image sub-region that has the flake in it
        y1, y2, x1, x2 = flake_i['bbox']
        # Make the crop border a bit bigger than the flake bounding box
        box_size = (1+run_args['bbox_pad'])*max( abs(x2-x1), abs(y2-y1) )
        x1p = int(np.clip((x1+x2)*0.5 - box_size/2, 0, w))
        x2p = int(np.clip((x1+x2)*0.5 + box_size/2, 0, w))
        y1p = int(np.clip((y1+y2)*0.5 - box_size/2, 0, h))
        y2p = int(np.clip((y1+y2)*0.5 + box_size/2, 0, h))
        box = y1p, y2p, x1p, x2p

        # Adjust image of flake
        flake = img[y1p:y2p , x1p:x2p, :]
        in_range = self.get_in_range(img, run_args['image_contrast'], **run_args)
        flake = skimage.exposure.rescale_intensity(flake, in_range=in_range, out_range='dtype')

        # Plot flake
        self.ax = self.fig.add_axes(ax_pos)
        self.ax.axes.get_xaxis().set_visible(False)
        self.ax.axes.get_yaxis().set_visible(False)

        self.ax.imshow(flake)

        xi, xf, yi, yf = self.ax.axis()
        yc, xc = flake_i['center_of_mass']
        s = '{}\nflake{:03d}\n({}, {})'.format(flake_i['infile'], flake_i['index'], int(xc), int(yc))
        self.ax.text(xi, yf, s, color='white', size=3, verticalalignment='top', horizontalalignment='left')

        self.ax.text(xi, yi, '${:.1f} \, \mathrm{{\mu m}}$'.format(flake_i['radius_um']), color='r', size=5, verticalalignment='bottom', horizontalalignment='left')

        self.ax.text((xi+xf)*0.5, yi, '{:.1f}'.format(distance), color='white', size=2, verticalalignment='bottom', horizontalalignment='center')

        self.ax.text(xf, yi, '{:.3f}'.format(flake_i['flake_contrast']), color='orange', size=3, verticalalignment='bottom', horizontalalignment='right')

        # Various overlays on the flake
        xc -= x1p
        yc -= y1p
        size = flake_i['radius_pixels']

        if run_args['overlays']>=1:
            c = flake_i['contour']
            xs = (c[:,0] - x1p)
            ys = (c[:,1] - y1p)
            self.ax.plot(xs, ys, '-', linewidth=0.6, color='r', dashes=[4,1], alpha=0.2)

        if run_args['overlays']>=7:
            c = flake_i['convex_hull']
            xs = (c[:,1] - x1p)
            ys = (c[:,0] - y1p)
            self.ax.plot(xs, ys, '-', linewidth=0.5, color='g', alpha=0.5)

        if run_args['overlays']>=5:
            rect = patches.Rectangle( ((x1-x1p), (y1-y1p)), (x2-x1), (y2-y1), linewidth=1.0, edgecolor='orange', facecolor='none', alpha=0.5)
            self.ax.add_patch(rect)

        if run_args['overlays']>=3:
            # Cross hair and circle
            rect = patches.Rectangle( (xc-size/2, yc), size, 0, linewidth=0.6, edgecolor='r', facecolor='none', alpha=0.3) # Horizontal bar
            self.ax.add_patch(rect)
            rect = patches.Rectangle( (xc, yc-size/2), 0, size, linewidth=0.6, edgecolor='r', facecolor='none', alpha=0.3) # Vertical bar
            self.ax.add_patch(rect)

        if run_args['overlays']>=5:
            # Circle overlay denoting size
            circ = patches.Circle(xy=(xc,yc), radius=size, linewidth=0.6, edgecolor='r', facecolor='none', alpha=0.3)
            self.ax.add_patch(circ)

    def get_in_range(self, data, im_contrast, image_contrast_trim=None, **run_args):

        if image_contrast_trim is not None:
            image_contrast_trim = np.clip(image_contrast_trim, 0, 0.95)

            avg = np.average(data)
            avg /= 255
            amt = image_contrast_trim
            im_contrast = ( avg*amt , 1.0-(1.0-avg)*amt )

        in_range = ( im_contrast[0]*255, im_contrast[1]*255 )

        return in_range

class select_flakes(cluster):

    def __init__(self, name='select_flakes', **kwargs):

        self.name = self.__class__.__name__ if name is None else name

        self.default_ext = '.pkl'
        self.run_args = {
                        'file_extension' : '.pkl',
                        'force' : False,
                        'verbosity' : 3,
                        'num_jobs' : None,
                        'num_clusters' : 20,
                        'cluster_method' : 'selection',
                        'features' : 'all', # 'shape', 'color', 'all'
                        'feature_normed_range' : [-2, +2], # range for plotting the normed features
                        'bbox_pad' : 0.5,
                        'image_contrast' : (0, 1),
                        'image_contrast_trim' : None,
                        'overlays' : 3,
                        }
        self.run_args.update(kwargs)

        # WARNING: This association of features names is hard-coded, and is thus contingent
        # on the current implementation of Protocols.py>flake_analysis
        self.feature_names_color = [
            'g contrast',
            'v contrast',
            'gray',
            'gray std',
            'H',
            'S',
            'V',
            'H std',
            'S std',
            'V std',
            'R',
            'G',
            'B',
            'R std',
            'G std',
            'B std',
            'entropy'
            ]
        self.feature_names_color = self.feature_names_color + ['{}_inner'.format(f) for f in self.feature_names_color]

        self.feature_names_shape = ['P/A'] + ['hist {}'.format(i) for i in range(15)] + ['fractal dimension']

    @run_default
    def run(self, datas, output_dir, basename, **run_args):

        results = {}

        # Load all flakes identified by "find_flakes" protocol
        flakes = self.load_flakes(datas, **run_args)
        if run_args['verbosity']>=4:
            print('  {:,d} flakes identified in {:d} images'.format(len(flakes), len(datas)))

        # Compute the rescaling of feature vectors
        features_all_orig = self.load_features(flakes, **run_args)
        rescale = StandardScaler()
        features_all_rescaled = rescale.fit_transform(features_all_orig)

        flakes_selected = self.select(flakes, features_all_orig, features_all_rescaled, **run_args)
        features_orig = self.load_features(flakes_selected, **run_args)

        feature_vector_orig = np.average(features_orig, axis=0)
        feature_vector = rescale.transform( [feature_vector_orig] )[0]
        features = rescale.transform(features_orig)

        if run_args['verbosity']>=4:
            print("  Selected {:,d} flakes using '{}'".format(len(flakes_selected), run_args['cluster_method']))

        clustering = self.load_clustering(basename=basename, output_dir=output_dir, features_rescaled=features, **run_args)

        self.plot_cluster(output_dir, cluster_name='selection', feature_vector=feature_vector, feature_vector_orig=feature_vector_orig, flakes_cluster=flakes_selected, features_cluster=features, distributions=clustering['distributions'], dist_bin_edges=clustering['dist_bin_edges'], rescale=rescale, **run_args)

        return results

    def extract_features(self, feature_name, flakes, flake_features, **run_args):
        # Extract the specified feature, returning a list of that feature
        # for the entire list of flakes

        # Handle special case of relative standard deviation
        if feature_name.endswith(' std_inner __relative'):
            if run_args['verbosity']>=5:
                print("    Computing {}".format(feature_name))

            name = feature_name[:-len(' std_inner __relative')]
            features = self.extract_features(name, flakes, flake_features, **run_args)
            features_std = self.extract_features('{} std_inner'.format(name), flakes, flake_features, **run_args)

            return features_std/features

        elif feature_name.endswith(' std __relative'):
            if run_args['verbosity']>=5:
                print("    Computing {}".format(feature_name))

            features = self.extract_features(feature_name[:-len(' std __relative')], flakes, flake_features, **run_args)
            features_std = self.extract_features(feature_name[:-len(' __relative')], flakes, flake_features, **run_args)

            return features_std/features

        # Check if it appears as value associated with each flake object
        if feature_name in flakes[0]:
            if run_args['verbosity']>=5:
                print("      Extracting {} from flakes".format(feature_name))
            return np.asarray( [ f[feature_name] for f in flakes ] )

        # Default: lookup in self.feature_names
        i = self.feature_names.index(feature_name)
        if run_args['verbosity']>=5:
            print("      Extracting {} from flake_features, index {}".format(feature_name, i))

        return flake_features[:,i]

    def select(self, flakes, flake_features_orig, flake_features_rescaled, **run_args):

        # Generate a list of boolean arrays, which are selecting flakes with
        # features within the specified range
        conditions = []
        for key, value in run_args['selection'].items():
            if run_args['verbosity']>=5:
                print("    Adding condition: {} between {} and {}".format(key, value[0], value[1]))

            if key.endswith(' __rescaled'):
                features = self.extract_features(key[:-len(' __rescaled')], flakes, flake_features_rescaled, **run_args)
            else:
                features = self.extract_features(key, flakes, flake_features_orig, **run_args)
            conditions.append( (features>=value[0]) )
            conditions.append( (features<=value[1]) )

        idx = np.where(np.all(conditions, axis=0))[0]

        flakes = np.asarray(flakes)[idx]

        if run_args['verbosity']>=3 and len(flakes)<1:
            print("WARNING: Selection criteria too restrictive. (No flakes meet criteria.)")

        return flakes


import os
from flask import Flask, render_template, request
import base64
from io import BytesIO
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import src.components.data_ingestion as DI
from src.components.model_trainer import modelTrain
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.config["UPLOAD_FOLDER"] = os.path.abspath(os.path.join(os.path.dirname(__file__), 'static', 'uploads'))
content_dir = DI.default_content_dir
style_dir = DI.default_style_dir

@app.route('/')
def index():
    # Get content and style image filenames from src/components/data directory
    content_images = [f for f in os.listdir(content_dir) if f.endswith('.jpg' or '.png' or '.jpeg')]
    style_images = [f for f in os.listdir(style_dir) if f.endswith('.jpg' or '.png' or '.jpeg')]

    return render_template('index.html', content_images=content_images, style_images=style_images)

@app.route('/transfer', methods=['POST'])
def transfer_style():
    # Retrieve user input from the form
    epochs = int(request.form['epochs'])
    learning_rate = float(request.form['learningRate'])
    alpha = float(request.form['alpha'])
    beta = float(request.form['beta'])

    selected_source = request.form.get("imageSource")
    content_image = request.form.get('contentImage')
    style_image = request.form.get('styleImage')

    if selected_source == 'default':
        content_image_path = os.path.join(content_dir, content_image)
        style_image_path = os.path.join(style_dir, style_image)

    elif selected_source == 'custom_image':
        custom_content = request.files.get('customContentImage')
        content_image_filename = secure_filename(custom_content.filename)
        content_image_path = os.path.join(app.config['UPLOAD_FOLDER'], content_image_filename)
        os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
        print("Content Image Path:", content_image_path)
        custom_content.save(content_image_path)

        style_image_path = os.path.join(style_dir, style_image)

    elif selected_source == 'custom_style':
        custom_style = request.files.get('customStyleImage')
        style_image_filename = secure_filename(custom_style.filename)

        style_image_path = os.path.join(app.config['UPLOAD_FOLDER'], style_image_filename)
        print("Style Image Path:", style_image_path)
        os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
        custom_style.save(style_image_path)

        content_image_path = os.path.join(content_dir, content_image)

    elif selected_source == 'custom':
        custom_content = request.files.get('customContentImage')
        content_image_filename = secure_filename(custom_content.filename)
        content_image_path = os.path.join(app.config['UPLOAD_FOLDER'], content_image_filename)
        os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
        print("Content Image Path:", content_image_path)
        custom_content.save(content_image_path)

        custom_style = request.files.get('customStyleImage')
        style_image_filename = secure_filename(custom_style.filename)
        style_image_path = os.path.join(app.config['UPLOAD_FOLDER'], style_image_filename)
        print("Style Image Path:", style_image_path)
        os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
        custom_style.save(style_image_path)

    # Perform style transfer
    test = modelTrain(content_image_path, style_image_path)
    generated_image = test.train(epochs=epochs, lr=learning_rate, alpha=alpha, beta=beta)

    # Convert the generated image to base64 and pass it to the template
    buffer = BytesIO()
    plt.imshow(generated_image)
    plt.axis('off')
    plt.savefig(buffer, format='png', bbox_inches='tight', pad_inches=0)
    buffer.seek(0)
    img_str = base64.b64encode(buffer.getvalue()).decode('utf-8')

    return render_template('result.html', img_data=img_str)

if __name__ == "__main__":
    app.run(debug=True)


import datetime
import os
import random
import string
from datetime import datetime

import requests
from boto3 import Session
from django.conf import settings
from django.conf.global_settings import MEDIA_ROOT

from market_backend.apps.accounts.models import Media
from market_backend.v0.accounts import serializers

class AccountsUtils:
    """
    Utility methods related to Accounts Application
    """

    @staticmethod
    def get_user_full_name(user):
        if isinstance(user, list):
            user_name_list = ''
            for i, _ in enumerate(user):
                if i != 0:
                    user_name_list += ' / '
                if _.first_name or _.last_name:
                    user_name_list += "{} {}".format(_.first_name, _.last_name)
                    user_name_list += "{}".format(_.username.split('@')[0])
            return user_name_list
        if user.first_name or user.last_name:
            return "{} {}".format(user.first_name, user.last_name)
        return "{}".format(user.username.split('@')[0])

    @staticmethod
    def get_readable_user_type(type):
        return type.replace('_', ' ').lower().capitalize()

class FileUploadUtils(object):
    @staticmethod
    def getFileKey():
        return ''.join(
            random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(50))

    @staticmethod
    def deleteFile(key):
        media = Media.objects.get(id=key)

        session = Session(aws_access_key_id=settings.AWS_ACCESS_KEY,
                          aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
                          region_name=settings.AWS_REGION_NAME)
        s3 = session.resource('s3')
        my_bucket = s3.Bucket(settings.AWS_BUCKET_NAME)
        response = my_bucket.delete_objects(
            Delete={
                'Objects': [
                    {
                        'Key': media.key
                    }
                ]
            }
        )
        media.delete()
        return response

    @staticmethod
    def getFileName(key):
        try:
            file = Media.objects.get(key=key)
            return file.file_name
        except Exception as e:
            print(e)
            return None

    @staticmethod
    def getContentType(extension, url=None):
        if extension == 'pdf':
            return 'application/pdf'
        elif extension == 'png':
            return 'image/png'
        elif extension == 'jpeg' or extension == 'jpg':
            return 'image/jpeg'
        else:
            return 'image/jpeg'

    @staticmethod
    def uploadFile(url):
        filename = url.split("/")[-1]
        fileextension = filename.split('.')[1]
        file = requests.get(url).content
        filepath = os.path.join(MEDIA_ROOT, filename)
        with open(filepath, 'wb') as destination:
            destination.write(file)
        file = open(filepath, 'rb')
        extension = FileUploadUtils.getContentType(fileextension)
        valid_file = True
        if extension is None:
            valid_file = False
        session = Session(aws_access_key_id=settings.AWS_ACCESS_KEY,
                          aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
                          region_name=settings.AWS_REGION_NAME)
        s3 = session.resource('s3')
        file_key = FileUploadUtils.getFileKey()
        if valid_file:
            res = s3.Bucket(settings.AWS_BUCKET_NAME).put_object(Key=file_key, Body=file, ContentType=extension,
                                                                 ACL='public-read')
            data = {'key': file_key, 'file_name': filename, 'is_link': True}
            serializer = serializers.CreateFileUploadSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
            if os.path.isfile(filepath):
                os.remove(filepath)
            media = Media.objects.get(key=file_key)
            return media
        else:
            return None

    @staticmethod
    def upload_file_by_file(file):
        milli_sec = str(datetime.datetime.now())
        filename = str(milli_sec) + '.pdf'
        print(file)
        session = Session(aws_access_key_id=settings.AWS_ACCESS_KEY,
                          aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
                          region_name=settings.AWS_REGION_NAME)
        s3 = session.resource('s3')
        file_key = FileUploadUtils.getFileKey()
        res = s3.Bucket(settings.AWS_BUCKET_NAME).put_object(Key=file_key, Body=file, ContentType='application/pdf',
                                                             ACL='public-read')
        data = {'key': file_key, 'file_name': filename, 'is_link': False}
        serializer = serializers.CreateFileUploadSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
        media = Media.objects.get(key=file_key)
        return media

    @staticmethod
    def get_url_from_media_object(media):
        return settings.AWS_S3_BASE_LINK + media.key


#!/usr/bin/env python3

############
## https://gist.github.com/DevBOFH/7bd65dbcb945cdfce42d21b1b6bc0e1b
############
##
##

description = 'Terraform workspace tool. This tool can be used to perform CRUD operations on Terraform Cloud via their public API.'
version = "0.0.1"

import os
import re
import sys
import requests
import argparse
import json

ORGANIZATION = "TF_CLOUD_ORG_NAME"
HEADERS = {"Content-Type": "application/vnd.api+json"}

def load_api_credentials(rc_path="~/.terraformrc"):
    with open(os.path.expanduser(rc_path)) as f:
        m = re.search(r'token = "([^"]+)"', f.read())

    if not m:
        raise RuntimeError(f"Unable to load credentials from {rc_path}")
    else:
        HEADERS["Authorization"] = f"Bearer {m.group(1)}"

def new_workspace(workspace_name):
    PAYLOAD = {'data': {'attributes': {'name': workspace_name}, 'type': 'workspaces'}}
    req = requests.post(
        f"https://app.terraform.io/api/v2/organizations/{ORGANIZATION}/workspaces",
        json=PAYLOAD,
        headers=HEADERS,
    )

    try:
        req.raise_for_status()
    except requests.exceptions.HTTPError as err:
        print (str(err))
        sys.exit(2)

def show_workspace(workspace_name):
    req = requests.get(
        f"https://app.terraform.io/api/v2/organizations/{ORGANIZATION}/workspaces/{workspace_name}",
        headers=HEADERS,
    )

    try:
        req.raise_for_status()
    except requests.exceptions.HTTPError as err:
        sys.exit(0)

    pretty_json = json.loads(req.text)
    print (json.dumps(pretty_json, indent=2))

def configure_workspace_by_name(workspace_name):
    PAYLOAD = {"data": {"type": "workspaces", "attributes": {"operations": False}}}
    req = requests.patch(
        f"https://app.terraform.io/api/v2/organizations/{ORGANIZATION}/workspaces/{workspace_name}",
        json=PAYLOAD,
        headers=HEADERS,
    )

    try:
        req.raise_for_status()
    except requests.exceptions.HTTPError as err:
        print (str(err))
        sys.exit(2)

def configure_workspace_by_id(workspace_id):
    PAYLOAD = {"data": {"type": "workspaces", "attributes": {"operations": False}}}
    req = requests.patch(
        f"https://app.terraform.io/api/v2/workspaces/{workspace_id}",
        json=PAYLOAD,
        headers=HEADERS,
    )

    try:
        req.raise_for_status()
    except requests.exceptions.HTTPError as err:
        print (str(err))
        sys.exit(2)

def configure_all_workspaces():
    next_page = "https://app.terraform.io/api/v2/organizations/" + ORGANIZATION + "/workspaces"

    while next_page:
        page = requests.get(next_page, headers=HEADERS).json()

        for i in page["data"]:
            ws_id = i["id"]
            ws_name = i["attributes"]["name"]
            print(f"Updating {ws_name}")
            try:
                configure_workspace_by_id(i["id"])
            except requests.exceptions.HTTPError as exc:
                print(f"Error updating {ws_id} {ws_name}: {exc}", file=sys.stderr)

        next_page = page["links"].get("next")

def delete_workspace(workspace_name):
    PAYLOAD = {'data': {'attributes': {'name': workspace_name}, 'type': 'workspaces'}}
    req = requests.delete(
        f"https://app.terraform.io/api/v2/organizations/{ORGANIZATION}/workspaces/{workspace_name}",
        headers=HEADERS,
    )

    try:
        req.raise_for_status()
    except requests.exceptions.HTTPError as err:
        print (str(err))
        sys.exit(2)

if __name__ == "__main__":

    # init argparse
    parser = argparse.ArgumentParser(description = description)
    parser.add_argument("-V", "--version", help="show version", action="store_true")
    parser.add_argument("-n", "--new", help="create a new workspace")
    parser.add_argument("-c", "--configure", help="configure a workspace to use local execution mode")
    parser.add_argument("-ca", "--configureall", help="configure all workspaces to use local execution mode", action="store_true")
    parser.add_argument("-d", "--delete", help="delete a workspace")
    parser.add_argument("-s", "--show", help="show details of a workspace")

    # read arguments from the command line
    args = parser.parse_args()

    # load terraform cloud api token
    load_api_credentials()

    # check for --version or -V
    if args.version:
        print("Terraform Workspace Tool " + version )

    # check for --new or -n
    if args.new:
        try:
            new_workspace(args.new)
        except AssertionError as err:
            print (str(err))
            sys.exit(2)

    # check for --show or -s
    if args.show:
        try:
            show_workspace(args.show)
        except AssertionError as err:
            print (str(err))
            sys.exit(2)

    # check for --configure or -c
    if args.configure:
        try:
            configure_workspace_by_name(args.configure)
        except AssertionError as err:
            print (str(err))
            sys.exit(2)

    # check for --configureall or -ca
    if args.configureall:
        try:
            configure_all_workspaces()
        except AssertionError as err:
            print (str(err))
            sys.exit(2)

    # check for --delete or -d
    if args.delete:
        try:
            delete_workspace(args.delete)
        except AssertionError as err:
            print (str(err))
            sys.exit(2)

####################################
##
##


import sqlite3
from sqlite3 import Error

class Key:
    def __init__(self, key,content,info, database_path):
     if database_path!="":
      try:
        self.key = key
        self.database_path =database_path

        if not self.check_key_exists():
          if len(self.get_all__key(key))==0:
           if key!="":
            self.create_key(key,content,info)
        else:
            self.update_key(key,content,info)
      except Error as e:
          print(e)

    def check_key_exists(self):
        conn = sqlite3.connect(self.database_path)
        cursor = conn.cursor()

        cursor.execute("SELECT id FROM os WHERE key like '%'+?+'%'", (self.key,))
        exists = cursor.fetchone()

        conn.close()

        if exists is None:
            return False
        else:
            return True
    def get_all__key(self, key):
     a=[]
     if self.database_path!="":
      conn = sqlite3.connect(self.database_path)
      if key!="":
       cur = conn.cursor()
       cur.execute("SELECT * FROM os", () )

       rows = cur.fetchall()

       for row in rows:
        #print("s",row[1])
        if key in row[1]:
         a.append(row[1])
      return a
     return a;
    def find_key_content(self, key):
     conn = sqlite3.connect(self.database_path)
     a=[]
     if key!='':
      cur = conn.cursor()
      cur.execute("SELECT * FROM os WHERE key=?", (key,) )
      rows = cur.fetchall()
      for row in rows:
        #print("s",row[2])
        return row[2]
        if key in row[2]:
         a.append(row[2])
     return a
    def delete_key(self,key):
        try:
         conn = sqlite3.connect(self.database_path)
         cursor = conn.cursor()

         cursor.execute("DELETE FROM os WHERE key=?", (key,))

         conn.commit()
         conn.close()
        except Error as e:
         print(e)
    def create_key(self,key,content,info):
      try:
        conn = sqlite3.connect(self.database_path)
        cursor = conn.cursor()
        print(str(len(self.get_all__key(key))))
        if len(self.get_all__key(key))==0:
         cursor.execute("INSERT INTO os (key,content,info) VALUES (?,?,?)", (key,content,info))

        conn.commit()
        conn.close()
      except Error as e:
        print(e)

    def update_key(self,key,content,info):
      try:
        conn = sqlite3.connect(self.database_path)
        cursor = conn.cursor()
        cursor.execute("UPDATE os SET content=?,info=? WHERE key=?", (content,info,key))
        conn.commit()
        conn.close()
      except Error as e:
        print(e)

    def get_key(self):
        conn = sqlite3.connect(self.database_path)
        cursor = conn.cursor()

        cursor.execute("SELECT key FROM os WHERE key=?", (self.key,))


from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    cors = CORS(app)
    app.config["FLASK_DEBUG"] = True
    app.config['SECRET_KEY'] = 'secret-key-goes-here'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'

    from .models import Result, Patient, DeliveryReports

    db.init_app(app)
    with app.app_context():
        db.create_all()

    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app


# -*- coding: utf-8 -*-
from pathlib import Path

class Manager:

    def create_readme():
        root_path = Path(__file__).parent
        info ="""## حل سوالات کوئرا
برای دیدن صفحه ی اصلی هر سوال در سایت کوئرا میتوانید روی نام هر سوال کلیک کنید و یا در قسمت توضیحات روی PDF کلیک کنید.
showmeyourcode.ir
        """
        table_header = [
            "شماره سؤال",
            "نام سؤال",
            "youtube",
            "لینک جواب",
            "توضیحات",
            ]
        with open('README.md',"w",encoding="utf8") as main_readme:
            main_readme.write(info+'\n')
            main_readme.write("|"+"|".join(table_header)+"|"+'\n')
            main_readme.write("|-"*len(table_header)+"|"+'\n')
            index=1
            for question_path in root_path.glob(r"*/"):
                if not question_path.is_file() and not str(question_path.relative_to(root_path)).startswith("."):
                    main_readme.write(f"|{index}")
                    # main_readme.write("|"+str(question_path.relative_to(root_path)))

                    with open(str(question_path.joinpath("readme.md")),"r",encoding="utf8") as local_readme:
                        main_readme.write("|"+local_readme.readline().strip())
                        main_readme.write("|"+local_readme.readline().strip())

                    main_readme.write("|")
                    for language in question_path.glob("*"):
                        if language.is_dir():
                            readme_path = str(language.relative_to(root_path)).replace(' ','%20').replace('\\','/')
                            main_readme.write(f"[{str(language.relative_to(question_path))}]({readme_path}), ")

                    main_readme.write("|")
                    for local_readmes in question_path.glob("*.md"):
                        if local_readmes.is_file():
                            readme_path = str(local_readmes.relative_to(root_path)).replace(' ','%20').replace('\\','/')
                            main_readme.write(f"[readme]({readme_path}), ")

                    for pdfs in question_path.glob("*.pdf"):
                        if pdfs.is_file():
                            pdf = str(pdfs.relative_to(root_path)).replace(' ','%20').replace('\\','/')
                            main_readme.write(f"[pdf]({pdf}), ")
                    main_readme.write("|\n")

                    index+=1

if __name__ == "__main__":
    Manager.create_readme()


from google.cloud import vision

# with 開始から終了まで自動で実行してくれる
# rb read binaryモード　バイナリーモードを読み込む
# テキスト以外のデータ　主に画像や動画

# road.jpgを開いて読み込む
with open('./road.jpg', 'rb') as image_file:
    content = image_file.read()

# vision APIが扱える画像データに変換
image = vision.Image(content=content)

# annotation テキストや音声、画像などあらゆる形式のデータにタグ付けをする作業
# client データを扱う人、もの
# ImageAnnotatorClientのインスタンスを生成
annotater_client = vision.ImageAnnotatorClient()

response_data = annotater_client.label_detection(image=image)
labels = response_data.label_annotations

print('----RESULT----')
for label in labels:
    print(label.description, ':', round(label.score * 100, 2), '%')
print('----RESULT----')


from PyQt5.QtWidgets import QTableWidgetItem, QLabel, QFileDialog
from PyQt5.QtCore import  Qt
from pandas.tests.io.excel.test_xlrd import xlwt

from UI.resultWinUI import *
from algorithm import *
from UI.mainWinUI import *

class BrokerWin(Ui_MainWindow, QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.setupUi(self)
        self.setFixedSize(1100, 540)
        self.fizButton.clicked.connect(self.sendInputFiz)
        self.bizButton.clicked.connect(self.sendInputBiz)
        self.selectAll.clicked.connect(self.selectAllFiz)
        self.selectAll_2.clicked.connect(self.selectAllBiz)

    def sendInputFiz(self):
        banks.clear()
        black_list.clear()
        optional_fiz['Осуществление автоплатежей'] = self.autoPayments.isChecked()
        optional_fiz['Перевод за рубеж'] = self.foreignTransfer.isChecked()
        optional_fiz['Создание автоперевода'] = self.createAutoPayments.isChecked()
        optional_fiz['Новости системы банка онлайн'] = self.news.isChecked()
        optional_fiz['Автострахование'] = self.insuranceAuto.isChecked()
        optional_fiz['Страхование недвижимости'] = self.insuranceEstate.isChecked()
        optional_fiz['Страхование путешественников'] = self.insuranceTravellers.isChecked()
        optional_fiz['Страхование пассажиров'] = self.insurancePassangers.isChecked()
        optional_fiz['Наличие мобильного приложения'] = self.mobileApp.isChecked()
        optional_fiz['Открытие брокерского счета'] = self.brokerAccount.isChecked()
        ranked_fiz['Переводы на карту'] = self.transferToClient_fiz_SpinBox.value()
        ranked_fiz['Минимальная сумма вклада'] = self.depositSum_fiz_SpinBox.value()
        ranked_fiz['Процент по вкладу '] = self.persentDepozit_fiz_SpinBox.value()
        ranked_fiz['Сумма кредита'] = self.creditSum_fiz_SpinBox.value()
        ranked_fiz['Ставка кредита'] = self.percentCredit_fiz_SpinBox.value()
        ranked_fiz['Переводы на карты по номеру телефона'] = self.transferNumber_fiz_SpinBox.value()

        choose_necessary('fiz')
        choose_ranked('fiz')
        kind_of_sort = self.sort_fiz.currentText()
        # self.close()
        if kind_of_sort == "Пользовательскому рейтингу":
            self.Open = ResultWin("По рейтингу")
        elif kind_of_sort == "Кредитным условиям":
            self.Open = ResultWin("по кредиту")
        elif kind_of_sort == "Условиям по вкладам":
            self.Open = ResultWin("по вкладу")
        self.Open.show()

        # print(special_sort('По рейтингу'))

    def sendInputBiz(self):
        banks.clear()
        black_list.clear()
        optional_biz['Мобильное приложение'] = self.mobileApp_biz.isChecked()
        optional_biz['Торговый эквайринг'] = self.trade_biz.isChecked()
        optional_biz['Мобильный эквайринг'] = self.mobileTrade_biz.isChecked()
        optional_biz['Онлайн-бухгалтерия'] = self.onlineAccounting_biz.isChecked()
        optional_biz['Проверка контрагентов'] = self.checkAgents_biz.isChecked()
        optional_biz['Управление корпоративными картами'] = self.cards_biz.isChecked()
        optional_biz['Финансовая аналитика'] = self.analitics_biz.isChecked()
        optional_biz['Техподдержка клиентов 24/7'] = self.clientSupport_biz.isChecked()
        optional_biz['Персональный менеджер'] = self.personalManager_biz.isChecked()
        ranked_biz['Стоимость обслуживания'] = self.mounthPayment_biz_SpinBox.value()
        ranked_biz['% за снятие наличных'] = self.cashComission_biz_SpinBox.value()
        ranked_biz['% за внесение наличных'] = self.cashInputComission_biz_SpinBox.value()
        ranked_biz['Лимит перевода на карту физ.лица'] = self.transfer_biz_SpinBox.value()

        choose_necessary('biz')
        choose_ranked('biz')
        kind_of_sort = self.sort_biz.currentText()
        # self.close()
        if kind_of_sort == "Пользовательскому рейтингу":
            self.Open = ResultWin("По рейтингу")
        elif kind_of_sort == "Стоимости обслуживания":
            self.Open = ResultWin("По обслуживанию в месяц")
        self.Open.show()

    def selectAllFiz(self):
        self.autoPayments.setChecked(True)
        self.foreignTransfer.setChecked(True)
        self.createAutoPayments.setChecked(True)
        self.news.setChecked(True)
        self.insuranceAuto.setChecked(True)
        self.insuranceEstate.setChecked(True)
        self.insuranceTravellers.setChecked(True)
        self.insurancePassangers.setChecked(True)
        self.mobileApp.setChecked(True)
        self.brokerAccount.setChecked(True)

    def selectAllBiz(self):
        self.mobileApp_biz.setChecked(True)
        self.trade_biz.setChecked(True)
        self.mobileTrade_biz.setChecked(True)
        self.onlineAccounting_biz.setChecked(True)
        self.checkAgents_biz.setChecked(True)
        self.cards_biz.setChecked(True)
        self.analitics_biz.setChecked(True)
        self.clientSupport_biz.setChecked(True)
        self.personalManager_biz.setChecked(True)

class ResultWin(Ui_ResultWindow, QtWidgets.QMainWindow):

    def __init__(self, type_of_sort, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.setupUi(self)
        self.setFixedSize(930, 900)
        self.type_of_sort = type_of_sort
        self.showResult()
    def showResult(self):
        result = special_sort(self.type_of_sort)
        i = 0
        self.sites=[]
        information = pd.read_csv("files/banks_info.csv", encoding="cp1251", sep=";")
        for key in result.keys():
            for bank in result[key]:
                self.tableWidget.insertRow(i)
                label = QLabel()
                item = QTableWidgetItem(str(key))
                item.setTextAlignment(Qt.AlignHCenter)
                self.tableWidget.setItem(i, 0, item)
                self.tableWidget.setItem(i, 1, QTableWidgetItem(bank))
                self.sites.append(information[bank][0])
                label.setText(''+information[bank][0]+'')
                label.setOpenExternalLinks(True)
                self.tableWidget.setCellWidget(i, 2, label)
                self.tableWidget.setItem(i, 3, QTableWidgetItem(information[bank][1]))
                item=QTableWidgetItem(information[bank][2])
                item.setTextAlignment(Qt.AlignHCenter)
                self.tableWidget.setItem(i, 4, item)
                item = QTableWidgetItem(information[bank][3])
                item.setTextAlignment(Qt.AlignHCenter)
                self.tableWidget.setItem(i, 5, item)
                i += 1
        self.tableWidget.resizeColumnsToContents()
        self.importButton.clicked.connect(self.savefile)
        style = "::section {""background-color: #ffc02b; font:10pt; }"
        self.tableWidget.horizontalHeader().setStyleSheet(style)

    def savefile(self):
        filename, _ = QFileDialog.getSaveFileName(self, 'Save File', '', ".xls(*.xls)")
        wbk = xlwt.Workbook()
        sheet = wbk.add_sheet("sheet", cell_overwrite_ok=True)
        style = xlwt.XFStyle()

        model = self.tableWidget.model()
        for c in range(model.columnCount()):
            text = model.headerData(c, QtCore.Qt.Horizontal)
            sheet.write(0, c , text, style=style)

        for c in range(model.columnCount()):
            for r in range(model.rowCount()):
                text = model.data(model.index(r, c))
                sheet.write(r + 1, c, text)
        for r in range(model.rowCount()):
            text = self.sites[r]
            sheet.write(r + 1, 2, text)

        wbk.save(filename)


from clearpath_config.common.types.config import BaseConfig
from clearpath_config.common.types.list import OrderedListConfig
from clearpath_config.common.utils.dictionary import flip_dict
from clearpath_config.mounts.types.fath_pivot import FathPivot
from clearpath_config.mounts.types.flir_ptu import FlirPTU
from clearpath_config.mounts.types.mount import BaseMount
from clearpath_config.mounts.types.pacs import PACS
from clearpath_config.mounts.types.post import Post
from clearpath_config.mounts.types.sick import SICKStand
from clearpath_config.mounts.types.disk import Disk
from typing import List

class Mount():
    FATH_PIVOT = FathPivot.MOUNT_MODEL
    FLIR_PTU = FlirPTU.MOUNT_MODEL
    PACS_RISER = PACS.Riser.MOUNT_MODEL
    PACS_BRACKET = PACS.Bracket.MOUNT_MODEL

    MODEL = {
        FATH_PIVOT: FathPivot,
        FLIR_PTU: FlirPTU,
        PACS_RISER: PACS.Riser,
        PACS_BRACKET: PACS.Bracket
    }

    def __new__(cls, model: str) -> BaseMount:
        assert model in Mount.MODEL, (
            "Model '%s' must be one of: '%s'" % (
                model,
                Mount.MODEL.keys()
            )
        )
        return Mount.MODEL[model]()

class MountListConfig(OrderedListConfig[BaseMount]):
    def __init__(self) -> None:
        super().__init__(obj_type=BaseMount)

    def to_dict(self) -> List[dict]:
        d = []
        for accessory in self.get_all():
            d.append(accessory.to_dict())
        return d

class MountsConfig(BaseConfig):

    MOUNTS = "mounts"
    BRACKET = PACS.Bracket.MOUNT_MODEL
    FATH_PIVOT = FathPivot.MOUNT_MODEL
    RISER = PACS.Riser.MOUNT_MODEL
    SICK = SICKStand.MOUNT_MODEL
    POST = Post.MOUNT_MODEL
    DISK = Disk.MOUNT_MODEL

    TEMPLATE = {
        MOUNTS: {
            BRACKET: BRACKET,
            FATH_PIVOT: FATH_PIVOT,
            RISER: RISER,
            SICK: SICK,
            POST: POST,
            DISK: DISK,
        }
    }

    KEYS = flip_dict(TEMPLATE)

    DEFAULTS = {
        BRACKET: [],
        FATH_PIVOT: [],
        RISER: [],
        SICK: [],
        POST: [],
        DISK: [],
    }

    def __init__(
            self,
            config: dict = {},
            bracket: List[PACS.Bracket] = DEFAULTS[BRACKET],
            fath_pivot: List[FathPivot] = DEFAULTS[FATH_PIVOT],
            riser: List[PACS.Riser] = DEFAULTS[RISER],
            sick_stand: List[SICKStand] = DEFAULTS[SICK],
            post: List[Post] = DEFAULTS[POST],
            disk: List[Disk] = DEFAULTS[DISK],
            ) -> None:
        # Initialization
        self.bracket = bracket
        self.fath_pivot = fath_pivot
        self.riser = riser
        self.sick_stand = sick_stand
        self.post = post
        self.disk = disk
        # Template
        template = {
            self.KEYS[self.BRACKET]: MountsConfig.bracket,
            self.KEYS[self.FATH_PIVOT]: MountsConfig.fath_pivot,
            self.KEYS[self.RISER]: MountsConfig.riser,
            self.KEYS[self.SICK]: MountsConfig.sick_stand,
            self.KEYS[self.POST]: MountsConfig.post,
            self.KEYS[self.DISK]: MountsConfig.disk,
        }
        super().__init__(template, config, self.MOUNTS)

    @property
    def bracket(self) -> OrderedListConfig:
        self.set_config_param(
            key=self.KEYS[self.BRACKET],
            value=self._bracket.to_dict()
        )
        return self._bracket

    @bracket.setter
    def bracket(self, value: List[dict]) -> None:
        assert isinstance(value, list), (
            "Mounts must be list of 'dict'")
        assert all([isinstance(i, dict) for i in value]), (
            "Mounts must be list of 'dict'")
        mounts = MountListConfig()
        mount_list = []
        for d in value:
            mount = PACS.Bracket()
            mount.from_dict(d)
            mount_list.append(mount)
        mounts.set_all(mount_list)
        self._bracket = mounts

    @property
    def riser(self) -> OrderedListConfig:
        self.set_config_param(
            key=self.KEYS[self.RISER],
            value=self._riser.to_dict()
        )
        return self._riser

    @riser.setter
    def riser(self, value: List[dict]) -> None:
        assert isinstance(value, list), (
            "Mounts must be list of 'dict'")
        assert all([isinstance(i, dict) for i in value]), (
            "Mounts must be list of 'dict'")
        mounts = MountListConfig()
        mount_list = []
        for d in value:
            mount = PACS.Riser(rows=1, columns=1)
            mount.from_dict(d)
            mount_list.append(mount)
        mounts.set_all(mount_list)
        self._riser = mounts

    @property
    def fath_pivot(self) -> OrderedListConfig:
        self.set_config_param(
            key=self.KEYS[self.FATH_PIVOT],
            value=self._fath_pivot.to_dict()
        )
        return self._fath_pivot

    @fath_pivot.setter
    def fath_pivot(self, value: List[dict]) -> None:
        assert isinstance(value, list), (
            "Mounts must be list of 'dict'")
        assert all([isinstance(i, dict) for i in value]), (
            "Mounts must be list of 'dict'")
        mounts = MountListConfig()
        mount_list = []
        for d in value:
            mount = FathPivot()
            mount.from_dict(d)
            mount_list.append(mount)
        mounts.set_all(mount_list)
        self._fath_pivot = mounts

    @property
    def sick_stand(self) -> OrderedListConfig:
        self.set_config_param(
            key=self.KEYS[self.SICK],
            value=self._sick.to_dict()
        )
        return self._sick

    @sick_stand.setter
    def sick_stand(self, value: List[dict]) -> None:
        assert isinstance(value, list), (
            "Mounts must be list of 'dict'")
        assert all([isinstance(i, dict) for i in value]), (
            "Mounts must be list of 'dict'")
        mounts = MountListConfig()
        mount_list = []
        for d in value:
            mount = SICKStand()
            mount.from_dict(d)
            mount_list.append(mount)
        mounts.set_all(mount_list)
        self._sick = mounts

    @property
    def post(self) -> OrderedListConfig:
        self.set_config_param(
            key=self.KEYS[self.POST],
            value=self._post.to_dict()
        )
        return self._post

    @post.setter
    def post(self, value: List[dict]) -> None:
        assert isinstance(value, list), (
            "Mounts must be list of 'dict'")
        assert all([isinstance(i, dict) for i in value]), (
            "Mounts must be list of 'dict'")
        mounts = MountListConfig()
        mount_list = []
        for d in value:
            mount = Post()
            mount.from_dict(d)
            mount_list.append(mount)
        mounts.set_all(mount_list)
        self._post = mounts

    @property
    def disk(self) -> OrderedListConfig:
        self.set_config_param(
            key=self.KEYS[self.DISK],
            value=self._disk.to_dict()
        )
        return self._disk

    @disk.setter
    def disk(self, value: List[dict]) -> None:
        assert isinstance(value, list), (
            "Mounts must be list of 'dict'")
        assert all([isinstance(i, dict) for i in value]), (
            "Mounts must be list of 'dict'")
        mounts = MountListConfig()
        mount_list = []
        for d in value:
            mount = Disk()
            mount.from_dict(d)
            mount_list.append(mount)
        mounts.set_all(mount_list)
        self._disk = mounts

    # Get All Mounts
    def get_all_mounts(self) -> List[BaseMount]:
        mounts = []
        mounts.extend(self.fath_pivot.get_all())
        mounts.extend(self.riser.get_all())
        mounts.extend(self.bracket.get_all())
        mounts.extend(self.sick_stand.get_all())
        mounts.extend(self.post.get_all())
        mounts.extend(self.disk.get_all())
        return mounts


import cv2
from pydarknet import Detector, Image
net = Detector(bytes("tank.cfg", encoding="utf-8"), bytes("tank.weights", encoding="utf-8"), 0, bytes("tank.data",encoding="utf-8"))

def Detect(path):

    vidObj = cv2.VideoCapture(path)
    count = 0
    success = 1

    while success:

        success, image = vidObj.read()
        img_darknet = Image(image)
        results = net.detect(img_darknet)
        for cat, score, bounds in results:
           x, y, w, h = bounds
           cv2.rectangle(image, (int(x - w / 2), int(y - h / 2)), (int(x + w / 2), int(y + h / 2)), (255, 0, 0), thickness=2)
           cv2.putText(image,str(cat.decode("utf-8")),(int(x),int(y)),cv2.FONT_HERSHEY_COMPLEX,1,(255,255,0))

        cv2.imshow("Detected Tank", image)
        if cv2.waitKey(25) & 0xFF == ord('q'):
            break
        count += 1

if __name__ == '__main__':
    #Detect(path to the surveillance video)
    Detect("test.mp4")


from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from starlette import status
from starlette.responses import RedirectResponse

from database import get_db
from domain.answer import answer_schema, answer_crud
from domain.question import question_crud, question_schema
from domain.user.user_router import get_current_user
from models import User

router = APIRouter(
    prefix="/api/answer",
)

@router.post("/create/{question_id}", response_model=question_schema.Question)
def answer_create(question_id: int,
                  _answer_create: answer_schema.AnswerCreate,
                  db: Session = Depends(get_db),
                  current_user: User = Depends(get_current_user)):
    # create answer
    question = question_crud.get_question(db, question_id=question_id)
    if not question:
        raise HTTPException(status_code=404, detail="Question not found")
    answer_crud.create_answer(db, question=question,
                              answer_create=_answer_create,
                              user=current_user)

    # redirect
    from domain.question.question_router import router as question_router
    url = question_router.url_path_for('question_detail',
                                       question_id=question_id)
    return RedirectResponse(url, status_code=303)

@router.put("/update", status_code=status.HTTP_204_NO_CONTENT)
def amswer_update(_answer_update: answer_schema.AnswerUpdate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)):
    db_answer = answer_crud.get_answer(db, answer_id=_answer_update.answer_id)
    if not db_answer:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="데이터를 찾을 수 없습니다.")
    if current_user.id != db_answer.user.id:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="수정 권한이 없습니다.")
    answer_crud.update_answer(db=db, db_answer=db_answer, answer_updaete=_answer_update)

@router.get("/detail/{answer_id}", response_model=answer_schema.Answer)
def answer_detail(answer_id: int, db: Session = Depends(get_db)):
    answer = answer_crud.get_answer(db, answer_id=answer_id)
    return answer

@router.post("/vote", status_code=status.HTTP_204_NO_CONTENT)
def answer_vote(_answer_vote: answer_schema.AnswerVote, db: Session = Depends(get_db), current_user: User =Depends(get_current_user)):
    db_answer = answer_crud.get_answer(db, answer_id=_answer_vote.answer_id)
    if not db_answer:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="데이터를 찾을 수 없다.")
    answer_crud.vote_answer(db, db_answer=db_answer, db_user=current_user)


import srt
from datetime import timedelta

INPUT = "You've Got Mail (si).srt"
OUTPUT = "out.srt"
START = 1411
END = -1
SHIFT = timedelta(milliseconds=1000)

with open(INPUT) as f:
    subs = list(srt.parse(f.read()))

for sub in subs[START-1:END]:
    sub.start += SHIFT
    sub.end += SHIFT

with open(OUTPUT, 'w') as f:
    f.write(srt.compose(subs))


# -*- coding: utf-8 -*-
"""
Created on Wed Aug  9 11:35:21 2023

@author: akava
"""

import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import customtkinter, tkinter
from retinaface import RetinaFace
import cv2
from gender_classification.gender_classifier_window import GenderClassifierWindow

class SinglePhotoDetectionPage:
    def __init__(self, Load, App, App_window, image1, options):
        self.App = App
        self.App_window = App_window
        self.Load = Load
        self.root = customtkinter.CTkToplevel()
        self.root.title("Pagina de Deteccion de Rostros de una Sola Foto")
        self.root.geometry("800x600")  # Tamaño de la ventana
        self.root.resizable(False, False)
        self.checkbox_vars = []

        # Configurar el evento de cierre de la ventana secundaria
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        # Variable de control para rastrear si se ha borrado alguna imagen
        self.images_deleted = False
        self.detected_faces = RetinaFace.extract_faces(image1, align = True)
        num_personas= len(self.detected_faces)
        self.scaled_image=image1
        self.Load.withdraw()

        main_frame = customtkinter.CTkFrame(self.root, fg_color=("transparent"))
        main_frame.pack(fill=tk.BOTH, expand=True)

        # Crear un Frame para el mensaje
        message_frame = customtkinter.CTkFrame(main_frame, fg_color=("transparent"))
        message_frame.pack(side=tk.TOP, fill=tk.X)

        # Agregar una etiqueta para el mensaje "Selecciona las fotos que deseas eliminar"
        message_label = customtkinter.CTkLabel(message_frame, text="Selecciona las fotos que deseas eliminar:", font=('Calibri', 15),  fg_color="transparent", width=110)
        message_label.pack(padx=10, pady=5, anchor=tk.W)

        # Crear un Frame para las imágenes
        images_frame = customtkinter.CTkFrame(main_frame, fg_color=("transparent"))
        images_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # Crear un Frame para los botones
        button_frame = customtkinter.CTkFrame(main_frame,  fg_color="transparent")
        button_frame.pack(side=tk.RIGHT, fill=tk.Y)

        face_count_image = customtkinter.CTkImage(Image.open("images/face.png"), size=(26, 26))
        self.face_count_label1 = customtkinter.CTkButton(button_frame, image=face_count_image, text_color="black", fg_color="transparent", text="", width=30)
        self.face_count_label1.pack(padx=10, pady=10, anchor=tk.W)

        # Botones para continuar y regresar en el Frame de los botones
        home_image = customtkinter.CTkImage(Image.open("images/home.png"), size=(26, 26))
        home_button = customtkinter.CTkButton(
            button_frame,
            image=home_image,
            fg_color="transparent",
            text_color= "black",
            text="Home", width=10,
            command=self.return_to_main_menu)
        home_button.pack(pady=10)
        home_button.pack(padx=10, pady=10, anchor=tk.W)

        continue_image = customtkinter.CTkImage(Image.open("images/aceptar.png"), size=(26, 26))
        continue_button = customtkinter.CTkButton(
            button_frame,
            text="Aceptar",
            width=20,
            command=self.continue_pressed,
            image=continue_image,
            text_color="black",
            fg_color="transparent"
        )
        continue_button.pack(padx=10, pady=10, anchor=tk.W)

        delete_image = customtkinter.CTkImage(Image.open("images/borrar.png"), size=(26, 26))
        delete_button = customtkinter.CTkButton(
            button_frame,
            text="Borrar",
            width=20,
            command=self.delete_selected,
            image=delete_image,
            text_color="black",
            fg_color="transparent"
        )
        delete_button.pack(padx=10, pady=10, anchor=tk.W)

        back_image  = customtkinter.CTkImage(Image.open("images/volver.png"), size=(26, 26))
        back_button = customtkinter.CTkButton(
            button_frame,
            text="Regresar",
            width=20,
            command=self.go_back,
            image=back_image,
            text_color="black",
            fg_color="transparent"
        )
        back_button.pack(padx=10, pady=10, anchor=tk.W)

        # Agregar una Scrollbar al Frame de las imágenes
        scroll_y = tk.Scrollbar(images_frame, orient=tk.VERTICAL)
        scroll_y.pack(side=tk.RIGHT, fill=tk.Y)

        # Crear un Canvas para mostrar las imágenes con scrollbar en el Frame de las imágenes
        canvas = tk.Canvas(images_frame, yscrollcommand=scroll_y.set)
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scroll_y.config(command=canvas.yview)

        # Crear un Frame en el Canvas para mostrar las imágenes
        self.frame = customtkinter.CTkFrame(canvas, fg_color=("transparent"), width=650)
        canvas.create_window((0, 0), window=self.frame, anchor=tk.NW)

        self.display_detected_faces(self.frame , self.detected_faces, self.scaled_image )

        # Configurar el Canvas para que pueda desplazarse
        canvas.update_idletasks()
        canvas.config(scrollregion=canvas.bbox("all"))

    # Función para eliminar imágenes seleccionadas
    def delete_selected(self):
        self.detected_faces = self.delete_selected_images(self.scaled_image, self.detected_faces, self.checkbox_vars)
        # Actualizar la variable de control
        self.images_deleted = True
        self.display_detected_faces(self.frame, self.detected_faces, self.scaled_image)

    def display_detected_faces(self, frame, detected_faces, scaled_image):

        for widget in frame.winfo_children():
            widget.destroy()

        self.face_count_label1.configure(text="Rostros: {}".format(self.count_faces(self.detected_faces)))

        # Lista para mantener el estado de los checkboxes
        self.checkbox_vars = []

        # Contadores para controlar las columnas y filas de las imágenes
        col_count = 0
        row_count = 0

        self.person_images_tk = []
        style = ttk.Style()
        style.configure('TCheckbutton', font=('Calibri', 9))

        # Lista para mantener las imágenes personales

        for i, detection in enumerate(detected_faces):

            person_image = detection

            # Convertir la imagen de NumPy a imagen de PIL
            person_image_pil = Image.fromarray(cv2.cvtColor(person_image, cv2.COLOR_BGR2RGB))

            # Redimensionar la imagen
            person_image_pil = person_image_pil.resize((150, 150), Image.LANCZOS)

            # Redimensionar la imagen para mostrarla en tamaño más pequeño en la interfaz
            person_image_pil_small = person_image_pil.resize((80, 80), Image.LANCZOS)

            # Convertir la imagen de PIL a PhotoImage
            person_image_tk = ImageTk.PhotoImage(person_image_pil)  # Usar la imagen original aquí
            self.person_images_tk.append(person_image_tk)  # Agregar a la lista

            # Crear una variable para el estado del checkbox
            checkbox_var = tk.BooleanVar(value=False)
            self.checkbox_vars.append(checkbox_var)

            # Convertir la imagen de PIL a PhotoImage
            person_image_small_tk = ImageTk.PhotoImage(person_image_pil_small)

            # Mostrar la imagen en una etiqueta dentro del Frame
            label = customtkinter.CTkLabel(frame, image=person_image_small_tk, text="")

            # Agregar un checkbox para seleccionar la imagen
            checkbox = ttk.Checkbutton(frame, text="Seleccionar", variable=checkbox_var)

            # Colocar la etiqueta y el checkbox en la posición adecuada usando grid
            label.grid(row=row_count, column=col_count, padx=9, pady=5)
            checkbox.grid(row=row_count + 1, column=col_count, padx=9, pady=0)

            # Actualizar los contadores de columna y fila
            col_count += 1

            # Si col_count es 0, significa que estamos en una nueva fila y necesitamos actualizar los contadores
            if col_count == 0:
                row_count += 2
            elif col_count >= 6:
                col_count = 0
                row_count += 2

        return self.person_images_tk

    def on_click(self, index):
        print(index)

    def continue_pressed(self):

        # Crear una nueva instancia de la ventana del Clasificador de género
        if self.images_deleted:
            self.root.withdraw()
            faces=self.extract_faces(self.scaled_image, self.updated_detected_faces)
            app = GenderClassifierWindow(self.root, self.App, self.App_window, faces)

        else:
            self.root.withdraw()
            faces=self.extract_faces(self.scaled_image, self.detected_faces)
            app = GenderClassifierWindow(self.root, self.App, self.App_window, faces)

    def count_faces(self, detected_faces):
        return len(detected_faces)

    def go_back(self):

        # Hacer que la ventana anterior vuelva a ser visible
        self.Load.deiconify()
        # Cerrar la ventana actual
        self.root.destroy()

    def extract_faces(self, scaled_image, detected_faces):

        faces = []  # Lista para almacenar los rostros extraídos
        # Iterar sobre las detecciones de rostros
        for detection in detected_faces:
            #x1, y1, width1, height1 = detection['box']
            #x1, y1, width1, height1 = int(x1), int(y1), int(width1), int(height1)
            #face_roi = scaled_image[y1:y1+height1, x1:x1+width1]
            #faces.append(face_roi)
            faces.append(detection)
        return faces

    def delete_selected_images(self, scaled_image, detected_faces, checkbox_vars):

        # Eliminar las imágenes seleccionadas de detected_faces
        updated_detected_faces = []
        for detection, checkbox_var in zip(detected_faces, checkbox_vars):
            if not checkbox_var.get():
                updated_detected_faces.append(detection)

        self.updated_detected_faces = updated_detected_faces
        return updated_detected_faces

    def on_closing(self):

        # Restaura la ventana principal
        self.App_window.deiconify()

        # Cierra la ventana de PhotoLoadPage
        self.root.destroy()
        self.Load.destroy()

    def return_to_main_menu(self):
        # Restaura la ventana principal
        self.App_window.deiconify()
        # Cierra la ventana de PhotoLoadPage
        self.root.destroy()
        self.Load.destroy()


import os
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.image import img_to_array, load_img
from tqdm import tqdm
import json
def preprocess_image(image_path, target_size):
    img = load_img(image_path, target_size=target_size)
    img_array = img_to_array(img)
    img_array = np.expand_dims(img_array, axis=0)
    img_array /= 255.0
    return img_array

def classify_images(model_path, image_dir, target_size, output_json):
    model = load_model(model_path)
    results = []
    lesion_type_mapping = {

        0: "BKL",
        1: "NV",
        2: "DF",
        3: "MEL",
        4: "VASC",
        5: "BCC",
        6: "AKIEC"
    }

    test_image_paths = [os.path.join(image_dir, filename) for filename in os.listdir(image_dir) if filename.endswith('.jpg')]
    test_images = [preprocess_image(image_path, target_size) for image_path in tqdm(test_image_paths)]
    test_images = np.vstack(test_images)
    predictions = model.predict(test_images)

    for image_path, prediction in zip(test_image_paths, predictions):
        predicted_label = lesion_type_mapping[np.argmax(prediction)]
        img_id = os.path.splitext(os.path.basename(image_path))[0]
        results.append({"image_id": img_id, "lesion_type": predicted_label})

    with open(output_json, 'w') as f:
        json.dump(results, f)

if __name__ == "__main__":
    model_path = '/Users/donika/Desktop/images/model_training/model.h5'
    image_dir = '/Users/donika/Desktop/images/datasets/test'
    target_size = (128, 128)
    output_json = 'JSON.json'

    classify_images(model_path, image_dir, target_size, output_json)


import base64
from rest_framework import serializers
from categories.models import Categories, Translations, Authorities
from categories.serializers import TranslationsSerializer
from users.models import User
from .models import Documents

def get_predicted_trees():
    try:
        return Categories.objects.filter(
            deprecated=False, parent=None, level=0
        ).values_list("tree_id", "name")
    except Exception as e:
        return []

class UsersSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["username"]

class CategoriesSerializer(serializers.ModelSerializer):
    translation = serializers.SerializerMethodField()
    authority = serializers.SerializerMethodField(method_name="get_authority")

    class Meta:
        model = Categories
        exclude = ["lft", "rght", "level"]

    def get_translation(self, obj):
        translation = Translations.objects.filter(category=obj, language="es").first()
        if translation:
            serializer = TranslationsSerializer(translation)
            return serializer.data
        return None

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["username"]

class DocumentsSerializer(serializers.ModelSerializer):
    pdf = serializers.CharField(
        max_length=None,
        style={"placeholder": "Enter the base64 of the pdf"},
    )
    img = serializers.CharField(
        max_length=None,
        style={"placeholder": "Enter the base64 of the img"},
        write_only=True,
    )

    category = serializers.SerializerMethodField()
    created_by = serializers.SerializerMethodField()
    updated_by = serializers.SerializerMethodField()
    predicted_trees = serializers.MultipleChoiceField(
        choices=get_predicted_trees(), write_only=True, required=False
    )

    class Meta:
        model = Documents
        fields = "__all__"
        read_only_fields = (
            "created_at",
            "updated_at",
            "created_by",
            "updated_by",
            "num_of_access",
        )

    def get_category(self, obj):
        categories = obj.categories.filter(authority__disabled=False)
        if categories:
            serializer = CategoriesSerializer(categories, many=True)
            return serializer.data
        return None

    def get_created_by(self, obj):
        serializer = UserSerializer(obj.created_by)
        return serializer.data

    def get_updated_by(self, obj):
        serializer = UserSerializer(obj.updated_by)
        return serializer.data

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation["pdf"] = None
        if self.context.get("request") and self.context["request"].path.endswith(
            f"/{instance.id}/"
        ):
            Documents.objects.filter(id=instance.id).update(
                num_of_access=instance.num_of_access + 1
            )
            if instance.pdf:
                pdf_base64 = base64.b64encode(instance.pdf).decode("utf-8")
                representation["pdf"] = pdf_base64

        return representation

class DocumentsTextExtractorSerializer(serializers.Serializer):
    """
    Serializer for the DocumentsTextExtractor.

    Converts instances of the DocumentsTextExtractor to JSON and vice versa.

    Attributes:
        title (CharField): The base64 encoded title of the document.
        summary (CharField): The base64 encoded summary of the document.
    """

    title = serializers.CharField(
        max_length=None, style={"placeholder": "Enter the base64 for the title"}
    )
    summary = serializers.CharField(
        max_length=None, style={"placeholder": "Enter the base64 for the summary"}
    )


from OpenGL.GL import *
from OpenGL.GLU import *

import sys

#from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QOpenGLWidget
from PyQt5.QtWidgets import QOpenGLWidget, QApplication, QMainWindow, QLabel, QLineEdit, QVBoxLayout, QWidget
from PyQt5.QtWidgets import QSlider
from PyQt5.QtCore import *

class MyGLWidget(QOpenGLWidget):

    def __init__(self, parent=None):
        super(MyGLWidget, self).__init__(parent)
        self.r = self.g = self.b = 0.0

    def initializeGL(self):
        # OpenGL 그리기를 수행하기 전에 각종 상태값을 초기화
        glClearColor(0.8, 0.8, 0.6, 1.0)

    def resizeGL(self, width, height):
        # 카메라의 투영 특성을 여기서 설정
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # 색과 프리미티브를 이용한 객체 그리기
        glColor3f(self.r, self.g, self.b)
        glBegin(GL_TRIANGLES)
        glVertex3fv([-1.0, 0.0, 0.0])
        glVertex3fv([ 1.0, 0.0, 0.0])
        glVertex3fv([ 0.0, 1.0, 0.0])
        glEnd()

        # 그려진 프레임버퍼를 화면으로 송출
        glFlush()

    def setR(self, val):
        self.r = val/99
        self.update()
    def setG(self, val):
        self.g = val/99
        self.update()
    def setB(self, val):
        self.b = val/99
        self.update()

class MyWindow(QMainWindow):

    def __init__(self, title = ''):
        QMainWindow.__init__(self)    # call the init for the parent class
        self.setWindowTitle(title)

        self.glWidget = MyGLWidget()

        ### GUI 설정
        gui_layout = QVBoxLayout()
        central_widget = QWidget()
        central_widget.setLayout(gui_layout)

        self.setCentralWidget(central_widget)
        gui_layout.addWidget(self.glWidget)

        sliderX = QSlider(Qt.Horizontal)
        sliderX.valueChanged.connect(lambda val: self.glWidget.setR(val))

        sliderY = QSlider(Qt.Horizontal)
        sliderY.valueChanged.connect(lambda val: self.glWidget.setG(val))

        sliderZ = QSlider(Qt.Horizontal)
        sliderZ.valueChanged.connect(lambda val: self.glWidget.setB(val))

        gui_layout.addWidget(sliderX)
        gui_layout.addWidget(sliderY)
        gui_layout.addWidget(sliderZ)

def main(argv = []):
    app = QApplication(argv)
    window = MyWindow('GL with Qt Widgets')
    window.setFixedSize(600, 600)
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main(sys.argv)