import os
import shutil
from runners import *
from runners.fhvae_runner import train, test, dump_latent, dump_repr, repl_repr_utt, factorize, traverse
from tools.kaldi.prep_kaldi_feat import flatten_channel
from datasets.segment import Segment
from datasets.datasets_loaders import datasets_loader
from datasets.datasets_loaders import get_frame_ra_dataset_conf, get_nonoverlap_ra_dataset_conf
from parsers.train_parsers import fhvae_train_parser as train_parser
from parsers.dataset_parsers import kaldi_ra_dataset_parser as dataset_parser
from tools.kaldi.plot_scp import plot_kaldi_feat
from tools.kaldi.plot_fac import plot_kaldi_feat_fac
from kaldi_io import BaseFloatMatrixWriter as BFMWriter
from kaldi_io import BaseFloatVectorWriter as BFVWriter
from kaldi_io import SequentialBaseFloatVectorReader as SBFVReader

DEFAULT_SET_NAME="uttid"
DEFAULT_TRAIN_CONF="conf/train/fhvae/e500_p50_lr1e-3_bs256_nbs2000_ad0.cfg"
DEFAULT_MODEL_CONF="conf/model/fhvae/lstm_2L_256_lat_32_32.cfg"

# flags for all actions
tf.app.flags.DEFINE_boolean("debug", False, "debugging mode (for training) if True")
tf.app.flags.DEFINE_string("arch", "rnn", "dnn|cnn|rnn")
tf.app.flags.DEFINE_string("exp_dir", "", "path to dump/load this experiment")

# flags for if running optional actions
tf.app.flags.DEFINE_boolean("test", True, "run testing if True")
tf.app.flags.DEFINE_boolean("dump_latent", False, "dump latent variable by frame if True")
tf.app.flags.DEFINE_boolean("dump_repr", False, "dump representations if True")
tf.app.flags.DEFINE_boolean("repl_repr_utt", False, "replace representations if True")
tf.app.flags.DEFINE_boolean("fac", False, "show factorization of latent variables if True")
tf.app.flags.DEFINE_boolean("trav", False, "traverse latent space")

# flags for train
tf.app.flags.DEFINE_string("set_name", DEFAULT_SET_NAME, "set name of label conditioned on")
tf.app.flags.DEFINE_string("train_conf", DEFAULT_TRAIN_CONF, "path to training config")
tf.app.flags.DEFINE_string("model_conf", DEFAULT_MODEL_CONF, "path to model config")
tf.app.flags.DEFINE_string("dataset_conf", "", "path to dataset config")
tf.app.flags.DEFINE_integer("n_print_steps", 200, "print training diagnostics every N steps")

tf.app.flags.DEFINE_float("alpha_dis", -1, "alpha for discriminative objective")
tf.app.flags.DEFINE_integer("n_latent1", 0, "z1 dimension")
tf.app.flags.DEFINE_integer("n_latent2", 0, "z2 dimension")

# flags for non-train actions
tf.app.flags.DEFINE_string("feat_rspec", "", "feat rspecifier to replace test_feat_rspec")
tf.app.flags.DEFINE_string("feat_set_name", "", "name(s) of label set(s)")
tf.app.flags.DEFINE_string("feat_utt2label_path", "", "utt2label_path(s) for feat_rspec")
tf.app.flags.DEFINE_string("feat_label_N", "", "number(s) of classes for feat_rspec")

# flags for dump_lat
tf.app.flags.DEFINE_string("train_lat_wspec", "", "train set write specifier")
tf.app.flags.DEFINE_string("dev_lat_wspec", "", "dev set write specifier")
tf.app.flags.DEFINE_string("test_lat_wspec", "", "test set write specifier")
tf.app.flags.DEFINE_string("train_utt_id_map", "", "path to utterance id map")
tf.app.flags.DEFINE_string("dev_utt_id_map", "", "path to utterance id map")
tf.app.flags.DEFINE_string("test_utt_id_map", "", "path to utterance id map")
tf.app.flags.DEFINE_boolean("use_z1", False, "dump z1")
tf.app.flags.DEFINE_boolean("use_z2", True, "dump z2")
tf.app.flags.DEFINE_boolean("use_mean", True, "dump mean of selected latent vars")
tf.app.flags.DEFINE_boolean("use_logvar", True, "dump logvar of selected latent vars")

# flags for dump_repr
tf.app.flags.DEFINE_string("train_repr_wspec", "", "train set write specifier")
tf.app.flags.DEFINE_string("dev_repr_wspec", "", "dev set write specifier")
tf.app.flags.DEFINE_string("test_repr_wspec", "", "test set write specifier")
tf.app.flags.DEFINE_string("train_repr_id_map", "", "path to utterance id map")
tf.app.flags.DEFINE_string("dev_repr_id_map", "", "path to utterance id map")
tf.app.flags.DEFINE_string("test_repr_id_map", "", "path to utterance id map")
tf.app.flags.DEFINE_string("repr_set_name", "", "set name of labels for feat_rspec")
tf.app.flags.DEFINE_string("repr_id_map", "", "path to label id map to dump")
tf.app.flags.DEFINE_string("which_repr", "mu1", "{model_mu1|mu1|mu2}. type of representations.")

# flags for repl_repr_utt
tf.app.flags.DEFINE_string("repl_utt_set_name", "", "set name for replacing representations")
tf.app.flags.DEFINE_string("repl_utt_repr_spec", "", "representation rspecifier")
tf.app.flags.DEFINE_string("repl_utt_list", "", "test set replacing representation list: (uttid_str, attr_str)")
tf.app.flags.DEFINE_string("repl_utt_wspec", "", "test set replacing representation write specifier")
tf.app.flags.DEFINE_string("repl_utt_img_dir", "", "test set replacing representation image directory")
tf.app.flags.DEFINE_string("repl_utt_id_map", "", "")

# flags for vis_fac
tf.app.flags.DEFINE_integer("fac_n", 1, "")
tf.app.flags.DEFINE_string("fac_z1_spec", "", "")
tf.app.flags.DEFINE_string("fac_z2_spec", "", "")
tf.app.flags.DEFINE_string("fac_wspec", "", "")
tf.app.flags.DEFINE_string("fac_img_dir", "", "")

# flags for trav
tf.app.flags.DEFINE_string("trav_spec", "", "")
tf.app.flags.DEFINE_string("trav_img_dir", "", "")

FLAGS = tf.app.flags.FLAGS

def main():
    if FLAGS.arch == "dnn":
        raise NotImplementedError()
    elif FLAGS.arch == "cnn":
        raise NotImplementedError()
    elif FLAGS.arch == "rnn":
        from models.rec_fhvae import RecFacHierVAE as model_class
        from parsers.model_parsers import rec_fhvae_model_parser as model_parser
    else:
        raise ValueError("unsupported architecture %s" % FLAGS.arch)

    # do training
    if not os.path.exists("%s/.done" % FLAGS.exp_dir):
        set_logger(custom_logger("%s/log/train.log" % FLAGS.exp_dir))
        is_train = True
        exp_dir, set_name, model_conf, train_conf, dataset_conf = _load_configs(
                FLAGS, model_parser, is_train)
        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        [train_set, dev_set, _], model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf,
                set_name, is_train, True, True, False)
        train(exp_dir, set_name, model, train_set, dev_set,
                train_conf, FLAGS.n_print_steps, FLAGS.debug)
        unset_logger()

    # do testing
    if FLAGS.test:
        set_logger(custom_logger("%s/log/test.log" % FLAGS.exp_dir))
        is_train = False
        tf.reset_default_graph()
        exp_dir, set_name, model_conf, train_conf, dataset_conf = _load_configs(
                FLAGS, model_parser, is_train)
        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        [_, _, test_set], model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf,
                set_name, is_train, False, False, True)
        test(exp_dir, set_name, model, test_set)
        unset_logger()

    # do dumping latent variables
    if FLAGS.dump_latent:
        set_logger(custom_logger("%s/log/dump_latent.log" % FLAGS.exp_dir))
        is_train = False
        tf.reset_default_graph()
        exp_dir, set_name, model_conf, train_conf, dataset_conf, \
                train_utt_id_map, dev_utt_id_map, test_utt_id_map, \
                dump_latent_opts, train_wspec, dev_wspec, test_wspec = \
                _load_dump_latent_configs(FLAGS, model_parser)

        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        info("WSPECS:\n\ttrain=%s, dev=%s, test=%s" % (train_wspec, dev_wspec, test_wspec))
        datasets, model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf, set_name,
                is_train, bool(train_wspec), bool(dev_wspec), bool(test_wspec))
        wspecs = [train_wspec, dev_wspec, test_wspec]
        id_maps = [train_utt_id_map, dev_utt_id_map, test_utt_id_map]
        dataset_wspec_tuples = [t for t in zip(datasets, wspecs, id_maps) if bool(t[1])]
        for dataset, wspec, id_map in dataset_wspec_tuples:
            for path in wspec.split(":")[1].split(","):
                check_and_makedirs(os.path.dirname(path))
            writer = BFMWriter(wspec)
            dump_latent(exp_dir, model, dataset, id_map, writer.write, dump_latent_opts)
            writer.close()
        unset_logger()

    # do dumping representations
    if FLAGS.dump_repr:
        set_logger(custom_logger("%s/log/dump_repr.log" % FLAGS.exp_dir))
        is_train = False
        tf.reset_default_graph()
        exp_dir, set_name, model_conf, train_conf, dataset_conf, \
                repr_set_name, train_repr_id_map, dev_repr_id_map, test_repr_id_map, \
                dump_repr_opts, train_wspec, dev_wspec, test_wspec = \
                _load_dump_repr_configs(FLAGS, model_parser)

        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        info("WSPECS:\n\ttrain=%s, dev=%s, test=%s" % (train_wspec, dev_wspec, test_wspec))
        datasets, model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf, set_name,
                is_train, bool(train_wspec), bool(dev_wspec), bool(test_wspec))
        wspecs = [train_wspec, dev_wspec, test_wspec]
        id_maps = [train_repr_id_map, dev_repr_id_map, test_repr_id_map]
        dataset_wspec_tuples = [t for t in zip(datasets, wspecs, id_maps) if bool(t[1])]
        for dataset, wspec, id_map in dataset_wspec_tuples:
            for path in wspec.split(":")[1].split(","):
                check_and_makedirs(os.path.dirname(path))
            writer = BFVWriter(wspec)
            dump_repr(exp_dir, model, dataset, id_map, repr_set_name, writer.write, dump_repr_opts)
            writer.close()
        unset_logger()

    # do replacing utterance representation
    if FLAGS.repl_repr_utt:
        set_logger(custom_logger("%s/log/repl_repr_utt.log" % FLAGS.exp_dir))
        is_train = False
        tf.reset_default_graph()
        exp_dir, set_name, model_conf, train_conf, dataset_conf, \
                repl_utt_set_name, repl_utt_wspec, repl_utt_id_map, \
                repl_utt_img_dir, repl_utt_list, label_str_to_repr = \
                _load_repl_repr_utt_configs(FLAGS, model_parser)

        info("Replacing Representation Configurations:")
        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        info("\tset_name: %s" % (repl_utt_set_name))
        info("\trepl_utt_list[0]: %s, repl_utt_wspec: %s" % (repl_utt_list[0], repl_utt_wspec))
        [_, _, test_set], model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf,
                set_name, is_train, False, False, True)

        for path in repl_utt_wspec.split(":")[1].split(","):
            check_and_makedirs(os.path.dirname(path))
        with BFMWriter(repl_utt_wspec) as writer:
            write_fn = lambda uttid, feat_3d: writer.write(uttid, flatten_channel(feat_3d))
            repl_repr_utt(
                    exp_dir, model, test_set, repl_utt_set_name,
                    repl_utt_id_map, label_str_to_repr, repl_utt_list, write_fn)

        check_and_makedirs(repl_utt_img_dir)
        plot_kaldi_feat(repl_utt_wspec, repl_utt_img_dir, dataset_conf["feat_cfg"]["feat_type"])
        unset_logger()

    # do visualizing factorization
    if FLAGS.fac:
        set_logger(custom_logger("%s/log/fac.log" % FLAGS.exp_dir))
        is_train = False
        tf.reset_default_graph()
        exp_dir, set_name, model_conf, train_conf, dataset_conf, \
                fac_opts, fac_wspec, fac_img_dir = _load_fac_configs(FLAGS, model_parser)

        info("Factorization Configurations:")
        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        info("\tfac_wspec: %s" % fac_wspec)
        info("\tfac_opts: %s" % fac_opts)
        [_, _, test_set], model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf,
                set_name, is_train, False, False, True)

        for path in fac_wspec.split(":")[1].split(","):
            check_and_makedirs(os.path.dirname(path))
        with BFMWriter(fac_wspec) as writer:
            write_fn = lambda uttid, feat_3d: writer.write(uttid, flatten_channel(feat_3d))
            factorize(exp_dir, model, test_set, write_fn, fac_opts)
        plot_kaldi_feat_fac(fac_wspec, fac_img_dir, dataset_conf["feat_cfg"]["feat_type"])
        unset_logger()

    # do traversing latent space
    if FLAGS.trav:
        set_logger(custom_logger("%s/log/trav.log" % FLAGS.exp_dir))
        is_train = False
        tf.reset_default_graph()
        exp_dir, set_name, model_conf, train_conf, dataset_conf, \
                trav_img_dir, trav_opts = _load_trav_configs(FLAGS, model_parser)

        info("Traversing Configurations:")
        _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf)
        info("\ttrav_img_dir: %s" % trav_img_dir)
        [_, _, test_set], model = _load_datasets_and_model(
                model_class, dataset_conf, model_conf, train_conf,
                set_name, is_train, False, False, True)

        traverse(exp_dir, model, test_set, trav_img_dir, trav_opts)
        unset_logger()

