import time
import displayio
import adafruit_imageload
from general import transparency

class PacmanHimself:
    '''Pacman character class with sprite sheet

       Tiles: 13 x 13
       0 = left, 1 = up, 2 = right, 3 = down, 4 = closed
    '''

    pacman_direction_left: int = 0
    pacman_direction_up: int = 1
    pacman_direction_right: int = 2
    pacman_direction_down: int = 3
    pacman_direction_closed: int = 4
    pacman_direction: int = pacman_direction_down # Initial direction
    pacman_x_position: int = 128//2-7 # Initial positions
    pacman_y_position: int = 7
    pacman_speed: int = 1
    update_counter: int = 0
    sprite_size: int = 13
    invinsible: bool = False
    invinsible_counter: int = 0
    alive: bool = True

    def __init__(self, sprite_sheet: str, chosen_map, screen_width: int, screen_height: int):
        bitmap, palette = adafruit_imageload.load(
            sprite_sheet,
            bitmap=displayio.Bitmap,
            palette=displayio.Palette
        )

        self.sprite = displayio.TileGrid(
            bitmap,
            pixel_shader=palette,
            width = 1,
            height = 1,
            tile_width = self.sprite_size,
            tile_height = self.sprite_size,
        )

        self.WIDTH = screen_width
        self.HEIGHT = screen_height

        self.chosen_map = chosen_map

        self.sprite.x = self.pacman_x_position
        self.sprite.y = self.pacman_y_position
        self.sprite[0] = self.pacman_direction

        transparency.make_shader_transparent(self.sprite.pixel_shader, palette)

    @property
    def sprite_front(self):
        if self.pacman_direction == self.pacman_direction_left:
            return list(zip([self.pacman_x_position - 2] * self.sprite_size, range(self.pacman_y_position, self.pacman_y_position + self.sprite_size)))
        elif self.pacman_direction == self.pacman_direction_right:
            return list(zip([self.pacman_x_position + self.sprite_size + 1] * self.sprite_size, range(self.pacman_y_position, self.pacman_y_position + self.sprite_size)))
        elif self.pacman_direction == self.pacman_direction_up:
            return list(zip(range(self.pacman_x_position, self.pacman_x_position + self.sprite_size), [self.pacman_y_position - 2] * self.sprite_size))
        elif self.pacman_direction == self.pacman_direction_down:
            return list(zip(range(self.pacman_x_position, self.pacman_x_position + self.sprite_size), [self.pacman_y_position + self.sprite_size + 1] * self.sprite_size))

    @property
    def sprite_center(self):
        point1 = (self.pacman_x_position + 5, self.pacman_y_position + 5)
        point2 = (self.pacman_x_position + 8, self.pacman_y_position + 5)
        point3 = (self.pacman_x_position + 5, self.pacman_y_position + 8)
        point4 = (self.pacman_x_position + 8, self.pacman_y_position + 8)
        return (point1, point2, point3, point4)

    def move(self, button_value: int):
        self._get_direction(button_value)
        self._limit_movement()
        self._update_position()
        self._set_position()
        self._invinsible()
        if self.update_counter == 2:
            self._update_sprite()
            self.update_counter = 0
        self.update_counter += 1
        self.pacman_speed = 1

    def _invinsible(self):
        if self.invinsible:
            self.invinsible_counter += 1
            if self.invinsible_counter == 200:
                self.invinsible = False

    def _get_direction(self, button_value: int):
        if button_value < 4:
            self.pacman_direction = button_value

    def _update_position(self):
        if self.pacman_direction == self.pacman_direction_left:
            self.pacman_x_position -= self.pacman_speed
        elif self.pacman_direction == self.pacman_direction_right:
            self.pacman_x_position += self.pacman_speed
        elif self.pacman_direction == self.pacman_direction_up:
            self.pacman_y_position -= self.pacman_speed
        elif self.pacman_direction == self.pacman_direction_down:
            self.pacman_y_position += self.pacman_speed

    def _limit_movement(self):
        for front in self.sprite_front:
            if front[0] < 0 or front[0] > self.WIDTH - 1:
                self.pacman_speed = -self.WIDTH + self.sprite_size + 1
            elif front[1] < 0 or front[1] > self.HEIGHT - 1:
                self.pacman_speed = -self.HEIGHT + self.sprite_size + 1
            elif self.chosen_map.bitmap[front[0], front[1]] == 1:
                self.pacman_speed = 0

    def _set_position(self):
        self.sprite.x = self.pacman_x_position
        self.sprite.y = self.pacman_y_position

    def _update_sprite(self):
        if self.sprite[0] != self.pacman_direction_closed:
            self.sprite[0] = self.pacman_direction_closed
        else:
            self.sprite[0] = self.pacman_direction

    def check_pacman_and_ghost_collision(self, ghost):
        for pacman_point in self.sprite_center:
            for ghost_point in ghost.sprite_center:
                if pacman_point == ghost_point:
                    return True

    def dead(self):
        for x in range(5,14):
            self.sprite[0] = x
            time.sleep(0.1)

        self.alive = False


from django.urls import path
from AdminDash import views

urlpatterns = [
    path('adminHome/', views.adminHome,name='admin_home'),
    path('adminLoginProcess/', views.adminLoginProcess, name='admin_login_process'),
    path('adminLogoutProcess/', views.adminLogoutProcess, name='admin_logout_process'),

]


# Module containing the code used to collect the results of the model evaluation.
#
# Author: Fernando García Gutiérrez
# Email: fgarcia@fundacioace.org
#
# STATUS: completed and functional
#
import warnings

import numpy as np
import pandas as pd
from copy import deepcopy

from ..core.base import Dataset
from ..core.evaluation import (
    getScores,
    Metric
)
from ..util.validation import (
    checkMultiInputTypes,
    checkInputType
)
from ..util.io import pprint

