import importlib, pkg_resources
importlib.reload(pkg_resources)

# %%
import tensorflow as tf
import tensorflow_quantum as tfq

import cirq
import sympy
import numpy as np
import seaborn as sns
import collections

# visualization tools
import matplotlib.pyplot as plt
from cirq.contrib.svg import SVGCircuit

# %% [markdown]
# ## 1. Load the data
#
# In this tutorial you will build a binary classifier to distinguish between the digits 3 and 6, following Farhi et al. This section covers the data handling that:
#
# - Loads the raw data from Keras.
# - Filters the dataset to only 3s and 6s.
# - Downscales the images so they fit can fit in a quantum computer.
# - Removes any contradictory examples.
# - Converts the binary images to Cirq circuits.
# - Converts the Cirq circuits to TensorFlow Quantum circuits.

# %% [markdown]
# ### 1.1 Load the raw data

# %% [markdown]
# Load the MNIST dataset distributed with Keras.

# %%
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

# Rescale the images from [0,255] to the [0.0,1.0] range.
x_train, x_test = x_train[..., np.newaxis]/255.0, x_test[..., np.newaxis]/255.0

print("Number of original training examples:", len(x_train))
print("Number of original test examples:", len(x_test))

# %% [markdown]
# Filter the dataset to keep just the 3s and 6s,  remove the other classes. At the same time convert the label, `y`, to boolean: `True` for `3` and `False` for 6.

# %%
def filter_36(x, y):
    keep = (y == 3) | (y == 6)
    x, y = x[keep], y[keep]
    y = y == 3
    return x,y

# %%
x_train, y_train = filter_36(x_train, y_train)
x_test, y_test = filter_36(x_test, y_test)

print("Number of filtered training examples:", len(x_train))
print("Number of filtered test examples:", len(x_test))

# %% [markdown]
# Show the first example:

# %%
# print(y_train[0])

# plt.imshow(x_train[0, :, :, 0])
# plt.colorbar()

# %% [markdown]
# ### 1.2 Downscale the images

# %% [markdown]
# An image size of 28x28 is much too large for current quantum computers. Resize the image down to 4x4:

# %%
x_train_small = tf.image.resize(x_train, (4,4)).numpy()
x_test_small = tf.image.resize(x_test, (4,4)).numpy()

# %% [markdown]
# Again, display the first training example—after resize:

# %%
# print(y_train[0])

# plt.imshow(x_train_small[0,:,:,0], vmin=0, vmax=1)
# plt.colorbar()

# %% [markdown]
# ### 1.3 Remove contradictory examples

# %% [markdown]
# From section *3.3 Learning to Distinguish Digits* of Farhi et al., filter the dataset to remove images that are labeled as belonging to both classes.
#
# This is not a standard machine-learning procedure, but is included in the interest of following the paper.

# %%
def remove_contradicting(xs, ys):
    mapping = collections.defaultdict(set)
    orig_x = {}
    # Determine the set of labels for each unique image:
    for x,y in zip(xs,ys):
       orig_x[tuple(x.flatten())] = x
       mapping[tuple(x.flatten())].add(y)

    new_x = []
    new_y = []
    for flatten_x in mapping:
      x = orig_x[flatten_x]
      labels = mapping[flatten_x]
      if len(labels) == 1:
          new_x.append(x)
          new_y.append(next(iter(labels)))
      else:
          # Throw out images that match more than one label.
          pass

    num_uniq_3 = sum(1 for value in mapping.values() if len(value) == 1 and True in value)
    num_uniq_6 = sum(1 for value in mapping.values() if len(value) == 1 and False in value)
    num_uniq_both = sum(1 for value in mapping.values() if len(value) == 2)

    return np.array(new_x), np.array(new_y)

# %% [markdown]
# The resulting counts do not closely match the reported values, but the exact procedure is not specified.
#
# It is also worth noting here that applying filtering contradictory examples at this point does not totally prevent the model from receiving contradictory training examples: the next step binarizes the data which will cause more collisions.

# %%
x_train_nocon, y_train_nocon = remove_contradicting(x_train_small, y_train)

# %% [markdown]
# ### 1.4 Encode the data as quantum circuits
#
# To process images using a quantum computer, Farhi et al. proposed representing each pixel with a qubit, with the state depending on the value of the pixel. The first step is to convert to a binary encoding.

# %%
THRESHOLD = 0.1

x_train_bin = np.array(x_train_nocon > THRESHOLD, dtype=np.float32)
x_test_bin = np.array(x_test_small > THRESHOLD, dtype=np.float32)

# %% [markdown]
# %% [markdown]

# Second, use a custiom `hinge_accuracy` metric that correctly handles `[-1, 1]` as the `y_true` labels argument.
# `tf.losses.BinaryAccuracy(threshold=0.0)` expects `y_true` to be a boolean, and so can't be used with hinge loss).

# %%
def hinge_accuracy(y_true, y_pred):
    y_true = tf.squeeze(y_true) > 0.0
    y_pred = tf.squeeze(y_pred) > 0.0
    result = tf.cast(y_true == y_pred, tf.float32)

    return tf.reduce_mean(result)

# %%
def convert_to_circuit(image):
    """Encode truncated classical image into quantum datapoint."""
    values = np.ndarray.flatten(image)
    qubits = cirq.GridQubit.rect(4, 4)
    circuit = cirq.Circuit()
    for i, value in enumerate(values):
        if value:
            circuit.append(cirq.X(qubits[i]))
    return circuit

x_train_circ = [convert_to_circuit(x) for x in x_train_bin]
x_test_circ = [convert_to_circuit(x) for x in x_test_bin]

# %% [markdown]
# Convert these `Cirq` circuits to tensors for `tfq`:

# %%
x_train_tfcirc = tfq.convert_to_tensor(x_train_circ)
x_test_tfcirc = tfq.convert_to_tensor(x_test_circ)

# %% [markdown]
# ## 2. Quantum neural network
#
# There is little guidance for a quantum circuit structure that classifies images. Since the classification is based on the expectation of the readout qubit, Farhi et al. propose using two qubit gates, with the readout qubit always acted upon. This is similar in some ways to running small a Unitary RNN across the pixels.

# %% [markdown]
# ### 2.1 Build the model circuit
#
# This following example shows this layered approach. Each layer uses *n* instances of the same gate, with each of the data qubits acting on the readout qubit.
#
# Start with a simple class that will add a layer of these gates to a circuit:

# %%
class CircuitLayerBuilder():
    def __init__(self, data_qubits, readout):
        self.data_qubits = data_qubits
        self.readout = readout

    def add_layer(self, circuit, gate, prefix):
        for i, qubit in enumerate(self.data_qubits):
            symbol = sympy.Symbol(prefix + '-' + str(i))
            circuit.append(gate(qubit, self.readout)**symbol)

# %% [markdown]
# Now build a two-layered model, matching the data-circuit size, and include the preparation and readout operations.
def create_quantum_model():
    """Create a QNN model circuit and readout operation to go along with it."""
    data_qubits = cirq.GridQubit.rect(4, 4)  # a 4x4 grid.
    readout = cirq.GridQubit(-1, -1)         # a single qubit at [-1,-1]
    circuit = cirq.Circuit()

    # Prepare the readout qubit.
    circuit.append(cirq.X(readout))
    circuit.append(cirq.H(readout))

    builder = CircuitLayerBuilder(
        data_qubits = data_qubits,
        readout=readout)

    # Then add layers (experiment by adding more).
    builder.add_layer(circuit, cirq.XX, "xx1")
    builder.add_layer(circuit, cirq.ZZ, "zz1")

    # Finally, prepare the readout qubit.
    circuit.append(cirq.H(readout))

    return circuit, cirq.Z(readout)

model_circuit, model_readout = create_quantum_model()
# %%
### 2.2 Wrap the model-circuit in a tfq-keras model

# Build the Keras model with the quantum components. This model is fed the "quantum data", from `x_train_circ`, that encodes the classical data. It uses a *Parametrized Quantum Circuit* layer, `tfq.layers.PQC`, to train the model circuit, on the quantum data.

# To classify these images, Farhi et al. proposed taking the expectation of a readout qubit in a parameterized circuit. The expectation returns a value between 1 and -1.
# Build the Keras model.
import qsimcirq

options = {'t': 16}

qsim_simulator = qsimcirq.QSimSimulator(options)

model = tf.keras.Sequential([
    # The input is the data-circuit, encoded as a tf.string
    tf.keras.layers.Input(shape=(), dtype=tf.string),
    # The PQC layer returns the expected value of the readout gate, range [-1,1].
    tfq.layers.PQC(model_circuit, model_readout,
                   backend=qsim_simulator,
                   ),
])
model.compile(
    loss=tf.keras.losses.Hinge(),
    optimizer=tf.keras.optimizers.Adam(),
    metrics=[hinge_accuracy])
# %% [markdown]
# Next, describe the training procedure to the model, using the `compile` method.
#
# Since the the expected readout is in the range `[-1,1]`, optimizing the hinge loss is a somewhat natural fit.
#
# Note: Another valid approach would be to shift the output range to `[0,1]`, and treat it as the probability the model assigns to class `3`. This could be used with a standard a `tf.losses.BinaryCrossentropy` loss.
#
# To use the hinge loss here you need to make two small adjustments. First convert the labels, `y_train_nocon`, from boolean to `[-1,1]`, as expected by the hinge loss.

# %%
y_train_hinge = 2.0*y_train_nocon-1.0
y_test_hinge = 2.0*y_test-1.0

# %% [markdown]
# ### Train the quantum model
#
# Now train the model—this takes about 45 min. If you don't want to wait that long, use a small subset of the data (set `NUM_EXAMPLES=500`, below). This doesn't really affect the model's progress during training (it only has 32 parameters, and doesn't need much data to constrain these). Using fewer examples just ends training earlier (5min), but runs long enough to show that it is making progress in the validation logs.