def _load_configs(flags, model_parser, is_train):
    """use fixed #batches for each epoch"""
    # load and copy configurations
    exp_dir = flags.exp_dir
    check_and_makedirs(exp_dir)
    set_name_path = "%s/set_name" % exp_dir

    if is_train:
        if os.path.exists("%s/model.cfg" % exp_dir):
            info("%s/model.cfg exists, using that" % exp_dir)
        else:
            model_conf = model_parser(flags.model_conf).get_config()
            if flags.n_latent1 > 0:
                model_conf["n_latent1"] = flags.n_latent1
            if flags.n_latent2 > 0:
                model_conf["n_latent2"] = flags.n_latent2
            with open("%s/model.cfg" % exp_dir, "w") as f:
                model_parser.write_config(model_conf, f)

        if os.path.exists("%s/train.cfg" % exp_dir):
            info("%s/train.cfg exists, using that" % exp_dir)
        else:
            train_conf = train_parser(flags.train_conf).get_config()
            if flags.alpha_dis != -1:
                train_conf["alpha_dis"] = flags.alpha_dis
            with open("%s/train.cfg" % exp_dir, "w") as f:
                train_parser.write_config(train_conf, f)

        maybe_copy(flags.dataset_conf, "%s/dataset.cfg" % exp_dir)

        if os.path.exists(set_name_path):
            info("%s exists, using that" % set_name_path)
        else:
            with open(set_name_path, "w") as f:
                f.write(flags.set_name)

    with open(set_name_path) as f:
        set_name = f.read().rstrip()
    model_conf = model_parser("%s/model.cfg" % exp_dir).get_config()
    train_conf = train_parser("%s/train.cfg" % exp_dir).get_config()
    dataset_conf = dataset_parser("%s/dataset.cfg" % exp_dir).get_config()
    if not is_train:
        train_conf["bs"] = 2048
    if not is_train and bool(flags.feat_rspec):
        dataset_conf["test_feat_rspec"] = flags.feat_rspec
        if bool(flags.feat_label_N) and bool(flags.feat_utt2label_path):
            dataset_conf["test_utt2label_paths"] = {}
            feat_set_name_list = flags.feat_set_name.split(",")
            label_N_list = flags.feat_label_N.split(",")
            utt2label_path_list = flags.feat_utt2label_path.split(",")
            assert(len(label_N_list) == len(feat_set_name_list))
            assert(len(label_N_list) == len(utt2label_path_list))
            for feat_set_name, N, path, in \
                    zip(feat_set_name_list, label_N_list, utt2label_path_list):
                dataset_conf["test_utt2label_paths"][feat_set_name] = (int(N), path)
        else:
            dataset_conf["test_utt2label_paths"] = {}
        dataset_conf["test_utt2talabels_paths"] = {}
        info("replaced test_feat_rspec with %s, utt2label_paths %s" % (
            dataset_conf["test_feat_rspec"], dataset_conf["test_utt2label_paths"]))

    return exp_dir, set_name, model_conf, train_conf, dataset_conf

def _print_configs(exp_dir, set_name, model_conf, train_conf, dataset_conf):
    if model_conf["n_bins"] != dataset_conf["n_bins"]:
        raise ValueError("model and dataset n_bins not matched (%s != %s)" % (
                model_conf["n_bins"], dataset_conf["n_bins"]))

    info("Experiment Directory:\n\t%s" % str(exp_dir))
    info("Set Name:\n\t%s" % str(set_name))
    info("Model Configurations:")
    for k, v in sorted(model_conf.items()):
        info("\t%s : %s" % (k.ljust(20), v))
    info("Training Configurations:")
    for k, v in sorted(train_conf.items()):
        info("\t%s : %s" % (k.ljust(20), v))
    info("Dataset Configurations:")
    for k, v in sorted(dataset_conf.items()):
        info("\t%s : %s" % (k.ljust(20), v))

def _load_datasets_and_model(
        FacHierVAE, dataset_conf, model_conf, train_conf,
        set_name, is_train, train, dev, test):
    # initialize dataset and model, create directories
    sets = datasets_loader(dataset_conf, train, dev, test)
    _set = [s for s in sets if s is not None][0]
    model_conf["n_class1"] = dataset_conf["train_utt2label_paths"][set_name][0]
    model_conf["input_shape"] = _set.feat_shape
    model_conf["target_shape"] = _set.feat_shape
    model_conf["target_dtype"] = tf.float32
    if model_conf["n_bins"] is not None:
        model_conf["target_dtype"] = tf.int32
    model = FacHierVAE(model_conf, train_conf, training=is_train)
    return sets, model

def _load_dump_latent_configs(flags, model_parser):
    assert(flags.use_mean or flags.use_logvar)
    assert(flags.train_lat_wspec or flags.dev_lat_wspec or flags.test_lat_wspec)

    exp_dir, set_name, model_conf, train_conf, dataset_conf = \
            _load_configs(flags, model_parser, is_train=False)
    dataset_conf, utt_left_pad, utt_right_pad = \
            get_frame_ra_dataset_conf(dataset_conf)
    dump_latent_opts = {
            "use_z1": flags.use_z1,
            "use_z2": flags.use_z2,
            "use_mean": flags.use_mean,
            "use_logvar": flags.use_logvar,
            "utt_left_pad": utt_left_pad,
            "utt_right_pad": utt_right_pad}
    train_lat_wspec = flags.train_lat_wspec
    dev_lat_wspec = flags.dev_lat_wspec
    test_lat_wspec = flags.test_lat_wspec
    train_utt_id_map = _load_id_map(flags.train_utt_id_map) if train_lat_wspec else None
    dev_utt_id_map = _load_id_map(flags.dev_utt_id_map) if dev_lat_wspec else None
    test_utt_id_map = _load_id_map(flags.test_utt_id_map) if test_lat_wspec else None

    return exp_dir, set_name, model_conf, train_conf, dataset_conf, \
            train_utt_id_map, dev_utt_id_map, test_utt_id_map, \
            dump_latent_opts, train_lat_wspec, dev_lat_wspec, test_lat_wspec

def _load_dump_repr_configs(flags, model_parser):
    assert(flags.repr_set_name)
    assert(flags.which_repr in ["model_mu1", "mu1", "mu2"])
    assert(flags.train_repr_wspec or flags.dev_repr_wspec or flags.test_repr_wspec)

    exp_dir, set_name, model_conf, train_conf, dataset_conf = \
            _load_configs(flags, model_parser, is_train=False)
    # dataset_conf, _, _ = get_frame_ra_dataset_conf(dataset_conf)
    dataset_conf = get_nonoverlap_ra_dataset_conf(dataset_conf)
    dump_repr_opts = {"which_repr": flags.which_repr}
    train_repr_wspec = flags.train_repr_wspec
    dev_repr_wspec = flags.dev_repr_wspec
    test_repr_wspec = flags.test_repr_wspec
    train_repr_id_map = _load_id_map(flags.train_repr_id_map) if train_repr_wspec else None
    dev_repr_id_map = _load_id_map(flags.dev_repr_id_map) if dev_repr_wspec else None
    test_repr_id_map = _load_id_map(flags.test_repr_id_map) if test_repr_wspec else None
    repr_set_name = flags.repr_set_name

    return exp_dir, set_name, model_conf, train_conf, dataset_conf, \
            repr_set_name, train_repr_id_map, dev_repr_id_map, test_repr_id_map, \
            dump_repr_opts, train_repr_wspec, dev_repr_wspec, test_repr_wspec

def _load_repl_repr_utt_configs(flags, model_parser):
    assert(flags.repl_utt_set_name)
    assert(flags.repl_utt_repr_spec)
    assert(flags.repl_utt_wspec)
    assert(flags.repl_utt_list)
    assert(flags.repl_utt_img_dir)
    assert(flags.repl_utt_id_map)

    exp_dir, set_name, model_conf, train_conf, dataset_conf = \
            _load_configs(flags, model_parser, is_train=False)
    dataset_conf, _, _ = get_frame_ra_dataset_conf(dataset_conf)
    repl_utt_set_name = flags.repl_utt_set_name
    repl_utt_wspec = flags.repl_utt_wspec
    repl_utt_img_dir = flags.repl_utt_img_dir
    repl_utt_id_map = _load_id_map(flags.repl_utt_id_map)
    repl_utt_list = [line.rstrip().split() for line in open(flags.repl_utt_list)]
    label_str_to_repr = _load_repr(flags.repl_utt_repr_spec)

    return exp_dir, set_name, model_conf, train_conf, dataset_conf, \
            repl_utt_set_name, repl_utt_wspec, repl_utt_id_map, \
            repl_utt_img_dir, repl_utt_list, label_str_to_repr