class CVReport(object):
    """ Object returned by the subroutines defined in :py:mod:`gojo.core.loops` functions with the results of the
    cross validation. """

    # Flags used to identify the columns of the generated dataframes where the predictions and true
    # labels are located
    _PRED_LABELS_FLAG = 'pred_labels'
    _TRUE_LABELS_FLAG = 'true_labels'
    _N_FOLD_FLAG = 'n_fold'
    _INDICES_FLAG = 'indices'

    def __init__(self,
                 raw_results: list,
                 X_dataset: Dataset,
                 y_dataset: Dataset,
                 n_fold_key: str,
                 pred_test_key: str,
                 true_test_key: str,
                 pred_train_key: str,
                 true_train_key: str,
                 test_idx_key: str,
                 train_idx_key: str,
                 trained_model_key: str,
                 fitted_transforms_key: str):

        checkMultiInputTypes(
            ('raw_results', raw_results, [list]),
            ('n_fold_key', n_fold_key, [str]),
            ('pred_test_key', pred_test_key, [str]),
            ('true_test_key', true_test_key, [str]),
            ('pred_train_key', pred_train_key, [str]),
            ('true_train_key', true_train_key, [str]),
            ('test_idx_key', test_idx_key, [str]),
            ('train_idx_key', train_idx_key, [str]),
            ('trained_model_key', trained_model_key, [str]),
            ('fitted_transforms_key', fitted_transforms_key, [str]),
        )

        if len(raw_results) == 0:
            raise TypeError('gojo.core.report.CVReport input results are empty.')

        for i in range(len(raw_results)):
            # list elements should be tuples of length 2
            checkInputType('raw_results[%d]' % i, raw_results[i], [tuple])
            for ii in range(len(raw_results[i])):
                if len(raw_results[i][ii]) != 2:
                    raise TypeError('Input results for index "%d" are not a two-length tuple' % i)

                # first-tuple element should be a string
                checkInputType('raw_results[%d][%d][0]' % (i, ii), raw_results[i][ii][0], [str])

        # stack all test/train predictions
        test_preds = {}
        train_preds = {}
        trained_models = {}
        fitted_transforms = {}
        for fold_results in raw_results:
            fold_results_dict = dict(fold_results)   # transform list of tuples to a hash
            n_fold = fold_results_dict[n_fold_key]

            # better prevent
            assert n_fold not in test_preds.keys(), \
                'Duplicated key in gojo.core.report.CVReport.__init__ (1)'

            assert n_fold not in train_preds.keys(), \
                'Duplicated key in gojo.core.report.CVReport.__init__ (2)'

            # check prediction types
            checkMultiInputTypes(
                ('[fold -> %d] (test) pred_labels' % n_fold, fold_results_dict[pred_test_key], [np.ndarray]),
                ('[fold -> %d] (test) true_labels' % n_fold, fold_results_dict[true_test_key], [np.ndarray]),
                ('[fold -> %d] (test) indices' % n_fold, fold_results_dict[test_idx_key], [np.ndarray]),
                ('[fold -> %d] (train) pred_labels' % n_fold,
                    fold_results_dict[pred_train_key], [np.ndarray, type(None)]),
                ('[fold -> %d] (train) true_labels' % n_fold,
                    fold_results_dict[true_train_key], [np.ndarray, type(None)]),
                ('[fold -> %d] (train) indices' % n_fold,
                    fold_results_dict[train_idx_key], [np.ndarray, type(None)]),
            )

            # process test-predictions
            test_preds[n_fold] = self._processRawPredictions(
                in_data=fold_results_dict, pred_key=pred_test_key, true_key=true_test_key, index_key=test_idx_key)

            # process train-predictions
            train_preds[n_fold] = self._processRawPredictions(
                in_data=fold_results_dict, pred_key=pred_train_key, true_key=true_train_key, index_key=train_idx_key)

            # save the trained models
            trained_models[n_fold] = fold_results_dict[trained_model_key]
            fitted_transforms[n_fold] = fold_results_dict[fitted_transforms_key]

        self.test_preds = test_preds
        self.train_preds = train_preds
        self.X = X_dataset
        self.y = y_dataset
        self._trained_models = trained_models
        self._fitted_transforms = fitted_transforms
        self._metadata = {}

    @property
    def metadata(self) -> dict:
        """ Return the report metadata. """
        return deepcopy(self._metadata)

    def getTestPredictions(self) -> pd.DataFrame:
        """ Function that returns a dataframe with the model predictions, indices, and true labels for the test set.

        Returns
        -------
        test_predictions : pd.DataFrame
             Model predictions over the test set.
        """
        return self._convertPredDict2Df(self.test_preds)

    def getTrainPredictions(self, supress_warnings: bool = False) -> pd.DataFrame or None:
        """ Function that returns a dataframe with the model predictions, indices, and true labels for the train set.

        Predictions will only be returned if they are available. In some subroutines of :py:mod:`gojo.core.loops` it
        should be noted that the predictions made on the training set are not saved or this decision is relegated to
        the user.

        Parameters
        ----------
        supress_warnings : bool, default=False
            Silence the warning raised when not training predictions have been made.

        Returns
        -------
        test_predictions : pd.DataFrame or None
             Model predictions over the train set.
        """
        return self._convertPredDict2Df(self.train_preds, supress_warnings=supress_warnings)

    def getTrainedModels(self, copy: bool = True) -> dict:
        """ Function that returns the trained models if they have been saved in the :py:mod:`gojo.core.loops`
        subroutine.

        Parameters
        ----------
        copy : bool, default=True
            Parameter that indicates whether to return a deepcopy of the models (using the `copy.deepcopy`) or
            directly the saved model. Defaults to True to avoid inplace modifications.

        Returns
        -------
        trained_models : dict or None
            Trained models or None if the models were not saved.
        """
        if copy:
            trained_models_copy = {
                n_fold: deepcopy(model) if model is not None else model
                for n_fold, model in self._trained_models.items()
            }
            return trained_models_copy

        return self._trained_models

    def getFittedTransforms(self, copy: bool = True) -> dict:
        """ Function that returns the fitted transforms if they have been saved in the :py:mod:`gojo.core.loops`
        subroutine.

        Parameters
        ----------
        copy : bool, default=True
            Parameter that indicates whether to return a deepcopy of the transforms or directly the saved transforms.
            Defaults to True to avoid inplace modifications.

        Returns
        -------
        fitted_transforms : dict or None
            Trained models or None if the models were not saved.
        """
        if copy:
            fitted_transforms_copy = {
                n_fold: deepcopy(trans) if trans is not None else trans
                for n_fold, trans in self._fitted_transforms.items()
            }
            return fitted_transforms_copy

        return self._fitted_transforms

    def getScores(self, metrics: list, loocv: bool = False, supress_warnings: bool = False) -> dict:
        """ Method used to calculate performance metrics for folds from a list of metrics (
        :class:`gojo.core.evaluation.Metric` instances) provided. If the subroutine from :py:mod:`gojo.core.loops`
        performed a leave-one-out cross-validation you must specify the parameter `loocv` as True.

        Parameters
        ----------
        metrics : list
            List of :class:`gojo.core.evaluation.Metric` instances

        loocv : bool
            Parameter indicating if the predictions correspond to a LOOCV schema

        supress_warnings : bool, default=False
            Indicates whether to supress the possible warnings returned by the method.

        Returns
        -------
        performance_metrics : dict
            Dictionary with the performance associated with the test data (identified with the 'test' key) and
            with the training data (identified with the 'train' key).

        Examples
        --------
        >>> from gojo import core
        >>>
        >>> # ... cv_report = core.loops.evalCrossVal(...)
        >>> scores = cv_report.getScores(core.getDefaultMetrics('binary_classification', bin_threshold=0.5))
        >>>
        """
        # check input parameters
        checkInputType('metrics', metrics, [list])
        for i in range(len(metrics)):
            checkInputType('metrics[%d]' % i, metrics[i], [Metric])

        # dictionary with the output metrics
        scores = {
            'test': None, 'train': None
        }

        # compute test-performance
        test_predictions_df = self.getTestPredictions()
        scores['test'] = self._calculatePerformanceMetrics(
            predictions=test_predictions_df, metrics=metrics, loocv=loocv)

        train_predictions_df = self.getTrainPredictions(supress_warnings=supress_warnings)
        if train_predictions_df is not None:
            scores['train'] = self._calculatePerformanceMetrics(
                predictions=train_predictions_df, metrics=metrics, loocv=loocv)

        return scores

    def addMetadata(self, **kwargs):
        """ Function used to add metadata to the report. """
        for k, v in kwargs.items():
            if k in self._metadata.keys():
                warnings.warn('Overwriting metadata information for key "%s".' % k)
            self._metadata[k] = v

    def _calculatePerformanceMetrics(self, predictions: pd.DataFrame, metrics: list, loocv: bool) -> pd.DataFrame:
        """ Subroutine used to calculate the performance metrics over a dataframe of predictions. """
        def _getMetricsDict(_n_fold, _df: pd.DataFrame, _metrics: list) -> dict:
            # select prediction columns
            y_pred = _df[[c for c in _df.columns if c.startswith(self._PRED_LABELS_FLAG)]].values
            y_true = _df[[c for c in _df.columns if c.startswith(self._TRUE_LABELS_FLAG)]].values

            # if predictions of true labels are one-dimensional reshape
            if y_pred.shape[1] == 1:
                y_pred = y_pred.reshape(-1)
            if y_true.shape[1] == 1:
                y_true = y_true.reshape(-1)

            # compute performance metrics
            metrics_out = getScores(y_true=y_true, y_pred=y_pred, metrics=_metrics)

            # raise a warning if self._N_FOLD_FLAG is used as it is a flag for indicating the fold to which
            # are the metrics calculated
            if self._N_FOLD_FLAG in metrics_out.keys():
                warnings.warn('Metric name "%s" cannot be used. Omitting metric' % self._N_FOLD_FLAG)

            # save metric fold number
            metrics_out[self._N_FOLD_FLAG] = _n_fold

            return metrics_out

        # check input parameters
        checkInputType('metrics', metrics, [list])
        for i in range(len(metrics)):
            checkInputType('metrics[%d]' % i, metrics[i], [Metric])

        fold_metrics = []
        detected_loocv = True
        if loocv:
            fold_metrics.append(_getMetricsDict(0, predictions, metrics))
            detected_loocv = False   # not-relevant
        else:
            for n_fold, fold_df in predictions.groupby(self._N_FOLD_FLAG):
                if fold_df.shape[0] > 1:   # check that all the predictions contains more than one instance
                    detected_loocv = False

                fold_metrics.append(_getMetricsDict(n_fold, fold_df, metrics))

        if detected_loocv:
            warnings.warn(
                'It has been detected that the predictions are arranged as if a leave-one-out cross-validation (LOOCV) '
                'evaluation has been performed, if this has been the case you must specify the loocv parameter as '
                'True in order to calculate the performance metrics. Review gojo.core.report.ReportCV.getScores '
                'method.')

        return pd.DataFrame(fold_metrics)

    def _convertPredDict2Df(self, d: dict, supress_warnings: bool = False) -> pd.DataFrame or None:
        """ Subroutine used to convert the predictions dict to a pandas DataFrame. """
        checkInputType('d', d, [dict])

        # check if predictions were performed
        all_none = True
        for v in d.values():
            for v2 in v.values():
                if v2 is not None:
                    all_none = False

        if all_none:
            if not supress_warnings:
                warnings.warn('Empty predictions. Returning None')

            return None

        # gather model predictions and true labels
        df = []
        for n_fold, preds in d.items():

            # try to convert the input dictionary to a dataframe
            try:
                key_df = pd.DataFrame(preds)
            except Exception as ex:
                pprint('Internal error in gojo.core.report.CVReport._convertPredDict2Df '
                      'function during pd.DataFrame creation.')
                raise ex

            assert self._N_FOLD_FLAG not in key_df.columns, \
                '"%s" already exists in the dictionary keys (3).' % self._N_FOLD_FLAG  # internal check
            assert self._INDICES_FLAG in key_df.columns, \
                '"%s" must exists in the dictionary keys (4).' % self._INDICES_FLAG  # internal check

            key_df[self._N_FOLD_FLAG] = n_fold
            key_df = key_df.set_index([self._N_FOLD_FLAG, self._INDICES_FLAG])

            df.append(key_df)

        return pd.concat(df, axis=0).sort_index()

    def _processRawPredictions(self, in_data: dict, pred_key: str, true_key: str, index_key: str) -> dict:
        """ Subroutine used to arrange the input raw predictions. """
        checkMultiInputTypes(
            ('in_data', in_data, [dict]),
            ('pred_key', pred_key, [str]),
            ('true_key', true_key, [str]),
            ('index_key', index_key, [str]))

        # check that the provided keys are in the input dictionary and correspond to the expected input type
        for name, key in [('pred_key', pred_key), ('true_key', true_key), ('index_key', index_key)]:
            if key not in in_data.keys():
                raise KeyError(
                    'Key "%s" for parameter "%s" not in the input data keys %r' % (key, name, list(in_data.keys())))
            checkInputType('in_data["%s"]' % name, in_data[key], [np.ndarray, type(None)])

        # create the output directory
        out_dict = {
            self._INDICES_FLAG: in_data[index_key]
        }

        # process model predictions
        predictions = in_data[pred_key]
        if predictions is None:
            out_dict[self._PRED_LABELS_FLAG] = None
        elif len(predictions.shape) == 2:    # predictions can be one-hot encoded (e.g., probabilistic outputs)
            for i in range(predictions.shape[1]):
                out_dict['%s_%d' % (self._PRED_LABELS_FLAG, i)] = predictions[:, i]
        elif len(predictions.shape) == 1:
            # test-predictions
            out_dict[self._PRED_LABELS_FLAG] = predictions
        else:
            assert False, \
                'Predictions contains a number of dimensions different from 1 o 2 (%d)' % len(predictions.shape)

        # process true labels
        true_labels = in_data[true_key]
        if true_labels is None:
            out_dict[self._TRUE_LABELS_FLAG] = None
        elif len(true_labels.shape) == 2:    # true labels also can be one-hot encoded
            for i in range(true_labels.shape[1]):
                out_dict['%s_%d' % (self._TRUE_LABELS_FLAG, i)] = true_labels[:, i]
        elif len(true_labels.shape) == 1:
            # test-predictions
            out_dict[self._TRUE_LABELS_FLAG] = true_labels
        else:
            assert False, \
                'True labels contains a number of dimensions different from 1 o 2 (%d)' % len(true_labels.shape)

        return out_dict


import logging
from logging import Logger

from danswer.configs.app_configs import LOG_LEVEL

def get_log_level_from_str(log_level_str: str = LOG_LEVEL) -> int:
    log_level_dict = {
        "CRITICAL": logging.CRITICAL,
        "ERROR": logging.ERROR,
        "WARNING": logging.WARNING,
        "INFO": logging.INFO,
        "DEBUG": logging.DEBUG,
        "NOTSET": logging.NOTSET,
    }

    return log_level_dict.get(log_level_str.upper(), logging.INFO)

def setup_logger(
    name: str = __name__, log_level: int = get_log_level_from_str()
) -> Logger:
    logger = logging.getLogger(name)

    # If the logger already has handlers, assume it was already configured and return it.
    if logger.handlers:
        return logger

    logger.setLevel(log_level)

    formatter = logging.Formatter(
        "%(asctime)s %(filename)20s%(lineno)4s : %(message)s",
        datefmt="%m/%d/%Y %I:%M:%S %p",
    )

    handler = logging.StreamHandler()
    handler.setLevel(log_level)
    handler.setFormatter(formatter)

    logger.addHandler(handler)

    return logger


import gensim
import pickle
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
import nltk
import os
import utils
from gensim.models import Word2Vec
import sys
from nltk.tag import pos_tag

data_dir=sys.argv[1]
model_path=sys.argv[2]
pretrained_vectors=sys.argv[3]
context_window=int(sys.argv[4])
print(context_window)

x=[]
for dir,subdir,files in os.walk(data_dir):
    for file in files:
        file_path=os.path.join(dir,file)
        proc=utils.read_data(file_path)
        x+=proc
        print(file_path)
print(len(x))

aux_data={}
def add(w1,w2):
    key=w1+"_"+w2
    key2=w2+"_"+w1
    if key not in aux_data:
        aux_data[key]=0
    if key2 not in aux_data:
        aux_data[key2]=0
    aux_data[key]+=1
    aux_data[key2]+=1

def is_prop_noun(tag):
    if (tag[1]=='NNP' or tag[1]=='NNPS'):
        return True
    return False

