import os
import yaml
import argparse
import subprocess
import logging
import json
from PIL import Image
from tqdm import tqdm

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

parser = argparse.ArgumentParser(description='Configure benchmark for Faster R-CNN')
parser.add_argument('--img-dir', help='Image directory name', type=str, required=True)
# parser.add_argument('--benchmark-type', help='Benchmark name, i.e. baseline, fsrcnn_x2, etc.', type=str, required=True)
# parser.add_argument('--sr-multiplier', type=int, help='Resolution upscaling multiplier, i.e. 1 for baseline', required=True)
# parser.add_argument('--device', default='0', help='Cuda device, i.e. 0 or 0,1,2,3 or cpu')
# parser.add_argument('--workers', type=int, default=8, help='Number of data loading workers')
# parser.add_argument('--batch-size', type=int, default=16, help='Batch size')
# parser.add_argument('--total-iterations', type=int, default=5000, help='Total training iterations')
parser.add_argument('--dataset-path', type=str, default='dataset', help='Path to root dataset directory')
args = parser.parse_args()

dataset_configs = {
    'apple_detection_drone_brazil': {
        'img_res': 256,
        'total_train_imgs': 483
    },
    'apple_detection_spain': {
        'img_res': 512,
        'total_train_imgs': 677
    },
    'apple_detection_usa': {
        'img_res': 640,
        'total_train_imgs': 1598
    },
    'fruit_detection_worldwide': {
        'img_res': 800,
        'total_train_imgs': 395
    },
    'grape_detection_californianight': {
        'img_res': 416,
        'total_train_imgs': 106
    },
    'mango_detection_australia': {
        'img_res': 512,
        'total_train_imgs': 870
    },
    'wheat_head_counting': {
        'img_res': 512,
        'total_train_imgs': 4558
    },
}

def run_if_exists(path, func):
    if os.path.exists(path):
        func(path)

def create_coco_annotations(img_lbl_path, img_dir, config_yaml):

    img_path = os.path.join(img_lbl_path, img_dir)
    lbl_path = os.path.join(img_lbl_path, 'labels')

    result = {
        'info': {
            'year': '2023',
            'description': 'Autogenerated COCO annotations',
        },
        'licenses': [{
            'id': 1,
            'url': 'https://creativecommons.org/licenses/by/4.0/',
            'name': 'CC BY 4.0'
        }],
        'categories': [
            {
                'id': i + 1,
                'name': config_yaml['names'][i],
                'supercategory': config_yaml['names'][i],
            }
            for i in range(len(config_yaml['names']))
        ],
        'images': [],
        'annotations': []
    }

    assert os.path.exists(img_path), f'Image path {img_path} does not exist'
    assert os.path.exists(lbl_path), f'Label path {lbl_path} does not exist'

    img_id = 0
    annotation_id = 0
    img_files = next(os.walk(img_path))[2]
    for img in tqdm(img_files):
        img_name = os.path.splitext(img)[0]
        label_file = os.path.join(lbl_path, f'{img_name}.txt')

        assert os.path.exists(label_file), f'Label file {label_file} does not exist'

        img_file = Image.open(os.path.join(img_path, img))
        img_width, img_height = img_file.size

        with open(label_file, 'r') as f:
            for line in f.readlines():
                line = line.strip()
                if line == '':
                    continue
                line = line.split(' ')
                category_id = int(line[0]) + 1
                x = int(float(line[1]) * img_width)
                y = int(float(line[2]) * img_height)
                w = int(float(line[3]) * img_width)
                h = int(float(line[4]) * img_height)

                result['annotations'].append({
                    'id': annotation_id,
                    'image_id': img_id,
                    'category_id': category_id,
                    'bbox': [x, y, w, h],
                    'area': w * h,
                    'segmentation': [],
                    'iscrowd': 0,
                })
                annotation_id += 1

        result['images'].append({
            'id': img_id,
            'license': 1,
            'file_name': img,
            'height': img_height,
            'width': img_width,
        })
        img_id += 1
    json.dump(result, open(os.path.join(img_lbl_path, 'annotations.json'), 'w'))

dataset_path = args.dataset_path
datasets = next(os.walk(dataset_path))[1]
for dataset in datasets:
    logger.info(f'Preparing {dataset}')
    d_train_path = os.path.join(os.path.abspath(dataset_path), dataset, 'train', args.img_dir)
    d_val_path = os.path.join(os.path.abspath(dataset_path), dataset, 'val', args.img_dir)
    d_test_path = os.path.join(os.path.abspath(dataset_path), dataset, 'test', args.img_dir)

    train_path = os.path.join(os.path.abspath(dataset_path), dataset, 'train', 'images')
    val_path = os.path.join(os.path.abspath(dataset_path), dataset, 'val', 'images')
    test_path = os.path.join(os.path.abspath(dataset_path), dataset, 'test', 'images')

    assert os.path.exists(d_train_path), f'Train path {d_train_path} does not exist'
    assert os.path.exists(d_val_path), f'Val path {d_val_path} does not exist'
    assert os.path.exists(d_test_path), f'Test path {d_test_path} does not exist'

    run_if_exists(train_path, os.unlink)
    run_if_exists(val_path, os.unlink)
    run_if_exists(test_path, os.unlink)
    os.symlink(d_train_path, train_path)
    os.symlink(d_val_path, val_path)
    os.symlink(d_test_path, test_path)

    with open(os.path.join(dataset_path, dataset, 'base.yaml'), 'r') as f:
        train_config = yaml.safe_load(f)

    base_dataset_path = os.path.join(os.path.abspath(dataset_path), dataset)
    run_if_exists(os.path.join(base_dataset_path, 'train', 'annotations.json'), os.remove)
    run_if_exists(os.path.join(base_dataset_path, 'val', 'annotations.json'), os.remove)
    run_if_exists(os.path.join(base_dataset_path, 'test', 'annotations.json'), os.remove)
    logger.info(f'Creating COCO annotations for {dataset}')

    create_coco_annotations(os.path.join(base_dataset_path, 'train'), args.img_dir, train_config)
    create_coco_annotations(os.path.join(base_dataset_path, 'val'), args.img_dir, train_config)
    create_coco_annotations(os.path.join(base_dataset_path, 'test'), args.img_dir, train_config)

    # total_train_imgs = dataset_configs[dataset]['total_train_imgs']
    # img_res = dataset_configs[dataset]['img_res']
    # epoch = args.total_iterations // (total_train_imgs // args.batch_size)

    # train_command = [
    #     f'python train.py --workers {args.workers} --device {args.device} --batch-size {args.batch_size} --epoch {epoch}',
    #     '--cfg cfg/training/yolov7.yaml --weights yolov7_training.pt --hyp data/hyp.scratch.custom.yaml',
    #     f'--data ../../dataset/{dataset}/config.yaml',
    #     f'--img-size {img_res * args.sr_multiplier} {img_res * args.sr_multiplier}',
    #     f'--name {dataset}',
    #     f'--project ../../results/{args.benchmark_type}/yolov7/train'
    # ]
    # train_command = ' '.join(train_command)
    # logger.info(f'Running training command: {train_command}')
    # subprocess.call(train_command.split(' '), cwd='./object_detectors/yolov7')

    # test_command = [
    #     f'python test.py --device 0 --weights ../../results/{args.benchmark_type}/yolov7/train/{dataset}/weights/best.pt',
    #     f'--data ../../dataset/{dataset}/config.yaml',
    #     f'--img-size {img_res * args.sr_multiplier} --batch 16',
    #     f'--task test --name {dataset}',
    #     f'--project ../../results/{args.benchmark_type}/yolov7/test',
    # ]
    # test_command = ' '.join(test_command)
    # logger.info(f'Running test command: {test_command}')
    # subprocess.call(test_command.split(' '), cwd='./object_detectors/yolov7')

    logger.info(f'Cleaning up {dataset}')
    run_if_exists(os.path.join(base_dataset_path, 'train', 'annotations.json'), os.remove)
    run_if_exists(os.path.join(base_dataset_path, 'val', 'annotations.json'), os.remove)
    run_if_exists(os.path.join(base_dataset_path, 'test', 'annotations.json'), os.remove)
    run_if_exists(train_path, os.unlink)
    run_if_exists(val_path, os.unlink)
    run_if_exists(test_path, os.unlink)
    logger.info(f'Finished {dataset}\n')