# %%
EPOCHS = 16
BATCH_SIZE = 32

# NUM_EXAMPLES = len(x_train_tfcirc)
NUM_EXAMPLES = 1000

# %%
x_train_tfcirc_sub = x_train_tfcirc[:NUM_EXAMPLES]
y_train_hinge_sub = y_train_hinge[:NUM_EXAMPLES]

# %% [markdown]
# Training this model to convergence should achieve >85% accuracy on the test set.

import datetime
log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + "_1000_samples_32_param_X,Y_qsim_Simulator_16threads"
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

qnn_history = model.fit(
      x_train_tfcirc_sub, y_train_hinge_sub,
      batch_size=32,
      epochs=EPOCHS,
      verbose=1,
      validation_data=(x_test_tfcirc, y_test_hinge),
      callbacks=[tensorboard_callback])
# %% [markdown]
# Note: The training accuracy reports the average over the epoch. The validation accuracy is evaluated at the end of each epoch.

# %% [markdown]
# ## 3. Classical neural network
#
# While the quantum neural network works for this simplified MNIST problem, a basic classical neural network can easily outperform a QNN on this task. After a single epoch, a classical neural network can achieve >98% accuracy on the holdout set.
#
# In the following example, a classical neural network is used for for the 3-6 classification problem using the entire 28x28 image instead of subsampling the image. This easily converges to nearly 100% accuracy of the test set.

# # %%
# def create_classical_model():
#     # A simple model based off LeNet from https://keras.io/examples/mnist_cnn/
#     model = tf.keras.Sequential()
#     model.add(tf.keras.layers.Conv2D(32, [3, 3], activation='relu', input_shape=(28,28,1)))
#     model.add(tf.keras.layers.Conv2D(64, [3, 3], activation='relu'))
#     model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2)))
#     model.add(tf.keras.layers.Dropout(0.25))
#     model.add(tf.keras.layers.Flatten())
#     model.add(tf.keras.layers.Dense(128, activation='relu'))
#     model.add(tf.keras.layers.Dropout(0.5))
#     model.add(tf.keras.layers.Dense(1))
#     return model

# model = create_classical_model()
# model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
#               optimizer=tf.keras.optimizers.Adam(),
#               metrics=['accuracy'])

# model.summary()

# # %%
# model.fit(x_train,
#           y_train,
#           batch_size=128,
#           epochs=1,
#           verbose=1,
#           validation_data=(x_test, y_test))

# cnn_results = model.evaluate(x_test, y_test)

# # %% [markdown]
# # The above model has nearly 1.2M parameters. For a more fair comparison, try a 37-parameter model, on the subsampled images:

# # %%
# def create_fair_classical_model():
#     # A simple model based off LeNet from https://keras.io/examples/mnist_cnn/
#     model = tf.keras.Sequential()
#     model.add(tf.keras.layers.Flatten(input_shape=(4,4,1)))
#     model.add(tf.keras.layers.Dense(2, activation='relu'))
#     model.add(tf.keras.layers.Dense(1))
#     return model

# model = create_fair_classical_model()
# model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
#               optimizer=tf.keras.optimizers.Adam(),
#               metrics=['accuracy'])

# model.summary()

# # %%

# import datetime
# log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S") + "_1000_samples_37_param_classical_model"
# tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

# model.fit(x_train_bin,
#           y_train_nocon,
#           batch_size=128,
#           epochs=20,
#           verbose=2,
#           validation_data=(x_test_bin, y_test),
#                 callbacks=[tensorboard_callback])

# fair_nn_results = model.evaluate(x_test_bin, y_test)

# %% [markdown]
# ## 4. Comparison
#
# Higher resolution input and a more powerful model make this problem easy for the CNN. While a classical model of similar power (~32 parameters) trains to a similar accuracy in a fraction of the time. One way or the other, the classical neural network easily outperforms the quantum neural network. For classical data, it is difficult to beat a classical neural network.

# # %%
# qnn_accuracy = qnn_results[1]
# cnn_accuracy = cnn_results[1]
# fair_nn_accuracy = fair_nn_results[1]

# sns.barplot(x=["Quantum", "Classical, full", "Classical, fair"],
#             y=[qnn_accuracy, cnn_accuracy, fair_nn_accuracy])

# %% [markdown]
# ## 5. Квантовая нейросеть с фазовым кодированием.

# %%
# def convert_to_circuit_2(image):
#     """Encode truncated classical image into quantum datapoint."""
#     values = np.ndarray.flatten(image)
#     qubits = cirq.GridQubit.rect(4, 4)
#     circuit = cirq.Circuit()
#     for i, value in enumerate(values):
#         if value:
#             circuit.append(cirq.rx(value*np.pi)(qubits[i]))
#     return circuit

# x_train_circ_2 = [convert_to_circuit_2(x) for x in x_train_nocon]
# x_test_circ_2 = [convert_to_circuit_2(x) for x in x_test_small]

# # %%
# SVGCircuit(x_train_circ_2[0])

# # %% [markdown]
# # Compare this circuit to the indices where the image value exceeds the threshold:

# # %%
# bin_img = x_train_nocon[0,:,:,0]
# indices = np.array(bin_img)
# indices

# # %% [markdown]
# # Convert these `Cirq` circuits to tensors for `tfq`:

# # %%
# x_train_tfcirc_2 = tfq.convert_to_tensor(x_train_circ_2)
# x_test_tfcirc_2 = tfq.convert_to_tensor(x_test_circ_2)

# # %% [markdown]
# # ### Train the quantum model
# #
# # Now train the model—this takes about 45 min. If you don't want to wait that long, use a small subset of the data (set `NUM_EXAMPLES=500`, below). This doesn't really affect the model's progress during training (it only has 32 parameters, and doesn't need much data to constrain these). Using fewer examples just ends training earlier (5min), but runs long enough to show that it is making progress in the validation logs.

# # %%
# EPOCHS = 10
# BATCH_SIZE = 32

# # NUM_EXAMPLES = len(x_train_tfcirc)
# NUM_EXAMPLES = 1000

# # %%
# x_train_tfcirc_sub_2 = x_train_tfcirc_2[:NUM_EXAMPLES]
# y_train_hinge_sub = y_train_hinge[:NUM_EXAMPLES]

# # %%
# qnn_history = model.fit(
#       x_train_tfcirc_sub_2, y_train_hinge_sub,
#       batch_size=32,
#       epochs=EPOCHS,
#       verbose=1,
#       validation_data=(x_test_tfcirc_2, y_test_hinge))

# qnn_results = model.evaluate(x_test_tfcirc_2, y_test)

# %% [markdown]
# ### try to repeat paper success

# %%
# class CircuitLayerBuilder():
#     def __init__(self, data_qubits, readout):
#         self.data_qubits = data_qubits
#         self.readout = readout

#     def add_layer(self, circuit, gate, prefix):
#         for i, qubit in enumerate(self.data_qubits):
#             symbol = sympy.Symbol(prefix + '-' + str(i))
#             circuit.append(gate(qubit, self.readout)**symbol)

# # %%
# def create_quantum_model():
#     """Create a QNN model circuit and readout operation to go along with it."""
#     data_qubits = cirq.GridQubit.rect(4, 4)  # a 4x4 grid.
#     readout = cirq.GridQubit(-1, -1)         # a single qubit at [-1,-1]
#     circuit = cirq.Circuit()

#     # Prepare the readout qubit.
#     circuit.append(cirq.X(readout))
#     circuit.append(cirq.H(readout))

#     builder = CircuitLayerBuilder(
#         data_qubits=data_qubits,
#         readout=readout)

#     # Then add layers (experiment by adding more).
#     builder.add_layer(circuit, cirq.ZZ, "zz1")
#     builder.add_layer(circuit, cirq.ZZ, "zz2")
#     builder.add_layer(circuit, cirq.ZZ, "zz3")
#     builder.add_layer(circuit, cirq.XX, "xx1")
#     builder.add_layer(circuit, cirq.XX, "xx2")
#     builder.add_layer(circuit, cirq.XX, "xx3")

#     # Finally, prepare the readout qubit.
#     circuit.append(cirq.H(readout))

#     return circuit, cirq.Z(readout)

# # %%
# model_circuit, model_readout = create_quantum_model()

# # %%
# # Build the Keras model.
# model = tf.keras.Sequential([
#     # The input is the data-circuit, encoded as a tf.string
#     tf.keras.layers.Input(shape=(), dtype=tf.string),
#     # The PQC layer returns the expected value of the readout gate, range [-1,1].
#     tfq.layers.PQC(model_circuit, model_readout),
# ])

# # %%
# model.compile(
#     loss=tf.keras.losses.Hinge(),
#     optimizer=tf.keras.optimizers.Adam(),
#     metrics=[hinge_accuracy])

# # %%
# print(model.summary())

# # %%
# len(x_train_tfcirc)

# # %%
# EPOCHS = 3
# BATCH_SIZE = 32

# NUM_EXAMPLES = len(x_train_tfcirc)
# # NUM_EXAMPLES = 1000

# # %%
# x_train_tfcirc_sub = x_train_tfcirc[:NUM_EXAMPLES]
# y_train_hinge_sub = y_train_hinge[:NUM_EXAMPLES]

# # %%
# qnn_history = model.fit(
#       x_train_tfcirc_sub, y_train_hinge_sub,
#       batch_size=32,
#       epochs=EPOCHS,
#       verbose=1,
#       validation_data=(x_test_tfcirc, y_test_hinge))

# qnn_results = model.evaluate(x_test_tfcirc, y_test)

# # %% [markdown]
# # The same on small subset of dataset

