import sys
import getopt
import numpy as np
import scipy
from scipy import ndimage
from os import listdir
import matplotlib.pyplot as plt

def Read_CSV(fname):
    f = open(fname, "r")
    Y = np.empty((1, 0))
    X = np.empty((64*64*3,0))
    i=0
    for line in f:
        data = line.split(',')
        with urllib.request.urlopen(data[0]) as url:
            f = io.BytesIO(url.read())
        a = ndimage.imread(f, flatten=False)
        b = scipy.misc.imresize(a, size=(128, 128))
        b = b/255
        c = b.reshape(128*128*3, 1)
        X = np.hstack((X, c))
        Y[0].append(int(data[1]))
        i = i+1
    print(Y)
    return X, Y

def Read_File(fname):
    a = ndimage.imread(fname, flatten=False)
    b = scipy.misc.imresize(a, size=(128, 128))
    #Normalize data. 255 beecause max pixel value is 255
    b = b/255
    c = b.reshape(128*128*3, 1)
    return c

def collect_data(dirname):
    files = listdir(dirname)
    Y = np.empty((1, len(files)))
    X = np.empty((128*128*3,0))

    i = 0
    for f in files:
        a = Read_File(dirname + "/" + f)
        if f.find("cat") == -1:
            Y[0][i] = 0
        else:
            Y[0][i] = 1
        X = np.hstack((X, a))
        i = i+1
    return X, Y

def initialize_hyperparams():
    hyperparams = {}
    hyperparams["learning_rate"] = 0.01 # Learning rate of gradient descent
    hyperparams["num_iterations"] = 4000 # Number of iterations of propagation
    hyperparams["dims"] = [4, 4, 3, 1] # Number of nodes in each layer of NN
    hyperparams["lamba"] = 0.01 # Regularization param lambda
    hyperparams["beta1"] = 0.9 # Exponential Weighted average param
    hyperparams["beta2"] = 0.999 # RMSProp param
    hyperparams["epsilon"] = 10 ** -8 # Adams optimization zero correction
    hyperparams["minibatch"] = 100 # size of the minibatch, 0 indicates no minibatching
    return hyperparams

# Initialize the parameters
# lists_dims["n_x=l0", "l1", "l2" ....]
def initialize_parameters(lists_dims):
    parameters = []
    for i in range(1, len(lists_dims)):
        # 'He' initialization for random weights
        W = np.random.randn(lists_dims[i], lists_dims[i-1]) * np.sqrt(np.divide(2, lists_dims[i-1]))
        Vw = np.zeros(W.shape)
        Sw = np.zeros(W.shape)
        b = np.zeros((lists_dims[i], 1))
        Vb = np.zeros(b.shape)
        Sb = np.zeros(b.shape)
        parameters.append((W, b, Vw, Vb, Sw, Sb))
    return parameters

#Activation Functions
def sigmoid(Z, derivative):
    s = (1/(1+np.exp(-Z)))
    if derivative == True:
        return s*(1-s)
    return s

def relu(Z, derivative):
    for i in range(len(Z)):
        for j in range(len(Z[i])):
            if Z[i][j] > 0:
                if derivative == True:
                    Z[i][j] = 1
                else:
                    pass
            else:
                Z[i][j] = 0
    #print("RELU: ", Z)
    return Z

def forward_activation(Z, func):
    if func == "sigmoid":
        return sigmoid(Z, False)
    elif func == "relu":
        return relu(Z, False)
    else:
        assert(0)
    return None

# Calculate the Z and A parameters of forward propagation for each layer
def forward_propagate(X, parameters, N):
    forward_cache = []
    A = X
    AL = A
    for i in range(N):
        A = AL
        W, b, Vw, Vb, Sw, Sb = parameters[i]
        Z = np.dot(W, A) + b
        if i == N-1 :
            activation_func = "sigmoid"
        else:
            activation_func = "sigmoid"
        AL = forward_activation(Z, activation_func)
        forward_cache.append((A, Z, W, b))
    #print (AL)
    return AL, forward_cache

def regularize_cost(cost, m, lamba, parameters):
    if lamba == 0:
        return cost
    W, b, Vw, Vb, Sw, Sb = parameters[len(parameters)-1]
    n = np.linalg.norm(W)
    normalize = np.divide(lamba, 2*m)*n
    cost = cost + normalize
    return cost

def compute_cost(AL, Y):
    m = Y.shape[1]
    cost = -(np.sum(np.multiply(Y, np.log(AL)) + np.multiply((1-Y), np.log(1-AL))))/Y.shape[1]
    cost = np.squeeze(cost)
    return cost

def back_propagate_linear(dZ, forward_cache):
    A, Z, W, b = forward_cache
    m = A.shape[1]
    dW = (np.dot(dZ, A.T))/m
    assert(W.shape == dW.shape)
    db = (np.sum(dZ, axis=1, keepdims=True))/m
    assert(b.shape == db.shape)
    dA_prev = np.dot(W.T, dZ)
    assert(dA_prev.shape == A.shape)
    return dA_prev, dW, db

def back_propagate_activation(dA, forward_cache, activation_func):
    A, Z, W, b = forward_cache

    if activation_func == "relu":
        dZ = dA*relu(Z, True)
    elif activation_func == "sigmoid":
        dZ = dA*sigmoid(Z, True)
    else:
        assert(0)

    return back_propagate_linear(dZ, forward_cache)

def back_propagate(AL, Y, forward_cache):
    grads = []
    dA = - (np.divide(Y, AL) - np.divide((1-Y), (1-AL)))
    activation_func = "sigmoid"
    for cache in reversed(forward_cache):
        dA_prev, dW, db = back_propagate_activation(dA, cache, activation_func)
        grads.append((dW, db))
        dA = dA_prev
        activation_func = "sigmoid"
    return grads

def regularize_weights(W, m, learning_rate, lamba):
    if lamba == 0:
        return W
    W = W - np.multiply(np.divide(np.multiply(learning_rate, lamba), m), W)
    return W

# A combination of Exponential Weighted Average and RMSProp with bias correction
# To be used with mini-batches

def momentum(dW, db, Vw, Vb, hyperparams, layer):
    beta1 = hyperparams["beta1"]
    Vw = np.multiply(beta1, Vw) + np.multiply((1-beta1), dW)
    Vw_corrected = np.divide(Vw, (1-np.power(beta1, layer)))
    Vb = np.multiply(beta1, Vb) + np.multiply((1-beta1), db)
    Vb_corrected = np.divide(Vb, (1-np.power(beta1, layer)))
    return Vw_corrected, Vb_corrected, Vw, Vb

def rms_prop(dW, db, Sw, Sb, hyperparams, layer):
    beta2 = hyperparams["beta2"]
    epsilon = hyperparams["epsilon"]
    Sw = np.multiply(beta2, Sw) + np.multiply((1-beta2), np.power(dW,2))
    Sw_corrected = np.divide(Sw, (1-np.power(beta2, layer)))
    Sb = np.multiply(beta2, Sb) + np.multiply((1-beta2), np.power(db, 2))
    Sb_corrected = np.divide(Sb, (1-np.power(beta2, layer)))
    dW_optimized = np.divide(dW, (np.sqrt(Sw_corrected + epsilon)))
    db_optimized = np.divide(db, (np.sqrt(Sb_corrected + epsilon)))
    return dW_optimized, db_optimized, Sw, Sb

def adams_optimization(dW, db, Vw, Vb, Sw, Sb, hyperparams, layer):
    beta1 = hyperparams["beta1"]
    beta2 = hyperparams["beta2"]
    epsilon = hyperparams["epsilon"]
    Vw = np.multiply(beta1, Vw) + np.multiply((1-beta1), dW)
    Vw_corrected = np.divide(Vw, (1-np.power(beta1, layer)))
    Sw = np.multiply(beta2, Sw) + np.multiply((1-beta2), np.power(dW, 2))
    Sw_corrected = np.divide(Sw, (1-np.power(beta2, layer)))
    Vb = np.multiply(beta1, Vb) + np.multiply((1-beta1), db)
    Vb_corrected = np.divide(Vb, (1-np.power(beta1, layer)))
    Sb = np.multiply(beta2, Sb) + np.multiply((1-beta2), np.power(db, 2))
    Sb_corrected = np.divide(Sb, (1-np.power(beta2, layer)))
    dW_optimized = np.divide(Vw_corrected, (np.sqrt(Sw_corrected) + epsilon))
    db_optimized = np.divide(Vb_corrected, (np.sqrt(Sb_corrected) + epsilon))
    return dW_optimized, db_optimized, Vw, Vb, Sw, Sb

def update_parameters(m, parameters, grads, hyperparams):
    new_params = []
    learning_rate = hyperparams["learning_rate"]
    j=len(parameters)-1
    for i in range(len(parameters)):
        W, b, Vw, Vb, Sw, Sb = parameters[i]
        dW, db = grads[j]
        #dW, db, Vw, Vb, Sw, Sb = adams_optimization(dW, db, Vw, Vb, Sw, Sb, hyperparams, j+1)
        dW, db, Vw, Vb = momentum(dW, db, Vw, Vb, hyperparams, j+1)
        #dW, db, Sw, Sb = rms_prop(dW, db, Sw, Sb, hyperparams, j+1)
        j = j-1
        W = W - (learning_rate * dW)
        W = regularize_weights(W, m, learning_rate, hyperparams["lamba"])
        b = b - (learning_rate * db)
        new_params.append((W, b, Vw, Vb, Sw, Sb))
    return new_params

def calculate_success(Y, AL):
    p = np.around(AL)
    #print("Activation: ", AL)
    for i in range(len(p[0])):
        if(p[0][i] != Y[0][i]):
            p[0][i] = 0
        else:
            p[0][i] = 1
    print("Success Cal: ", p)
    #print("Expectation: ", Y)
    #print(p.shape)
    #print(np.sum(p))
    #print(len(p[0]))
    return np.squeeze(np.sum(p, axis=1, keepdims=1)/len(p[0]))

def create_mini_batches(X, Y, batch_size, seed):
    np.random.seed(seed)
    mini_batches = []
    if batch_size == 0:
        mini_batches.append((X,Y))
        return mini_batches
    m = X.shape[1]
    permutate = np.random.permutation(m)
    X_shuffle = X[:, permutate]
    Y_shuffle = Y[:, permutate]

    num_batches = int(np.floor(m/batch_size))
    for k in range(num_batches):
        mini_batches.append((X[:, batch_size*k:batch_size*(k+1)], Y[:, batch_size*k:batch_size*(k+1)]))

    if m%batch_size>0 :
        mini_batches.append((X[:, batch_size*num_batches:], Y[:, batch_size*num_batches:]))
    return mini_batches

def run_one_epoch(seed, X, Y, parameters, hyperparams, costs, m):
    N = len(parameters)
    batches = create_mini_batches(X, Y, hyperparams["minibatch"], seed)
    for batch in batches:
        X,Y = batch
        AL, forward_cache = forward_propagate(X, parameters, N)
        c = compute_cost(AL, Y)
        c = regularize_cost(c, m, hyperparams["lamba"], parameters)
        costs.append(c)
        grads = back_propagate(AL, Y, forward_cache)
        parameters = update_parameters(m, parameters, grads, hyperparams)
    return parameters, costs, AL

