import numpy as np
import json
import os
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

class LatentConverter():

	def __init__(self, places_path):
		place_list = []
		place2idx = {}
		with open(places_path, encoding='utf-8') as f:
			for p_idx, place in enumerate(json.load(f)):
				place = tuple(place)
				place2idx[place] = p_idx
				place_list.append(place)
		self.places_path = places_path
		self.place_len = len(place_list)
		self.place_list = place_list
		self.place2idx = place2idx

	def get_normalized(self, reviewer_path):
		with open(reviewer_path, encoding='utf-8') as f:
			review_list = json.load(f)

		stars_dict = {}
		for review in review_list:
			place = (review['place'], review['address'])
			if place in self.place2idx:
				stars_dict[place] = review['stars']
		if len(stars_dict)==0:
			print('Reviewer "' + reviewer_path + '":\n\tNone of the reviews overlaps with "' + self.places_path + '"')
			mean, std = 0, 0
		else:
			stars_list = list(stars_dict.values())
			mean, std = np.mean(stars_list), np.std(stars_list)

		normalized = np.zeros(self.place_len)
		for p_idx, place in enumerate(self.place_list):
			if std==0:
				normalized[p_idx] = 0
			else:
				normalized[p_idx] = (stars_dict[place]-mean)/std if place in stars_dict else 0

		return normalized

	def gen_proj(self, guides_normalized, latent_dim=20):
		u, s, vh = np.linalg.svd(guides_normalized)
		print('gen_proj: The first', latent_dim, 'latent dimensions are taken.')
		print('Singular values:\n', s)
		# guides_smoothed = np.matmul(np.matmul(u[:,:20], np.diag(s[:20])), vh[:20,:])
		# print('Smoothed:\n', guides_smoothed)
		# # for debug use
		# guides_normalized = guides_normalized.transpose()
		# guides_smoothed = guides_smoothed.transpose()
		return u[:,:latent_dim].transpose()

	def get_latent(self, proj, reviewer_path):
		return np.matmul(proj, self.get_normalized(reviewer_path))

	@staticmethod
	def visualize(guides_latent, dims=(0,1,2)):
		fig = plt.figure()
		ax = fig.add_subplot(111, projection='3d')
		X = guides_latent[dims[0],:]
		Y = guides_latent[dims[1],:]
		Z = guides_latent[dims[2],:]
		ax.scatter(X, Y, Z)
		ax.set_xlabel('X')
		ax.set_ylabel('Y')
		ax.set_zlabel('Z')
		plt.show()

class ReviewReader():

	def __init__(self, guides_path, reviews_path):
		self.reviews_path = reviews_path
		# guide_list[<number>] = <guide ID>
		guide_list = []
		with open(guides_path, encoding='utf-8') as f:
			for i in f:
				guide_list.append(i[:-1])
		self.guide_len = len(guide_list)
		# guide_file_dict[<guide ID>] = <file name>
		guide_file_dict = {}
		for i in os.listdir(reviews_path):
			guide_file_dict[i.split()[2].split('=')[1].split('.')[0]] = i
		# file_mame[<number>] = <file name>
		file_mame = []
		for num in range(len(guide_list)):
			file_mame.append(guide_file_dict[guide_list[num]])
		self.file_name = file_mame

	def getPath(self, guideNum):
		return os.path.join(self.reviews_path, self.file_name[guideNum])

	def getReviews(self, guideNum):
		with open(self.getPath(guideNum), encoding='utf-8') as f:
			review_list = json.load(f)
		return review_list

if __name__ == '__main__':

	# initialize with a list of places
	lc = LatentConverter('places.json')
	# get reviews
	rr = ReviewReader('guides.txt', '../data/reviews_guide')
	# generate all normalized vectors
	guides_normalized = np.zeros((lc.place_len, rr.guide_len))
	for g_idx in range(rr.guide_len):
		guides_normalized[:,g_idx] = lc.get_normalized(rr.getPath(g_idx))
	# generate projection matrix
	proj = lc.gen_proj(guides_normalized, latent_dim=20)
	# project guides
	guides_latent = np.matmul(proj, guides_normalized)
	# save for future use
	np.save('guides_normalized.npy', guides_normalized)
	np.save('proj.npy', proj)
	np.save('guides_latent.npy', guides_latent)

def example_get_latent():
	# initialize with a list of places
	lc = LatentConverter('places.json')
	# load projection matrix
	proj = np.load('proj.npy')
	# get latent vector
	return lc.get_latent(proj, '../data/reviews_guide/reviews_guide length=117 guideID=107297262039687837164.json')

def example_visualize():
	# visualize the 0th, 1st, and 2nd latent dimension
	LatentConverter.visualize(np.load('guides_latent.npy'), dims=(0,1,2))


import os
import sys
import unittest
import logging
from datetime import datetime
import json

from flask import Flask, request
from flask_restful import Resource

import settings as CONST

curpath = os.path.dirname(__file__)
sys.path.append(os.path.abspath(os.path.join (curpath, "../")))

from app_models import Customer
from app_utils import MongoRepository, DbEntity

class CustomerAPI(Resource):

    def __init__(self):
        #Create and configure logger
        logfile= os.path.abspath("{0}/{1}".format(CONST.log_settings["log_folder"], CONST.log_settings["log_file"]))
        os.makedirs( os.path.dirname(logfile), exist_ok=True)

        logging.basicConfig(
            filename=logfile,
            format='%(asctime)s %(message)s',
            filemode='a'
        )

        #Creating an object
        self.logger=logging.getLogger()

        #Setting the threshold of logger to DEBUG
        self.logger.setLevel(CONST.log_settings["log_level"])

        self.entity = "customers"
        self.repo = MongoRepository(logger=self.logger,
            server=CONST.db_customer["url"],
            port=CONST.db_customer["port"],
            database=CONST.db_customer["db"],
            collection=self.entity,
            session_id=1)

    ###########################################################################
    # GET /customers
    # GET /customers/1
    def get(self,id=None):
        '''
            Used to read one records
        '''

        if id:
            msg = 'Processing request to get {0} with id:{1}'.format(self.entity, id)
            self.logger.debug(msg)
        else:
            msg = 'Processing request to get all {0}'.format(self.entity)
            self.logger.debug(msg)

        try:
            if id:
                records = self.repo.find_by_id(id)
            else:
                records = [c for c in self.repo.fetchall()]

            return json.dumps(records), 200

        except Exception as e:
            msg = 'Error in processing GET request.', str(e)
            self.logger.error(msg)

            return { 'status' : 'error' }, 500
    ###########################################################################
    # POST /customers
    def post(self):
        '''
            Used to create entity
        '''
        self.logger.debug('Processing POST request')

        if not request.data:
            msg = "Request to create entity needs to come with form 'data' "
            self.logger.error(msg)
            return {
                'status' : 'error',
                'msg' : msg
            }, 400

        try:
            entity = Customer( json=json.loads(request.data) )

            wellformed, msg = entity.isValid()
            if not wellformed:
                self.logger.error(msg)
                return {
                    'status' : 'error',
                    'msg' : msg
                }, 400

            result = self.repo.create(entity)

            return { 'status' : 'success' }, 200

        except Exception as e:
            msg = 'Error in processing POST request.', str(e)
            self.logger.error(msg)

            return { 'status' : 'error' }, 500

    ###########################################################################
    # PUT /customers/id
    def put(self, id=None):
        '''
            Used for update
        '''
        if (not id) or (not request.data):
            msg = "Request to update entity needs to come for a specific entity id and 'data' "
            self.logger.error(msg)
            return {
                'status' : 'error',
                'msg' : msg
            }, 400

        msg = 'Processing request to update entity:{0} with id:{1}'.format(self.entity, id)

        try:
            entity = Customer( json=json.loads(request.data) )

            wellformed, msg = entity.isValid()
            if not wellformed:
                self.logger.error(msg)
                return {
                    'status' : 'error',
                    'msg' : msg
                }, 400

            result = self.repo.update_by_id(id,entity)
            return { 'status' : 'success' }, 200

        except Exception as e:
            msg = 'Error in processing PUT request.', str(e)
            self.logger.error(msg)

            return { 'status' : 'error' }, 500

    ###########################################################################
    # DELETE /customers/id
    def delete(self, id):
        '''
            Used for update
        '''

        msg = 'Processing request to delete entity:{0} with id:{1}'.format(self.entity, id)
        self.logger.debug(msg)

        try:
            result = self.repo.delete_by_id(id)

            return { 'status' : 'success' }, 200

        except Exception as e:
            msg = 'Error in processing DELETE request.', str(e)
            self.logger.error(msg)

            return { 'status' : 'error' }, 500

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

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


from alipy.index import IndexCollection
from alipy.experiment import State
from alipy.data_manipulate import split
from sklearn.preprocessing import StandardScaler

def cancel_step(select_ind, lab, unlab):
    lab = IndexCollection(lab)
    unlab = IndexCollection(unlab)
    unlab.update(select_ind)
    lab.difference_update(select_ind)
    lab_list, unlab_list = [], []
    for i in lab:
        lab_list.append(i)
    for i in unlab:
        unlab_list.append(i)
    return lab_list, unlab_list

def update(select_ind, lab, unlab):
    lab = IndexCollection(lab)
    unlab = IndexCollection(unlab)
    lab.update(select_ind)
    unlab.difference_update(select_ind)
    lab_list, unlab_list = [],[]
    for i in  lab:
        lab_list.append(i)
    for i in  unlab:
        unlab_list.append(i)
    return lab_list, unlab_list

def save_state(data, select_ind, current_ac):
    quried_label = data.loc[select_ind,['target']]
    st = State(select_ind,current_ac,queried_label=quried_label)
    return st
def separate(data):
    if 'start' or 'end' in data.columns:
        data = data.drop(columns=['start', 'end'])
    if 'video' in data.columns:
        data = data.drop(columns=['video'])
    if 'color' in data.columns:
        data = data.drop(columns=['color'])

    y = labels = data['target']
    features = data.drop(columns=['target'])

    X = features = StandardScaler().fit_transform(features)

    train, test, lab, unlab = split(X, y, test_ratio=0.3, initial_label_rate=0.2, split_count=1, all_class=True,
                                    saving_path='.')
    train_list, test_list, lab_list, unlab_list = [] , [] ,[] ,[]
    for i in train[0]:
        train_list.append(i)
    for i in test[0]:
        test_list.append(i)
    for i in  lab[0]:
        lab_list.append(i)
    for i in  unlab[0]:
        unlab_list.append(i)
    return X[lab_list], y[lab_list]


from random import randint
import numpy

