import os
from typing import List
from matplotlib import pyplot as plt
import more_itertools
import numpy as np
import pandas as pd
import tensorflow as tf
from embedding_dataset import EmbeddingDataset
from embedding_generator import EmbeddingPair
from mongo_db_client import MongoDbClient, MongoDbPairDoc
from runnable import Runnable

class DataAnalysis(Runnable):
  def __init__(self, analysis_dir = '') -> None:
    self.analysis_dir = analysis_dir if len(analysis_dir) > 0 else os.path.join(os.path.abspath(os.curdir), 'analysis')

    if not os.path.isdir(self.analysis_dir):
      os.mkdir(self.analysis_dir)

  def run(self):
    mongo_db = MongoDbClient()

    pairs = list(mongo_db.get_pairs_collection().find({ "partition": "train", "language": "python" }).limit(50))
    positive_pairs_db = self.create_tf_dataset(pairs)
    train_dataset = self.generate_dataset_with_negative_samples(positive_pairs_db)

    self.embeddings_analysis(train_dataset)
    self.raw_data_analysis(train_dataset)

  def raw_data_analysis(self, train_dataset: tf.data.Dataset):
    ids = [pair['id'].decode('utf-8') for pair, target in train_dataset.as_numpy_iterator()]
    pairs: dict[str, MongoDbPairDoc] = { pair['id']: pair for pair in MongoDbClient().get_pairs_collection().find({ "id": { "$in": ids } }) }
    raw_data_path = os.path.join(self.analysis_dir, 'raw_data.csv')

    df_data = []
    sample = 0

    for [positive_emb_pair, pos_target], [negative_emb_pair, neg_target] in more_itertools.chunked(train_dataset.as_numpy_iterator(), 2):
      positive_pair = pairs[positive_emb_pair['id'].decode('utf-8')]
      negative_pair = pairs[negative_emb_pair['id'].decode('utf-8')]

      if positive_pair is None:
        raise ValueError(f"positive pair with id {positive_emb_pair['id']} was not found")

      if negative_pair is None:
        raise ValueError(f"negative pair with id {negative_emb_pair['id']} was not found")

      df_data.append({
        "sample": sample,
        "code": positive_pair['code_tokens'],
        "positive_comment": positive_pair['comment_tokens'],
        "negative_comment": negative_pair['comment_tokens'],
      })
      sample += 1

    df = pd.DataFrame(df_data)
    df.to_csv(raw_data_path)

  def embeddings_analysis(self, train_dataset):
    sample = 0
    for [positive, pos_target], [negative, neg_target] in more_itertools.chunked(train_dataset.as_numpy_iterator(), 2):
      self.save_plot_emb_pairs(positive, negative, f'sample-{sample}')
      sample += 1

  def save_raw_data(self, positive_pair: EmbeddingPair, negative_pair: EmbeddingPair, title: str):
    path = os.path.join(self.analysis_dir, f'{title}.csv')
    with open(path, 'w') as file:
      file.write(f"{positive_pair['code_embedding']},{positive_pair['comment_embedding']},{negative_pair['comment_embedding']}\n")

  def save_plot_emb_pairs(self, positive, negative, title: str):
    fig, axes = plt.subplots(2, 2, constrained_layout=True)
    code_graph, comment_graph, neg_comment_graph, diff_graph = axes[0][0], axes[0][1], axes[1][0], axes[1][1]

    comment_diff = np.absolute(positive['comment_embedding'] - negative['comment_embedding'])

    code_graph.plot(positive['code_embedding'], color='#14d0c5')
    code_graph.set_title('Code')

    comment_graph.plot(positive['comment_embedding'], color='#b1d697')
    comment_graph.set_title('Comment')

    neg_comment_graph.plot(negative['comment_embedding'], color='#6db474')
    neg_comment_graph.set_title('Negative comment')

    diff_graph.plot(comment_diff, color='#8db670')
    diff_graph.set_title('Comment Diff')

    fig.suptitle(title)

    fig_path = os.path.join(self.analysis_dir, title)
    fig.savefig(fig_path)
    plt.close(fig)

  def create_tf_dataset(self, pairs: List[MongoDbPairDoc]) -> tf.data.Dataset:
    def dataset_generator():
      with EmbeddingDataset('embeddings') as embedding_dataset:
        for pair in pairs:
          embedding = embedding_dataset.get(pair["id"])
          if embedding is None:
            raise ValueError(f"{pair['id']} from partition {pair['partition']} was not found")

          yield {
            "id": embedding['id'],
            "code_embedding": embedding["code_embedding"],
            "comment_embedding": embedding["comment_embedding"],
          }

    return tf.data.Dataset.from_generator(dataset_generator, output_types={
      "id": tf.string,
      "code_embedding": tf.float32,
      "comment_embedding": tf.float32,
    })

  def generate_dataset_with_negative_samples(self, positive_samples: tf.data.Dataset) -> tf.data.Dataset:
    negative_samples = positive_samples.shuffle(100)
    def generator():
      for positive_sample, negative_sample in zip(positive_samples, negative_samples):
        yield {
          "id": positive_sample['id'],
          "code_embedding": positive_sample['code_embedding'],
          "comment_embedding": positive_sample['comment_embedding']
        }, 1.0
        yield {
          "id": negative_sample['id'],
          "code_embedding": positive_sample['code_embedding'],
          "comment_embedding": negative_sample['comment_embedding']
        }, 0.0

    return tf.data.Dataset.from_generator(generator, output_types=({
      "id": tf.string,
      "code_embedding": tf.float32,
      "comment_embedding": tf.float32,
    }, tf.float32))


import json
from os import walk

try:
	File = open("Data.json", "r")
	LastDirUsed = json.load(File) #Loads the json file into a dictionary
	File.close()
except:
	LastDirUsed = {}

Data = {}

def DirIndexLoad():
	Results = []
	CurrentSet = ""
	dirPath = ""
	#input(LastDirUsed)

	while True:
		try:
			UserInput = input("Please enter the path to a folder with your JSON sets.\nYour last used folder was located at " + LastDirUsed["RecentDirPath"] + "\nIf you would like to use this folder, press enter")
		except:
			UserInput = input("Please enter the path to a folder with your JSON sets.")
		if UserInput == "":
			DirPath = LastDirUsed["RecentDirPath"]
		else:
			DirPath = UserInput

		#Saving the recently used directory path
		Data["RecentDirPath"] = DirPath
		File = open("Data.json", "w")
		json.dump(Data,File)
		File.close()

		for (DirPath, DirNames, FileNames) in walk(DirPath):
			Results.extend(FileNames)

		Count = 0
		IndexedResults = {}
		for x in Results:
			Count += 1
			print(str(Count) + ". " + x + "\n")
			IndexedResults[Count] = x

		UserInput = input("Type the number of the set you would like to load")

		try:
			File = open(DirPath + "\\" + IndexedResults[int(UserInput)], "r")
			InputDict = json.load(File) #Loads the json file into a dictionary
			File.close()
		except:
			print("Sorry, that file does not exist")
			continue
		else:
			break

	CurrentSet = IndexedResults[int(UserInput)]
	return (InputDict, CurrentSet, DirPath)


from django.db import models
from django.conf import settings

from notification.api import add_notification
import user_profile.models
import dashboard.models

class StudentManager(models.Manager):
    # get or create the referral codes for a user
    def create_student(self, user, school):
        student = user_profile.models.Student(
            user=user, school=school,
        )
        student.save()
        profile = user_profile.models.UserProfile(student=student)
        profile.save()
        roles = user_profile.models.UserRole(user=user)
        roles.save()

        # set default rss settings
        dashboard.models.RSSSetting.objects.restore_default_settings(student)
        return student

    def referral_reward(self, user, referrer):
        reward_points = settings.MCHP_PRICING['referral_reward']
        user.student.add_earned_points(reward_points)
        referrer_roles = user_profile.models.UserRole.objects.get_roles(referrer)
        if referrer_roles.rep:
            referrer.student.modify_balance(1)
            add_notification(
                referrer,
                user.username + " used your code. You've got money in the bank",
            )
        else:
            referrer.student.add_earned_points(reward_points)
            add_notification(
                referrer,
                user.username + " used your code. You made a cool {} points".format(reward_points),
            )

class UserRoleManager(models.Manager):
    def get_roles(self, user):
        roles = user_profile.models.UserRole.objects.filter(user=user)
        if roles.exists():
            return roles[0]
        else:
            roles = user_profile.models.UserRole(user=user)
            roles.save()
            return roles

class OneTimeEventManager(models.Manager):
    @staticmethod
    def get_event(name):
        if not name:
            return None

        return user_profile.models.OneTimeEvent.objects.get_or_create(
            name=name
        )[0]

class OneTimeFlagManager(models.Manager):
    @staticmethod
    def clear_flags(student):
        user_profile.models.OneTimeFlag.objects.filter(
            student=student
        ).delete()

    @staticmethod
    def set_flag(student, event):
        flag, created = user_profile.models.OneTimeFlag.objects.get_or_create(
            student=student,
            event=event,
        )
        return created

    @staticmethod
    def get_flags(student):
        return user_profile.models.OneTimeFlag.objects.filter(
            student=student
        )

    @staticmethod
    def get_flag(student, event_name):
        # usually this mean the user is not logged in, so don't show any of these
        if not student:
            return (True,)

        event = user_profile.models.OneTimeEvent.objects.filter(
            name=event_name
        )

        flag = user_profile.models.OneTimeFlag.objects.filter(
            student=student,
            event=event,
        )
        return flag.exists()


import os
import numpy as np
import binvox_rw
import datetime
import time

from sklearn.model_selection import train_test_split

from tensorflow.keras import Model, initializers, activations
from tensorflow.keras.layers import Input, Dense, Activation, Dropout, Flatten , GaussianNoise
from tensorflow.keras.layers import Conv3D, MaxPooling3D
from tensorflow.nn import relu, softmax
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.utils import plot_model, to_categorical