def train_model(X, Y, parameters, hyperparams):
    num_iterations = hyperparams["num_iterations"]
    N = len(parameters)
    m = X.shape[1]
    costs = []
    for i in range(num_iterations):
        parameters, costs, AL = run_one_epoch(i, X, Y, parameters, hyperparams, costs, m)
        if i%100 == 0:
            print ("Cost after ", i, " iterations:", costs[-1])
    AL, forward_cache = forward_propagate(X, parameters, N)
    print ("Trained model success rate: " +  str(calculate_success(Y, AL) *100) + "%")
    return parameters, costs

def test_model(X, Y, parameters):
    m = X.shape[1]
    N = len(parameters)
    AL, forward_cache = forward_propagate(X, parameters, N)
    return calculate_success(Y, AL)

def print_help():
    print ("classifier.py -l <learn_dir> -t <test_dir> -r <learn_rate> -i <num iterations> -n \"<comma separated num nodes in each layer>\"")

def plot_cost_gradient(cost):
    plt.plot(cost)
    plt.ylabel("Cost")
    plt.xlabel("Per 100 iterations")
    plt.title("Cost gradient")
    plt.show()

def main(argv):
    np.random.seed(1)
    learn_dir = "./images"
    test_dir = "./test"
    hyperparams = initialize_hyperparams()

    dims = hyperparams["dims"]

    try:
        opts, args = getopt.getopt(argv, "hl:t:r:i:n:",["help", "learndir=", "testdir=", "learnrate=", "iters=", "net="])
    except getopt.GetoptError:
        print_help()
        sys.exit(2)
    for opt, arg in opts:
        if opt == "-h":
            print_help()
            sys.exit(2)
        elif opt == "-l":
            learn_dir = arg
        elif opt == "-t":
            test_dir == arg
        elif opt == "-r":
            learning_rate = float(arg)
        elif opt == "-i":
            num_iterations = int(arg)
        elif opt == "-n":
            dims_str = arg.split(",")
            dims = []
            for num in dims_str:
                dims.append(int(num))
        else:
            print_help()
            sys.exit(2)
    XL, YL = collect_data(learn_dir)
    XT, YT = collect_data(test_dir)
    #Starting Hyperparameters
    lists_dims = [XL.shape[0]]
    for num in dims:
        lists_dims.append(num)
    print("NN Dimensions: ", lists_dims)
    #Train the model
    parameters = initialize_parameters(lists_dims)
    parameters, cost = train_model(XL, YL, parameters, hyperparams)
    # check out the success rate with a test run
    success_rate = test_model(XT, YT, parameters)
    print ("Test Success rate: " + str(success_rate*100) + "%")
    plot_cost_gradient(cost)

if __name__ == "__main__" :
    main(sys.argv[1:])


import tkinter as tk
mat_op = ''

def click_vienads():
    global mat_op
    otrais_skaitlis = int(teksta_lauks.get())
    result = 0
    if mat_op == '+':
        result = pirmais_skaitlis + otrais_skaitlis
    elif mat_op == '-':
        result = pirmais_skaitlis - otrais_skaitlis
    elif mat_op == '*':
        result = pirmais_skaitlis * otrais_skaitlis
    elif mat_op == '/':
        result = pirmais_skaitlis / otrais_skaitlis
    else:
        result = 0
    teksta_lauks.delete(0,tk.END)
    teksta_lauks.insert(0, str(result))

    mat_op = '='
    #pass

def click_darbiba(command):
    global pirmais_skaitlis
    global mat_op
    mat_op = command
    pirmais_skaitlis = int(teksta_lauks.get())
    teksta_lauks.delete(0,tk.END)

def click_skaitli(number):
    global mat_op
    if mat_op == '=':
        teksta_lauks.delete(0,tk.END)
        mat_op = ''
    teksta_lauks.insert(tk.END,number)

def click_backsp():
    teksts = teksta_lauks.get()
    print(type(teksts))
    teksta_lauks.delete(len(teksts)-1,tk.END)

def click_clear():
    teksta_lauks.delete(0,tk.END)
    #pirmais_skaitlis = 0
    #mat_op = ""

window = tk.Tk()
window.title("Mans kalkulators")

teksta_lauks = tk.Entry(master=window, width=25, font=("Arial", 20), justify=tk.RIGHT)

poga_0 = tk.Button(master=window, text='0', padx=40, pady=20, command=lambda:click_skaitli(0))
poga_1 = tk.Button(master=window, text='1', padx=40, pady=20, command=lambda:click_skaitli(1))
poga_2 = tk.Button(master=window, text='2', padx=40, pady=20, command=lambda:click_skaitli(2))
poga_3 = tk.Button(master=window, text='3', padx=40, pady=20, command=lambda:click_skaitli(3))
poga_4 = tk.Button(master=window, text='4', padx=40, pady=20, command=lambda:click_skaitli(4))
poga_5 = tk.Button(master=window, text='5', padx=40, pady=20, command=lambda:click_skaitli(5))
poga_6 = tk.Button(master=window, text='6', padx=40, pady=20, command=lambda:click_skaitli(6))
poga_7 = tk.Button(master=window, text='7', padx=40, pady=20, command=lambda:click_skaitli(7))
poga_8 = tk.Button(master=window, text='8', padx=40, pady=20, command=lambda:click_skaitli(8))
poga_9 = tk.Button(master=window, text='9', padx=40, pady=20, command=lambda:click_skaitli(9))

poga_plus = tk.Button(master=window, text='+', padx=40, pady=20, command=lambda:click_darbiba('+'))
poga_minus = tk.Button(master=window, text='-', padx=40, pady=20, command=lambda:click_darbiba('-'))
poga_reiz = tk.Button(master=window, text='*', padx=40, pady=20, command=lambda:click_darbiba('*'))
poga_dalit = tk.Button(master=window, text='/', padx=40, pady=20, command=lambda:click_darbiba('/'))
poga_vienads = tk.Button(master=window, text='=', padx=40, pady=20, command=lambda:click_vienads())
poga_backsp = tk.Button(master=window, text='B', padx=40, pady=20, command=lambda:click_backsp())
poga_clear = tk.Button(master=window, text='C', padx=80, pady=20, command=lambda:click_clear())

teksta_lauks.grid(row=0, column=0, columnspan=4)
poga_7.grid(row=1, column=0)
poga_8.grid(row=1, column=1)
poga_9.grid(row=1, column=2)

poga_4.grid(row=2, column=0)
poga_5.grid(row=2, column=1)
poga_6.grid(row=2, column=2)

poga_1.grid(row=3, column=0)
poga_2.grid(row=3, column=1)
poga_3.grid(row=3, column=2)
poga_0.grid(row=4, column=1)

poga_reiz.grid(row=1, column=3)
poga_dalit.grid(row=2, column=3)
poga_plus.grid(row=3, column=3)
poga_minus.grid(row=4, column=3)

poga_backsp.grid(row=4, column=0)
poga_vienads.grid(row=4, column=2)
poga_clear.grid(row=5, column=0, columnspan=4)

window.mainloop()


import math

from qgis.PyQt import QtGui, QtCore

from qgis.core import (
    QgsCircle,
    QgsPoint,
    QgsPointXY,
    QgsFeature,
    QgsGeometry,
    QgsCircularString,
    QgsSnappingConfig,
    QgsProject,
    QgsTolerance,
)

from qgis.PyQt.QtCore import pyqtSignal
from qgis.gui import QgsMapTool, QgsVertexMarker, QgsRubberBand, QgsGeometryRubberBand

# ----------------------------------------------------------- #
#                      Point Dimension                        #
# ----------------------------------------------------------- #
class DimensionPointTool(QgsMapTool):

    completed = pyqtSignal()

    def __init__(self, canvas, dimension_layer):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas

        enable_snapping()

        self.dimension_layer = dimension_layer

        self.vm = create_vertex_marker(self.canvas, "BOX")

    def canvasMoveEvent(self, event):
        point_snap, status = snapping_point(self.canvas, event.pos())
        self.vm.setCenter(point_snap)

    def canvasReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            pt, _ = snapping_point(self.canvas, event.pos())

            geom_line_zero_length = QgsGeometry().fromPolylineXY([pt, pt])

            feat = QgsFeature()
            feat.setGeometry(geom_line_zero_length)
            titik_nilai = str(round(pt.x(), 3)) + "," + str(round(pt.y(), 3))
            feat.setAttributes(["Titik", titik_nilai])

            self.dimension_layer_prov = self.dimension_layer.dataProvider()
            self.dimension_layer.startEditing()
            self.dimension_layer_prov.addFeatures([feat])
            self.dimension_layer.commitChanges()
        elif event.button() == QtCore.Qt.RightButton:
            try:
                self.canvas.scene().removeItem(self.vm)
            except NameError:
                pass

            self.completed.emit()

