import tensorflow as tf
from pathlib import Path
import numpy as np
import dataset
import tensorflow_probability as tfp

tfd = tfp.distributions

class Encoder:

    def __init__(self, latent_size):
        super(Encoder, self).__init__()

        # static parameters
        self.latent_size = latent_size
        self.num_channels = 1
        self.dimensionality = 3
        self.fmap_base = 4096
        self.fmap_max = 512

        # dynamic parameters
        self.current_resolution = 1
        self.current_width = 2 ** self.current_resolution
        self.growing_encoder = self.make_Ebase(nf=self._nf(1))
        self.train_encoder = tf.keras.Sequential(self.growing_encoder,name='sequential')

    def update_res(self):
        self.current_resolution += 1
        self.current_width = 2 ** self.current_resolution

    def make_Ebase(self,nf):

        images = tf.keras.layers.Input(shape= (2,)*self.dimensionality + (nf,), name='images_2iso')

        # Final dense layer
        x = tf.keras.layers.Flatten()(images)
        x = tf.keras.layers.Dense(2*self.latent_size,activation=None)(x)
        return tf.keras.models.Model(inputs=[images], outputs=[x], name='z_params')

    def make_Eblock(self,name,nf):

        # on fait cette approche car on ne sait pas la taille donc on met pas un input
        block_layers = []

        #block_layers.append(tf.keras.layers.Convolution3D(nf, kernel_size=3, strides=1, padding='same'))
        #block_layers.append(tf.keras.layers.Activation(tf.nn.leaky_relu))

        block_layers.append(tf.keras.layers.Convolution3D(nf, kernel_size=4, strides=2, padding='same')) # check padding
        block_layers.append(tf.keras.layers.Activation(tf.nn.leaky_relu))

        return tf.keras.models.Sequential(block_layers, name=name)

    def _nf(self, stage):
        # computes number of filters for each layer
        return min(int(self.fmap_base / (2.0 ** (stage))), self.fmap_max)

    def _weighted_sum(self):
        return tf.keras.layers.Lambda(lambda inputs : (1-inputs[2])*inputs[0] + (inputs[2])*inputs[1])

    def add_resolution(self):

        # Add resolution
        self.update_res()

        # Gan images
        images = tf.keras.layers.Input(shape=(self.current_width,)*self.dimensionality+ (self.num_channels,),name = 'GAN_images')
        alpha = tf.keras.layers.Input(shape=[], name='e_alpha')

        # Compression block
        name = 'block_{}'.format(self.current_resolution)
        e_block = self.make_Eblock(name=name,nf=self._nf(self.current_resolution-1))

        # Channel compression
        from_rgb_1 = tf.keras.layers.AveragePooling3D()(images)
        from_rgb_1 = tf.keras.layers.Conv3D(self._nf(self.current_resolution-1), kernel_size=1, padding='same', name='from_rgb_1')(from_rgb_1)

        from_rgb_2 = tf.keras.layers.Conv3D(self._nf(self.current_resolution), kernel_size=1, padding='same', name='from_rgb_2')(images)
        from_rgb_2 = e_block(from_rgb_2)

        lerp_input = self._weighted_sum()([from_rgb_1, from_rgb_2, alpha]) # RANDOM ALPHA

        # Getting latent code
        e_z = self.growing_encoder(lerp_input)

        # Updating the model
        self.growing_encoder = tf.keras.Sequential([e_block,self.growing_encoder]) # without channel compression
        self.train_encoder = tf.keras.Model(inputs=[images,alpha],outputs=[e_z]) # with channel compression

class Decoder():

    def __init__(self, latent_size, generator_folder):
        super(Decoder, self).__init__()

        # static parameters
        self.latent_size = latent_size
        self.model_folder = generator_folder

        # dynamic parameters
        self.current_resolution = 1
        self.current_width = 2** self.current_resolution
        self.decoder = None

    def get_model(self,folder,res):
        # find the model for the appropriate resolution
        path = Path(folder)
        return str(list(path.glob('g_{}.h5'.format(res)))[0].resolve()) # check if single one

    def update_res(self):
        self.current_resolution += 1
        self.current_width = 2 ** self.current_resolution

    def make_Dblock(self,name):

        block_layers = []
        block_layers.append(tf.keras.layers.Flatten()) # obligé ??
        block_layers.append(tf.keras.layers.Dense(self.current_width**3))
        block_layers.append(tf.keras.layers.Reshape((self.current_width,self.current_width,self.current_width),input_shape=(self.current_width**3,)))
        #block_layers.append(tf.keras.layers.Activation(tf.nn.leaky_relu)) - depends on expression of NLL loss

        return tf.keras.models.Sequential(block_layers, name=name)

    def add_resolution(self):
        self.update_res()

        if self.current_resolution > 2:

            latent = tf.keras.layers.Input(shape=self.latent_size)
            alpha = tf.keras.layers.Input(shape=[], name='d_alpha')
            common = tf.keras.models.load_model(self.get_model(self.model_folder,self.current_resolution), custom_objects={'leaky_relu': tf.nn.leaky_relu}, compile=True)([latent,alpha])
            shape = tf.shape(common)
            common = tf.reshape(common,[shape[0],common.shape[1],common.shape[2],common.shape[3]])
            mu = self.make_Dblock(name='mu_block')(common)
            sigma = self.make_Dblock(name='sigma_block')(common)

            self.decoder = tf.keras.Model(inputs=[latent,alpha],outputs=[mu,sigma])
            self.decoder.trainable = True

    def get_decoder(self):
        return self.decoder

    def get_currentres(self):
        return self.current_resolution

class Generator():

    def __init__(self, latent_size, generator_folder):
        super(Generator,self).__init__()

        #static parameters
        self.latent_size = latent_size  # LOOK UP WHAT SIZE
        self.model_folder = generator_folder

        # dynamic
        self.current_resolution = 1
        self.current_width = 2**3
        self.generator = None

    def get_model(self,folder,res):
        # find the model for the appropriate resolution
        path = Path(folder)
        try:
            return str(list(path.glob('**/g_{}.h5'.format(res)))[0].resolve())
        except: print('No pretrained model for this resolution')

    def update_res(self):
        self.current_resolution += 1
        self.current_width = 2 ** self.current_resolution

    def add_resolution(self):
        self.update_res()
        if self.current_resolution > 2:
            self.generator = tf.keras.models.load_model(self.get_model(self.model_folder,self.current_resolution), custom_objects={'leaky_relu': tf.nn.leaky_relu}, compile=True)
            self.generator.trainable = False

    def generate_latents(self,num_samples):
        latents = []
        for i in range(num_samples):
            latent = tf.random.normal((1, self.latent_size))
            latents.append(latent)
        return latents


from discord.ext import commands
import discord
import random

class HelpCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.command(aliases=['хелп'])
    async def help(self, ctx):
        prefix = '!'
        emb = discord.Embed(title='Команды сервера: ', description=f'`{prefix}help`', color=discord.Color(random.randint(0x000000, 0xFFFFFF)), inline=False)
        emb.set_thumbnail(url=self.bot.user.avatar_url)
        emb.add_field(name='Модерация: только для роли [Админ] ',
                      value=f'`{prefix}clear` `{prefix}add_role` `{prefix}ban` `{prefix}mute` `{prefix}unmute` `{prefix}call`',
                      inline=False)
        emb.add_field(name='Развлечения: ',
                      value=f'`{prefix}cat` `{prefix}quote`',
                      inline=False)
        emb.add_field(name='Прочее: ',
                      value=f'`{prefix}info` `{prefix}my_info`',
                      inline=False)
        await ctx.send(embed=emb)