def fill_unassigned(row):
    '''
    >>> a = numpy.array([1, 0, 5, 5, 0, 2])
    >>> fill_unassigned(a)
    >>> a
    array([1, 3, 5, 5, 4, 2])
    '''
    usednums, c = set(row), 1
    for i, x in enumerate(row):
        if x != 0:
            continue
        while c in usednums:
            c += 1
        row[i] = c
        usednums.add(c)

def join_sets(row, a, b):
    '''
    >>> a = numpy.array([1, 1, 2, 2, 3, 2])
    >>> join_sets(a, 1, 2)
    >>> a
    array([1, 1, 1, 1, 3, 1])
    '''
    row[numpy.where(row == b)[0]] = a

def make_bottom_walls(row):
    sets = {}
    for x in row:
        sets[x] = sets.get(x, 0) + 1
    guarded = {k: randint(0, v - 1) for k, v in sets.items()}
    bwalls = numpy.zeros(row.shape, dtype='bool')
    for i, x in enumerate(row):
        sets[x] -= 1
        if guarded[x] == sets[x]:
            continue
        if randint(0, 1):
            bwalls[i] = True
    return bwalls

def genmaze_eller(cellcount, heightcount):
    #     0   1
    # +xxx+xxx+xxx+
    # x   |   |   x
    # +---+---+---+  0
    # x   |   |   x
    # +xxx+xxx+xxx+

    all_right_walls = numpy.zeros((cellcount - 1, heightcount), dtype=numpy.bool_)
    all_bottom_walls = numpy.zeros((cellcount, heightcount - 1), dtype=numpy.bool_)

    row = numpy.arange(1, cellcount + 1, dtype=numpy.int16)
    rwalls = numpy.zeros((cellcount - 1,), dtype=numpy.bool_)
    rwalls_req = numpy.zeros(rwalls.shape, dtype=numpy.bool_)
    for y in range(heightcount):
        fill_unassigned(row)
        rwalls[:] = False
        rwalls_req[:] = False
        for x in range(cellcount - 1):
            if row[x] == row[x + 1]:
                rwalls_req[x] = True
                continue
            if randint(0, 1):
                rwalls[x] = True
            else:
                join_sets(row, row[x], row[x + 1])

        if y == heightcount - 1:  # last row condition
            break
        all_right_walls[:, y] = rwalls_req | rwalls

        bwalls = make_bottom_walls(row)
        all_bottom_walls[:, y] = bwalls
        row[bwalls] = 0

    # walls in last row
    for x in range(cellcount - 1):
        if row[x + 1] != row[x]:
            rwalls[x] = False
            join_sets(row, row[x], row[x + 1])
    all_right_walls[:, heightcount - 1] = rwalls | rwalls_req

    return {
        'width': cellcount,
        'height': heightcount,
        'rwalls': all_right_walls,
        'bwalls': all_bottom_walls,
    }

def debug_draw_maze(maze):
    from PIL import Image, ImageDraw

    WorldSize.cell = 20
    w, h = maze['width'], maze['height']
    img = Image.new('RGB', (w * WorldSize.cell, h * WorldSize.cell))
    draw = ImageDraw.Draw(img)
    draw.rectangle((0, 0, w * WorldSize.cell - 1, h * WorldSize.cell - 1), fill=(0, 0, 0))
    for y in range(h):
        for x in range(w - 1):
            if maze['rwalls'][x, y]:
                draw.line((
                    x * WorldSize.cell + WorldSize.cell, y * WorldSize.cell,
                    x * WorldSize.cell + WorldSize.cell, y * WorldSize.cell + WorldSize.cell
                ), fill=(255, 255, 255))
    for y in range(h - 1):
        for x in range(w):
            if maze['bwalls'][x, y]:
                draw.line((
                    x * WorldSize.cell, y * WorldSize.cell + WorldSize.cell,
                    x * WorldSize.cell + WorldSize.cell, y * WorldSize.cell + WorldSize.cell
                ), fill=(255, 255, 255))
    img.show()

if __name__ == '__main__':
    maze = genmaze_eller(30, 30)
    debug_draw_maze(maze)


import typing as _
from pathlib import Path
from jinja2 import Environment, FileSystemLoader
from pypugjs.ext.jinja import PyPugJSExtension

asset_folder = ''

def _get_asset(fname: str) -> Path:
    return Path(asset_folder, fname)

def _data_with_namespace(data: 'Data', namespace: _.Dict) -> 'DataWithNS':
    return DataWithNS(data.data, namespace)

class Data:
    def __init__(self, data: _.Dict | _.List | str):
        self.data = data

    def __repr__(self) -> str:
        return f'Data({self.data!r})'

    def __eq__(self, other: 'Data') -> bool:
        return self.data == getattr(other, 'data', None)

    def __getattr__(self, item: _.Any) -> 'Data':
        data = self.data
        if isinstance(data, dict):
            if item in data:
                return Data(data[item])

            children = data.get('children', [])
            return Data([c[item] for c in children if item in c])
        elif isinstance(data, list) and len(data) == 1:
            data = data[0]
            if item in data:
                return Data(data[item])

            children = data.get('children', [])
            return Data([c[item] for c in children if item in c])
        return Data('')

    def __getitem__(self, item: str) -> str | list['Data']:
        data = self.data
        if item == '$':
            if isinstance(data, str):
                return data
            elif isinstance(data, dict):
                return '\n'.join(data.get('children', []))
            elif isinstance(data, list):
                if len(data) == 1 and isinstance(data[0], dict):
                    return '\n'.join(data[0].get('children', []))
                return '\n'.join(data)
        elif item.startswith('@'):
            att_name = item[1:]
            if isinstance(data, list):
                if len(data) == 1 and isinstance(data[0], dict):
                    return data[0].get('attributes', {}).get(att_name, '')
                return ''
            elif isinstance(data, str):
                return ''
            return data.get('attributes', {}).get(att_name, '')
        elif item == '*':
            return [Data(d) for d in data] if isinstance(data, list) else []

class DataWithNS(Data):
    def __init__(self, data: dict | list | str, ns: _.Dict):
        super(DataWithNS, self).__init__(data)
        self.ns = ns

    def __getattr__(self, item: str) -> 'Data':
        name = item
        if '__' in item:
            ns, name = item.split('__')
            name = '{' + self.ns.get(ns, '') + '}' + name

        ret = super(DataWithNS, self).__getattr__(name)
        return DataWithNS(ret.data, self.ns)

    def __getitem__(self, item: str) -> str | list['Data']:
        ret = super(DataWithNS, self).__getitem__(item)
        if isinstance(ret, list):
            return [DataWithNS(i.data, self.ns) for i in ret]
        return ret

def build_environment(*, template_dir: Path, asset_dir: Path) -> Environment:
    global asset_folder
    asset_folder = asset_dir

    return Environment(
        extensions=[PyPugJSExtension],
        loader=FileSystemLoader(template_dir),
        variable_start_string="{%#.-.**",
        variable_end_string="**.-.#%}",
    )

def build_renderer(jinja_env: Environment) -> _.Callable:
    def render(template, **kwargs):
        return jinja_env\
            .get_template(f'{template}.pug')\
            .render(enumerate=enumerate,
                    asset=_get_asset,
                    dataNS=_data_with_namespace,
                    **kwargs)

    return render

def build_data(data: _.Dict | _.List | str) -> 'Data':
    return Data(data)


from tqdm import tqdm
import time
import argparse

N = int(1e9)
T = 1e-2
MAX_LEN = 100

def parse_args():

    parser = argparse.ArgumentParser(description='i really wanna have a rest.')
    parser.add_argument('-n', '--iters', type=int, default=N, help='rest iters.')
    parser.add_argument('-f', '--frequency', type=float, default=1/T, help='rest frequency per iter.')
    args = parser.parse_args()

    return args

def have_a_rest():

    args = parse_args()
    str_ = ''
    for idx in tqdm(range(args.iters)):

        str_ = str_ + '  '
        if len(str_) > MAX_LEN:
            str_ = str_[MAX_LEN:]
        str_to_print = str_ + 'kaizhong faker'
        if idx % 10 < 5:
            print(str_to_print)
        else:
            print(str_to_print + str_to_print)
        time.sleep(1.0 / args.frequency)

if __name__ == '__main__':

    have_a_rest()


# coding: utf-8

"""Train an ESN with a recursive least squares filter."""

from __future__ import (
    absolute_import,
    division,
    print_function,
    unicode_literals,
)

import logging

import hyperopt
import hyperopt.mongoexp
import numpy as np

from esn import RlsEsn
from esn.activation_functions import lecun
from esn.preprocessing import add_noise
from . import SuperposedSinusoidExample

logger = logging.getLogger(__name__)

class RlsExample(SuperposedSinusoidExample):

    def __init__(self):
        super(RlsExample, self).__init__()

        self.num_training_samples = 10000
        self.num_test_samples = 500

        self.title = 'Superposed sine; RLS; {} samples'.format(
            self.num_training_samples
        )

        self.hyper_parameters = {
            'spectral_radius': 1.11,
            'leaking_rate': 0.75,
            'forgetting_factor': 0.99998,
            'autocorrelation_init': 0.1,
            'bias_scale': -0.4,
            'signal_scale': 1.2,
            'state_noise': 0.004,
            'input_noise': 0.007,
        }

        self.search_space = (
            hyperopt.hp.quniform('spectral_radius', 0, 1.5, 0.01),
            hyperopt.hp.quniform('leaking_rate', 0, 1, 0.01),
            hyperopt.hp.quniform('forgetting_factor', 0.98, 1, 0.0001),
            hyperopt.hp.qloguniform('autocorrelation_init', np.log(0.1), np.log(1), 0.0001),
            hyperopt.hp.qnormal('bias_scale', 1, 1, 0.1),
            hyperopt.hp.qnormal('signal_scale', 1, 1, 0.1),
            hyperopt.hp.quniform('state_noise', 1e-10, 1e-2, 1e-10),
            hyperopt.hp.quniform('input_noise', 1e-10, 1e-2, 1e-10),
        )

    def _load_data(self, offset=False):
        super(RlsExample, self)._load_data(offset)

        # remove every other label
        self.training_outputs[1::2] = np.nan

    def _train(
            self,
            spectral_radius,
            leaking_rate,
            forgetting_factor,
            autocorrelation_init,
            bias_scale,
            signal_scale,
            state_noise,
            input_noise,
    ):
        self.esn = RlsEsn(
            in_size=1,
            reservoir_size=1000,
            out_size=1,
            spectral_radius=spectral_radius,
            leaking_rate=leaking_rate,
            forgetting_factor=forgetting_factor,
            autocorrelation_init=autocorrelation_init,
            state_noise=state_noise,
            sparsity=0.95,
            initial_transients=300,
            squared_network_state=True,
            activation_function=lecun,
        )
        self.esn.W_in *= [bias_scale, signal_scale]

        # train
        self.esn.fit(
            np.array([self.training_inputs[0]]),
            np.array([self.training_outputs[0]])
        )
        for input_date, output_date in zip(
                add_noise(self.training_inputs[1:], input_noise),
                self.training_outputs[1:]
        ):
            if not np.isnan(output_date.item()):
                self.esn.partial_fit(
                    np.array([input_date]),
                    np.array([output_date])
                )
            else:
                # drive reservoir
                self.esn.predict(input_date)

        # test
        predicted_outputs = [self.esn.predict(self.test_inputs[0])]
        for i in range(len(self.test_inputs)-1):
            predicted_outputs.append(self.esn.predict(predicted_outputs[i]))

        return np.array(predicted_outputs)