# ----------------------------------------------------------- #
#                      Angle Dimension                        #
# ----------------------------------------------------------- #
class DimensionAngleTool(QgsMapTool):

    completed = pyqtSignal()

    def __init__(self, canvas, dimension_layer):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas

        enable_snapping()

        self.dimension_layer = dimension_layer

        self.vm_center = create_vertex_marker(self.canvas, "CIRCLE")
        self.vm_1 = create_vertex_marker(self.canvas, "CROSS")
        # self.vm_1.hide()
        self.vm_2 = create_vertex_marker(self.canvas, "CROSS")
        # self.vm_2.hide()

        self.rb_buffer = create_rubberband(self.canvas, "SOLID")
        self.geomrb_buffer = create_geom_rubberband(self.canvas, "SOLID")
        # self.geomrb_buffer.hide()
        self.geomrb_short_arc = create_geom_rubberband(self.canvas, "DOT_LINE")
        # self.geomrb_short_arc.hide()
        self.geomrb_long_arc = create_geom_rubberband(self.canvas, "DOT_LINE")
        # self.geomrb_long_arc.hide()

        self.click_counter = 0

    def canvasMoveEvent(self, event):
        point_snap, status = snapping_point(self.canvas, event.pos())
        if self.click_counter == 0:  # add center point
            # self.vm_center.show()
            self.vm_center.setCenter(point_snap)

        elif self.click_counter == 1:  # create estimate buffer
            # self.geomrb_buffer.show()
            cur_pt = QgsPoint(point_snap)
            circle = QgsCircle.fromCenterPoint(self.center_pt, cur_pt)
            self.circular_string = circle.toCircularString()
            self.geomrb_buffer.setGeometry(self.circular_string)

        elif self.click_counter == 2:  # get first arc point
            cur_pt = QgsPoint(point_snap)
            _, start_arc, _, _ = self.circular_string.closestSegment(cur_pt)
            # self.vm_1.show()
            self.vm_1.setCenter(QgsPointXY(start_arc))

        elif self.click_counter == 3:  # get second arc point
            cur_pt = QgsPoint(point_snap)
            _, end_arc, _, _ = self.circular_string.closestSegment(cur_pt)
            # self.vm_2.show()
            self.vm_2.setCenter(QgsPointXY(end_arc))

        elif self.click_counter == 4:  # choose segment
            p = QgsPoint(point_snap)

            arc = self.check_arc(p, self.shortest_arc, self.longest_arc)
            self.canvas.refresh()
            self.final_arc = arc

    def canvasReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.click_counter += 1
            point_snap, _ = snapping_point(self.canvas, event.pos())
            cur_pt = QgsPoint(point_snap)

            if self.click_counter == 1:  # center point stored
                self.center_pt = QgsPoint(point_snap)
                self.vm_center.setCenter(point_snap)

            elif self.click_counter == 2:  # radius point stored
                self.radius_pt = QgsPointXY(point_snap)

            elif self.click_counter == 3:  # start arc stored
                _, start_arc, _, _ = self.circular_string.closestSegment(cur_pt)
                self.start_arc_pt = start_arc

            elif self.click_counter == 4:  # end arc stored
                _, end_arc, _, _ = self.circular_string.closestSegment(cur_pt)
                self.end_arc_pt = end_arc

                self.shortest_arc = QgsCircularString().fromTwoPointsAndCenter(
                    self.start_arc_pt, self.end_arc_pt, self.center_pt, True
                )
                self.longest_arc = QgsCircularString().fromTwoPointsAndCenter(
                    self.start_arc_pt, self.end_arc_pt, self.center_pt, False
                )
                # self.geomrb_buffer.hide()
                self.geomrb_short_arc.setGeometry(self.shortest_arc)
                # self.geomrb_short_arc.show()
                self.geomrb_long_arc.setGeometry(self.longest_arc)
                # self.geomrb_long_arc.show()

            elif self.click_counter == 5:  # arc finalised
                start_az = self.center_pt.azimuth(self.start_arc_pt)
                end_az = self.center_pt.azimuth(self.end_arc_pt)
                if start_az < 0:
                    start_az = 360 + start_az
                if end_az < 0:
                    end_az = 360 + end_az

                delta_az = abs(start_az - end_az)

                if delta_az >= 180:
                    large_angle = delta_az
                    small_angle = 360 - delta_az
                elif delta_az < 180:
                    small_angle = delta_az
                    large_angle = 360 - delta_az

                if self.arc_chosen == "short":
                    angle = small_angle
                elif self.arc_chosen == "long":
                    angle = large_angle

                angle_feat = QgsFeature()
                angle_feat.setGeometry(self.final_arc.segmentize(0.1))

                angle_value = angle
                angle_feat.setAttributes(["Sudut", str(angle_value)])

                self.dimension_layer_prov = self.dimension_layer.dataProvider()
                self.dimension_layer.startEditing()
                self.dimension_layer_prov.addFeatures([angle_feat])
                self.dimension_layer.commitChanges()

                # try:
                #     self.vm_center.hide()
                #     self.vm_1.hide()
                #     self.vm_2.hide()
                #     self.geomrb_short_arc.hide()
                #     self.geomrb_long_arc.hide()
                # except:
                #     pass

                self.click_counter = 0

        elif event.button() == QtCore.Qt.RightButton:
            try:
                self.canvas.scene().removeItem(self.vm_center)
                self.canvas.scene().removeItem(self.vm_1)
                self.canvas.scene().removeItem(self.vm_2)
                self.canvas.scene().removeItem(self.rb_buffer)
                self.canvas.scene().removeItem(self.geomrb_buffer)
                self.canvas.scene().removeItem(self.geomrb_short_arc)
                self.canvas.scene().removeItem(self.geomrb_long_arc)
            except NameError:
                pass

            self.completed.emit()

    def check_arc(self, point_check, short_arc, long_arc):
        a1, b1, c1, d1 = short_arc.closestSegment(point_check)
        a2, b2, c2, d2 = long_arc.closestSegment(point_check)

        if a1 < a2:
            arc_highlight(self.geomrb_short_arc)
            arc_dehighlight(self.geomrb_long_arc)
            self.arc_chosen = "short"
            return short_arc
        elif a1 > a2:
            arc_highlight(self.geomrb_long_arc)
            arc_dehighlight(self.geomrb_short_arc)
            self.arc_chosen = "long"
            return long_arc

# ----------------------------------------------------------- #
#                     Distance Dimension                      #
# ----------------------------------------------------------- #
class DimensionDistanceTool(QgsMapTool):

    completed = pyqtSignal()

    def __init__(self, canvas, dimension_layer):
        QgsMapTool.__init__(self, canvas)
        self.canvas = canvas
        self.dimension_layer = dimension_layer

        enable_snapping()

        self.vm_1 = create_vertex_marker(self.canvas, "CROSS")
        self.vm_2 = create_vertex_marker(self.canvas, "CIRCLE")

        self.rb_draw = create_rubberband(self.canvas)
        self.rb_main = create_rubberband(self.canvas)
        self.rb_start = create_rubberband(self.canvas, "DASH_LINE")
        self.rb_end = create_rubberband(self.canvas, "DASH_LINE")

        self.list_vm = []
        self.list_vm.append(self.vm_1)
        self.list_vm.append(self.vm_2)

        self.click_counter = 0

    def canvasMoveEvent(self, event):
        point_snap, _ = snapping_point(self.canvas, event.pos())
        if self.click_counter == 0:  # proceed to add start point
            self.vm_1.setCenter(point_snap)

        elif self.click_counter == 1:  # proceed to add end point
            self.vm_2.setCenter(point_snap)
            list_point = [self.start_point, point_snap]
            draw_geom = QgsGeometry().fromPolylineXY(list_point)
            self.rb_draw.setToGeometry(draw_geom)

        elif self.click_counter == 2:  # proceed to start offsetting
            p = self.canvas.getCoordinateTransform().toMapCoordinates(event.pos())
            sqrdist, pt, nid, side = self.main_geom.closestSegmentWithContext(p)
            dist = math.sqrt(sqrdist)
            # breaking change since QGIS 3.22
            # self.offset_geom = self.main_geom.offsetCurve(-side * dist, 6, 'JoinStyleMiter', 1)
            self.offset_geom = self.main_geom.offsetCurve(-side * dist, 6, QgsGeometry.JoinStyleRound, 1)
            _, offset_start, _, _ = self.offset_geom.closestSegmentWithContext(
                self.start_point
            )
            _, offset_end, _, _ = self.offset_geom.closestSegmentWithContext(
                self.end_point
            )
            start_point_list = [self.start_point, offset_start]
            end_point_list = [self.end_point, offset_end]
            self.start_geom = QgsGeometry.fromPolylineXY(start_point_list)
            self.end_geom = QgsGeometry.fromPolylineXY(end_point_list)
            self.rb_start.setToGeometry(self.start_geom)
            self.rb_end.setToGeometry(self.end_geom)
            self.rb_main.setToGeometry(self.offset_geom)

    def canvasReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.click_counter += 1
            self.point_snap, _ = snapping_point(self.canvas, event.pos())

            if self.click_counter == 1:  # indicates finished adding first point
                self.vm_1.setCenter(self.point_snap)
                self.start_point = self.point_snap

            elif self.click_counter == 2:  # indicates finished adding second point
                self.vm_2.setCenter(self.point_snap)
                self.end_point = self.point_snap
                list_point_main = [self.start_point, self.end_point]
                self.main_geom = QgsGeometry().fromPolylineXY(list_point_main)
                self.rb_main.setToGeometry(self.main_geom)

            elif self.click_counter == 3:  # indicates finished offsetting line
                start_feat = QgsFeature()
                start_feat.setGeometry(self.start_geom)
                start_feat.setAttributes(["-", "-"])

                end_feat = QgsFeature()
                end_feat.setGeometry(self.end_geom)
                end_feat.setAttributes(["-", "-"])

                offset_feat = QgsFeature()
                offset_feat.setGeometry(self.offset_geom)
                distance_value = round(self.offset_geom.length(), 3)
                offset_feat.setAttributes(["Jarak", str(distance_value)])

                result_feat = [start_feat, end_feat, offset_feat]

                self.dimension_layer_prov = self.dimension_layer.dataProvider()
                self.dimension_layer.startEditing()
                self.dimension_layer_prov.addFeatures(result_feat)
                self.dimension_layer.commitChanges()

                self.click_counter = 0

        elif event.button() == QtCore.Qt.RightButton:
            try:
                self.canvas.scene().removeItem(self.vm_1)
                self.canvas.scene().removeItem(self.vm_2)
                self.canvas.scene().removeItem(self.rb_draw)
                self.canvas.scene().removeItem(self.rb_main)
                self.canvas.scene().removeItem(self.rb_start)
                self.canvas.scene().removeItem(self.rb_end)
            except Exception:
                pass
            self.completed.emit()

def snapping_point(canvas, point):
    map_coord = canvas.getCoordinateTransform().toMapCoordinates(point)
    snapped = canvas.snappingUtils().snapToMap(point)

    if snapped.isValid():
        return snapped.point(), snapped.isValid()
    else:
        return map_coord, snapped.isValid()

def create_vertex_marker(canvas, type="BOX"):
    vm = QgsVertexMarker(canvas)

    if type == "BOX":
        icon_type = QgsVertexMarker.ICON_BOX
    elif type == "CIRCLE":
        icon_type = QgsVertexMarker.ICON_CIRCLE
    elif type == "CROSS":
        icon_type = QgsVertexMarker.ICON_CROSS
    else:
        icon_type = QgsVertexMarker.ICON_X

    vm.setIconType(icon_type)
    vm.setPenWidth(3)
    vm.setIconSize(7)
    return vm

def create_rubberband(canvas, line_style="SOLID_LINE"):
    rb = QgsRubberBand(canvas, False)
    rb.setStrokeColor(QtGui.QColor(128, 128, 128, 180))  # grey
    rb.setFillColor(QtGui.QColor(0, 0, 0, 0))
    rb.setWidth(1)
    if line_style == "DASH_LINE":
        rb.setLineStyle(QtCore.Qt.DashLine)
    elif line_style == "SOLID_LINE":
        rb.setLineStyle(QtCore.Qt.SolidLine)
    elif line_style == "DOT_LINE":
        rb.setLineStyle(QtCore.Qt.DotLine)
    return rb

def create_geom_rubberband(canvas, line_style="SOLID_LINE"):
    # QgsGeometryRubberBand allows the usage of circular string so that it will
    # be possible to draw circle without using buffer function

    rb = QgsGeometryRubberBand(canvas, False)
    rb.setStrokeColor(QtGui.QColor(128, 128, 128, 180))  # grey
    rb.setFillColor(QtGui.QColor(0, 0, 0, 0))
    rb.setVertexDrawingEnabled(False)
    rb.setStrokeWidth(1)
    if line_style == "DASH_LINE":
        rb.setLineStyle(QtCore.Qt.DashLine)
    elif line_style == "SOLID_LINE":
        rb.setLineStyle(QtCore.Qt.SolidLine)
    elif line_style == "DOT_LINE":
        rb.setLineStyle(QtCore.Qt.DotLine)
    return rb

def arc_highlight(arc):
    arc.setStrokeWidth(2)
    arc.setStrokeColor(QtGui.QColor(100, 100, 100, 180))

def arc_dehighlight(arc):
    arc.setStrokeWidth(1)
    arc.setStrokeColor(QtGui.QColor(128, 128, 128, 180))

def snapping_config():
    config = QgsSnappingConfig()
    config.setType(QgsSnappingConfig.VertexAndSegment)
    config.setUnits(QgsTolerance.Pixels)
    config.setTolerance(15)
    config.setIntersectionSnapping(True)
    config.setMode(QgsSnappingConfig.AllLayers)
    return config

def enable_snapping(value=True):
    config = snapping_config()
    config.setEnabled(value)
    QgsProject.instance().setSnappingConfig(config)


class Meta:
    def __getattr__(self, name):
        print('get', name)

    def __setattr__(self, name, value):
        print('set', name, value)

if __name__ == '__main__':
    x = Meta()
    x.append = '+'
    x.append
    x.lang = 'Python'
    x.lang
    x.framework
    x.framework = 'Django'


import json

from rest_framework import status