# logger.info(f'Benchmark {args.benchmark_type} completed')


from algorithms import advancedHillclimber as ah
from algorithms import hillclimberAlgo as ha
from algorithms import geneticAlgo as ge
from algorithms import greedyAlgo as gr
from algorithms import randomAlgo as ra
from algorithms import simulatedAnnealing as sa
from classes import railroad as rail
from classes import trainlining as tl
from helpers import results
from helpers import userInterface as UI
from helpers import visual

def runAll(userChoice):
    """
    Receives whether the user wants to use the long or short UI. Then runs the UI, \
    generates the information for the algorithms and runs the specified algorithm.

    Args: userChoice (string)
    """

    if userChoice == "long":
        info = UI.userInterfaceLong()
    elif userChoice == "short":
        info = UI.userInterfaceShort()

    csvChoice = info[0]
    csvConnections = info[1]
    maxTrajectories = info[2]
    maxLength = info[3]
    algorithm = info[4]

    if algorithm == "genetic":
        populationSize = info[5]
        recombinationCoefficient = info[6]
        mutationRate = info[7]
        runs = info[8]
        rerun = info[9]
        image = info[10]

    elif algorithm == "simulatedAnnealing":
        hill = info[5]
        runs = info[6]
        rerun = info[7]
        image = info[8]

    elif algorithm == "all":
        populationSize = info[5]
        recombinationCoefficient = info[6]
        mutationRate = info[7]
        hill = info[8]
        runs = info[9]
        rerun = info[10]
        image = info[11]

    else:
        runs = info[5]
        rerun = info[6]
        image = info[7]

    railroad = rail.Railroad()
    railroad.loadStations(csvChoice, csvConnections)
    totalCritical = railroad.addTotalCritical()
    trainlining = tl.Trainlining(maxTrajectories, maxLength, totalCritical)

    scoresList = []

    if algorithm == "random":
        if rerun == 'y':
            for i in range(100):
                total = ra.runRandom(railroad, trainlining, runs, rerun, algorithm, image)
                scoresList.append(total)
                print(f"Rerun: {i + 1}")
            results.calculateScores(scoresList)
        else:
            ra.runRandom(railroad, trainlining, runs, rerun, algorithm, image)

    elif algorithm == "greedy":
        if rerun == 'y':
            for i in range(100):
                total = gr.runGreedy(railroad, trainlining, runs, rerun, algorithm, image)
                scoresList.append(total)
                print(f"Rerun: {i + 1}")
                trainlining = tl.Trainlining(maxTrajectories, maxLength, totalCritical)
            results.calculateScores(scoresList)
        else:
            gr.runGreedy(railroad, trainlining, runs, rerun, algorithm, image)

    elif algorithm == "hillclimber":
        if rerun == 'y':
            for i in range(100):
                total = ha.runHillclimber(railroad, trainlining, runs, rerun, algorithm, image)
                scoresList.append(total)
                print(f"Rerun: {i + 1}")
            results.calculateScores(scoresList)
        else:
            ha.runHillclimber(railroad, trainlining, runs, rerun, algorithm, image)

    elif algorithm == "genetic":
        if rerun == 'y':
            for i in range(100):
                total = ge.genetic(trainlining, railroad, runs, rerun, algorithm, populationSize, recombinationCoefficient, mutationRate, image)
                scoresList.append(total)
                print(f"Rerun: {i + 1} ")
            results.calculateScores(scoresList)
        else:
            ge.genetic(trainlining, railroad, runs, rerun, algorithm, populationSize, recombinationCoefficient, mutationRate, image)

    elif algorithm == "advancedHillclimber":
        if rerun == 'y':
            for i in range(100):
                total = ah.runAdvancedHillclimber(railroad, trainlining, runs, rerun, algorithm, image)
                scoresList.append(total)
                print(f"Rerun: {i + 1}")
            results.calculateScores(scoresList)
        else:
            ah.runAdvancedHillclimber(railroad, trainlining, runs, rerun, algorithm, image)

    elif algorithm == "simulatedAnnealing":
        if rerun == 'y':
            for i in range(100):
                total = sa.simAnnealing(railroad, trainlining, runs, rerun, algorithm, hill, image)
                scoresList.append(total)
                print(f"Rerun: {i + 1} score {total}")
            results.calculateScores(scoresList)
        else:
            sa.simAnnealing(railroad, trainlining, runs, rerun, algorithm, hill, image)

    elif algorithm == "all":
        list1 = ra.runRandom(railroad, trainlining, runs, rerun, algorithm, image)
        list2 = gr.runGreedy(railroad, trainlining, runs, rerun, algorithm, image)
        list3 = ha.runHillclimber(railroad, trainlining, runs, rerun, algorithm, image)
        list4 = ge.genetic(trainlining, railroad, runs, rerun, algorithm, populationSize, recombinationCoefficient, mutationRate, image)
        list5 = ah.runAdvancedHillclimber(railroad, trainlining, runs, rerun, algorithm, image)
        list6 = sa.simAnnealing(railroad, trainlining, runs, rerun, algorithm, hill, image)

        list = [list6, list1, list2, list3, list4, list5]
        visual.makeTotalGraph(list)


# patricia.roxanne.kwarwp_v2.py
# SPDX-License-Identifier: GPL-3.0-or-later
# patricia.roxanne.kwarwp.py
# SPDX-License-Identifier: GPL-3.0-or-later

"""
Meu Kwarwp Isaac
.. codeauthor:: Isaac D'Césares <isaac.dcesares@gmail.com>
Changelog
---------
.. versionadded::    20.08
        Classe Índio

.. versionadded::    20.07
        Criando novo Kwarwp!
"""
from collections import namedtuple as nt

IMGUR = "https://imgur.com/"