def _load_fac_configs(flags, model_parser):
    assert(flags.fac_z1_spec)
    assert(flags.fac_z2_spec)
    assert(flags.fac_wspec)
    assert(flags.fac_img_dir)

    fac_n = flags.fac_n
    z1_utt_list, z1_segs = _load_utt_or_seg_spec(flags.fac_z1_spec)
    z2_utt_list, z2_segs = _load_utt_or_seg_spec(flags.fac_z2_spec)
    fac_opts = {
            "n": fac_n,
            "z1_utt_list": z1_utt_list,
            "z2_utt_list": z2_utt_list,
            "z1_segs": z1_segs,
            "z2_segs": z2_segs}
    fac_wspec = flags.fac_wspec
    fac_img_dir = flags.fac_img_dir
    exp_dir, set_name, model_conf, train_conf, dataset_conf = \
            _load_configs(flags, model_parser, is_train=False)
    return exp_dir, set_name, model_conf, train_conf, \
            dataset_conf, fac_opts, fac_wspec, fac_img_dir

def _load_trav_configs(flags, model_parser):
    assert(flags.trav_img_dir)

    exp_dir, set_name, model_conf, train_conf, dataset_conf = \
            _load_configs(flags, model_parser, is_train=False)
    if flags.trav_spec:
        seed_utt_list, seed_segs = _load_utt_or_seg_spec(flags.trav_spec)
    else:
        seed_utt_list, seed_segs = None, None
    trav_img_dir = flags.trav_img_dir
    trav_opts = {
        "n": 5,
        "seed_utt_list": seed_utt_list,
        "seed_segs": seed_segs,
        "k": 9,
        "trav_range": (-3, 3),
        "figsize": (10, 30),
        "feat_type": dataset_conf["feat_cfg"]["feat_type"],
    }
    return exp_dir, set_name, model_conf, train_conf, dataset_conf, trav_img_dir, trav_opts

def _load_utt_or_seg_spec(fac_spec_path):
    fac_spec = [line.rstrip() for line in open(fac_spec_path)]
    assert(bool(fac_spec))
    if len(fac_spec[0].split()) == 1:
        fac_list, fac_segs = fac_spec, None
    elif len(fac_spec[0].split()) == 3:
        fac_list = None
        fac_spec = [line.split() for line in fac_spec]
        fac_segs = [Segment(toks[0], int(toks[1]), int(toks[2]), None) for toks in fac_spec]
    else:
        raise ValueError(
                "#fields must be 1 (utterance id) or 3 (segment); got %s" % len(fac_spec[0]))
    return fac_list, fac_segs

def _load_id_map(id_map_path):
    """id_map_path is the path to a file with ``key id'' format
    output is a dictionary map from id (int) to key (str)"""
    id_map = {}
    with open(id_map_path) as f:
        id_content = f.readlines()
    for l in id_content:
        l = l.split(' ')
        id_map[int(l[1])] = l[0]
    return id_map

def _load_repr(repr_rspec):
    label_str_to_repr = dict()
    with SBFVReader(repr_rspec) as f:
        while not f.done():
            label_str, attr = f.next()
            label_str_to_repr[label_str] = attr
    return label_str_to_repr

if __name__ == "__main__":
    main()


from flask import Blueprint, redirect, url_for, render_template, jsonify, request, flash
from flask_login import login_required, current_user
from kriskap.addresses.forms import AddressForm
from kriskap.addresses.utils import (
    search_municipality,
    search_barangay,
    search_province,
)
from kriskap import db
from kriskap.models import Address

addresses = Blueprint("addresses", __name__)

@addresses.route("/address")
@login_required
def address():
    """Route for displaying addresses of the current user."""

    addresses = (
        Address.query.filter_by(buyer_id=current_user.id)
        .order_by(Address.default)
        .all()
    )
    return render_template("address.html", title="Address", addresses=addresses)

@addresses.route("/address/add", methods=["GET", "POST"])
@login_required
def add_address():
    """Route for adding new delivery addresses for the current user."""

    form = AddressForm()
    # If the user has an existing address, the new address is not set as the default.
    # Otherwise, the new address is set as the default.
    if Address.query.filter_by(buyer_id=current_user.id).first():
        default = "not_default"
    else:
        default = "default"
    if form.validate_on_submit():
        cities = search_municipality(request.form["province"])
        barangays = search_barangay(request.form["city"])
        new_address = Address(
            default=default,
            buyer=current_user,
            house=form.house.data,
            province=dict(search_province()).get(form.province.data),
            city=dict(cities).get(request.form["city"]),
            barangay=dict(barangays).get(request.form["barangay"]),
        )
        db.session.add(new_address)
        db.session.commit()
        flash("Delivery address added successfully", "success")
        return redirect(url_for("addresses.address"))
    return render_template("add_address.html", title="Add Address", form=form)

@addresses.route("/address/<int:address_id>/edit", methods=["GET", "POST"])
@login_required
def edit_address(address_id):
    """Route for editing an existing delivery address for the current user."""

    address = Address.query.get_or_404(address_id)
    form = AddressForm(house=address.house)
    if form.validate_on_submit():
        cities = search_municipality(request.form["province"])
        barangays = search_barangay(request.form["city"])
        address.house = form.house.data
        address.province = dict(search_province()).get(form.province.data)
        address.city = dict(cities).get(request.form["city"])
        address.barangay = dict(barangays).get(request.form["barangay"])
        db.session.commit()
        flash("Address edited successfully.", "success")
        return redirect(url_for("addresses.address"))
    return render_template(
        "add_address.html", title="Edit Address", address_id=address_id, form=form
    )

@addresses.route("/address/<int:address_id>/delete")
@login_required
def delete_address(address_id):
    """Route for deleting an existing delivery address for the current user."""

    address = Address.query.get_or_404(address_id)
    db.session.delete(address)
    db.session.commit()
    flash("Address deleted.", "success")
    return redirect(url_for("addresses.address"))

@addresses.route("/address/<int:address_id>/default_address")
@login_required
def default_address(address_id):
    """Set a specific address as the default address for the current user."""

    address = Address.query.get_or_404(address_id)
    # Find any existing default addresses for the user.
    is_exist = Address.query.filter_by(
        buyer_id=current_user.id, default="default"
    ).first()
    # If there's an existing default address, set it to not default.
    if is_exist:
        is_exist.default = "not_default"
        db.session.commit()

    # Set the specified address as the default address.
    address.default = "default"
    db.session.commit()
    return redirect(url_for("addresses.address"))

@addresses.route("/address/search-city", methods=["POST"])
@login_required
def search_city():
    """AJAX request to search for a cities/municipalities."""

    province_code = request.form["province_code"]
    cities = search_municipality(province_code)
    return jsonify({"result": "success", "cities": cities})

@addresses.route("/address/search-barangay", methods=["POST"])
@login_required
def search_home_address():
    """AJAX request to search for barangays."""

    city_code = request.form["city_code"]
    barangays = search_barangay(city_code)
    return jsonify({"result": "success", "barangays": barangays})


#Import all dependencies:
import numpy as np
import sqlalchemy
import datetime as dt
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine, func
from flask import Flask, jsonify

# Create connection to Hawaii.sqlite file
engine = create_engine("sqlite:///Resources/hawaii.sqlite")

# reflect an existing database into a new model
Base = automap_base()

# reflect the tables
Base.prepare(engine, reflect=True)

# Save references to the measurement and station tables in the database
Measurement = Base.classes.measurement
Station = Base.classes.station

# Initialize Flask
app = Flask(__name__)

# Create  route
@app.route("/")
def welcome():
    """List all available api routes."""
    return (
        f"Available Routes:
"
        f"/api/v1.0/precipitation
"
        f"/api/v1.0/stations
"
        f"/api/v1.0/tobs
"
        f"/api/v1.0/start
"
        f"/api/v1.0/start/end
"
        f"Note: to access values between a start and end date enter both dates using format: YYYY-mm-dd/YYYY-mm-dd"
    )

app.route("/api/v1.0/precipitation")
def precipitation():
    session = Session(engine)
    #calculate previous year based on the last entry in the table
    prev_year = dt.date(2017,8,23) - dt.timedelta(days=365)
    #calculate precipitation for the previous year
    precipitation = session.query(Measurement.date, Measurement.prcp).\
    filter(Measurement.date >= prev_year).all()
    precip = {date: prcp for date, prcp in precipitation}
    session.close()
    return jsonify(precip)

app.route("/api/v1.0/precipitation")
def precipitation():
    session = Session(engine)
    #calculate previous year based on the last entry in the table
    prev_year = dt.date(2017,8,23) - dt.timedelta(days=365)
    #calculate precipitation for the previous year
    precipitation = session.query(Measurement.date, Measurement.prcp).\
    filter(Measurement.date >= prev_year).all()
    precip = {date: prcp for date, prcp in precipitation}
    session.close()
    return jsonify(precip)

@app.route("/api/v1.0/tobs")
def temp_monthly():
     session = Session(engine)
     prev_year = dt.date(2017,8,23) - dt.timedelta(days=365)
     #calculate all the temperature reported at the highest reported station for the previous year
     results = session.query(Measurement.tobs).\
         filter(Measurement.station == 'USC00519281').\
         filter(Measurement.date >= prev_year).all()
     temps = list(np.ravel(results))
     session.close()
     return jsonify(temps=temps)

@app.route("/api/v1.0/<start>/<end>")

# Define function, set start and end dates entered by user as parameters for start_end_date decorator
def Start_end_date(start, end):
    session = Session(engine)

    """Return a list of min, avg and max tobs between start and end dates entered"""

    # Create query for minimum, average, and max tobs where query date is greater than or equal to the start date and less than or equal to end date user submits in URL

    start_end_date_tobs_results = session.query(func.min(Measurement.tobs), func.avg(Measurement.tobs), func.max(Measurement.tobs)).\
        filter(Measurement.date >= start).\
        filter(Measurement.date <= end).all()

    session.close()

    # Create a list of min,max,and average temps that will be appended with dictionary values for min, max, and avg tobs queried above
    start_end_tobs_date_values = []
    for min, avg, max in start_end_date_tobs_results:
        start_end_tobs_date_dict = {}
        start_end_tobs_date_dict["min_temp"] = min
        start_end_tobs_date_dict["avg_temp"] = avg
        start_end_tobs_date_dict["max_temp"] = max
        start_end_tobs_date_values.append(start_end_tobs_date_dict)

    return jsonify(start_end_tobs_date_values)

if __name__ == '__main__':
    app.run(debug=True)


import http.client
from typing import Annotated, Literal

from core.formatting import _str_to_bool
from database.studies import (
    attach_run_to_study,
    attach_task_to_study,
    get_study_by_alias,
    get_study_by_id,
    get_study_data,
)
from database.studies import create_study as db_create_study
from database.users import User, UserGroup
from fastapi import APIRouter, Depends, HTTPException
from schemas.core import Visibility
from schemas.study import CreateStudy, Study, StudyType
from sqlalchemy import Connection, Row

from routers.dependencies import expdb_connection, fetch_user

router = APIRouter(prefix="/studies", tags=["studies"])

def _get_study_raise_otherwise(id_or_alias: int | str, user: User | None, expdb: Connection) -> Row:
    if isinstance(id_or_alias, int) or id_or_alias.isdigit():
        study = get_study_by_id(int(id_or_alias), expdb)
    else:
        study = get_study_by_alias(id_or_alias, expdb)

    if study is None:
        raise HTTPException(status_code=http.client.NOT_FOUND, detail="Study not found.")
    if study.visibility == Visibility.PRIVATE:
        if user is None:
            raise HTTPException(status_code=http.client.UNAUTHORIZED, detail="Study is private.")
        if study.creator != user.user_id and UserGroup.ADMIN not in user.groups:
            raise HTTPException(status_code=http.client.FORBIDDEN, detail="Study is private.")
    if _str_to_bool(study.legacy):
        raise HTTPException(
            status_code=http.client.GONE,
            detail="Legacy studies are no longer supported",
        )
    return study