from api.constans import AutoNotificationConstants, TaskStageConstants, \
    CopyFieldConstants
from api.models import *
from api.tests import GigaTurnipTestHelper, to_json

class CategoryTest(GigaTurnipTestHelper):

    def test_list_categories(self):
        products_category = Category.objects.create(
            name="Producs"
        )

        e_commerce_category = Category.objects.create(
            name="E-Commerce"
        )
        e_commerce_category.parents.add(self.category)

        electronics_category = Category.objects.create(
            name="Electronics"
        )
        pcs_category = Category.objects.create(
            name="Personal computers"
        )
        pcs_devices_category = Category.objects.create(
            name="Personal computers attributes."
        )
        pcs_mouses_category = Category.objects.create(
            name="Mouses"
        )

        electronics_category.out_categories.add(pcs_category)
        electronics_category.out_categories.add(pcs_devices_category)
        pcs_devices_category.out_categories.add(pcs_mouses_category)

        answer = [
            {
                'id': self.category.id,
                'name': self.category.name,
                'out_categories': [
                    e_commerce_category.id
                ]},
            {
                'id': e_commerce_category.id,
                'name': e_commerce_category.name,
                'out_categories': []},
            {
                'id': electronics_category.id,
                'name': electronics_category.name,
                'out_categories': [
                    pcs_category.id,
                    pcs_devices_category.id
                ]
            },
            {
                'id': pcs_mouses_category.id,
                'name': pcs_mouses_category.name,
                'out_categories': []},
            {
                'id': pcs_category.id,
                'name': pcs_category.name,
                'out_categories': []
            },
            {
                'id': pcs_devices_category.id,
                'name': pcs_devices_category.name,
                'out_categories': [pcs_mouses_category.id]
            },
            {
                'id': products_category.id,
                'name': products_category.name,
                'out_categories': []
            }
        ]
        response = self.get_objects("category-list")
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        content = to_json(response.content)
        self.assertEqual(content["count"], Category.objects.count())
        self.assertEqual(content["results"], answer)


class Solution:
    def countSubarrays(self, nums: List[int], minK: int, maxK: int) -> int:
        ans = 0
        j = -1
        pMin = -1
        pMax = -1

        for i, num in enumerate(nums):
            if num < minK or num > maxK:
                j = i
            if num == minK:
                pMin = i
            if num == maxK:
                pMax = i

            ans += max(0, min(pMin, pMax) - j)

        return ans

LeetCode/2444. Count Subarrays With Fixed Bounds/2444. Count Subarrays With Fixed Bounds.py


def addTwoNumbers1(self, l1, l2):
    num1 = 0
    num2 = 0

    count = 0
    while l1:
        num1 += l1.val * (10 ** count)
        count += 1
        l1 = l1.next

    count = 0

    while l2:
        num2 += l2.val * (10 ** count)
        count += 1
        l2 = l2.next

    result = str(num1 + num2)

    last = None

    for c in result:
        node = ListNode(c)
        node.next = last
        # 여기서 last가 가리키는 것을 바꾸지만, node.next는 last가 이전에 가리키고 있던 객체를 가리키기 때문에 바뀌지 않는다.
        last = node

    return node

def addTwoNumbers2(self, l1, l2):
    root = head = ListNode(0)

    carry = 0
    while l1 or l2 or carry:
        sum = 0
        if l1:
            sum += l1.val
            l1 = l1.next

        if l2:
            sum += l2.val
            l2 = l2.next

        carry, val = divmod(sum + carry, 10)
        head.next = ListNode(val)
        head = head.next

    return root.next


from derivacao.derivada import derivada
from derivacao.polinomio import gerarpolinomio, gerarfuncao
import math

#x = int(input("Insira o valor de x >> "))
grau = int(input("Insira o grau do polinômio >> "))
poli = gerarpolinomio(grau)
f = gerarfuncao(poli)
x_par = int(input("Insira o valor de x >> "))

z = 1
while(z <3):
  print("Derivada de %d° ordem :::::: usando entrada"%z)
  print("forward >> %.5f"%derivada(f,x_par,0.1,'f',z))
  print("backward >> %.5f"%derivada(f,x_par,0.1,'b',z))
  print("cenral >> %.5f"%derivada(f,x_par,0.1,'c',z))
  z +=1

'''

######## usando valores do exemplo em sala

f = math.sin
x = math.pi/3
delta = 0.1

print("Derivada primeira :::::: Exemplo em sala")
print("%.5f"%derivate(f,x,delta,'f'))
print("%.5f"%derivate(f,x,delta,'b'))
print("%.5f"%derivate(f,x,delta,'c'))

print("Derivada segunda::::::::: Exemplo em sala")
print("%.5f"%derivate(f,x,delta,'f',2))
print("%.5f"%derivate(f,x,delta,'b',2))
print("%.5f"%derivate(f,x,delta,'c',2))
'''


import os

import cv2
import matplotlib.pyplot as plt
import numpy as np
import yaml

class Map:
    '''
    Wraps ros2 map into a class
    '''
    def __init__(self):
        self.yaml_path = ''
        self.image_path = ''

        self.image = None
        self.resolution = None
        self.origin = [0.0, 0.0, 0.0]
        self.negate = 0
        self.occupied_thresh = 0.65
        self.free_thresh = 0.196
        self.height = None
        self.width = None

    def initialize(self, path):
        '''
        Initializes the map object from a yaml file

        Args:
        - path: path to the yaml file
        '''
        # read yaml file into a dictionary
        params_dict = {}
        params_dict = yaml.load(open(path, 'r'), Loader=yaml.FullLoader)

        self.yaml_path = path
        self.image_path = os.path.join(os.path.dirname(path),
                                       params_dict['image'])
        self.resolution = params_dict['resolution']
        self.origin = params_dict['origin']
        self.negate = params_dict['negate']
        self.occupied_thresh = params_dict['occupied_thresh']
        self.free_thresh = params_dict['free_thresh']

        # read image
        self.image = cv2.imread(self.image_path, -1)#cv2.IMREAD_GRAYSCALE)
        # if image has > 1 channel, convert to grayscale
        if len(self.image.shape) > 2:
            self.image = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
        self.height, self.width = self.image.shape

    def show_map(self):
        '''
        Shows the map
        '''
        plt.figure()
        print(self.image)
        plt.imshow(self.image, cmap='gray')
        plt.show()

    def show_coordinates(self, xs_cart, ys_cart, color=None, size=600):
        '''
        Shows the map with a coordinate marked in cartesian coordinates

        Args:
        - xs: ndarray of x coordinates
        - ys: ndarray of y coordinates
        - color: ndarray of colors
        - size: size of the map in pixels
        '''
        # if x, y are not iterables, convert them to lists
        if not hasattr(xs_cart, '__iter__'):
            xs_cart = np.array([xs_cart])
            ys_cart = np.array([ys_cart])

        half_size = int(size / 2)
        plt.figure(figsize=(30, 30))
        # use initial coordinates to center the map

        xs, ys = self.cartesian_to_pixel(xs_cart, ys_cart)
        x0 = xs[0]
        y0 = ys[0]

        # shows a square around the initial coordinates
        plt.imshow(self.image, cmap='gray')

        if color is not None:
            #plt.scatter(xs-x0+half_size, ys-y0+half_size, s=100, c=color, cmap='rainbow')
            plt.scatter(xs, ys, s=100, c=color, cmap='rainbow')
        else:
            #plt.scatter(xs-x0+half_size, ys-y0+half_size, s=100, c=np.arange(len(xs)), cmap='rainbow')
            plt.scatter(xs, ys, s=100, c=np.arange(len(xs)), cmap='rainbow')

        # equal aspect ratio
        plt.gca().set_aspect('equal', adjustable='box')

        step = 1 # meters
        step = step / self.resolution # convert to pixels

        xtick_origin = half_size + xs_cart[0] / self.resolution
        ytick_origin = half_size + ys_cart[0] / self.resolution
        xtick_neg = np.arange(xtick_origin, xtick_origin-half_size, -step)
        xtick_pos = np.arange(xtick_origin, xtick_origin+half_size, step)
        ytick_neg = np.arange(ytick_origin, ytick_origin-half_size, -step)
        ytick_pos = np.arange(ytick_origin, ytick_origin+half_size, step)

        xticks = np.concatenate((xtick_neg[::-1][:-1], xtick_pos))
        yticks = np.concatenate((ytick_neg[::-1][:-1], ytick_pos))

        xlabels_pos = np.arange(0, len(xtick_pos))
        xlabels_neg = np.arange(0, -len(xtick_neg), -1)
        ylabels_pos = np.arange(0, -len(ytick_pos),-1)
        ylabels_neg = np.arange(0, len(ytick_neg))

        xlabels = np.concatenate((xlabels_neg[::-1][:-1], xlabels_pos))
        ylabels = np.concatenate((ylabels_neg[::-1][:-1], ylabels_pos))

        #plt.xticks(xticks, xlabels, rotation=45, fontsize=20)
        #plt.yticks(yticks, ylabels, rotation=0, fontsize=20)

        #plt.grid()
        plt.show()

    def cartesian_to_pixel(self, x, y):
        '''
        Converts cartesian coordinates to pixel coordinates

        Args:
        - x: ndarray of x coordinates
        - y: ndarray of y coordinates
        '''
        print(self.origin)
        x_pixel = np.round((x - self.origin[0]) / self.resolution).astype(int)
        y_pixel = self.height - np.round((y - self.origin[1]) / self.resolution).astype(int)

        return x_pixel, y_pixel

    def pixel_to_cartesian(self, x_pixel, y_pixel):
        '''
        Converts pixel coordinates to cartesian coordinates

        Args:
        - x_pixel: ndarray of x coordinates
        - y_pixel: ndarray of y coordinates
        '''
        x = x_pixel * self.resolution + self.origin[0]
        y = (self.height - y_pixel) * self.resolution + self.origin[1]

        return x, y


from os import environ as env
from setuptools import find_packages, setup
from setuptools.command.install import install
import sys

VERSION = "0.1.0"

with open("README.md", "r", encoding="utf-8") as rdm:
    long_description = rdm.read()

class VerifyVersionCommand(install):
    """Custom command to verify that the git tag matches our version"""
    description = 'verify that the git tag matches our version'

    def run(self):
        tag = env .get('CLIPENV_TAG')
        if tag != VERSION:
            info = f"Git tag: {tag} doesn't match with this version: {VERSION}"
            sys.exit(info)

setup(
    name="clipenv",
    version=VERSION,
    description="Attach your venv variables with a clip to your project",
    long_description=long_description,
    author="Ana Valeria Calderón Briz, Daniel Omar Vergara Pérez",
    author_email="valerybriz@gmail.com, daniel.omar.vergara@gmail.com",
    url="https://github.com/dany2691/clipenv",
    license="MIT",
    install_requires=[
        "click",
        "colored"
    ],
    classifiers=[
        # Trove classifiers
        # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
        'Programming Language :: Python :: 3.7',
        'Programming Language :: Python :: Implementation :: CPython',
        'Programming Language :: Python :: Implementation :: PyPy'
    ],
    packages=find_packages(exclude=('tests',)),
    entry_points={
        "console_scripts": [
            "clipenv=clipenv.__main__:clipenv"
        ]
    },
    cmdclass={'verify': VerifyVersionCommand}
)


# temperature
temp = int( input("What will be the maximum temperature today? ") )
if temp <10:
    print("Cold today")
elif temp < 20:
    print("Regular Wellington day, today")