# # %%
# # Build the Keras model.
# model = tf.keras.Sequential([
#     # The input is the data-circuit, encoded as a tf.string
#     tf.keras.layers.Input(shape=(), dtype=tf.string),
#     # The PQC layer returns the expected value of the readout gate, range [-1,1].
#     tfq.layers.PQC(model_circuit, model_readout),
# ])

# # %%
# model.compile(
#     loss=tf.keras.losses.Hinge(),
#     optimizer=tf.keras.optimizers.Adam(),
#     metrics=[hinge_accuracy])

# # %%
# NUM_EXAMPLES = 1000

# x_train_tfcirc_sub = x_train_tfcirc[:NUM_EXAMPLES]
# y_train_hinge_sub = y_train_hinge[:NUM_EXAMPLES]

# # %%

# qnn_history = model.fit(
#       x_train_tfcirc_sub, y_train_hinge_sub,
#       batch_size=32,
#       epochs=EPOCHS,
#       verbose=1,
#       validation_data=(x_test_tfcirc, y_test_hinge))

# qnn_results = model.evaluate(x_test_tfcirc, y_test)

# # %% [markdown]
# # ## Декомпозиция ZX

# # %%
# class CircuitLayerBuilder():
#     def __init__(self, data_qubits, readout):
#         self.data_qubits = data_qubits
#         self.readout = readout

#     def add_layer(self, circuit, gate, prefix):
#         for i, qubit in enumerate(self.data_qubits):
#             symbol = sympy.Symbol(prefix + '-' + str(i))
#             circuit.append(gate(qubit, self.readout)**symbol)
#     def add_ZX_gate(self, circuit, prefix):
#         for i, qubit in enumerate(self.data_qubits):
#             symbol = sympy.Symbol(prefix + '-' + str(i))
#             circuit.append(cirq.H(qubit))
#             circuit.append(cirq.X(qubit).controlled_by(self.readout))
#             circuit.append(cirq.rz(symbol).on(qubit))
#             circuit.append(cirq.X(qubit).controlled_by(self.readout))
#             circuit.append(cirq.H(qubit))

# # %%
# def create_quantum_model():
#     """Create a QNN model circuit and readout operation to go along with it."""
#     data_qubits = cirq.GridQubit.rect(4, 4)  # a 4x4 grid.
#     readout = cirq.GridQubit(-1, -1)         # a single qubit at [-1,-1]
#     circuit = cirq.Circuit()

#     # Prepare the readout qubit.
#     circuit.append(cirq.X(readout))
#     circuit.append(cirq.H(readout))

#     builder = CircuitLayerBuilder(
#         data_qubits=data_qubits,
#         readout=readout)

#     # Then add layers (experiment by adding more).
#     builder.add_ZX_gate(circuit, "zx1")
#     builder.add_layer(circuit, cirq.XX, "xx1")
#     builder.add_ZX_gate(circuit, "zx2")
#     builder.add_layer(circuit, cirq.XX, "xx2")
#     builder.add_ZX_gate(circuit, "zx3")
#     builder.add_layer(circuit, cirq.XX, "xx3")

#     # Finally, prepare the readout qubit.
#     circuit.append(cirq.H(readout))

#     return circuit, cirq.Z(readout)

# # %%
# model_circuit, model_readout = create_quantum_model()

# # %%
# # Build the Keras model.
# model = tf.keras.Sequential([
#     # The input is the data-circuit, encoded as a tf.string
#     tf.keras.layers.Input(shape=(), dtype=tf.string),
#     # The PQC layer returns the expected value of the readout gate, range [-1,1].
#     tfq.layers.PQC(model_circuit, model_readout),
# ])

# # %%
# SVGCircuit(model_circuit)

# # %%
# model.compile(
#     loss=tf.keras.losses.Hinge(),
#     optimizer=tf.keras.optimizers.Adam(),
#     metrics=[hinge_accuracy])

# # %%
# qnn_history = model.fit(
#       x_train_tfcirc_sub, y_train_hinge_sub,
#       batch_size=32,
#       epochs=EPOCHS,
#       verbose=1,
#       validation_data=(x_test_tfcirc, y_test_hinge))

# qnn_results = model.evaluate(x_test_tfcirc, y_test)

# # %% [markdown]
# # (сверху результаты для сети предложенной в туториале)

# # %% [markdown]
# # addintg tensrboard

# # %%
# import datetime
# log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
# tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

# qnn_history = model.fit(
#       x_train_tfcirc_sub, y_train_hinge_sub,
#       batch_size=32,
#       epochs=EPOCHS,
#       verbose=1,
#       validation_data=(x_test_tfcirc, y_test_hinge),
#       callbacks=[tensorboard_callback])

# # %% [markdown]
# # #### Прямо в точности такая же схема, как в статье:

# # %%
# def create_quantum_model():
#     """Create a QNN model circuit and readout operation to go along with it."""
#     data_qubits = cirq.GridQubit.rect(4, 4)  # a 4x4 grid.
#     readout = cirq.GridQubit(-1, -1)         # a single qubit at [-1,-1]
#     circuit = cirq.Circuit()

#     builder = CircuitLayerBuilder(
#         data_qubits=data_qubits,
#         readout=readout)

#     # Then add layers (experiment by adding more).
#     builder.add_ZX_gate(circuit, "zx1")
#     builder.add_layer(circuit, cirq.XX, "xx1")
#     builder.add_ZX_gate(circuit, "zx2")
#     builder.add_layer(circuit, cirq.XX, "xx2")
#     builder.add_ZX_gate(circuit, "zx3")
#     builder.add_layer(circuit, cirq.XX, "xx3")

#     return circuit, cirq.Z(readout)

# # %%
# model_circuit, model_readout = create_quantum_model()

# # %%
# # Build the Keras model.
# model = tf.keras.Sequential([
#     # The input is the data-circuit, encoded as a tf.string
#     tf.keras.layers.Input(shape=(), dtype=tf.string),
#     # The PQC layer returns the expected value of the readout gate, range [-1,1].
#     tfq.layers.PQC(model_circuit, model_readout),
# ])

# # %%
# model.compile(
#     loss=tf.keras.losses.Hinge(),
#     optimizer=tf.keras.optimizers.Adam(),
#     metrics=[hinge_accuracy])

# # %%
# import datetime
# log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
# tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

# qnn_history = model.fit(
#       x_train_tfcirc_sub, y_train_hinge_sub,
#       batch_size=32,
#       epochs=EPOCHS,
#       verbose=1,
#       validation_data=(x_test_tfcirc, y_test_hinge),
#       callbacks=[tensorboard_callback])


from django.contrib import admin
from django.urls import path, include
from . import views

urlpatterns = [
    path('',views.home, name="home"),
    path('signup/', views.signup, name='signup'),
    path('about/', views.about, name = 'about'),
    path('login/', views.login, name = 'login'),
    path('logout/', views.logout, name = 'logout'),
    path('dashboard/', views.home, name='dashboard'),
    path('test/',views.test, name='test' )

]


import datetime
import logging
import typing
import urllib.parse

from http import cookies

from .exceptions import UnknownHttpType
from .models import (
    HttpType,
    Host,
    HttpRequest,
    LoadBalancerErrorReason,
)

logger = logging.getLogger(__name__)

def to_http_type(value):
    for ht in HttpType:
        if ht.value == value:
            return ht
    raise UnknownHttpType(value)

def to_datetime(value):
    return datetime.datetime.fromisoformat(value.rstrip("Z")).replace(
        tzinfo=datetime.timezone.utc
    )

def to_http_request(value):
    # The url can contain spaces
    split = value.split()
    url = " ".join(split[1:-1])
    parsed = urllib.parse.urlparse(url)
    return HttpRequest(
        split[0],
        url,
        parsed.path,
        urllib.parse.parse_qs(parsed.query),
        split[-1],
    )

def to_cookie(value):
    cookie = cookies.SimpleCookie()
    cookie.load(rawdata=value)
    return {urllib.parse.unquote(key): morsel.value for key, morsel in cookie.items()}

def to_python(value, field):
    value = value.strip('"')

    origin = typing.get_origin(field.type)
    field_type = (
        typing.get_args(field.type)[0]  # XXX: only supports Optional types
        if origin == typing.Union
        else field.type
    )

    if field_type is datetime.datetime:
        return to_datetime(value)
    if field_type == datetime.date:
        return datetime.date.fromisoformat(value)
    if field_type == datetime.time:
        return datetime.time.fromisoformat(value)
    if field_type == typing.List[str]:
        return value.split(",")
    if value == "-":
        return None
    if field_type == LoadBalancerErrorReason:
        return getattr(LoadBalancerErrorReason, value)
    if field_type == Host:
        ip, port = value.split(":")
        return Host(ip, int(port))
    if field_type == HttpRequest:
        return to_http_request(value)
    if field_type == HttpType:
        return to_http_type(value)
    if field.name == "user_agent":
        return urllib.parse.unquote(value)
    if field.name == "uri_query":
        return urllib.parse.parse_qs(value)
    if field.name == "cookie":
        return to_cookie(value)
    return field_type(value)


import yaml
import json
import os
import requests
import os.path
import errno
import shutil
from rich.progress import track
import concurrent.futures
from urllib.parse import urlparse

URL = "https://developer-data.cloud.com/master"
APISPECPATH = os.path.join(os.path.expanduser("~"), ".cxcli", "apispecs")
METACACHEPATH = os.path.join(APISPECPATH, "metadata.dat")
WORKERCOUNT = 4