MAPA_INICIO = """
@....&
......
......
.#.^..
"""

MAPA_CERCA = """
%%%%%%%
%..%..&
%.....%
%^.%..%
%%%%%%%
"""

"""Mapa com o posicionamento inicial dos elementos."""
Ponto = nt("Ponto", "x y")
"""Par de coordenadas na direção horizontal (x) e vertiacal (y)."""
Rosa = nt("Rosa", "n l s o")
"""Rosa dos ventos com as direções norte, leste, sul e oeste."""

class Indio():
    """ Cria o personagem principal na arena do Kwarwp na posição definida.
        :param imagem: A figura representando o índio na posição indicada.
        :param x: Coluna em que o elemento será posicionado.
        :param y: Cinha em que o elemento será posicionado.
        :param cena: Cena em que o elemento será posicionado.
    """

    def __init__(self, imagem, x, y, cena):
        self.lado = lado = Kwarwp.LADO
        self.indio = Kwarwp.VITOLLINO.a(imagem, w=lado, h=lado, x=x, y=y, cena=cena)

class Kwarwp():
    """ Arena onde os desafios ocorrem.

        :param vitollino: Empacota o engenho de jogo Vitollino.
        :param mapa: Um texto representando o mapa do desafio.
    """
    VITOLLINO = None
    """Referência estática para obter o engenho de jogo."""
    LADO = None
    """Referência estática para definir o lado do piso da casa."""

    def __init__(self, vitollino=None, mapa=MAPA_INICIO, medidas={}):
        Kwarwp.VITOLLINO = self.v = vitollino()
        """Cria um matriz com os elementos descritos em cada linha de texto"""
        self.mapa = mapa.split()
        """Largura da casa da arena dos desafios, número de colunas no mapa"""
        self.lado, self.col, self.lin = 100, len(self.mapa[0]), len(self.mapa)+1
        Kwarwp.LADO = self.lado
        w, h = self.col *self.lado, self.lin *self.lado
        self.taba = {}
        """Dicionário que a partir de coordenada (i,J) localiza um piso da taba"""
        medidas.update(width=w, height=f"{h}px")
        self.cena = self.cria(mapa=self.mapa) if vitollino else None

    def cria(self, mapa=""):
        """ Fábrica de componentes.

            :param mapa: Um texto representando o mapa do desafio.
        """
        Fab = nt("Fab", "objeto imagem")
        """Esta tupla nomeada serve para definir o objeto construido e sua imagem."""

        fabrica = {
        "&": Fab(self.coisa, f"{IMGUR}dZQ8liT.jpg"), # OCA
        "^": Fab(self.indio, f"{IMGUR}8jMuupz.png"), # INDIO
        ".": Fab(self.vazio, f"{IMGUR}npb9Oej.png"), # VAZIO
        "_": Fab(self.coisa, f"{IMGUR}sGoKfvs.jpg"), # SOLO
        "#": Fab(self.coisa, f"{IMGUR}ldI7IbK.png"), # TORA
        "@": Fab(self.coisa, f"{IMGUR}tLLVjfN.png"), # PICHE
        "~": Fab(self.coisa, f"{IMGUR}UAETaiP.gif"), # CEU
        "*": Fab(self.coisa, f"{IMGUR}PfodQmT.gif"), # SOL
        "|": Fab(self.coisa, f"{IMGUR}uwYPNlz.png")  # CERCA
        }
        """Dicionário que define o tipo e a imagem do objeto para cada elemento."""
        mapa = mapa if mapa != "" else self.mapa
        """Cria um cenário com imagem de terra de chão batido, céu e sol"""
        mapa = self.mapa
        lado = self.lado
        print(f"cria(self, mapa={mapa}, col={len(self.mapa[0])}")
        cena = self.v.c(fabrica["_"].imagem)
        ceu = self.v.a(fabrica["~"].imagem, w=lado*self.col, h=lado, x=0, y=0, cena=cena)
        sol = self.v.a(fabrica["*"].imagem, w=60, h=60, x=0, y=40, cena=cena)
        self.taba = {(i, j): fabrica[imagem].objeto(fabrica[imagem].imagem, x=i*lado, y=j*lado+lado, cena=cena)
            for j, linha in enumerate(mapa) for i, imagem in enumerate(linha)}
        """Posiciona os elementos segundo suas posições i, j na matriz mapa"""
        cena.vai()
        return cena

    def coisa(self, imagem, x, y, cena):
        """ Cria um elemento na arena do Kwarwp na posição definida.
            :param x: coluna em que o elemento será posicionado.
            :param y: linha em que o elemento será posicionado.
            :param cena: cena em que o elemento será posicionado.
        """
        lado = self.lado
        return self.v.a(imagem, w=lado, h=lado, x=x, y=y, cena=cena)

    def vazio(self, imagem, x, y, cena):
        """ Cria um espaço vazio na arena do Kwarwp na posição definida.
            :param x: coluna em que o elemento será posicionado.
            :param y: linha em que o elemento será posicionado.
            :param cena: cena em que o elemento será posicionado.
        """
        lado = self.lado
        return self.v.a(imagem, w=lado, h=lado, x=x, y=y, cena=cena)

    def indio(self, imagem, x, y, cena):
        """ Cria o personagem principal na arena do Kwarwp na posição definida.
            :param x: coluna em que o elemento será posicionado.
            :param y: linha em que o elemento será posicionado.
            :param cena: cena em que o elemento será posicionado.
        """
        lado = self.lado
        return Indio(imagem, x=x, y=y, cena=cena)

def main(vitollino, medidas={}):
    """ Rotina principal que invoca a classe Kwarwp.

        :param vitollino: Empacota o engenho de jogo Vitollino.
        :param medidas: Um dicionário usado para redimensionar a tela.
    """
    # print(f"main(vitollino={vitollino} medidas={medidas}")
    Kwarwp(vitollino, medidas=medidas)

if __name__ == "__main__":
    from _spy.vitollino.main import Jogo, STYLE
    STYLE.update(width=600, height="500px")
    main(Jogo, STYLE)


days = int(input())
room = input()
appraisement = input()
nights = days - 1
price = 0

if room == 'apartment':
    if days < 10:
        price = 0.7 * 25
    elif days <= 15:
        price = 0.65 * 25
    else:
        price = 0.5 * 25
elif room == 'president apartment':
    if days < 10:
        price = 0.9 * 35
    elif days <= 15:
        price = 0.85 * 35
    else:
        price = 0.8 * 35
elif room == 'room for one person':
    price = 18
if appraisement == 'positive':
    price *= 1.25
else:
    price *= 0.9
price *= nights
print(f'{price:.2f}')


from __future__ import print_function
import os
import re
import sys
from setuptools import setup, find_packages
from distutils.command.build_py import build_py as _build_py
from glob import glob
from os.path import join

python_requires = (3, 6)

if sys.version_info < python_requires:
    raise SystemExit('Python 3.6 or later is required!')

install_requires = [
    'numpy>=1.11.3',
    'scipy>=0.18.1',
    'matplotlib>=2.0.0',
]