else:
    print("Hot today")
print(20*"-")

# allowance
kitchen = input("Have you helped clean the kitchen (y/n) ? ")
allowance = 5
if kitchen == "y":
    allowance += 2
else:
    allowance +=1
output = "Your allowance is now ${:.2f} ".format(allowance)
print(output)
print(20*"-")

# allowance extended
kitchen = input("Have you helped clean the kitchen (y/n) ? ")
garbage = input("Have you helped put out the garbage (y/n) ? ")
allowance = 5

if kitchen == "y" and garbage == "y":
    allowance += 4
elif kitchen == "y" or garbage == "y":
    allowance += 2
else:
    allowance +=1
output = "Your allowance is now ${:.2f} ".format(allowance)
print(output)
print(20*"-")

# minimum number
a = int( input("Please enter a number: ") )
b = int( input("Please enter a number: ") )
c = int( input("Please enter a number: ") )

if a < b and a < c:
    print( "The minumum is {}".format(a) )
elif b < c:
    print( "The minumum is {}".format(b) )
else:
    print( "The minumum is {}".format(c) )
print(20*"-")
# university entrance
age = 17
ncea = True
english = True
# option 1
if english:
    if age > 20 or (age > 16 and ncea):
        print("Accepted")
    else:
        print("Not accepted")
else:
    print("Not accepted")
print(20*".")
# option 2
if english and ( age > 20 or (age > 16 and ncea)) :
    print("Accepted")
else:
    print("Not accepted")


# imports
import datetime as dt
import os
import os.path as osp
import time

import numpy as np

from .global_imports.smmpl_opcodes import *
from .quickscanpat_calc import quickscanpat_calc
from .sop import sigmampl_boot

# params
_nodoubleinit_l = [
    'suncone'
]

# main func
def main(quickscantype=None, **quickscanparams):
    '''
    quick scan pattern parameters are adjusted in their respective scripts,
    i.e. quickscanpat_calc.<quickscantype>

    But quick scanpattern type, bin resolution and shot averaging time are
    controlled in .params
    '''
    if not quickscantype:
        quickscantype = QUICKSCANTYPE

    # setting log file
    now = dt.datetime.now()
    mainlog = DIRCONFN(
        MPLDATADIR, DATEFMT.format(now), QUICKSCANLOG.format(now)
    )
    SETLOGFN(mainlog)
    today = dt.datetime.combine(dt.date.today(), dt.time())
    mainlognext_dt = today + dt.timedelta(1)  # start a new log the next day

    # determining whether to perform double initialisation
    if quickscantype in _nodoubleinit_l:
        coldstart_boo = False
    else:
        coldstart_boo = True

    # begin operation
    for i in range(QUICKSCANTIMES):
        print(f'starting {quickscantype} quickscan {i}...')

        # updating logfile
        now = dt.datetime.now()

        if now >= mainlognext_dt:
            mainlog = DIRCONFN(
                MPLDATADIR, DATEFMT.format(now), QUICKSCANLOG.format(now)
            )
            SETLOGFN(mainlog)
            mainlognext_dt += dt.timedelta(1)

        # calculating scan pattern
        scanpat_a = quickscanpat_calc(quickscantype, **quickscanparams)

        # writing scan pattern to file
        now = dt.datetime.now()
        scanpatpar_dir = DIRCONFN(
            MPLDATADIR, DATEFMT.format(now)
        )
        if not osp.isdir(scanpatpar_dir):
            os.mkdir(scanpatpar_dir)
        scanpat_dir = DIRCONFN(
            scanpatpar_dir,
            QUICKSCANFILE.format(now, quickscantype)
        )
        print(f'writing quick scanpattern to: {scanpat_dir}')
        np.savetxt(scanpat_dir, scanpat_a,
                   fmt='%.2f', delimiter=', ', newline='\n\n')

        # beginning init and measurement
        sigmampl_boot(
            coldstart_boo=coldstart_boo, scanpat_dir=scanpat_dir,
            stdoutlog=mainlog
        )
        coldstart_boo = False

        # waiting between next measurement
        print(f'waittime: {QUICKSCANWAITTIME}min, next measurement time:'
              f'{dt.datetime.now() + dt.timedelta(minutes=QUICKSCANWAITTIME)}\n')
        time.sleep(QUICKSCANWAITTIME*60)

# testing
if __name__ == '__main__':
    main()


from inspect import getcomments
from pickle import FALSE, TRUE
import ee
import geemap
import datetime
import pandas as pd
import shapely.wkt
import multiprocessing
ee.Initialize()

visParamsTrue = {'bands': ['B4', 'B3', 'B2'], min: 0, max: 2000}
CLOUD_FILTER = 50
CLD_PRB_THRESH = 50
NIR_DRK_THRESH = 0.15
CLD_PRJ_DIST = 1
BUFFER = 5

def transformPolygon(polygon):
    Polygon = shapely.wkt.loads(polygon)
    input_polygon = shapely.wkt.dumps(Polygon)[10:-2]
    split_polygon = input_polygon.split(",")
    return_arr = []
    for sub_arr in split_polygon:
        split_subarr = sub_arr.split(" ")
        clean_split_subbarr = list(filter(None, split_subarr))
        return_arr.append(clean_split_subbarr)
    return_str = [[float(c) for c in row] for row in return_arr]
    return return_str

def get_s2_sr_cld_col(geom, start_date, end_date):
    s2_sr_col = (ee.ImageCollection('COPERNICUS/S2_SR')
                 .filterBounds(geom)
                 .filterDate(start_date, end_date)
                 .sort('CLOUD_COVERAGE_ASSESSMENT'))
                # .filter(ee.Filter.lte('CLOUDY_PIXEL_PERCENTAGE', CLOUD_FILTER)))
    s2_cloudless_col = (ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY')
                        .filterBounds(geom)
                        .filterDate(start_date, end_date))
    return ee.ImageCollection(ee.Join.saveFirst('s2cloudless').apply(
        primary=s2_sr_col,
        secondary=s2_cloudless_col,
        condition=ee.Filter.equals(
            leftField='system:index',
            rightField='system:index'
        )
    ))

def add_cloud_bands(img):
    cld_prb = ee.Image(img.get('s2cloudless')).select('probability')
    is_cloud = cld_prb.gt(CLD_PRB_THRESH).rename('clouds')
    return img.addBands(ee.Image([cld_prb, is_cloud]))

def add_shadow_bands(img):
    not_water = img.select('SCL').neq(6)
    SR_BAND_SCALE = 1e4
    dark_pixels = img.select('B8').lt(
        NIR_DRK_THRESH*SR_BAND_SCALE).multiply(not_water).rename('dark_pixels')
    shadow_azimuth = ee.Number(90).subtract(
        ee.Number(img.get('MEAN_SOLAR_AZIMUTH_ANGLE')))
    cld_proj = (img.select('clouds').directionalDistanceTransform(shadow_azimuth, CLD_PRJ_DIST*10)
                # .reproject({'crs': img.select(0).projection(), 'scale': 100})
                .select('distance')
                .mask()
                .rename('cloud_transform'))
    shadows = cld_proj.multiply(dark_pixels).rename('shadows')
    return img.addBands(ee.Image([dark_pixels, cld_proj, shadows]))

def add_cld_shdw_mask(img):
    img_cloud = add_cloud_bands(img)
    img_cloud_shadow = add_shadow_bands(img_cloud)
    is_cld_shdw = img_cloud_shadow.select('clouds').add(
        img_cloud_shadow.select('shadows')).gt(0)
    is_cld_shdw2 = (is_cld_shdw.focal_min(2).focal_max(BUFFER*2/20)
                    # .reproject({'crs': img.select([0]).projection(), 'scale': 20})
                    .rename('cloudmask'))
    return img_cloud_shadow.addBands(is_cld_shdw2)

def apply_cld_shdw_mask(img):
    not_cld_shdw = img.select('cloudmask').Not()
    return img.select('B.*').updateMask(not_cld_shdw)

def calculate_ndvi_ndwi(image_masked, geom):
    ndwi = image_masked.normalizedDifference(['B3', 'B8']).rename('NDWI')
    ndvi = image_masked.normalizedDifference(['B8', 'B4']).rename('NDVI')
    # print('NDWI')
    avg_ndwi_mosaic = ndwi.reduceRegion(
        ee.Reducer.mean(), geom, 10).get('NDWI').getInfo()
    # max = ndwi.reduceRegion(ee.Reducer.max(), geom, 10).get('NDWI').getInfo()
    # min = ndwi.reduceRegion(ee.Reducer.min(), geom, 10).get('NDWI').getInfo()
    # print('avg', avg_ndwi_mosaic, 'min', min, 'max', max)
    ndwiParams = {min: -1, max: 1, 'palette': ['8E3200', '#A64B2A', 'D7A86E',
                                               '#FFEBC1', '#E3CAA5', '#d7efa9', '#9ecae1', '#4292c6', '#2171b5', '#08519c']}
    # if (avg_ndwi_mosaic >= -1 and avg_ndwi_mosaic <= -0.3):
    #     print("NDWI result: Drought")
    # elif(avg_ndwi_mosaic >= -0.3 and avg_ndwi_mosaic <= 0.0):
    #     print("NDWI result: Moderately Drought")
    # elif(avg_ndwi_mosaic >= 0.0 and avg_ndwi_mosaic <= 0.2):
    #     print("NDWI result: Flood")
    # else:
    #     print("NDWI result: Water surface")
    flood_threshold_ndwi = 0
    flood_ndwi = ndwi.gte(flood_threshold_ndwi).selfMask()
    flood_pixel_area_ndwi = flood_ndwi.multiply(ee.Image.pixelArea())
    flood_area_ndwi = flood_pixel_area_ndwi.reduceRegion(**{
        'reducer': ee.Reducer.sum(),
        'geometry': geom,
        'scale': 10
    })
    # print(flood_area_ndwi.getInfo(), 'flood area ndwi')
    drought_threshold1_ndwi = 0
    drought_ndwi = ndwi.lt(drought_threshold1_ndwi).selfMask()
    drought_pixel_area_ndwi = drought_ndwi.multiply(ee.Image.pixelArea())
    drought_area_ndwi = drought_pixel_area_ndwi.reduceRegion(**{
        'reducer': ee.Reducer.sum(),
        'geometry': geom,
        'scale': 10
    })
    # print(drought_area_ndwi.getInfo(), 'drought area ndwi')
    # print('NDVI')
    avg_ndvi_mosaic = ndvi.reduceRegion(
        ee.Reducer.mean(), geom, 10).get('NDVI').getInfo()
    # max = ndvi.reduceRegion(ee.Reducer.max(), geom, 10).get('NDVI').getInfo()
    # min = ndvi.reduceRegion(ee.Reducer.min(), geom, 10).get('NDVI').getInfo()
    # print('avg', avg_ndvi_mosaic, 'min', min, 'max', max)
    ndviParams = {min: -1, max: 1, 'palette': ['#08306b', '#0850d1', '#2171b5',
                                               '#4292c6', '#9ecae1', '#b8d4e1', '#d7a86e', '#e9efc0', '#83bd75', '#4e944f']}
    # if (avg_ndvi_mosaic >= 0.1 and avg_ndvi_mosaic <= 0.4):
    #     print("NDVI result: Drought")
    # elif(avg_ndvi_mosaic > 0.4 and avg_ndvi_mosaic <= 1):
    #     print("NDVI result: Vegetation")
    # elif(avg_ndvi_mosaic >= -1 and avg_ndvi_mosaic < 0.1):
    #     print("NDVI result: Flood")

    flood_threshold_ndvi = 0.17
    flood_ndvi = ndvi.lt(flood_threshold_ndvi).selfMask()
    flood_pixel_area_ndvi = flood_ndvi.multiply(ee.Image.pixelArea())
    flood_area_ndvi = flood_pixel_area_ndvi.reduceRegion(**{
        'reducer': ee.Reducer.sum(),
        'geometry': geom,
        'scale': 10
    })
    # print(flood_area_ndvi.getInfo(), 'flood area ndvi')
    drought_threshold1_ndvi = 0.17
    drought_threshold2_ndvi = 0.45
    drought_ndvi = ndvi.gte(drought_threshold1_ndvi).And(
        ndvi.lte(drought_threshold2_ndvi)).selfMask()
    drought_pixel_area_ndvi = drought_ndvi.multiply(ee.Image.pixelArea())
    drought_area_ndvi = drought_pixel_area_ndvi.reduceRegion(**{
        'reducer': ee.Reducer.sum(),
        'geometry': geom,
        'scale': 10
    })
    # print(drought_area_ndvi.getInfo(), 'drought area ndvi')
    vegetation_threshold1_ndvi = 0.45
    vegetation_ndvi = ndvi.gt(vegetation_threshold1_ndvi).selfMask()
    vegetation_pixel_area_ndvi = vegetation_ndvi.multiply(ee.Image.pixelArea())
    vegetation_area_ndvi = vegetation_pixel_area_ndvi.reduceRegion(**{
        'reducer': ee.Reducer.sum(),
        'geometry': geom,
        'scale': 10
    })
    # print(vegetation_area_ndvi.getInfo(), 'vegetation area ndvi')
    return {'flood_area_ndwi': flood_area_ndwi.getInfo()['NDWI'], 'drought_area_ndwi': drought_area_ndwi.getInfo()['NDWI'], 'avg_ndwi_mosaic':avg_ndwi_mosaic, 'flood_area_ndvi': flood_area_ndvi.getInfo()['NDVI'], 'drought_area_ndvi': drought_area_ndvi.getInfo()['NDVI'], 'vegetation_area_ndvi': vegetation_area_ndvi.getInfo()['NDVI'],'avg_ndvi_mosaic':avg_ndvi_mosaic}