counter=0
for line in x:
    if(counter%5000==0):
        print(counter)
    le=len(line)
    pos_tag=nltk.pos_tag(line)
    if(len(line)!=len(pos_tag)):
        print(len(line),len(pos_tag))
        print(line)
        print(pos_tag)
        exit(0)
    counter+=1

    for i in range(le):
        line[i]=line[i].lower()
    for i in range(le):
        w1=line[i]
        for j in range(1,context_window+1,1):
            if i+j<le:
                w2=line[i+j]
                add(w1,w2)
                if is_prop_noun(pos_tag[i]):
                    add('-pro-',w2)
                if is_prop_noun(pos_tag[j]):
                    add(w1,'-pro-')

utils.dump_pickle(dump=aux_data,filename="aux_ds"+str(context_window)+".pkl")
print("Created Aux DS")

def my_train(x,size,epochs,model,model_path,pret=False):
    model_2 = Word2Vec(size=300, min_count=1,workers=1,sg=1)
    model_2.build_vocab(x)
    total_examples = model_2.corpus_count
    print(total_examples)
    print(len(list(model_2.wv.vocab.keys())))
    print(list(model_2.wv.vocab.keys())[0:10])
    total_examples = model_2.corpus_count
    if pret:
        model_2.intersect_word2vec_format(pretrained_vectors, binary=True, lockf=1.0)
    model_2.train(x, total_examples=total_examples, epochs=epochs,report_delay=20)
    utils.dump_pickle(model_2,model_path)

model=None
model = gensim.models.KeyedVectors.load_word2vec_format(pretrained_vectors, binary=True)
print("Loaded Google pretrained_vectors")
my_train(x,300,10,model,model_path,True)


import os, ogr2ogr, subprocess, json, urllib.request

#import os
#from osgeo import ogr
#import geopandas
#from geopandas import datasets, GeoDataFrame, read_file

year="2021"
scale="60M"
geo=""
crs="3035"
type="RG"

outpath = "tmp/"+year+"/"+geo+"/"+crs+"/"

input = outpath + scale + "_CNTR_" + type + ".geojson",
output = outpath + scale + "_LAND_" + type + ".geojson",

ogr2ogr.main(["-overwrite","-f","GeoJSON",
                    output,
                    input,
                    "-nlt", "MULTIPOLYGON" if type=="RG" else "MULTILINESTRING",
                    "-dialect", "sqlite"
                    "-sql", "SELECT ST_Union(geometry) FROM input",
])

#ogr2ogr output.shp input.shp -dialect sqlite -sql "SELECT ST_Union(geometry), dissolve_field FROM input GROUP BY dissolve_field"

# https://geopandas.org/getting_started/introduction.html
#path_to_data = geopandas.datasets.get_path("nybb")
#gdf = geopandas.read_file(path_to_data)
#gdf

#def dedup(geometries):
#    """Return a geometry that is the union of all geometries."""
#    if not geometries:  return None
#    multi  = ogr.Geometry(ogr.wkbMultiPolygon)
#    for g in geometries:
#        multi.AddGeometry(g.geometry())
#    return multi.UnionCascaded()

#from shapely.geometry import Polygon
#from shapely.ops import cascaded_union
#polygon1 = Polygon([(0, 0), (5, 3), (5, 0)])
#polygon2 = Polygon([(0, 0), (3, 10), (3, 0)])
#polygons = [polygon1, polygon2]
#u = cascaded_union(polygons)

# write file
#gdf.to_file("my_file.geojson", driver="GeoJSON")


import re
import scrapy
from scrapy.http import TextResponse

from jobparser.items import JobparserItem

TEMPLATE_URL = 'https://hh.ru/search/vacancy?text='