@router.post("/")
def create_study(
    study: CreateStudy,
    user: Annotated[User | None, Depends(fetch_user)] = None,
    expdb: Annotated[Connection, Depends(expdb_connection)] = None,
) -> dict[Literal["study_id"], int]:
    if user is None:
        raise HTTPException(
            status_code=http.client.UNAUTHORIZED,
            detail="Creating a study requires authentication.",
        )
    if study.main_entity_type == StudyType.RUN and study.tasks:
        raise HTTPException(
            status_code=http.client.BAD_REQUEST,
            detail="Cannot create a run study with tasks.",
        )
    if study.main_entity_type == StudyType.TASK and study.runs:
        raise HTTPException(
            status_code=http.client.BAD_REQUEST,
            detail="Cannot create a task study with runs.",
        )
    if study.alias and get_study_by_alias(study.alias, expdb):
        raise HTTPException(
            status_code=http.client.CONFLICT,
            detail="Study alias already exists.",
        )
    study_id = db_create_study(study, user, expdb)
    if study.main_entity_type == StudyType.TASK:
        for task_id in study.tasks:
            attach_task_to_study(task_id, study_id, user, expdb)
    if study.main_entity_type == StudyType.RUN:
        for run_id in study.runs:
            attach_run_to_study(run_id, study_id, user, expdb)
    # Make sure that invalid fields raise an error (e.g., "task_ids")
    return {"study_id": study_id}

@router.get("/{alias_or_id}")
def get_study(
    alias_or_id: int | str,
    user: Annotated[User | None, Depends(fetch_user)] = None,
    expdb: Annotated[Connection, Depends(expdb_connection)] = None,
) -> Study:
    study = _get_study_raise_otherwise(alias_or_id, user, expdb)
    study_data = get_study_data(study, expdb)
    return Study(
        id_=study.id,
        name=study.name,
        alias=study.alias,
        main_entity_type=study.type_,
        description=study.description,
        visibility=study.visibility,
        status=study.status,
        creation_date=study.creation_date,
        creator=study.creator,
        data_ids=[row.data_id for row in study_data],
        task_ids=[row.task_id for row in study_data],
        run_ids=[row.run_id for row in study_data] if study.type_ == StudyType.RUN else [],
        flow_ids=[row.flow_id for row in study_data] if study.type_ == StudyType.RUN else [],
        setup_ids=[row.setup_id for row in study_data] if study.type_ == StudyType.RUN else [],
    )


"""Munge transmitter data."""

import argparse
import logging
from pathlib import Path

import dbfread
import numpy as np
import pandas as pd

from ..utils.misc import sex_to_dec
from .file import fix_raw_tafl

logger = logging.getLogger('rasp')
logger.addHandler(logging.NullHandler())

__all__ = ["tafl", "baserad", "sitedata",]

DROP_COLUMNS = [
    "auto_prog",
    "bc_mode",
    "border",
    "brdr_lat",
    "brdr_long",
    "can_land",
    "cert_numb",
    "clist1",
    "clist10",
    "clist2",
    "clist3",
    "clist4",
    "clist5",
    "clist6",
    "clist7",
    "clist8",
    "clist9",
    "dec_number",
    "doc_file",
    "euvalu",
    "fre_land",
    "ifrbn_d",
    "ifrbn_n",
    "last_mod_date",
    "latitude2",
    "longitude2",
    "network",
    "ok_dump",
    "scmo",
    "st_creat",
    "st_mod",
    "status1",
    "status2",
    "structure_height",
    "tx_pwr_type",
    "unattended",
    "usa_land",
    "zone_enhancer",
]

# for MBS stations
RENAME_COLUMNS = {
    "transmit_freq": "frequency",
    "transmit_lower": "frequency_lower",
    "transmit_upper": "frequency_upper",
    "transmit_bw": "bandwidth",
    "bw_emission": "bandwidth_designator",
    "tx_pwr": "eirp",
    "tx_ant_gain": "gain",
    "tx_line_loss": "line_loss",
    "tx_ant_azim": "azimuth_angle",
    "tx_ant_elev_angle": "elevation_angle",
    "tx_ant_ht": "height",
    "stuct_ht": "structure_height",
    "site_elev": "site_elevation",
    "tx_ant_mfr": "antenna_manufacturer",
    "tx_ant_model": "antenna_model",
    "tx_ant_directional": "directional",
    "tx_mfr": "manufacturer",
    "tx_model": "model",
    "new_licno": "new_licence_number",
    "old_licno": "old_licence_number",
    "prov": "province",
}

NUMERIC_COLUMNS = [
    "frequency",
    "frequency_lower",
    "frequency_upper",
    "bandwidth",
    "latitude",
    "longitude",
    "site_elevation",
    "structure_height",
    "eirp",
    "erpvav",
    "erpvpk",
    "erphav",
    "erphpk",
    "height",
    "azimuth_angle",
    "elevation_angle",
    "gain",
    "line_loss",
]

def dbf_to_df(path, encoding="latin1"):
    return pd.DataFrame(iter(dbfread.DBF(path, encoding=encoding)))

def _tafl(stations, radians=False, allow_duplicates=False, allow_nonoperational=False, allow_unauthorized=False):
    logger.info('Munging transmitter database...')
    transmitters = stations.loc[stations.station_function == 'TX'].copy()

    if not radians:
        # Convert latitudes and longitudes from degrees to radians
        transmitters.loc[:,'latitude'] = np.radians(transmitters.loc[:,'latitude'])
        transmitters.loc[:,'longitude'] = np.radians(transmitters.loc[:,'longitude'])

    if not allow_duplicates:
        # Remove any duplicated tranmitters in database
        n1 = len(transmitters)
        transmitters.drop_duplicates(keep='first', inplace=True)
        n2 = len(transmitters)
        logger.info(f'Found and removed {n1-n2} duplicated transmitters')

    if not allow_nonoperational:
        # Remove non-operational transmitters (including auxiliary transmitters and those under consideration)
        n1 = len(transmitters)
        bad_operational_status = ('AX','AXO','AXP','UX','PUC','UC')
        transmitters = transmitters[~transmitters.operational_status.isin(bad_operational_status)]
        n2 = len(transmitters)
        logger.info(f'Removed {n1-n2} non-operational transmitters (including auxiliary transmitters and those under consideration)')

    if not allow_unauthorized:
        # Remove transmitters with cancelled or "not granted" authorization status
        n1 = len(transmitters)
        bad_authorization_status = ('-4','-2','NG')
        transmitters = transmitters[~transmitters.authorization_status.isin(bad_authorization_status)]
        n2 = len(transmitters)
        logger.info(f'Removed {n1-n2} unauthorized transmitters')

    return transmitters

def tafl(input_path, output_path=None):
    columns = [0,1,10,14,15,16,23,24,25,26,27,28,29,30,31,33,37,39,40,41,42,43,48,49,51,52,54,56,58,59]
    fieldnames = ['station_function','frequency','bandwidth','erp','power','loss','gain','pattern',
                      'half_power_beamwidth','fb_ratio','polarization','haat','azimuth','elevation_angle','location',
                      'call_sign','identical_stations','province','latitude','longitude','ground_elevation','height',
                      'service','subservice','authorization_status','in-service_date','licensee','operational_status',
                      'horizontal_power','vertical_power']
    dtypes = {'frequency': float,'bandwidth': float,'erp': float,'power': float,'loss': float,'gain': float,
                  'pattern': str,'half_power_beamwidth': float,'fb_ratio': float,'haat': float,'azimuth': float,
                  'elevation_angle': float,'latitude': float,'longitude': float,'ground_elevation': float,'height': float,
                  'service': int,'subservice': int,'authorization_status': str,'licensee': str, 'operational_status': str,
                  'horizontal_power': float,'vertical_power': float}
    try:
        stations = pd.read_csv(input_path, usecols=columns, names=fieldnames, dtype=dtypes, header=None, na_values=['-'])
    except ValueError:
        logger.warning('Failed to read CSV. Trying to fix known delimiter error in TAFL database...')
        fix_raw_tafl(tafl_path=input_path)
        stations = pd.read_csv(input_path, usecols=columns, names=fieldnames, dtype=dtypes, header=None, na_values=['-'])
        logger.warning('Successfully read CSV!')
    transmitters = _tafl(stations)

    if output_path is None:
        output_path = input_path.with_name(input_path.name.lower())

    logger.info(f'writing munged TAFL data to {output_path}')
    transmitters.to_csv(output_path, index=False)
    return output_path

def _sitedata(stations):
    logger.info('munging records')
    stations.rename(columns={c: c.lower() for c in stations.columns}, inplace=True)
    stations.rename(columns=RENAME_COLUMNS, inplace=True)

    for col in NUMERIC_COLUMNS:
        try:
            stations[col] = pd.to_numeric(stations[col])
        except KeyError:
            continue

    stations.latitude = np.deg2rad(stations.latitude)
    stations.longitude = np.deg2rad(stations.longitude)

    # if power values are EIRP (i.e. type "I"), then we don't have to do anything else there
    if not (stations.tx_pwr_type == "I").all():
        print(f"not all site power values in the SiteData DBF are EIRP, like expected")

    # clean up heights
    bad_height_inds = np.any(
        [np.isnan(stations.height), stations.height == 0.0], axis=0
    )

    stations.loc[bad_height_inds, "height"] = stations.loc[
        bad_height_inds, "structure_height"
    ]

    # convert EIRP to power, baking in the line losses
    stations.loc[:, "power"] = stations.eirp / 10 ** (stations.gain / 10.0)

    stations.drop(columns=DROP_COLUMNS, errors="ignore", inplace=True)
    # stations = stations.reindex(sorted(stations.columns), axis=1)

    stations.loc[:, 'service'] = 'MBS'

    return stations

def sitedata(input_path, output_path=None):
    input_path = Path(input_path)

    logger.info(f'reading site data from {input_path}')
    stations = pd.read_csv(input_path, encoding="latin1", dtype=str)
    logger.info(f'{len(stations)} records found')

    stations = _sitedata(stations)

    if output_path is None:
        output_path = input_path.with_name(input_path.name.lower())

    logger.info(f'writing munged site data to {output_path}')
    stations.to_csv(output_path, index=False, encoding="utf8")
    return output_path