extras_require = {
    'docs': [
        'sphinx',
        'sphinx_rtd_theme',
        'pillow',
    ],
    'test': [
        'pytest>=3.6.1',
        'pytest-xdist>=1.22.1',
    ]
}

with open('README.rst') as fd:
    long_description = fd.read()

# Get the current version number:
with open('ase/__init__.py') as fd:
    version = re.search("__version__ = '(.*)'", fd.read()).group(1)

package_data = {'ase': ['spacegroup/spacegroup.dat',
                        'collections/*.json',
                        'db/templates/*',
                        'db/static/*'],
                'ase.test': ['pytest.ini',
                             'data/*']}

class build_py(_build_py):
    """Custom distutils command to build translations."""
    def __init__(self, *args, **kwargs):
        _build_py.__init__(self, *args, **kwargs)
        # Keep list of files to appease bdist_rpm.  We have to keep track of
        # all the installed files for no particular reason.
        self.mofiles = []

    def run(self):
        """Compile translation files (requires gettext)."""
        _build_py.run(self)
        msgfmt = 'msgfmt'
        status = os.system(msgfmt + ' -V')
        if status == 0:
            for pofile in sorted(glob('ase/gui/po/*/LC_MESSAGES/ag.po')):
                dirname = join(self.build_lib, os.path.dirname(pofile))
                if not os.path.isdir(dirname):
                    os.makedirs(dirname)
                mofile = join(dirname, 'ag.mo')
                print()
                print('Compile {}'.format(pofile))
                status = os.system('%s -cv %s --output-file=%s 2>&1' %
                                   (msgfmt, pofile, mofile))
                assert status == 0, 'msgfmt failed!'
                self.mofiles.append(mofile)

    def get_outputs(self, *args, **kwargs):
        return _build_py.get_outputs(self, *args, **kwargs) + self.mofiles

setup(name='ase-koopmans',
      version=version,
      description='Atomic Simulation Environment for Koopmans',
      url='https://github.com/elinscott/ase_koopmans',
      maintainer='Edward Linscott',
      maintainer_email='edwardlinscott@gmail.com',
      license='LGPLv2.1+',
      platforms=['unix'],
      packages=find_packages(),
      install_requires=install_requires,
      extras_require=extras_require,
      package_data=package_data,
      entry_points={'console_scripts': ['ase=ase.cli.main:main',
                                        'ase-db=ase.cli.main:old',
                                        'ase-gui=ase.cli.main:old',
                                        'ase-run=ase.cli.main:old',
                                        'ase-info=ase.cli.main:old',
                                        'ase-build=ase.cli.main:old']},
      long_description=long_description,
      cmdclass={'build_py': build_py},
      classifiers=[
          'Development Status :: 2 - Pre-Alpha',
          'License :: OSI Approved :: '
          'GNU Lesser General Public License v2 or later (LGPLv2+)',
          'Operating System :: OS Independent',
          'Programming Language :: Python :: 3',
          'Programming Language :: Python :: 3.6',
          'Programming Language :: Python :: 3.7',
          'Topic :: Scientific/Engineering :: Physics'])


import torch
import torch.nn as nn
from torch.nn.parallel import DataParallel, DistributedDataParallel

import os
import copy
import pickle
import numpy as np
from termcolor import colored
from collections import defaultdict
from typing import Any, Dict, List, Optional

from .missing import get_missing_parameters_message, get_unexpected_parameters_message
from .heuristic import align_and_update_state_dicts

from vistem.utils.logger import setup_logger

__all__ = ['Checkpointer']

class Checkpointer:
    def __init__(
        self,
        model: nn.Module,
        save_dir: str = "",
        *,
        save_to_disk: bool = True,
        **checkpointables: object,
    ) -> None:
        if isinstance(model, (DistributedDataParallel, DataParallel)):
            model = model.module

        self.model = model
        self.save_dir = save_dir
        self.save_to_disk = save_to_disk
        self.checkpointables = copy.copy(checkpointables)

        self._logger = setup_logger(__name__)
        if not self.save_to_disk:
            self._logger.warning('No saving checkpoint mode')
        if not self.save_dir:
            self._logger.error('Not clarify saving directory')
            self.save_to_disk = False

    def _load_file(self, filename) -> object:
        if filename.endswith(".pkl"):
            with open(filename, "rb") as f:
                data = pickle.load(f, encoding="latin1")

            if "model" in data and "__author__" in data:
                # file is in Detectron2 model zoo format
                self._logger.info(f"Reading a file from '{data['__author__']}'")
                return data
            else:
                # assume file is from Caffe2 / Detectron1 model zoo
                data = {k: v for k, v in data.items() if not k.endswith("_momentum")}
                return {"model": data, "__author__": "Caffe2", "matching_heuristics": True}

        loaded = torch.load(filename, map_location=torch.device("cpu"))
        if '__author__' not in loaded:
            if filename.split('/')[-1].startswith('efficientnet'):
                loaded = {'model' : loaded, '__author__' : 'lukemelas', 'matching_heuristics' : True} # https://github.com/lukemelas/EfficientNet-PyTorch

        else :
            assert loaded['__author__'] == 'vistem'

        return loaded

    def _load_model(self, checkpoint: Any):
        if checkpoint.get("matching_heuristics", False):
            self._convert_ndarray_to_tensor(checkpoint["model"])
            model_state_dict = self.model.state_dict()
            align_and_update_state_dicts(
                model_state_dict,
                checkpoint["model"],
                c2_conversion=checkpoint.get("__author__", None),
            )
            checkpoint["model"] = model_state_dict

        checkpoint_state_dict = checkpoint.pop("model")
        self._convert_ndarray_to_tensor(checkpoint_state_dict)
        self._strip_prefix_if_present(checkpoint_state_dict, "module.")

        model_state_dict = self.model.state_dict()
        incorrect_shapes = []
        for k in list(checkpoint_state_dict.keys()):
            if k in model_state_dict:
                shape_model = tuple(model_state_dict[k].shape)
                shape_checkpoint = tuple(checkpoint_state_dict[k].shape)
                if shape_model != shape_checkpoint:
                    incorrect_shapes.append((k, shape_checkpoint, shape_model))
                    checkpoint_state_dict.pop(k)

        incompatible = self.model.load_state_dict(checkpoint_state_dict, strict=False)

        return incompatible, incorrect_shapes

    def load(self, path: str, checkpointables: Optional[List[str]] = None) -> object:
        if not path:
            self._logger.warning("No checkpoint found. Initializing model from scratch")
            return {}

        self._logger.info("Loading checkpoint from {}".format(path))
        assert os.path.isfile(path), "Checkpoint {} not found!".format(path)

        checkpoint = self._load_file(path)
        incompatible, incorrect_shapes = self._load_model(checkpoint)
        self._log_incompatible_keys(incompatible, incorrect_shapes)
        for key in self.checkpointables if checkpointables is None else checkpointables:
            if key in checkpoint:
                self._logger.info("Loading {} from {}".format(key, path))
                obj = self.checkpointables[key]
                obj.load_state_dict(checkpoint.pop(key))

        return checkpoint

    def save(self, name: str, **kwargs: Dict[str, str]) -> None:
        data = {}
        data['__author__'] = 'vistem'
        data["model"] = self.model.state_dict()
        for key, obj in self.checkpointables.items():
            data[key] = obj.state_dict()
        data.update(kwargs)

        basename = "{}.pth".format(name)
        save_file = os.path.join(self.save_dir, basename)
        assert os.path.basename(save_file) == basename, basename

        self._logger.info("Saving checkpoint to {}".format(save_file))
        with open(save_file, "wb") as f:
            torch.save(data, f)

        self.tag_last_checkpoint(basename)

    def resume_or_load(self, path: str, *, resume: bool = True) -> object:
        if resume and self.has_checkpoint():
            path = self.get_checkpoint_file()
            return self.load(path)
        else:
            return self.load(path, checkpointables=[])

    def has_checkpoint(self) -> bool:
        save_file = os.path.join(self.save_dir, "last_checkpoint")
        return os.path.isfile(save_file)

    def get_checkpoint_file(self) -> str:
        save_file = os.path.join(self.save_dir, "last_checkpoint")
        try:
            with open(save_file, "r") as f:
                last_saved = f.read().strip()
        except IOError:
            return ""
        return os.path.join(self.save_dir, last_saved)

    def tag_last_checkpoint(self, last_filename_basename: str) -> None:
        save_file = os.path.join(self.save_dir, "last_checkpoint")
        with open(save_file, "w") as f:
            f.write(last_filename_basename)

    def _log_incompatible_keys(self, incompatible, incorrect_shapes) -> None:
        for k, shape_checkpoint, shape_model in incorrect_shapes:
            self._logger.error(
                f"Unable to load '{k}' to the model due to incompatible shapes: "
                f"{shape_checkpoint} in the checkpoint "
                f"but {shape_model} in the model!"
            )

        if incompatible.missing_keys:
            msg = get_missing_parameters_message(incompatible.missing_keys)
            self._logger.info(msg)

        if incompatible.unexpected_keys:
            msg = get_unexpected_parameters_message(incompatible.unexpected_keys)
            self._logger.info(msg)

    def _convert_ndarray_to_tensor(self, state_dict: Dict[str, Any]) -> None:
        for k in list(state_dict.keys()):
            v = state_dict[k]
            if not isinstance(v, np.ndarray) and not isinstance(v, torch.Tensor):
                raise ValueError(f"Unsupported type found in checkpoint! {k}: {type(v)}")
            if not isinstance(v, torch.Tensor):
                state_dict[k] = torch.from_numpy(v)

    def _strip_prefix_if_present(self, state_dict: Dict[str, Any], prefix: str) -> None:
        keys = sorted(state_dict.keys())
        if not all(len(key) == 0 or key.startswith(prefix) for key in keys):
            return

        for key in keys:
            newkey = key[len(prefix) :]
            state_dict[newkey] = state_dict.pop(key)

        try:
            metadata = state_dict._metadata
        except AttributeError:
            pass
        else:
            for key in list(metadata.keys()):
                # for the metadata dict, the key can be:
                # '': for the DDP module, which we want to remove.
                # 'module': for the actual model.
                # 'module.xx.xx': for the rest.

                if len(key) == 0:
                    continue
                newkey = key[len(prefix) :]
                metadata[newkey] = metadata.pop(key)