def setup(bot):
    bot.add_cog(HelpCog(bot))


import sys
sys.path.append("..")
from common import *

def parse(d):
    d = d.split(" ")
    cords = dict()
    for c in d[1].split(","):
        c = c.split("=")
        cords[c[0]] = tuple(map(int,c[1].split("..")))
    return (d[0],cords)

data = fnl(parse)

opp = {
"on":"off",
"off":"on"
}

cubemap = defaultdict(int)
duplicates = 0
for cuboid in data:
    for x in range(cuboid[1]["x"][0],cuboid[1]["x"][1]+1):
        if x >= -50 and x <= 50:
            for y in range(cuboid[1]["y"][0],cuboid[1]["y"][1]+1):
                if y >= -50 and y <= 50:
                    for z in range(cuboid[1]["z"][0],cuboid[1]["z"][1]+1):
                        if z >= -50 and z <= 50:
                            cubemap[(x,y,z)] = 1 if cuboid[0] == "on" else 0

print(sum([cubemap[c] for c in cubemap]))


#! /usr/bin/env python3.
from os import path
from pydub import AudioSegment
from custom_filesystem import CustomFilesystem, WAV_EXTENSION
import speech_accent_archive_analysis

# Create a wav duplicate (in the same directory) for an mp3 recording.
def create_wav_duplicate(mp3_recording_path):
    path_without_extension = mp3_recording_path[:-4]
    wav_recording_path = path_without_extension + WAV_EXTENSION
    sound = AudioSegment.from_mp3(mp3_recording_path)
    sound.export(wav_recording_path, format="wav")

if __name__ == '__main__':
    # Create wav duplicates for all the recordings in the Speech Accent Archive dataset.
    recordings_per_language = speech_accent_archive_analysis.recordings_per_language()
    custom_filesystem = CustomFilesystem()
    print("Creating wav duplicates for the following files:")
    for language, recordings in recordings_per_language.items():
        for recording in recordings:
            mp3_recording_path = custom_filesystem.mp3_recording_path(recording)
            print(mp3_recording_path)
            create_wav_duplicate(mp3_recording_path)


import os
import sys

import inference
import storage
import boto3

# Flask
from flask import Flask, redirect, url_for, request, render_template, Response, jsonify, redirect
from werkzeug.utils import secure_filename
from gevent.pywsgi import WSGIServer

# Some utilites
import numpy as np
from util import base64_to_pil

TCP_PORT = 5000
aws_access_key_id=''
aws_secret_access_key=''
# Declare a flask app
app = Flask(__name__)

s3 = boto3.client('s3',aws_access_key_id = aws_access_key_id, aws_secret_access_key = aws_secret_access_key)
inference_handler = inference.Inference(s3)
print('Model loaded. Check http://127.0.0.1:'+str(TCP_PORT))

@app.route('/', methods=['GET'])
def index():
    # Main page
    return render_template('index.html')

@app.route('/predict', methods=['GET', 'POST'])
def predict():
    if request.method == 'POST':
        img = base64_to_pil(request.json)
        hash_value = str(hex(hash(img.tobytes())))
        response = inference_handler.predict(img)
        storage.temp_store(hash_value, img)

        return jsonify(result=response, hash_value=hash_value)

    return None

@app.route('/feedback', methods=['GET', 'POST'])
def feedback():
    global s3
    if request.method == 'POST':
        hash_value = request.json['hash_value']
        correct_label = str.lower(request.json['label'])
        if(correct_label in inference_handler.classes):
            storage.copy_file(correct_label, hash_value)
        storage.remove_file(hash_value)
        resp = jsonify(success=True)
        return resp

    return None

if __name__ == '__main__':

    http_server = WSGIServer(('0.0.0.0', TCP_PORT), app)
    http_server.serve_forever()


from flask import make_response
from google.cloud import bigquery

# my modules
import config
from my_logging import getLogger

log = getLogger(__name__)
config = config.Config()

with open('auth.txt', 'r') as f:
    cf_token = f.readline().rstrip('\r\n')

# entry point of Cloud Functions
# trigger = http
def atm_iv_data(request):
    if not check_auth(request):
        return 'Forbidden', 403

    num_days = request.args.get('d', default='7')
    n_th_contract_month = request.args.get('n', default='0')

    df = query_atm_iv(num_days, n_th_contract_month)

    # CSV化
    atm_iv_csv = df.to_csv(index=False, header=False)

    res = make_response(atm_iv_csv, 200)
    res.headers['Content-type'] = 'text/csv; charset=utf-8'
    return res

def query_atm_iv(num_days, n_th_contract_month=0):
    table_iv = f'{config.gcp_bq_dataset_name}.atm_iv'
    table_option_price = f'{config.gcp_bq_dataset_name}.option_price'

    query = (f'''
        WITH t1 AS (
            SELECT
                (ARRAY_AGG(DISTINCT(last_trading_day) IGNORE NULLS ORDER BY last_trading_day ASC))[OFFSET({n_th_contract_month})] AS last_trading_day
            FROM
                {table_iv}
            WHERE
                started_at > TIMESTAMP_TRUNC(TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -10 DAY), DAY)
                AND last_trading_day >=  CURRENT_DATE('Asia/Tokyo')
        ), t2 AS (
            SELECT
                open,high,low,close, started_at
            FROM
                {table_iv}
            WHERE
                last_trading_day=(SELECT t1.last_trading_day FROM t1)
                AND started_at >= TIMESTAMP_TRUNC(TIMESTAMP_ADD(CURRENT_TIMESTAMP() , INTERVAL -{num_days} DAY), DAY)
        ), t3 AS (
            -- まだ時間足集計が保存されていない分(=UTCでの当日分)の時間足を集計する
            SELECT
                (array_agg(iv IGNORE NULLS ORDER BY created_at ASC))[OFFSET(0)] open,
                MAX(iv) high,
                MIN(iv) low,
                (array_agg(iv IGNORE NULLS ORDER BY created_at DESC))[OFFSET(0)] close,
                TIMESTAMP_SECONDS(CAST(TRUNC(UNIX_SECONDS(created_at)/3600) AS INT64) * 3600) AS started_at
            FROM
                {table_option_price}
            WHERE
                created_at >= TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), DAY)
                AND is_atm=True AND type=2 AND last_trading_day=(SELECT t1.last_trading_day FROM t1)
            GROUP BY started_at
        )
        SELECT
            open, high, low, close, started_at
        FROM
            t2

        UNION ALL

        SELECT
            open, high, low, close, started_at
        FROM
            t3
        ORDER BY started_at
    ''')

    client = bigquery.Client()
    query_job = client.query(query)
    rows = query_job.result()
    df = rows.to_dataframe()

    return df

def check_auth(request):
    auth_header = request.headers.get("Authorization")

    req_cf_token = None

    if auth_header is not None:
        req_cf_token = auth_header.split(' ')[1]

    return req_cf_token == cf_token

if __name__ == '__main__':
    from flask import Flask, request

    app = Flask(__name__)

    @app.route('/')
    def index():
        return atm_iv_data(request)

    app.run('127.0.0.1', 8000, debug=True)


import tensorflow as tf
from tensorflow.contrib.layers.python.layers import fully_connected
import numpy as np

def add_fc(inputs, outdim, train_phase, scope_in):
    fc =  fully_connected(inputs, outdim, activation_fn=None, scope=scope_in + '/fc')
    fc_bnorm = tf.layers.batch_normalization(fc, momentum=0.1, epsilon=1e-5,
                         training=train_phase, name=scope_in + '/bnorm')
    fc_relu = tf.nn.relu(fc_bnorm, name=scope_in + '/relu')
    fc_out = tf.layers.dropout(fc_relu, seed=0, training=train_phase, name=scope_in + '/dropout')
    return fc_out