class Dataset:

    def __init__(self, prefixDir, prefixDirOutput):
        print("\n----- Dataset Initialization  started!! -----")
        time.sleep(2)

        self.prefixDir = prefixDir
        self.prefixDirOutput = prefixDirOutput

        self.classesInfo = {"listOfClasses": list(),
                            "numberOfSample_in_trainFolder": dict(),
                            "minNumberOfSample_in_trainFolder": 0,
                            "BINVOXsampleNameList_in_trainFolder": dict(),
                            "OFFsampleNameList_in_trainFolder" : dict(),

                            "numberOfSample_in_testFolder": dict(),
                            "minNumberOfSample_in_testFolder": 0,
                            "BINVOXsampleNameList_in_testFolder": dict(),
                            "OFFsampleNameList_in_testFolder": dict(),
                            }

        for file in os.listdir(self.prefixDir):
            if os.path.isdir(os.path.join(self.prefixDir, file)):
                self.classesInfo["listOfClasses"].append(file)

        self.classesInfo["listOfClasses"].sort()

        for classname in self.classesInfo["listOfClasses"]:
            temp = list()
            temp2 = list()
            for fileName in os.listdir(self.prefixDir + classname + "/train"):
                if ".off" in fileName:
                    temp.append(fileName)
                if ".binvox" in fileName:
                    temp2.append(fileName)

            temp.sort()
            temp2.sort()
            self.classesInfo["OFFsampleNameList_in_trainFolder"][classname] = temp
            self.classesInfo["BINVOXsampleNameList_in_trainFolder"][classname] = temp2
            self.classesInfo["numberOfSample_in_trainFolder"][classname] = len(temp)
            # print("asdasd ", self.classesInfo["OFFsampleNameList_in_trainFolder"][classname])

        for classname in self.classesInfo["listOfClasses"]:
            temp = list()
            temp2 = list()
            for fileName in os.listdir(self.prefixDir + classname + "/test"):
                if ".off" in fileName:
                    temp.append(fileName)
                if ".binvox" in fileName:
                    temp2.append(fileName)

            temp.sort()
            temp2.sort()
            self.classesInfo["OFFsampleNameList_in_testFolder"][classname] = temp
            self.classesInfo["BINVOXsampleNameList_in_testFolder"][classname] = temp2
            self.classesInfo["numberOfSample_in_testFolder"][classname] = len(temp)

        self.classesInfo["minNumberOfSample_in_trainFolder"] = min(self.classesInfo["numberOfSample_in_trainFolder"].values())
        self.classesInfo["minNumberOfSample_in_testFolder"] = min(self.classesInfo["numberOfSample_in_testFolder"].values())

        firstClassName_in_trainFolder = self.classesInfo["listOfClasses"][0]

        print("listOfClasses:", self.classesInfo["listOfClasses"],
              "\nminNumberOfSample_in_trainFolder", self.classesInfo["minNumberOfSample_in_trainFolder"],
              "\nminNumberOfSample_in_testFolder", self.classesInfo["minNumberOfSample_in_testFolder"],
              "\nOFFsampleNameList_in_trainFolder", self.classesInfo["OFFsampleNameList_in_trainFolder"][ classname ][0:10],
              "\nOFFsampleNameList_in_testFolder", self.classesInfo["OFFsampleNameList_in_testFolder"][ classname ][0:10])

        print("----- Dataset Initialization  finished!! -----\n")

    def deleteBinvoxFiles(self):
        print("----- deleteBinvoxFiles  started!!")
        time.sleep(2)

        totalCounter = 0

        for classname in self.classesInfo["listOfClasses"]:
            fileNames_in_trainFolder = os.listdir(self.prefixDir + classname + "/train")
            # print("TrainFolder classname:", classname, "list: ", sampleNameList_inTrainFolder)
            for fileName in fileNames_in_trainFolder:
                if ".binvox" in fileName:
                    os.remove(self.prefixDir + classname + "/train" + "/" + fileName)
                    print("'{}' is removing..".format(fileName))
                    totalCounter = totalCounter + 1

            fileNames_in_testFolder = os.listdir(self.prefixDir + classname + "/test")
            # print("TrainFolder classname:", classname, "list: ", sampleNameList_inTrainFolder)
            for fileName in fileNames_in_testFolder:
                if ".binvox" in fileName:
                    os.remove(self.prefixDir + classname + "/test" + "/" + fileName)
                    print("'{}' is removing..".format(fileName))
                    totalCounter = totalCounter + 1

        print("{} files were deleted.".format(totalCounter))
        print("----- deleteBinvoxFiles  finished!!")

    def create_binvoxFiles_from_offFiles(self, shapeNumber):
        print("\n----- create_binvoxFiles_from_offFiles  started!!")
        time.sleep(2)

        totalCounter = 0

        minNumber_train = self.classesInfo["minNumberOfSample_in_trainFolder"]
        for classname in self.classesInfo["listOfClasses"]:
            cl_name = classname
            for sampleName in self.classesInfo["OFFsampleNameList_in_trainFolder"][cl_name][0:minNumber_train]:
                os.system(
                    "./binvox -c -d " + str(
                        shapeNumber) + " -e -t binvox -cb " + self.prefixDir + classname + "/train" + "/" + sampleName)
                totalCounter = totalCounter + 1

        minNumber_test = self.classesInfo["minNumberOfSample_in_testFolder"]
        for classname in self.classesInfo["listOfClasses"]:
            cl_name = classname
            for sampleName in self.classesInfo["OFFsampleNameList_in_testFolder"][cl_name][0:minNumber_test]:

                os.system(
                    "./binvox -c -d " + str(
                        shapeNumber) + " -e -t binvox -cb " + self.prefixDir + classname + "/test" + "/" + sampleName)
                totalCounter = totalCounter + 1

        print("{} files were created.".format(totalCounter))
        print("----- create_binvoxFiles_from_offFiles  finished!!")

    def create_numpyFiles_from_binvoxFiles(self, shapeNumber):
        print("----- create_numpyFiles_from_binvoxFiles  started!!")

        passOrbreak = 0
        for classname in self.classesInfo["listOfClasses"]:
            if self.classesInfo["minNumberOfSample_in_trainFolder"] != len(self.classesInfo["BINVOXsampleNameList_in_trainFolder"][classname]):
                passOrbreak = 1
                print("Eksik bin dosyası var!!",
                      "\nminNumberOfSample_in_trainFolder:", self.classesInfo["minNumberOfSample_in_trainFolder"],
                      "\t\tlen(OFFsampleNameList_in_trainFolder in {}): ".format(classname), len(self.classesInfo["BINVOXsampleNameList_in_trainFolder"][classname]) )

            if self.classesInfo["minNumberOfSample_in_testFolder"] != len(self.classesInfo["BINVOXsampleNameList_in_testFolder"][classname]):
                passOrbreak = 1
                print("Eksik bin dosyası var!!",
                      "\nminNumberOfSample_in_testFolder:", self.classesInfo["minNumberOfSample_in_testFolder"],
                      "\t\tlen(OFFsampleNameList_in_testFolder in {}): ".format(classname), len(self.classesInfo["BINVOXsampleNameList_in_testFolder"][classname]) )

        if passOrbreak == 1:
            exit()
        else:
            pass

        totalNUmberOfSamples = self.classesInfo["minNumberOfSample_in_trainFolder"] * len(self.classesInfo["listOfClasses"])
        x_train = np.zeros(shape=(totalNUmberOfSamples, shapeNumber, shapeNumber, shapeNumber), dtype=float)
        y_train = np.zeros((totalNUmberOfSamples,), dtype="int")

        totalNUmberOfSamples2 = self.classesInfo["minNumberOfSample_in_testFolder"] * len(self.classesInfo["listOfClasses"])
        x_test = np.zeros(shape=(totalNUmberOfSamples2, shapeNumber, shapeNumber, shapeNumber), dtype=float)
        y_test = np.zeros((totalNUmberOfSamples2,), dtype="int")

        currentNumberOfSample = 0
        currentNumberOfSample2 = 0
        for label, classname in enumerate(self.classesInfo["listOfClasses"]):
            for binvoxFileName in self.classesInfo["BINVOXsampleNameList_in_trainFolder"][classname]:
                with open(self.prefixDir + classname + "/train/" + binvoxFileName, 'rb') as f:
                    model = binvox_rw.read_as_3d_array(f)
                    narray = np.ndarray(shape=(1, shapeNumber, shapeNumber, shapeNumber), dtype=float)
                    narray = model.data
                    x_train[currentNumberOfSample, :] = narray.astype(float)
                    y_train[currentNumberOfSample] = label
                    currentNumberOfSample = currentNumberOfSample +1
                    # print("currentNumberOfSample: ", currentNumberOfSample)

            for binvoxFileName2 in self.classesInfo["BINVOXsampleNameList_in_testFolder"][classname]:
                with open(self.prefixDir + classname + "/test/" + binvoxFileName2, 'rb') as f:
                    model2 = binvox_rw.read_as_3d_array(f)
                    narray2 = np.ndarray(shape=(1, shapeNumber, shapeNumber, shapeNumber), dtype=float)
                    narray2 = model2.data
                    x_test[currentNumberOfSample2, :] = narray2.astype(float)
                    y_test[currentNumberOfSample2] = label
                    currentNumberOfSample2 = currentNumberOfSample2 +1
                    # print("currentNumberOfSample2: ", currentNumberOfSample2)

        dt = datetime.datetime.today()

        print("x_train.shape", x_train.shape)
        np.save(self.prefixDirOutput + "x_train_shape{}_{}_{}_{}__{}_{}_{}.npy".format(shapeNumber, dt.day,
                                                                                dt.month, dt.year,
                                                                                dt.hour, dt.minute,
                                                                                dt.second), x_train)
        y_train_categorical = to_categorical(y_train, len(self.classesInfo["listOfClasses"]))
        print("y_train_categorical.shape", y_train_categorical.shape)
        np.save(self.prefixDirOutput + "y_train_shape{}_{}_{}_{}__{}_{}_{}.npy".format(shapeNumber, dt.day,
                                                                                dt.month, dt.year,
                                                                                dt.hour, dt.minute,
                                                                                dt.second), y_train_categorical)

        print("x_test.shape", x_test.shape)
        np.save(self.prefixDirOutput + "x_test_shape{}_{}_{}_{}__{}_{}_{}.npy".format(shapeNumber, dt.day,
                                                                                dt.month, dt.year,
                                                                                dt.hour, dt.minute,
                                                                                dt.second), x_test)

        y_test_categorical = to_categorical(y_test, len(self.classesInfo["listOfClasses"]))
        print("y_test_categorical.shape", y_test_categorical.shape)
        np.save(self.prefixDirOutput + "y_test_shape{}_{}_{}_{}__{}_{}_{}.npy".format(shapeNumber, dt.day,
                                                                                dt.month, dt.year,
                                                                                dt.hour, dt.minute,
                                                                                dt.second), y_test_categorical)

        print("----- create_numpyFiles_from_binvoxFiles  finished!!")