from unittest import TestCase
from square import Square
from quadrilateral import Quadrilateral

class TestSquare(TestCase):

    def test_snap(self):
        floats1 = [0.49, 0.49, 0.0, 0.49, 0.0, 0.0, 0.49, 0.0]
        squ1 = Square(floats1)
        # should return true because all the points will snap to 0.0 and then return the original square
        self.assertTrue(squ1.snap() == squ1)

        floats2 = [0.51, 0.51, 0.0, 0.51, 0.0, 0.0, 0.51, 0.0]
        squ2 = Square(floats2)
        # should return true because all the points at 0.51 will snap to 1.0, keeping the square shape
        self.assertFalse(squ2.snap() == squ2)

        floats3 = [.5, .5, .0, .5, .0, .0, .5, .0]
        floats4 = [1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]
        squ3 = Square(floats3)
        q1 = Quadrilateral(floats4)
        self.assertEqual(squ3.snap(), q1)

    def test___eq__(self):
        floats1 = [1, 1, 0, 1, 0, 0, 1, 0]
        squ1 = Square(floats1)
        floats2 = [1, 1, 0, 1, 0, 0, 1, 0]
        squ2 = Square(floats2)
        floats3 = [3, 3, 0, 3, 0, 0, 3, 0]
        squ3 = Square(floats3)

        self.assertTrue(squ1 == squ2)
        self.assertFalse(squ1 == squ3)


import numpy as np
from PIL import Image, ImageFilter
from os import path, walk
import pandas as pd
from scipy.ndimage.filters import gaussian_filter
import shutil

def Gaussian33(img):
    kernel = ImageFilter.Kernel((3, 3), (1/16, 1/8, 1/16, 1/8, 1/4, 1/8, 1/16, 1/8, 1/16), 1, 0)
    im2 = img.filter(kernel)
    return im2

def Laplacian(img):
    kernel = ImageFilter.Kernel((3, 3), (-1, -1, -1, -1, 8, -1, -1, -1, -1), 1, 0)
    im2 = img.filter(kernel)
    return im2

def sharpe(dir, filename, label):
    img = Image.open(path.join(dir, filename)).convert('L')
    print(path.join(dir, filename))
    # crop
    (height, width) = img.size
    (top, idx) = (0, 1)
    while top + 32 <= height:
        left = 0
        while left + 32 <= width:
            imgCrop = img.crop((top, left, top + 32, left + 32))
            left += 32
            imgLP = Gaussian33(imgCrop)
            imgLP = Laplacian(imgLP)
            imgLP = np.array(imgLP)
            shar = np.var(imgLP)
            if shar < 2000:
                continue
            fn = str(idx) + '_' + filename
            dd = dir.replace('image', 'imageSharp')
            imgCrop.save(path.join(dd, fn))
            label['file'].append(fn)
            label['sharp'].append(shar)
            idx += 1
        top += 32

def sharpAll(rootdir):
    label = { 'file': [], 'sharp': [] }
    labelPath = rootdir.replace('image', 'sharp.csv')
    for subdir, dirs, files in walk(rootdir):
        for file in files:
            pd.DataFrame(label).to_csv(labelPath, index=False)
            sharpe(subdir, file, label)