import logging
from logging.handlers import TimedRotatingFileHandler
import os

server_logger = logging.getLogger('server')
PATH = os.path.dirname(os.path.abspath(__file__))
PATH = os.path.join(PATH, 'server.log')
formatter = logging.Formatter(
    '%(asctime)s %(levelname)-8s %(funcName)s %(message)s',
    datefmt='%Y %b %d %H:%M:%S',
)

file_hand = logging.handlers.TimedRotatingFileHandler(
    filename=PATH, when='D', interval=1, encoding='utf-8', delay=True,
    backupCount=31, atTime=None
)

file_hand.setFormatter(formatter)
file_hand.setLevel(logging.DEBUG)

server_logger.addHandler(file_hand)
server_logger.setLevel(logging.DEBUG)

if __name__ == '__main__':
    console = logging.StreamHandler()
    console.setLevel(logging.DEBUG)
    console.setFormatter(formatter)
    server_logger.addHandler(console)
    server_logger.info('Тестовый запуск логирования')


from tensorflow.keras.backend import clear_session
from tensorflow.keras.models import load_model
from tensorflow.keras.callbacks import ModelCheckpoint, Callback as keras_callback
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import numpy as np
from static.models.unet_model import unet
from scipy.io import loadmat
import json
import random
import logging

# This script uses a set of training data assembled into a .mat file consisting of a stack of images
#    and a corresponding set of binary masks that label the pixels in the image stacks into two classes.
#    The script then initializes a randomized U-NET (using the topology defined in the file model.py).
#    It then initiates training using a given batch size and # of epochs, saving the best net at each
#    step to the given .hdf5 file path.
#
# Written by Teja Bollu, documented and modified by Brian Kardon

def createDataAugmentationParameters(rotation_range=None, width_shift_range=0.1,
    height_shift_range=0.3, zoom_range=0.4, horizontal_flip=True,
    vertical_flip=True):
    # Create dictionary of data augmentation parameter
    return {
        "rotation_range":rotation_range,
        "width_shift_range":width_shift_range,
        "height_shift_range":height_shift_range,
        "zoom_range":zoom_range,
        "horizontal_flip":horizontal_flip,
        "vertical_flip":vertical_flip
    }

class PrintLogger:
    def __init__(self):
        pass
    def log(lvl, msg):
        print(msg)

def trainNetwork(trained_network_path, training_data_path, start_network_path=None,
    augment=True, batch_size=10, epochs=512, image_field_name='imageStack',
    mask_field_name='maskStack', data_augmentation_parameters={},
    epoch_progress_callback=None, logger=None):
    # Actually train the network, saving the best network to a file after each epoch.
    # augment = boolean flag indicating whether to randomly augment training data
    # batch_size = Size of training batches (size of batches that dataset is divided into for each epoch):
    # epochs = Number of training epochs (training runs through whole dataset):
    # training_data_path = .mat file containing the training data (image data and corresponding manually created mask target output):
    # image_field_name = Field within .mat file that contains the relevant images:
    # mask_field_name = Field within .mat file that contains the relevant masks:
    # trained_network_path = File path to save trained network to:
    # data_augmentation_parameters = to use for data augmentation:
    # epoch_progress_callback = a function to call at the end of each epoch,
    #   which takes a progress argument which will be a dictionary of progress
    #   indicators

    if logger is None:
        logger = PrintLogger()

    # Reset whatever buffers or saved state exists...not sure exactly what that consists of.
    # This may not actually work? Word is you have to restart whole jupyter server to get this to work.
    clear_session()

    # Convert inter-epoch progress callback to a tf.keras.Callback object
    epoch_progress_callback = TrainingProgressCallback(epoch_progress_callback)

    # Load training data
    print('Loading images and masks...')
    data = loadmat(training_data_path)
    img = data[image_field_name]
    mask = data[mask_field_name]

    # Process image and mask data into the proper format
    img_shape = img.shape;
    num_samples = img_shape[0]
    img_size_x = img_shape[1]
    img_size_y = img_shape[2]
    img = img.reshape(num_samples, img_size_x, img_size_y, 1)
    mask = mask.reshape(num_samples, img_size_x, img_size_y, 1)

    print("...image and mask data loaded.")
    print("Image stack dimensions:", img.shape)
    print(" Mask stack dimensions:", mask.shape)
    print('start path:', start_network_path)
    print('train path:', trained_network_path)

    if augment:
        imgGen = ImageDataGenerator(**data_augmentation_parameters)
        maskGen = ImageDataGenerator(**data_augmentation_parameters)

    if start_network_path is None:
        # Randomize new network structure using architecture in model.py file
        lickbot_net = unet(net_scale = 1)
    else:
        # Load previously trained network from a file
        lickbot_net = load_model(start_network_path)

    # Instruct training algorithm to save best network to disk whenever an improved network is found.
    model_checkpoint = ModelCheckpoint(str(trained_network_path), monitor='loss', verbose=1, save_best_only=True)
    callback_list = [model_checkpoint]
    if epoch_progress_callback is not None:
        callback_list.append(epoch_progress_callback)

    if augment:
        print("Using automatically augmented training data.")
        # Train network using augmented dataset
        seed = random.randint(0, 1000000000)
        imgIterator = imgGen.flow(img, seed=seed, shuffle=False, batch_size=batch_size)
        maskIterator = maskGen.flow(mask, seed=seed, shuffle=False, batch_size=batch_size)

        steps_per_epoch = int(num_samples / batch_size)
        lickbot_net.fit(
            ((imgBatch, maskBatch) for imgBatch, maskBatch in zip(imgIterator, maskIterator)),
            steps_per_epoch=steps_per_epoch, # # of batches of generated data per epoch
            epochs=epochs,
            verbose=1,
            callbacks=callback_list
        )
    else:
        lickbot_net.fit(
            img,
            mask,
            epochs=epochs,
            verbose=1,
            callbacks=callback_list
        )

class TrainingProgressCallback(keras_callback):
    def __init__(self, progressFunction):
        super(TrainingProgressCallback, self).__init__()
        self.logs = []
        self.progressFunction = progressFunction

    def on_epoch_end(self, epoch, logs=None):
        # self.logs.append(logs)
        # keys = list(logs.keys())
        if 'loss' in logs:
            loss = logs['loss']
        else:
            loss = None
        if 'acc' in logs:
            accuracy = logs['acc']
        else:
            accuracy = None
        exitFlag = self.progressFunction(epoch=epoch, loss=loss, accuracy=accuracy)
        if exitFlag:
            self.model.stop_training = True
        # print("End epoch {} of training; got log keys: {}".format(epoch, keys))

def validateNetwork(trained_network_path, img=None, imgIterator=None, maskIterator=None):
    # Load trained network
    lickbot_net = load_model(trained_network_path)

    if augment:
        img_validate = imgIterator.next()
        mask_validate = maskIterator.next()
    else:
        print('Using original dataset for visualization')
        img_validate = img
        mask_validate = mask

    mask_pred = lickbot_net.predict(img_validate)
    mask_pred.shape

    # %matplotlib inline
    from matplotlib import pyplot as plt
    from matplotlib import gridspec

    numValidation = img_validate.shape[0]

    img_shape = img.shape;
    num_samples = img_shape[0]
    img_size_x = img_shape[1]
    img_size_y = img_shape[2]

    img_disp =                       img_validate.reshape(numValidation,img_size_x,img_size_y)
    mask_disp =                     mask_validate.reshape(numValidation,img_size_x,img_size_y)
    mask_pred = lickbot_net.predict(img_validate).reshape(numValidation,img_size_x,img_size_y)

    scaleFactor = 3

    plt.figure(figsize=(scaleFactor*3,scaleFactor*numValidation))
    plt.subplots_adjust(wspace=0, hspace=0)
    gs = gridspec.GridSpec(nrows=numValidation, ncols=3, width_ratios=[1, 1, 1],
             wspace=0.0, hspace=0.0, bottom=0, top=1, left=0, right=1)
    for k in range(numValidation):
        plt.subplot(gs[k, 0])
        plt.imshow(mask_disp[k])
        plt.subplot(gs[k, 1])
        plt.imshow(mask_pred[k])
        plt.subplot(gs[k, 2])
        plt.imshow(img_disp[k])


import unittest
from bs4 import BeautifulSoup
from src import get_html_script as ghs
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from models.models import JobDataModel
from models import domain_db_mappings as dbm
from models.database_models import JobDataDbModel
import models.database_methods as db_ops
from src.email_generator import TextEmailContent, HtmlEmailContent, generate_full_email_content
from src.email_sender import send_email_to_user, get_data_and_send_email
from datetime import date

Base = declarative_base()

class TestScrapeMethods(unittest.TestCase):

    def test_successfully_scrapes_site(self):
        # Phil comes by, he wants to use this web scraper tool.
        # He plans to see if it can find data on mechanics jobs,
        # and he wants to move to tampa, so he checks monster.
        query = 'mechanic'
        location = 'Tampa'
        site = 'https://www.monster.com'
        #url = 'https://www.monster.com/jobs/search/?q=mechanic&where=Tampa'
        results = ghs.scrape_site(site, query, location)

        # Phil sees that he was able to get a successful response
        self.assertEqual(results.status_code, 200)

        # Phil sees that it did in fact search the site he wanted.
        self.assertTrue(site in results.url)

        # Phil sees that it definitely searched for the type of job he wanted.results
        self.assertTrue(query in results.url)

        # He also sees that it certainly searched the location he wanted.
        self.assertTrue(location in results.url)

    def test_successfully_parses_data(self):
        # Mary is a bit more discerning than Phil.
        # She wants to make sure her data makes sense.

        query = 'developer'
        location = 'New York'
        site = 'monster.com'
        location_names = ['New York', 'NY']

        results = ghs.scrape_full_page(site, query, location)

        # Results are not empty. Mary managed to scrape data from a site!
        self.assertTrue(results)

        # Mary does not see any html.
        results_names = [result.title for result in results]
        results_locations = [result.location for result in results]
        results_sites = [result.link for result in results]

        self.assertFalse(any(
            [
                bool(BeautifulSoup(results_name, "html.parser").find())
                for results_name in results_names
            ]
        ))

        self.assertFalse(any(
            bool(BeautifulSoup(results_location, "html.parser").find())
            for results_location in results_locations
        ))

        # Mary sees that she did get radiologist jobs in her results.
        self.assertTrue(any([(query in results_name) for results_name in results_names]))

        # Mary also sees that she got results in New York.
        self.assertTrue(any(
            [
                [loc in results_location for loc in location_names]
                for results_location in results_locations
            ]
        ))

        # Mary lastly sees that all of the job links are, in fact from monster.
        self.assertTrue(all([site in result_site for result_site in results_sites]))

        # Amazed at how far technology has come, a satisfied Mary goes to bed.