def compute_NDVI_NDWI(geom, input_date):
    try:
        rawPolygon = ee.Geometry.Polygon(transformPolygon(geom))
        START_DATE = datetime.datetime.strptime(input_date, "%Y-%m-%d")
        START_DATE = ee.Date(START_DATE)
        END_DATE = START_DATE.advance(5, 'days')
        s2_sr_cld_col_eval = get_s2_sr_cld_col(
            rawPolygon, START_DATE, END_DATE)
        img = s2_sr_cld_col_eval
        try:
            epochtime = img.aggregate_array('system:time_start').getInfo()[-1]
        except:
            epochtime = 0
        img = s2_sr_cld_col_eval.map(add_cld_shdw_mask)
        img = img.first()
        image_masked = apply_cld_shdw_mask(img)

        area_after_masking = image_masked.reduceRegion(
            ee.Reducer.sum(), rawPolygon, 10).get('B1').getInfo()
        # print(area_after_masking, 'Area after masking within 5 days')

        area_before_masking = img.reduceRegion(
            ee.Reducer.sum(), rawPolygon, 10).get('B1').getInfo()
        # print(area_before_masking, 'Area before masking within 5 days')
        if(area_after_masking == area_before_masking):
            calc_ndvi_ndwi = calculate_ndvi_ndwi(image_masked, rawPolygon)
            return calc_ndvi_ndwi, epochtime
        else:
            return 0, 0
    except:
        return 'error', 0

def compute(dataframe):
    for index, row in dataframe.iterrows():
        print("Working On index: ", index)
        result, epochtime = compute_NDVI_NDWI(
            row['geom'], row['warranty_dmgdate'])
        if(result != 0 and result != 'error'):
            dataframe.at[index, 'flood_area_ndwi'] = str(
                result['flood_area_ndwi'])
            dataframe.at[index, 'drought_area_ndwi'] = str(
                result['drought_area_ndwi'])
            dataframe.at[index, 'avg_ndwi_mosaic'] = str(
                result['avg_ndwi_mosaic'])
            dataframe.at[index, 'flood_area_ndvi'] = str(
                result['flood_area_ndvi'])
            dataframe.at[index, 'drought_area_ndvi'] = str(
                result['drought_area_ndvi'])
            dataframe.at[index, 'vegetation_area_ndvi'] = str(
                result['vegetation_area_ndvi'])
            dataframe.at[index, 'avg_ndvi_mosaic'] = str(
                result['avg_ndvi_mosaic'])
        else:
            dataframe.at[index, 'flood_area_ndwi'] = "-"
            dataframe.at[index, 'drought_area_ndwi'] = "-"
            dataframe.at[index, 'avg_ndwi_mosaic'] = "-"
            dataframe.at[index, 'flood_area_ndvi'] = "-"
            dataframe.at[index, 'drought_area_ndvi'] = "-"
            dataframe.at[index, 'vegetation_area_ndvi'] = "-"
            dataframe.at[index, 'avg_ndvi_mosaic'] = "-"
        if(epochtime != 0 and result != 'error'):
            normalTime = datetime.datetime.fromtimestamp(
                epochtime/1000).strftime("%Y-%m-%d")
            dataframe.at[index, 'sat_time'] = normalTime
        elif(result == 'error'):
            dataframe.at[index, 'sat_time'] = "Calculation Error"
        else:
            dataframe.at[index, 'sat_time'] = "Cloudy"
    return dataframe

# geom = ee.Geometry.Polygon([[102.5633930333, 15.3911126506452], [102.5633412905, 15.3911006621863], [102.5632589747, 15.3910814856279], [102.5630058721, 15.3910283104296], [
#     102.5628613992, 15.3909717388604], [102.5629181022, 15.3884164751931], [102.5631823462, 15.3885207260593], [102.5635976384, 15.3886884700794], [102.5633930333, 15.3911126506452]])
# START_DATE = ee.Date('2021-5-5')

if __name__ == "__main__":
    df = pd.read_csv('./raw_data_800.csv', header=0)
    num_processes = multiprocessing.cpu_count()
    chunk_size = df.shape[0] if(
        int(df.shape[0]/num_processes) == 0) else int(df.shape[0]/num_processes)
    chunks = [df.iloc[df.index[i:i + chunk_size]]
              for i in range(0, df.shape[0], chunk_size)]
    pool = multiprocessing.Pool(processes=num_processes)
    result = pool.map(compute, chunks)
    df2 = pd.DataFrame()
    for i in range(len(result)):
        df2 = pd.concat([df2, result[i]], axis=0)
    df2.to_csv(r'C:\Users\geoma\Downloads\ee\ee\testndvindwi.csv',
               index=False, header=True)

NDVI and NDWI on Sentinel-2A images/NDVINDWI.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Модуль класса управления ресурсом проекта.

Описание ресурсного файла проекта информационной системы:

<имя файла> :=   *.pro
<описание проекта информационной системы> =
[
{<описание проекта текущей информационной системы>},
{<описание проекта импортируемой информационной системы 1> }, Е ,
{ <описание проекта импортируемой информационной системы N> }
] //список

<описание проекта текущей информационной системы> =
{
 'имя корневой папки проекта'     : <значение папки> ,
 '__py__' : <имя корневого пакета модулей питона, создаваемых в рамках текущего проекта>
'__ftl__' : <значение папки шаблонов форм>
'__mth__' : <значение папки методов>
'__env__' : <словарь дополнительных глобальных атрибутов проекта>
} // словарь

<значение папки> =
[
{'имя папки':<значение папки> / <тип ресурса> значения: 'tab' / 'var' / 'win' / 'mnu' / 'svb' / 'frm ' / 'src'}, Е {}
] //список словарей

<значение папки шаблонов форм> =
[
{'имя папки' : <значение папки> / <тип ресурса> значения: 'ftl'}, Е {}
] //список словарей

<значение папки методов> =
[
{'имя папки' : <значение папки> / <тип ресурса> значения: 'mth'}, Е {}
] //список словарей

<описание проекта импортируемой информационной системы> =
{  'имя корневой папки проекта'     : <значение папки> }                                   // словарь

<значение папки> =
{
'type':  <тип импортируемой информационной системы>
'name':  <имя импортируемой информационной системы>
 '__py__':  <имя корневого пакета модулей питона, созданных в импортируемой информационной системе>
'link':  <тип связи импортируемой информационной системы: определим тип связи  импортируемой системы как ССЫЛКА, если информационные ресурсы импортируемой системы расположены НЕ в директории информационных ресурсов текущей системы; определим тип связи  импортируемой системы как КОПИЯ, если информационные ресурсы импортируемой системы расположены в директории информационных ресурсов текущей системы; 1 - ССЫЛКА, 0 - КОПИЯ>
'path':  <путь к файлу *.pro, содержащему описание структуры импортируемой информационной системы; если link=1, то указан полный путь, он дополняется значением ключа __py__ и используется при сборке, если link=0, то при сборке значение этого ключа не используется, а используется ключ __py__ для получения пути для сборки ресурсов>
}

Пример текущей информационной системы:
{'__py__':'icmodule','бухучет':
    [ { 'базы данных':
           [{'первичные документы':
                                  [{'приходные':[{'ордер1':'tab'},{'фактура1':'tab'},{'счет-фактура1':'tab'}]},
                                   {'расходные':[{'ордер2':'tab'},{'фактура2':'tab'},{'счет-фактура2':'tab'}]}
                                  ]
             },
             {'прочие':[{}, Е {}]}
           ]
        },
        {'переменные':[{},Е{}]}
    ]
}

<словарь дополнительных глобальных атрибутов проекта> =
{
'имя переменной' : <значение переменной хранимого типа>
}