def _baserad(stations, params=None, label=False):
    # lower-case column names
    stations.rename(
        columns={c: c.split(",")[0].lower() for c in stations.columns}, inplace=True
    )

    # convert to decimal lat/lon, assuming western hemisphere
    stations.latitude = stations.latitude.map(sex_to_dec)
    stations.longitude = -stations.longitude.map(sex_to_dec)

    if "latitude2" in stations:
        stations.loc[stations.latitude == 0, "latitude"] = stations.loc[
            stations.latitude == 0, "latitude2"
        ]
        stations.loc[stations.longitude == 0, "longitude"] = stations.loc[
            stations.longitude == 0, "longitude2"
        ]

    # convert to radians
    stations.latitude = np.deg2rad(stations.latitude)
    stations.longitude = np.deg2rad(stations.longitude)

    for col in NUMERIC_COLUMNS:
        try:
            stations[col] = pd.to_numeric(stations[col])
        except KeyError:
            continue

    label = label.lower()

    if label == "am":
        if params is None:
            raise ValueError("`params` must be supplied for AM transmitters")

        # convert to MHz, from kHz
        stations.frequency = stations.frequency.astype(float) / 1e3

        # (worst-case) power
        stations = stations.assign(
            power=np.max([stations.powerday, stations.powernight], axis=0)
        )

        # make callsign_banner -> height mapping
        heights = {row.calls_banr: row.height for _, row in params.iterrows()}
        average_height = np.mean(list(heights.values()))

        # add height field
        stations["height"] = stations.apply(
            lambda row: heights.get(f"{row.call_sign},{row.banner}", average_height),
            axis=1,
        )

        # convert height from degrees to metres
        stations["wavelength"] = 299.8 / stations.frequency
        stations["height"] = stations.height * stations.wavelength / 360
    elif label in ["fm", "tv"]:
        erp_columns = ["erpvav", "erpvpk", "erphav", "erphpk"]

        stations["erp"] = np.max(
            stations[[col for col in erp_columns if col in stations]], axis=1
        )
        stations["eirp"] = 1.64 * stations["erp"]

        stations.rename(columns={"overall_h": "height"}, inplace=True)
        stations["height"] = stations["height"].astype(float)

        # missing height stations get set to the average value
        stations.loc[~(stations.height > 0), "height"] = (
            stations.loc[stations.height > 0, "height"].astype(float).mean()
        )
    else:
        raise ValueError(
            f'baserad label `{label}` not understood; expecting "am", "fm", or "tv"'
        )

    stations.drop(columns=DROP_COLUMNS, errors="ignore", inplace=True)
    # stations = stations.reindex(sorted(stations.columns), axis=1)

    stations.loc[:, 'service'] = label.upper()

    return stations

def baserad(input_dir, output_dir=None):
    input_dir = Path(input_dir)
    params = dbf_to_df(input_dir.joinpath("params.dbf"))
    params.rename(
        columns={c: c.split(",")[0].lower() for c in params.columns}, inplace=True
    )

    if output_dir is None:
        output_dir = input_dir

    for label in ["am", "fm", "tv"]:
        dbf_path = input_dir.joinpath(label + "statio.dbf")

        logger.info(f'reading site data from {dbf_path}')
        stations = dbf_to_df(dbf_path)

        logger.info(f'{len(stations)} records found')
        stations = _baserad(stations, params, label)

        output_path = output_dir.joinpath(label + "statio.csv")
        logger.info(f'writing munged site data to {output_path}')
        stations.to_csv(
            output_path, index=False, encoding="utf8"
        )

    return output_dir

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Munge the Industry Canada transmitter dbf files.")
    parser.add_argument("--tafl", type=str)
    parser.add_argument("--baserad", type=str)
    parser.add_argument("--sitedata", type=str)
    args = parser.parse_args()

    if args.tafl:
        tafl(args.tafl)

    if args.baserad:
        baserad(args.baserad)

    if args.sitedata:
        sitedata(args.sitedata)


import json

from Logic.Files.Classes.Skins import Skins
from Database.DatabaseManager import DatabaseManager

from Logic.Data.DataManager import Writer, Reader

class LogicEnableSkinRandomizerCommand(Reader):
    def __init__(self, client, player, data):
        super().__init__(data)
        self.client = client
        self.player = player

    def decode(self):
        print()
        self.skinData = self.readDataReferenceDouble()
        self.state = self.readBoolean()

    def process(self):
        self.db = DatabaseManager()
        self.database = json.loads(self.db.getPlayerWithLowID(self.player.LowID)[0][2])
        if self.skinData != 0:
            if self.state == True:
                self.database['brawlerState'][Skins.getBrawlerBySkin(self, self.skinData[1])] = 18
            else:
                self.database['brawlerState'][Skins.getBrawlerBySkin(self, self.skinData[1])] = 2
            self.database['selectedSkin'][Skins.getBrawlerBySkin(self, self.skinData[1])] = self.skinData[1]
        self.db.updatePlayerData(self.database, self.player.LowID)


"""
Count nice pairs in an array

Reference: https://leetcode.com/problems/count-number-of-nice-pairs/

You are given an array nums that consists of non-negative integers. Let us
define rev(x) as the reverse of the non-negative integer x. For example,
rev(123) = 321, and rev(120) = 21. A pair of indices (i, j) is nice if it
satisfies all of the following conditions:

- 0 <= i < j < nums.length
- nums[i] + rev(nums[j]) == nums[j] + rev(nums[i]) i

Return the number of nice pairs of indices. Since that number can be too large, return
it modulo 109 + 7.

Example 1:

Input: nums = [42,11,1,97]
Output: 2

Explanation: The two pairs are:
 - (0,3) : 42 + rev(97) = 42 + 79 = 121, 97 + rev(42) = 97 + 24 = 121.
 - (1,2) : 11 + rev(1) = 11 + 1 = 12, 1 + rev(11) = 1 + 11 = 12.

Example 2:

Input: nums = [13,10,35,24,76]
Output: 4

Time Complexity: O(N)
Space Complexity: O(N)
"""

import collections

def countNicePairs(nums):
    """
    :type nums: List[int]
    :rtype: int
    """

    def rev(x):
        """Reverse String"""
        return int(str(x)[::-1])

    MOD = 10 ** 9 + 7
    total = 0
    c = collections.Counter()
    for x in nums:
        current = x - rev(x)
        total += c[current]
        total %= MOD
        c[current] += 1
    return total % MOD

if __name__ == "__main__":
    nums = [42, 11, 1, 97]
    print(countNicePairs(nums))


import json
import boto3
from botocore.exceptions import ClientError
from boto3.dynamodb.conditions import Key, Attr
from datetime import datetime

dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])
notdictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i not in set(y) ])
class AssumptionsRepo:
    def __init__(self, aws_session):
        dynamodb = aws_session.resource('dynamodb', region_name='us-west-2')
        self.assumptions_table = dynamodb.Table('Assumptions')
        self.criteria_table = dynamodb.Table('CmaCriteria')

    def save(self, a):
        assumptions_table = self.assumptions_table
        criteria_table = self.criteria_table
        print('updating assumptions for ' + a.user_id)
        if (a.site_id == "__DEFAULT__"):
            global_criteria = a.global_criteria
            global_criteria["siteId"] = "__DEFAULT__"
            print('updating global criteria')
            print(global_criteria)
            criteria_table.put_item(Item=global_criteria)
        else:
            site_assumptions = a.site_assumptions
            site_assumptions["siteId"] = a.site_id
            site_assumptions["updatedBy"] = a.user_id
            site_assumptions["lastUpdateDate"] = a.date
            print('updating site criteria for ' + a.site_id)
            criteria_table.put_item(Item=site_assumptions)

        return assumptions_table.put_item(Item=a.user_assumptions)

    def save_platform_assumptions(self, a):
        criteria_table = self.criteria_table
        print('updating platform assumptions')

        global_criteria = a.global_criteria
        global_criteria["siteId"] = "__DEFAULT__"
        print(global_criteria)
        return criteria_table.put_item(Item=global_criteria)

    def save_user_assumptions(self, a):
        assumptions_table = self.assumptions_table
        print('updating assumptions for ' + a.user_id)
        return assumptions_table.put_item(Item=a.user_assumptions)

    def save_site_assumptions(self, a):
        criteria_table = self.criteria_table
        site_assumptions = a.site_assumptions
        site_assumptions["siteId"] = a.site_id
        site_assumptions["updatedBy"] = a.user_id
        site_assumptions["lastUpdateDate"] = a.date
        print('updating site criteria for ' + a.site_id)
        return criteria_table.put_item(Item=site_assumptions)

    def delete(self, user):
        # don't delete the default values
        if (user != "__DEFAULT__"):
            self.criteria_table.delete_item(Key={'userId': user })

    @classmethod
    def get_options(self, isAdmin):
        return {
            "cma_pretty": False,
            "pretty_money": False,
            "cma_properties": isAdmin,
            "area_properties": isAdmin,
            "market_value": isAdmin,
            "aggregate_results": isAdmin
        }

    def get_assumptions(self, user, site_id, isAdmin):
        assumptions_table = self.assumptions_table
        criteria_table = self.criteria_table
        try:
            print('getting user assumptions for ' + user)
            response = assumptions_table.get_item(Key={'userId': user })

            if (not response.get("Item")):
                print('assumptions for user ' + user + ' not found.  getting default assumptions.')
                # if the user doesn't have assumptions, just use the default assumptions
                response = assumptions_table.get_item(Key={'userId': '__DEFAULT__' })

            user_assumptions = response['Item']
            # if (user == "__DEFAULT__" and isAdmin):
            #     criteria_response = criteria_table.get_item(Key={'siteId': '__DEFAULT__' })
            #     criteria = criteria_response['Item']
            #     user_assumptions = {**criteria, **user_assumptions}
            if site_id:
                response = criteria_table.get_item(Key={'siteId': '__DEFAULT__' })
                platform_assumptions = response.get('Item', {})
                print('platform assumptions')
                print(platform_assumptions)
                response = criteria_table.get_item(Key={'siteId': site_id })
                site_assumptions = response.get('Item', {})
                print('site assumptions for ' + site_id)
                print(site_assumptions)
                user_assumptions = {**platform_assumptions, **site_assumptions, **user_assumptions}
                print('merged assumptions')
                print(user_assumptions)

            result = {
                "options": AssumptionsRepo.get_options(isAdmin),
                "parameters": user_assumptions
            }

            return result
        except ClientError as e:
            print(e.response['Error']['Message'])
            return None


from typing import Dict, Sequence, Tuple
import re
import numpy as np
import torch

def postprocess_classification_generation(predictions) -> str:
    return re.split("Prompt|Completion", predictions, 1)[0]

def compute_classification_accuracy(predictions: Sequence[Dict[str, str]]) -> float:
    """Compute the accuracy of a sequence of predictions."""

    def _preprocess_fn(s):
        """Function to preprocess both targets and predictions."""
        return s.lower()

    is_correct = [
        _preprocess_fn(x["prediction"]) == _preprocess_fn(x["class_label"])
        for x in predictions
    ]

    return np.mean(is_correct).item()

def compute_shifted_logits_and_labels(
    logits: torch.Tensor, encodings, tokenizer, eoc_token_id
) -> Tuple[torch.Tensor, torch.Tensor]:
    """Helper function to compute shifted logits and labels.

    This allows for straightforward computation of the loss on shift_logits
    and shift_labels such that the nth element of logits computes the n-1th
    element of the original labels (in the outputs, the nth element of logits
    corresponds to the nth element of the labels).

    Elements in shift_labels that correspond to inputs are masked with values
    of -100 (by default in hf, loss is only computed on token IDs >= 0).

    Returns: tuple containing two elements:
        shift_logits: a float Tensor of shape [batch_size, seq_len - 1].
        shift_labels: an integer Tensor of shape [batch_size, seq_len - 1]
    """

    labels = encodings["input_ids"].clone()

    # convert padding and EOC tokens to -100 so they are ignored in loss
    labels[labels == tokenizer.pad_token_id] = -100
    labels[labels == eoc_token_id] = -100

    # Convert all tokens in prefix until separator to -100 so they are
    # ignored in loss
    for idx in range(len(labels)):
        # Find the location of the last token of prefix *from right*,
        # since the first non-padding token of the sequence will also be
        # eos_token (because bos_token and eos_token are the same for
        # the tokenizer).
        end_of_prefix = -labels[idx].tolist()[::-1].index(tokenizer.eos_token_id) - 1
        labels[idx, : end_of_prefix + 1] = -100

    # Shift so that tokens < n predict n. The shifted tensors both have
    # shape [batch_size, seq_len - 1].
    shift_logits = logits[..., :-1, :].contiguous()
    shift_labels = labels[..., 1:].contiguous()

    return shift_logits, shift_labels