class TrainOP:

    def __init__(self, prefixDirOutput, filename__x_train, filename__y_train):
        print("\n----- TrainOP Initialization  started!! -----")
        self.prefixDirOutput = prefixDirOutput

        dt = datetime.datetime.today()
        self.prefixForOutputFileName = "output_{}{}{}__{}_{}_{}__".format(dt.day, dt.month, dt.year,
                                                                         dt.hour, dt.minute, dt.second)

        y_train_total = np.load(filename__y_train)
        # y_train_total = y_train_total.astype(float)
        x_train_total = np.load(filename__x_train)
        x_train_total = x_train_total.astype(float)
        x_train_total = np.expand_dims(x_train_total, axis=4)
        print("x_train_total shape: ", x_train_total.shape, "\ty_train_total shape: ", y_train_total.shape)

        self.x_train, self.x_valid, self.y_train, self.y_valid = train_test_split(x_train_total, y_train_total, test_size=0.2, random_state=1)
        print("\nx_train shape: ", self.x_train.shape, "\ty_train shape: ", self.y_train.shape)
        print("x_valid shape: ", self.x_valid.shape, "\ty_valid shape: ", self.y_valid.shape)

        print("\n----- TrainOP Initialization  finished!! -----")

    def build_and_train_ModelNet(self):
        print("\n----- build_and_train  started!! -----")

        #### Nested definiton START ####
        def my_initializer(shape, dtype=None):
            receptive_field_size = np.prod(shape[2:])
            c = shape[1]  # input channels
            nl = c * receptive_field_size
            std = np.sqrt(2.0 / (nl))
            return np.random.normal(0, std, size=shape).astype('float32')

        #### Nested definiton END   ####

        input_shape = self.x_train.shape[1:5]
        num_classes = self.y_train.shape[1]
        print("input shape: ", input_shape, "num classes: ", num_classes)

        inputs1 = Input(shape=input_shape)

        layer1 = Conv3D(filters=32, kernel_size=5, strides=(2, 2, 2), padding="valid",
                        activation='relu', kernel_initializer=my_initializer)(inputs1)
        layer1 = Dropout(0.2)(layer1)

        layer2 = Conv3D(filters=32, kernel_size=3, strides=(1, 1, 1), padding="valid",
                        activation='relu', kernel_initializer=my_initializer)(layer1)
        layer2 = MaxPooling3D(pool_size=(2, 2, 2), padding="valid")(layer2)
        layer2 = Dropout(0.3)(layer2)

        flat = Flatten()(layer2)

        dense1 = Dense(128, kernel_initializer=initializers.RandomNormal(stddev=0.01))(flat)
        dense1 = Dropout(0.4)(dense1)

        outputs = Dense(num_classes, kernel_initializer=initializers.RandomNormal(stddev=0.01))(dense1)
        outputs = Activation("softmax")(outputs)

        model = Model(inputs=inputs1, outputs=outputs)
        model.summary()

        filepath = self.prefixDirOutput + self.prefixForOutputFileName + "Architecture.png"
        ## ""sudo apt-get install graphviz""
        ## terminal'e bunu yazmalısın. virEnv bağımsız yüklemelisin.
        plot_model(model, show_shapes=True, to_file=filepath)

        sgd = SGD(lr=0.01, momentum=0.9, nesterov=True)
        model.compile(optimizer=sgd, loss="categorical_crossentropy", metrics=["accuracy"])

        history = model.fit(x=self.x_train, y=self.y_train, validation_data=(self.x_valid, self.y_valid),
                            epochs=10, batch_size=16, verbose=2)

        model_filepath = self.prefixDirOutput + self.prefixForOutputFileName + "Model.h5"
        model.save(model_filepath)
        print("Model was saved to the path")

        print("\n----- build_and_train  finished!! -----")

class TrainModel:

    def __init__(self, prefixDir):
        self.prefixDir = prefixDir

        dt = datetime.datetime.today()
        self.prefixForOutputFile = "output_{}{}{}__{}_{}_{}__".format(dt.day, dt.month, dt.year,
                                                                 dt.hour, dt.minute, dt.second)

    def load_npyFile(self, filename__x_train, filename__y_train):
        print("----- TrainModel --> load_npyFile  started!!")

        y_total = np.load(filename__y_train)
        # y_total = y_total.astype(float)
        x_total = np.load(filename__x_train)
        x_total = x_total.astype(float)
        x_total = np.expand_dims(x_total, axis=4)
        print("x_total shape: ", x_total.shape, "\ty_total shape: ", y_total.shape)

        x_train, x_valid, y_train, y_valid = train_test_split(x_total, y_total, test_size=0.2, random_state=1)
        print("\nx_train shape: ", x_train.shape, "\ty_train shape: ", y_train.shape)
        print("x_valid shape: ", x_valid.shape, "\ty_valid shape: ", y_valid.shape)

        print("----- TrainModel --> load_npyFile  finished!!")

        return x_train, x_valid, y_train, y_valid

    def train_with_VoxNet(self, x_train, x_valid, y_train, y_valid):
        print("----- TrainModel --> train_with_VoxNet  started!!")

        #### Nested definiton START ####
        def my_initializer(shape, dtype=None):
            receptive_field_size = np.prod(shape[2:])
            c = shape[1]  # input channels
            nl = c * receptive_field_size
            std = np.sqrt(2.0 / (nl))
            return np.random.normal(0, std, size=shape).astype('float32')
        #### Nested definiton END   ####

        input_shape = x_train.shape[1:5]
        num_classes = y_train.shape[1]
        print("input shape: ", input_shape, "num classes: ", num_classes)

        inputs1 = Input(shape=input_shape)

        layer1 = Conv3D(8, 3, strides=(2, 2, 2), padding="valid",
                        activation='relu', kernel_initializer=my_initializer)(inputs1)
        layer1 = Dropout(0.2)(layer1)

        layer2 = Conv3D(8, 3, strides=(2, 2, 2), padding="valid",
                        activation='relu', kernel_initializer=my_initializer)(layer1)
        layer2 = MaxPooling3D(pool_size=(2, 2, 2), padding="valid")(layer2)
        layer2 = Dropout(0.3)(layer2)

        flat = Flatten()(layer2)

        dense1 = Dense(128, kernel_initializer=initializers.RandomNormal(stddev=0.01))(flat)
        dense1 = Dropout(0.4)(dense1)

        outputs = Dense(num_classes, kernel_initializer=initializers.RandomNormal(stddev=0.01))(dense1)
        outputs = Activation("softmax")(outputs)

        model = Model(inputs=inputs1, outputs=outputs)
        model.summary()

        filepath = self.prefixDir + self.prefixForOutputFile + "Architecture.png"
        ## ""sudo apt-get install graphviz""
        ## terminal'e bunu yazmalısın. virEnv bağımsız yüklemelisin.
        plot_model(model, show_shapes=True, to_file=filepath)

        sgd = SGD(lr=0.01, momentum=0.9, nesterov=True)
        model.compile(optimizer=sgd, loss="categorical_crossentropy", metrics=["accuracy"])

        history = model.fit(x=x_train, y=y_train, validation_data=(x_valid, y_valid),
                            epochs=10, batch_size=16, verbose=2)

        model_filepath = self.prefixDir + self.prefixForOutputFile + "Model.h5"
        model.save(model_filepath)
        print("Model was saved to the path")

        print("----- TrainModel --> train_with_VoxNet  finished!!")


#!/usr/bin/python3
"""
This python module returns the state id of a given state name from
hbtn_0e_6_usa using sqlalchemy ORM in interacting with the database
"""

from sqlalchemy.orm import sessionmaker
from sys import argv
from model_state import Base, State
from sqlalchemy import create_engine

if __name__ == '__main__':
    if (len(argv) != 5):
        exit()
    engine = create_engine('mysql+mysqldb://{}:{}@localhost:3306/{}'.format(
        argv[1], argv[2], argv[3]))
    Base.metadata.create_all(engine)

    stateSearchName = (argv[4],)

    # create a connection Session
    Session = sessionmaker(bind=engine)
    session = Session()

    # quering the database in search of a given state name
    states = session.query(State).filter_by(name=stateSearchName).first()

    # printing the result
    if states:
        print(states.id)
    else:
        print("Not found")


import requests
# If you are using a Jupyter notebook, uncomment the following line.
# %matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from PIL import Image
from io import BytesIO
import os
import sys
import json
import glob
import time

indir = sys.argv[1]
outdir = sys.argv[2]

dirlist = []
dirlist = glob.glob(os.path.join(indir, '*.jpg'))

# Add your Computer Vision subscription key and endpoint to your environment variables.
if 'COMPUTER_VISION_SUBSCRIPTION_KEY' in os.environ:
    subscription_key = os.environ['COMPUTER_VISION_SUBSCRIPTION_KEY']
else:
    print("\nSet the COMPUTER_VISION_SUBSCRIPTION_KEY environment variable.\n**Restart your shell or IDE for changes to take effect.**")
    sys.exit()

if 'COMPUTER_VISION_ENDPOINT' in os.environ:
    endpoint = os.environ['COMPUTER_VISION_ENDPOINT']

ocr_url = endpoint + "vision/v2.0/ocr"

for image in dirlist:
    image_path = image
    # Read the image into a byte array
    image_data = open(image_path, "rb").read()

    headers = {'Ocp-Apim-Subscription-Key': subscription_key, 'Content-Type': 'application/octet-stream'}
    params = {'language': 'unk', 'detectOrientation': 'true'}
    #data = {'url': image_url}
    response = requests.post(ocr_url, headers=headers, params=params, data = image_data)
    response.raise_for_status()

    analysis = response.json()

    out = os.path.join(outdir, os.path.basename(image.rstrip('.jpg') + '.json'), )
    with open(out, 'w') as outfile:
        outfile.write(json.dumps(analysis))
        outfile.close()
    time.sleep(5)

# Extract the word bounding boxes and text.
# line_infos = [region["lines"] for region in analysis["regions"]]
# word_infos = []
# for line in line_infos:
#     for word_metadata in line:
#         for word_info in word_metadata["words"]:
#             word_infos.append(word_info)
# word_infos


# -*- coding: utf8 -*-
"""Base API module.

Design notes:

- Content Negotiation: All responses are in the JSON-LD format and use the
  Web Annotation profile, more formats may be added in future.
"""

import os
import json
from flask import current_app
from flask import abort, request, jsonify, make_response, url_for
from jsonschema import validate as validate_json
from jsonschema.exceptions import ValidationError
from sqlalchemy.exc import IntegrityError
from past.builtins import basestring

from explicates.core import repo
from explicates.model.annotation import Annotation
from explicates.model.collection import Collection
from explicates.model.base import BaseDomainObject