def fetch_portal_specs_from_sitedata(sitedata, specsdict={}):
    if isinstance(sitedata, list):
        for item in sitedata:
            specsdict = fetch_portal_specs_from_sitedata(item, specsdict)
    elif isinstance(sitedata, dict):
        if "apis" in sitedata and "title" in sitedata:
            specfilename = (
                sitedata["title"]
                .lower()
                .replace(" ", "")
                .replace("cloudservicesplatform-", "")
            )
            # Patch API names
            if "/adm/" in sitedata["apis"]:
                specfilename = "adm_" + specfilename
            if specfilename == "exportandimportrestapis":
                specfilename = "microapps"
            elif specfilename == "windowsmanagement":
                specfilename = "wem"
            elif specfilename == "globalappconfigurationservice":
                specfilename = "globalappconfiguration"
            specfilename = specfilename.replace("citrixcloud-", "")
            specsdict[specfilename] = URL + sitedata["apis"]
        for _, value in sitedata.items():
            specsdict = fetch_portal_specs_from_sitedata(value, specsdict)
    return specsdict

def fetch_portal_specs():
    req = requests.get(f"{URL}/all_site_data.json")
    req.raise_for_status()
    data = yaml.safe_load(req.content)
    specsdict = fetch_portal_specs_from_sitedata(data)
    return specsdict

def merge_spec(source, destination):
    for key, value in source.items():
        if isinstance(value, dict):
            node = destination.setdefault(key, {})
            merge_spec(value, node)
        else:
            destination[key] = value
    return destination

def reset_synced_specs():
    try:
        for filename in os.listdir(APISPECPATH):
            filepath = os.path.join(APISPECPATH, filename)
            if os.path.isfile(filepath) or os.path.islink(filepath):
                os.unlink(filepath)
    except FileNotFoundError:
        pass

def sync_public_specs():
    make_spec_dir()
    sync_specs(fetch_portal_specs())

def make_spec_dir():
    try:
        os.makedirs(APISPECPATH)
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise

def sync_specs(specdict):
    make_spec_dir()
    with concurrent.futures.ThreadPoolExecutor(max_workers=WORKERCOUNT) as executor:
        results = executor.map(sync_specs_single, specdict.items())
        groups = {}
        for result in track(
            results, description="Downloading OpenAPI specs...", total=len(specdict)
        ):
            if result is None:
                continue
            groupname = result["groupname"]
            spec = result["spec"]
            if groupname not in groups:
                groups[groupname] = {}
            groups[groupname] = merge_spec(spec, groups[groupname])
    for groupname, groupspec in groups.items():
        with open(os.path.join(APISPECPATH, groupname), "w+") as fp:
            json.dump(groupspec, fp, indent=2)
    build_metadata()

def sync_specs_single(openapi_spec):
    (apiname, apiurl) = openapi_spec
    if apiname == "workspaceenvironmentmanagement":
        apiname = "wem"
    if apiname.startswith("adm") and "_" in apiname:
        asplit = apiname.split("_")
        groupname = f"{asplit[0]}_{asplit[1]}.json"
    else:
        groupname = f"{apiname}.json"
    if os.path.exists(os.path.join(APISPECPATH, groupname)):
        # Todo: check age and expire
        return
    response = requests.get(f"{apiurl}")
    if not response.ok:
        print(f"Failed to get {apiname} from {apiurl}")
        return
    if apiurl.endswith(".yaml") or apiurl.endswith(".yml"):
        spec = yaml.safe_load(response.content)
    elif apiurl.endswith(".json") or apiurl.endswith("/swagger/docs/v1"):
        spec = response.json()
    else:
        raise Exception(apiurl)
    if apiname == "microapps":
        # Custom hack for microapps
        params = [
            {"name": "customerid", "in": "path", "required": "true"},
            {"name": "geo", "in": "path", "required": "true"},
        ]
        spec = patch_parameters(spec, params)
    elif apiname == "reportingapi":
        # Custom hack for reportingapi
        params = [
            {"name": "customerid", "in": "path", "required": "true"},
        ]
        spec = patch_parameters(spec, params)
    elif apiname == "wem":
        # Custom hack for wem
        params = [
            {"name": "api", "in": "path", "required": "true"},
        ]
        spec = patch_parameters(spec, params)
    # Fix up openapi files without service host
    if not "host" in spec and ".citrixworkspacesapi.net" in apiurl:
        spec["host"] = urlparse(apiurl).netloc
    return {"groupname": groupname, "spec": spec}

def patch_parameters(spec, add_parameters):
    for pathkey, pathvalue in spec["paths"].items():
        for operationkey, operationvalue in pathvalue.items():
            if "parameters" in operationvalue:
                for add in add_parameters:
                    spec["paths"][pathkey][operationkey]["parameters"].append(add)
    return spec

def build_metadata():
    metacache = {}
    for filename in sorted(os.listdir(APISPECPATH)):
        if not filename.endswith(".json"):
            continue
        with open(os.path.join(APISPECPATH, filename), "r") as read_file:
            spec = json.load(read_file)
            metacache[filename.replace(".json", "")] = spec["info"]["title"]
    with open(METACACHEPATH, "w") as fp:
        json.dump(metacache, fp, indent=2)


import subprocess
import sys

from knack.log import get_logger
from knack.util import CLIError
from .uri import uri_parse

logger = get_logger(__name__)

_GIT_EXE = 'git'

def set_config(key, value, local=True):
    scope = _get_git_config_scope_arg(local)
    subprocess.check_output([_GIT_EXE, 'config', scope, key, value])

def unset_config(key, local=True):
    scope = _get_git_config_scope_arg(local)
    subprocess.check_output([_GIT_EXE, 'config', scope, '--unset', key])

def get_config(key, local=True):
    scope = _get_git_config_scope_arg(local)
    return subprocess.check_output([_GIT_EXE, 'config', scope, key])

def _get_git_config_scope_arg(local):
    if local:
        return '--local'
    return '--global'

def fetch_remote_and_checkout(refName, remote_name):
    subprocess.run([_GIT_EXE, 'fetch', remote_name, refName], check=False)
    subprocess.run([_GIT_EXE, 'checkout', get_branch_name_from_ref(refName)], check=False)
    subprocess.run([_GIT_EXE, 'pull', remote_name, get_branch_name_from_ref(refName)], check=False)

def get_current_branch_name():
    try:
        output = subprocess.check_output([_GIT_EXE, 'symbolic-ref', '--short', '-q', 'HEAD'])
    except BaseException as ex:  # pylint: disable=broad-except
        logger.info('GitDetect: Could not detect current branch based on current working directory.')
        logger.debug(ex, exc_info=True)
        return None
    if sys.stdout.encoding is not None:
        result = output.decode(sys.stdout.encoding)
    else:
        result = output.decode()
    return result.strip()

def get_remote_url(validation_function=None):
    remotes = get_git_remotes()
    if remotes is not None:
        if _ORIGIN_PUSH_KEY in remotes and (validation_function is None or
                                            validation_function(remotes[_ORIGIN_PUSH_KEY])):
            return remotes[_ORIGIN_PUSH_KEY]
        for k, value in remotes.items():
            if k != _ORIGIN_PUSH_KEY and k.endswith('(push)') and (validation_function is None or
                                                                   validation_function(value)):
                return value
    return None

def get_git_credentials(organization):
    parse_result = uri_parse(organization)
    protocol = parse_result.scheme
    host = parse_result.netloc
    standard_in = bytes('protocol={protocol}\nhost={host}'.format(protocol=protocol, host=host), 'utf-8')
    try:
        # pylint: disable=unexpected-keyword-arg
        output = subprocess.check_output([_GIT_EXE, 'credential-manager', 'get'], input=standard_in)
    except BaseException as ex:  # pylint: disable=broad-except
        logger.info('GitDetect: Could not detect git credentials for current working directory.')
        logger.debug(ex, exc_info=True)
        return None
    if sys.stdout.encoding is not None:
        lines = output.decode(sys.stdout.encoding).split('\n')
    else:
        lines = output.decode().split('\n')
    properties = {}
    for line in lines:
        equal_position = line.find('=')
        if equal_position >= 0:
            properties[line[0:equal_position]] = line[equal_position + 1:]
    return properties

def get_git_remotes():
    if _git_remotes:
        return _git_remotes
    try:
        # Example output:
        # git remote - v
        # full  https://mseng.visualstudio.com/DefaultCollection/VSOnline/_git/_full/VSO (fetch)
        # full  https://mseng.visualstudio.com/DefaultCollection/VSOnline/_git/_full/VSO (push)
        # origin  https://mseng.visualstudio.com/defaultcollection/VSOnline/_git/VSO (fetch)
        # origin  https://mseng.visualstudio.com/defaultcollection/VSOnline/_git/VSO (push)
        output = subprocess.check_output([_GIT_EXE, 'remote', '-v'], stderr=subprocess.STDOUT)
    except BaseException as ex:  # pylint: disable=broad-except
        logger.info('GitDetect: Could not detect current remotes based on current working directory.')
        logger.debug(ex, exc_info=True)
        return None
    if sys.stdout.encoding is not None:
        lines = output.decode(sys.stdout.encoding).split('\n')
    else:
        lines = output.decode().split('\n')
    for line in lines:
        components = line.strip().split()
        if len(components) == 3:
            _git_remotes[components[0] + components[2]] = components[1]
    return _git_remotes

def resolve_git_refs(ref):
    """Prepends 'refs/' prefix to ref str if not already there.
    :param str ref: The text to validate.
    :rtype: str
    """
    if ref is not None and not ref.startswith(REFS_PREFIX):
        ref = REFS_PREFIX + ref
    return ref

def get_ref_name_from_ref(ref):
    """Removes 'refs/' prefix from ref str if there.
    :param ref: The text to validate.
    :type ref: str
    :rtype: str
    """
    if ref is not None and ref.startswith(REFS_PREFIX):
        ref = ref[len(REFS_PREFIX):]
    return ref

def resolve_git_ref_heads(ref):
    """Prepends 'refs/heads/' prefix to ref str if not already there.
    :param ref: The text to validate.
    :type ref: str
    :rtype: str
    """
    if (ref is not None and not ref.startswith(REF_HEADS_PREFIX) and
            not ref.startswith(REF_PULL_PREFIX) and not ref.startswith(REF_TAGS_PREFIX)):
        ref = REF_HEADS_PREFIX + ref
    return ref