def pdist(x1, x2):
    x1_square = tf.reshape(tf.reduce_sum(x1*x1, axis=1), [-1, 1])
    x2_square = tf.reshape(tf.reduce_sum(x2*x2, axis=1), [1, -1])
    return tf.sqrt(x1_square - 2 * tf.matmul(x1, tf.transpose(x2)) + x2_square + 1e-4)

def get_network(img_emb, sent_emb):
	im_fc1 = add_fc(img_emb, 2048, True, 'im_embed_1')
	im_fc2 = fully_connected(im_fc1, 512, activation_fn=None, scope = 'im_embed_2')
	i_embed = tf.nn.l2_normalize(im_fc2, 1, epsilon=1e-10)
	sent_fc1 = add_fc(sent_emb, 2048, True,'sent_embed_1')
	sent_fc2 = fully_connected(sent_fc1, 512, activation_fn=None, scope = 'sent_embed_2')
	s_embed = tf.nn.l2_normalize(sent_fc2, 1, epsilon=1e-10)
	return i_embed, s_embed

def embedding_loss(im_embeds, sent_embeds, im_labels):
    sent_im_ratio = 2 # Sample_size
    num_img = 40 # Batch_Size
    num_sent = num_img * sent_im_ratio
    im_loss_factor = 1.5
    margin = 0.05
    sent_only_loss_factor=0.05
    sent_im_dist = pdist(sent_embeds, im_embeds)
    pos_pair_dist = tf.reshape(tf.boolean_mask(sent_im_dist, im_labels), [num_sent, 1])
    neg_pair_dist = tf.reshape(tf.boolean_mask(sent_im_dist, ~im_labels), [num_sent, -1])
    im_loss = tf.clip_by_value(margin+ pos_pair_dist - neg_pair_dist, 0, 1e6)
    im_loss = tf.reduce_mean(tf.nn.top_k(im_loss, k=4)[0])
    neg_pair_dist = tf.reshape(tf.boolean_mask(tf.transpose(sent_im_dist), ~tf.transpose(im_labels)), [num_img, -1])
    neg_pair_dist = tf.reshape(tf.tile(neg_pair_dist, [1, sent_im_ratio]), [num_sent, -1])
    sent_loss = tf.clip_by_value(margin + pos_pair_dist - neg_pair_dist, 0, 1e6)
    sent_loss = tf.reduce_mean(tf.nn.top_k(sent_loss, k=4)[0])
    sent_sent_dist = pdist(sent_embeds, sent_embeds)
    sent_sent_mask = tf.reshape(tf.tile(tf.transpose(im_labels), [1, sent_im_ratio]), [num_sent, num_sent])
    pos_pair_dist = tf.reshape(tf.boolean_mask(sent_sent_dist, sent_sent_mask), [-1, sent_im_ratio])
    pos_pair_dist = tf.reduce_max(pos_pair_dist, axis=1, keep_dims=True)
    neg_pair_dist = tf.reshape(tf.boolean_mask(sent_sent_dist, ~sent_sent_mask), [num_sent, -1])
    sent_only_loss = tf.clip_by_value(margin + pos_pair_dist - neg_pair_dist, 0, 1e6)
    sent_only_loss = tf.reduce_mean(tf.nn.top_k(sent_only_loss, k=4)[0])

    loss = im_loss * im_loss_factor + sent_loss + sent_only_loss * sent_only_loss_factor

    return loss

def own_loss(model1, model2, y):
	margin = 0.2
	with tf.name_scope("own-loss"):
		x1_square = tf.reshape(tf.reduce_sum(model1*model1, axis=1), [-1, 1])
		x2_square = tf.reshape(tf.reduce_sum(model2*model2, axis=1), [1, -1])
		y = tf.to_float(y)
		softmax_1 = tf.nn.softmax(model1)
		ce_1 = -tf.reduce_sum(tf.tensordot(y, tf.log(softmax_1), axes=0), 1)
		ce_1 = 0.1*ce_1
		coss_dist = tf.losses.cosine_distance(tf.nn.l2_normalize(x1_square, 0), tf.nn.l2_normalize(x2_square, 0), dim=0)
		softmax_2 = tf.nn.softmax(model2)
		ce_2 = -tf.reduce_sum(tf.tensordot(y, tf.log(softmax_2), axes=0), 1)
		ce_2 = ce_2*0.1

		d =  pdist(model1, model2)
		tmp = tf.tensordot(y,tf.square(d), axes=0)
		tmp2 = tf.tensordot((1 - y), tf.square(tf.maximum((	margin - d),0)), axes=0)
		k_norm = tf.pow(tf.reduce_sum(tf.pow(x1_square-x2_square,1)),1)

		tmp_coss = tf.tensordot(y, tf.square(coss_dist), axes=0)
		tmp2_coss = tf.tensordot((1 - y), tf.square(tf.maximum((margin - coss_dist),0)), axes=0)

		tmp_k = tf.tensordot(y,tf.square(k_norm), axes=0)
		tmp2_k = tf.tensordot((1 - y), tf.square(tf.maximum((margin - k_norm),0)), axes=0)
		return tf.reduce_mean(tmp+tmp2)/2 + tf.reduce_mean(tmp_coss + tmp2_coss)/2 + tf.reduce_mean(ce_1)/2 + tf.reduce_mean(ce_2)/2


from __future__ import absolute_import, division, print_function

import torch
import torch.nn as nn
from torch.autograd import Variable

import os, sys, errno
import argparse
import time
import numpy as np
import cv2
import matplotlib.pyplot as plt
from tqdm import tqdm

from utils import post_process_depth, flip_lr
from networks.NewCRFDepth import NewCRFDepth

def convert_arg_line_to_args(arg_line):
    for arg in arg_line.split():
        if not arg.strip():
            continue
        yield arg

def print_minmax(arr,desc):
    """visualize depths and uncertainty of any method"""

    print("*" * 60)
    print("***{}***  :".format(desc))
    print("arr.shape = {}".format(arr.shape))
    print("type(arr[0,0] = {}".format(type(arr[0,0])))
    print("np.min = {}".format(np.min(arr)))
    print("np.max = {}".format(np.max(arr)))
    print("np.mean = {}".format(np.mean(arr)))
    print("np.median = {}".format(np.median(arr)))
    #print("arr[200:220,200:220] = \n",arr[200:220,200:220])
    print("arr[0:10,0:10] = \n",arr[0:10,0:10])
    print("*" * 60 + "\n")

parser = argparse.ArgumentParser(description='NeWCRFs PyTorch implementation.', fromfile_prefix_chars='@')
parser.convert_arg_line_to_args = convert_arg_line_to_args

parser.add_argument('--model_name', type=str, help='model name', default='newcrfs')
parser.add_argument('--encoder', type=str, help='type of encoder, base07, large07', default='large07')
parser.add_argument('--data_path_eval', type=str, help='path to the data', required=True)
parser.add_argument('--gt_path_eval',type=str,   help='path to the groundtruth data for evaluation', required=False)
parser.add_argument('--filenames_file_eval', type=str, help='path to the filenames text file', required=True)
parser.add_argument('--input_height', type=int, help='input height', default=480)
parser.add_argument('--input_width', type=int, help='input width', default=640)
parser.add_argument('--max_depth',                 type=float, help='maximum depth in estimation', default=10)
parser.add_argument('--min_depth_eval',type=float, help='minimum depth for evaluation', default=1e-3)
parser.add_argument('--max_depth_eval', type=float, help='maximum depth in estimation', default=80)
parser.add_argument('--checkpoint_path', type=str, help='path to a specific checkpoint to load', default='')
parser.add_argument('--dataset', type=str, help='dataset to train on', default='nyu')
parser.add_argument('--do_kb_crop', help='if set, crop input images as kitti benchmark images', action='store_true')
parser.add_argument('--save_viz', help='if set, save visulization of the outputs', action='store_true')
parser.add_argument('--gray', help='Use gray images for testing', action='store_true')