class APIBase(object):

    def _get_domain_object(self, model_cls, id, **kwargs):
        """Return a domain object."""
        obj = repo.get_by(model_cls, id=id, **kwargs)
        if not obj:
            abort(404)
        elif obj.deleted:
            abort(410)
        return obj

    def _get_iri(self, obj, **kwargs):
        """Get the IRI for an object."""
        if isinstance(obj, Annotation):
            kwargs.pop('iris', None)
            return url_for('api.annotations', annotation_id=obj.id,
                           collection_id=obj.collection.id, _external=True,
                           **kwargs)

        elif isinstance(obj, Collection):
            if not obj.id:
                return url_for('api.search', _external=True, **kwargs)
            return url_for('api.collections', collection_id=obj.id,
                           _external=True, **kwargs)

        cls_name = obj.__class__.__name__
        raise TypeError('Cannot generated IRI for {}'.format(cls_name))

    def _create(self, model_cls, **kwargs):
        """Create and return a domain object."""
        data = self._get_validated_data(model_cls)
        slug = request.headers.get('Slug')

        # Move posted ID to via
        if data and data.get('id'):
            data['via'] = data.pop('id')

        try:
            obj = model_cls(id=slug, data=data, **kwargs)
            repo.save(model_cls, obj)
        except (IntegrityError, TypeError) as err:
            abort(400, err)
        return obj

    def _update(self, obj):
        """Update a domain object."""
        data = self._get_validated_data(obj.__class__)
        try:
            obj.data = data
            model_cls = obj.__class__
            repo.update(model_cls, obj)
        except (IntegrityError, TypeError) as err:  # pragma: no cover
            abort(400, err)

    def _delete(self, obj):
        """Delete a domain object."""
        try:
            model_cls = obj.__class__
            repo.delete(model_cls, obj.key)
        except (IntegrityError, TypeError) as err:  # pragma: no cover
            abort(400, err)

    def _get_validated_data(self, model_cls):
        data = request.get_json()
        try:
            self._validate_data(data, model_cls)
        except ValidationError as err:
            abort(400, err)
        return data

    def _validate_data(self, obj, model_cls):
        """Validate data according JSON schema for the model class."""
        schema_fn = '{}.json'.format(model_cls.__name__.lower())
        here = os.path.dirname(os.path.abspath(__file__))
        schemas_dir = os.path.join(os.path.dirname(here), 'schemas')
        schema_path = os.path.join(schemas_dir, schema_fn)
        with open(schema_path) as json_file:
            schema = json.load(json_file)
            validate_json(obj, schema)

    def _jsonld_response(self, rv, status_code=200, headers=None):
        """Return a JSON-LD Response.

        The Web Annotation profile is used for Web Annotations.

        See https://www.w3.org/TR/annotation-protocol/#annotation-retrieval
        """
        out = rv if rv else {}
        if isinstance(rv, BaseDomainObject):
            out = rv.dictize()

        if not isinstance(out, dict):
            err_msg = '{} is not a valid return value'.format(type(rv))
            raise TypeError(err_msg)

        context = 'http://www.w3.org/ns/anno.jsonld'
        out['@context'] = context
        response = jsonify(out)
        response.mimetype = 'application/ld+json; profile="{}"'.format(context)

        # Add Etags for HEAD and GET requests
        if request.method in ['HEAD', 'GET']:
            response.add_etag()

        # Add headers
        self._add_link_headers(response, out)
        common_headers = getattr(self, 'headers', {})
        response.headers.extend(common_headers)
        if headers:
            response.headers.extend(headers)

        response.status_code = status_code
        return response

    def _add_link_headers(self, response, out):
        """Add Link headers basic on the domain object."""
        types = out.get('type', [])
        if isinstance(types, basestring):
            types = [types]

        namespaces = []
        if 'Annotation' in types:
            namespaces.append('ldp#Resource')
        if 'AnnotationCollection' in types:
            namespaces.append('oa#AnnotationCollection')
        if 'AnnotationPage' in types:
            namespaces.append('oa#AnnotationPage')
        if 'BasicContainer' in types:
            namespaces.append('ldp#BasicContainer')
        if 'DirectContainer' in types:
            namespaces.append('ldp#DirectContainer')
        if 'IndirectContainer' in types:
            namespaces.append('ldp#IndirectContainer')

        links = [dict(url='http://www.w3.org/ns/{}'.format(ns), rel='type')
                 for ns in namespaces]
        containers = ['BasicContainer', 'DirectContainer', 'IndirectContainer']
        if set(containers).intersection(set(types)):
            links.append({
                'url': 'http://www.w3.org/TR/annotation-protocol/',
                'rel': 'http://www.w3.org/ns/ldp#constrainedBy'
            })

        for link in links:
            link_str = '<{0}>; rel="{1}"'.format(link['url'], link['rel'])
            response.headers.add('Link', link_str)

    def _get_container_preferences(self):
        """Get container preferences.

        Defaults to PreferContainedDescriptions.
        """
        minimal = False
        iris = False
        prefer = request.headers.get('Prefer')
        if not prefer:
            return minimal, iris
        try:
            _return, include = prefer.split(';')
        except ValueError:  # pragma: no cover
            return minimal, iris
        if _return.strip() != 'return=representation':
            return minimal, iris
        if not include.strip().startswith('include='):
            return minimal, iris
        parts = include.split('=')[1].split()
        prefs = [part.strip('"') for part in parts]

        if 'http://www.w3.org/ns/ldp#PreferMinimalContainer' in prefs:
            minimal = True
        if 'http://www.w3.org/ns/oa#PreferContainedIRIs' in prefs:
            iris = True

        return minimal, iris

    def _get_container(self, collection_base, items=None, total=None,
                       **params):
        """Return a container for Annotations."""
        out = collection_base.dictize()
        minimal, iris = self._get_container_preferences()
        if not params:
            params = {}
        params['iris'] = 1 if iris or request.args.get('iris') == '1' else None

        out['id'] = self._get_iri(collection_base, **params)

        # Defining total manually is useful for search
        # results returned in fake containers
        if total:
            out['total'] = total

        page = self._get_page_arg()
        per_page = current_app.config.get('ANNOTATIONS_PER_PAGE')
        n_pages = self._get_n_pages(items, out['total'], per_page)

        if items:
            items = self._slice_items(items, int(per_page), page)
            if isinstance(page, int) and not items:
                abort(404)
            elif isinstance(page, int):
                return self._get_page(page, n_pages, per_page, collection_base,
                                      items, partof=out, **params)
            elif minimal:
                out['first'] = self._get_iri(collection_base, page=0, **params)
            else:
                out['first'] = self._get_page(0, n_pages, per_page,
                                              collection_base, items, **params)
            if n_pages > 1:
                out['last'] = self._get_iri(collection_base, page=n_pages - 1,
                                            **params)

        return out

    def _slice_items(self, items, per_page, page=0):
        """Return a slice of items. """
        start = page * per_page if page and page > 0 else 0
        return items[start:start + per_page]

    def _get_page_arg(self):
        """Return the page query param and check it's an int."""
        page = request.args.get('page')
        if page:
            try:
                page = int(request.args.get('page', 0))
            except ValueError:  # pragma: no cover
                abort(400, 'page must be a valid integer')
        return page

    def _get_n_pages(self, items, total, per_page):
        """Return the number of pages."""
        n = 0 if total <= 0 else (total - 1) // per_page
        return n + 1

    def _get_page(self, page, n_pages, per_page, collection_base, items,
                  partof=None, **params):
        """Return an AnnotationPage."""
        page_iri = self._get_iri(collection_base, page=page, **params)
        data = {
            'id': page_iri,
            'type': 'AnnotationPage',
            'startIndex': 0
        }

        if page > 0:
            data['prev'] = self._get_iri(collection_base, page=page - 1,
                                         **params)
        if page < n_pages - 1:
            data['next'] = self._get_iri(collection_base, page=page + 1,
                                         **params)

        if partof:
            data['partOf'] = partof

        items = self._decorate_page_items(items, params.get('iris'))
        data['items'] = items
        return data

    def _decorate_page_items(self, items, iris=False):
        """Dictize and decorate a list of page items."""
        out = []
        for item in items:
            item_dict = item.dictize()
            item_dict['id'] = self._get_iri(item)
            if iris:
                out.append(item_dict['id'])
            else:
                out.append(item_dict)
        return out


class Solution:
    def partition(self, s: str) -> List[List[str]]:
        def is_palindrome(start, end):
            while start < end:
                if s[start] != s[end]:
                    return False
                start += 1
                end -= 1
            return True

        def backtrack(start, partition):
            if start == len(s):
                ans.append(partition[:])
                return
            for end in range(start, len(s)):
                if is_palindrome(start, end):
                    partition.append(s[start:end + 1])
                    backtrack(end + 1, partition)
                    partition.pop()

        ans = []
        backtrack(0, [])
        return ans


import contextlib
import warnings

from google.protobuf import json_format as _json_format

# exports Summary, SummaryDescription, Event, TaggedRunMetadata, SessionLog
# pylint: disable=unused-import, g-importing-member
from tensorflow.core.framework.summary_pb2 import Summary
from tensorflow.core.framework.summary_pb2 import SummaryDescription
from tensorflow.core.framework.summary_pb2 import SummaryMetadata as _SummaryMetadata  # pylint: enable=unused-import
from tensorflow.core.util.event_pb2 import Event
from tensorflow.core.util.event_pb2 import SessionLog
from tensorflow.core.util.event_pb2 import TaggedRunMetadata
# pylint: enable=unused-import

from tensorflow.python.distribute import summary_op_util as _distribute_summary_op_util
from tensorflow.python.eager import context as _context
from tensorflow.python.framework import constant_op as _constant_op
from tensorflow.python.framework import dtypes as _dtypes
from tensorflow.python.framework import ops as _ops
from tensorflow.python.ops import array_ops as _array_ops
from tensorflow.python.ops import gen_logging_ops as _gen_logging_ops
from tensorflow.python.ops import gen_summary_ops as _gen_summary_ops  # pylint: disable=unused-import
from tensorflow.python.ops import summary_op_util as _summary_op_util
from tensorflow.python.ops import summary_ops_v2 as _summary_ops_v2
from tensorflow.python.summary import tb_summary
# exports FileWriter, FileWriterCache
# pylint: disable=unused-import
from tensorflow.python.summary.writer.writer import FileWriter
from tensorflow.python.summary.writer.writer_cache import FileWriterCache
# pylint: enable=unused-import

from tensorflow.python.training import training_util as _training_util
from tensorflow.python.util import compat as _compat
from tensorflow.python.util.tf_export import tf_export

@tf_export(v1=['summary.scalar'])
def scalar(name, tensor, collections=None, family=None):
  """Outputs a `Summary` protocol buffer containing a single scalar value.

  The generated Summary has a Tensor.proto containing the input Tensor.

  Args:
    name: A name for the generated node. Will also serve as the series name in
      TensorBoard.
    tensor: A real numeric Tensor containing a single value.
    collections: Optional list of graph collections keys. The new summary op is
      added to these collections. Defaults to `[GraphKeys.SUMMARIES]`.
    family: Optional; if provided, used as the prefix of the summary tag name,
      which controls the tab name used for display on Tensorboard.

  Returns:
    A scalar `Tensor` of type `string`. Which contains a `Summary` protobuf.

  Raises:
    ValueError: If tensor has the wrong shape or type.

  @compatibility(TF2)
  For compatibility purposes, when invoked in TF2 where the outermost context is
  eager mode, this API will check if there is a suitable TF2 summary writer
  context available, and if so will forward this call to that writer instead. A
  "suitable" writer context means that the writer is set as the default writer,
  and there is an associated non-empty value for `step` (see
  `tf.summary.SummaryWriter.as_default`, `tf.summary.experimental.set_step` or
  alternatively `tf.compat.v1.train.create_global_step`). For the forwarded
  call, the arguments here will be passed to the TF2 implementation of
  `tf.summary.scalar`, and the return value will be an empty bytestring tensor,
  to avoid duplicate summary writing. This forwarding is best-effort and not all
  arguments will be preserved.

  To migrate to TF2, please use `tf.summary.scalar` instead. Please check
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete
  steps for migration. `tf.summary.scalar` can also log training metrics in
  Keras, you can check [Logging training metrics in
  Keras](https://www.tensorflow.org/tensorboard/scalars_and_keras) for details.

  #### How to Map Arguments

  | TF1 Arg Name  | TF2 Arg Name    | Note                                   |
  | :------------ | :-------------- | :------------------------------------- |
  | `name`        | `name`          | -                                      |
  | `tensor`      | `data`          | -                                      |
  | -             | `step`          | Explicit int64-castable monotonic step |
  :               :                 : value. If omitted, this defaults to    :
  :               :                 : `tf.summary.experimental.get_step()`.  :
  | `collections` | Not Supported   | -                                      |
  | `family`      | Removed         | Please use `tf.name_scope` instead to  |
  :               :                 : manage summary name prefix.            :
  | -             | `description`   | Optional long-form `str` description   |
  :               :                 : for the summary. Markdown is supported.:
  :               :                 : Defaults to empty.                     :

  @end_compatibility
  """
  if _distribute_summary_op_util.skip_summary():
    return _constant_op.constant('')

  # Special case: invoke v2 op for TF2 users who have a v2 writer.
  if _should_invoke_v2_op():
    # Defer the import to happen inside the symbol to prevent breakage due to
    # missing dependency.
    with _compat_summary_scope(name, family) as tag:
      tb_summary.scalar(name=tag, data=tensor, step=_get_step_for_v2())
    # Return an empty Tensor, which will be acceptable as an input to the
    # `tf.compat.v1.summary.merge()` API.
    return _constant_op.constant(b'')

  # Fall back to legacy v1 scalar implementation.
  with _summary_op_util.summary_scope(
      name, family, values=[tensor]) as (tag, scope):
    val = _gen_logging_ops.scalar_summary(tags=tag, values=tensor, name=scope)
    _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES])
  return val