def get_branch_name_from_ref(ref):
    """Removes 'refs/heads/' prefix from ref str if there.
    :param ref: The text to validate.
    :type ref: str
    :rtype: str
    """
    if ref is not None and ref.startswith(REF_HEADS_PREFIX):
        ref = ref[len(REF_HEADS_PREFIX):]
    return ref

def setup_git_alias(alias, command, local=False):
    try:
        set_config(key=_get_alias_key(alias),
                   value=_get_alias_value(command),
                   local=local)
    except OSError:
        raise CLIError('Setting the git alias failed. Ensure git is installed and in your path.')

def clear_git_alias(alias, local=False):
    unset_config(key=_get_alias_key(alias), local=local)

def is_git_alias_setup(alias, command, local=False):
    try:
        try:
            value = get_config(key=_get_alias_key(alias), local=local)
        except subprocess.CalledProcessError:
            return False
        return _get_alias_value(command) == value.decode(sys.stdout.encoding).strip()
    except OSError:
        raise CLIError('Checking the git config values failed. Ensure git is installed and in your path.')

def _get_alias_key(alias):
    return 'alias.' + alias

def _get_alias_value(command):
    mime = '.cmd' if sys.platform.lower().startswith('win') else ''
    return '!f() { exec az' + mime + ' ' + command + ' \"$@\"; }; f'

_git_remotes = {}
_ORIGIN_PUSH_KEY = 'origin(push)'
REFS_PREFIX = 'refs/'
REF_HEADS_PREFIX = 'refs/heads/'
REF_PULL_PREFIX = 'refs/pull/'
REF_TAGS_PREFIX = 'refs/tags/'
GIT_CREDENTIALS_USERNAME_KEY = 'username'
GIT_CREDENTIALS_PASSWORD_KEY = 'password'


import cv2
import socket
import keyboard
from djitellopy import Tello

# Maak een TCP/IP socket
sock_dashboard = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Bind de socket aan een specifiek adres en poort
server_adres = ('localhost', 12345)
sock_dashboard.bind(server_adres)

# Luister naar inkomende verbindingen
sock_dashboard.listen(1)

# Initialiseer de Tello drone
tello = Tello()
tello.connect()
tello.streamon()

# Laad een vooraf getraind model voor gezichtsdetectie
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# IP- en poortinformatie voor de Tello
tello_adres = ('192.168.10.1', 8889)

# Maak een UDP-socket voor het verzenden van commando's
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# Bind de socket aan een lokale poort om reacties te ontvangen
sock.bind(('', 9000))

# Functie om een commando naar de Tello Drone te sturen
def stuur_commando(commando):
    try:
        sock.sendto(commando.encode('utf-8'), tello_adres)
        reactie, ip = sock.recvfrom(1024)
        return reactie.decode('utf-8')
    except Exception as e:
        return str(e)

# Definieer de dronebesturingscommando's op basis van toetsenbordinvoer
def bestuur_drone(tello, toets):
    if toets == 'w':
        tello.send_rc_control(0, 20, 0, 0)  # Vooruit bewegen
    elif toets == 's':
        tello.send_rc_control(0, -20, 0, 0)  # Achteruit bewegen
    elif toets == 'a':
        tello.send_rc_control(-20, 0, 0, 0)  # Links bewegen
    elif toets == 'd':
        tello.send_rc_control(20, 0, 0, 0)   # Rechts bewegen
    if toets == 'i':
        tello.send_rc_control(0, 0, 20, 0)  # Omhoog bewegen
    elif toets == 'k':
        tello.send_rc_control(0, 0, -20, 0)  # Omlaag bewegen
    elif toets == 'h':
        tello.send_rc_control(0, 0, 0, 0)  # Zweven
    elif toets == 'l':
        tello.send_rc_control(0, 0, 0, 20)  # Met de klok mee draaien
    elif toets == 'j':
        tello.send_rc_control(0, 0, 0, -20)  # Tegen de klok in draaien
    elif toets == 'q':
        tello.land()  # Landen

def main():
    try:
        # Opstijgen
        tello.takeoff()

        # Voeg sneltoetsen toe om de drone te besturen
        keyboard.add_hotkey('w', lambda: bestuur_drone(tello, 'w'))
        keyboard.add_hotkey('s', lambda: bestuur_drone(tello, 's'))
        keyboard.add_hotkey('a', lambda: bestuur_drone(tello, 'a'))
        keyboard.add_hotkey('d', lambda: bestuur_drone(tello, 'd'))
        keyboard.add_hotkey('i', lambda: bestuur_drone(tello, 'i'))
        keyboard.add_hotkey('k', lambda: bestuur_drone(tello, 'k'))
        keyboard.add_hotkey('j', lambda: bestuur_drone(tello, 'j'))
        keyboard.add_hotkey('l', lambda: bestuur_drone(tello, 'l'))
        keyboard.add_hotkey('h', lambda: bestuur_drone(tello, 'h'))
        keyboard.add_hotkey('q', tello.land)

        # Wacht op verbinding
        verbinding, client_adres = sock_dashboard.accept()

        #wanneer de loop true is dan gaat hij pas de code gebruiken
        while True:

            try:
                print('Verbinding van', client_adres)

                frame = tello.get_frame_read().frame
                grijs = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

                gezichten = face_cascade.detectMultiScale(grijs, scaleFactor=1.3, minNeighbors=5)

                for (x, y, w, h) in gezichten:
                    if w * h < 4000:  # Pas de groottegrens indien nodig aan
                        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)  # Rode kleur voor kleinere gezichten
                    else:
                        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)  # Groene kleur voor andere gezichten

                print(frame.shape)

                # Wacht op opdracht van LabVIEW
                data = verbinding.recv(16)

                # Toon het frame met gezichtsdetectie
                if data:
                    verbinding.sendall(frame)
                else:
                    print('Geen gegevens van', client_adres)
                    break
            except Exception as e:
                print(e)

    except KeyboardInterrupt:
        tello.land()
    finally:
        # Sluit de verbinding
        verbinding.close()
        tello.land()
        tello.streamoff()
        cv2.destroyAllWindows()
        tello.end()

if __name__ == "__main__":
    main()


"""Result page"""

import cgi
import cgitb
import chatons

cgitb.enable()
form = cgi.FieldStorage()

html_result = """
<!DOCTYPE html>

    <meta charset="UTF-8">
    <title> Download images with Selenium</title

Voici la page de l'application web de téléchargement d'images

    Merci, le téléchargement des images de

"""

def printresult():
    print(str(html_result) + str(animal) + "s" + " est terminé!")

if form.getvalue("inputanimal"):
    animal = form.getvalue("inputanimal")
    chatons.getimages(animal)
    printresult()
else:
    raise Exception("Animal non écrit")


#coding=utf-8

import os
import time
import random
import logging
import argparse
from flask import Flask, render_template, request, redirect, send_from_directory

from ocrLibrary.OcrHandle import getOcrMethod
from ocrLibrary.Imgtools import drawResults

def getRandomStr(length=8):
    seed = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    return ''.join(random.sample(seed, length))

app = Flask(__name__)

def setLoggerFormat(logFile="flask.log", logLevel="INFO"):

    fh = logging.FileHandler(logFile, 'w')
    fh.setLevel(logLevel)

    formatter = logging.Formatter('[%(asctime)s] %(name)s:%(levelname)s: %(message)s')
    fh.setFormatter(formatter)

    app.logger.addHandler(fh)
    app.logger.setLevel(logLevel)

@app.route("/", methods=["GET"])
def index():
    context = {"imgPath": "../static/upload.png",
               "info": "Click for select, only support English"
               }
    return render_template("index.html", **context)

@app.route("/", methods=["POST"])
def uploadimage():
    try:
        img = request.files["filechoose"]
        base, ext = os.path.splitext(img.filename)
        base += time.strftime("_%Y%m%d%H%M%S_", time.localtime(time.time())) + getRandomStr(8)
        imgName = base + ext
        resultName = base + "_result" + ext
        imgPath = os.path.join("originImg", imgName)
        resultPath = os.path.join("resultImg", resultName)
        img.save(imgPath)

        app.logger.info("start detect image: {}".format(imgPath))
        results = getOcrResult(imgPath)
        drawResults(imgPath, resultPath, results)

        context = {"imgPath": "../" + resultPath}
        if len(results) != 0:
            context["info"] = "Success"
        else:
            context["info"] = "No words detected"
    except Exception as e:
        app.logger.exception(e)
        context = {"imgPath": "../static/error.png",
                   "info": "Service error"
                   }

    return render_template("index.html", **context)

@app.route("/resultImg/<string:filename>", methods=["GET"])
def download(filename):
    if os.path.isfile(os.path.join("resultImg", filename)):
        return send_from_directory("resultImg", filename, as_attachment=True)
    else:
        app.logger.warn("File doesn't exist: {}".format(filename))
        return None

if __name__ == "__main__":

    parser = argparse.ArgumentParser()

    parser.add_argument("-p", "--port", dest="port", default=5000, help="Listen port, default is 5000")
    parser.add_argument("-m", "--method", dest="method", default="pyocr",
                        help="Ocr method, choose from [tesserocr, pyocr, api], default is pyocr")
    parser.add_argument("--debug", dest="debug", required=False, action="store_true", default=False, help="Open debug mode")

    args = parser.parse_args()

    host = "0.0.0.0"
    port = args.port
    debug = args.debug
    getOcrResult = getOcrMethod(args.method)
    if getOcrResult is None:
        exit(1)

    setLoggerFormat(logLevel="DEBUG" if args.debug else "INFO")
    app.logger.info("start ocr service")
    app.run(host=host, port=port, debug=debug)