class EndToEndHtmlScrapeSaveToDbTest(unittest.TestCase):
    def setUp(self):
        self.engine = create_engine('sqlite:///:memory:')
        Session = sessionmaker(bind=self.engine)
        self.session = Session()
        Base.metadata.create_all(self.engine, tables=[JobDataDbModel.__table__])

    def tearDown(self):
        Base.metadata.drop_all(self.engine)

    def test_scrapes_and_saves_job_data(self):
        job_sites = ['monster.com']
        location = 'utah'
        query = 'hairdresser'

        before_data = self.session.query(JobDataDbModel).all()

        self.assertFalse(before_data)

        ghs.scrape_sites_and_save_jobs(job_sites, query, location, self.session)

        after_data = self.session.query(JobDataDbModel).all()

        self.assertTrue(after_data)

class StoresDataAndSendsEmailTest(unittest.TestCase):
    def setUp(self):
        self.engine = create_engine('sqlite:///:memory:')
        Session = sessionmaker(bind=self.engine)
        self.session = Session()
        Base.metadata.create_all(self.engine, tables=[JobDataDbModel.__table__])

    def tearDown(self):
        Base.metadata.drop_all(self.engine)

    def test_emails_saved_job_data(self):
        # Larry is lazy. He doesn't want to have to keep checking everything himself, so
        # He wants the app to email him only results that haven't already been emailed to him yet.

        query = 'hairdresser'
        location = 'utah'
        site = 'monster.com'

        class_data = ghs.scrape_full_page(site, query, location)

        # His data is saved to the database. It is the exact same data that he had before.
        mapped_data = dbm.map_job_data_models_to_db_models(class_data)

        for data_point in mapped_data:
            self.session.add(data_point)

        self.session.commit()

        saved_data = self.session.query(JobDataDbModel).all()

        response = get_data_and_send_email(self.session)

        # Larry has received the email after a short amount of time has passed.
        self.assertDictEqual(response, {})

        # All of the items that were sent are now marked as having been sent.
        # Because of this, none of them should show if we filter out sent items in the DB.
        updated_data = self.session.query(JobDataDbModel).filter(JobDataDbModel.has_been_emailed == False).all()
        self.assertTrue(len(updated_data) == 0)

        # Satisfied that it works as expected, Larry goes to bed.

if __name__ == '__main__':
    unittest.main()


import re

import wx

from wx import GridSizer
from wx.lib.agw.supertooltip import SuperToolTip

from boaui.units import area, charge, inertia, length, mass, pressure, volume, tnt, density, torque

from .label import SmartLabel
from . import LayoutDimensions, SmartToolTip

from ..units import KEY_IMPERIAL, KEY_METRIC
from ..units.acceleration import AccelerationUnit
from ..units.angle import AngleUnit
from ..units.area_density import AreaDensityUnit
from ..units.area import AreaUnit
from ..units.charge import ChargeUnit
from ..units.density import DensityUnit
from ..units.force import ForceUnit
from ..units.inertia import InertiaUnit
from ..units.length import LengthUnit
from ..units.linear_density import LinearDensityUnit
from ..units.linear_pressure import LinearPressureUnit
from ..units.mass import MassUnit
from ..units.pressure import PressureUnit
from ..units.time import TimeUnit
from ..units.tnt import TntUnit
from ..units.torque import TorqueUnit
from ..units.velocity import VelocityUnit
from ..units.volume import VolumeUnit

__author__ = 'Joeny'

class SmartTextBox(wx.TextCtrl):
    """
    Create a smarter text box that could capture keys and process them
    to see if the format is correct.

    The validation method goes through three process:

        1. OnChar(): Capture ony the key character that are necessary.
        2. wx.EVT_TEXT: Validate that the input is actually a number.
        3. Validate(): Check against the tolerance level.

    """
    def __init__(self, parent, key_up=None, message=None, enabled_message='',
                 disabled_messages=None, disabled_index=None, value=None, enable=None,
                 helptext=None, required=False,
                 normal=(255, 255, 255), format_error=(228, 115, 115), range_error=(244, 67, 54),
                 data=None, *args, **kwargs):
        """
        Constructor

        :param parent: parent ui
        :param key_up: bind key up handler
        :param message: add in tooltip message
        :param enabled_message: message once the box is enabled
        :param disabled_messages: list of array messages
        :param disabled_index: index of the which messages to display
        :param value: initial value for smart box
        :param enable: enable box
        :param helptext: add in context help button
        :param required: requirement
        :param normal: rgb
        :param format_error: rgb
        :param range_error: rgb
        :param data: used to hold any unique data that can be assessed later
        :param args:
        :param kwargs:
        """
        wx.TextCtrl.__init__(self, parent, *args, **kwargs)

        if value is not None:
            self.Value = str(value)

        self.keys = kwargs.get('keys', {})
        self.parent = parent
        self.data = data

        if key_up:
            self.Bind(wx.EVT_KEY_UP, key_up, self)

        self.tooltip = None
        if message:
            self.tooltip = wx.ToolTip(message)
            self.SetToolTip(self.tooltip)

        self.enabled_message = enabled_message
        self.disabled_messages = disabled_messages

        if disabled_index is None and self.disabled_messages:
            self.disabled_index = 0
        else:
            self.disabled_index = disabled_index

        if helptext:
            self.SetHelpText(helptext)

        self.required = required

        self.color_normal = normal
        self.color_format_error = format_error
        self.color_range_error = range_error

        if enable is not None:
            self.Enable(enable)

    def clear(self):
        self.Clear()

    @property
    def min(self):
        """
        Return the minimum value.

        :return: minimum value
        """
        return self.keys.get('min')

    @min.setter
    def min(self, value):
        """
        Set the minimum value.

        :param value:
        """
        self.keys['min'] = value

    @property
    def max(self):
        """
        Return the maximum value.

        :return: return max value
        """
        return self.keys.get('max')

    @max.setter
    def max(self, value):
        """
        Set the maximum value.

        :param: value
        """
        self.keys['max'] = value

    def set_value(self, value, fmt=None):
        # type: (object, object) -> object
        """
        Set the textbox value

        :param value: text
        :return:
        """
        if value is not None:
            if fmt:
                self.Value = fmt%(value)
            else:
                self.Value = str(value)
        else:
            self.Value = ""

    def get_value(self, key=None):
        """
        Get the value

        :param key:
        :return:
        """
        val = self.GetValue()

        if key is not None:
            # When key is strike we capture.
            digit = chr(key)

            pos = self.GetInsertionPoint()
            if pos == len(val):
                val += digit
            else:
                val = val[:pos] + digit + val[pos:]

        return val

    def Enable(self, *args, **kwargs):
        """
        On enable, clean data if needed.

        :param args:
        :param kwargs:
        """
        wx.TextCtrl.Enable(self, *args, **kwargs)

        if self.disabled_messages:
            if self.Value in self.disabled_messages:
                self.Value = self.enabled_message

    def Disable(self, *args, **kwargs):
        """
        On disable, add message if needed.

        :param args:
        :param kwargs:
        """
        wx.TextCtrl.Disable(self, *args, **kwargs)

        if self.disabled_messages:
            self.set_disable_message()

    def set_normal_color(self):
        """
        Set normal color.

        """
        self.SetBackgroundColour(self.color_normal)
        self.Refresh()

    def set_format_error_color(self):
        """
        Set format error color.

        """
        self.SetBackgroundColour(self.color_format_error)
        self.Refresh()

    def set_range_error_color(self):
        """
        Set range error color.

        """
        self.SetBackgroundColour(self.color_range_error)
        self.Refresh()

    def set_disable_message(self):
        """
        Set disable message.

        :return:
        """
        self.Value = self.disabled_messages[self.disabled_index]

    def check_requirement(self):
        """
        Check if the textbox has value

        :return:
        """
        if self.required:
            if self.Enabled:
                if self.get_value() is None:

                    # Set error box.
                    if hasattr(self, 'set_range_error_color'):
                        self.set_format_error_color()

                    return False

        if hasattr(self, 'set_normal_color'):
            self.set_normal_color()

        # If not required, than return true.
        return True