@tf_export(v1=['summary.image'])
def image(name, tensor, max_outputs=3, collections=None, family=None):
  """Outputs a `Summary` protocol buffer with images.

  The summary has up to `max_outputs` summary values containing images. The
  images are built from `tensor` which must be 4-D with shape `[batch_size,
  height, width, channels]` and where `channels` can be:

  *  1: `tensor` is interpreted as Grayscale.
  *  3: `tensor` is interpreted as RGB.
  *  4: `tensor` is interpreted as RGBA.

  The images have the same number of channels as the input tensor. For float
  input, the values are normalized one image at a time to fit in the range
  `[0, 255]`.  `uint8` values are unchanged.  The op uses two different
  normalization algorithms:

  *  If the input values are all positive, they are rescaled so the largest one
     is 255.

  *  If any input value is negative, the values are shifted so input value 0.0
     is at 127.  They are then rescaled so that either the smallest value is 0,
     or the largest one is 255.

  The `tag` in the outputted Summary.Value protobufs is generated based on the
  name, with a suffix depending on the max_outputs setting:

  *  If `max_outputs` is 1, the summary value tag is '*name*/image'.
  *  If `max_outputs` is greater than 1, the summary value tags are
     generated sequentially as '*name*/image/0', '*name*/image/1', etc.

  Args:
    name: A name for the generated node. Will also serve as a series name in
      TensorBoard.
    tensor: A 4-D `uint8` or `float32` `Tensor` of shape `[batch_size, height,
      width, channels]` where `channels` is 1, 3, or 4.
    max_outputs: Max number of batch elements to generate images for.
    collections: Optional list of ops.GraphKeys.  The collections to add the
      summary to.  Defaults to [_ops.GraphKeys.SUMMARIES]
    family: Optional; if provided, used as the prefix of the summary tag name,
      which controls the tab name used for display on Tensorboard.

  Returns:
    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
    buffer.

  @compatibility(TF2)
  For compatibility purposes, when invoked in TF2 where the outermost context is
  eager mode, this API will check if there is a suitable TF2 summary writer
  context available, and if so will forward this call to that writer instead. A
  "suitable" writer context means that the writer is set as the default writer,
  and there is an associated non-empty value for `step` (see
  `tf.summary.SummaryWriter.as_default`, `tf.summary.experimental.set_step` or
  alternatively `tf.compat.v1.train.create_global_step`). For the forwarded
  call, the arguments here will be passed to the TF2 implementation of
  `tf.summary.image`, and the return value will be an empty bytestring tensor,
  to avoid duplicate summary writing. This forwarding is best-effort and not all
  arguments will be preserved. Additionally:

  *  The TF2 op does not do any of the normalization steps described above.
     Rather than rescaling data that's outside the expected range, it simply
     clips it.
  *  The TF2 op just outputs the data under a single tag that contains multiple
     samples, rather than multiple tags (i.e. no "/0" or "/1" suffixes).

  To migrate to TF2, please use `tf.summary.image` instead. Please check
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete
  steps for migration.

  #### How to Map Arguments

  | TF1 Arg Name  | TF2 Arg Name    | Note                                   |
  | :------------ | :-------------- | :------------------------------------- |
  | `name`        | `name`          | -                                      |
  | `tensor`      | `data`          | -                                      |
  | -             | `step`          | Explicit int64-castable monotonic step |
  :               :                 : value. If omitted, this defaults to    :
  :               :                 : `tf.summary.experimental.get_step()`.  :
  | `max_outputs` | `max_outputs`   | -                                      |
  | `collections` | Not Supported   | -                                      |
  | `family`      | Removed         | Please use `tf.name_scope` instead     |
  :               :                 : to manage summary name prefix.         :
  | -             | `description`   | Optional long-form `str` description   |
  :               :                 : for the summary. Markdown is supported.:
  :               :                 : Defaults to empty.                     :

  @end_compatibility
  """
  if _distribute_summary_op_util.skip_summary():
    return _constant_op.constant('')

  # Special case: invoke v2 op for TF2 users who have a v2 writer.
  if _should_invoke_v2_op():
    # Defer the import to happen inside the symbol to prevent breakage due to
    # missing dependency.
    with _compat_summary_scope(name, family) as tag:
      tb_summary.image(
          name=tag,
          data=tensor,
          step=_get_step_for_v2(),
          max_outputs=max_outputs)
    # Return an empty Tensor, which will be acceptable as an input to the
    # `tf.compat.v1.summary.merge()` API.
    return _constant_op.constant(b'')

  # Fall back to legacy v1 image implementation.
  with _summary_op_util.summary_scope(
      name, family, values=[tensor]) as (tag, scope):
    val = _gen_logging_ops.image_summary(
        tag=tag, tensor=tensor, max_images=max_outputs, name=scope)
    _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES])
  return val

@tf_export(v1=['summary.histogram'])
def histogram(name, values, collections=None, family=None):
  # pylint: disable=line-too-long
  """Outputs a `Summary` protocol buffer with a histogram.

  Adding a histogram summary makes it possible to visualize your data's
  distribution in TensorBoard. You can see a detailed explanation of the
  TensorBoard histogram dashboard
  [here](https://www.tensorflow.org/get_started/tensorboard_histograms).

  The generated
  [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto)
  has one summary value containing a histogram for `values`.

  This op reports an `InvalidArgument` error if any value is not finite.

  Args:
    name: A name for the generated node. Will also serve as a series name in
      TensorBoard.
    values: A real numeric `Tensor`. Any shape. Values to use to
      build the histogram.
    collections: Optional list of graph collections keys. The new summary op is
      added to these collections. Defaults to `[GraphKeys.SUMMARIES]`.
    family: Optional; if provided, used as the prefix of the summary tag name,
      which controls the tab name used for display on Tensorboard.

  Returns:
    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
    buffer.

  @compatibility(TF2)
  For compatibility purposes, when invoked in TF2 where the outermost context is
  eager mode, this API will check if there is a suitable TF2 summary writer
  context available, and if so will forward this call to that writer instead. A
  "suitable" writer context means that the writer is set as the default writer,
  and there is an associated non-empty value for `step` (see
  `tf.summary.SummaryWriter.as_default`, `tf.summary.experimental.set_step` or
  alternatively `tf.compat.v1.train.create_global_step`). For the forwarded
  call, the arguments here will be passed to the TF2 implementation of
  `tf.summary.histogram`, and the return value will be an empty bytestring
  tensor, to avoid duplicate summary writing. This forwarding is best-effort and
  not all arguments will be preserved.

  To migrate to TF2, please use `tf.summary.histogram` instead. Please check
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete
  steps for migration.

  #### How to Map Arguments

  | TF1 Arg Name  | TF2 Arg Name    | Note                                   |
  | :------------ | :-------------- | :------------------------------------- |
  | `name`        | `name`          | -                                      |
  | `values`      | `data`          | -                                      |
  | -             | `step`          | Explicit int64-castable monotonic step |
  :               :                 : value. If omitted, this defaults to    :
  :               :                 : `tf.summary.experimental.get_step()`   :
  | -             | `buckets`       | Optional positive `int` specifying     |
  :               :                 : the histogram bucket number.           :
  | `collections` | Not Supported   | -                                      |
  | `family`      | Removed         | Please use `tf.name_scope` instead     |
  :               :                 : to manage summary name prefix.         :
  | -             | `description`   | Optional long-form `str` description   |
  :               :                 : for the summary. Markdown is supported.:
  :               :                 : Defaults to empty.                     :

  @end_compatibility
  """
  if _distribute_summary_op_util.skip_summary():
    return _constant_op.constant('')

  # Special case: invoke v2 op for TF2 users who have a v2 writer.
  if _should_invoke_v2_op():
    # Defer the import to happen inside the symbol to prevent breakage due to
    # missing dependency.
    with _compat_summary_scope(name, family) as tag:
      tb_summary.histogram(name=tag, data=values, step=_get_step_for_v2())
    # Return an empty Tensor, which will be acceptable as an input to the
    # `tf.compat.v1.summary.merge()` API.
    return _constant_op.constant(b'')

  # Fall back to legacy v1 histogram implementation.
  with _summary_op_util.summary_scope(
      name, family, values=[values],
      default_name='HistogramSummary') as (tag, scope):
    val = _gen_logging_ops.histogram_summary(
        tag=tag, values=values, name=scope)
    _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES])
  return val