if sys.argv.__len__() == 2:
    arg_filename_with_prefix = '@' + sys.argv[1]
    args = parser.parse_args([arg_filename_with_prefix])
else:
    args = parser.parse_args()

if args.dataset == 'kitti' or args.dataset == 'nyu' or args.dataset == '12scenes' or args.dataset == 'iitd':
    from dataloaders.dataloader import NewDataLoader
elif args.dataset == 'kittipred':
    from dataloaders.dataloader_kittipred import NewDataLoader

model_dir = os.path.dirname(args.checkpoint_path)
sys.path.append(model_dir)

def get_num_lines(file_path):
    f = open(file_path, 'r')
    lines = f.readlines()
    f.close()
    return len(lines)

def test(params):
    """Test function."""
    #args.mode = 'test'
    args.distributed = False
    args.mode = 'online_eval'
    dataloader = NewDataLoader(args, args.mode)

    model = NewCRFDepth(version='large07', inv_depth=False, max_depth=args.max_depth)
    model = torch.nn.DataParallel(model)

    checkpoint = torch.load(args.checkpoint_path)
    model.load_state_dict(checkpoint['model'])
    model.eval()
    model.cuda()

    num_params = sum([np.prod(p.size()) for p in model.parameters()])
    print("Total number of parameters: {}".format(num_params))

    num_test_samples = get_num_lines(args.filenames_file_eval)

    with open(args.filenames_file_eval) as f:
        lines = f.readlines()

    print('now testing {} files with {}'.format(num_test_samples, args.checkpoint_path))

    pred_depths = []
    gt_depths = []
    images = []
    start_time = time.time()
    #save_name = 'models/result_' + args.model_name
    save_name = 'visualisations/result_' + args.dataset + "_" + args.filenames_file_eval.split("/")[-1].split("_")[-1].split(".")[-2] + ("_gray" if args.gray else "")
    os.makedirs(save_name,exist_ok=True)

    try:

        os.mkdir(save_name + '/raw')
        #os.mkdir(save_name + '/cmap')
        os.mkdir(save_name + '/rgb')
        os.mkdir(save_name + '/gt')
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise
    with torch.no_grad():
        for i, sample in enumerate(tqdm(dataloader.data)):
            image = Variable(sample['image'].cuda())
            has_valid_depth = sample['has_valid_depth']
            if not has_valid_depth:
                # print('Invalid depth. continue.')
                continue
            gt_depth = sample['depth']

            # Predict
            depth_est = model(image)
            post_process = True
            if post_process:
                image_flipped = flip_lr(image)
                depth_est_flipped = model(image_flipped)
                depth_est = post_process_depth(depth_est, depth_est_flipped)

            if args.dataset == "kitti":
                pred_depth = (depth_est.cpu().numpy().squeeze() * 256.0 ).astype(np.uint16)
                image = (image.cpu().numpy().squeeze() * 255).astype(np.uint8)
                gt_depth = (gt_depth.numpy().squeeze() * 256.0).astype(np.uint16)

            elif args.dataset == "iitd":
                pred_depth = depth_est.cpu().numpy().squeeze()
                pred_depth[pred_depth < args.min_depth_eval] = args.min_depth_eval
                pred_depth[pred_depth > 6.0] = 6.0
                pred_depth[np.isinf(pred_depth)] = 6.0
                pred_depth[np.isnan(pred_depth)] = args.min_depth_eval

                pred_depth = (pred_depth * 1000.0).astype(np.uint16)
                image = (image.cpu().numpy().squeeze() * 255).astype(np.uint8)
                gt_depth = (gt_depth.numpy().squeeze() * 1000.0).astype(np.uint16)
            else:
                print("please change here for you dataset !!")
                sys.exit(0)

            #print_minmax(gt_depth,"gt_depth after")
            #print_minmax(pred_depth, "pred_depth")

            image = image.transpose(1,2,0)
            image = image[:,:,::-1] #because cv2.imwrite assumes in BGR format.
            #print(image.shape)
            #sys.exit(0)
            if args.do_kb_crop:
                height, width = 352, 1216
                top_margin = int(height - 352)
                left_margin = int((width - 1216) / 2)
                pred_depth_uncropped = np.zeros((height, width), dtype=np.uint16)
                pred_depth_uncropped[top_margin:top_margin + 352, left_margin:left_margin + 1216] = pred_depth
                pred_depth = pred_depth_uncropped

            #save pred_depth, image and gt_depths
            #print_minmax(gt_depth,"gt_depth")
            cv2.imwrite(save_name + f'/raw/{i:06d}.png',pred_depth)
            cv2.imwrite(save_name + f'/gt/{i:06d}.png',gt_depth)
            cv2.imwrite(save_name + f'/rgb/{i:06d}.png',image)
            # pred_depths.append(pred_depth)
            # gt_depths.append(gt_depth)
            # images.append(image)

    elapsed_time = time.time() - start_time
    print('Elapesed time: %s' % str(elapsed_time))
    print('Done.')

    os.makedirs(save_name+"/orig_rgb/",exist_ok=True)
    i = 0
    print(len(lines),num_test_samples)
    for s in tqdm(range(num_test_samples)):
        if lines[s].split()[1] == "None":
            print("continue")
            continue
        if args.dataset == 'kitti' or args.dataset == 'iitd':
            orig_rgb_path = os.path.join(args.data_path_eval, lines[s].split()[0])
            orig_rgb = cv2.imread(orig_rgb_path,-1)
            cv2.imwrite(save_name + f'/orig_rgb/{i:06d}.png'  , orig_rgb)
            i+=1
    print()
    print(f"{i} orig_rgb saved!!")

    """
    #save_name = 'models/result_' + args.model_name
    save_name = 'visualisations/result_' + args.dataset + ("_gray" if args.gray else "")
    os.makedirs(save_name,exist_ok=True)

    print('Saving result pngs..')
    if not os.path.exists(save_name):
        try:
            os.mkdir(save_name)
            os.mkdir(save_name + '/raw')
            #os.mkdir(save_name + '/cmap')
            os.mkdir(save_name + '/rgb')
            os.mkdir(save_name + '/gt')
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise
    print("len(line) = ",len(lines))
    for i in tqdm(range(len(images))):
    #for s in tqdm(range(num_test_samples)):

        # if lines[s].split()[1] == "None":
        #     continue
        if args.dataset == 'kitti':
            date_drive = lines[s].split('/')[1]
            filename_pred_png = save_name + '/raw/' + date_drive + '_' + lines[s].split()[0].split('/')[-1].replace(
                '.jpg', '.png')
            filename_cmap_png = save_name + '/cmap/' + date_drive + '_' + lines[s].split()[0].split('/')[
                -1].replace('.jpg', '.png')
            filename_image_png = save_name + '/rgb/' + date_drive + '_' + lines[s].split()[0].split('/')[-1]
            #filename_gtnorm_png = save_name + '/gt_normalized/' + scene_name + '_' + lines[s].split()[0].split('/')[2].replace(
                #'.jpg', '.png')
            filename_gt_png = save_name + '/gt/' + date_drive + '_' + lines[s].split()[0].split('/')[2].replace(
                '.jpg', '_gt.png')

        elif args.dataset == 'kittipred':
            filename_pred_png = save_name + '/raw/' + lines[s].split()[0].split('/')[-1].replace('.jpg', '.png')
            filename_cmap_png = save_name + '/cmap/' + lines[s].split()[0].split('/')[-1].replace('.jpg', '.png')
            filename_image_png = save_name + '/rgb/' + lines[s].split()[0].split('/')[-1]
        else:
            # scene_name = lines[s].split()[0].split('/')[0]
            # filename_pred_png = save_name + '/raw/' + scene_name + '_' + lines[s].split()[0].split('/')[1].replace(
            #     '.jpg', '.png')
            # filename_cmap_png = save_name + '/cmap/' + scene_name + '_' + lines[s].split()[0].split('/rgb_')[1].replace(
            #     '.jpg', '.png')
            # filename_gt_png = save_name + '/gt/' + scene_name + '_' + lines[s].split()[0].split('/rgb_')[1].replace(
            #     '.jpg', '_gt.png')
            # filename_image_png = save_name + '/rgb/' + scene_name + '_' + lines[s].split()[0].split('/rgb_')[1]

            scene_name = lines[s].split()[0].split('/')[0]
            filename_pred_png = save_name + '/raw/' + scene_name + '_' + lines[s].split()[0].split('/')[2].replace(
                '.jpg', '.png')
            filename_gtnorm_png = save_name + '/gt_normalized/' + scene_name + '_' + lines[s].split()[0].split('/')[2].replace(
                '.jpg', '.png')
            filename_gt_png = save_name + '/gt/' + scene_name + '_' + lines[s].split()[0].split('/')[2].replace(
                '.jpg', '_gt.png')
            filename_image_png = save_name + '/rgb/' + scene_name + '_' + lines[s].split()[0].split('/')[2]

        #rgb
        rgb_path = os.path.join(args.data_path, './' + lines[s].split()[0])
        image = cv2.imread(rgb_path)

        #gt_depth
        if args.dataset == 'nyu':
            gt_path = os.path.join(args.data_path, './' + lines[s].split()[1])
            gt = cv2.imread(gt_path, -1).astype(np.float32) / 1000.0  # Visualization purpose only
            gt[gt == 0] = np.amax(gt)
        elif args.dataset=="kitti":

            gt_path = os.path.join(args.data_path, lines[s].split()[0].split('/')[0] , lines[s].split()[1])
            print("gt_ptah ", gt_path)
            gt = cv2.imread(gt_path, -1).astype(np.float32) / 1000.0  # Visualization purpose only
            gt[gt == 0] = np.amax(gt)

        #pred_depth
        pred_depth = pred_depths[s]
        if args.dataset == 'kitti' or args.dataset == 'kittipred':
            pred_depth_scaled = pred_depth * 256.0
        else:
            pred_depth_scaled = pred_depth * 1000.0
        pred_depth_scaled = pred_depth_scaled.astype(np.uint16)

        #save pred_depth
        cv2.imwrite(filename_pred_png, pred_depth_scaled, [cv2.IMWRITE_PNG_COMPRESSION, 0])

        if args.save_viz:

            #save rgb
            cv2.imwrite(filename_image_png, image[10:-1 - 9, 10:-1 - 9, :])
            if args.dataset == 'nyu' or args.dataset=="kitti":

                #save gtnorm
                #plt.imsave(filename_gtnorm_png, (10 - gt) / 10, cmap='plasma')

                #save gt
                plt.imsave(filename_gt_png, gt)
                # pred_depth_cropped = pred_depth[10:-1 - 9, 10:-1 - 9]
                #plt.imsave(filename_cmap_png, (10 - pred_depth) / 10, cmap='plasma')
            #else:
                #plt.imsave(filename_cmap_png, np.log10(pred_depth), cmap='Greys')

    return
    """