def select_sharp(sharp):
    rootdir = path.join('data', 'train', 'image')
    labelPath = rootdir.replace('image', 'sharp2.csv')
    df = pd.read_csv(labelPath)
    print(df.shape)
    data = df.loc[df['sharp'] > sharp].reset_index(drop=True)
    print(data.shape)
    # labelPath = rootdir.replace('image', 'sharp4.csv')
    # data.to_csv(labelPath, index=False)

    rootdir = path.join('data', 'test', 'image')
    labelPath = rootdir.replace('image', 'sharp2.csv')
    df = pd.read_csv(labelPath)
    print(df.shape)
    data = df.loc[df['sharp'] > sharp].reset_index(drop=True)
    print(data.shape)
    # labelPath = rootdir.replace('image', 'sharp4.csv')
    # data.to_csv(labelPath, index=False)

    rootdir = path.join('data', 'valid', 'image')
    labelPath = rootdir.replace('image', 'sharp2.csv')
    df = pd.read_csv(labelPath)
    print(df.shape)
    data = df.loc[df['sharp'] > sharp].reset_index(drop=True)
    print(data.shape)
    # labelPath = rootdir.replace('image', 'sharp4.csv')
    # data.to_csv(labelPath, index=False)

def move_to_valid():
    rootdir = path.join('data', 'train', 'image')
    labelPath = rootdir.replace('image', 'sharp2.csv')
    df = pd.read_csv(labelPath)
    N = int(df.shape[0] / 5 * 4)
    train_df = df.iloc[:N,:].reset_index(drop=True)
    valid_df = df.iloc[N:,:].reset_index(drop=True)
    train_df.to_csv(labelPath, index=False)
    labelPath = labelPath.replace('train', 'valid')
    valid_df.to_csv(labelPath, index=False)

    from_dir = rootdir.replace('image', 'imageSharp')
    to_dir = from_dir.replace('train', 'valid')
    for file in valid_df['file']:
        print(file)
        shutil.move(path.join(from_dir, file), path.join(to_dir, file))

def check(rootdir):
    for subdir, dirs, files in walk(rootdir):
        print(len(files))
    sharpfile = rootdir.replace('imageBlur5000', 'groundTruth5000.csv')
    df = pd.read_csv(sharpfile)
    print(df.shape)

def createLabel(rootdir):
    sharpfile = rootdir.replace('imageSharp', 'sharp2.csv')
    df = pd.read_csv(sharpfile)
    labelDf = { 'file': [], 'label': [] }
    for file in df['file']:
        blur(rootdir, file, labelDf)
    trainGT = pd.DataFrame(labelDf)
    trainGT.to_csv(rootdir.replace('imageSharp', 'groundTruth5000.csv'), index=False)

def blur(dir, filename, gt):
    img = Image.open(path.join(dir, filename)).convert('L')
    # print(path.join(dir, filename)
    imgArr = np.array(img)
    # for i in range(20):
    z = int(np.random.rand(1)[0] * 20)
    newArr = gaussian_filter(imgArr, sigma=z)
    newArr.astype(int)
    data = Image.fromarray(newArr, 'L')
    # fn = str(i) + '_' + filename
    fn = filename
    dd = dir.replace('imageSharp', 'imageBlur5000')
    gt['file'].append(fn)
    gt['label'].append(z)
    data.save(path.join(dd, fn))

if __name__ == '__main__':
    # rootdir = path.join('data', 'train', 'image')
    # sharpAll(rootdir)

    # rootdir = path.join('data', 'test', 'image')
    # sharpAll(rootdir)

    select_sharp(5000)
    # move_to_valid()

    createLabel(path.join('data', 'train', 'imageSharp'))
    createLabel(path.join('data', 'valid', 'imageSharp'))
    createLabel(path.join('data', 'test', 'imageSharp'))

    check(path.join('data', 'train', 'imageBlur5000'))
    check(path.join('data', 'valid', 'imageBlur5000'))
    check(path.join('data', 'test', 'imageBlur5000'))


import os

import psycopg2

from flask import current_app
from flask import g

def init_db(app):
    try:
        app.config['db_dsn'] = ('host={DB_HOST} '
                                'dbname={DB_NAME} '
                                'user={DB_USER} '
                                'password={DB_PASSWORD}').format(**os.environ)
    except KeyError as e:
        app.logger.error('Missing database configuration: %s', e)

    @app.teardown_appcontext
    def close_db(error):
        """Close the database at the end of the request"""
        if hasattr(g, 'db'):
            g.db.close()

def connect_db():
    dsn = current_app.config['db_dsn']
    return psycopg2.connect(dsn)

def get_db():
    """Open a new database connection if there is none yet for the
    current application context.
    """
    if not hasattr(g, 'db'):
        g.db = connect_db()
    return g.db


import geopandas as gpd
from shapely.geometry import Point
import json

def calculate_distance(city1, city2, cities_df):
    point1 = cities_df.loc[cities_df['city'] == city1]['geometry'].values[0]
    point2 = cities_df.loc[cities_df['city'] == city2]['geometry'].values[0]
    return point1.distance(point2)

def create_distance_matrix(city_pairs, cities_datafile):
    cities = list(set([city for pair in city_pairs for city in pair]))
    n = len(cities)
    with open(cities_datafile) as f:
        cities_data = json.load(f)
    print(cities_data.columns())
    cities_df = gpd.GeoDataFrame(cities_data, crs='EPSG:4326', geometry=[Point(xy) for xy in cities_data['coordinates']])
    distances = np.zeros((n, n))
    for i in range(n):
        for j in range(i+1, n):
            city1, city2 = cities[i], cities[j]
            if (city1, city2) in city_pairs:
                distance = calculate_distance(city1, city2, cities_df)
                distances[i][j] = distance
                distances[j][i] = distance
    return distances, cities

def clarke_and_wright(num_cars, capacity, distances):

    n = len(distances)
    savings = np.zeros((n, n))
    for i in range(n):
        for j in range(i+1, n):
            savings[i][j] = distances[i][0] + distances[0][j] - distances[i][j]

    indices = [(i, j) for i in range(1, n) for j in range(i+1, n)]
    sorted_indices = sorted(indices, key=lambda x: savings[x[0]][x[1]], reverse=True)

    routes = [[0] * (capacity + 1) for _ in range(num_cars)]
    remaining_capacity = [capacity for _ in range(num_cars)]
    penalties = [0 for _ in range(num_cars)]
    distances_traveled = [0 for _ in range(num_cars)]
    empty_distances_traveled = [0 for _ in range(num_cars)]

    for (i, j) in sorted_indices:
        for k in range(num_cars):
            if (i in routes[k]) and (j not in routes[k]) and (remaining_capacity[k] >= 1):
                index = routes[k].index(i)
                routes[k].insert(index+1, j)
                distance = distances[i][j]
                distances_traveled[k] += distance
                remaining_capacity[k] -= 1
                if remaining_capacity[k] > 0:
                    penalties[k] = remaining_capacity[k]
                    empty_distances_traveled[k] += distance
                break

            elif (j in routes[k]) and (i not in routes[k]) and (remaining_capacity[k] >= 1):

                index = routes[k].index(j)
                routes[k].insert(index, i)
                distance = distances[i][j]
                distances_traveled[k] += distance
                remaining_capacity[k] -= 1
                if remaining_capacity[k] > 0:
                    penalties[k] = remaining_capacity[k]
                    empty_distances_traveled[k] += distance
                break

    for k in range(num_cars):
        for i in range(1, n):
            if i not in routes[k]:
                min_penalty = min(penalties)
                index = penalties.index(min_penalty)
                routes[index].append(i)
                distance = distances[routes[index][-2]][i]
                distances_traveled[index] += distance
                remaining_capacity[index] -= 1
                if remaining_capacity[index] > 0:
                    penalties[index] = remaining_capacity[index]
                    empty_distances_traveled[index] += distance
                else:
                    penalties[index] = 0

    return routes, distances_traveled, empty_distances_traveled