@tf_export(v1=['summary.audio'])
def audio(name, tensor, sample_rate, max_outputs=3, collections=None,
          family=None):
  # pylint: disable=line-too-long
  """Outputs a `Summary` protocol buffer with audio.

  The summary has up to `max_outputs` summary values containing audio. The
  audio is built from `tensor` which must be 3-D with shape `[batch_size,
  frames, channels]` or 2-D with shape `[batch_size, frames]`. The values are
  assumed to be in the range of `[-1.0, 1.0]` with a sample rate of
  `sample_rate`.

  The `tag` in the outputted Summary.Value protobufs is generated based on the
  name, with a suffix depending on the max_outputs setting:

  *  If `max_outputs` is 1, the summary value tag is '*name*/audio'.
  *  If `max_outputs` is greater than 1, the summary value tags are
     generated sequentially as '*name*/audio/0', '*name*/audio/1', etc

  Args:
    name: A name for the generated node. Will also serve as a series name in
      TensorBoard.
    tensor: A 3-D `float32` `Tensor` of shape `[batch_size, frames, channels]`
      or a 2-D `float32` `Tensor` of shape `[batch_size, frames]`.
    sample_rate: A Scalar `float32` `Tensor` indicating the sample rate of the
      signal in hertz.
    max_outputs: Max number of batch elements to generate audio for.
    collections: Optional list of ops.GraphKeys.  The collections to add the
      summary to.  Defaults to [_ops.GraphKeys.SUMMARIES]
    family: Optional; if provided, used as the prefix of the summary tag name,
      which controls the tab name used for display on Tensorboard.

  Returns:
    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
    buffer.

  @compatibility(TF2)
  For compatibility purposes, when invoked in TF2 where the outermost context is
  eager mode, this API will check if there is a suitable TF2 summary writer
  context available, and if so will forward this call to that writer instead. A
  "suitable" writer context means that the writer is set as the default writer,
  and there is an associated non-empty value for `step` (see
  `tf.summary.SummaryWriter.as_default`, `tf.summary.experimental.set_step` or
  alternatively `tf.compat.v1.train.create_global_step`). For the forwarded
  call, the arguments here will be passed to the TF2 implementation of
  `tf.summary.audio`, and the return value will be an empty bytestring tensor,
  to avoid duplicate summary writing. This forwarding is best-effort and not all
  arguments will be preserved. Additionally:

  * The TF2 op just outputs the data under a single tag that contains multiple
    samples, rather than multiple tags (i.e. no "/0" or "/1" suffixes).

  To migrate to TF2, please use `tf.summary.audio` instead. Please check
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete
  steps for migration.

  #### How to Map Arguments

  | TF1 Arg Name  | TF2 Arg Name    | Note                                   |
  | :------------ | :-------------- | :------------------------------------- |
  | `name`        | `name`          | -                                      |
  | `tensor`      | `data`          | Input for this argument now must be    |
  :               :                 : three-dimensional `[k, t, c]`, where   :
  :               :                 : `k` is the number of audio clips, `t`  :
  :               :                 : is the number of frames, and `c` is    :
  :               :                 : the number of channels. Two-dimensional:
  :               :                 : input is no longer supported.          :
  | `sample_rate` | `sample_rate`   | -                                      |
  | -             | `step`          | Explicit int64-castable monotonic step |
  :               :                 : value. If omitted, this defaults to    :
  :               :                 : `tf.summary.experimental.get_step()`.  :
  | `max_outputs` | `max_outputs`   | -                                      |
  | `collections` | Not Supported   | -                                      |
  | `family`      | Removed         | Please use `tf.name_scope` instead to  |
  :               :                 : manage summary name prefix.            :
  | -             | `encoding`      | Optional constant str for the desired  |
  :               :                 : encoding. Check the docs for           :
  :               :                 : `tf.summary.audio` for latest supported:
  :               :                 : audio formats.                         :
  | -             | `description`   | Optional long-form `str` description   |
  :               :                 : for the summary. Markdown is supported.:
  :               :                 : Defaults to empty.                     :

  @end_compatibility
  """
  if _distribute_summary_op_util.skip_summary():
    return _constant_op.constant('')

  # Special case: invoke v2 op for TF2 users who have a v2 writer.
  if _should_invoke_v2_op():
    # Defer the import to happen inside the symbol to prevent breakage due to
    # missing dependency.
    if tensor.shape.rank == 2:
      # TF2 op requires 3-D tensor, add the `channels` dimension.
      tensor = _array_ops.expand_dims_v2(tensor, axis=2)
    with _compat_summary_scope(name, family) as tag:
      tb_summary.audio(
          name=tag,
          data=tensor,
          sample_rate=sample_rate,
          step=_get_step_for_v2(),
          max_outputs=max_outputs,
      )
    # Return an empty Tensor, which will be acceptable as an input to the
    # `tf.compat.v1.summary.merge()` API.
    return _constant_op.constant(b'')

  # Fall back to legacy v1 audio implementation.
  with _summary_op_util.summary_scope(
      name, family=family, values=[tensor]) as (tag, scope):
    sample_rate = _ops.convert_to_tensor(
        sample_rate, dtype=_dtypes.float32, name='sample_rate')
    val = _gen_logging_ops.audio_summary_v2(
        tag=tag, tensor=tensor, max_outputs=max_outputs,
        sample_rate=sample_rate, name=scope)
    _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES])
  return val

@tf_export(v1=['summary.text'])
def text(name, tensor, collections=None):
  """Summarizes textual data.

  Text data summarized via this plugin will be visible in the Text Dashboard
  in TensorBoard. The standard TensorBoard Text Dashboard will render markdown
  in the strings, and will automatically organize 1d and 2d tensors into tables.
  If a tensor with more than 2 dimensions is provided, a 2d subarray will be
  displayed along with a warning message. (Note that this behavior is not
  intrinsic to the text summary api, but rather to the default TensorBoard text
  plugin.)

  Args:
    name: A name for the generated node. Will also serve as a series name in
      TensorBoard.
    tensor: a string-type Tensor to summarize.
    collections: Optional list of ops.GraphKeys.  The collections to add the
      summary to.  Defaults to [_ops.GraphKeys.SUMMARIES]

  Returns:
    A TensorSummary op that is configured so that TensorBoard will recognize
    that it contains textual data. The TensorSummary is a scalar `Tensor` of
    type `string` which contains `Summary` protobufs.

  Raises:
    ValueError: If tensor has the wrong type.

  @compatibility(TF2)
  For compatibility purposes, when invoked in TF2 where the outermost context is
  eager mode, this API will check if there is a suitable TF2 summary writer
  context available, and if so will forward this call to that writer instead. A
  "suitable" writer context means that the writer is set as the default writer,
  and there is an associated non-empty value for `step` (see
  `tf.summary.SummaryWriter.as_default`, `tf.summary.experimental.set_step` or
  alternatively `tf.compat.v1.train.create_global_step`). For the forwarded
  call, the arguments here will be passed to the TF2 implementation of
  `tf.summary.text`, and the return value will be an empty bytestring tensor, to
  avoid duplicate summary writing. This forwarding is best-effort and not all
  arguments will be preserved.

  To migrate to TF2, please use `tf.summary.text` instead. Please check
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x) for concrete
  steps for migration.

  #### How to Map Arguments

  | TF1 Arg Name  | TF2 Arg Name    | Note                                   |
  | :------------ | :-------------- | :------------------------------------- |
  | `name`        | `name`          | -                                      |
  | `tensor`      | `data`          | -                                      |
  | -             | `step`          | Explicit int64-castable monotonic step |
  :               :                 : value. If omitted, this defaults to    :
  :               :                 : `tf.summary.experimental.get_step()`.  :
  | `collections` | Not Supported   | -                                      |
  | -             | `description`   | Optional long-form `str` description   |
  :               :                 : for the summary. Markdown is supported.:
  :               :                 : Defaults to empty.                     :

  @end_compatibility
  """
  if tensor.dtype != _dtypes.string:
    raise ValueError('Expected tensor %s to have dtype string, got %s' %
                     (tensor.name, tensor.dtype))

  # Special case: invoke v2 op for TF2 users who have a v2 writer.
  if _should_invoke_v2_op():
    # `skip_summary` check for v1 op case is done in `tensor_summary`.
    if _distribute_summary_op_util.skip_summary():
      return _constant_op.constant('')
    # Defer the import to happen inside the symbol to prevent breakage due to
    # missing dependency.
    tb_summary.text(name=name, data=tensor, step=_get_step_for_v2())
    # Return an empty Tensor, which will be acceptable as an input to the
    # `tf.compat.v1.summary.merge()` API.
    return _constant_op.constant(b'')

  # Fall back to legacy v1 text implementation.
  summary_metadata = _SummaryMetadata(
      plugin_data=_SummaryMetadata.PluginData(plugin_name='text'))
  t_summary = tensor_summary(
      name=name,
      tensor=tensor,
      summary_metadata=summary_metadata,
      collections=collections)
  return t_summary

@tf_export(v1=['summary.tensor_summary'])
def tensor_summary(name,
                   tensor,
                   summary_description=None,
                   collections=None,
                   summary_metadata=None,
                   family=None,
                   display_name=None):
  """Outputs a `Summary` protocol buffer with a serialized tensor.proto.

  Args:
    name: A name for the generated node. If display_name is not set, it will
      also serve as the tag name in TensorBoard. (In that case, the tag
      name will inherit tf name scopes.)
    tensor: A tensor of any type and shape to serialize.
    summary_description: A long description of the summary sequence. Markdown
      is supported.
    collections: Optional list of graph collections keys. The new summary op is
      added to these collections. Defaults to `[GraphKeys.SUMMARIES]`.
    summary_metadata: Optional SummaryMetadata proto (which describes which
      plugins may use the summary value).
    family: Optional; if provided, used as the prefix of the summary tag,
      which controls the name used for display on TensorBoard when
      display_name is not set.
    display_name: A string used to name this data in TensorBoard. If this is
      not set, then the node name will be used instead.

  Returns:
    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
    buffer.
  """

  if summary_metadata is None:
    summary_metadata = _SummaryMetadata()

  if summary_description is not None:
    summary_metadata.summary_description = summary_description

  if display_name is not None:
    summary_metadata.display_name = display_name

  serialized_summary_metadata = summary_metadata.SerializeToString()

  if _distribute_summary_op_util.skip_summary():
    return _constant_op.constant('')
  with _summary_op_util.summary_scope(
      name, family, values=[tensor]) as (tag, scope):
    val = _gen_logging_ops.tensor_summary_v2(
        tensor=tensor,
        tag=tag,
        name=scope,
        serialized_summary_metadata=serialized_summary_metadata)
    _summary_op_util.collect(val, collections, [_ops.GraphKeys.SUMMARIES])
  return val

@tf_export(v1=['summary.merge'])
def merge(inputs, collections=None, name=None):
  # pylint: disable=line-too-long
  """Merges summaries.

  This op creates a
  [`Summary`](https://www.tensorflow.org/code/tensorflow/core/framework/summary.proto)
  protocol buffer that contains the union of all the values in the input
  summaries.

  When the Op is run, it reports an `InvalidArgument` error if multiple values
  in the summaries to merge use the same tag.

  Args:
    inputs: A list of `string` `Tensor` objects containing serialized `Summary`
      protocol buffers.
    collections: Optional list of graph collections keys. The new summary op is
      added to these collections. Defaults to `[]`.
    name: A name for the operation (optional).

  Returns:
    A scalar `Tensor` of type `string`. The serialized `Summary` protocol
    buffer resulting from the merging.

  Raises:
    RuntimeError: If called with eager mode enabled.

  @compatibility(TF2)
  This API is not compatible with eager execution or `tf.function`. To migrate
  to TF2, this API can be omitted entirely, because in TF2 individual summary
  ops, like `tf.summary.scalar()`, write directly to the default summary writer
  if one is active. Thus, it's not necessary to merge summaries or to manually
  add the resulting merged summary output to the writer. See the usage example
  shown below.

  For a comprehensive `tf.summary` migration guide, please follow
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x).

  #### TF1 & TF2 Usage Example

  TF1:

  ```python
  dist = tf.compat.v1.placeholder(tf.float32, [100])
  tf.compat.v1.summary.histogram(name="distribution", values=dist)
  writer = tf.compat.v1.summary.FileWriter("/tmp/tf1_summary_example")
  summaries = tf.compat.v1.summary.merge_all()

  sess = tf.compat.v1.Session()
  for step in range(100):
    mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100])
    summ = sess.run(summaries, feed_dict={dist: mean_moving_normal})
    writer.add_summary(summ, global_step=step)
  ```

  TF2:

  ```python
  writer = tf.summary.create_file_writer("/tmp/tf2_summary_example")
  for step in range(100):
    mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100])
    with writer.as_default(step=step):
      tf.summary.histogram(name='distribution', data=mean_moving_normal)
  ```

  @end_compatibility
  """
  # pylint: enable=line-too-long
  if _context.executing_eagerly():
    raise RuntimeError(
        'Merging tf.summary.* ops is not compatible with eager execution. '
        'Use tf.contrib.summary instead.')
  if _distribute_summary_op_util.skip_summary():
    return _constant_op.constant('')
  name = _summary_op_util.clean_tag(name)
  with _ops.name_scope(name, 'Merge', inputs):
    val = _gen_logging_ops.merge_summary(inputs=inputs, name=name)
    _summary_op_util.collect(val, collections, [])
  return val