'''
根据QSim将Parser生成的语法树翻译成Pyhton代码
if __name__ == '__main__':
    将生成的py文件保存在 log/auto.py
date: 2020-11-10
'''
import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #当前程序上上一级目录，这里为QSim
sys.path.append(BASE_DIR) #添加环境变量
from string import Template
from Lexer.Lexer import Lexer
from Parser.Parser import Parser
import logging
def mkdir(path):
    path=path.strip()
    path=path.rstrip("\\")
    isExists=os.path.exists(path)
    if not isExists:
        os.makedirs(path)
        return True
    else:
        return False
mkdir('log')
logging.basicConfig(filename='log/translate.log', level=logging.DEBUG)
log = logging.getLogger('translate')

py_template = {
    'header':
    '''
import os
import sys
import time
# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #当前程序上上一级目录，这里为QSim
# sys.path.append(BASE_DIR)
from lib.QSim import QuantumRegister
from lib.QSim import Tools
tools = Tools()
import numpy as np
start_time = time.perf_counter ()
    ''',
    'footer':
    '''
t_cost = time.perf_counter () - start_time
_wf = tools.print_wf(qubit.a2wf())
memory_cost = sys.getsizeof(qubit) / 1024 / 1024
# print(_wf)
    ''',
    'FuncStatement':
Template('''
def $FuncStatement_Name($ParameterList):
    $Statement
'''),
    'IFStatement':
Template('''if $bool_str:
    $Statement'''),
    'Declare_func':
Template('''$name = $FuncCall_Name($ParameterList)'''),
    'Declare_INT':
Template('''$Iden = $INT'''),
    'GateOp':
Template('''qubit.applyGate('$GateOp_Name',$placeList)'''),
    'FuncCall':
Template('''$FuncCall_Name($ParameterList)'''),
    'measure':
Template('''qubit.measure(place=$place, count=$count)'''),
    'Declare_quantum':
Template('''qubit = QuantumRegister($numQubits)'''),
    'Declare_measure':
Template('''$Iden = qubit.measure(place=$place, count=$count)'''),
    'show':
Template('''# show( $Iden )'''),
    'R':
Template('''qubit.applyGate('$GateOp_Name',$placeList)''')
}

# TODO
qasm_template = {
    'header':
    '''
OPENQASM 3;
include "stdgates.inc";
    ''',
    'Declare_quantum':
Template('''qubit[$numQubits] _q'''),
    'GateOp':
Template('''$GateOp_Name $placeList'''),
    'R':
Template('''cphase(pi / $k) $placeList'''),
    'measure':
Template('''_c = measure _q''')
}

class pyFileHandler():
    '''维护生成的代码'''
    def __init__(self):
        self.result = []
        self.result.append(py_template['header'])

    def insert(self, _value, _type):
        s = py_template[_type].substitute(_value)
        self.result.append(s)

    def generate_file(self, file_name=''):
        if file_name == '':
            file_name = 'log/auto.py'
        self.result.append(py_template['footer'])
        self.file = open(file_name, 'w+', encoding = 'utf-8')
        self.file.write('\n'.join(self.result) + '\n')
        self.file.close()

class qasmFileHandler():
    '''维护生成的代码'''
    def __init__(self):
        self.result = []
        self.result.append(py_template['header'])

    def insert(self, _value, _type):
        s = py_template[_type].substitute(_value)
        self.result.append(s)

    def generate_file(self, file_name=''):
        if file_name == '':
            file_name = 'log/qasm.txt'
        self.file = open(file_name, 'w+', encoding = 'utf-8')
        self.file.write('\n'.join(self.result) + '\n')
        self.file.close()

class SymbalTable:
    '''
    符号表
    负责维护程序中的变量信息，以便调用
    '''
    def __init__(self):
        self.table = {
            'qubit': 'qubit',
            '_wf': '_wf',
            't_cost': 't_cost',
            'measure' : [],
            'show' : [],
            'FuncStatement': [],
            'Identify': []
        }
        self.showCount = 0

    def add(self, name=None, value=None, type=None):
        if type == 'measure':
            self.table['measure'].append({name: value})
        elif type == 'show':
            name = str(self.showCount)
            self.showCount += 1
            self.table['show'].append({name: value})
        elif type == 'FuncStatement':
            self.table['FuncStatement'].append({name: value})
        elif type == 'Identify':
            self.table['Identify'].append({name: value})
        else:
            raise ValueError('type {} is not defined!'.format(type))

    def initial(self):
        del self.table['measure']
        self.table['measure'] = []
        del self.table['show']
        self.table['show'] = []
        del self.table['FuncStatement']
        self.table['FuncStatement'] = []
        del self.table['Identify']
        self.table['Identify'] = []

    def check(self, name, type):
        pass

symbalTable = SymbalTable()