if __name__ == '__main__':
    test(args)


import urllib

class ActionBatchNetworks(object):
    def __init__(self):
        super(ActionBatchNetworks, self).__init__()

    def updateNetwork(self, networkId: str, **kwargs):
        """
        **Update a network**
        https://developer.cisco.com/meraki/api-v1/#!update-network

        - networkId (string): Network ID
        - name (string): The name of the network
        - timeZone (string): The timezone of the network. For a list of allowed timezones, please see the 'TZ' column in the table in this article.
        - tags (array): A list of tags to be applied to the network
        - enrollmentString (string): A unique identifier which can be used for device enrollment or easy access through the Meraki SM Registration page or the Self Service Portal. Please note that changing this field may cause existing bookmarks to break.
        - notes (string): Add any notes or additional information about this network here.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure'],
            'operation': 'updateNetwork'
        }
        resource = f'/networks/{networkId}'

        body_params = ['name', 'timeZone', 'tags', 'enrollmentString', 'notes', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def deleteNetwork(self, networkId: str):
        """
        **Delete a network**
        https://developer.cisco.com/meraki/api-v1/#!delete-network

        - networkId (string): Network ID
        """

        metadata = {
            'tags': ['networks', 'configure'],
            'operation': 'deleteNetwork'
        }
        resource = f'/networks/{networkId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def bindNetwork(self, networkId: str, configTemplateId: str, **kwargs):
        """
        **Bind a network to a template.**
        https://developer.cisco.com/meraki/api-v1/#!bind-network

        - networkId (string): Network ID
        - configTemplateId (string): The ID of the template to which the network should be bound.
        - autoBind (boolean): Optional boolean indicating whether the network's switches should automatically bind to profiles of the same model. Defaults to false if left unspecified. This option only affects switch networks and switch templates. Auto-bind is not valid unless the switch template has at least one profile and has at most one profile per switch model.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure'],
            'operation': 'bindNetwork'
        }
        resource = f'/networks/{networkId}/bind'

        body_params = ['configTemplateId', 'autoBind', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def provisionNetworkClients(self, networkId: str, clients: list, devicePolicy: str, **kwargs):
        """
        **Provisions a client with a name and policy**
        https://developer.cisco.com/meraki/api-v1/#!provision-network-clients

        - networkId (string): Network ID
        - clients (array): The array of clients to provision
        - devicePolicy (string): The policy to apply to the specified client. Can be 'Group policy', 'Allowed', 'Blocked', 'Per connection' or 'Normal'. Required.
        - groupPolicyId (string): The ID of the desired group policy to apply to the client. Required if 'devicePolicy' is set to "Group policy". Otherwise this is ignored.
        - policiesBySecurityAppliance (object): An object, describing what the policy-connection association is for the security appliance. (Only relevant if the security appliance is actually within the network)
        - policiesBySsid (object): An object, describing the policy-connection associations for each active SSID within the network. Keys should be the number of enabled SSIDs, mapping to an object describing the client's policy
        """

        kwargs.update(locals())

        if 'devicePolicy' in kwargs:
            options = ['Allowed', 'Blocked', 'Group policy', 'Normal', 'Per connection']
            assert kwargs['devicePolicy'] in options, f'''"devicePolicy" cannot be "{kwargs['devicePolicy']}", & must be set to one of: {options}'''

        metadata = {
            'tags': ['networks', 'configure', 'clients'],
            'operation': 'provisionNetworkClients'
        }
        resource = f'/networks/{networkId}/clients/provision'

        body_params = ['clients', 'devicePolicy', 'groupPolicyId', 'policiesBySecurityAppliance', 'policiesBySsid', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def claimNetworkDevices(self, networkId: str, serials: list):
        """
        **Claim devices into a network. (Note: for recently claimed devices, it may take a few minutes for API requsts against that device to succeed)**
        https://developer.cisco.com/meraki/api-v1/#!claim-network-devices

        - networkId (string): Network ID
        - serials (array): A list of serials of devices to claim
        """

        kwargs = locals()

        metadata = {
            'tags': ['networks', 'configure', 'devices'],
            'operation': 'claimNetworkDevices'
        }
        resource = f'/networks/{networkId}/devices/claim'

        body_params = ['serials', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def vmxNetworkDevicesClaim(self, networkId: str, size: str):
        """
        **Claim a vMX into a network**
        https://developer.cisco.com/meraki/api-v1/#!vmx-network-devices-claim

        - networkId (string): Network ID
        - size (string): The size of the vMX you claim. It can be one of: small, medium, large, 100
        """

        kwargs = locals()

        if 'size' in kwargs:
            options = ['100', 'large', 'medium', 'small']
            assert kwargs['size'] in options, f'''"size" cannot be "{kwargs['size']}", & must be set to one of: {options}'''

        metadata = {
            'tags': ['networks', 'configure', 'devices', 'claim'],
            'operation': 'vmxNetworkDevicesClaim'
        }
        resource = f'/networks/{networkId}/devices/claim/vmx'

        body_params = ['size', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def removeNetworkDevices(self, networkId: str, serial: str):
        """
        **Remove a single device**
        https://developer.cisco.com/meraki/api-v1/#!remove-network-devices

        - networkId (string): Network ID
        - serial (string): The serial of a device
        """

        kwargs = locals()

        metadata = {
            'tags': ['networks', 'configure', 'devices'],
            'operation': 'removeNetworkDevices'
        }
        resource = f'/networks/{networkId}/devices/remove'

        body_params = ['serial', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def updateNetworkFirmwareUpgrades(self, networkId: str, **kwargs):
        """
        **Update firmware upgrade information for a network**
        https://developer.cisco.com/meraki/api-v1/#!update-network-firmware-upgrades

        - networkId (string): Network ID
        - upgradeWindow (object): Upgrade window for devices in network
        - timezone (string): The timezone for the network
        - products (object): Contains information about the network to update
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'firmwareUpgrades'],
            'operation': 'updateNetworkFirmwareUpgrades'
        }
        resource = f'/networks/{networkId}/firmwareUpgrades'

        body_params = ['upgradeWindow', 'timezone', 'products', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def createNetworkFirmwareUpgradesRollback(self, networkId: str, reasons: list, **kwargs):
        """
        **Rollback a Firmware Upgrade For A Network**
        https://developer.cisco.com/meraki/api-v1/#!create-network-firmware-upgrades-rollback

        - networkId (string): Network ID
        - reasons (array): Reasons for the rollback
        - product (string): Product type to rollback (if the network is a combined network)
        - time (string): Scheduled time for the rollback
        - toVersion (object): Version to downgrade to (if the network has firmware flexibility)
        """

        kwargs.update(locals())

        if 'product' in kwargs:
            options = ['appliance', 'camera', 'cellularGateway', 'switch', 'switchCatalyst', 'wireless']
            assert kwargs['product'] in options, f'''"product" cannot be "{kwargs['product']}", & must be set to one of: {options}'''

        metadata = {
            'tags': ['networks', 'configure', 'firmwareUpgrades', 'rollbacks'],
            'operation': 'createNetworkFirmwareUpgradesRollback'
        }
        resource = f'/networks/{networkId}/firmwareUpgrades/rollbacks'

        body_params = ['product', 'time', 'reasons', 'toVersion', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def createNetworkFirmwareUpgradesStagedGroup(self, networkId: str, name: str, isDefault: bool, **kwargs):
        """
        **Create a Staged Upgrade Group for a network**
        https://developer.cisco.com/meraki/api-v1/#!create-network-firmware-upgrades-staged-group

        - networkId (string): Network ID
        - name (string): Name of the Staged Upgrade Group. Length must be 1 to 255 characters
        - isDefault (boolean): Boolean indicating the default Group. Any device that does not have a group explicitly assigned will upgrade with this group
        - description (string): Description of the Staged Upgrade Group. Length must be 1 to 255 characters
        - assignedDevices (object): The devices and Switch Stacks assigned to the Group
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'firmwareUpgrades', 'staged', 'groups'],
            'operation': 'createNetworkFirmwareUpgradesStagedGroup'
        }
        resource = f'/networks/{networkId}/firmwareUpgrades/staged/groups'

        body_params = ['name', 'description', 'isDefault', 'assignedDevices', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def deleteNetworkFirmwareUpgradesStagedGroup(self, networkId: str, groupId: str):
        """
        **Delete a Staged Upgrade Group**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-firmware-upgrades-staged-group

        - networkId (string): Network ID
        - groupId (string): Group ID
        """

        metadata = {
            'tags': ['networks', 'configure', 'firmwareUpgrades', 'staged', 'groups'],
            'operation': 'deleteNetworkFirmwareUpgradesStagedGroup'
        }
        resource = f'/networks/{networkId}/firmwareUpgrades/staged/groups/{groupId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def updateNetworkFloorPlan(self, networkId: str, floorPlanId: str, **kwargs):
        """
        **Update a floor plan's geolocation and other meta data**
        https://developer.cisco.com/meraki/api-v1/#!update-network-floor-plan

        - networkId (string): Network ID
        - floorPlanId (string): Floor plan ID
        - name (string): The name of your floor plan.
        - center (object): The longitude and latitude of the center of your floor plan. If you want to change the geolocation data of your floor plan, either the 'center' or two adjacent corners (e.g. 'topLeftCorner' and 'bottomLeftCorner') must be specified. If 'center' is specified, the floor plan is placed over that point with no rotation. If two adjacent corners are specified, the floor plan is rotated to line up with the two specified points. The aspect ratio of the floor plan's image is preserved regardless of which corners/center are specified. (This means if that more than two corners are specified, only two corners may be used to preserve the floor plan's aspect ratio.). No two points can have the same latitude, longitude pair.
        - bottomLeftCorner (object): The longitude and latitude of the bottom left corner of your floor plan.
        - bottomRightCorner (object): The longitude and latitude of the bottom right corner of your floor plan.
        - topLeftCorner (object): The longitude and latitude of the top left corner of your floor plan.
        - topRightCorner (object): The longitude and latitude of the top right corner of your floor plan.
        - imageContents (string): The file contents (a base 64 encoded string) of your new image. Supported formats are PNG, GIF, and JPG. Note that all images are saved as PNG files, regardless of the format they are uploaded in. If you upload a new image, and you do NOT specify any new geolocation fields ('center, 'topLeftCorner', etc), the floor plan will be recentered with no rotation in order to maintain the aspect ratio of your new image.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'floorPlans'],
            'operation': 'updateNetworkFloorPlan'
        }
        resource = f'/networks/{networkId}/floorPlans/{floorPlanId}'

        body_params = ['name', 'center', 'bottomLeftCorner', 'bottomRightCorner', 'topLeftCorner', 'topRightCorner', 'imageContents', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def deleteNetworkFloorPlan(self, networkId: str, floorPlanId: str):
        """
        **Destroy a floor plan**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-floor-plan

        - networkId (string): Network ID
        - floorPlanId (string): Floor plan ID
        """

        metadata = {
            'tags': ['networks', 'configure', 'floorPlans'],
            'operation': 'deleteNetworkFloorPlan'
        }
        resource = f'/networks/{networkId}/floorPlans/{floorPlanId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def createNetworkGroupPolicy(self, networkId: str, name: str, **kwargs):
        """
        **Create a group policy**
        https://developer.cisco.com/meraki/api-v1/#!create-network-group-policy

        - networkId (string): Network ID
        - name (string): The name for your group policy. Required.
        - scheduling (object):     The schedule for the group policy. Schedules are applied to days of the week.

        - bandwidth (object):     The bandwidth settings for clients bound to your group policy.

        - firewallAndTrafficShaping (object):     The firewall and traffic shaping rules and settings for your policy.

        - contentFiltering (object): The content filtering settings for your group policy
        - splashAuthSettings (string): Whether clients bound to your policy will bypass splash authorization or behave according to the network's rules. Can be one of 'network default' or 'bypass'. Only available if your network has a wireless configuration.
        - vlanTagging (object): The VLAN tagging settings for your group policy. Only available if your network has a wireless configuration.
        - bonjourForwarding (object): The Bonjour settings for your group policy. Only valid if your network has a wireless configuration.
        """

        kwargs.update(locals())

        if 'splashAuthSettings' in kwargs:
            options = ['bypass', 'network default']
            assert kwargs['splashAuthSettings'] in options, f'''"splashAuthSettings" cannot be "{kwargs['splashAuthSettings']}", & must be set to one of: {options}'''

        metadata = {
            'tags': ['networks', 'configure', 'groupPolicies'],
            'operation': 'createNetworkGroupPolicy'
        }
        resource = f'/networks/{networkId}/groupPolicies'

        body_params = ['name', 'scheduling', 'bandwidth', 'firewallAndTrafficShaping', 'contentFiltering', 'splashAuthSettings', 'vlanTagging', 'bonjourForwarding', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def updateNetworkGroupPolicy(self, networkId: str, groupPolicyId: str, **kwargs):
        """
        **Update a group policy**
        https://developer.cisco.com/meraki/api-v1/#!update-network-group-policy

        - networkId (string): Network ID
        - groupPolicyId (string): Group policy ID
        - name (string): The name for your group policy.
        - scheduling (object):     The schedule for the group policy. Schedules are applied to days of the week.

        - bandwidth (object):     The bandwidth settings for clients bound to your group policy.

        - firewallAndTrafficShaping (object):     The firewall and traffic shaping rules and settings for your policy.

        - contentFiltering (object): The content filtering settings for your group policy
        - splashAuthSettings (string): Whether clients bound to your policy will bypass splash authorization or behave according to the network's rules. Can be one of 'network default' or 'bypass'. Only available if your network has a wireless configuration.
        - vlanTagging (object): The VLAN tagging settings for your group policy. Only available if your network has a wireless configuration.
        - bonjourForwarding (object): The Bonjour settings for your group policy. Only valid if your network has a wireless configuration.
        """

        kwargs.update(locals())

        if 'splashAuthSettings' in kwargs:
            options = ['bypass', 'network default']
            assert kwargs['splashAuthSettings'] in options, f'''"splashAuthSettings" cannot be "{kwargs['splashAuthSettings']}", & must be set to one of: {options}'''

        metadata = {
            'tags': ['networks', 'configure', 'groupPolicies'],
            'operation': 'updateNetworkGroupPolicy'
        }
        resource = f'/networks/{networkId}/groupPolicies/{groupPolicyId}'

        body_params = ['name', 'scheduling', 'bandwidth', 'firewallAndTrafficShaping', 'contentFiltering', 'splashAuthSettings', 'vlanTagging', 'bonjourForwarding', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def deleteNetworkGroupPolicy(self, networkId: str, groupPolicyId: str):
        """
        **Delete a group policy**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-group-policy

        - networkId (string): Network ID
        - groupPolicyId (string): Group policy ID
        """

        metadata = {
            'tags': ['networks', 'configure', 'groupPolicies'],
            'operation': 'deleteNetworkGroupPolicy'
        }
        resource = f'/networks/{networkId}/groupPolicies/{groupPolicyId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def createNetworkMerakiAuthUser(self, networkId: str, email: str, authorizations: list, **kwargs):
        """
        **Authorize a user configured with Meraki Authentication for a network (currently supports 802.1X, splash guest, and client VPN users, and currently, organizations have a 50,000 user cap)**
        https://developer.cisco.com/meraki/api-v1/#!create-network-meraki-auth-user

        - networkId (string): Network ID
        - email (string): Email address of the user
        - authorizations (array): Authorization zones and expiration dates for the user.
        - name (string): Name of the user. Only required If the user is not a Dashboard administrator.
        - password (string): The password for this user account. Only required If the user is not a Dashboard administrator.
        - accountType (string): Authorization type for user. Can be 'Guest' or '802.1X' for wireless networks, or 'Client VPN' for MX networks. Defaults to '802.1X'.
        - emailPasswordToUser (boolean): Whether or not Meraki should email the password to user. Default is false.
        - isAdmin (boolean): Whether or not the user is a Dashboard administrator.
        """

        kwargs.update(locals())

        if 'accountType' in kwargs:
            options = ['802.1X', 'Client VPN', 'Guest']
            assert kwargs['accountType'] in options, f'''"accountType" cannot be "{kwargs['accountType']}", & must be set to one of: {options}'''

        metadata = {
            'tags': ['networks', 'configure', 'merakiAuthUsers'],
            'operation': 'createNetworkMerakiAuthUser'
        }
        resource = f'/networks/{networkId}/merakiAuthUsers'

        body_params = ['email', 'name', 'password', 'accountType', 'emailPasswordToUser', 'isAdmin', 'authorizations', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def deleteNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **kwargs):
        """
        **Delete an 802.1X RADIUS user, or deauthorize and optionally delete a splash guest or client VPN user.**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-meraki-auth-user

        - networkId (string): Network ID
        - merakiAuthUserId (string): Meraki auth user ID
        - delete (boolean): If the ID supplied is for a splash guest or client VPN user, and that user is not authorized for any other networks in the organization, then also delete the user. 802.1X RADIUS users are always deleted regardless of this optional attribute.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'merakiAuthUsers'],
            'operation': 'deleteNetworkMerakiAuthUser'
        }
        resource = f'/networks/{networkId}/merakiAuthUsers/{merakiAuthUserId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def updateNetworkMerakiAuthUser(self, networkId: str, merakiAuthUserId: str, **kwargs):
        """
        **Update a user configured with Meraki Authentication (currently, 802.1X RADIUS, splash guest, and client VPN users can be updated)**
        https://developer.cisco.com/meraki/api-v1/#!update-network-meraki-auth-user

        - networkId (string): Network ID
        - merakiAuthUserId (string): Meraki auth user ID
        - name (string): Name of the user. Only allowed If the user is not Dashboard administrator.
        - password (string): The password for this user account. Only allowed If the user is not Dashboard administrator.
        - emailPasswordToUser (boolean): Whether or not Meraki should email the password to user. Default is false.
        - authorizations (array): Authorization zones and expiration dates for the user.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'merakiAuthUsers'],
            'operation': 'updateNetworkMerakiAuthUser'
        }
        resource = f'/networks/{networkId}/merakiAuthUsers/{merakiAuthUserId}'

        body_params = ['name', 'password', 'emailPasswordToUser', 'authorizations', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def createNetworkMqttBroker(self, networkId: str, name: str, host: str, port: int, **kwargs):
        """
        **Add an MQTT broker**
        https://developer.cisco.com/meraki/api-v1/#!create-network-mqtt-broker

        - networkId (string): Network ID
        - name (string): Name of the MQTT broker.
        - host (string): Host name/IP address where the MQTT broker runs.
        - port (integer): Host port though which the MQTT broker can be reached.
        - security (object): Security settings of the MQTT broker.
        - authentication (object): Authentication settings of the MQTT broker
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'mqttBrokers'],
            'operation': 'createNetworkMqttBroker'
        }
        resource = f'/networks/{networkId}/mqttBrokers'

        body_params = ['name', 'host', 'port', 'security', 'authentication', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def updateNetworkMqttBroker(self, networkId: str, mqttBrokerId: str, **kwargs):
        """
        **Update an MQTT broker**
        https://developer.cisco.com/meraki/api-v1/#!update-network-mqtt-broker

        - networkId (string): Network ID
        - mqttBrokerId (string): Mqtt broker ID
        - name (string): Name of the MQTT broker.
        - host (string): Host name/IP address where the MQTT broker runs.
        - port (integer): Host port though which the MQTT broker can be reached.
        - security (object): Security settings of the MQTT broker.
        - authentication (object): Authentication settings of the MQTT broker
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'mqttBrokers'],
            'operation': 'updateNetworkMqttBroker'
        }
        resource = f'/networks/{networkId}/mqttBrokers/{mqttBrokerId}'

        body_params = ['name', 'host', 'port', 'security', 'authentication', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def deleteNetworkMqttBroker(self, networkId: str, mqttBrokerId: str):
        """
        **Delete an MQTT broker**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-mqtt-broker

        - networkId (string): Network ID
        - mqttBrokerId (string): Mqtt broker ID
        """

        metadata = {
            'tags': ['networks', 'configure', 'mqttBrokers'],
            'operation': 'deleteNetworkMqttBroker'
        }
        resource = f'/networks/{networkId}/mqttBrokers/{mqttBrokerId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def updateNetworkSettings(self, networkId: str, **kwargs):
        """
        **Update the settings for a network**
        https://developer.cisco.com/meraki/api-v1/#!update-network-settings

        - networkId (string): Network ID
        - localStatusPageEnabled (boolean): Enables / disables the local device status pages (my.meraki.com, ap.meraki.com, switch.meraki.com, wired.meraki.com). Optional (defaults to false)
        - remoteStatusPageEnabled (boolean): Enables / disables access to the device status page (http://[device's LAN IP]). Optional. Can only be set if localStatusPageEnabled is set to true
        - localStatusPage (object): A hash of Local Status page(s)' authentication options applied to the Network.
        - securePort (object): A hash of SecureConnect options applied to the Network.
        - namedVlans (object): A hash of Named VLANs options applied to the Network.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'settings'],
            'operation': 'updateNetworkSettings'
        }
        resource = f'/networks/{networkId}/settings'

        body_params = ['localStatusPageEnabled', 'remoteStatusPageEnabled', 'localStatusPage', 'securePort', 'namedVlans', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action

    def splitNetwork(self, networkId: str):
        """
        **Split a combined network into individual networks for each type of device**
        https://developer.cisco.com/meraki/api-v1/#!split-network

        - networkId (string): Network ID
        """

        metadata = {
            'tags': ['networks', 'configure'],
            'operation': 'splitNetwork'
        }
        resource = f'/networks/{networkId}/split'

        action = {
            "resource": resource,
            "operation": "create",
        }
        return action

    def unbindNetwork(self, networkId: str, **kwargs):
        """
        **Unbind a network from a template.**
        https://developer.cisco.com/meraki/api-v1/#!unbind-network

        - networkId (string): Network ID
        - retainConfigs (boolean): Optional boolean to retain all the current configs given by the template.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure'],
            'operation': 'unbindNetwork'
        }
        resource = f'/networks/{networkId}/unbind'

        body_params = ['retainConfigs', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def createNetworkVlanProfile(self, networkId: str, name: str, vlanNames: list, vlanGroups: list, iname: str):
        """
        **Create a VLAN profile for a network**
        https://developer.cisco.com/meraki/api-v1/#!create-network-vlan-profile

        - networkId (string): Network ID
        - name (string): Name of the profile, string length must be from 1 to 255 characters
        - vlanNames (array): An array of named VLANs
        - vlanGroups (array): An array of VLAN groups
        - iname (string): IName of the profile
        """

        kwargs = locals()

        metadata = {
            'tags': ['networks', 'configure', 'vlanProfiles'],
            'operation': 'createNetworkVlanProfile'
        }
        resource = f'/networks/{networkId}/vlanProfiles'

        body_params = ['name', 'vlanNames', 'vlanGroups', 'iname', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def deleteNetworkVlanProfile(self, networkId: str, iname: str):
        """
        **Delete a VLAN profile of a network**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-vlan-profile

        - networkId (string): Network ID
        - iname (string): Iname
        """

        metadata = {
            'tags': ['networks', 'configure', 'vlanProfiles'],
            'operation': 'deleteNetworkVlanProfile'
        }
        resource = f'/networks/{networkId}/vlanProfiles/{iname}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def createNetworkWebhooksPayloadTemplate(self, networkId: str, name: str, **kwargs):
        """
        **Create a webhook payload template for a network**
        https://developer.cisco.com/meraki/api-v1/#!create-network-webhooks-payload-template

        - networkId (string): Network ID
        - name (string): The name of the new template
        - body (string): The liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
        - headers (array): The liquid template used with the webhook headers.
        - bodyFile (string): A file containing liquid template used for the body of the webhook message. Either `body` or `bodyFile` must be specified.
        - headersFile (string): A file containing the liquid template used with the webhook headers.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'webhooks', 'payloadTemplates'],
            'operation': 'createNetworkWebhooksPayloadTemplate'
        }
        resource = f'/networks/{networkId}/webhooks/payloadTemplates'

        body_params = ['name', 'body', 'headers', 'bodyFile', 'headersFile', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "create",
            "body": payload
        }
        return action

    def deleteNetworkWebhooksPayloadTemplate(self, networkId: str, payloadTemplateId: str):
        """
        **Destroy a webhook payload template for a network**
        https://developer.cisco.com/meraki/api-v1/#!delete-network-webhooks-payload-template

        - networkId (string): Network ID
        - payloadTemplateId (string): Payload template ID
        """

        metadata = {
            'tags': ['networks', 'configure', 'webhooks', 'payloadTemplates'],
            'operation': 'deleteNetworkWebhooksPayloadTemplate'
        }
        resource = f'/networks/{networkId}/webhooks/payloadTemplates/{payloadTemplateId}'

        action = {
            "resource": resource,
            "operation": "destroy",
        }
        return action

    def updateNetworkWebhooksPayloadTemplate(self, networkId: str, payloadTemplateId: str, **kwargs):
        """
        **Update a webhook payload template for a network**
        https://developer.cisco.com/meraki/api-v1/#!update-network-webhooks-payload-template

        - networkId (string): Network ID
        - payloadTemplateId (string): Payload template ID
        - name (string): The name of the template
        - body (string): The liquid template used for the body of the webhook message.
        - headers (array): The liquid template used with the webhook headers.
        - bodyFile (string): A file containing liquid template used for the body of the webhook message.
        - headersFile (string): A file containing the liquid template used with the webhook headers.
        """

        kwargs.update(locals())

        metadata = {
            'tags': ['networks', 'configure', 'webhooks', 'payloadTemplates'],
            'operation': 'updateNetworkWebhooksPayloadTemplate'
        }
        resource = f'/networks/{networkId}/webhooks/payloadTemplates/{payloadTemplateId}'

        body_params = ['name', 'body', 'headers', 'bodyFile', 'headersFile', ]
        payload = {k.strip(): v for k, v in kwargs.items() if k.strip() in body_params}
        action = {
            "resource": resource,
            "operation": "update",
            "body": payload
        }
        return action