@tf_export(v1=['summary.merge_all'])
def merge_all(key=_ops.GraphKeys.SUMMARIES, scope=None, name=None):
  """Merges all summaries collected in the default graph.

  Args:
    key: `GraphKey` used to collect the summaries.  Defaults to
      `GraphKeys.SUMMARIES`.
    scope: Optional scope used to filter the summary ops, using `re.match`.
    name: A name for the operation (optional).

  Returns:
    If no summaries were collected, returns None.  Otherwise returns a scalar
    `Tensor` of type `string` containing the serialized `Summary` protocol
    buffer resulting from the merging.

  Raises:
    RuntimeError: If called with eager execution enabled.

  @compatibility(TF2)
  This API is not compatible with eager execution or `tf.function`. To migrate
  to TF2, this API can be omitted entirely, because in TF2 individual summary
  ops, like `tf.summary.scalar()`, write directly to the default summary writer
  if one is active. Thus, it's not necessary to merge summaries or to manually
  add the resulting merged summary output to the writer. See the usage example
  shown below.

  For a comprehensive `tf.summary` migration guide, please follow
  [Migrating tf.summary usage to
  TF 2.0](https://www.tensorflow.org/tensorboard/migrate#in_tf_1x).

  #### TF1 & TF2 Usage Example

  TF1:

  ```python
  dist = tf.compat.v1.placeholder(tf.float32, [100])
  tf.compat.v1.summary.histogram(name="distribution", values=dist)
  writer = tf.compat.v1.summary.FileWriter("/tmp/tf1_summary_example")
  summaries = tf.compat.v1.summary.merge_all()

  sess = tf.compat.v1.Session()
  for step in range(100):
    mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100])
    summ = sess.run(summaries, feed_dict={dist: mean_moving_normal})
    writer.add_summary(summ, global_step=step)
  ```

  TF2:

  ```python
  writer = tf.summary.create_file_writer("/tmp/tf2_summary_example")
  for step in range(100):
    mean_moving_normal = np.random.normal(loc=step, scale=1, size=[100])
    with writer.as_default(step=step):
      tf.summary.histogram(name='distribution', data=mean_moving_normal)
  ```

  @end_compatibility
  """
  if _context.executing_eagerly():
    raise RuntimeError(
        'Merging tf.summary.* ops is not compatible with eager execution. '
        'Use tf.contrib.summary instead.')
  summary_ops = _ops.get_collection(key, scope=scope)
  if not summary_ops:
    return None
  else:
    return merge(summary_ops, name=name)

@tf_export(v1=['summary.get_summary_description'])
def get_summary_description(node_def):
  """Given a TensorSummary node_def, retrieve its SummaryDescription.

  When a Summary op is instantiated, a SummaryDescription of associated
  metadata is stored in its NodeDef. This method retrieves the description.

  Args:
    node_def: the node_def_pb2.NodeDef of a TensorSummary op

  Returns:
    a summary_pb2.SummaryDescription

  Raises:
    ValueError: if the node is not a summary op.

  @compatibility(eager)
  Not compatible with eager execution. To write TensorBoard
  summaries under eager execution, use `tf.contrib.summary` instead.
  @end_compatibility
  """

  if node_def.op != 'TensorSummary':
    raise ValueError("Can't get_summary_description on %s" % node_def.op)
  description_str = _compat.as_str_any(node_def.attr['description'].s)
  summary_description = SummaryDescription()
  _json_format.Parse(description_str, summary_description)
  return summary_description

def _get_step_for_v2():
  """Get step for v2 summary invocation in v1.

  In order to invoke v2 op in `tf.compat.v1.summary`, global step needs to be
  set for the v2 summary writer.

  Returns:
    The step set by `tf.summary.experimental.set_step` or
    `tf.compat.v1.train.create_global_step`, or None is no step has been
    set.
  """
  step = _summary_ops_v2.get_step()
  if step is not None:
    return step
  return _training_util.get_global_step()

def _should_invoke_v2_op():
  """Check if v2 op can be invoked.

  When calling TF1 summary op in eager mode, if the following conditions are
  met, v2 op will be invoked:
  - The outermost context is eager mode.
  - A default TF2 summary writer is present.
  - A step is set for the writer (using `tf.summary.SummaryWriter.as_default`,
    `tf.summary.experimental.set_step` or
    `tf.compat.v1.train.create_global_step`).

  Returns:
    A boolean indicating whether v2 summary op should be invoked.
  """
  # Check if in eager mode.
  if not _ops.executing_eagerly_outside_functions():
    return False
  # Check if a default summary writer is present.
  if not _summary_ops_v2.has_default_writer():
    warnings.warn(
        'Cannot activate TF2 compatibility support for TF1 summary ops: '
        'default summary writer not found.')
    return False
  # Check if a step is set for the writer.
  if _get_step_for_v2() is None:
    warnings.warn(
        'Cannot activate TF2 compatibility support for TF1 summary ops: '
        'global step not set. To set step for summary writer, '
        'use `tf.summary.SummaryWriter.as_default(step=_)`, '
        '`tf.summary.experimental.set_step()` or '
        '`tf.compat.v1.train.create_global_step()`.')
    return False
  return True

@contextlib.contextmanager
def _compat_summary_scope(name, family):
  """Handles `family` argument for v2 op invocation in v1."""
  # Get a new summary tag name with the `family` arg.
  with _summary_op_util.summary_scope(name, family) as (tag, _):
    # Reset the root name scope with an empty summary_scope.
    with _summary_op_util.summary_scope(name='', family=None):
      yield tag


# standard imports
import logging

# external imports
from fastapi import APIRouter, Depends, status, Query
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

# local imports
from api import dependencies
from api.api_v1.docs.openapi.api.routes.country import (add_country_endpoint_responses,
                                                        fetch_all_countries_endpoint_responses,
                                                        update_country_endpoint_responses)
from src.config import config
from src import crud
from src.schemas import Paginate
from src.schemas.country import CountryCreate, CountryUpdate
from tasks import sync_supported_languages

logg = logging.getLogger()
router = APIRouter(prefix='/countries')

@router.get("", responses=fetch_all_countries_endpoint_responses())
def fetch_all_countries(db: Session = Depends(dependencies.get_database),
                        limit: int = Query(
                            default=100,
                            title="limit",
                            description="the row to end at when filtering query results (pagination end)",
                        ),
                        skip: int = Query(
                            default=0,
                            title="skip",
                            description="the row to start from when filtering query results (pagination start)")
                        ) -> Paginate:
    """This function fetches all countries from the database.
    :param db: A database session object.
    :type db: Session
    :param limit: The number of rows to return.
    :type limit: int
    :param skip: The number of rows to skip.
    :type skip: int
    :return: A Paginate object.
    :rtype: Paginate
    """
    countries = crud.country.get_multi(db=db, limit=limit, skip=skip)
    return Paginate(values=countries, total=len(countries), prev_link="", next_link="")

@router.post("/add", responses=add_country_endpoint_responses())
def add_country(payload: CountryCreate, db: Session = Depends(dependencies.get_database)) -> JSONResponse:
    """This endpoint adds a country object to the database.
    :param db: A database session object.
    :type db: Session
    :param payload: Country object to be added to the database.
    :type payload: CountryCreate
    :return: A JSON response containing the country object that was added to the database.
    :rtype: JSONResponse
    """
    response = {}
    try:
        country = crud.country.create(db=db, obj_in=payload)
        response['message'] = 'Country successfully added.'
        response['status'] = 0
        response['data'] = jsonable_encoder(country)
        sync_supported_languages.apply_async(queue=config.get("WORKER_QUEUE"))
        return JSONResponse(content=response, status_code=status.HTTP_201_CREATED)
    except IntegrityError as error:
        logg.error(error)
        response['message'] = 'Country already exists.'
        response['status'] = 1
        return JSONResponse(content=response, status_code=status.HTTP_409_CONFLICT)

@router.patch("/update/{country_id}", responses=update_country_endpoint_responses())
def update_country(payload: CountryUpdate,
                   country_id: int,
                   db: Session = Depends(dependencies.get_database)) -> JSONResponse:
    """This endpoint updates a country object in the database.
    :param db: A database session object.
    :type db: Session
    :param payload: Country data to update.
    :type payload: CountryUpdate
    :param country_id: id of the country object to update.
    :type country_id: int
    :return: A JSON response containing the country object that was updated in the database.
    :rtype: JSONResponse
    """
    response = {}
    country = crud.country.get(db=db, object_id=country_id)
    if not country:
        response['message'] = 'Country not found.'
        response['status'] = 1
        return JSONResponse(content=response, status_code=status.HTTP_404_NOT_FOUND)
    try:
        updated_country = crud.country.update(db=db, db_obj=country, obj_in=payload)
        response['message'] = 'Country successfully updated.'
        response['status'] = 0
        response['data'] = jsonable_encoder(updated_country)
        return JSONResponse(content=response, status_code=status.HTTP_200_OK)
    except Exception as error:
        logg.error(error)
        response['message'] = 'Country not updated.'
        response['status'] = 1
        return JSONResponse(content=response, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)


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

os.putenv("SAC_DISPLAY_COPYRIGHT", "0")

p = subprocess.Popen(['sac'], stdin=subprocess.PIPE)

s = ""
s += "fg seismo \n"
s += "ch kuser0 &1,kevnm& \n"
tmp = "ABC"   # Python变量，用于代替SAC中的黑板变量
s += "ch kuser1 %s \n" % (tmp)
s += "lh kuser0 kuser1 \n"
s += "q \n"

p.communicate(s.encode())


import gcj