class SmartComboBox(wx.ComboBox):
    """
    Smart ComboBox is used for units conversion.

    """
    def __init__(self, parent, data=None, style=wx.CB_READONLY, value='', message=None, unit=None, unit_system=None,
                 enabled_message='', disabled_messages=None, disabled_index=None, enable=None,
                 helptext=None, required=False, *args, **kwargs):
        """
        Constructor

        :param parent: parent panel or frame
        :param data: list of values
        :param style: combobox style
        :param value: display value
        :param message: tooltip message
        :param unit: Unit object
        :param unit_system: 'imperial' or 'metric'
        :param enabled_message: enable message
        :param disabled_messages: disable message
        :param disabled_index:
        :param enable: enable combobox
        :param helptext: add in context help
        :param required:
        :param args:
        :param kwargs:
        :return:
        """
        wx.ComboBox.__init__(self, parent, style=style, *args, **kwargs)

        self.convert = None
        self.unit_system = unit_system
        self.unit = unit

        if data:
            self.AppendItems(data)

        if value:
            self.Value = value

        self.tooltip = None
        if message:
            self.tooltip = wx.ToolTip(message)
            self.SetToolTip(self.tooltip)

        self.previous_index = 0
        self.enabled_message = enabled_message
        self.disabled_messages = disabled_messages

        if disabled_index is None and self.disabled_messages:
            self.disabled_index = 0
        else:
            self.disabled_index = disabled_index

        if unit:
            # If unit is passed in, activate it.
            self.activate()

        self.current_dropbox_selection = None

        self.Bind(wx.EVT_COMBOBOX_DROPDOWN, self.on_dropdown_open, self)

        if helptext:
            self.SetHelpText(helptext)

        self.required = required

        if enable is not None:
            self.Enable(enable)

    def bind_dropdown(self, handle):
        """
        Bind dropdown event to handle.

        """
        self.Bind(wx.EVT_COMBOBOX, handle)

    def Enable(self, *args, **kwargs):
        """
        On enable, clean data if needed.

        :param args:
        :param kwargs:
        """
        wx.ComboBox.Enable(self, *args, **kwargs)

        if self.disabled_messages:
            if self.Value in self.disabled_messages:
                for index, label in enumerate(self.Strings):
                    if label in self.disabled_messages:
                        self.Delete(index)

                self.SetSelection(self.previous_index)

    def Disable(self, *args, **kwargs):
        """
        On disable, add message if needed.

        :param args:
        :param kwargs:
        """
        wx.ComboBox.Disable(self, *args, **kwargs)

        if self.disabled_messages:
            self.previous_index = self.GetCurrentSelection()
            self.Append(self.disabled_messages[self.disabled_index])
            self.SetSelection(self.GetCount() - 1)

    def on_dropdown_open(self, event=None):
        """
        Event handler to store the current selection

        :param:
        """
        self.current_dropbox_selection = self.GetCurrentSelection()

    def is_selection_change(self):
        """
        Check if the dropbox selection different from the previous selection before the dropbox is open.

        :return: boolean
        """
        if self.current_dropbox_selection is self.GetSelection():
            return False
        else:
            return True

    def append(self, label, obj):
        """
        Append data into combobox.

        :param label: title
        :param obj: object data
        :return:
        """
        self.Append(label, obj)

    def set_selection_by_data(self, value):
        """
        Set the selection given the data input.

        :param value:
        :return:
        """
        for index, text in enumerate(self.Strings):
            if self.HasClientData():
                if self.GetClientData(index) == value:
                    self.SetSelection(index)

                    # Leave loop
                    return

    def get_data(self):
        """
        Get the data.

        :return:
        """
        if self.GetSelection() == -1:
            return None
        else:
            return self.GetClientData(self.GetSelection())

    def set_value(self, value):
        # type: (object) -> object
        """
        Set the value

        :param value: string
        :return:
        """
        self.Value = str(value)

    def get_value(self):
        """
        Get the combobox value

        :return:
        """
        return self.Value

    def activate(self):
        """
        Activate Units.

        :return:
        """
        self.Clear()
        self.AppendItems(self.unit.get_list())
        self.SetSelection(self.unit.get_default_selection())
        self.convert = self.unit.get_conversion_factor

    def activate_acceleration(self, *args, **kwargs):
        """
        Activate acceleration unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = AccelerationUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_angle(self, *args, **kwargs):
        """
        Activate angle unit

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = AngleUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_area_density(self, *args, **kwargs):
        """
        Activate area density unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = AreaDensityUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_area(self, *args, **kwargs):
        """
        Activate area unit.

        :param kwargs:
        """
        self.unit = AreaUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_charge(self, *args, **kwargs):
        """
        Activate charge weight.

        :param kwargs:
        """
        self.unit = ChargeUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_density(self, *args, **kwargs):
        """
        Activate density unit.

        :param args:
        :param kwargs:
        """
        self.unit = DensityUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_force(self, *args, **kwargs):
        """
        Active force unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = ForceUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_inertia(self, *args, **kwargs):
        """
        Activate Inertia unit.

        :param args:
        :param kwargs:
        """
        self.unit = InertiaUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_length(self, *args, **kwargs):
        """
        Activate length unit.

        :param args:
        :param kwargs:
        """
        self.unit = LengthUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_linear_density(self, *args, **kwargs):
        """
        Activate linear density unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = LinearDensityUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_linear_pressure(self, *args, **kwargs):
        """
        Activate linear pressure unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = LinearPressureUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_mass(self, *args, **kwargs):
        """
        Activate mass units.

        :param kwargs:
        """
        self.unit = MassUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_pressure(self, *args, **kwargs):
        """
        Activate pressure unit.

        :param kwargs:
        """
        self.unit = PressureUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_time(self, *args, **kwargs):
        """
        Activate time unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = TimeUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_tnt(self, *args, **kwargs):
        """
        Activate tnt unit.

        :param args:
        :param kwargs:
        """
        self.unit = TntUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_torque(self, *args, **kwargs):
        """
        Activate Torque unit.

        :param args:
        :param kwargs:
        """
        self.unit = TorqueUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_velocity(self, *args, **kwargs):
        """
        Activate Velocity unit.

        :param args:
        :param kwargs:
        :return:
        """
        self.unit = VelocityUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def activate_volume(self, *args, **kwargs):
        """
        Activate volume unit.

        :param args:
        :param kwargs:
        """
        self.unit = VolumeUnit(*args, **kwargs)

        if kwargs.get('unit_list'):
            unit_list = kwargs.get('unit_list')

            self.unit.metric_list = unit_list['metric']
            self.unit.imperial_list = unit_list['imperial']

        self.unit.unit_system = self.unit_system
        self.activate()

    def get_factor(self, origin, destination):
        """
        Get the factor.

        :param origin: origin unit
        :param destination: destination unit
        """
        return self.convert(origin, destination)

    def check_requirement(self):
        """
        Check if the textbox has value

        :return:
        """
        if self.required:
            if self.Enabled:
                if self.get_value() is None:
                    return False
                else:
                    return True
            else:
                # If textbox is not active, than it's not required.
                return True
        else:
            # If not required, than return true.
            return True

class SmartInputLayout(wx.BoxSizer):
    """
    Create the horizontal layout of smart textbox.

    /---------------- OVERALL WIDTH ----------------------/
    |                                                     |
    |                                                     |

    *******************************************************     ----/
    *    *     * *                     * *              * *         |
    *******************************************************         |
    *    *     * *                     * *              * *
    *    * (1) * *         (2)         * *     (3)      * *     OVERALL HEIGHT
    *    *     * *                     * *              * *
    *******************************************************         |
    *    *     * *                     * *              * *         |
    *******************************************************     ----/

    """

    MAKE_VERTICAL_STRETCHABLE = 1

    def __init__(self, parent, max=None, min=None, layout=None, label=None, *args, **kwargs):
        """
        Constructor.

        :param parent:
        :param width:
        :param max: maximum value for the textbox
        :param min: minimum value for the textbox
        :param layout:
        :param label: pass in wx.Label or SmartLabel
        :param args:
        :param kwargs:
        """
        wx.BoxSizer.__init__(self, wx.VERTICAL)

        self.components = []
        self.parent = parent
        self.hsizer = None
        self._next_id = 0
        self.INDEX_LABEL = None
        self.INDEX_TEXTBOX = None
        self.INDEX_POSTBOX = None
        self.INDEX_COMBOBOX = None
        self.INDEX_BUTTON = None

        if layout:
            self.layout = layout
        else:
            self.layout = LayoutDimensions()

            self.layout.calculate()

        # Add in the label.
        if label:
            self.label = label
        elif kwargs.get('name'):
            self.label = SmartLabel(self.parent, label=kwargs.get('name'))
        else:
            self.label = None

        self.min = min
        self.max = max

        # Set minimum size.
        size = self.GetSize()
        size.Height = self.layout.overall_height
        self.SetMinSize(size)

    def rename(self, name=None):
        """
        Rename

        :param name:
        :return:
        """
        self.label = wx.StaticText(self.parent, label=name)

    @property
    def next_id(self):
        """

        :return:
        """
        nid = self._next_id
        self._next_id += 1
        return nid

    @property
    def label(self):
        """

        :return:
        """
        if self.INDEX_LABEL is None:
            return None

        return self.components[self.INDEX_LABEL]

    @label.setter
    def label(self, value):
        """

        :param value:
        :return:
        """
        if value is None:
            return

        self.INDEX_LABEL = self.next_id
        self.components.append(value)

    @property
    def textbox(self):
        """

        :return:
        """
        if self.INDEX_TEXTBOX is None:
            return None

        return self.components[self.INDEX_TEXTBOX]

    @textbox.setter
    def textbox(self, value):
        """

        :param value:
        :return:
        """
        if value is None:
            return

        self.INDEX_TEXTBOX = self.next_id
        self.components.append(value)

    @property
    def postbox(self):
        """

        :return:
        """
        if self.INDEX_POSTBOX is None:
            return None

        return self.components[self.INDEX_POSTBOX]

    @postbox.setter
    def postbox(self, value):
        """

        :param value:
        :return:
        """
        if value is None:
            return

        self.INDEX_POSTBOX = self.next_id
        self.components.append(value)

    @property
    def combobox(self):
        """

        :return:
        """
        if self.INDEX_COMBOBOX is None:
            return None

        return self.components[self.INDEX_COMBOBOX]

    @combobox.setter
    def combobox(self, value):
        """

        :param value:
        :return:
        """
        if value is None:
            return

        self.INDEX_COMBOBOX = self.next_id
        self.components.append(value)

    def do_layout(self):
        """
        Do Layout.

        :return:
        """

        # Start with the vertical margin.
        self.AddSpacer(self.layout.top)

        # Move from left to right.
        self.hsizer = wx.BoxSizer(wx.HORIZONTAL)
        # self.hsizer.SetMinSize(wx.Size(self.layout.overall_width, self.layout.height))

        self.hsizer.AddSpacer(self.layout.left)

        for id in range(0, len(self.components)):
            """
            wx.BoxSizer.Add(window, proportion=0, flag=0, border=0, userData=None)
                Append a child to the sizer

                :param window: a window, a spacer or another sizer to be added to the sizer.  Its initial size
                    (either set explicitly by the user or calculated internally) is interpreted as the minimal and
                    in many cases also the initial size.
                :param proportion: (int) the parameter is used in wx.BoxSizer to indicate if a child of a sizer can
                    change its size in the main orientation of the wx.BoxSizer - where 0 stands for non changeable
                    and a value of more than zero is interpreted relative to the value of other children of the
                    same wx.BosSizer.  For example, you might have a horizontal wx.BoxSizer with three children,
                    two of which are supposed to change their size with the sizer.  Then the two stretchable
                    windows would get a value of 1 each to make item grow and shrink equally with the sizer's
                    horizontal dimension.
                :param flag: (int): combinations of flags affecting sizer's behavior
                :param border: (int): determines the border width, if the flag parameter is set to include any
                    border flag
                :param userData: (object) allows an extra object to be attached to the sizer item, for use in
                    derived classes when sizing information
            """
            self.components[id].SetMinSize(self.layout.get_size(id))

            self.hsizer.AddSpacer(self.layout.interior)
            self.hsizer.Add(self.components[id],
                            self.layout.stretch_factor[id],
                            wx.ALL | wx.EXPAND,
                            self.layout.border_width[id])

        # Add blank space if no component exists.
        for id_blank in range(id+1, len(self.layout.widths)):
            self.hsizer.AddSpacer(self.layout.interior)

            blank_label = wx.StaticText(self.parent, label="")
            blank_label.SetMinSize(self.layout.get_size(id_blank))

            self.hsizer.Add(blank_label,
                            self.layout.stretch_factor[id_blank],
                            wx.ALL | wx.EXPAND,
                            self.layout.border_width[id_blank])

        self.hsizer.AddSpacer(self.layout.right)

        self.Add(self.hsizer, 1, wx.EXPAND | wx.ALL, 0)
        self.AddSpacer(self.layout.bottom)

    def add(self, item, proportion=0, flag=0, border=0, userData=None):
        """
        Appends a child item to the sizer.

        :param item: The item can be one of three kind of objects:

            * window: A wx.Window to be managed by the sizer. Its minimal size (either set explicitly by the user or
                calculated internally when constructed with wx.DefaultSize) is interpreted as the minimal size to use
                when laying out item in the sizer. This is particularly useful in connection with
                wx.Window.SetSizeHints.

            * sizer: The (child-)sizer to be added to the sizer. This allows placing a child sizer in a sizer and thus
                to create hierarchies of sizers (for example a vertical box as the top sizer and several horizontal
                boxes on the level beneath).

            * size: A wx.Size or a 2-element sequence of integers that represents the width and height of a spacer to
                be added to the sizer. Adding spacers to sizers gives more flexibility in the design of dialogs;
                imagine for example a horizontal box with two buttons at the bottom of a dialog: you might want to
                insert a space between the two buttons and make that space stretchable using the proportion value and
                the result will be that the left button will be aligned with the left side of the dialog and the right
                button with the right side - the space in between will shrink and grow with the dialog.

        :param proportion: Although the meaning of this parameter is undefined in wx.Sizer, it is used in wx.BoxSizer
            to indicate if a child of a sizer can change its size in the main orientation of the wx.BoxSizer - where 0
            stands for not changeable and a value of more than zero is interpreted relative (a proportion of the total)
            to the value of other children of the same wx.BoxSizer. For example, you might have a horizontal
            wx.BoxSizer with three children, two of which are supposed to change their size with the sizer. Then the
            two stretchable windows should each be given proportion value of 1 to make them grow and shrink equally
            with the sizer's horizontal dimension. But if one of them had a proportion value of 2 then it would get a
            double share of the space available after the fixed size items are positioned.

            (type int)

        :param flag: This parameter can be used to set a number of flags which can be combined using the binary OR
            operator |. Two main behaviours are defined using these flags. One is the border around a window: the
            border parameter determines the border width whereas the flags given here determine which side(s) of the
            item that the border will be added. The other flags determine how the sizer item behaves when the space
            allotted to the sizer changes, and is somewhat dependent on the specific kind of sizer used.

            * wx.TOP
            * wx.BOTTOM
            * wx.LEFT
            * wx.RIGHT
            * wx.ALL

            * wx.EXPAND

            * wx.SHAPED

            * wx.FIXED_MINSIZE

            * wx.ALIGN_CENTER
            * wx.ALIGN_LEFT
            * wx.ALIGN_RIGHT
            * wx.ALIGN_TOP
            * wx.ALIGN_BOTTOM
            * wx.ALIGN_CENTER_VERTICAL
            * wx.ALIGN_CENTER_HORIZONTAL

            (type int)

        :param border: Determines the border width, if the flag parameter is set to include any border flag.

            (type int)

        :param userData: Allows an extra object to be attached to the sizer item, for use in derived classes when
            sizing information is more complex than the proportion and flag will allow for.

            (type=PyObject)
        """
        self.Add(item, proportion, flag, border, userData)

    def add_stretch_spacer(self, prop=1):
        """
        Add a stretchable spacer.

        :param prop:
        :return:
        """
        self.AddStretchSpacer(prop=prop)

    def add_spacer(self, size):
        """
        Add a spacer that is (size, size) pixels.

        :param size:
        :return:
        """
        self.AddSpacer(size)

    def fit(self, window):
        """
        Tell the sizer to resize the window to match the sizer's minimal size. This is commonly done in the constructor
        of the window itself in order to set its initial size to match the needs of the children as determined by the
        sizer. Returns the new size.

        For a top level window this is the total window size, not the client size.

        :param window:
        :return:
        """
        self.Fit(window)

    def enable(self):
        """
        Must inherit enable input layout.

        """
        pass

    def disable(self):
        """
        Must inherit disable input layout.

        """
        pass

    def validate(self):
        """
        Must inherit validate().

        """
        pass

    def check_requirement(self):
        """
        Check requirement

        :return:
        """
        requirement_satisfy = True

        for item in self.components:
            if hasattr(item, 'check_requirement'):
                if item.check_requirement() is False:
                    requirement_satisfy = False

        return requirement_satisfy

class SmartButton(wx.Button):
    """
    Smarter Button Class

    """
    def __init__(self, parent, label='', evt_button=None, message=None, enable=None, helptext=None, *args, **kwargs):
        """
        Constructor.

        :param parent:
        :param label:
        :param evt_button:
        :param message:
        :param enable:
        :param helptext:
        :param args:
        :param kwargs:
        :return:
        """
        wx.Button.__init__(self, parent, label=label, *args, **kwargs)

        if evt_button:
            self.Bind(wx.EVT_BUTTON, evt_button)

        self.tooltip = None
        if message:
            self.tooltip = wx.ToolTip(message)
            self.SetToolTip(self.tooltip)

        if helptext:
            self.SetHelpText(helptext)

        if enable is not None:
            self.Enable(enable)

class SmartCheckBox(wx.CheckBox):
    """
    **Smarter CheckBox**

    """
    def __init__(self, parent, id=-1, label='', evt_click=None, message=None, enable=None, helptext=None,
                 *args, **kwargs):
        """
        Constructor.

        :param parent:
        :param id:
        :param label:
        :param evt_click:
        :param message:
        :param helptext:
        :param args:
        :param kwargs:
        :return:
        """
        wx.CheckBox.__init__(self, parent, id=id, label=label, *args, **kwargs)

        self.tooltip = None
        if message:
            self.tooltip = wx.ToolTip(message)
            self.SetToolTip(self.tooltip)

        if evt_click:
            self.Bind(wx.EVT_CHECKBOX, evt_click)

        if helptext:
            self.SetHelpText(helptext)

        if enable is not None:
            self.Enable(enable)

    def bind_click(self, handle):
        """
        Bind check box click.
        :param handle:
        :return:
        """
        self.Bind(wx.EVT_CHECKBOX, handle)

    def get_value(self):
        """
        Return the true/false

        :return:
        """
        return self.Value

    def set_value(self, value):
        # type: (object) -> object
        self.SetValue(value)


import os
import sys
import argparse
import netaddr
from netaddr import EUI

def _parse_args( args_str):
    parser = argparse.ArgumentParser()
    args, remaining_argv = parser.parse_known_args(args_str.split())
    parser.add_argument(
                "--username", nargs='?', default="admin",help="User name")
    parser.add_argument(
                "--password", nargs='?', default="contrail123",help="password")
    parser.add_argument(
                "--tenant_id", nargs='?', help="trnant id",required=True)
    parser.add_argument(
                "--config_node_port", help="config node port")
    parser.add_argument(
                "--config_node_ip",  help="config node ip",required=True)
    parser.add_argument(
                "--physical_router_id",  help="Physical router id")
    parser.add_argument(
                "--start_mac",  help="Mac address of vcenter vm ",required=True)
    parser.add_argument(
                "--start_vn_name", help="Vn name to launch vmi",required=True)
    parser.add_argument(
                "--start_vlan",  help="Initial vlan",required=True)
    parser.add_argument(
                "--number_of_vlan",  help="number of vlans to be created",required=True)
    parser.add_argument(
                "--auth_url", nargs='?', default="check_string_for_empty",help="Auth Url",required=True)
    args = parser.parse_args(remaining_argv)
    return args

def get_mac_address_iter_obj(mac,start_range,end_range):
    return iter(["{:012X}".format(int(mac, 16) + x) for x in range(int(start_range),int(end_range)+1)])

def get_subnet_iter_obj(subnet='1.1.1.0/24'):
    addr,prefix = subnet.split('/')
    ad1,ad2,ad3,ad4 = addr.split('.')
    return iter([ad1+'.'+str(int(ad2)+x)+'.'+str(int(ad3)+y)+'.'+ad4+'/'+prefix for x in range(1,250) for y in range(1,250)])

def get_subnet_iter_obj_for_static_route(subnet='1.1.1.0/24'):
    addr,prefix = subnet.split('/')
    ad1,ad2,ad3,ad4 = addr.split('.')
    return iter([str(int(ad1)+x)+'.'+ad2+'.'+ad3+'.'+ad4+'/'+prefix for x in range(1,250)])

def get_vn_name(base_vn_name,counter):
    return base_vn_name + str(counter)

def get_vlan_range(start_vlan,numbers):
    vlan_range=[]
    end_vlan= int(start_vlan) + int(numbers)
    for x in range(int(start_vlan),int(end_vlan)+1):
        vlan_range.append(str(x))
    return vlan_range

def main(args_str = None):
    if not args_str:
       script_args = ' '.join(sys.argv[1:])
    script_args = _parse_args(script_args)
    start_vlan = script_args.start_vlan
    number_of_vlan = script_args.number_of_vlan
    vlans = get_vlan_range(start_vlan,number_of_vlan)
    mac = get_mac_address_iter_obj(script_args.start_mac,'0',number_of_vlan)
    subnet = get_subnet_iter_obj()
    static_route_subnet = get_subnet_iter_obj_for_static_route(subnet='2.0.1.0/24')
    for vlan in vlans:
        try:
            m_addr = mac.next()
            sub = subnet.next()
            static_route_sub = static_route_subnet.next()
        except StopIteration:
            return
        vn_name = get_vn_name(script_args.start_vn_name,vlan)
        os.system("python vmi.py --static_route_subnet %s\
                          --tenant_id %s\
                          --config_node_ip %s\
                          --vcenter_vm_mac %s\
                          --vn_name %s\
                          --subnet %s\
                          --auth_url %s"
                          %(static_route_sub,
                           script_args.tenant_id,
                           script_args.config_node_ip,
                           m_addr,vn_name,sub,
                           script_args.auth_url
                           )
                         )

#python vmi_scale.py  --tenant_id 74ebcac4-21da-4fe3-8c7f-e84c9e0424ca --config_node_ip 192.168.192.60 --start_mac 000029572113 --start_vn_name tor_vn_ --start_vlan   6 --number_of_vlan 7 --auth_url http://10.204.217.144:5000/v2.0
if __name__ == "__main__":
    main()


## Archived on the 22/09/2021
## Original terrain.py lived at io_ogre/terrain.py

import bpy

def _get_proxy_decimate_mod( ob ):
    proxy = None
    for child in ob.children:
        if child.subcollision and child.name.startswith('DECIMATED'):
            for mod in child.modifiers:
                if mod.type == 'DECIMATE':
                    return mod

def bake_terrain( ob, normalize=True ):
    assert ob.collision_mode == 'TERRAIN'
    terrain = None
    for child in ob.children:
        if child.subcollision and child.name.startswith('TERRAIN'):
            terrain = child
            break
    assert terrain
    data = terrain.to_mesh(bpy.context.scene, True, "PREVIEW")
    raw = [ v.co.z for v in data.vertices ]
    Zmin = min( raw )
    Zmax = max( raw )
    depth = Zmax-Zmin
    m = 1.0 / depth

    rows = []
    i = 0
    for x in range( ob.collision_terrain_x_steps ):
        row = []
        for y in range( ob.collision_terrain_y_steps ):
            v = data.vertices[ i ]
            if normalize:
                z = (v.co.z - Zmin) * m
            else:
                z = v.co.z
            row.append( z )
            i += 1
        if x%2:
            row.reverse() # blender grid prim zig-zags
        rows.append( row )
    return {'data':rows, 'min':Zmin, 'max':Zmax, 'depth':depth}

def save_terrain_as_NTF( path, ob ): # Tundra format - hardcoded 16x16 patch format
    info = bake_terrain( ob )
    url = os.path.join( path, '%s.ntf' % clean_object_name(ob.data.name) )
    f = open(url, "wb")
    # Header
    buf = array.array("I")
    xs = ob.collision_terrain_x_steps
    ys = ob.collision_terrain_y_steps
    xpatches = int(xs/16)
    ypatches = int(ys/16)
    header = [ xpatches, ypatches ]
    buf.fromlist( header )
    buf.tofile(f)
    # Body
    rows = info['data']
    for x in range( xpatches ):
        for y in range( ypatches ):
            patch = []
            for i in range(16):
                for j in range(16):
                    v = rows[ (x*16)+i ][ (y*16)+j ]
                    patch.append( v )
            buf = array.array("f")
            buf.fromlist( patch )
            buf.tofile(f)
    f.close()
    path,name = os.path.split(url)
    R = {
        'url':url, 'min':info['min'], 'max':info['max'], 'path':path, 'name':name,
        'xpatches': xpatches, 'ypatches': ypatches,
        'depth':info['depth'],
    }
    return R

class OgreCollisionOp(bpy.types.Operator):
    '''Ogre Collision'''
    bl_idname = "ogre.set_collision"
    bl_label = "modify collision"
    bl_options = {'REGISTER'}
    MODE = StringProperty(name="toggle mode", maxlen=32, default="disable")

    @classmethod
    def poll(cls, context):
        if context.active_object and context.active_object.type == 'MESH':
            return True

    def get_subcollisions( self, ob, create=True ):
        r = get_subcollisions( ob )
        if not r and create:
            method = getattr(self, 'create_%s'%ob.collision_mode)
            p = method(ob)
            p.name = '%s.%s' %(ob.collision_mode, ob.name)
            p.subcollision = True
            r.append( p )
        return r

    def create_DECIMATED(self, ob):
        child = ob.copy()
        bpy.context.scene.collection.objects.link( child )
        child.matrix_local = mathutils.Matrix()
        child.parent = ob
        child.hide_select = True
        child.draw_type = 'WIRE'
        #child.select = False
        child.lock_location = [True]*3
        child.lock_rotation = [True]*3
        child.lock_scale = [True]*3
        decmod = child.modifiers.new('proxy', type='DECIMATE')
        decmod.ratio = 0.5
        return child

    def create_TERRAIN(self, ob):
        x = ob.collision_terrain_x_steps
        y = ob.collision_terrain_y_steps
        #################################
        #pos = ob.matrix_world.to_translation()
        bpy.ops.mesh.primitive_grid_add(
            x_subdivisions=x,
            y_subdivisions=y,
            size=1.0 )      #, location=pos )
        grid = bpy.context.active_object
        assert grid.name.startswith('Grid')
        grid.collision_terrain_x_steps = x
        grid.collision_terrain_y_steps = y
        #############################
        x,y,z = ob.dimensions
        sx,sy,sz = ob.scale
        x *= 1.0/sx
        y *= 1.0/sy
        z *= 1.0/sz
        grid.scale.x = x/2
        grid.scale.y = y/2
        grid.location.z -= z/2
        grid.data.show_all_edges = True
        grid.draw_type = 'WIRE'
        grid.hide_select = True
        #grid.select = False
        grid.lock_location = [True]*3
        grid.lock_rotation = [True]*3
        grid.lock_scale = [True]*3
        grid.parent = ob
        bpy.context.scene.objects.active = ob
        mod = grid.modifiers.new(name='temp', type='SHRINKWRAP')
        mod.wrap_method = 'PROJECT'
        mod.use_project_z = True
        mod.target = ob
        mod.cull_face = 'FRONT'
        return grid

    def invoke(self, context, event):
        ob = context.active_object
        game = ob.game
        subtype = None

        if ':' in self.MODE:
            mode, subtype = self.MODE.split(':')
            ##BLENDERBUG##ob.game.collision_bounds_type = subtype   # BUG this can not come before
            if subtype in 'BOX SPHERE CYLINDER CONE CAPSULE'.split():
                ob.draw_bounds_type = subtype
            else:
                ob.draw_bounds_type = 'POLYHEDRON'
            ob.game.collision_bounds_type = subtype  # BLENDERBUG - this must come after draw_bounds_type assignment
        else:
            mode = self.MODE
        ob.collision_mode = mode

        if ob.data.show_all_edges:
            ob.data.show_all_edges = False
        if ob.show_texture_space:
            ob.show_texture_space = False
        if ob.show_bounds:
            ob.show_bounds = False
        if ob.show_wire:
            ob.show_wire = False
        for child in ob.children:
            if child.subcollision and not child.hide_viewport:
                child.hide_viewport = True

        if mode == 'NONE':
            game.use_ghost = True
            game.use_collision_bounds = False
        elif mode == 'PRIMITIVE':
            game.use_ghost = False
            game.use_collision_bounds = True
            ob.show_bounds = True
        elif mode == 'MESH':
            game.use_ghost = False
            game.use_collision_bounds = True
            ob.show_wire = True
            if game.collision_bounds_type == 'CONVEX_HULL':
                ob.show_texture_space = True
            else:
                ob.data.show_all_edges = True
        elif mode == 'DECIMATED':
            game.use_ghost = True
            game.use_collision_bounds = False
            game.use_collision_compound = True
            proxy = self.get_subcollisions(ob)[0]
            if proxy.hide_viewport: proxy.hide_viewport = False
            ob.game.use_collision_compound = True  # proxy
            mod = _get_proxy_decimate_mod( ob )
            mod.show_viewport = True
            if not proxy.select:    # ugly (but works)
                proxy.hide_select = False
                proxy.select = True
                proxy.hide_select = True
            if game.collision_bounds_type == 'CONVEX_HULL':
                ob.show_texture_space = True
        elif mode == 'TERRAIN':
            game.use_ghost = True
            game.use_collision_bounds = False
            game.use_collision_compound = True
            proxy = self.get_subcollisions(ob)[0]
            if proxy.hide_viewport:
                proxy.hide_viewport = False
        elif mode == 'COMPOUND':
            game.use_ghost = True
            game.use_collision_bounds = False
            game.use_collision_compound = True
        else:
            assert 0 # unknown mode

        return {'FINISHED'}


# Bootstrap dropdown doesn't have select tag
# inspect the dropdown, find all the li under ui tag
# Loop through it and click the right li

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service

# Launch the browser
service_obj = Service("C:\Drivers\chromedriver_win32\chromedriver.exe")
driver = webdriver.Chrome(service=service_obj)
driver.implicitly_wait(10)

# Open the web application
driver.get("https://www.dummyticket.com/dummy-ticket-for-visa-application/")
driver.maximize_window()

driver.find_element(By.XPATH, "//span[@id='select2-billing_country-container']").click()

countries_list = driver.find_elements(By.XPATH, "//ul[@id='select2-billing_country-results']/li")
print(len(countries_list))

for country in countries_list:
    if country.text == "India":
        country.click()
        break


# coding=utf-8
from __future__ import print_function

from ActionSpace import settings
from om.util import update_from_salt, syn_data_outside, fmt_salt_out, check_computer
from om.models import CallLog
from django.contrib.auth.models import User, AnonymousUser
from om.proxy import Salt
from channels.generic.websockets import JsonWebsocketConsumer
from om.models import SaltMinion
from utils.util import CheckFireWall
import traceback
import re

class OmConsumer(JsonWebsocketConsumer):
    http_user = True

    def raw_connect(self, message, **kwargs):
        user = 'unknown'
        # noinspection PyBroadException
        try:
            not_login_user = User.objects.get_or_create(username='not_login_yet', is_active=False)[0]
            user = not_login_user if isinstance(message.user, AnonymousUser) else message.user
        except Exception as e:
            settings.logger.error(repr(e))
        CallLog.objects.create(
            user=user,
            type='message',
            action=message['path'],
            detail=message.content
        )
        settings.logger.info('recv_data:{data}'.format(data=message.content, path=message['path']))
        super(OmConsumer, self).raw_connect(message, **kwargs)

    def receive(self, content, **kwargs):
        try:
            CallLog.objects.create(
                user=User.objects.get(username=self.message.user.username),
                type='message',
                action=self.message['path'],
                detail=self.message.content
            )
        except Exception as e:
            settings.logger.error(repr(e))
            try:
                settings.logger.error(self.message.user.username)
            except Exception as e:
                settings.logger.error(repr(e))
        settings.logger.info('recv_data:{data}'.format(data=content, path=self.message['path']))
        super(OmConsumer, self).receive(content, **kwargs)

class SaltConsumer(OmConsumer):
    def receive(self, content, **kwargs):
        super(SaltConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        if not self.message.user.is_superuser:
            self.send({'result': '仅管理员有权限执行该操作！'})
            return
        info = content.get('info', '')
        if info == 'refresh-server':
            update_from_salt(None if settings.OM_ENV == 'PRD' else 'UAT')
            self.send({'result': 'Y', 'info': 'refresh-server'})
        elif info == 'check_computer':
            self.send({'return': check_computer(), 'info': 'check_computer'})
        else:
            self.send({'result': '未知操作！'})

class ServerConsumer(OmConsumer):
    def receive(self, content, **kwargs):
        super(ServerConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        if not self.message.user.is_superuser:
            self.send({'result': '仅管理员有权限执行该操作！'})
            return
        if content.get('info', None) != 'syn_data_outside':
            self.send({'result': '未知操作！'})
            return
        syn_data_outside()
        self.send({'result': 'Y'})

class ActionDetailConsumer(OmConsumer):
    group_prefix = 'action_detail-'
    yes = {"result": 'Y'}
    no = {"result": 'N'}

    def label(self):
        reg = r'^/om/action_detail/(?P<task_id>[0-9]+)/$'
        task_id = re.search(reg, self.message['path']).group('task_id')
        return f'{self.group_prefix}{task_id}'

    def connection_groups(self, **kwargs):
        return self.groups or [self.label()]

    def receive(self, content, **kwargs):
        super(ActionDetailConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        self.group_send(self.label(), self.yes)

    @classmethod
    def task_change(cls, task_id):
        settings.logger.info(f'{cls.group_prefix}{task_id}')
        ActionDetailConsumer.group_send(f'{cls.group_prefix}{task_id}', cls.yes)

class UnlockWinConsumer(OmConsumer):
    def receive(self, content, **kwargs):
        super(UnlockWinConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        user = content.get('user', None)
        server_info = content.get('server_info', None)
        if not all([user, server_info]) or not all([user.strip(), server_info]):
            self.send({'result': '参数选择错误，请检查！'})

        agents = [x['name'] for x in server_info]

        if settings.OM_ENV == 'PRD':  # 只有生产环境可以双通
            prd_agents = list(SaltMinion.objects.filter(name__in=agents, env='PRD', os='Windows').values_list('name', flat=True))
            settings.logger.info('prd_agents:{ag}'.format(ag=repr(prd_agents)))
            uat_agents = list(SaltMinion.objects.exclude(env='PRD').filter(name__in=agents, os='Windows').values_list('name', flat=True))
            settings.logger.info('uat_agents:{ag}'.format(ag=repr(uat_agents)))
            if len(prd_agents) > 0:
                prd_result, prd_output = Salt('PRD').shell(prd_agents, f'net user {user} /active:yes')
            else:
                prd_result, prd_output = True, ''

            if len(uat_agents) > 0:
                uat_result, uat_output = Salt('UAT').shell(uat_agents, f'net user {user} /active:yes')
            else:
                uat_result, uat_output = True, ''

            salt_result = prd_result and uat_result
            salt_output = fmt_salt_out('{prd}\n{uat}'.format(prd=fmt_salt_out(prd_output), uat=fmt_salt_out(uat_output)))
        else:
            agents = list(SaltMinion.objects.exclude(env='PRD').filter(name__in=agents, os='Windows').values_list('name', flat=True))
            settings.logger.info('agents:{ag}'.format(ag=repr(agents)))
            if len(agents) > 0:
                salt_result, salt_output = Salt('UAT').shell(agents, 'net user {user} /active:yes'.format(user=user))
            else:
                salt_result, salt_output = True, ''
            salt_output = fmt_salt_out(salt_output)

        if salt_result:
            settings.logger.info('unlock success!')
            result = salt_output.replace('The command completed successfully', '解锁成功')
            result = result.replace('[{}]', '选中的机器不支持解锁，请联系基础架构同事解锁！')
            self.send({"result": result})
        else:
            settings.logger.info('unlock false for salt return false')
            self.send({"result": '解锁失败！'})

class CmdConsumer(OmConsumer):
    # noinspection PyBroadException
    def receive(self, content, **kwargs):
        super(CmdConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        name = content.get('name', '').strip()
        cmd = content.get('cmd', '').strip()
        user = content.get('user', '').strip()
        if not all([name, cmd, user]):
            self.send({'result': '参数错误！'})
            return
        try:
            pc = SaltMinion.objects.get(name=name, status='up')
            if not any(
                    [self.message.user.has_perm('om.can_exec_cmd'),
                     self.message.user.has_perm('om.can_exec_cmd', pc)]
            ):
                self.send({'result': '没有执行命令权限，请联系管理员！'})
                return
            if not any([self.message.user.has_perm('om.can_root'), self.message.user.has_perm('om.can_root', pc)]):
                if user == 'root':
                    self.send({'result': '没有root权限，请联系管理员！'})
                    return
            _, back = Salt(pc.env).shell(pc.name, cmd, None if user == 'NA' else user)
            self.send({'result': back['return'][0].get(name, '未知结果！')})
        except Exception as e:
            self.send({'result': f"{e}\n{content}"})

class MakeFireWallConsumer(OmConsumer):
    # noinspection PyBroadException
    def receive(self, content, **kwargs):
        super(MakeFireWallConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        s_ip = content.get('s_ip', '').strip()
        t_ip = content.get('t_ip', '').strip()
        port = content.get('port', '').strip()
        if not all([s_ip, t_ip, port]):
            self.send({'result': '参数错误！'})
            return
        s_ip = s_ip.replace('
', '').replace('
', '').split('
')
        t_ip = t_ip.replace('
', '').replace('
', '').split('
')
        port = port.replace('
', '').replace('
', '').split('
')
        try:
            src_ag = [SaltMinion.objects.get(name__endswith='-'+x) for x in s_ip]
            dst_ag = [SaltMinion.objects.get(name__endswith='-'+x) for x in t_ip]
            result = []
            for p in port:
                cf = CheckFireWall(src_ag, dst_ag, int(p))
                result.append(cf.check())
                # self.message.reply_channel.send({'text': json.dumps(result)}, immediately=True)
            self.send(result)
        except Exception as e:
            if self.message.user.is_superuser:
                self.send({'result': f"{e}\n{traceback.format_exc()}\n{content}"})
            else:
                self.send({'result': 'error'})

class CheckFireWallConsumer(OmConsumer):

    def check_port(self, src_list, dst_list, port):
        result = []
        for p in port:
            cf = CheckFireWall(src_list, dst_list, int(p))
            result.append(cf.check())
        self.send(result)

    def check_policy(self, src_list, dst_list, port):
        from utils.util import FireWallPolicy
        src = ';'.join([x.ip() for x in src_list])
        dst = ';'.join([x.ip() for x in dst_list])
        srv = ','.join([f'tcp/{x}' for x in port])
        self.send({
            'src': [x.ip() for x in src_list],
            'dst': [x.ip() for x in dst_list],
            'port': port,
            'protocol': 'TCP',
            'result': FireWallPolicy(src, dst, srv).check()
        })

    def receive(self, content, **kwargs):
        super(CheckFireWallConsumer, self).receive(content, **kwargs)
        if not self.message.user.is_authenticated:
            self.send({'result': '未授权，请联系管理员！'})
            return
        check_type = content.get('check_type', '')
        src = content.get('src', [])
        dst = content.get('dst', [])
        port = [int(x) for x in re.split(r'\W+', content.get('port', [''])[0]) if x.strip() != '']
        try:
            if all([src, dst, port]):
                src_list = [x for x in SaltMinion.objects.filter(pk__in=src)]
                dst_list = [x for x in SaltMinion.objects.filter(pk__in=dst)]
                if all([src_list, dst_list]):
                    if check_type == 'port':
                        self.check_port(src_list, dst_list, port)
                    elif check_type == 'policy':
                        self.check_policy(src_list, dst_list, port)
                    else:
                        self.send({'result': '类型错误'})
        except Exception as e:
            settings.logger.error(repr(e))
            if self.message.user.is_superuser:
                self.send({'result': f"{e}\n{traceback.format_exc()}\n{content}"})
            else:
                self.send({'result': '执行报错，请联系管理员检查！'})

om_routing = [
    SaltConsumer.as_route(path=r"^/om/salt_status/"),
    ActionDetailConsumer.as_route(path=r"^/om/action_detail/", attrs={'group_prefix': 'action_detail-'}),
    UnlockWinConsumer.as_route(path=r"^/om/unlock_win/"),
    CmdConsumer.as_route(path=r'^/om/admin_action/'),
    MakeFireWallConsumer.as_route(path=r'^/utils/make_firewall_table/'),
    CheckFireWallConsumer.as_route(path=r'^/utils/check_firewall/'),
    ServerConsumer.as_route(path=r'^/om/show_server/')
]


from django.urls import path
from . import views

app_name = 'cis'

urlpatterns = [
    path('cis/<status>/', views.CIListView.as_view(), name='ci_list'),
    path('ci/create/', views.CICreateView.as_view(), name='ci_create'),
    path('ci/upload/', views.ci_upload, name='ci_upload'),
    path('ci/<int:pk>', views.CIDetailView.as_view(), name='ci_detail'),
    path('ci/pack/send/', views.send_ci_pack, name='ci_pack_send'),
    path('places/', views.manage_client_places, name='manage_client_places'),
    path('place/create/', views.PlaceCreateView.as_view(), name='place_create'),
    path('place/<int:pk>', views.PlaceUpdateView.as_view(), name='place_update'),
    path('manufacturer/<int:pk>', views.ManufacturerDetailView.as_view(), name='manufacturer_detail'),
    path('appliances/', views.ApplianceListView.as_view(), name='appliance_list'),
    path('appliance/create/', views.ApplianceCreateView.as_view(), name='appliance_create'),
    path('appliance/<int:pk>', views.ApplianceUpdateView.as_view(), name='appliance_update'),
]


# 给你一个下标从 0 开始的整数数组 nums 。

# 现定义两个数字的 串联 是由这两个数值串联起来形成的新数字。

# 例如，15 和 49 的串联是 1549 。
# nums 的 串联值 最初等于 0 。执行下述操作直到 nums 变为空：

# 如果 nums 中存在不止一个数字，分别选中 nums 中的第一个元素和最后一个元素，将二者串联得到的值加到 nums 的 串联值 上，然后从 nums 中删除第一个和最后一个元素。
# 如果仅存在一个元素，则将该元素的值加到 nums 的串联值上，然后删除这个元素。
# 返回执行完所有操作后 nums 的串联值。

from typing import List

class Solution:
    def findTheArrayConcVal(self, nums: List[int]) -> int:

        ans = 0

        while(len(nums) > 0):
            if len(nums) == 1:
                ans += nums.pop()

            else:
                l = nums.pop(0)
                r = nums.pop()

                ans += int(str(l) + str(r))

        return ans

nums = [7,52,2,4]

a = Solution()
print(a.findTheArrayConcVal(nums))