class Translate:
    def __init__(self, tree):
        self.tree = tree
        self.fileHandler = pyFileHandler()

    def log(self, file_name=''):
        self.fileHandler.generate_file(file_name)

    def getResult(self):
        result = self.fileHandler.result
        result.append(py_template['footer'])
        return '\n'.join(result) + '\n'

    def getSymbalTable(self):
        return symbalTable.table

    def initSymbalTable(self):
        symbalTable.initial()

    def process_statement(self, node):
        '''处理大括号内的情况，如if,while,func'''
        if not node:
            return
        child = node.first_son
        statement_list = []
        while child:
            if child.value == 'Declare_func':
                dict = self.Declare_func(child)
                s = py_template['Declare_func'].substitute(dict)
                statement_list.append(s)
            elif child.value == 'Declare_INT':
                dict = self.Declare_INT(child)
                self.fileHandler.insert(dict, 'Declare_INT')
            elif child.value == 'Declare_quantum':
                dict = self.Declare_quantum(child)
                s = py_template['Declare_quantum'].substitute(dict)
                statement_list.append(s)
                pass
            elif child.value == 'Declare_measure':
                dict = self.Declare_measure(child)
                self.fileHandler.insert(dict, 'Declare_measure')
            elif child.value == 'GateOp':
                dict = self.GateOp(child)
                s = py_template['GateOp'].substitute(dict)
                statement_list.append(s)
            elif child.value == 'FuncStatement':
                dict = self.FuncStatement(child)
                s = py_template['FuncStatement'].substitute(dict)
                statement_list.append(s)
            elif child.value == 'FuncCall':
                if child.first_son.value == 'measure':
                    dict = self.measure(child)
                    s = py_template['measure'].substitute(dict)
                    statement_list.append(s)
                elif child.first_son.value == 'show':
                    dict = self.show(child)
                    s = py_template['show'].substitute(dict)
                    statement_list.append(s)
                elif child.first_son.value == 'R':
                    dict = self.R(child)
                    s = py_template['R'].substitute(dict)
                else:
                    dict = self.FuncCall(child)
                    s = py_template['FuncCall'].substitute(dict)
                    statement_list.append(s)
            elif child.value == 'IFStatement':
                dict = self.IFStatement(child)
                s = py_template['IFStatement'].substitute(dict)
                statement_list.append(s)
                pass
            child = child.right
        statement_str = ''.join(statement_list) + '\n'
        return statement_str

    def FuncStatement(self, node):
        '''
        func f(){}
        '''
        if not node:
            return
        child = node.first_son
        FuncStatement_Name = ''
        ParameterList = ''
        Statement_str = ''
        while child:
            if child.type == 'FuncStatement_Name':
                FuncStatement_Name = child.value
            elif child.value == 'ParameterList' and child.type == None:
                pl = self.tree.find_all_child(child)
                for p in pl:
                    ParameterList += ',' + p.value
                ParameterList = ParameterList[1:]   # 去除第一个,
            elif child.value == 'Statement' and child.type == None:
                Statement_str = self.process_statement(child)
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        symbalTable.add(name=FuncStatement_Name, value='FuncStatement', type='FuncStatement')
        return dict(FuncStatement_Name=FuncStatement_Name,ParameterList=ParameterList,Statement=Statement_str)

    def IFStatement(self, node):
        '''
        if(2>1){}
        '''
        if not node:
            return
        child = node.first_son
        bool_str = ''
        statement_str = ''
        while child:
            if child.value == 'Bool' and child.type == None:
                bs = self.tree.find_all_child(child)
                for b in bs:
                    bool_str += b.value
            elif child.value == 'Statement' and child.type == None:
                statement_str = self.process_statement(child)
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(bool_str=bool_str, Statement=statement_str)

    def Return(self, node):
        pass

    def Expression(self, node):
        if not node:
            return
        child = node.first_son
        Expression_str = ''
        while child:
            Expression_str += child.value
        return Expression_str

    def Declare_func(self, node):
        '''
        a = f()
        '''
        if not node:
            return
        child = node.first_son
        name = ''
        FuncCall_Name = ''
        ParameterList = ''
        '''按层遍历'''
        while child:
            # print(child.format())
            if child.type == 500:
                name = child.value
            elif child.value == '=':
                pass
            elif child.value == 'FuncCall' and child.type == None:
                list = self.tree.find_all_child(child)
                for n in list:
                    if n.type == 'FuncCall_Name':
                        FuncCall_Name = n.value
                    elif n.value == 'ParameterList' and n.type == None:
                        pl = self.tree.find_all_child(n)
                        for p in pl:
                            ParameterList += ',' + p.value
                        ParameterList = ParameterList[1:]   # 去除第一个,
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(name=name,FuncCall_Name=FuncCall_Name,ParameterList=ParameterList)

    def GateOp(self, node):
        if not node:
            return
        child = node.first_son
        GateOp_Name = ''
        placeList = ''
        while child:
            if child.type == 'GateOp_Name':
                GateOp_Name = child.value
            elif child.value == 'ParameterList' and child.type == None:
                list = self.tree.find_all_child(child)
                for n in list:
                    placeList += ',' + n.value
                placeList = placeList[1:]   # 去除第一个,
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(GateOp_Name=GateOp_Name, placeList=placeList)

    def R(self, node):
        if not node:
            return
        child = node.first_son
        GateOp_Name = ''
        placeList = ''
        while child:
            if child.value == 'R':
                GateOp_Name = child.value
            elif child.value == 'ParameterList' and child.type == None:
                list = self.tree.find_all_child(child)
                GateOp_Name = GateOp_Name + list[0].value
                list = list[1:]
                for n in list:
                    placeList += ',' + n.value
                placeList = placeList[1:]   # 去除第一个,
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(GateOp_Name=GateOp_Name, placeList=placeList)

    def FuncCall(self, node):
        if not node:
            return
        child = node.first_son
        FuncCall_Name = ''
        ParameterList = ''
        while child:
            if child.type == 'FuncCall_Name':
                FuncCall_Name = child.value
            elif child.value == 'ParameterList' and child.type == None:
                pl = self.tree.find_all_child(child)
                for p in pl:
                    ParameterList += ',' + p.value
                ParameterList = ParameterList[1:]   # 去除第一个,
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(FuncCall_Name=FuncCall_Name, ParameterList=ParameterList)

    '''qubit.measure(place=$place, count=$count)'''
    def measure(self, node):
        if not node:
            return
        child = node.first_son
        place = '-1'
        count = '1'
        while child:
            if child.value == 'measure':
                pass
            elif child.value == 'ParameterList' and child.type == None:
                pl = self.tree.find_all_child(child)
                '''这里需要分别处理measure(q) === measure(),
                    measure(q[0]) === measure(0)的情况'''
                for p in pl:
                    if p.type == 500:
                        pass
                    elif p.type == 600:
                        place = p.value
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(place=place, count=count)

    def show(self, node):
        if not node:
            return
        child = node.first_son
        iden = None
        while child:
            if child.value == 'show':
                pass
            elif child.value == 'ParameterList' and child.type == None:
                pl = self.tree.find_all_child(child)
                '''show(m1), show(1)'''
                for p in pl:
                    if p.type == 500:
                        iden = p.value
                    elif p.type == 600:
                        iden = p.value
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        symbalTable.add(value=iden, type='show')
        return dict(Iden=iden)

    def Declare_quantum(self, node):
        if not node:
            return
        child = node.first_son
        numQubits = '-1'
        qubit = 'qubit'
        while child:
            if child.value == 'quantum':
                pass
            elif child.type == 500:
                pass
            elif child.value == '=':
                pass
            elif child.value == 'Declare_quantum' and child.father.value == 'Declare_quantum':
                return Translate.Declare_quantum(self, child)
            elif child.value == 'FuncCall' and child.type == None:
                list = self.tree.find_all_child(child)
                for n in list:
                    if n.type == 'FuncCall_Name':
                        pass
                    elif n.value == 'ParameterList' and n.type == None:
                        pl = self.tree.find_all_child(n)
                        numQubits = pl[0].value
            elif child.type == None and child.value == 'ParameterList':
                # 函数式声明quantumRegister
                list = self.tree.find_all_child(child)
                numQubits = list[0].value
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        return dict(qubit=qubit, numQubits=numQubits)

    def Declare_measure(self, node):
        if not node:
            return
        child = node.first_son
        Iden = 'm'
        place = '-1'
        count = '1'
        while child:
            if child.type == 500:
                Iden = child.value
            elif child.value == '=':
                pass
            elif child.value == 'FuncCall' and child.type == None:
                list = self.tree.find_all_child(child)
                for n in list:
                    if n.type == 'FuncCall_Name':
                        pass
                    elif n.value == 'ParameterList' and n.type == None:
                        pl = self.tree.find_all_child(n)
                        '''这里需要分别处理measure(q), measure(q[0])的情况'''
                        for p in pl:
                            if p.type == 500:
                                pass
                            elif p.type == 600:
                                place = p.value
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        symbalTable.add(name=Iden, value='measure', type='measure')
        return dict(Iden=Iden, place=place, count=count)

    def Declare_INT(self, node):
        if not node:
            return
        child = node.first_son
        Iden = 'Iden'
        INT = ''
        while child:
            if child.type == 500:
                Iden = child.value
            elif child.value == '=':
                pass
            elif child.type == 'INT':
                INT = child.value
            else:
                raise ValueError('Failed to analyze child: {}'.format(child.format()))
            child = child.right
        symbalTable.add(name=Iden, value=INT, type='Identify')
        return dict(Iden=Iden, INT=INT)

    def main(self):
        tree = self.tree
        childs = tree.find_all_child(tree.root)
        for child in childs:
            if child.value == 'Declare_func':
                dict = self.Declare_func(child)
                self.fileHandler.insert(dict, 'Declare_func')
            elif child.value == 'Declare_INT':
                dict = self.Declare_INT(child)
                self.fileHandler.insert(dict, 'Declare_INT')
            elif child.value == 'Declare_quantum':
                dict = self.Declare_quantum(child)
                self.fileHandler.insert(dict, 'Declare_quantum')
            elif child.value == 'Declare_measure':
                dict = self.Declare_measure(child)
                self.fileHandler.insert(dict, 'Declare_measure')
            elif child.value == 'GateOp':
                dict = self.GateOp(child)
                self.fileHandler.insert(dict, 'GateOp')
            elif child.value == 'FuncStatement':
                dict = self.FuncStatement(child)
                self.fileHandler.insert(dict, 'FuncStatement')
            elif child.value == 'FuncCall':
                if child.first_son.value == 'measure':
                    dict = self.measure(child)
                    self.fileHandler.insert(dict, 'measure')
                elif child.first_son.value == 'show':
                    # show函数不需要生成代码
                    dict = self.show(child)
                    self.fileHandler.insert(dict, 'show')
                elif child.first_son.value == 'R':
                    dict = self.R(child)
                    self.fileHandler.insert(dict, 'R')
                else:
                    dict = self.FuncCall(child)
                    self.fileHandler.insert(dict, 'FuncCall')
            elif child.value == 'IFStatement':
                dict = self.IFStatement(child)
                self.fileHandler.insert(dict, 'IFStatement')
                pass

if __name__ == '__main__':
    print('translate')
    lexer = Lexer(file_path='QLight/code_2.txt')
    lexer.scanner()
    lexer.log()
    parser = Parser(lexer.getTOKEN())
    parser.parse()
    parser.log()
    translate = Translate(parser.tree)
    translate.main()
    translate.log()


import random
from typing import Sequence

class HomophonicSubstitutionCipher:
    """Шифр многозначной замены."""

    @classmethod
    def encode(cls, message: Sequence, alphabet: str, table: Sequence) -> list:
        result = []

        for letter in message:
            index = alphabet.index(letter)
            result.append(random.choice(table[index]))

        return result

    @classmethod
    def decode(cls, message: Sequence, alphabet: str, table: Sequence) -> str:
        if isinstance(message, str):
            keys = []

            for i, letter in enumerate(message):
                if i % 3 == 0:
                    keys.append(letter)
                    continue

                keys[-1] += letter

            keys = [int(key) for key in keys]
        else:
            keys = message

        table = [set(row) for row in table]
        result = ''

        for key in keys:
            for i, row in enumerate(table):
                if key in row:
                    result += alphabet[i]
                    break

        return result


import cv2
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("file")
args = parser.parse_args()
file = args.file

img=cv2.imread(file, cv2.IMREAD_UNCHANGED)
def checkHits(img):
    shp=img.shape
    if len(shp)==2:
        r,g,b,mask = cv2.split(img)
    elif len(shp)==3:
        mask=img.copy()
    else:
        print('huh?')

    size=shp[0]*shp[1]

    marked=cv2.countNonZero(mask)
return

print(marked/size,'%')


import streamlit as st
import pandas as pd

tipo_de_material = []
rugosidad = []
tipo_de_materialR = []
rugosidadR = []

#Funciones para realizar conversiones
def milimetros_metros(mm):
    return mm*0.001

def milimetros_pie(mm):
    return mm*0.00328084

def milimetros_pulgadas(mm):
    return mm*0.03937008

#Funcion para mostrar la informacion ordenada
def mostrarInformacion(nombre_del_material, mm):
    informacion = ""

    print(nombre_del_material.upper())

    if(len(mm) == 2):
        informacion = {
            "Metros": "{:.8f} - {:.8f}".format(milimetros_metros(mm[0]), milimetros_metros(mm[0])),
            "Pies": "{:.8f} - {:.8f}".format(milimetros_pie(mm[0]), milimetros_pie(mm[0])),
            "Pulgadas":"{:.8f} - {:.8f}" .format(milimetros_pulgadas(mm[0]), milimetros_pulgadas(mm[1]))
        }
    else:
        informacion = {
            "Metros: ": "{:.8f}".format(milimetros_metros(mm[0])),
            "Pies": "{:.8f}".format(milimetros_pie(mm[0])),
            "Pulgadas": "{:.8f}".format(milimetros_pulgadas(mm[0]))
        }

    return informacion

materiales = {
    "Drawn Copper":[0.001,0.002],
    "Lead":[0.001,0.002],
    "Brass":[0.001,0.002],
    "Aluminum (new) and the like":[0.001,0.002],
    "PVC":[0.0015,0.007],
    "PE and other smooth Plastic Pipes":[0.0015,0.007],
    "Stainless steel, turned":[0.0004,0.006],
    "Stainless steel, electron-polished":[0.0001,0.0008],
    "Comercial steel or wrought iron":[0.045,0.09],
    "Stretched steel":[0.015],
    "Weld steel":[0.045],
    "Galvanized steel":[0.15],
    "Rusted steel (corrosion)":[0.15,4],
    "New cast iron":[0.25,0.8],
    "Worn cast iron":[0.8,1.5],
    "Rusty cast iron":[1.5,2.5],
    "Sheet or asphalted cast iron":[0.01,0.015],
    "Smoothed cement":[0.3],
    "Ordinary concrete":[0.3,1],
    "Coarse concrete":[0.3,5],
    "Wood stove":[0.18,0.9],
    "Well planed wood":[0.18,0.9],
    "Ordinary wood":[5],
}