class Solver(gcj.Solver):
    def _solve_one(self):
        N = self._getintline()
        sets = self._getstringsline()
        assert len(sets) == N
        letordering = []
        for i in range(26):
            letordering.append([None, None])
        PREV, NEXT = range(2)

        # 1. order letters
        for set in sets:
            prevlet = None
            let = None
            for letter in set:
                prevlet = let
                let = ord(letter) - ord('a')
                if prevlet is not None and prevlet != let:
                    # the pair (let -> prevlet) specifies ordering of letters, check and fail/add
                    prevorder = letordering[prevlet]
                    nextorder = letordering[let]
                    if prevorder[NEXT] is not None and prevorder[NEXT] != let:
                        return 0
                    if nextorder[PREV] is not None and nextorder[PREV] != prevlet:
                        return 0
                    p = let
                    while p is not None and p != prevlet:
                        p = letordering[p][NEXT]
                    if p == prevlet:
                        return 0
                    prevorder[NEXT] = let
                    nextorder[PREV] = prevlet
        components = []
        for let in range(26):
            if letordering[let][PREV] is None:
                components.append(let)
        letters = []
        for component in components:
            letter = component
            while letter is not None:
                letters.append(letter)
                letter = letordering[letter][NEXT]
        letterorder = range(26)
        for i, letter in enumerate(letters):
            letterorder[letter] = i
        # letters contains letters in their order, letterorder contains order index of each letter
        # 2. order sets
#        print "Order of letters: %s" % (letterorder,)
 #       print "sets: %s" % (sets,)
        sets = map(lambda set: (ord(set[0]) - ord('a'), ord(set[-1]) - ord('a'),), sets)
  #      print "sets: %s" % (sets,)
        BEGIN, END = range(2)
        sets = sorted(sets, key=lambda set: set[BEGIN]==set[END] and (letterorder[set[BEGIN]] - 0.1) or letterorder[set[BEGIN]])
        prevset = None
        setcomponents = []
        setcomponent = []
        setcount = 26*[0]
        for set in sets:
            #print "Examining set %s" % (set,)
            if set[BEGIN] == set[END]:
                setcount[set[BEGIN]] += 1
            if prevset is not None:
                if letterorder[prevset[END]] > letterorder[set[BEGIN]]:
                    return 0
                elif letterorder[prevset[END]] < letterorder[set[BEGIN]]:
                    setcomponent = []
                    setcomponents.append(setcomponent)
            else:
                # very first set
                setcomponent = []
                setcomponents.append(setcomponent)
            if set[BEGIN] != set[END] or setcount[set[BEGIN]] == 1:
                setcomponent.append(set)
            prevset = set
        # setcomponents contains components of set graph, each component is ordered list of sets
        results = 1
        def modmultiply(initial, factor, mod):
            for f in range(factor):
                initial *= (f+1)
                initial %= mod
            return initial
        for setcomponent in setcomponents:
            for set in setcomponent:
                if set[BEGIN] == set[END]:
                    assert setcount[set[BEGIN]] > 0
                    factor = setcount[set[BEGIN]]
                    results = modmultiply(results, factor, 1000000007)
        results = modmultiply(results, len(setcomponents), 1000000007)
        #print "setcount = %s" % (setcount,)
        #print "setcomponents = %s" % (setcomponents,)
        return results


import numpy as np
import os
from god_config import *
import bdpy
dir_path = os.path.dirname(os.path.realpath(__file__)) #current directory
####################################################
#ML part
from sklearn.preprocessing import normalize
from sklearn.model_selection import RepeatedStratifiedKFold, GridSearchCV, train_test_split
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score

from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from imblearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder,MinMaxScaler

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d

for subject in {'Subject1'}: #for now only subject1, later on replace with subjects dictionary from god_config
    for roi in ['VC']:
        # f=open(dir_path+'/results/without-convolution/'+subject+'_'+roi+'_'+'imagination_accuracy-flat'+'.txt','w')
        subject_fmri=bdpy.BData(subjects[subject])
        X=subject_fmri.select(rois[roi])
        voxel_x = subject_fmri.get_metadata('voxel_x', where=area[roi])
        voxel_y = subject_fmri.get_metadata('voxel_y', where=area[roi])
        voxel_z = subject_fmri.get_metadata('voxel_z', where=area[roi])
        del subject_fmri
        datatype=np.load(dir_path+'/data/'+subject+'_'+'datatype'+'.npy')
        # X=X.reshape(X.shape[0],X.shape[1],1)

        input_shape=X.shape

        y=[]
        for j in range(len(datatype)):
            if datatype[j]==3:
                y.append(1)
            else:
                y.append(0)
        y=np.array(y)

        model = DummyClassifier(strategy="most_frequent")
        model.fit(X, y)
        y_pred = model.predict(X)
        accuracy1 = accuracy_score(y, y_pred)
        print('Base Accuracy: ' + roi ,accuracy1)

        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)

        true_im=X_train[y_train==1]
        true_pt=X_train[y_train==0]

        over = SMOTE(random_state=2)
        under = RandomUnderSampler(random_state=2)
        steps = [('o', over), ('u', under)]
        pipeline = Pipeline(steps=steps)
        # transform the dataset
        print("Before SMOLE",X_train.shape)
        X_train=X_train.reshape(X_train.shape[0],-1)
        X_train, y_train = pipeline.fit_resample(X_train, y_train)
        X_train = X_train.reshape((-1,input_shape[1]))
        print("After SMOLE",X_train.shape)

        smote_im=X_train[y_train==1]
        smote_pt=X_train[y_train==0]

        smote_av = np.mean(X_train,axis=0)
        smote_im_av = np.mean(smote_im,axis=0)
        smote_pt_av = np.mean(smote_pt,axis=0)

        true_av = np.mean(X_train,axis=0)
        true_im_av = np.mean(true_im,axis=0)
        true_pt_av = np.mean(true_pt,axis=0)

        fig = plt.figure(figsize =(2, 3))

        ax = fig.add_subplot(2, 3, 1,projection="3d")
        plot=ax.scatter(voxel_x,voxel_y,voxel_z,s=20,c=true_av,cmap='coolwarm',vmin=-10,vmax=+10)
        ax.set_xlabel('X Axes')
        ax.set_ylabel('Y Axes')
        ax.set_zlabel('Z Axes')
        ax.set_title("Average of true data in " + roi+ " of " + subject)
        fig.colorbar(plot,shrink=1)

        ax = fig.add_subplot(2, 3, 2,projection="3d")
        plot=ax.scatter(voxel_x,voxel_y,voxel_z,s=20,c=true_pt_av,cmap='coolwarm',vmin=-0.8,vmax=+0.8)
        ax.set_xlabel('X Axes')
        ax.set_ylabel('Y Axes')
        ax.set_zlabel('Z Axes')
        ax.set_title("Average of true perception data in " + roi+ " of " + subject)
        fig.colorbar(plot,shrink=1)

        ax = fig.add_subplot(2, 3, 3,projection="3d")
        plot=ax.scatter(voxel_x,voxel_y,voxel_z,s=20,c=true_im_av,cmap='coolwarm',vmin=-10,vmax=+10)
        ax.set_xlabel('X Axes')
        ax.set_ylabel('Y Axes')
        ax.set_zlabel('Z Axes')
        ax.set_title("Average of true imagined data in " + roi+ " of " + subject)
        fig.colorbar(plot,shrink=1)

        ax = fig.add_subplot(2, 3, 4, projection='3d')
        plot=ax.scatter(voxel_x,voxel_y,voxel_z,s=20,c=smote_av,cmap='coolwarm',vmin=-10,vmax=+10)
        ax.set_xlabel('X Axes')
        ax.set_ylabel('Y Axes')
        ax.set_zlabel('Z Axes')
        ax.set_title("Average of synthetic data in " + roi+ " of " + subject)
        fig.colorbar(plot,shrink=1)

        ax = fig.add_subplot(2, 3, 5, projection='3d')
        plot=ax.scatter(voxel_x,voxel_y,voxel_z,s=20,c=smote_pt_av,cmap='coolwarm',vmin=-0.8,vmax=+0.8)
        ax.set_xlabel('X Axes')
        ax.set_ylabel('Y Axes')
        ax.set_zlabel('Z Axes')
        ax.set_title("Average of synthetic perception data in " + roi+ " of " + subject)
        fig.colorbar(plot,shrink=1)

        ax = fig.add_subplot(2, 3, 6, projection='3d')
        plot=ax.scatter(voxel_x,voxel_y,voxel_z,s=20,c=smote_im_av,cmap='coolwarm',vmin=-10,vmax=+10)
        ax.set_xlabel('X Axes')
        ax.set_ylabel('Y Axes')
        ax.set_zlabel('Z Axes')
        ax.set_title("Average of synthetic imagined data in " + roi+ " of " + subject)
        fig.colorbar(plot,shrink=1)

        plt.show()


# 1 Вычислить число π c заданной точностью d
#
# *Пример:*
#
# - при $d = 0.001, π = 3.141.$    $10^{-1} ≤ d ≤10^{-10}$

d = 0.001  # До 8 знаков точно считает, а начиная с 9-го вычисления длятся слишком долго.
n = 0
s2 = 0
n += 1
s1 = s2 + 4 / ((2 * n) - 1)
n += 1
s2 = s1 - 4 / ((2 * n) - 1)
while s1 - s2 >= d:
    n += 1
    s1 = s2 + 4 / ((2 * n) - 1)
    n += 1
    s2 = s1 - 4 / ((2 * n) - 1)
pi = str(((s1 + s2) / 2))
d = str(d)
length_pi = 0
print(d)
if len(d) == 5 and d[4] != str(1):
    length_pi = d[4]
elif len(d) == 5 and d[3] != str(0):
    print(pi)
    quit()
else:
    length_pi = len(d) - 2
print(length_pi)
for i in range(0, (int(length_pi) + 2)):
    print(pi[i], end="")


"""City.py - Contains the City object"""

import os, random, datetime
import pygame
from Project import Project

class City(object):
    """The cities with projects to let"""

    def __init__(self, date, name="sometown", xy=(0, 0)):
        self.name = name
        self.location = xy
        self.projects = []

        # project characteristics - below should net to 1,000,000 cm/year in 4 projects
        self.project_probability = 8. / 365.  # probability of a project per day (i.e. 8/year avg)
        self.project_size = 550000.  # average project size
        self.project_growth = 500  # projects grow (shoal) at this rate on average
        self.project_unit = 4.5  # projects start at this unit rate

        self.image_loc = os.path.join('graphics', 'city_256x256.png')
        image = pygame.image.load(self.image_loc).convert()
        self.image_size = (32, 32)
        self.image = pygame.transform.scale(image, self.image_size)
        self.plane = None

        self.generate_project(date)

    def generate_project(self, date, probability=1):
        """generateProject - Add a project to the city
           probability is the probability of a project.
        """
        if random.random() <= probability:
            size = random.normalvariate(self.project_size, self.project_size * 0.25)
            size = int(size / 1000.) * 1000
            unit = random.normalvariate(self.project_unit, self.project_unit * 0.2)
            proj = Project(self, date, qty=size, unit=unit)
            self.projects.append(proj)
            return [(self, "Project %s advertised for tender in %s" % (proj.name, self.name))]
        else:
            return []

    def time_step(self, steptimesize, game):
        """update the city as time passes"""
        # eventually generate new projects here
        ts_messages = []
        # Check my projects
        for p in self.projects:
            ts_messages.extend(p.time_step(steptimesize, game))
        # generate any new projects
        ts_messages.extend(self.generate_project(game.date, self.project_probability * steptimesize))
        return ts_messages