def compute_per_sample_probs(
    encodings, tokenizer, logits: torch.Tensor, eoc_token_id
) -> torch.Tensor:
    """Helper function to compute per-sample probability of the input sequence.

    Assumes <eos token> is used to separate inputs from targets in the
    prompt text
    """
    shift_logits, shift_labels = compute_shifted_logits_and_labels(
        logits, encodings, tokenizer, eoc_token_id
    )

    # Tuple of tensors for unmasked label tokens. The first element of the
    # tuple contains the batch indices; the second element contains the
    # sequence indices.
    unmasked_indices = torch.nonzero(shift_labels != -100, as_tuple=True)
    # Tensor where the i^th element is the token_id corresponding to the i^th
    # element of unmasked_indices
    unmasked_token_ids = shift_labels[unmasked_indices]

    # 3d tensor of [batch_idx, sequence_position, token_id] for unmasked tokens.
    target_idxs = torch.column_stack([*unmasked_indices, unmasked_token_ids])
    target_idxs = target_idxs.to(shift_logits.device)

    # Sanity check that every element in batch has at least one unmasked
    # target token
    assert torch.all(
        torch.bincount(target_idxs[:, 0]) != 0
    ), "At least one element in batch has no unmasked target tokens."

    # Renormalize over tokens to make sure they are proper probabilities via
    # softmax over the token dimension.
    shift_probs = torch.nn.functional.softmax(shift_logits, 2)

    # Compute the probability of the target sequence (as the product of the
    # probability of the individual tokens in the sequence).
    target_probs = torch.ones(len(shift_labels), device=shift_logits.device)
    for i, j, k in target_idxs:
        target_probs[i] *= shift_probs[i, j, k]

    return target_probs

def compute_per_sample_loss(encodings, tokenizer, logits, eoc_token_id) -> torch.Tensor:
    """Helper function to compute per-sample classification loss.

    Assumes <eos token> is used to separate inputs from targets in the
    prompt text
    """
    shift_logits, shift_labels = compute_shifted_logits_and_labels(
        logits, encodings, tokenizer, eoc_token_id
    )

    device = shift_logits.device

    # Loss is computed token-wise, on Tensors of shape
    # [batch_size * (seq_len - 1), vocab_size]
    # and returns a loss tensor of shape
    # [batch_size * (seq_len - 1)]. Most of the tokens will be masked
    # in this computation.
    loss = torch.nn.functional.cross_entropy(
        shift_logits.view(-1, shift_logits.size(-1)),
        shift_labels.view(-1).to(device),
        reduction="none",
    )

    # Reshape to [batch_size, seq_len - 1]
    loss = loss.view(shift_logits.size(0), shift_logits.size(1)).cpu()

    # loss_mask is 1 for tokens we want included in the loss, and 0 for tokens
    # that should be ignored in the loss.
    loss_mask = (shift_labels != -100).int().cpu()

    loss *= loss_mask

    # Compute per-element loss : sum loss over all (unmasked) tokens and
    # divide by number of variable tokens to obtain tensor of
    # shape [batch_size,]
    loss = loss.sum(dim=1) / (shift_labels != -100).sum(dim=1).float()
    return loss


"""
Input général
"""

import datetime
from default_values import TIME_CONTROL
from Models.Player import Player

# MENU
def user_choice_menu(possibilities):
    try:
        choice = int(input("\nVeuillez indiquer votre choix : "))
        if choice not in possibilities:
            print("\nMauvais choix ! Veuillez renseigner un choix valide")
            return user_choice_menu(possibilities)
        else:
            return choice
    except ValueError:
        print("\nValeur incorrecte - Veuillez saisir un chiffre svp !")
        return user_choice_menu(possibilities)

# INPUT JOUEUR
def date_of_birth():
    user_date_of_birth = input("Date de naissance (JJ/MM/AAAA) : ")
    try:
        datetime.datetime.strptime(user_date_of_birth, "%d/%m/%Y")
        return user_date_of_birth
    except ValueError:
        print("Cette date n'est pas valide - Merci d'en saisir une nouvelle")
        return date_of_birth()

def gender():
    try:
        user_gender = str(input("Sexe du joueur (M ou F) : "))
        if user_gender in {"M", "F"}:
            return user_gender
        else:
            print("Veuillez saisir une informations valide !")
            return gender()
    except ValueError:
        print("Veuillez saisir une informations valide !")
        return gender()

def ranking():
    try:
        user_ranking = int(input("Classement du joueur (Positif obligatoirement) : "))
        if user_ranking < 0:
            print("Le classement est obligatoirement positif - Réessayez !")
            return ranking()
        else:
            print("")
            return user_ranking
    except ValueError:
        print("Mauvaise saisie - Réessayez !")
        return ranking()

def name(type_of_name):
    if type_of_name == 'first_name':
        return input("Nom de famille : ")
    elif type_of_name == 'last_name':
        return input('Prénom : ')

# INPUT POUR TROUVER UN JOUEUR AVEC SON ID
def return_player_with_unique_id():
    try:
        unique_id = int(input("Indiquez l'ID du joueur : "))
        if unique_id == 0:
            return
        player = Player.return_player(unique_id)
        if not player:
            print("Ce joueur n'existe pas dans la base de données - Réessayez svp !")
            return return_player_with_unique_id()
        else:
            return player
    except ValueError:
        print("Veuillez renseigner une information valide svp !")
        return return_player_with_unique_id()

# INPUT TOURNOI
def basic_informations(type_of_information):
    information = ''
    if type_of_information == 'name':
        information = input("\nNom du tournoi : ")
    elif type_of_information == 'location':
        information = input("Lieu du tournoi : ")
    elif type_of_information == 'description':
        information = input("Description du tournoi : ")

    return information

def add_date():
    """
    if ( date début == date de fin ) :
        return date début
    else :
        return les 2 dates : "du JJ/MM/AAAA au JJ/MM/AAAA"
    """
    try:
        duration = input("Tournoi sur plusieurs jours ? (O/N) ")
        if duration == "O":
            start_date, formatted_start_date = start_and_end_date('start')
            end_date, formatted_end_date = start_and_end_date('end')
            if formatted_start_date > formatted_end_date:
                print("La date de début du tournoi ne peut être "
                      "après la date de fin du tournoi - Merci de recommencer")
                return add_date()
            return start_date, end_date
        elif duration == "N":
            start_date, formatted_start_date = start_and_end_date('day_only')
            end_date = None
            return start_date, end_date
        elif duration not in {"O", "N"}:
            print("Veuillez saisir O ou N svp !")
            return add_date()
    except ValueError:
        print("Veuillez saisir une valeur valide !")
        return add_date()

def start_and_end_date(moment):
    """
    Vérifie que les dates existentent
    """
    date = ""
    if moment == 'start':
        date = input("Début du tournoi : ")
    elif moment == 'end':
        date = input("Fin du tournoi : ")
    elif moment == 'day_only':
        date = input("Date du tournoi : ")
    try:
        formatted_date = datetime.datetime.strptime(date, "%d/%m/%Y")
        return date, formatted_date
    except ValueError:
        print("Cette date n'est pas valide - Merci d'en saisir une nouvelle")
        return start_and_end_date(moment)

def tournament_time_control(possibilities):
    try:
        type_tc = int(input(f"Type de contrôle du temps (1. {TIME_CONTROL[0]} - 2. {TIME_CONTROL[1]} "
                            f"- 3. {TIME_CONTROL[2]}) : "))
        if type_tc not in possibilities:
            print("Veuillez choisir un choix entre 1 et 3 svp !")
            return tournament_time_control(possibilities)
        elif type_tc == 1:
            return TIME_CONTROL[0]
        elif type_tc == 2:
            return TIME_CONTROL[1]
        elif type_tc == 3:
            return TIME_CONTROL[2]
    except ValueError:
        print("Caractère non-valide - Merci de saisir un chiffre entre 1 et 3")
        return tournament_time_control(possibilities)

def return_tournament_id():
    try:
        unique_id = int(input("\nID du tournoi concerné : "))
        return unique_id
    except ValueError:
        print("Veuillez saisir un nombre positif svp")

def display_results(list_of_matchs, tournament):
    """
    L'user rentre les résultats du tour, les classement sont mis à jour
    si un joueur gagne un match, on ajoute +1 à player.score
    """
    for match_number, match in enumerate(list_of_matchs):
        print(f"Match n°{match_number + 1} - {match[0]['Nom']} contre {match[1]['Nom']}")
        try:
            result = int(input("Résultat du match : "))
            if result not in {0, 1, 2}:
                print("Veuillez indiquer 0, 1 ou 2 svp !")
                return display_results(list_of_matchs, tournament)
            else:
                if result == 1:
                    player = tournament.return_player(match[0]['ID'])
                    player['Score'] += 1
                elif result == 2:
                    player = tournament.return_player(match[1]['ID'])
                    player['Score'] += 1
                elif result == 0:
                    player = tournament.return_player(match[0]['ID'])
                    player['Score'] += 0.5
                    player = tournament.return_player(match[1]['ID'])
                    player['Score'] += 0.5
        except ValueError:
            print("Veuillez saisir un chiffre !")
            return display_results(list_of_matchs, tournament)

def continue_tournament():
    try:
        choice = input("\nContinuer le tournoi (O/N) : ").capitalize()
        if choice not in {'O', 'N'}:
            print("Merci de saisir O ou N")
            return continue_tournament()
        else:
            return choice
    except ValueError:
        print("Merci de saisir une information valide")
        return continue_tournament()


import os
import sys
sys.path.append('..')
sys.path.append('../..')
sys.path.append(os.path.abspath(os.path.expanduser('~/sourcetree/errudite/')))
from tqdm import tqdm
import pandas as pd

import errudite
from errudite.io import DatasetReader
from errudite.predictors import Predictor
from errudite.targets.instance import Instance
from errudite.targets.label import Label
from errudite.utils import accuracy_score, normalize_file_path

import logging
logger = logging.getLogger(__name__)  # pylint: disable=invalid-name

if __name__ == "__main__":
    sample_size = 10570
    DATASET_FOLDER = normalize_file_path("~/datasets/raw_data/squad/")
    MODEL_FOLDER = normalize_file_path("~/datasets/models/bidaf/")
    reader = DatasetReader.by_name("squad")(cache_folder_path=f"~/datasets/caches/error_analysis/squad-{sample_size}")

    instances = reader.read(
        os.path.join(DATASET_FOLDER, "dev-v1.1.json"),
        sample_size=sample_size)
    reader.dump(instances)
    Label.set_task_evaluator(accuracy_score, task_primary_metric='accuracy')

    bidaf = Predictor.by_name("bidaf")(
        name='bidaf',
        description='Pretrained model from Allennlp, for the BiDAF model (QA)',
        model_online_path="https://s3-us-west-2.amazonaws.com/allennlp/models/bidaf-model-2017.09.15-charpad.tar.gz")
    """
    bidaf_elmo = Predictor.by_name("bidaf")(
        name='bidaf_elmo',
        description='Pretrained model from Allennlp, for the BiDAF model (QA), with the elmo embedding.',
        model_path=os.path.join(MODEL_FOLDER, "elmo", "model.tar.gz"))
    """
    predictors = { p.name: p for p in [bidaf] }
    predictions = { p: [] for p in predictors }
    logger.info("Running predictions....")
    for instance in tqdm(instances):
        instance_predictions = []
        for predictor in predictors.values():
            prediction = Predictor.by_name("qa_task_class").model_predict(
                predictor,
                instance.question,
                instance.context,
                instance.groundtruths)
            instance_predictions.append(prediction)
            predictions[predictor.name].append(prediction)
        instance.set_entries(predictions=instance_predictions)
    for predictor in predictors.values():
        predictor.evaluate_performance(instances)
    print(pd.DataFrame([ {"predictor": p.name, "f1": p.perform["f1"] } for p in predictors.values() ]))
    Instance.build_instance_hashes(instances)
    reader.count_vocab_freq(os.path.join(DATASET_FOLDER, "train-v1.1.json"))
    reader.compute_ling_perform_dict(list(Instance.instance_hash.values()))
    reader.dump_preprocessed()