for i in materiales:
  tipo_de_material.append(i)
  rugosidad.append(materiales[i])

tabla_materiales = {
  "Materiales": tipo_de_material,
  "Rango De Rugosidad": rugosidad
}

if st.checkbox("Mostrar Tabla"):
  st.write(pd.DataFrame.from_dict(tabla_materiales))

with st.form("My Form"):
  st.title("Seleccione el material")
  material_elegido = st.radio(
        "",
        (tipo_de_material))

  submitted = st.form_submit_button("Calcular")
  if submitted:
    st.write("El material elegido es: {}".format(material_elegido))
    resultados = mostrarInformacion(material_elegido, materiales[material_elegido])

    for i in resultados:
      tipo_de_materialR.append(i)
      rugosidadR.append(resultados[i])

    tabla_resultados = {
        "Unidad de medida": tipo_de_materialR,
        "Rango De Rugosidad": rugosidadR
    }

    st.write(pd.DataFrame.from_dict(tabla_resultados))


from aws_cdk import (
    aws_eks as _eks,
    aws_ec2 as _ec2,
    aws_iam as _iam
)
from constructs import Construct

class DeployEksCluster(Construct):

    def __init__(self, scope: Construct, id: str, ecr_repo_name: str, image_tag: str, container_port: int, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        #Create EKS Cluster
        cluster_name='%s-Cluster' % id
        eks_cluster=_eks.FargateCluster(
            self, cluster_name,
            cluster_name=cluster_name,
            version=_eks.KubernetesVersion.V1_21
        )

        #eks_cluster.add_nodegroup_capacity(
        #    'node_group',
        #    min_size=1,
        #    max_size=2,
        #    instance_types=[_ec2.InstanceType('t2.micro')]
        #)

        #Deploy the App
        #eks_cluster.add_manifest("mypod", {
        #    "apiVersion": "v1",
        #    "kind": "Pod",
        #    "metadata": {"name": "mypod"},
        #    "spec": {
        #        "containers": [{
        #            "name": "hello",
        #            "image": "%s:%s" % (ecr_repo_name, image_tag),
        #            "ports": [{"containerPort": container_port}]
        #        }
        #        ]
        #    }
        #})


from django.core.management.base import BaseCommand
from corehq.sql_db.shard_data_management import get_count_of_unmatched_models_by_shard
from corehq.sql_db.util import get_db_aliases_for_partitioned_query, get_all_sharded_models

class Command(BaseCommand):
    help = "Print out all shard data that exists in databases that don't contain the associated shards."

    def handle(self, **options):
        sharded_models = list(get_all_sharded_models())
        for database in get_db_aliases_for_partitioned_query():
            for model in sharded_models:
                invalid_data = get_count_of_unmatched_models_by_shard(database, model)
                if invalid_data:
                    for shard_id, count in invalid_data:
                        print('found {} unexpected {}s in {} (shard {}).'.format(
                            count, model.__name__, database, shard_id)
                        )


from selenium import webdriver #pip install selenium
from selenium import common
from selenium.webdriver.common import keys #pip install webdriver-manager
from webdriver_manager.chrome import ChromeDriverManager
import subprocess
import keyboard
import random
import time
import os

import configurations
#import bot file name
filename = configurations.bot_file

# Twitter credentials
twitter_name = configurations.username
twitter_pass = configurations.password

class Twitter_Service(object):

    def __init__(self):
        pass

    # Senitise User Input
    def sanitised_input(self, prompt, type_=None, min_=None, max_=None, range_=None):
        if min_ is not None and max_ is not None and max_ < min_:
            raise ValueError("min_ must be less than or equal to max_.")
        while True:
            ui = input(prompt)
            if type_ is not None:
                try:
                    ui = type_(ui)
                except ValueError:
                    print("Input type must be {0}.".format(type_.__name__))
                    continue
            if max_ is not None and ui > max_:
                print("Input must be less than or equal to {0}.".format(max_))
            elif min_ is not None and ui < min_:
                print("Input must be greater than or equal to {0}.".format(min_))
            elif range_ is not None and ui not in range_:
                if isinstance(range_, range):
                    template = "Input must be between {0.start} and {0.stop}."
                    print(template.format(range_))
                else:
                    template = "Input must be {0}."
                    if len(range_) == 1:
                        print(template.format(*range_))
                    else:
                        expected = " or ".join((
                            ", ".join(str(x) for x in range_[:-1]),
                            str(range_[-1])
                        ))
                        print(template.format(expected))
            else:
                return ui

    # Read data from file
    def read_file(self, filename):
        with open(filename) as fin:
            data = fin.read().splitlines(True)
            data_count = len(data)

            if (data_count==0):
                return {
                    "have_data" : False,
                }

            else:
               return {
                    "have_data" : True,
                    "data" : data,
                }

    # Write data to file
    def write_file(self, filename, data):
        with open(filename, 'w') as fout:
                fout.writelines("%s\n" % datapoint for datapoint in data)
        return True

    # Combine and rotate hashtags
    def rotate_hashtags(self, list_input, n):
        rotated_list = list_input[n:] + list_input[:n]
        rotated_hashtag_string = ""

        for item in rotated_list:
            item = item.strip("\n")
            rotated_hashtag_string += item + " "

        return rotated_hashtag_string

    # Initiate browser
    def initiate_browser(self):
        browser  = webdriver.Chrome(ChromeDriverManager().install())
        time.sleep(3)
        return browser

    # Open Twitter Website
    def open_twitter(self, browser):
        browser.get('https://twitter.com/login/')
        time.sleep(3)

    # Fill credentials and login
    def login(self, browser):
        try:
            browser.find_element_by_name('session[username_or_email]').send_keys(twitter_name)
            time.sleep(1)
            browser.find_element_by_name('session[password]').send_keys(twitter_pass)
            time.sleep(1)
            browser.find_element_by_name('session[password]').send_keys(keys.Keys.RETURN)
            time.sleep(3)

        except Exception as e:
            print("EXCEPTION - LOG IN. RESTARTING!")
            print(e)
            time.sleep(2)
            browser.close()
            time.sleep(2)
            subprocess.Popen('python ' + filename, shell=True).wait()

    # Logout
    def logout(self, browser):
        try:
            browser.find_element_by_xpath("//div[@data-testid='SideNav_AccountSwitcher_Button']").click()
            time.sleep(2)
            browser.find_element_by_xpath("//a[@data-testid='AccountSwitcher_Logout_Button']").click()
            time.sleep(2)
            browser.find_element_by_xpath("//div[@data-testid='confirmationSheetConfirm']").click()
            time.sleep(3)

        except Exception as e:
            print("EXCEPTION - LOG OUT. RESTARTING!")
            print(e)
            time.sleep(2)
            browser.close()
            time.sleep(2)
            subprocess.Popen('python ' + filename, shell=True).wait()

    # Post tweets
    def post_tweets(self, browser, hashtagged_tweets):
        random_int = random.randint(0,len(hashtagged_tweets)-1)
        tweet = hashtagged_tweets[random_int]

        try:
            browser.find_element_by_xpath("//a[@data-testid='SideNav_NewTweet_Button']").click()
            time.sleep(2)

            img = tweet.split('|')[0]
            tweet = tweet.split('|')[1]

            if(img!=''):
                files = []
                for i in os.listdir(configurations.img_path):
                    if os.path.isfile(os.path.join(configurations.img_path,i)) and img in i:
                        files.append(i)

                for file_ in files:
                    file_upload = browser.find_element_by_xpath("//input[@type='file']")
                    browser.execute_script("arguments[0].style.display = 'block';", file_upload)
                    file_upload.send_keys(configurations.img_path + file_)

            browser.find_element_by_xpath("//div[@role='textbox']").send_keys(tweet)
            time.sleep(2)
            browser.find_element_by_class_name("notranslate").send_keys(keys.Keys.ENTER)
            time.sleep(2)
            browser.find_element_by_xpath("//div[@data-testid='tweetButton']").click()
            time.sleep(3)

        except Exception as e:
            print("EXCEPTION - POST TWEETS. RESTARTING!")
            print(e)
            time.sleep(2)
            browser.close()
            time.sleep(2)
            subprocess.Popen('python ' + filename, shell=True).wait()

    # Search tweets
    def search_tweets(self, browser, keyword):
        try:
            browser.get('https://twitter.com/hashtag/' + keyword + '?src=hashtag_click&f=live')
            return True

        except Exception as e:
            print("EXCEPTION - SEARCH TWEETS. RESTARTING!")
            print(e)
            time.sleep(2)
            browser.close()
            time.sleep(2)
            subprocess.Popen('python ' + filename, shell=True).wait()

    # Like/Retweet tweets
    def like_tweets(self, browser, count=10):
        keyboard.press_and_release('left alt + tab')
        keyboard.press_and_release('right arrow')
        keyboard.send('enter')

        for i in range(count):
            try:
                keyboard.send('j')
                time.sleep(0.5)

                keyboard.send('l')
                time.sleep(0.5)

                keyboard.send('t')
                time.sleep(0.5)

                keyboard.send('enter')
                time.sleep(2)

            except Exception as e:
                print("EXCEPTION - LIKE/RETWEET TWEETS. RESTARTING!")
                print(e)
                time.sleep(2)
                browser.close()
                time.sleep(2)
                subprocess.Popen('python ' + filename, shell=True).wait()