class HhruSpider(scrapy.Spider):
    name = 'hhru'
    allowed_domains = ['hh.ru']

    def __init__(self, query, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.start_urls = [TEMPLATE_URL + query]
        self.site_for_vacancies = 'hh.ru'

    def get_salary(self, salary):
        salary_min = 0
        salary_max = 0
        salary_currency = ''

        new_salary = ''.join(salary)

        if re.search('\d+', new_salary):
            get_salary_text = new_salary.replace('\xa0', '')
            clear_salary_currency = re.sub(r'(\..*)', '', get_salary_text)
            salary_currency = re.sub(r'[дотДОТ\W0-9]', '', clear_salary_currency)
            salary_text = re.sub(r'\b\D*\B\D*', ' ', get_salary_text)
            salaries = salary_text.split(' ')
            if len(salaries) > 3:
                salary_min = int(salaries[1])
                salary_max = int(salaries[2])
            elif 'от' in get_salary_text:
                salary_min = int(salaries[1])
            elif 'до' in get_salary_text:
                salary_max = int(salaries[1])

        return {'salary_min': salary_min,
                'salary_max': salary_max,
                'salary_currency': salary_currency
                }

    def parse_item(self, response: TextResponse, title: str):
        salary = response.xpath('//div[@data-qa="vacancy-salary"]/span//text()').getall()
        salaries = self.get_salary(salary)

        item = JobparserItem()
        item['title'] = title
        item['salary_min'] = salaries['salary_min']
        item['salary_max'] = salaries['salary_max']
        item['salary_currency'] = salaries['salary_currency']
        item['url'] = response.url
        item['vacancy_for_website'] = self.site_for_vacancies
        yield item

    def parse(self, response: TextResponse, *args, **kwargs):
        items = response.xpath('//a[contains(@data-qa, "__vacancy-title")]')
        for item in items:
            url = item.xpath('./@href').get()
            title = item.xpath('.//text()').get()
            data_kwargs = {'title': title}
            yield response.follow(url, callback=self.parse_item, cb_kwargs=data_kwargs)

        next_url = response.xpath('//a[contains(@data-qa, "pager-next")]/@href').get()
        if next_url:
            yield response.follow(next_url, callback=self.parse)


from django.utils import timezone
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from config.models import Config
from transaction.models import Transaction, Payment
from utils.rest_framework.serializers import Base64ImageField

class TransactionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Transaction
        fields = "__all__"

class TransactionBalance(serializers.ModelSerializer):
    class Meta:
        model = Transaction
        fields = (
            'id',
            'account',
            'desc',
            'method',
            'coin',
            'status',
            'values',
            'thb_values',
            'rate_per_usdt',
            'datetime_create'
        )

class TransactionRetrieveSearializer(serializers.ModelSerializer):
    class Meta:
        model = Transaction
        fields = (
            'id',
            'account',
            'transaction_hash',
            'source_key',
            'destination_key',
            'values',
            'thb_values',
            'paid_by',
            'coin',
            'method',
            'status',
            'datetime_update',
            'datetime_complete'
        )

class PaymentResultSerializer(serializers.ModelSerializer):
    class Meta:
        model = Payment
        fields = "__all__"

class TransactionPaymentSerializer(serializers.ModelSerializer):
    payment = serializers.SerializerMethodField()

    class Meta:
        model = Transaction
        fields = (
            'id',
            'desc',
            'method',
            'coin',
            'status',
            'values',
            'thb_values',
            'rate_per_usdt',
            'datetime_create',
            'payment'
        )

    def get_payment(self, transaction):
        from transaction.models import Payment
        payment = Payment.objects.filter(transaction_id=transaction.id).first()
        return PaymentResultSerializer(payment).data

class TransactionTopUp(serializers.Serializer):
    token_name = serializers.CharField(required=True)
    thb_amount = serializers.FloatField(required=True)
    coin_amount = serializers.FloatField(required=True)
    is_own_account = serializers.BooleanField(default=False)
    is_not_reuse = serializers.BooleanField(default=False)
    is_not_overtime = serializers.BooleanField(default=False)

class PaymentUpdatePaySlip(serializers.ModelSerializer):
    payment_slip = Base64ImageField(allow_empty_file=True, allow_null=True, required=True)
    datetime_stamp = serializers.DateTimeField(required=True)

    class Meta:
        model = Payment
        fields = (
            'id',
            'payment_slip',
            'datetime_stamp'
        )

    def update(self, payment, validated_data):
        if 'payment_slip' in validated_data:
            if validated_data['payment_slip']:
                validated_data['payment_slip_log'] = validated_data['payment_slip']
        payment.datetime_stamp = timezone.now()
        payment.save()
        return super().update(payment, validated_data)

class TransactionActivityCreateSerializer(serializers.Serializer):
    account = serializers.SerializerMethodField()
    source_key = serializers.SerializerMethodField()
    destination_key = serializers.SerializerMethodField()
    values = serializers.SerializerMethodField()
    thb_values = serializers.SerializerMethodField()
    paid_by = serializers.SerializerMethodField()
    coin = serializers.SerializerMethodField()
    method = serializers.SerializerMethodField()
    activity_type = serializers.IntegerField()
    desc = serializers.CharField()
    code = serializers.CharField()

    class Meta:
        model = Transaction
        fields = (
            'id',
            'account',
            'source_key',
            'destination_key',
            'method',
            'coin',
            'status',
            'values',
            'thb_values',
            'rate_per_usdt',
            'datetime_create',
            'datetime_update',
            'activity_type',
            'desc',
            'code'
        )

    def create(self, validated_data):
        from account.models import Account
        from activity.models import CarbonActivity
        if 'account' in validated_data and not validated_data['account']:
            raise ValidationError('account is invalid.')
        is_account = Account.objects.filter(id=validated_data.get('account'), is_active=True).exists()
        if not is_account:
            raise ValidationError('account is invalid.')

        if 'method' in validated_data and not validated_data['method']:
            raise ValidationError('account is invalid.')

        method = validated_data.get('method')
        if method and not isinstance(method, int):
            raise ValidationError('method is invalid.')

        if int(method) != 4:
            raise ValidationError('method is match with type.')

        if 'activity_type' in validated_data and not validated_data['activity_type']:
            raise ValidationError('Activity type is invalid.')

        activity_type = validated_data.get('activity_type')
        if activity_type and not isinstance(activity_type, int):
            raise ValidationError('Activity type is invalid.')

        if int(activity_type) not in CarbonActivity.TYPE_CHOICE:
            raise ValidationError('method is match with type.')
        return super().create(validated_data)

class TransactionUpdateStatusSerializer(serializers.ModelSerializer):
    status = serializers.IntegerField(default=0)
    desc = serializers.CharField()

    class Meta:
        model = Transaction
        fields = (
            'id',
            'status',
            'desc'
        )

    def update(self, transaction, validated_data):
        from transaction.models import Payment
        if 'status' in validated_data:
            # upload new avatar
            if not validated_data['status']:
                raise ValidationError('status is required.')
            if not isinstance(validated_data['status'], int):
                raise ValidationError('Wrong format type status.')
            if int(validated_data['status']) not in dict(Transaction.STATUS_CHOICES):
                raise ValidationError('Status not match with status in system.')
            if int(validated_data['status']) == 2:
                payment_transaction = Payment.objects.filter(transaction_id=transaction.id).first()
                if not payment_transaction.payment_slip:
                    raise ValidationError(
                        'This transaction can not complete, because payment of this transaction does not pay.'
                    )
        return super().update(transaction, validated_data)

class TransactionSwapReceiver(serializers.Serializer):
    sol_amount = serializers.FloatField(required=True)


from django.urls import path

from . import views

urlpatterns = [
    path("", views.index, name="index"),
    path("wiki/create",views.create, name ="create"),
    path("wiki/search",views.search, name ="search"),
    path("wiki/<str:entry>", views.page, name="page"),
    path("wiki/<str:title>/edit", views.edit, name="edit"),
    path("wiki/<str:title>/delete", views.delete, name="delete"),
    path("wiki/<str:title>/save", views.save, name="save"),
    path("wiki", views.random_page, name="random_page"),

]


## File Handling Basics

# Read file from a default folder
my_file = open("Booleans.py")
my_file.read()
my_file.read()
my_file.seek(0)
my_file.read()
my_file.seek(0)

my_file.readlines()
my_file.seek(0)

# Store file data into a variable
new_file = my_file.read()
print(new_file)

# Find the current directory
#print(pwd)

# Read a file from anywhere in th computer
#my_file = open("C:\\Users\\vijay\\Desktop\\Python 3\\The Avengers.txt")
#my_file.read()
#my_file.seek(0)
#my_file.readlines()

# Path format for MAC/Linux
my_file = open("/home/demonho/vsCode/Python-Course-2018/Booleans.py")

# Close the file
my_file.close()
## File Handling Basics

# 1) Read file from a default folder
# 2) Store file data into a variable
# 3) Find the current directory
# 4) Read a file from anywhere in th computer
# 5) Close the file


from odoo import models, api, _

class PurchaseOrder(models.Model):
    _inherit = "purchase.order"

    @api.onchange('partner_id')
    def onchange_partner_id(self):
        result = super(PurchaseOrder, self).onchange_partner_id()
        if not self.partner_id:
            return result
        warnings = self._find_partner_warnings(self.partner_id)
        if warnings:
            self.notes = warnings
        return result

    def _prepare_invoice(self):
        invoice_vals = super(PurchaseOrder, self)._prepare_invoice()
        del invoice_vals['narration']
        partner = self.env['res.partner'].browse(
            invoice_vals.get('partner_id'))
        warnings = self.env['account.move']._find_partner_warnings(partner)
        if warnings:
            invoice_vals['narration'] = warnings
        return invoice_vals

    def _prepare_picking(self):
        values = super(PurchaseOrder, self)._prepare_picking()
        warnings = self.env['stock.picking']._find_partner_warnings(
            self.partner_id)
        if warnings:
            values['note'] = warnings
        return values

    def _find_partner_warnings(self, partner):
        warnings = False
        if partner.purchase_warn == 'no-message' and partner.parent_id:
            partner = partner.parent_id
        if partner.purchase_warn and partner.purchase_warn != 'no-message':
            warnings = _("- Warning: %s", partner.purchase_warn_msg)
        return warnings


from csv import reader

from typing import List
from leitor_csv.data_classes import Aluno, Disciplina, Historico, Professor, Turma

class LeitorCSV:

    alunos: List[Aluno] = []
    displinas: List[Disciplina] = []
    historico: List[Historico] = []
    professores: List[Professor] = []
    turmas: List[Turma] = []

    @staticmethod
    def ler_dados():
        LeitorCSV.ler_csv_alunos()
        LeitorCSV.ler_csv_disciplinas()
        LeitorCSV.ler_csv_historico()
        LeitorCSV.ler_csv_professores()
        LeitorCSV.ler_csv_turmas()

    @staticmethod
    def ler_csv_alunos() -> None:
        with open("data/Alunos.csv", encoding="utf-8") as file:
            csv_reader = reader(file)
            csv_reader.__next__()  # pulando a primeira linha do arquivo
            for line in csv_reader:
                matricula, nome, semestre, data_nasc = line[0], line[1], line[2], line[3]
                LeitorCSV.alunos.append(
                    Aluno(matricula, nome, semestre, data_nasc))

    @staticmethod
    def ler_csv_disciplinas() -> None:
        with open("data/Disciplinas.csv", encoding="utf-8") as file:
            csv_reader = reader(file)
            csv_reader.__next__()  # pulando a primeira linha do arquivo
            for line in csv_reader:
                codigo_disc, nome_disc, creditos = line[0], line[1], line[2]
                LeitorCSV.displinas.append(Disciplina(
                    codigo_disc, nome_disc, creditos))

    @staticmethod
    def ler_csv_historico() -> None:
        with open("data/Historico.csv", encoding="utf-8") as file:
            csv_reader = reader(file)
            csv_reader.__next__()  # pulando a primeira linha do arquivo
            for line in csv_reader:
                codigo_historico = line[0]
                matricula_aluno = line[1]
                codigo_turma = line[2]
                codigo_disc = line[3]
                codigo_professor = line[4]
                ano = line[5]
                frequencia = line[6]
                nota = line[7]
                LeitorCSV.historico.append(
                    Historico(
                        codigo_historico, matricula_aluno, codigo_turma,
                        codigo_disc, codigo_professor, ano, frequencia, nota
                    )
                )

    @staticmethod
    def ler_csv_professores() -> None:
        with open("data/Professores.csv", encoding="utf-8") as file:
            csv_reader = reader(file)
            csv_reader.__next__()  # pulando a primeira linha do arquivo
            for line in csv_reader:
                codigo_professor, nome, area_pesquisa = line[0], line[1], line[2]
                LeitorCSV.professores.append(
                    Professor(codigo_professor, nome, area_pesquisa))

    @staticmethod
    def ler_csv_turmas() -> None:
        with open("data/Turmas.csv", encoding="utf-8") as file:
            csv_reader = reader(file)
            csv_reader.__next__()  # pulando a primeira linha do arquivo
            for line in csv_reader:
                codigo_turma, codigo_disc, codigo_professor, ano, horario = line[
                    0], line[1], line[2], line[3], line[4]
                LeitorCSV.turmas.append(
                    Turma(codigo_turma, codigo_disc, codigo_professor, ano, horario))


#!/usr/bin/env python3

import bpaTools
from shapely.geometry import LineString, Point
from rdp import rdp

cstGeoType:str              = "type"
cstGeojsonGeometry:str      = "geometry"
cstGeoFeature:str           = "Feature"
cstGeoProperties:str        = "properties"
cstGeoCoordinates:str       = "coordinates"
cstGeoPoint:str             = "Point"
cstGeoLine:str              = "LineString"
cstGeoPolygon:str           = "Polygon"
errLocalisationPoint:list   = [-5,45]

#geojson Colors attributes
def addColorProperties(prop:dict, dstProp:dict, oLog:bpaTools.Logger):
    sClass = prop["class"]

    #Red            - #ff0000
    #medium red     - #ff6480
    #ligth Red      - #ff8080
    #Purple         - #800080
    #medium purple  - #ffb9dc
    #light purple   - #ff96dc
    #bordeau        - #aa0014
    #Gres           - #444444
    #ligth Gres     - #a0868b
    #Orange         - #f07800
    #Blue           - #0000ff
    #ligth blue     - #ceeffe
    #bright blue    - #80ffff

    #Red and fill
    if sClass in ["P","ZIT"]:
        sStroke = "#ff0000"
        sFill = "#ff8080"
        nFillOpacity = 0.6
    #Red and fill
    elif sClass in ["A","B","C","P","ZIT","CTR","CTR-P","TMA","TMA-P","TMZ","RMZ/TMZ","TMZ/RMZ"]:
        sStroke = "#ff0000"
        sFill = "#ff8080"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.6
        else:
            nFillOpacity = 0.3
    #Red and No-Fill
    elif sClass in ["CTA","CTA-P","FIR","FIR-P","NO-FIR","PART","CLASS","SECTOR","SECTOR-C","OCA","OCA-P","OTA","OTA-P","UTA","UTA-P","UIR","UIR-P","TSA","CBA","RCA","RAS","TRA","AMA","ASR","ADIZ","POLITICAL","OTHER","AWY"]:
        sStroke = "#ff0000"
        sFill = "#ff8080"
        nFillOpacity = 0
    #Purple and No-fill
    elif sClass=="D" and prop.get("type", None)=="LTA":
        sStroke = "#800080"
        sFill = "#ff96dc"
        nFillOpacity = 0
    #Red and fill
    elif sClass in ["D","D-AMC"] and not bool(prop.get("declassifiable", False)):
        sStroke = "#ff0000"
        sFill = "#ff8080"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.6
        else:
            nFillOpacity = 0.3
    #Light-Red and Purple fill
    elif sClass in ["D","D-AMC"] and bool(prop.get("declassifiable", False)):
        sStroke = "#ff0000"
        sFill = "#ffb9dc"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.6
        else:
            nFillOpacity = 0.3
    #Purple and fill
    elif sClass in ["R","R-AMC"] and prop.get("type", None)!="RTBA":
        sStroke = "#800080"
        sFill = "#ffb9dc"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.6
        else:
            nFillOpacity = 0.3
    #Gres and fill
    elif sClass in ["R","R-AMC"] and prop.get("type", None)=="RTBA":
        sStroke = "#444444"
        sFill = "#a0868b"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.6
        else:
            nFillOpacity = 0.3
    #Orange and ligth-fill
    elif sClass in ["GP","Q","VV","VL","BA","PA"]:
        sStroke = "#f07800"
        sFill = "#f07800"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.3
        else:
            nFillOpacity = 0.1
    #Orange and No-Fill
    elif sClass in ["RMZ","W"]:
        sStroke = "#f07800"
        sFill = "#f07800"
        nFillOpacity = 0
    #Blue
    elif sClass in ["ZSM","BIRD","PROTECT","D-OTHER","SUR","AER","TRPLA","TRVL","VOL","REFUEL"]:
        sStroke = "#0000ff"
        sFill = "#ceeffe"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.4
        else:
            nFillOpacity = 0.2
    #Green
    elif sClass in ["E","F","G","SIV","FIS","FFVL","FFVP"]:
        sStroke = "#008040"
        sFill = "#80ff80"
        if prop.get("lower", None)=="SFC":
            nFillOpacity = 0.4
        else:
            nFillOpacity = 0.2
    else:
        oLog.warning("GeoJSON Color not found for Class={0}".format(sClass), outConsole=False)
        return

    #Quasi transparence pour toutes les zones au dessus de FL115
    if nFillOpacity!=0 and prop.get("lowerM", None)>=3505:
            nFillOpacity = 0.1

    dstProp.update({"stroke": sStroke})
    dstProp.update({"stroke-width": 2})
    dstProp.update({"stroke-opacity": 0.8})
    dstProp.update({"fill": sFill})
    dstProp.update({"fill-opacity": nFillOpacity})
    return

class Aixm2json4_5:

    def __init__(self, oCtrl) -> None:
        bpaTools.initEvent(__file__, oCtrl.oLog)
        self.oCtrl = oCtrl
        self.oAirspacesCatalog = None
        self.geoBorders = None                  #Geographic borders dictionary
        self.geoAirspaces = None                #Geographic airspaces dictionary
        self.epsilonReduce:float = -1           #Default value=0 for no-doubling with no-compression, =0.0001 for good compression
        return

    def parseControlTowers(self) -> None:
        sTitle = "Aerodrome control towers"
        sXmlTag = "Uni"

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        oList = self.oCtrl.oAixm.root.find_all(sXmlTag, recursive=False)
        barre = bpaTools.ProgressBar(len(oList), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        geojson = []
        for uni in oList:
            idx+=1
            twr = self.tower2json(uni)
            if twr:
                geojson.append(twr)
            barre.update(idx)
        barre.reset
        self.oCtrl.oAixmTools.writeGeojsonFile("towers", geojson)
        return

    def tower2json(self, uni) -> dict:
        if uni.codeType.string in ("TWR", "OTHER"):
            if uni.find("geoLat", recursive=False):
                prop = self.oCtrl.oAixmTools.initProperty("Aerodrome Control Tower")
                prop = self.oCtrl.oAixmTools.addProperty(prop, uni.OrgUid, "txtName", "organisationAuthority")
                prop = self.oCtrl.oAixmTools.addProperty(prop, uni, "codeType", "codeType")
                prop = self.oCtrl.oAixmTools.addProperty(prop, uni.UniUid, "txtName", "name")
                geom = {cstGeoType:cstGeoPoint, cstGeoCoordinates:self.oCtrl.oAixmTools.geo2coordinates("dd", uni)[::-1]}
                return {cstGeoType:cstGeoFeature, cstGeoProperties:prop, cstGeojsonGeometry:geom}
            else:
                self.oCtrl.oLog.warning("Missing TWR coordinates {0}".format(uni.UniUid), outConsole=False)
        return

    def parseAerodromes(self) -> None:
        sTitle = "Aerodromes / Heliports"
        sXmlTag = "Ahp"

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        oList = self.oCtrl.oAixm.root.find_all(sXmlTag, recursive=False)
        barre = bpaTools.ProgressBar(len(oList), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        geojson = []
        for ahp in oList:
            idx+=1
            geojson.append(self.ahp2json(ahp))
            barre.update(idx)
        barre.reset()
        self.oCtrl.oAixmTools.writeGeojsonFile("aerodromes", geojson)
        return

    def ahp2json(self, ahp) -> dict:
        prop = self.oCtrl.oAixmTools.initProperty("Aerodrome / Heliport")
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp.OrgUid, "txtName", "organisationAuthority")
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "codeType")
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "txtName", "name")
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp.AhpUid, "codeId", "codeId")
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "codeIcao", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "codeIata", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "valElev", "elevation", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "uomDistVer", "verticalUnit", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "txtDescrRefPt", "description", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "txtDescrSite", "descriptionSite", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "txtNameCitySer", "cityServing", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "txtNameAdmin", "nameAdmin", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, ahp, "txtRmk", "remark", optional=True)
        geom = {cstGeoType:cstGeoPoint, cstGeoCoordinates:self.oCtrl.oAixmTools.geo2coordinates("dd", ahp)[::-1]}
        return {cstGeoType:cstGeoFeature, cstGeoProperties:prop, cstGeojsonGeometry:geom}

    def parseObstacles(self) -> None:
        sTitle = "Obstacles"
        sXmlTag = "Obs"

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        oList = self.oCtrl.oAixm.root.find_all(sXmlTag, recursive=False)
        barre = bpaTools.ProgressBar(len(oList), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        geojson = []
        for obs in oList:
            idx+=1
            geojson.append(self.obs2json(obs))
            barre.update(idx)
        barre.reset()
        self.oCtrl.oAixmTools.writeGeojsonFile("obstacles", geojson)
        return

    def obs2json(self, obs) -> dict:
        prop = self.oCtrl.oAixmTools.initProperty("Obstacle")
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "txtDescrType", "type")
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "txtName", "name")
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "txtDescrMarking", "marked", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "codeLgt", "codeLight")
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "txtDescrLgt", "descrLight", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "valElev", "elevation")
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "valHgt", "height", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "uomDistVer", "verticalUnit")
        prop = self.oCtrl.oAixmTools.addProperty(prop, obs, "txtRmk", "remark", optional=True)
        geom = {cstGeoType:cstGeoPoint, cstGeoCoordinates:self.oCtrl.oAixmTools.geo2coordinates("dd", obs.ObsUid)[::-1]}
        return {cstGeoType:cstGeoFeature, cstGeoProperties:prop, cstGeojsonGeometry:geom}

    def parseRunwayCenterLinePosition(self) -> None:
        sTitle = "Runway Center Line Position"
        sXmlTag = "Rcp"

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        oList = self.oCtrl.oAixm.root.find_all(sXmlTag, recursive=False)
        barre = bpaTools.ProgressBar(len(oList), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        geojson = []
        for rcp in oList:
            idx+=1
            geojson.append(self.rcp2json(rcp))
            barre.update(idx)
        barre.reset()
        self.oCtrl.oAixmTools.writeGeojsonFile("runwaysCenter", geojson)
        return

    def rcp2json(self, rcp) -> dict:
        prop = self.oCtrl.oAixmTools.initProperty("Runway Center")
        prop = self.oCtrl.oAixmTools.addProperty(prop, rcp.RcpUid.RwyUid.AhpUid, "codeId")
        prop = self.oCtrl.oAixmTools.addProperty(prop, rcp.RcpUid.RwyUid, "txtDesig", "designator")
        prop = self.oCtrl.oAixmTools.addProperty(prop, rcp, "valElev", "elevation", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, rcp, "uomDistVer", "verticalUnit", optional=True)
        geom = {cstGeoType:cstGeoPoint, cstGeoCoordinates:self.oCtrl.oAixmTools.geo2coordinates("dd", rcp.RcpUid)[::-1]}
        return {cstGeoType:cstGeoFeature, cstGeoProperties:prop, cstGeojsonGeometry:geom}

    def parseGateStands(self) -> None:
        sTitle = "Gates and Stands"
        sXmlTag = "Gsd"

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        oList = self.oCtrl.oAixm.root.find_all(sXmlTag, recursive=False)
        barre = bpaTools.ProgressBar(len(oList), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        geojson = []
        for gsd in oList:
            idx+=1
            geojson.append(self.gsd2json(gsd))
            barre.update(idx)
        barre.reset()
        self.oCtrl.oAixmTools.writeGeojsonFile("gates-stands", geojson)
        return

    def gsd2json(self, gsd) -> dict:
        prop = self.oCtrl.oAixmTools.initProperty("Gate or Stand")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gsd.GsdUid, "txtDesig", "designator")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gsd.ApnUid, "txtName", "parkingPosition")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gsd.ApnUid.AhpUid, "codeId")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gsd, "codeType")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gsd, "txtDescrRestrUse", optional=True)
        prop = self.oCtrl.oAixmTools.addProperty(prop, gsd, "txtRmk", optional=True)
        geom = {cstGeoType:cstGeoPoint, cstGeoCoordinates:self.oCtrl.oAixmTools.geo2coordinates("dd", gsd)[::-1]}
        return {cstGeoType:cstGeoFeature, cstGeoProperties:prop, cstGeojsonGeometry:geom}

    def parseGeographicBorders(self) -> None:
        sTitle = "Geographic borders"
        sXmlTag = "Gbr"

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        if self.geoBorders == None:
            self.geoBorders = dict()
            oList = self.oCtrl.oAixm.root.find_all(sXmlTag, recursive=False)
            barre = bpaTools.ProgressBar(len(oList), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
            idx = 0
            geojson = []
            for gbr in oList:
                idx+=1
                j,l = self.gbr2json(gbr)
                geojson.append(j)
                self.geoBorders[gbr.GbrUid["mid"]] = LineString(l)
                barre.update(idx)
        barre.reset()
        self.oCtrl.oAixmTools.writeGeojsonFile("borders", geojson)
        return

    def gbr2json(self, gbr):
        prop = self.oCtrl.oAixmTools.initProperty("Geographic border")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gbr, "codeType", "type")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gbr.GbrUid, "txtName", "name")
        prop = self.oCtrl.oAixmTools.addProperty(prop, gbr, "txtRmk", "desc", optional=True)
        # geometry
        g = []
        l = []
        ddPrev = None
        for gbv in gbr.find_all("Gbv", recursive=False):
            if gbv.codeType.string not in ("GRC", "END"):
                self.oCtrl.oLog.critical("Not recognized codetype\n{0}".format(gbv), outConsole=True)
            dd = self.oCtrl.oAixmTools.geo2coordinates("dd", gbv)[::-1]
            #Suppression des doublons (après prise en compte de l'arrondi 'GeojsonDigitOptimize')
            if dd != ddPrev:
                g.append(dd)
                l.append((dd[0], dd[1]))
                ddPrev = dd
        geom = {cstGeoType:cstGeoLine, cstGeoCoordinates:g}
        return ({cstGeoType:cstGeoFeature, cstGeoProperties:prop, cstGeojsonGeometry:geom}, l)

    def findJsonObjectAirspacesBorders(self, sAseUid) -> dict:
        for o in self.geoAirspaces:
            if o[cstGeoProperties]["UId"]==sAseUid:
                return o[cstGeojsonGeometry]
        return None

    def parseAirspacesBorders(self, airspacesCatalog) -> None:
        self.oAirspacesCatalog = airspacesCatalog

        #Controle de prerequis
        if self.geoBorders == None:
            self.parseGeographicBorders()

        sTitle = "Airspaces Borders"
        sXmlTag = "Abd"

        if not self.oCtrl.oAixm.root.find(sXmlTag, recursive=False):
            sMsg = "Missing tags {0} - {1}".format(sXmlTag, sTitle)
            self.oCtrl.oLog.warning(sMsg, outConsole=True)
            return

        sMsg = "Parsing {0} to GeoJSON - {1}".format(sXmlTag, sTitle)
        self.oCtrl.oLog.info(sMsg)

        barre = bpaTools.ProgressBar(len(self.oAirspacesCatalog.oAirspaces), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        self.geoAirspaces = []                #Réinitialisation avant traitement global
        for k,oZone in self.oAirspacesCatalog.oAirspaces.items():
            idx+=1
            if not oZone["groupZone"]:          #Ne pas traiter les zones de type 'Regroupement'
                sAseUid = oZone["UId"]

                #Map 20200801
                #if oZone["id"] in ["EBS27"]:  #[W] LOW FLYING AREA GOLF ONE
                #    self.oCtrl.oLog.critical("just for bug {0}".format(oZone["id"]), outConsole=False)

                oBorder = self.oAirspacesCatalog.findAixmObjectAirspacesBorders(sAseUid)
                if oBorder:
                    self.parseAirspaceBorder(oZone, oBorder)
                else:
                    sAseUidBase = self.oAirspacesCatalog.findZoneUIdBase(sAseUid)       #Identifier la zone de base (de référence)
                    if sAseUidBase==None:
                        self.oCtrl.oLog.warning("Missing Airspaces Borders AseUid={0} of {1}".format(sAseUid, oZone["nameV"]), outConsole=False)
                        self.geoAirspaces.append({cstGeoType:cstGeoFeature, cstGeoProperties:oZone, cstGeojsonGeometry:{cstGeoType: cstGeoPoint, cstGeoCoordinates: errLocalisationPoint}})
                    else:
                        geom = self.findJsonObjectAirspacesBorders(sAseUidBase)         #Recherche si la zone de base a déjà été parsé
                        if geom:
                            if geom[cstGeoCoordinates]==errLocalisationPoint:
                                self.oCtrl.oLog.warning("Missing Airspaces Borders sAseUidBase={0} used by AseUid={1} of {2}".format(sAseUidBase, sAseUid, oZone["nameV"]), outConsole=False)
                            self.geoAirspaces.append({cstGeoType:cstGeoFeature, cstGeoProperties:oZone, cstGeojsonGeometry:geom})
                        else:
                            oBorder = self.oAirspacesCatalog.findAixmObjectAirspacesBorders(sAseUidBase)
                            if oBorder==None:
                                self.oCtrl.oLog.warning("Missing Airspaces Borders AseUid={0} AseUidBase={1} of {2}".format(sAseUid, sAseUidBase, oZone["nameV"]), outConsole=False)
                                self.geoAirspaces.append({cstGeoType:cstGeoFeature, cstGeoProperties:oZone, cstGeojsonGeometry:{cstGeoType: cstGeoPoint, cstGeoCoordinates: errLocalisationPoint}})
                            else:
                                self.parseAirspaceBorder(oZone, oBorder)
            barre.update(idx)

        barre.reset()
        return

    def parseAirspaceBorder(self, oZone, oBorder) -> None:
        g = []              #geometry GeoJSON
        points4map = []

        #Init
        bIsSpecCircle:bool = False
        bIsCircle:bool = bool(oBorder.Circle)   #Zone uniqumement contituée d'un cercle
        if not bIsCircle:
            #Extraction des vecteurs
            avx_list = oBorder.find_all("Avx", recursive=False)

            #Si la zone est 'Danger' ou 'Vol libre et Vol a voile' ; et uniquement déclarée sous forme d'un 'Point' ; alors reconstituer un cercle !
            if len(avx_list)==1 and oZone.get("class",None) in ["Q","W"]:   bIsSpecCircle = True

        #Construction d'un cercle standard
        if bIsCircle:
            lat_c, lon_c = self.oCtrl.oAixmTools.geo2coordinates("dd",
                                                                 oBorder.Circle,
                                                                 latitude=oBorder.Circle.geoLatCen.string,
                                                                 longitude=oBorder.Circle.geoLongCen.string,
                                                                 oZone=oZone)

            radius = float(oBorder.Circle.valRadius.string)
            radius = self.oCtrl.oAixmTools.convertLength(radius, oBorder.uomRadius.string, "M")   #Convert radius in Meter for GeoJSON format

            Pcenter = Point(lon_c, lat_c)
            if self.oCtrl.MakePoints4map:
                points4map.append(self.oCtrl.oAixmTools.make_point(Pcenter, "Circle Center of {0}".format(oZone["nameV"])))
            g = self.oCtrl.oAixmTools.make_arc(Pcenter, radius)
            #oZone.update({"name":str(len(g)) + " Segments - " + oZone.get("name")})
            geom = {cstGeoType:cstGeoPolygon, cstGeoCoordinates:[g]}

        #Construction spécifique d'un cercle sur la base d'un Point unique
        elif bIsSpecCircle:
            lat_c, lon_c = self.oCtrl.oAixmTools.geo2coordinates("dd", avx_list[0],oZone=oZone)

            #Radius in Meter for GeoJSON format / Depend of area type
            radius:float = float(1000)              #Fixe un rayon de 1000m par défaut
            if   oZone["type"] in ["TRVL"]:         #TRVL Treuil-Vol-Libre
                radius = float(2000)                #Fixe un rayon de 2000m
            elif oZone["type"] in ["TRPLA"]:        #TRPLA Treuil Planeurs
                radius = float(5000)                #Fixe un rayon de 5000m
            elif oZone["type"] in ["PJE"]:          #PJE=Parachute Jumping Exercise
                radius = float(1000)                #Fixe un rayon de 1000m

            Pcenter = Point(lon_c, lat_c)
            if self.oCtrl.MakePoints4map:
                points4map.append(self.oCtrl.oAixmTools.make_point(Pcenter, "Circle Center of {0}".format(oZone["nameV"])))
            g = self.oCtrl.oAixmTools.make_arc(Pcenter, radius)
            geom = {cstGeoType:cstGeoPolygon, cstGeoCoordinates:[g]}

        #Construction d'un tracé sur la base d'une suite de Points et/ou Arcs
        else:
            for avx_cur in range(0,len(avx_list)):
                avx = avx_list[avx_cur]
                codeType = avx.codeType.string

                # 'Great Circle' or 'Rhumb Line' segment
                if codeType in ["GRC", "RHL"]:
                    lat, lon = self.oCtrl.oAixmTools.geo2coordinates("dd", avx, oZone=oZone)
                    if self.oCtrl.MakePoints4map:
                        pt = Point(lon, lat)
                        points4map.append(self.oCtrl.oAixmTools.make_point(pt, "Point {0} of {1}; type={2}".format(avx_cur, oZone["nameV"], codeType)))
                    g.append([lon, lat])

                # 'Counter Clockwise Arc' or 'ClockWise Arc'
                #Nota: 'ABE' = 'Arc By Edge' ne semble pas utilisé dans les fichiers SIA-France et Eurocontrol-Europe
                elif codeType in ["CCA", "CWA"]:
                    start = self.oCtrl.oAixmTools.geo2coordinates("dd", avx, oZone=oZone)[::-1]
                    if avx_cur+1 == len(avx_list):
                        stop = g[0]
                    else:
                        stop = self.oCtrl.oAixmTools.geo2coordinates("dd", avx_list[avx_cur+1], oZone=oZone)[::-1]

                    center = self.oCtrl.oAixmTools.geo2coordinates("dd",
                                                                   avx,
                                                                   latitude=avx.geoLatArc.string,
                                                                   longitude=avx.geoLongArc.string,
                                                                   oZone=oZone)[::-1]

                    Pcenter = Point(center[0], center[1])
                    Pstart = Point(start[0], start[1])
                    Pstop = Point(stop[0], stop[1])

                    if self.oCtrl.MakePoints4map:
                        points4map.append(self.oCtrl.oAixmTools.make_point(Pstart, "Arc Start {0} of {1}".format(avx_cur, oZone["nameV"])))
                        points4map.append(self.oCtrl.oAixmTools.make_point(Pcenter, "Arc Center {0} of {1}".format(avx_cur, oZone["nameV"])))
                        points4map.append(self.oCtrl.oAixmTools.make_point(Pstop, "Arc Stop {0} of {1}".format(avx_cur, oZone["nameV"])))

                    #Alignement pas toujours idéal sur les extremités d'arcs
                    radius = float(avx.valRadiusArc.string)
                    radius = self.oCtrl.oAixmTools.convertLength(radius, oBorder.uomRadiusArc.string, "M")   #Convert radius in Meter for GeoJSON format

                    #Amélioration de l'alignement des arcs par recalcul systématique du rayon sur la base des coordonnées d'entrée et de sortie d'arc
                    arc = self.oCtrl.oAixmTools.make_arc2(Pcenter, Pstart, Pstop, 0.0, (codeType=="CWA"))
                    #arc = self.oCtrl.oAixmTools.make_arc2(Pcenter, Pstart, Pstop, radius, (codeType=="CWA"))   #Sans recalcul - Des erreurs d'alignement !
                    for o in arc:
                        g.append(o)

                # 'Sequence of geographical (political) border vertexes'
                elif codeType == "FNT":
                    # geographic borders
                    start = self.oCtrl.oAixmTools.geo2coordinates("dd", avx, oZone=oZone)[::-1]
                    if avx_cur+1 == len(avx_list):
                        stop = g[0]
                    else:
                        stop = self.oCtrl.oAixmTools.geo2coordinates("dd", avx_list[avx_cur+1], oZone=oZone)[::-1]

                    if avx.GbrUid["mid"] in self.geoBorders:
                        fnt = self.geoBorders[avx.GbrUid["mid"]]
                        start_d = fnt.project(Point(start[0], start[1]), normalized=True)
                        stop_d = fnt.project(Point(stop[0], stop[1]), normalized=True)
                        geom = self.oCtrl.oAixmTools.substring(fnt, start_d, stop_d, normalized=True)
                        for c in geom.coords:
                            lon, lat = c
                            g.append([lon, lat])
                    else:
                        self.oCtrl.oLog.warning("Missing geoBorder GbrUid='{0}' Name={1} of {2}".format(avx.GbrUid["mid"], avx.GbrUid.txtName.string, oZone["nameV"]), outConsole=False)
                        g.append(start)
                else:
                    self.oCtrl.oLog.warning("Default case - GbrUid='{0}' Name={1} of {2}".format(avx.GbrUid["mid"], avx.GbrUid.txtName.string, oZone["nameV"]), outConsole=False)
                    g.append(self.oCtrl.oAixmTools.geo2coordinates("dd", avx, oZone=oZone)[::-1])

            if len(g) == 0:
                self.oCtrl.oLog.error("Empty geometry of {0}\n{1}".format(oZone["nameV"], oBorder.prettify()), outConsole=True)
                geom = None
            elif len(g) == 1:
                geom = {cstGeoType:cstGeoPoint, cstGeoCoordinates:g[0]}
            elif len(g) == 2:
                geom = {cstGeoType:cstGeoLine, cstGeoCoordinates:g}
            else:
                #Contrôle de fermeture du Polygone
                if g[0] != g[-1]:
                    g.append(g[0])
                geom = {cstGeoType:cstGeoPolygon, cstGeoCoordinates:[g]}

        #Ajout spécifique des points complémentaires pour map des cartographies
        for g0 in points4map:
            for g1 in g0:
                self.geoAirspaces.append(g1)
        self.geoAirspaces.append({cstGeoType:cstGeoFeature, cstGeoProperties:oZone, cstGeojsonGeometry:geom})
        return

    #Use epsilonReduce for compress shape in file (Default value=0 for no-doubling with no-compression, =0.0001 for good compression)
    def saveAirspacesFilter(self, aContext, epsilonReduce:float=None) -> None:
        if epsilonReduce and epsilonReduce>0:
            self.epsilonReduce = epsilonReduce
        else:
            self.epsilonReduce = self.oCtrl.epsilonReduce
        if not self.geoAirspaces:                                   #Contrôle si le fichier est vide
            return
        context = aContext[0]
        sMsg = "Prepare GeoJSON file - {0}".format(aContext[1])
        self.oCtrl.oLog.info(sMsg)
        barre = bpaTools.ProgressBar(len(self.oAirspacesCatalog.oAirspaces), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        geojson = []       #Initialisation avant filtrage spécifique
        for o in self.geoAirspaces:
            oZone = o[cstGeoProperties]
            idx+=1
            include = not oZone["groupZone"]                         				#Ne pas traiter les zones de type 'Regroupement'
            #if include and ("excludeAirspaceNotCoord" in oZone):     				#Ne pas traiter les zones qui n'ont pas de coordonnées geometriques
            #    include = not oZone["excludeAirspaceNotCoord"]
            if include:
                include = False
                if context=="all":
                    include = True
                elif context=="ifr":
                    include = (not oZone["vfrZone"]) and (not oZone["groupZone"])
                elif context=="vfr":
                    include = oZone["vfrZone"]
                    include = include or oZone.get("vfrZoneExt", False)     		#Exporter l'extension de vol possible en VFR de 0m jusqu'au FL195/5944m
                elif context=="ff":
                    include = oZone["freeFlightZone"]
                    include = include or oZone.get("freeFlightZoneExt", False) 	    #Exporter l'extension de vol possible en VFR de 0m jusqu'au FL195/5944m
                    include = include and (o[cstGeojsonGeometry][cstGeoCoordinates]!=errLocalisationPoint)
            if include:
                #Extract single parts of properties
                oSingleCat:dict = {}
                aSinglePorperties:list = ["name", "nameV", "class", "type", "codeActivity",
                                          "lower", "lowerMin", "ordinalLowerM", "lowerM",
                                          "upper", "upperMax", "ordinalUpperM", "upperM", "groundEstimatedHeight",
                                          "desc", "activationCode", "activationDesc", "declassifiable", "timeScheduling", "Mhz",
                                          "GUId", "UId", "id"]  #Exclude: zoneType, groupZone, srcClass, srcType, vfrZone, vfrZoneExt, freeFlightZone, freeFlightZoneExt, srcName; etc...
                for sProp in aSinglePorperties:
                    value = o[cstGeoProperties].get(sProp, None)
                    if value!=None:
                        oSingleCat.update({sProp:value})
                addColorProperties(o[cstGeoProperties], oSingleCat, self.oCtrl.oLog)    #Ajout des propriétés pour colorisation de la zone

                #Extraction des coordonnées
                oAsGeo = o[cstGeojsonGeometry]
                if oAsGeo[cstGeoType].lower()==(cstGeoPoint).lower():
                    oCoords:list = oAsGeo[cstGeoCoordinates]                        #get coordinates of geometry
                elif oAsGeo[cstGeoType].lower()==(cstGeoLine).lower():
                    oCoords:list = oAsGeo[cstGeoCoordinates]                        #get coordinates of geometry
                elif oAsGeo[cstGeoType].lower()==(cstGeoPolygon).lower():
                    oCoords:list = oAsGeo[cstGeoCoordinates][0]                     #get coordinates of geometry

                #Optimisation du tracé GeoJSON
                oCoordsDst:list = []
                #if self.epsilonReduce<0: --> do not change !
                if self.epsilonReduce==0 or (self.epsilonReduce>0 and len(oCoords)>40):     #Ne pas optimiser le tracé des zones ayant moins de 40 segments (préservation des tracés de cercle minimaliste)
                    oCoordsDst = rdp(oCoords, epsilon=self.epsilonReduce)                   #Optimisation du tracé des coordonnées

                #Remplacement du tracé s'il a été optimisé
                iOrgSize:int = len(oCoords)
                iNewSize:int = len(oCoordsDst)
                if iNewSize>0 and iNewSize!=iOrgSize:
                    percent:float = (1-(iNewSize/iOrgSize))*100
                    percent = int(percent) if percent>1 else round(percent,1)
                    sOpti:str = "Segments optimisés à {0}% ({1}->{2}) [rdp={3}] ***".format(percent, iOrgSize, iNewSize, self.epsilonReduce)
                    self.oCtrl.oLog.debug("GeoJSON RDP Optimisation: {0} - {1}".format(oZone["nameV"], sOpti), level=2, outConsole=False)
                    #self.oCtrl.oLog.debug("RDP Src: {0}".format(oCoords), level=8)
                    #self.oCtrl.oLog.debug("RDP Dst: {0}".format(oCoordsDst), level=8)
                    if oAsGeo[cstGeoType].lower()==(cstGeoPoint).lower():
                        oNewGeo:dict = {cstGeoType:oAsGeo[cstGeoType], cstGeoCoordinates:oCoordsDst}
                    elif oAsGeo[cstGeoType].lower()==(cstGeoLine).lower():
                       oNewGeo:dict = {cstGeoType:oAsGeo[cstGeoType], cstGeoCoordinates:oCoordsDst}
                    elif oAsGeo[cstGeoType].lower()==(cstGeoPolygon).lower():
                        oNewGeo:dict = {cstGeoType:oAsGeo[cstGeoType], cstGeoCoordinates:[oCoordsDst]}
                    oArea:dict = {cstGeoType:cstGeoFeature, cstGeoProperties:oSingleCat, cstGeojsonGeometry:oNewGeo}
                else:
                    oArea:dict = {cstGeoType:cstGeoFeature, cstGeoProperties:oSingleCat, cstGeojsonGeometry:oAsGeo}

                geojson.append(oArea)
            barre.update(idx)
        barre.reset()
        if geojson:
            self.oCtrl.oAixmTools.writeGeojsonFile("airspaces", geojson, context)
        return

    #Nétoyage du catalogue de zones pour desactivation des éléments qui ne sont pas valides ; ou constitués que d'un ou deux 'Point' a exclure uniquement pour le freefligth
    #Ces simples 'Point remarquable' sont supprimés de la cartographie freefligth (ex: un VOR, un émmzteur radio, un centre de piste)
    #Idem, suppression des 'lignes' (ex: Axe d'approche d'un aérodrome ou autres...)
    def cleanAirspacesCalalog(self, airspacesCatalog) -> None:
        if not self.geoAirspaces:                                   #Contrôle si le fichier est vide
            return
        self.oAirspacesCatalog = airspacesCatalog
        if self.oAirspacesCatalog.cleanAirspacesCalalog:            #Contrôle si l'optimisation est déjà réalisée
            return
        sMsg = "Clean catalog"
        self.oCtrl.oLog.info(sMsg)
        barre = bpaTools.ProgressBar(len(self.geoAirspaces), 20, title=sMsg, isSilent=self.oCtrl.oLog.isSilent)
        idx = 0
        lNbChange = 0
        for o in self.geoAirspaces:
            oZone = o[cstGeoProperties]
            idx+=1

            #Flag all not valid area
            oGeom:dict = o[cstGeojsonGeometry]                              #Sample - "geometry": {"type": "Polygon", "coordinates": [[[3.069444, 45.943611], [3.539167, 45.990556], ../..
            if oGeom[cstGeoType] in [cstGeoPoint] and oGeom[cstGeoCoordinates]==errLocalisationPoint:
                oZone.update({"excludeAirspaceNotCoord":True})       #Flag this change in catalog
                lNbChange+=1

            #if oZone["freeFlightZone"]:
            if oGeom[cstGeoType] in [cstGeoPoint,cstGeoLine]:
                exclude=True
            elif len(oGeom[cstGeoCoordinates][0])<3:
                exclude=True
            else:
                exclude=False
            if exclude:
                oZone.update({"freeFlightZone":False})              #Change value in catalog
                if oZone.get("freeFlightZoneExt", False)==True:
                    oZone.update({"freeFlightZoneExt":False})       #Change value in catalog
                oZone.update({"excludeAirspaceNotFfArea":True})     #Flag this change in catalog
                oZone.update({"geometryType":oGeom[cstGeoType]})    #info for catalog 'Point' or 'LineString'
                lNbChange+=1
            barre.update(idx)
        barre.reset()

        if lNbChange>0:
            self.oAirspacesCatalog.saveAirspacesCalalog()               #Save the new catalogs

        self.oAirspacesCatalog.cleanAirspacesCalalog = True  #Marqueur de traitement réalisé
        return


import pygame

from pygame.locals import *

import ui.sftext.resources as resources
from ui.sftext.style.style import Style

class SFText():
    def __init__(self, text, surface=None, font_path='.', style=None):

        if isinstance(text, bytes):
            # print('text is', bytes)
            self.text = text.decode('utf-8')
        elif isinstance(text, str):
            # print('text is', str)
            self.text = text

        self.fonts = resources.Fonts(path=font_path)

        if style:
            Style.set_default(style)

        if surface is None:
            self.screen = pygame.display.get_surface()
        else:
            self.screen = surface
        self.screen_rect = self.screen.get_rect()
        self.bg = self.screen.copy()

        # print('parsing text')
        self.parse_text()
        # print('done parsing')

    def set_font(self, obj):
        if obj['bold'] and obj['italic'] and obj['separate_bolditalic']:
            obj['font_obj'] = self.fonts.load(
                obj['separate_bolditalic'], obj['size'])
        elif obj['separate_bold'] and obj['bold']:
            obj['font_obj'] = self.fonts.load(
                obj['separate_bold'], obj['size'])
        elif obj['separate_italic'] and obj['italic']:
            obj['font_obj'] = self.fonts.load(
                obj['separate_italic'], obj['size'])
        else:
            obj['font_obj'] = self.fonts.load(
                obj['font'], obj['size'])

    def parse_text(self):
        self.parsed = []
        scr_w = self.screen_rect.width

        self.default_style = Style.default_style
        self.default_style['font_obj'] = self.fonts.load(
            self.default_style['font'], self.default_style['size'])
        self.default_style['w'], self.default_style['h'] = (
            self.default_style['font_obj'].size(' '))

        y = 0
        for line in self.text.splitlines():
            x = 0
            for style in line.split("{style}"):

                text, styled_txt = Style.split(style)

                self.set_font(styled_txt)
                font = styled_txt['font_obj']

                w, h = styled_txt['w'], styled_txt['h'] = font.size(' ')
                # determine the amount of space needed to render text

                wraps = self.wrap_text(text, scr_w, x, styled_txt)

                for wrap in wraps:
                    rect = pygame.Rect((0, 0), font.size(wrap['text']))

                    if (x + wrap['w1'] + w * 3) > scr_w:
                        x = 0
                        y += wrap['h']

                    if len(wraps) == 1 and wrap['align'] == 'center':
                        rect.midtop = (
                            self.screen_rect.centerx,
                            self.screen_rect.bottom + y)
                    else:
                        rect.topleft = (
                            x + w * 3,
                            self.screen_rect.bottom + y)
                    wrap['rect'] = rect
                    wrap['x'] = x
                    wrap['y'] = y
                    if False:
                        print("\n{}: {},".format('x', wrap['x']), end='')
                        print("{}: {},".format('y', wrap['y']), end='')
                        print("{}: {},".format('w', wrap['w']), end='')
                        print("{}: {}".format('h', wrap['h']))
                        print(wrap['text'])
                    self.parsed.append(wrap)

                    x += wrap['w1']
            y += wrap['h']
        # exit()
        # print('done parsing')

        self.start_y = 0 - self.screen_rect.h + self.default_style['h']

        self.y = int(self.start_y)

        self.end_y = (
            -sum(p['h'] for p in self.parsed if p['x'] == 0)
            - self.default_style['h'] * 2)

    def wrap_text(self, text, width, _x, styled_txt):
        style = dict(styled_txt)
        x = int(_x)
        wrapped = []
        size = style['font_obj'].size
        c_width = style['w']

        # print(size(text))
        # print(width)
        if size(text)[0] <= (
            width - c_width * 6 - x
        ):
            # print('fits')
            style['text'] = text
            style['w1'] = size(text)[0]
            wrapped.append(style)

            return wrapped
        else:
            # print("doesn't fit")
            # print(text)
            wrapped = [text]
            guessed_length = ((width - c_width * 6 - x) // c_width)
            all_fit = False
            all_fit_iter = 1
            while not all_fit:
                #########
                # DEBUG #
                if False:
                    print("all_fit iteraions: {}".format(all_fit_iter))
                    if all_fit_iter >= guessed_length * 5:
                        exit()
                # DEBUG #
                #########
                for i in range(len(wrapped)):
                    # print('for i in range(len(wrapped))')
                    fit = size(wrapped[i])[0] < width - c_width * 6 - x
                    # print(width - c_width * 6 - x)
                    iter_length = int(guessed_length)
                    # print(iter_length)
                    fit_iter = 0
                    while not fit:
                        #########
                        # DEBUG #
                        if False:
                            fit_iter += 1
                            print("fit iteraions: {}, iter_length: {}".format(
                                fit_iter, iter_length))
                            if fit_iter >= guessed_length * 5:
                                print(wrapped[i])
                                exit()
                        # DEBUG #
                        #########
                        if guessed_length <= 2 or iter_length <= 2:
                            # print('if guessed_length <= 2')
                            x = 0
                            guessed_length = (
                                (width - c_width * 6 - x) // c_width)
                            iter_length = int(guessed_length)
                            continue
                        guess = wrapped[i][:iter_length]
                        # print('while not fit: "{}"'.format(guess))
                        if guess[-1:] not in [" ", ",", ".", "-", "\n"]:
                            # print('if guess[-1:] not in:')
                            iter_length -= 1
                        else:
                            if size(guess)[0] < width - c_width * 6 - x:
                                remains = wrapped[i][iter_length:]
                                wrapped[i] = guess
                                wrapped.append(remains)
                                fit = True
                            else:
                                iter_length -= 1
                    all_fit_iter += 1
                    # print("Cut point: {}".format(iter_length))
                    # print('Guess: ({})"{}"'.format(type(guess), guess))
                    # print('Remains: "{}"'.format(remains))
                    # print("[{}]fit? {}".format(i, fit))
                status = True
                for i in range(len(wrapped)):
                    if size(wrapped[i])[0] >= width:
                        status = False
                all_fit = status

            for i in range(len(wrapped)):
                # print('"{}"'.format(wrapped[i]))
                style['text'] = wrapped[i]
                style['w1'] = size(wrapped[i])[0]
                wrapped[i] = dict(style)

            return wrapped

    def on_update(self):
        for i, p in enumerate(self.parsed[:]):
            rect = p['rect'].move(0, self.y)

            if not isinstance(p['text'], pygame.Surface):
                p['font_obj'].set_bold(False)
                p['font_obj'].set_italic(False)

                if p['bold'] and p['italic'] and not p['separate_bolditalic']:
                    print('pygame-bold', p['text'])
                    p['font_obj'].set_bold(p['bold'])
                    print('pygame-italic', p['text'])
                    p['font_obj'].set_italic(p['italic'])
                elif not p['separate_bold'] and p['bold']:
                    print('pygame-bold', p['text'])
                    p['font_obj'].set_bold(p['bold'])
                elif not p['separate_italic'] and p['italic']:
                    print('pygame-italic', p['text'])
                    p['font_obj'].set_italic(p['italic'])

                p['font_obj'].set_underline(p['underline'])

                p['text'] = p['font_obj'].render(p['text'], 1, p['color'])
            self.screen.blit(p['text'], rect)

            if rect.top >= (
                self.screen_rect.bottom - self.default_style['h']
            ):
                break
        """
        if obj['bold'] and obj['italic'] and obj['separate_bolditalic']:
            obj['font_obj'] = self.fonts.load(
                obj['separate_bold_italic'], obj['size'])
        elif obj['separate_bold'] and obj['bold']:
            obj['font_obj'] = self.fonts.load(
                obj['separate_bold'], obj['size'])
        elif obj['separate_italic'] and obj['italic']:
            obj['font_obj'] = self.fonts.load(
                obj['separate_italic'], obj['size'])
        else:
            obj['font_obj'] = self.fonts.load(
                obj['font'], obj['size'])
        """

    def scroll(self, y=0):
        if isinstance(y, int):
            self.y += y
            if self.y < self.end_y:
                self.y = self.end_y
            elif self.y > self.start_y:
                self.y = self.start_y
        elif isinstance(y, str):
            if y == 'home':
                self.y = self.start_y
            elif y == 'end':
                self.y = self.end_y

    def post_update(self):
        self.screen.blit(self.bg, (0, 0))

    def on_key_press(self, event):
        if event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
            self.scroll(50)
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_PAGEUP:
            self.scroll(500)
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_HOME:
            self.scroll('home')

        elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
            self.scroll(-50)
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_PAGEDOWN:
            self.scroll(-500)
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_END:
            self.scroll('end')

    def on_mouse_scroll(self, event):
        if event.button == 4:
            self.scroll(50)
        elif event.button == 5:
            self.scroll(-50)


"""
Rename wheelodex_version

Revision ID: 8820a6b34f40
Revises: b835c6894d5a
Create Date: 2018-10-12 20:33:03.002855+00:00
"""

from __future__ import annotations
from alembic import op

# revision identifiers, used by Alembic.
revision = "8820a6b34f40"
down_revision = "b835c6894d5a"
branch_labels: None = None
depends_on: None = None

def upgrade() -> None:
    op.alter_column(
        "wheel_data",
        "wheelodex_version",
        new_column_name="wheel_inspect_version",
    )

def downgrade() -> None:
    op.alter_column(
        "wheel_data",
        "wheel_inspect_version",
        new_column_name="wheelodex_version",
    )


def merge_sort(arr):
    if len(arr)>1:
        left_arr = arr[:len(arr)//2]    # 2 diye vag krar por  bamer gula print krbe
        right_arr = arr[len(arr)//2:]   # 2 diye vag krar por  daner gula print krbe ,odd hle besi ta print krbe

        # recursion
        merge_sort(left_arr)    # bamer gula ke merge krar jonne
        merge_sort(right_arr)   # daner gula ke merge krar jonne

        # arpor left and right ke merge krte hbe
        #merge
        i=0     # left_arr index
        j=0     # right_arr index
        k=0     # merge array index
        while i < len(left_arr) and j < len(right_arr):
            if left_arr[i] < right_arr[j]:
                arr[k] = left_arr[i]
                i +=1

            else:
                arr[k] = right_arr[j]
                j +=1
            k +=1

        while i < len(left_arr):
            arr[k] = left_arr[i]
            i += 1
            k += 1

        while j<len(right_arr):
            arr[k] = right_arr[j]
            j +=1
            k +=1

arr_test = [2,4,1,6,12,5,4,8,3]
print('Before merging = ',arr_test)
merge_sort(arr_test)
print('After Merging = ',arr_test)

5. To sort a linear array using the merge sort algorithm.py


from threading import current_thread

from django.utils.deprecation import MiddlewareMixin

_requests = {}

def get_request(*args, **kwargs):
    t = current_thread()
    if t in _requests:
        return _requests[t]

class UserRequestMiddleware(MiddlewareMixin):
    def process_request(self, request):
        _requests[current_thread()] = request


import numpy as np
from matplotlib import pyplot as plt
from noiseestimation.playback_sensor import PlaybackSensor
from simple_bicycle_ekf import SimpleBicycleEKF

# Parameters
num_samples = 11650
steering_to_wheel_angle = 0.067
lf = 1.45      # distance center of gravity (cog) <-> front axle
lb = 1.42      # distance cog <-> rear axle [m]
wheelbase = lf + lb
var_vel = 0.001
var_steer = 0.0001
var_measurement = 0.01
var_sim = 0.0001
dt = 0.01

def setup():
    sim = PlaybackSensor("data/vehicle_state_integrated.json",
                         ["fVx", "fStwAng", "pose_x", "pose_y"])
    # set up kalman filter
    tracker = SimpleBicycleEKF(dt, wheelbase, var_vel, var_steer)
    tracker.Q = np.eye(2) * 0.001
    tracker.H = np.array([[1, 0, 0],
                          [0, 1, 0]])
    tracker.R = var_measurement
    tracker.x = np.array([[0, 0, 0]]).T
    tracker.P = np.eye(3) * 500

    return sim, tracker

def filtering(sim, tracker):
    # perform sensor simulation and filtering
    readings = []
    filtered = []
    R = [[var_sim]]
    for _ in range(num_samples):
        time, reading = sim.read(R)
        velocity = reading[0, 0]
        delta = reading[1, 0] * steering_to_wheel_angle
        velocity = velocity if velocity > 0 else 0.1
        tracker.predict(u=np.array([[velocity],
                                    [delta]]))
        tracker.update(reading[2:])
        readings.append(reading)
        filtered.append(tracker.x)

    readings = np.asarray(readings)
    filtered = np.asarray(filtered)
    return readings, filtered

def plot_results(readings, filtered):
    plt.plot(
        filtered[:, 0],
        filtered[:, 1],
        "b-"
    )
    plt.show()

def run_tracker():
    sim, tracker = setup()
    readings, filtered = filtering(sim, tracker)
    plot_results(readings, filtered)

if __name__ == "__main__":
    run_tracker()


from ast import AST
import os
from pathlib import Path
from torch.utils.data import DataLoader
from src.data_utils.teacher_precompute import PrecomputeDataset, get_pretrained_ast, _prepare_dataset_json, _precompute_batch, precompute_teacher_preds
from src.ast.src.dataloader import AudiosetDataset
from src.constants import AST_MODEL_PATH, AUDIOS_PATH, INFERENCE_AUDIO_CONFIG, LABEL_CSV, LABEL_LIST

os.environ['TORCH_HOME'] = 'checkpoints'

def test_get_pretrained_ast():
    pretrained_mdl_path = AST_MODEL_PATH
    audio_model, _ = get_pretrained_ast(pretrained_mdl_path)
    assert audio_model is not None

def test_prepare_dataset_json():
    audios_path = AUDIOS_PATH
    dataset_json_file = _prepare_dataset_json(audios_path, 'testing')

    dataset = AudiosetDataset(dataset_json_file, label_csv=LABEL_CSV, audio_conf=INFERENCE_AUDIO_CONFIG)
    dataloader = DataLoader(dataset, batch_size=2, num_workers=1)

    for audio_inputs, labels in dataloader:
        assert audio_inputs is not None

def test_precompute():
    audios_path = AUDIOS_PATH
    pretrained_mdl_path = AST_MODEL_PATH
    audio_model, device = get_pretrained_ast(pretrained_mdl_path)

    batch_size = 2
    dataset = PrecomputeDataset(audios_path)
    dataloader = DataLoader(dataset, batch_size=batch_size, num_workers=1)

    for audio_input, _, _ in dataloader:
        predictions = _precompute_batch(audio_model, audio_input, device)
        assert predictions.shape == (batch_size, len(LABEL_LIST))
        break


from django.shortcuts import render
# import requests to get websites
import requests

# Create your views here.
def Movies_list(request):
# to add the base website that we will request information from.
	query = request.GET.get("q")
	url = "http://www.omdbapi.com/?apikey=37c1229d&s=king"
	if query:
		url = "http://www.omdbapi.com/?apikey=37c1229d&s=" + query
	response = requests.get(url)
	print(response.json())

	context = {
		"movies": response.json()
	}

	return render(request, 'movies_list.html', context)

def movie_details(request, movie_id):
	url = "http://www.omdbapi.com/?apikey=37c1229d&i=" + movie_id
	response = requests.get(url)

	context = {
		"movie": response.json()
	}
	return render(request, 'movie_details.html', context)

# def movie_search(requests, movie_id):


from numba import njit
from multiprocessing import Process
from time import sleep

@njit
def fun(x, y):
    return x + y

def process(i, xs, ys):
    for x, y in zip(xs, ys):
        print(f"Process [{i}]", x, y, fun(x, y))
        sleep(0.2)

if __name__ == "__main__":
    procs = []
    for i in range(5):
        procs.append(
            Process(target=process, args=(i, list(range(10)), list(range(10))))
        )
        procs[-1].start()

    for proc in procs:
        proc.join()