Переменные и значения попадают в окружение проекта автоматически.
"""

import re
import os.path
import wx

from ic.dlg import dlgfunc
from ic.log import log

from ic.interfaces import resManager
from ic.utils import util
from ic.utils import resfunc
import ic

__version__ = (0, 1, 1, 1)

_ = wx.GetTranslation

# Константы

DEFAULT_PRJ_NAME = 'new_prj'

# Типы ресурсов ('tab','var','win','mnu','svb','frm')

class icPrjRes(resManager.icResourceManagerInterface):
    """
    Класс управления ресурсом проекта.
    """
    def __init__(self):
        """
        Конструктор.
        """
        resManager.icResourceManagerInterface.__init__(self)

        # Файл проекта
        self.prj_file_name = None

        # Структура проекта
        self._prj = []

    def setResFileName(self, res_filename=None):
        self.prj_file_name = res_filename

    def newPrj(self, prj_name, py_pack=None, prj_template=None):
        """
        Создание нового проекта по умолчанию.

        :param prj_name: Имя проекта.
        :param py_pack: Макет модулей питона.
        :param prj_template: Шаблон для создания проекта.
        """
        # Файл проекта
        prj_res = {}
        if prj_template is None:
            prj_template = self._newPrjTemplate()
        prj_res[prj_name] = prj_template
        prj_res['__py__'] = py_pack
        prj_res['__env__'] = {'AutoLogin': 'admin',
                              'AutoPassword': '',
                              'db_auth': '0',
                              'db_engine': 'PostgreSQLDB',
                              'convert_unicode': 'UTF-8',
                              'dbname': None,
                              'host': '127.0.0.1',
                              'user': 'admin',
                              'sys_table_name': 'resource_tab',
                              'password': '',
                              'port': '5432',
                              'dbstore': '.acc',
                              }
        # Добавить в основную структуру
        self._prj = [prj_res]
        return prj_res

    def _newPrjTemplate(self):
        """
        Шаблон нового проекта по умолчанию.
        """
        return [{'DB': []},
                {'Tables': []},
                {'Menu': []},
                {'System': []},
                {'Forms': []},
                {'Metadata': []},
                ]

    def openPrj(self, prj_filename):
        """
        Открыть файл проекта.
        """
        path, name = os.path.split(prj_filename)
        ic.set_ini_file(path)
        self.prj_file_name = prj_filename
        if os.path.isfile(self.prj_file_name) and os.path.exists(self.prj_file_name):
            prj = util.readAndEvalFile(self.prj_file_name, bRefresh=True)
            self._prj = self._prepareDataPrj(prj)

    # Один метод под двумя именами
    load = openPrj

    def savePrj(self):
        """
        Сохранить проект.
        """
        if not self.prj_file_name:
            self.prj_file_name = dlgfunc.getFileDlg(None, u'Создание проекта',
                                                  u'Project file (*.pro)|*.pro')
        if self.prj_file_name:
            prj_path = os.path.dirname(self.prj_file_name.strip())
            if (not os.path.isdir(prj_path)) or \
               (not self._prj[0]['__py__']):
                # Если директории проекта не существует, то
                # сохранить ее в __py__
                self._prj[0]['__py__'] = prj_path
            return self._save_prj(self.prj_file_name.strip(), self._prepareDataPrj(self._prj))
        return False

    # Один метод под двумя именами
    save = savePrj

    def _prepareDataPrj(self, project):
        """
        Подготовка данных проекта для записи/чтения.
        """
        if isinstance(project, dict):
            project = dict([(key.strip(), self._prepareDataPrj(value)) for key, value in project.items()])
        elif isinstance(project, list):
            project = [self._prepareDataPrj(value) for value in project]
        elif isinstance(project, tuple):
            project = tuple([self._prepareDataPrj(value) for value in project])
        elif isinstance(project, str):
            project = project.strip()
        return project

    def _save_prj(self, prj_filename, project=None):
        """
        Непосредственное сохранение проекта.

        :param prj_filename: Имя файла проекта.
        :param project: Структура проекта.
        :return: Возвращает результат выполнения True/False.
        """
        if project is None:
            project = self._prepareDataPrj(self._prj)
        ok = resfunc.saveResourceText(prj_filename.strip(), project)
        # Кроме того, что сохраняем проект, еще делаем его пакетом
        resfunc.createInitFile(os.path.dirname(prj_filename.strip()))
        return ok

    def getPrjRes(self):
        return self._prj

    def addFolder(self, new_folder_name, dst_folder_name, cur_folder=None):
        """
        Добавить папку.

        :param new_folder_name: Имя новой папки.
        :param dst_folder_name: Имя папки или проекта,
            в которую будет добавляться новая папка.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: Результат добавления True|False.
        """
        if cur_folder is None:
            cur_folder = self.getPrjRoot()
        # Если имя папки==имя проекта, то просто добавить
        # папку в проект
        if dst_folder_name == self.getPrjRootName():
            self.getPrjRoot().append({new_folder_name: []})
            return True

        ok = False
        for folder in cur_folder:
            folder_name = list(folder.keys())[0]
            # Проверять только папки
            if isinstance(folder[folder_name], list):
                if folder_name == dst_folder_name:
                    folder[folder_name].append({new_folder_name: []})
                    ok = True
                    return ok
                else:
                    add = self.addFolder(new_folder_name, dst_folder_name, folder[folder_name])
                    if add:
                        return add
        return ok

    def addRes(self, new_res_name, res_type, dst_folder_name, cur_folder=None):
        """
        Добавить ресурс.

        :param new_res_name: Имя нового ресурса.
        :param res_type: Тип ресурса ('tab','var','win','mnu','svb','frm').
        :param dst_folder_name: Имя папки или проекта,
            в которую будет добавляться новая папка.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: Результат добавления True|False.
        """
        if cur_folder is None:
            cur_folder = self.getPrjRoot()
        ok = False
        for folder in cur_folder:
            folder_name = list(folder.keys())[0]
            # Проверять только папки
            if isinstance(folder[folder_name], list):
                if folder_name == dst_folder_name:
                    folder[folder_name].append({new_res_name: res_type})
                    return True
                else:
                    add = self.addRes(new_res_name, res_type, dst_folder_name, folder[folder_name])
                    if add:
                        return add
        return ok

    def delFolder(self, del_folder_name, cur_folder=None):
        """
        Удалить папку с именем.

        :param del_folder_name: Имя удаляемой папки.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: True-успешное удаление. False-не удален.
        """
        if cur_folder is None:
            cur_folder = self.getPrjRoot()
        del_ok = False
        for i_folder in range(len(cur_folder)):
            folder = cur_folder[i_folder]
            folder_name = list(folder.keys())[0]
            # Проверять только папки
            if isinstance(folder[folder_name], list):
                if folder_name == del_folder_name:
                    del cur_folder[i_folder]
                    return True
                else:
                    delete_ok = self.delFolder(del_folder_name, folder[folder_name])
                    if delete_ok:
                        return delete_ok
        return del_ok

    def getFolder(self, folder_name, cur_folder=None):
        """
        Взять папку с именем.

        :param folder_name: Имя папки.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: Список папки в ресурсе проекта.
        """
        if cur_folder is None:
            cur_folder = self.getPrjRoot()
        for i_folder in range(len(cur_folder)):
            folder = cur_folder[i_folder]
            cur_folder_name = list(folder.keys())[0]
            # Проверять только папки
            if isinstance(folder[cur_folder_name], list):
                if cur_folder_name == folder_name:
                    return cur_folder[i_folder]
                else:
                    find_fld = self.getFolder(folder_name, folder[cur_folder_name])
                    if find_fld is not None:
                        return find_fld
        return None

    def getFolderBody(self, folder_name, cur_folder=None):
        """
        Взять содержимое папки с именем.

        :param folder_name: Имя папки.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: Список папки в ресурсе проекта.
        """
        if cur_folder is None:
            cur_folder = self.getPrjRoot()
        for i_folder in range(len(cur_folder)):
            folder = cur_folder[i_folder]
            cur_folder_name = list(folder.keys())[0]
            # Проверять только папки
            if isinstance(folder[cur_folder_name], list):
                if cur_folder_name == folder_name:
                    return cur_folder[i_folder][folder_name]
                else:
                    find_fld = self.getFolderBody(folder_name, folder[cur_folder_name])
                    if find_fld is not None:
                        return find_fld
        return None

    def delRes(self, res_name, res_type=None, cur_folder=None):
        """
        Удалить ресурс по имени и типу.

        :param res_name: Имя ресурса.
        :param res_type: Тип ресурса, если None,
            то проверка на тип не производится.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: True-успешное удаление. False-не удален.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()
        del_ok = False
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            cur_res_name = list(res.keys())[0]
            # Проверять только папки
            if isinstance(res[cur_res_name], list):
                find_res = self.delRes(res_name, res_type, res[cur_res_name])
                if find_res:
                    return find_res
            else:
                if cur_res_name == res_name and res[cur_res_name] == res_type:
                    del cur_folder[i_res]
                    return True
                elif cur_res_name == res_name and not res_type:
                    del cur_folder[i_res]
                    return True
        return del_ok

    def getResRef(self, res_name, res_type=None, cur_folder=None):
        """
        Получить кортеж указания ресурса по имени и типу.

        :param res_name: Имя ресурса.
        :param res_type: Тип ресурса, если None,
            то проверка на тип не производится.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: Кортеж (Имя ресурса, тип ресурса) или None в случае ошибки.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()
        ret_res = None
        for res in cur_folder:
            cur_res_name = list(res.keys())[0]
            # Проверять только папки
            if isinstance(res[cur_res_name], list):
                find_res = self.getResRef(res_name, res_type, res[cur_res_name])
                if find_res:
                    return find_res
            else:
                if cur_res_name == res_name and res[cur_res_name] == res_type:
                    return cur_res_name, res[cur_res_name]
                elif cur_res_name == res_name and res_type is None:
                    return cur_res_name, res[cur_res_name]

        if ret_res is None:
            log.warning(u'Не найден ресурс <%s.%s> %s' % (res_name, res_type, str(cur_folder)))
        return ret_res

    def getImportSystems(self):
        """
        Список импортируемых подсистем.
        """
        return self._prj[1:]

    def getPyPackage(self):
        """
        Пакет модулей питона текущего проекта.
        """
        return self._prj[0]['__py__']

    def getPrjRootName(self):
        """
        Имя корневой папки проекта.
        """
        root = self._prj[0]
        names = [key for key in root.keys() if not key.startswith('_')]
        return names[0]

    def setPrjRootName(self, new_prj_root_name):
        """
        Имя корневой папки проекта.
        """
        new_prj_root_name = new_prj_root_name
        root = self._prj[0]
        names = [key for key in root.keys() if not key.startswith('_')]
        old_prj_root_name = names[0]
        prj_root = root[old_prj_root_name]
        del self._prj[0][old_prj_root_name]
        self._prj[0][new_prj_root_name] = prj_root

    def getPrjRoot(self):
        """
        Корневая папка проекта.
        """
        if not self._prj:
            self.newPrj(DEFAULT_PRJ_NAME)
        return self._prj[0][self.getPrjRootName()]

    def getPyPackageImportSys(self, import_sys):
        """
        Пакет модулей питона импортироуемой системы.
        """
        return None

    def addPackage(self, package_path, new_package_name=None):
        """
        Добавить пакет модулей в дерево проектов.

        :param package_path: Путь пакета.
        :param new_package_name: Имя нового пакета.
        :return: Результат добавления True|False.
        """
        cur_package_path = package_path
        if new_package_name:
            cur_package_path = os.path.join(cur_package_path, new_package_name)
        return resfunc.createInitFile(cur_package_path)

    def addModule(self, module_name, package_path):
        """
        Добавить модуль в дерево проектов.

        :param module_name: Имя модуля.
        :param package_path: Путь пакета.
        """
        pass

    def renameRes(self, old_name, new_name, cur_folder=None):
        """
        Переименовать ресурс/папку.

        :param old_name: Старое имя.
        :param new_name: Новое имя.
        :param cur_folder: Текущая папка,  если None,
            то берется папка проекта.
        :return: Возвращает результат выполнения переименования.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()
        rename_res = False
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            res_name = list(res.keys())[0]
            if res_name == old_name:
                cur_folder[i_res] = {new_name: res[res_name]}
                return True
            elif isinstance(res[res_name], list):
                # Если это папка, то обработать все подпапки
                rename_res = self.renameRes(old_name, new_name, res[res_name])
                if rename_res:
                    return rename_res
        return rename_res

    def newSubSys(self, subsys_name, subsys_prj_filename, py_pack):
        """
        Создать новую импортируемую подсистему.

        :param subsys_name: Имя импортируемой подсистемы.
        :param subsys_prj_filename: Файл импортируемой подсистемы.
        :param py_pack: Пакет импортируемой подсистмы.
        """
        imp_sys = {'name': subsys_name,
                   'type': 'icSubSys',
                   '__py__': py_pack,
                   'link': 0,
                   'path': subsys_prj_filename}
        # Добавить в проект
        self._prj.append(imp_sys)
        return imp_sys

    def isResORFolderByName(self, name, cur_folder=None):
        """
        Проверка, есть ли ресурс или папка с таким именем в проекте.

        :param name: Имя.
        :return: Возвращает результат операции True/False.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()
        find = False
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            res_name = list(res.keys())[0]
            if res_name == name:
                return True
            elif isinstance(res[res_name], list):
                # Если это папка, то обработать все подпапки
                find_folder = self.isResORFolderByName(name, res[res_name])
                if find_folder:
                    return find_folder
        return find

    def isResByNameANDType(self, name, res_type=None, cur_folder=None):
        """
        Проверка, есть ли ресурс с таким именем и типом в проекте.

        :param name: Имя.
        :param res_type: Строковое определение типа ресурса 'tab','frm',...
            Если тип None, то проверка по типу не делается.
        :return: Возвращает результат операции True/False.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()
        find = False
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            cur_res_name = list(res.keys())[0]
            cur_res_type = res[cur_res_name]
            if isinstance(res[cur_res_name], list):
                # Если это папка, то обработать все подпапки
                find_folder = self.isResByNameANDType(name, res_type, res[cur_res_name])
                if find_folder:
                    return find_folder
            elif cur_res_name == name and cur_res_type == res_type:
                return True
            elif cur_res_name == name and res_type is None:
                return True
        return find

    def getResNameListByType(self, res_type, cur_folder=None):
        """
        Список имен ресурсов в проекте по их типу.

        :param res_type: Строковое определение типа ресурса 'tab','frm',...
        :return: Возвращает список имен ресурсов заданного типа.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()

        find_list = []
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            cur_res_name = list(res.keys())[0]
            cur_res_type = res[cur_res_name]
            if isinstance(res[cur_res_name], list):
                # Если это папка, то обработать все подпапки
                find_folder = self.getResNameListByType(res_type, res[cur_res_name])
                if find_folder:
                    find_list += find_folder
            elif cur_res_type == res_type:
                find_list.append(cur_res_name)
        return find_list

    def getResNameListByTypes(self, res_types, cur_folder=None):
        """
        Список имен ресурсов в проекте по их типу.

        :param res_types: Кортеж строковых определение типа ресурса 'tab','frm',...
        :return: Возвращает список имен ресурсов заданных типов.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()

        find_list = []
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            cur_res_name = list(res.keys())[0]
            cur_res_type = res[cur_res_name]
            if isinstance(res[cur_res_name], list):
                # Если это папка, то обработать все подпапки
                find_folder = self.getResNameListByTypes(res_types, res[cur_res_name])
                if find_folder:
                    find_list += find_folder
            elif cur_res_type in res_types:
                find_list.append(cur_res_name)
        return find_list

    def getResNamesByTypes(self, *res_types):
        """
        Список имен ресурсов в проекте по их типу.

        :param res_types: Кортеж строковых определение типа ресурса 'tab','frm',...
        :return: Возвращает список имен ресурсов заданных типов.
        """
        return self.getResNameListByTypes(*res_types)

    def getResFileNamesByResPattern(self, res_pattern, cur_folder=None):
        """
        Список имен файлов ресурсов по шаблону ресурса.

        :param res_pattern: Кортеж строковых определений шаблонов ресурса '.*\.tab',...
        :return: Список имен файлов ресурсов по шаблону ресурса.
        """
        if cur_folder is None:
            # Отсечь импортитруемые подсистемы
            cur_folder = self.getPrjRoot()

        find_list = []
        for i_res in range(len(cur_folder)):
            res = cur_folder[i_res]
            res_name = list(res.keys())[0]
            res_type = res[res_name]
            if isinstance(res[res_name], list):
                # Если это папка, то обработать все подпапки
                find_folder = self.getResFileNamesByResPattern(res_pattern, res[res_name])
                if find_folder:
                    find_list += find_folder
            else:
                res_file_name = u''
                try:
                    res_file_name = res_name+'.'+res_type
                    if [pattern for pattern in res_pattern if re.match(pattern, res_file_name)]:
                        # Если имя файла подходит под какойлибо шаблон,
                        # то добавитьв выходной список
                        find_list.append(res_file_name)
                except:
                    log.fatal(u'Ошибка поиска файла <%s> по шаблону <%s>' % (res_file_name, res_pattern))
        return find_list

    def getObjectsByResPattern(self, *res_pattern):
        """
        Получить список кортежей (тип объекта,имя объекта) по шаблону ресурса.

        :param res_pattern: Кортеж строковых определений шаблонов ресурса '.*\.tab',...
        :return: Список кортежей (тип объекта,имя объекта) по шаблону ресурса.
        """
        obj_list = []
        res_file_names = self.getResFileNamesByResPattern(res_pattern)
        prj_dir = os.path.dirname(self.prj_file_name)
        for res_file_name in res_file_names:
            full_res_file_name = os.path.join(prj_dir, res_file_name)
            spc = util.readAndEvalFile(full_res_file_name, bRefresh=True)
            obj = (spc['type'], spc['name'], spc['description'])
            obj_list.append(obj)
        return obj_list

    def getObjNamesByResPattern(self, *res_pattern):
        """
        Имена объектов по шаблону ресурсов.
        """
        return [obj[1] for obj in self.getObjectsByResPattern(*res_pattern)]

    def getObjectsInResByType(self, res_filename, obj_type, cur_obj=None):
        """
        Поиск объектов в ресурсе по типу.

        :param res_filename: Имя файла ресурса.
        :param OBjType_: Тип объекта, например 'icButton'.
        :return: Список кортежей формата:
            [('тип объекта','имя объекта','описание'),...]
        """
        if cur_obj is None:
            spc = util.readAndEvalFile(res_filename, bRefresh=True)
            cur_obj = spc[list(spc.keys())[0]]

        find_list = []
        try:
            if cur_obj is None:
                # Ресурс пустой
                return find_list
            if cur_obj['type'] == obj_type:
                find_list.append((cur_obj['type'], cur_obj['name'], cur_obj['description']))
            if 'child' in cur_obj and cur_obj['child']:
                for child in cur_obj['child']:
                    find_grp = self.getObjectsInResByType(res_filename, obj_type, child)
                    find_list += find_grp
        except:
            log.fatal(u'Search error in function getObjectsInResByType: %s, %s, %s' % (res_filename, obj_type, cur_obj))
        return find_list

    def getObjectsInResByTypes(self, res_filename, obj_types, cur_obj=None):
        """
        Поиск объектов в ресурсе по типу.

        :param res_filename: Имя файла ресурса.
        :param OBjTypes_: Кортеж типов объектов, например ('icButton',).
        :return: Список кортежей формата:
            [('тип объекта','имя объекта','описание'),...]
        """
        if cur_obj is None:
            spc = util.readAndEvalFile(res_filename, bRefresh=True)
            cur_obj = spc[list(spc.keys())[0]]

        find_list = []
        try:
            if cur_obj is None:
                # Ресурс пустой
                return find_list
            if cur_obj['type'] in obj_types:
                find_list.append((cur_obj['type'], cur_obj['name'], cur_obj['description']))
            if 'child' in cur_obj and cur_obj['child']:
                for child in cur_obj['child']:
                    find_grp = self.getObjectsInResByTypes(res_filename, obj_types, child)
                    find_list += find_grp
        except:
            log.fatal(u'Search error in function getObjectsInResByTypes: (%s, %s, %s)' % (res_filename,
                                                                                obj_types, cur_obj))
        return find_list

    def getObjByResPatternANDType(self, res_pattern, obj_type):
        """
        Получить список кортежей (тип объекта,имя объекта) по шаблону ресурса и типу объекта.

        :param res_pattern: Кортеж строковых определений шаблонов ресурса '.*\.tab',...
        :param obj_type: Тип объекта. Например 'icButton'.
        :return: Список кортежей (тип объекта,имя объекта) по шаблону ресурса и типу объекта.
        """
        obj_list = []
        res_file_names = self.getResFileNamesByResPattern(res_pattern)
        prj_dir = os.path.dirname(self.prj_file_name)
        for res_file_name in res_file_names:
            full_res_file_name = os.path.join(prj_dir, res_file_name)
            obj_lst = self.getObjectsInResByType(full_res_file_name, obj_type)
            obj_list += obj_lst
        return obj_list

    def getObjByResPatternANDTypes(self, res_pattern, obj_types):
        """
        Получить список кортежей (тип объекта,имя объекта) по шаблону ресурса и типу объекта.

        :param res_pattern: Кортеж строковых определений шаблонов ресурса '.*\.tab',...
        :param obj_types: Кортеж типов объектов, например ('icButton',).
        :return: Список кортежей (тип объекта,имя объекта) по шаблону ресурса и типу объекта.
        """
        obj_list = []
        res_file_names = self.getResFileNamesByResPattern(res_pattern)
        prj_dir = os.path.dirname(self.prj_file_name)
        for res_file_name in res_file_names:
            full_res_file_name = os.path.join(prj_dir, res_file_name)
            obj_lst = self.getObjectsInResByTypes(full_res_file_name, obj_types)
            obj_list += obj_lst
        return obj_list

    def isModByName(self, module_name):
        """
        Проверить, есть ли модуль с таким именем.

        :param module_name: Имя модуля.
        :return: Возвращает результат операции True/False.
        """
        return False

    def isImpSubSys(self, name):
        """
        Проверить, является ли name именем импортируемой подсистемы.

        :param name: Имя некого ресурса.
        :return: Возвращает True/False.
        """
        return bool([sub_sys for sub_sys in self.getImportSystems() if sub_sys['name'] == name])

    def getImpSubSysIdx(self, name):
        """
        Возвращает индекс импортируемой подсистемы по имени.

        :param name: Имя подсистемы.
        :return: Индекс в структуре ресурсного файла импортируемой подсистемы
            с именем name или -1, если такая подсистема в описании не найдена.
        """
        find_idx = -1
        try:
            name_list = ['']+[sub_sys['name'] for sub_sys in self.getImportSystems()]
            find_idx = name_list.index(name)
        except ValueError:
            log.fatal()
            find_idx = -1

        return find_idx

    def delImpSubSys(self, name, bAutoSave=True):
        """
        Удалить из файла *.pro импортируемую подсистему по имени.

        :param name: Имя подсистемы.
        :param bAutoSave: Автоматически сохранить файл *.pro после удаления.
        :return: Возвращает True/False.
        """
        try:
            sub_sys_idx = self.getImpSubSysIdx(name)
            if sub_sys_idx > 0:
                del self._prj[sub_sys_idx]
            if bAutoSave:
                self.save()
            return True
        except:
            log.fatal()
            return False

    def getPrjEnv(self):
        """
        Получить словарь дополнительных атрибутов проекта.
        """
        if '__env__' in self._prj[0]:
            return self._prj[0]['__env__']
        return {}

    def setPrjEnv(self, env):
        """
        Установить словарь дополнительных атрибутов проекта.
        """
        self._prj[0]['__env__'] = env

def test():
    """
    Функция тестирования.
    """
    prj_res = icPrjRes()
    prj_res.newPrj('root', None, None, None)
    print(prj_res.getPrjRes())
    prj_res.addRes('tab1', 'tab', u'Формы')
    print(prj_res.getPrjRes())

if __name__ == '__main__':
    test()