import streamlit as st
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import seaborn as sns

"""
## Connecting variables

Correlation plot

"""

st.sidebar.markdown("""
  - season : season (1:winter, 2:spring, 3:summer, 4:fall)
  - yr : year (0: 2011, 1:2012)
  - mnth : month ( 1 to 12)
  - holiday : whether day is holiday or not
  - weekday : day of the week ( 0:Sunday, 6:Saturday)
  - workingday : if day is neither weekend nor holiday is 1, otherwise is 0.
  + weathersit :
    - 1: Clear, Few clouds, Partly cloudy, Partly cloudy
    - 2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
    - 3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
    - 4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog""")

df_hour = pd.read_csv('hour.csv')
df = pd.read_csv('day.csv')

## Correlation Plot
cmap = sns.diverging_palette(180, 280, s=60, as_cmap=True)
fig, ax = plt.subplots(figsize=(15,10))
sns.heatmap(data = df.loc[:,['hum','windspeed','atemp','cnt']].corr(),
               vmin = -1, vmax = 1, center=0,
               cmap = cmap,
               annot=True, annot_kws={'size':16})

st.pyplot(fig)

cat_names = df.loc[:,['season','yr','mnth','holiday','weekday','workingday','weathersit']].columns.tolist()

with st.expander("Make a grouped correlation plot: "):
  user_cat = st.selectbox(
    'Select grouping variable:',
    cat_names,
    0
  )
  cmap = sns.diverging_palette(180, 280, s=60, as_cmap=True)
  if user_cat == 'season':
    corr_per_season = df.loc[:,['hum','windspeed','atemp','cnt','season']].groupby(['season']).corr()

    the_season = df.season.unique().tolist()

    fig, axs = plt.subplots(1, len(the_season), figsize=(12, 6), sharex=True, sharey=True)

    for ix, x in enumerate(the_season):
        sns.heatmap(data = corr_per_season.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap, cbar=False,
                    annot=True,
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)

  elif user_cat == 'yr':
    corr_per_yr = df.loc[:,['hum','windspeed','atemp','cnt','yr']].groupby(['yr']).corr()

    the_yr = df.yr.unique().tolist()

    fig, axs = plt.subplots(1, len(the_yr), figsize=(12, 6), sharey = True)

    for ix, x in enumerate(the_yr):
        sns.heatmap(data = corr_per_yr.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap, cbar=False,
                    annot=True,
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)

  elif user_cat == 'mnth':
    corr_per_mnth = df.loc[:,['hum','windspeed','atemp','cnt','mnth']].groupby(['mnth']).corr()

    the_mnth = df.mnth.unique().tolist()

    fig, axs = plt.subplots(1, len(the_mnth), figsize=(24,6), sharex = True, sharey = True)

    for ix, x in enumerate(the_mnth):
        sns.heatmap(data = corr_per_mnth.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap,cbar = False,
                    annot = True, annot_kws = {'rotation':'vertical'},
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)

  elif user_cat == 'holiday':
    corr_per_holiday = df.loc[:,['hum','windspeed','atemp','cnt','holiday']].groupby(['holiday']).corr()

    the_holiday = df.holiday.unique().tolist()

    fig, axs = plt.subplots(1, len(the_holiday), figsize=(12, 6), sharey = True)

    for ix, x in enumerate(the_holiday):
        sns.heatmap(data = corr_per_holiday.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap, cbar=False,
                    annot=True,
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)

  elif user_cat == 'weekday':
    corr_per_weekday = df.loc[:,['hum','windspeed','atemp','cnt','weekday']].groupby(['weekday']).corr()

    the_weekday = df.weekday.unique().tolist()

    fig, axs = plt.subplots(1, len(the_weekday), figsize=(18, 6), sharey = True)

    for ix, x in enumerate(the_weekday):
        sns.heatmap(data = corr_per_weekday.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap, cbar=False,
                    annot=True,
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)

  elif user_cat == 'workingday':
    corr_per_workingday = df.loc[:,['hum','windspeed','atemp','cnt','workingday']].groupby(['workingday']).corr()

    the_workingday = df.workingday.unique().tolist()

    fig, axs = plt.subplots(1, len(the_workingday), figsize=(12, 6), sharey = True)

    for ix, x in enumerate(the_workingday):
        sns.heatmap(data = corr_per_workingday.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap, cbar=False,
                    annot=True,
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)

  else:
    corr_per_weathersit = df.loc[:,['hum','windspeed','atemp','cnt','weathersit']].groupby(['weathersit']).corr()

    the_weathersit = df.weathersit.unique().tolist()

    fig, axs = plt.subplots(1, len(the_weathersit), figsize=(12, 6),sharey = True)

    for ix, x in enumerate(the_weathersit):
        sns.heatmap(data = corr_per_weathersit.loc[x],
                    vmin=-1, vmax=1, center=0,
                    cmap=cmap, cbar=False,
                    annot=True,
                    ax=axs[ix])
        axs[ix].set_title( x)
    st.pyplot(fig)
## Scatter plots

st.write("Choose hue and facets")

cont_names = ['atemp','hum','windspeed']

hue_facet = st.checkbox(
  'Add hue',
  False
)

row_facet = st.checkbox(
  'Facet by row',
  False
)

col_facet = st.checkbox(
  'Facet by column',
  False
)
user_cont = st.selectbox(
  'Select x-axis variable:',
  cont_names,
  0
)

if row_facet:
  row_choose = st.selectbox(
    'Select row facet: ',
    cat_names,
    0
  )
else: row_choose = None

if hue_facet:
  hue_choose = st.selectbox(
    'Select hue facet: ',
    cat_names,
    0
  )
else: hue_choose = None

if col_facet:
  col_choose = st.selectbox(
    'Select column facet: ',
    cat_names,
    0
  )
else: col_choose = None

st.pyplot(sns.relplot(data = df, x = user_cont, y = 'cnt', hue = hue_choose, row = row_choose, col = col_choose, palette = 'Dark2'))


from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.urls import reverse
from courses.models import Review
from util.models import Vote
from professors.models import Professor
from .course_util import *
from util.views import error404, util_like_review, util_dislike_review
from django.utils import timezone
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

LOGGER = logging.getLogger("project")

def course_detail(request, course_id: str):
    LOGGER.debug(f"course_detail: {course_id}")
    try:
        if request.method == "GET":
            rev_sorting = request.GET.get('rev-sorting')
            if rev_sorting is None:
                return load_course_detail(request, course_id)
            else:
                return load_course_detail(request, course_id, rev_sorting=rev_sorting)
        elif request.method == "POST" and "submit" in request.POST:
            LOGGER.debug(request.POST)
            review, message = add_review_from_details(request)
            return load_course_detail(request, course_id, review, message)
        else:
            LOGGER.error(request.POST)
            return error404(request, error="Invalid request")
    except Exception as e:
        return error404(request, error=e)