import numpy as np
import matplotlib.pyplot as plt
import cv2
from pdf2image import convert_from_path

images = list(map(np.array, convert_from_path("/Users/azsarki/Documents/books/strategy2.pdf")))
idx = 0
for image in images[0:30]:
	gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
	edged = cv2.Canny(image, 50, 250)
	(cnts, hierarchy) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

	for i, c in enumerate(cnts):
		if hierarchy[0, i, 3] != -1:
			continue
		x,y,w,h = cv2.boundingRect(c)
		if w>200 and h>200:
			idx+=1
			new_img=image[y:y+h,x:x+w]
			cv2.imwrite('imgs/' + str(idx) + '.png', new_img)


# coding: utf-8
from __future__ import unicode_literals

from traitlets import Unicode, Bool, Enum, Any

from .utils import shorten
from .shortcut import KEYS
from .widget import DOMWidget, register_widget
from .colors import COLORS, GRAY, BLUE, RED, GREEN

@register_widget
class Button(DOMWidget):
    _view_name = Unicode('ButtonView').tag(sync=True)
    _model_name = Unicode('ButtonModel').tag(sync=True)

    color = Enum(COLORS).tag(sync=True)
    icon = Unicode(allow_none=True).tag(sync=True)
    label = Unicode(allow_none=True).tag(sync=True)
    shortcut = Enum(KEYS, allow_none=True).tag(sync=True)
    active = Bool(False).tag(sync=True)

    def __init__(self, color=GRAY, icon=None, label=None, shortcut=None):
        super(Button, self).__init__(
            color=color,
            icon=icon,
            label=label,
            shortcut=shortcut
        )
        self.annotation = None
        self.callback = None

        self.on_msg(self.handle_message)

    @property
    def is_registered(self):
        return self.annotation is not None

    def register(self, annotation):
        if self.is_registered:
            raise RuntimeError('already register: %r' % self)
        self.annotation = annotation

    def assert_registered(self):
        if not self.is_registered:
            raise RuntimeError('not registered')

    def handle_click(self):
        if self.callback:
            self.callback(self)

    def handle_message(self, _, content, buffers):
        event = content['event']
        if event == 'click':
            self.handle_click()

    def click(self):
        self.send({'event': 'click'})

    def on_click(self, callback):
        self.callback = callback

class ValueButton(Button):
    value = Any()

    def __init__(self, value, color=GRAY, icon=None, label=None, shortcut=None):
        if label is None:
            label = shorten(str(value), cap=10)
        super(ValueButton, self).__init__(
            color=color,
            icon=icon,
            label=label,
            shortcut=shortcut,
        )
        self.value = value

    def handle_click(self):
        Button.handle_click(self)
        self.assert_registered()
        self.annotation.toolbar.handle_click(self)

def has_value(item):
    return isinstance(item, ValueButton)

class OkButton(ValueButton):
    def __init__(self, value=True, color=GREEN, icon='👌', label='ok', shortcut='1'):
        super(OkButton, self).__init__(
            value=value,
            color=color,
            icon=icon,
            label=label,
            shortcut=shortcut,
        )

class ErrorButton(ValueButton):
    def __init__(self, value=False, color=RED, icon='❌', label='err', shortcut='2'):
        super(ErrorButton, self).__init__(
            value=value,
            color=color,
            icon=icon,
            label=label,
            shortcut=shortcut,
        )

class ControlButton(Button):
    pass

def is_control(item):
    return isinstance(item, ControlButton)

class NextButton(ControlButton):
    def __init__(self, color=GRAY, icon='→ ', label='next', shortcut='j'):
        super(NextButton, self).__init__(
            color=color,
            icon=icon,
            label=label,
            shortcut=shortcut,
        )

    def handle_click(self):
        Button.handle_click(self)
        self.assert_registered()
        self.annotation.next()

class BackButton(ControlButton):
    def __init__(self, color=GRAY, icon='← ', label='back', shortcut='k'):
        super(BackButton, self).__init__(
            color=color,
            icon=icon,
            label=label,
            shortcut=shortcut,
        )

    def handle_click(self):
        Button.handle_click(self)
        self.assert_registered()
        self.annotation.back()


#!/usr/bin/python
# -*- Coding: utf-8 -*-

import torch
import torch.nn as nn
from torch.nn import functional as F
import torchvision
from torchvision import models
from torchvision.models.segmentation.deeplabv3 import DeepLabHead

from collections import OrderedDict

from module.unet import UNet, EfficientUNet

from efficientnet_pytorch import EfficientNet

def get_model(args, num_classes):
    if args.model == "Deeplab":
        if args.pretrained:
            model = models.segmentation.deeplabv3_resnet101(pretrained=True)
            num_ftr = model.classifier[-1].in_channels
            model.classifier[-1] = nn.Conv2d(num_ftr, num_classes,
                        kernel_size=(1, 1), stride=(1, 1))

            num_ftr_aux = model.aux_classifier[-1].in_channels
            model.aux_classifier[-1] = nn.Conv2d(num_ftr_aux, num_classes,
                        kernel_size=(1, 1), stride=(1, 1))

        else:
            model = models.segmentation.deeplabv3_resnet101(
                num_classes=num_classes
            )

    elif args.model == "UNet":
        model = UNet(1, num_classes, dropout=args.dropout, use_scSE=args.use_scse, use_gain=args.use_gain)

    elif args.model == "EfficientDeeplab":
        model = efficient_deeplabv3(args)

    elif args.model == "EfficientUNet":
        model = efficient_unet(args)

    else:
        print("no such a model")
        exit()
    return model

class Deeplabv3(models.segmentation._utils._SimpleSegmentationModel):
    def forward(self, x):
        input_shape = x.shape[-2:]
        features = self.backbone(x)

        result = OrderedDict()
        x = features
        x = self.classifier(x)
        x = F.interpolate(x, size=input_shape, mode='bilinear', align_corners=False)
        result["out"] = x

        if self.aux_classifier is not None:
            x = features["aux"]
            x = self.aux_classifier(x)
            x = F.interpolate(x, size=input_shape, mode='bilinear', align_corners=False)
            result["aux"] = x

        return result

class EfficientNetExtractor(EfficientNet):
    def forward(self, inputs):
        """use convolution layer to extract feature .
        Args:
            inputs (tensor): Input tensor.
        Returns:
            Output of the final convolution
            layer in the efficientnet model.
        """
        # Stem
        x = self._swish(self._bn0(self._conv_stem(inputs)))

        # Blocks
        for idx, block in enumerate(self._blocks):
            drop_connect_rate = self._global_params.drop_connect_rate
            if drop_connect_rate:
                drop_connect_rate *= float(idx) / len(self._blocks) # scale drop connect_rate
            x = block(x, drop_connect_rate=drop_connect_rate)

        # Head
        x = self._swish(self._bn1(self._conv_head(x)))

        return x

def efficient_deeplabv3(args):
    # args.backbone には 'efficientnet-b0'などが入る
    efficientnet = EfficientNetExtractor.from_name(args.backbone, in_channels=1)

    num_ch = efficientnet._conv_head.out_channels
    classifier = DeepLabHead(num_ch, args.num_classes)
    base_model = Deeplabv3
    model = base_model(efficientnet, classifier)
    return model

def efficient_unet(args):
    # args.backbone には 'efficientnet-b0'などが入る
    model = EfficientUNet.from_name(args.backbone, in_channels=1, n_classes=args.num_classes, use_scSE=args.use_scse)
    return model

if __name__ == "__main__":
    class A:
        pass
    args = A()
    args.backbone = "efficientnet-b0"
    args.num_classes = 4
    model = efficient_deeplabv3(args)
    img = torch.rand(2,1,512,512)
    print(model(img)["out"].shape)


import numpy as np
import cv2

class DeepSortMock():
    def __init__(self, filename):
        self.frame_num = 0
        self.detections = [ ]
        import pickle
        with open(filename, 'rb') as f:
            self.detections = pickle.load(f)
    def load():
        pass
    def update(self, frame):
        self.frame_num += 1
        if self.frame_num >= len(self.detections):
            return []
        else:
            return self.detections[self.frame_num]

import matplotlib.pyplot as plt
#initialize color map
cmap = plt.get_cmap('tab20b')
colors = [cmap(i)[:3] for i in np.linspace(0, 1, 20)]

def drawDetection(frame, detection, info = ""):
    p1, p2, class_name, ID = detection

    color = colors[int(ID) % len(colors)]
    color = [i * 255 for i in color]

    cv2.rectangle(frame, p1, p2, color, 5)
    cv2.rectangle(frame, (int(p1[0]), int(p1[1]-30)), (int(p1[0])+(len(class_name)+len(str(ID))+len(str(info)) + 1)*17, int(p1[1])), color, -1)
    cv2.putText(frame, f"{class_name}-{ID}: {info}",(int(p1[0]), int(p1[1]-10)),0, 0.75, (255,255,255),2)
    return frame

class Identity():
    def __init__(self, ID, memory_length = 45): # Frames):
        self.ID = ID
        self.age = 0
        self.name = str(ID)
        self.memory_length = memory_length
        self.__reference_images = []
    def push_image(self,frame):
        self.__reference_images.append(frame)
        self.__reference_images = self.__reference_images[-self.memory_length:]
    def get_images(self):
        return self.__reference_images
    def get_latest_image(self):
        if len(self.__reference_images) > 0:
            return self.__reference_images[-1]
        else:
            return None

img_grab_gap = 24 * .25 # Frames
max_id_age = 30 * 24 # Frames

data_files = ["grandma_A", "grandma_B"]
feeds = [cv2.VideoCapture(f"raw_data/videos/grandma_me/{file}.mp4") for file in data_files]
feed_memories = [dict() for _ in feeds] # TODO: Store in a queue instead
detectors = [DeepSortMock(f"raw_data/videos/grandma_me/{file}.pb") for file in data_files]

# DEBUG
output_frames = []
fps = feeds[0].get(cv2.CAP_PROP_FPS)
_, frame = feeds[0].read()
out_size = frame.shape[:-1][::-1]
fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') # note the lower case
out = cv2.VideoWriter()
out.open('output.flow.mp4',fourcc,fps,out_size,True)