def load_course_detail(
    request, course_id: str, review: bool = None, review_message: str = "",
        rev_sorting: str = "RevDateDesc"
) -> HttpResponse:
    try:
        course = Course.objects.get(course_id=course_id)
        classes = Class.objects.filter(course=course)
        professors_list = [cl.professor for cl in classes]
        reviews_list = create_review_objects(classes, rev_sorting)
        reviews_avg = calculate_rating_avg(reviews_list)
        likes = []
        dislikes = []
        if request.user.id is not None:
            user = User.objects.get(username=request.user)
            likes = [vote.review.id for vote in Vote.objects.filter(user=user) if vote.vote == "L"]
            dislikes = [vote.review.id for vote in Vote.objects.filter(user=user) if vote.vote == "D"]

        paginator = Paginator(reviews_list, 10)
        page_number = request.GET.get('page')

        for rev in reviews_list:
            rev["like"] = len(Vote.objects.filter(review=rev['review_obj'], vote="L"))
            rev["dislike"] = len(Vote.objects.filter(review=rev['review_obj'], vote="D"))

        try:
            page_obj = paginator.get_page(page_number)
        except PageNotAnInteger:
            page_obj = paginator.page(1)
        except EmptyPage:
            page_obj = paginator.page(paginator.num_pages)

        if review is not None:
            context = {
                "classes": classes,
                "course": course,
                "reviews_list": reviews_list,
                "reviews_avg": reviews_avg,
                "professors_list": professors_list,
                "review_saved": review,
                "review_message": review_message,
                "page_obj": page_obj,
                "likes": likes,
                "dislikes": dislikes,
                "sorting_reviews": rev_sorting
            }
        else:
            context = {
                "classes": classes,
                "course": course,
                "reviews_list": reviews_list,
                "reviews_avg": reviews_avg,
                "professors_list": professors_list,
                "page_obj": page_obj,
                "likes": likes,
                "dislikes": dislikes,
                "sorting_reviews": rev_sorting,
            }
        LOGGER.debug(context)
        return render(request, "courses/detail.html", context)
    except Exception as e:
        LOGGER.exception(f"Could not load course detail, encountered error: {e}")
        return error404(request, error=e)

def add_review(request):
    context = {
        "courses": Course.objects.all(),
        "professors": Professor.objects.only("professor_id", "name"),
        "course_ids": [f"{course.course_subject_code} {course.catalog_number}" for course in Course.objects.all()],
        "courses_json": get_courses_data_json(),
        "professors_json": get_professors_data_json()
    }
    if request.method == "GET":
        if request.user.id is None:
            return redirect(reverse("search:index"))
        return render(request, "courses/add_review.html", context)
    elif request.method == "POST":
        user = User.objects.get(username=request.user)
        try:
            if not text_is_valid(request.POST["review_text"]):
                context["review_text_invalid"] = True
                add_redirect_message(
                    request=request,
                    message="Review not saved. Review text failed to meet RateNYU standards.",
                    success=False,
                )
                return redirect("courses:add_review")

            new_review = save_new_review(
                user=user,
                user_entered_course_id=request.POST["add_review_course_id"],
                professor_name=request.POST["add_review_professor_name"],
                review_rating=request.POST["review_rating"],
                review_text=request.POST["review_text"],
            )
            if new_review == "Already wrote review for this course":
                add_redirect_message(
                    request=request,
                    message="You already wrote a review for this course.",
                    success=False,
                )
            else:
                LOGGER.info(f"Created new Review: {new_review}")
                add_redirect_message(
                    request=request,
                    message="Your review was saved!",
                    success=True,
                )
            return redirect("courses:add_review")
        except Exception as e:
            LOGGER.exception(f"Could not create review, encountered error: {e}")
            add_redirect_message(
                request=request,
                message="Uh Oh, something went wrong. Your review could not be saved.",
                success=False,
            )
            return redirect("courses:add_review")

def delete_review(request, review_id: str):
    try:
        r = Review.objects.get(pk=review_id)
        r.delete()
        add_redirect_message(
            request=request, message="Your review was deleted.", success=True
        )
        return redirect("users:profile", user_name=request.user)
    except Exception as e:
        return error404(request, error=e)

def edit_review(request):
    if request.method == 'POST':
        r = Review.objects.get(pk=request.POST.get('review_id'))
        r.review_text = request.POST.get('new_review_text')
        if not text_is_valid(r.review_text):
            add_redirect_message(request=request,
                                 message="Review not saved. Review text failed to meet RateNYU standards.",
                                 success=False)
            return redirect('users:profile', user_name=request.user)

        r.rating = request.POST['review_rating']
        r.pub_date = timezone.now()
        r.save()
    return redirect('users:profile', user_name=request.user)

def like_review(request, review_id: str):
    return util_like_review(request=request, review_id=review_id)

def dislike_review(request, review_id: str):
    return util_dislike_review(request=request, review_id=review_id)


"""Event image handlers."""

from flask import request

from hinews.messages.image import NoSuchImage, ImageDeleted, ImagePatched
from his import authenticated, authorized
from wsgilib import Binary, JSON

from hievents.orm import Image

__all__ = ["ROUTES"]

def get_image(ident):
    """Returns the respective image."""

    try:
        return Image.get(Image.id == ident)
    except Image.DoesNotExist:
        raise NoSuchImage()

@authenticated
@authorized("hievents")
def list_all():
    """Lists all available images."""

    return JSON([image.to_json() for image in Image])

@authenticated
@authorized("hievents")
def get(ident):
    """Returns a specific image."""

    return Binary(get_image(ident).data)

@authenticated
@authorized("hievents")
def delete(ident):
    """Deletes the respective image."""

    get_image(ident).delete_instance()
    return ImageDeleted()

@authenticated
@authorized("hievents")
def patch(ident):
    """Modifies image meta data."""

    image = get_image(ident)
    image.patch_json(request.json)
    image.save()
    return ImagePatched()

ROUTES = (
    ("GET", "/image", list_all, "list_images"),
    ("GET", "/image/<int:ident>", get, "get_image"),
    ("DELETE", "/image/<int:ident>", delete, "delete_image"),
    ("PATCH", "/image/<int:ident>", patch, "patch_image"),
)


"""
Title     : Symmetric Difference
Subdomain : Sets
Domain    : Python
Author    : Ahmedur Rahman Shovon
Created   : 15 July 2016
Updated   : 15 March 2021
Updated   : 19 June 2022
Problem   : https://www.hackerrank.com/challenges/symmetric-difference/problem
"""
m = int(input())
set_a = set(map(int, input().split()))
n = int(input())
set_b = set(map(int, input().split()))
set_a_diff = set_a.difference(set_b)
set_b_diff = set_b.difference(set_a)
for i in sorted(set_a_diff.union(set_b_diff)):
    print(i)