frames_left = True
frame_num = 0
try:
    while frames_left:
        frame_num += 1
        output_frames = [ ]
        for feed_num, (feed, detector, identities) in enumerate(zip(feeds, detectors, feed_memories)):
            frames_left, frame = feed.read()

            if not frames_left: break

            # Query Deep Sort Algorithm
            people = detector.update(frame)

            # Grab Positive Person images to train seperators
            for person in people:
                p1, p2, cat, ID = person
                if ID not in identities:
                    identities[ID] = Identity(ID)
                    if ID == 1 and feed_num == 1:
                        identities[ID].name = "Grandma"
                    if ID == 1 and feed_num == 1:
                        identities[ID].name = "Grandma"
                    if ID == 6 and feed_num == 0:
                        identities[ID].name = "Me"

                frame = drawDetection(frame, (p1, p2, cat, ID), info = identities[ID].name)
            output_frames.append(frame)
        ##################################################

        # Debug
        joined = np.concatenate(tuple(output_frame for output_frame in output_frames), axis = 1)
        joined = cv2.resize(joined, out_size, interpolation = cv2.INTER_AREA)

        out.write(output_frames[0])
        print(output_frames[0].dtype, output_frames[0].shape,joined.dtype, joined.shape)
        cv2.imshow("Joined Product",joined)
        cv2.waitKey(1)

finally:
    [cap.release() for cap in feeds]
    out.release()
    cv2.destroyAllWindows()


import os

from flask import (
    Blueprint, current_app, flash, g, redirect, render_template, request, url_for, send_from_directory
)
from flask_ckeditor import CKEditorField
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed
from werkzeug.exceptions import abort
from werkzeug.utils import secure_filename
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

from flaskr.auth import login_required
from flaskr.db import get_db

bp = Blueprint("article", __name__)

class PostForm(FlaskForm):
    title = StringField("Title", validators=[DataRequired()])
    body = CKEditorField("Body")
    image = FileField("Image", validators=[
        FileAllowed(["jpg", "png", "gif", "svg"], "Images only!")
    ])
    caption = CKEditorField("Caption")
    submit = SubmitField("Save")

def get_article(search, check_author=True):
    if type(search) is int:
        article = get_db().execute(
            "SELECT a.id, title, body, image, caption, created, author_id, username"
            " FROM article a JOIN user u on a.author_id = u.id"
            " WHERE a.id = ?",
            (search,)
        ).fetchone()
        if article is None:
            abort(404, f"Article id {search} doesn't exist.")
    elif type(search) is str:
        processed_search = search.replace("%20", " ")
        article = get_db().execute(
            "SELECT a.id, title, body, image, caption, created, author_id, username"
            " FROM article a JOIN user u on a.author_id = u.id"
            " WHERE a.title = ?",
            (processed_search,)
        ).fetchall()
        if len(article) == 0:
            abort(404, f"No article by the title {search} exists. Titles are case sensitive.")
        elif len(article) > 1:
            abort(400, f"Multiple articles with title {search}. Please use an ID instead.")
        article = article[0]
    else:
        raise TypeError("get_article() takes a search of type int or str only.")

    if check_author and article["author_id"] != g.user["id"]:
        abort(403)

    return article

@bp.route("/images/<filename>")
def get_image(filename):
    return send_from_directory(current_app.instance_path, filename)

@bp.route("/index")
@login_required
def index():
    return render_template("article/index.html")

@bp.route("/<int:id>")
def view_by_id(id=1):
    article = get_article(id, check_author=False)
    return render_template("article/page.html", article=article)

@bp.route("/<title>")
def view_by_title(title):
    article = get_article(title, check_author=False)
    return render_template("article/page.html", article=article)

@bp.route("/create", methods=("GET", "POST"))
@login_required
def create():
    form = PostForm()

    if form.validate_on_submit():
        title = form.title.data
        body = form.body.data
        image = form.image.data
        caption = form.caption.data
        if image:
            filename = secure_filename(image.filename)
            image.save(os.path.join(
                current_app.instance_path, filename
            ))
            db = get_db()
            db.execute(
                "INSERT INTO article (title, body, image, caption, author_id)"
                " VALUES (?, ?, ?, ?, ?)",
                (title, body, filename, caption, g.user["id"])
            )
            db.commit()
        else:
            db = get_db()
            db.execute(
                "INSERT INTO article (title, body, caption, author_id)"
                " VALUES (?, ?, ?, ?)",
                (title, body, caption, g.user["id"])
            )
            db.commit()
        return redirect(url_for("article.index"))

    else:
        if form.errors:
            for error in form.errors:
                current_app.logger.error("An error occurred during validation: %s", error)
                flash(error)
        else:
            current_app.logger.info("Request method is not post.")

    return render_template("article/create.html", form=form)

@bp.route("/<int:id>/update", methods=("GET", "POST"))
@login_required
def update(id):
    article = get_article(id)
    form = PostForm()

    if form.validate_on_submit():
        db = get_db()
        title = form.title.data
        body = form.body.data
        image = form.image.data
        caption = form.caption.data
        if image:
            filename = secure_filename(image.filename)
            image.save(os.path.join(
                current_app.instance_path, filename
            ))
            db.execute(
                "UPDATE article SET title = ?, body = ?, image = ?, caption = ?"
                " WHERE id = ?",
                (title, body, filename, caption, id)
            )
            db.commit()
        else:
            db.execute(
                "UPDATE article SET title = ?, body = ?, caption = ?"
                " WHERE id = ?",
                (title, body, caption, id)
            )
            db.commit()

        return redirect(url_for("article.index"))

    else:
        if form.errors:
            for error in form.errors:
                current_app.logger.error("An error occurred during validation: %s", error)
                flash(error)
        elif request.method == "GET":
            form.title.data = article["title"]
            form.body.data = article["body"]
            form.caption.data = article["caption"]

    return render_template("article/update.html", article=article, form=form)

@bp.route("/<int:id>/delete", methods=("POST",))
@login_required
def delete(id):
    article = get_article(id)
    if article["image"]:
        try:
            os.remove(os.path.join(
                current_app.instance_path, article["image"]
            ))
        except IOError as e:
            raise e
    db = get_db()
    db.execute("DELETE FROM article WHERE id = ?", (id,))
    db.commit()
    return redirect(url_for("article.index"))


__version__ = "0.1.0"

import platform

import httpx
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse

app = FastAPI()

@app.get("/rate/{base}")
async def get_rate(base: str, target: str):
    return {
        "source": base.upper(),
        "target": target.upper(),
        "rate": 0.752492,
        "node": platform.node(),
    }

@app.get("/discover")
async def discover():
    resp = httpx.get("http://quotes.service.consul/hostname")
    other_node = resp.text
    return {"node": platform.node(), "other_node": other_node}

@app.get("/hostname", response_class=PlainTextResponse)
async def hostname():
    return platform.node()

@app.get("/health")
async def health():
    return {"status": "ok"}


import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder

def load_data(file_path):
    """
    Load the dataset from a CSV file.

    Args:
        file_path (str): Path to the CSV file.

    Returns:
        pandas.DataFrame: Loaded dataset.
    """
    data = pd.read_csv(file_path)
    return data

def preprocess_data(data):
    """
    Perform preprocessing on the dataset.

    Args:
        data (pandas.DataFrame): Input dataset.

    Returns:
        tuple: Tuple containing preprocessed features and target variables.
    """
    # convert `Neighborhood` into numeric
    le = LabelEncoder()
    data["Neighborhood"] = le.fit_transform(data["Neighborhood"])

    # Split features and target variable
    X = data.drop('Price', axis=1)
    y = data['Price']

    # Perform train-test split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    # Standardize features using StandardScaler
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)

    return X_train_scaled, X_test_scaled, y_train, y_test


from collections import deque

# 입력받기
N, M, K, X = map(int, input().split(' '))

road = [[] for _ in range(N+1)]

for i in range(M):
    n, m = map(int, input().split(' '))
    road[n].append(m)

# BFS 메서드 정의
def bfs(road, start, visited):
    # 큐(Queue) 구현을 위해 deque 라이브러리 사용
    queue = deque([start])
    # 현재 노드를 방문 처리
    visited[start] = 0
    while queue:
        # 큐에서 하나의 원소를 뽑아 출력
        now_node = queue.popleft()
        # 해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입
        for next_node in road[now_node]:
            if visited[next_node] == -1:
                queue.append(next_node)
                visited[next_node] = visited[now_node] + 1

# 각 노드가 방문된 정보를 리스트 자료형으로 표현(1차원 리스트)
visited = [-1] * (N + 1)

# 정의된 BFS 함수 호출
bfs(road, X, visited)

# 최단 거리가 정확히 K인 모든 도시들의 번호를 출력
if K not in visited : print(-1)
else :
    number = 0
    for v in visited :
        if v == K :
            print(number)
        number += 1


from queue import Queue
from collections import deque

class ACTrie:
    """Aho Corasick Trie"""

    def __init__(self):
        self.root = Node(output='')
        # self.q = Queue()
        self.q = deque()

    def _build(self, patterns):

        for w_i, word in enumerate(patterns):
            node = self.root
            for i, letter in enumerate(word, start=1):
                # output = (word, w_i) if i == len(word) else None
                output = word if i == len(word) else None
                node = node.append_letter(letter, output)

    def print(self, node):
        """"""
        print(node)
        for child in node.c.values():
            self.print(child)

    def _build_fails(self):
        """"""
        # root children to queue
        q = self.q
        for child in self.root.c.values():
            child.f = self.root
            # q.put(child)
            q.append(child)

        # while not q.empty():
        while len(q):
            # current = q.get()
            current = q.popleft()

            for letter, child in current.c.items():
                # q.put(child)
                q.append(child)

                # find a fail for child
                fail_node = current.f

                while True:
                    # fail_node has an appropriate letter
                    if letter in fail_node.c:
                        child.f = fail_node.c[letter]
                        child.o.extend(child.f.o)
                        break

                    # does not have letter
                    # if root
                    if fail_node.f is None:
                        child.f = fail_node
                        break
                    else:
                        # go to upper fail node
                        fail_node = fail_node.f

    def build(self, patterns):
        """"""
        self._build(patterns)
        self._build_fails()

    # fixme maybe as generator
    def find_matching(self, string):
        """"""
        # from collections import Counter
        # result = Counter()
        result = []
        current = self.root

        for letter in string:
            if letter in current.c:
                current = current.c[letter]
                result.extend(current.o)
                # result.update(current.o)

            # fixme here we need to check all fails up to root
            else:
                current = current.f
                while current is not None and letter not in current.c:
                    current = current.f
                # went up to root
                if current is None:
                    current = self.root
                    continue

                current = current.c[letter]
                result.extend(current.o)
                # result.update(current.o)

        return result
        # return set(result)
        # from collections import Counter
        # return Counter(result)

class Node:

    __slots__ = ('o', 'c', 'f')

    def __init__(self, output=None):

        self.o = []
        self.c = {}
        self.f = None

        if output:
            self.o.append(output)

    def __str__(self):
        return f'Node: ' \
               f'outputs: `{self.o}` ' \
               f'fail_node: {getattr(self.f, "letter", None)}'

    def append_letter(self, letter, output=None) -> 'Node':

        if letter in self.c:
            child = self.c[letter]
            if output:
                child.o.append(output)
        else:
            child = Node(output=output or None)
            self.c[letter] = child

        return child

if __name__ == '__main__':

    # words = ['asd', 'as', 'a', 'bdd']
    # words = ['c', 'cc', 'ccc', 'cccc']
    # words = []
    words = ['aab', 'aab']
    # words = ['c', 'dadac']
    # words = ['a', 'ab', 'bc', 'aab', 'aac', 'bd']

    trie = ACTrie()
    trie.build(patterns=words)
    trie.print(trie.root)

    # string = 'aaab'
    # string = 'abcabcabc'
    string = 'bcaab'

    matches = trie.find_matching(string)
    print(matches)