import datetime
import random
import argparse
import yaml
import pandas as pd
import pyswip
import re

class ArgNumber:
    """Implement the notion of 'number' when passed as input argument to the program, deeply checking it.
    It also checks if the number falls in a given range."""

    def __init__(self, number_type: type(int) | type(float),
                 min_val: int | float | None = None,
                 max_val: int | float | None = None):
        self.__number_type = number_type
        self.__min = min_val
        self.__max = max_val
        if number_type not in [int, float]:
            raise argparse.ArgumentTypeError("Invalid number type (it must be int or float)")
        if not ((self.__min is None and self.__max is None) or
                (self.__max is None) or (self.__min is not None and self.__min < self.__max)):
            raise argparse.ArgumentTypeError("Invalid range")

    def __call__(self, value: int | float | str) -> int | float:
        try:
            val = self.__number_type(value)
        except ValueError:
            raise argparse.ArgumentTypeError(f"Invalid value specified, conversion issues! Provided: {value}")
        if self.__min is not None and val < self.__min:
            raise argparse.ArgumentTypeError(f"Invalid value specified, it must be >= {self.__min}")
        if self.__max is not None and val > self.__max:
            raise argparse.ArgumentTypeError(f"Invalid value specified, it must be <= {self.__max}")
        return val

class ArgBoolean:
    """Implement the notion of 'boolean' when passed as input argument to the program, deeply checking it.
    It allows the user to provide it in different forms {1, 'True', 'true', 'yes'}, {0, 'False', 'false', 'no'}."""

    def __call__(self, value: str | bool | int) -> bool:
        if isinstance(value, str):
            val = value.lower().strip()
            if val != "true" and val != "false" and val != "yes" and val != "no":
                raise argparse.ArgumentTypeError(f"Invalid value specified: {value}")
            val = True if (val == "true" or val == "yes") else False
        elif isinstance(value, int):
            if value != 0 and value != 1:
                raise argparse.ArgumentTypeError(f"Invalid value specified: {value}")
            val = value == 1
        elif isinstance(value, bool):
            val = value
        else:
            raise argparse.ArgumentTypeError(f"Invalid value specified (expected boolean): {value}")
        return val

class ArgString:
    """Implement the notion of 'string' when passed as input argument to the program, deeply checking it.
    It allows the user to provide it in different forms {1, 'True', 'true', 'yes'}, {0, 'False', 'false', 'no'}."""

    def __call__(self, value: str | bool | int) -> bool:
        val = str(value)

        if val == "None":
            val = None
        return val

def generate_experiment_name(prefix: str | None = None, suffix: str | None = None) -> str:
    """Generate a dummy name for an experiment, such as 2023-08-10_17-06-22_Chianina.

        :param prefix: An optional prefix to add to the experiment name.
        :param suffix: An optional suffix to add to the experiment name (by default, it is a cattle breed).
        :returns: A string that represents the name of an experiment, such as 2023-08-10_17-06-22_Chianina.
    """

    def_suffix = ["Agerolese", "Angus", "Bianca_Modenese", "Bruna", "Burlina", "Cinisara", "Chianina", "Frisona",
                  "Grigio_Alpina", "Herens", "Limousine", "Marchigiana", "Maremmana", "Modicana", "Pezzata_Rossa",
                  "Piemontese", "Podolica", "Romagnola", "Simmental", "Valdostana", "Wagyu"]
    ret = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    if prefix is not None:
        ret = prefix + "_" + ret
    if suffix is not None:
        ret = ret + "_" + suffix
    else:
        ret = ret + "_" + random.choice(def_suffix)
    return ret

def elapsed_time(from_seconds: float, to_seconds: float) -> str:
    """Format a string message with the time elapsed between two checkpoints.

        :param from_seconds: The float time of the first checkpoint.
        :param to_seconds: The float time of the second checkpoint.
        :returns: A message like this one: "3 hours, 24 minutes, 2.311 seconds".
    """

    elapsed = to_seconds - from_seconds
    minutes = int(elapsed / 60.)
    hours = int(elapsed / 60. / 60.)
    seconds = elapsed - hours * 60. * 60. - minutes * 60.
    return str(hours) + " hours, " + str(minutes) + " minutes, " + f"{seconds:.3f} seconds"

def symbol_to_prolog_natural(symbol: dict) -> str:
    if "shape" in symbol:
        return "{}_{}_{}".format(symbol["shape"], symbol["color"], symbol["size"])
    else:
        op = list(symbol.keys())[0]
        return "{}([{}])".format(op, ", ".join([symbol_to_prolog_natural(x) for x in symbol[op]]))

def build_problem_aleph_natural(df: pd.DataFrame, target_task_id: int) -> (str, str):
    pos_examples = []
    neg_examples = []
    examples = [] # Popper-like encoding to use a single compute_metrics function.

    for i in range(len(df)):
        x = df.iloc[i]
        if x["task_id"] == target_task_id:
            sample = symbol_to_prolog_natural(yaml.safe_load(x["symbol"]))
            if x["label"]:
                pos_examples.append("valid({}).".format(sample))
                examples.append("pos(valid({})).".format(sample))
            else:
                neg_examples.append("valid({}).".format(sample))
                examples.append("neg(valid({})).".format(sample))

    return "\n".join(sorted(list(pos_examples))), "\n".join(sorted(list(neg_examples))), "\n".join(sorted(list(examples)))

def build_problem_popper_natural(df: pd.DataFrame, target_task_id: int) -> str:
    examples = []

    for i in range(len(df)):
        x = df.iloc[i]
        if x["task_id"] == target_task_id:
            sample = symbol_to_prolog_natural(yaml.safe_load(x["symbol"]))
            examples.append("{}(valid({})).".format(("pos" if x["label"] else "neg"), sample))

    return "\n".join(sorted(list(examples)))

def symbol_to_prolog_pointer(symbol: dict, known_compositions: dict, known_atoms: set) -> (str, list, dict, set):
    out = []

    if str(symbol) not in known_compositions:
        known_compositions[str(symbol)] = "c{:06d}".format(len(known_compositions))

    assert len(symbol.keys()) == 1

    operator = list(symbol.keys())[0]
    children = []

    for c in symbol[operator]:
        if "shape" in c:
            children.append("{}_{}_{}".format(c["shape"], c["color"], c["size"]))
            known_atoms.add("{}_{}_{}".format(c["shape"], c["color"], c["size"]))
        else:
            child_comp, child_list, known_compositions, known_atoms = symbol_to_prolog_pointer(c, known_compositions,
                                                                                known_atoms)
            out.extend(child_list)
            children.append(child_comp)

    out.insert(0, (known_compositions[str(symbol)], operator, children))

    return known_compositions[str(symbol)], out, known_compositions, known_atoms

def build_problem_aleph_pointer(df: pd.DataFrame, task_id: int) -> (str, str, str):
    known_compositions = {}
    known_atoms = set()

    bg = set()
    pos_examples = set()
    neg_examples = set()
    examples = set()  # Popper-like encoding to use a single compute_metrics function.

    for i in range(len(df)):
        if df.iloc[i]["task_id"] == task_id:
            x = df.iloc[i]

            sample_name = "t{:03d}_s{:06d}".format(df.iloc[i]["task_id"], len(pos_examples) + len(neg_examples))

            if str(x["symbol"]) not in known_compositions:
                known_compositions[str(x["symbol"])] = "c{:06d}".format(len(known_compositions))

            bg.add("sample_is({}, {}).".format(sample_name, known_compositions[str(x["symbol"])]))

            _, children, known_compositions, known_atoms = symbol_to_prolog_pointer(yaml.safe_load(x["symbol"]),
                                                                                known_compositions, known_atoms)

            for comp in children:
                bg.add("defined_as({}, {}, [{}]).".format(comp[0], comp[1],
                                                                  ", ".join([str(c) for c in comp[2]])))
            if x["label"]:
                pos_examples.add("valid({}).".format(sample_name))
                examples.add("pos(valid({})).".format(sample_name))
            else:
                neg_examples.add("valid({}).".format(sample_name))
                examples.add("neg(valid({})).".format(sample_name))

    for a in known_atoms:
        bg.add("atomic_obj({}).".format(a))

    return "\n".join(sorted(list(bg))), "\n".join(sorted(list(pos_examples))), "\n".join(sorted(list(neg_examples))), "\n".join(sorted(list(examples)))

def build_problem_popper_pointer(df: pd.DataFrame, task_id: int) -> (str, str):
    known_compositions = {}
    known_atoms = set()

    bg = set()
    examples = set()

    for i in range(len(df)):
        if df.iloc[i]["task_id"] == task_id:
            x = df.iloc[i]

            sample_name = "t{:03d}_s{:06d}".format(df.iloc[i]["task_id"], len(examples))

            if str(x["symbol"]) not in known_compositions:
                known_compositions[str(x["symbol"])] = "c{:06d}".format(len(known_compositions))

            bg.add("sample_is({}, {}).".format(sample_name, known_compositions[str(x["symbol"])]))

            _, children, known_compositions, known_atoms = symbol_to_prolog_pointer(yaml.safe_load(x["symbol"]),
                                                                                known_compositions, known_atoms)

            for comp in children:
                bg.add("defined_as({}, {}, [{}]).".format(comp[0], comp[1],
                                                                  ", ".join([str(c) for c in comp[2]])))
            examples.add("{}(valid({})).".format(("pos" if x["label"] else "neg"), sample_name))

    for a in known_atoms:
        bg.add("atomic_obj({}).".format(a))

    return "\n".join(sorted(list(bg))), "\n".join(sorted(list(examples)))

def compute_metrics(bg_file: str, theory: dict, examples: str) -> dict:
    metrics = {}
    pl = pyswip.Prolog()

    pl.assertz("tp(N) :- aggregate_all(count, (pos(Y), arg(1, Y, X), distinct(valid(X))), N)")
    pl.assertz("tn(N) :- aggregate_all(count, (neg(Y), arg(1, Y, X), distinct(not(valid(X)))), N)")
    pl.assertz("fp(N) :- aggregate_all(count, (neg(Y), arg(1, Y, X), distinct(valid(X))), N)")
    pl.assertz("fn(N) :- aggregate_all(count, (pos(Y), arg(1, Y, X), distinct(not(valid(X)))), N)")

    for task_id in theory.keys():
        next(pl.query("dynamic(pos/1)"))
        next(pl.query("dynamic(neg/1)"))

        if theory[task_id] is None:
            metrics[task_id] = {"acc": 0.0, "pr": 0.0, "rec": 0.0, "f1": 0.0, "macro_acc": 0.0, "tp": 0, "tn": 0, "fp": 0, "fn": 0}
        else:
            with open(bg_file.format(task_id), "r") as file:
                for r in file.read().split("\n"):
                    if re.match("\w*[a-z]+.*\.$", r):
                        pl.assertz(r.split(".")[0]) # We assert the file line by line, since we cannot retract it later with consult...

            with open(examples.format(task_id)) as file:
                for e in file.read().split("\n"):
                    if re.match("\w*[a-z]+.*\.$", e):
                        pl.assertz(e.split(".")[0])

            for p in theory[task_id].split("."):
                if re.match("\w*[a-z]+.*", p):
                    pl.assertz(p) # TODO: SE i predicati sono multipli fare split su \n?

            out = list(pl.query("tp(TP), tn(TN), fp(FP), fn(FN)", maxresult=1))

            acc = 0.0
            pr = 0.0
            rec = 0.0
            f1 = 0.0
            tp = 0
            tn = 0
            fp = 0
            fn = 0
            macro_acc = 0.0

            if len(out) > 0:
                tp = float(out[0]["TP"])
                tn = float(out[0]["TN"])
                fp = float(out[0]["FP"])
                fn = float(out[0]["FN"])

                if tp + tn + fp + fn > 0:
                    acc = (tp + tn) / (tp + tn + fp + fn)
                if tp + fp > 0:
                    pr = tp / (tp + fp)
                if tp + fn > 0:
                    rec = tp / (tp + fn)
                if tn + fp > 0:
                    fpr = tn / (tn + fp)
                if pr + rec > 0:
                    f1 = 2 * pr * rec / (pr + rec)

                macro_acc = (rec + fpr) / 2

            metrics[task_id] = {"acc": acc, "pr": pr, "rec": rec, "f1": f1, "macro_acc": macro_acc, "tp": tp, "tn": tn, "fp": fp, "fn": fn}

            with open(bg_file.format(task_id), "r") as file:
                for r in file.read().split("\n"):
                    if re.match("\w*[a-z]+.*\.$", r):
                        head = r.split(":-")[0]
                        pred = head.split("(")[0].strip()
                        for arity in range(10):  # Ugly hack to abolish all possible arities...
                            next(pl.query("abolish({}/{})".format(pred, arity)))

            for p in theory[task_id].split("."):
                if re.match("\w*[a-z]+.*", p):
                    head = p.split(":-")[0]
                    pred = head.split("(")[0].strip()
                    for arity in range(10):  # Ugly hack to abolish all possible arities...
                        next(pl.query("abolish({}/{})".format(pred, arity)))

            next(pl.query("abolish(pos/1)"))
            next(pl.query("abolish(neg/1)"))

    return metrics


# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging

import fixtures
from testtools import TestCase
from testtools.matchers import Equals

from snapcraft_legacy.internal import lifecycle, project_loader, states, steps
from snapcraft_legacy.project import Project
from snapcraft_legacy.storeapi.errors import SnapNotFoundError
from snapcraft_legacy.storeapi.info import SnapInfo
from tests.legacy import fixture_setup

class TestGlobalState(TestCase):
    def setUp(self):
        super().setUp()

        self.useFixture(fixtures.FakeLogger(level=logging.ERROR))

        temp_cwd = fixture_setup.TempCWD()
        self.useFixture(temp_cwd)

        snapcraft_yaml = fixture_setup.SnapcraftYaml(
            temp_cwd.path, base="core20", parts={"test-part": {"plugin": "nil"}}
        )
        self.useFixture(snapcraft_yaml)

        project = Project(
            snapcraft_yaml_file_path=snapcraft_yaml.snapcraft_yaml_file_path
        )

        self.global_state_filepath = project._get_global_state_file_path()

        self.project_config = project_loader.load_config(project)

        self.useFixture(
            fixtures.MockPatchObject(
                self.project_config, "get_build_snaps", return_value={"core20"}
            )
        )

        self.useFixture(
            fixtures.MockPatch(
                "snapcraft_legacy.internal.lifecycle._runner._Executor.run"
            )
        )

        self.useFixture(
            fixtures.MockPatch("snapcraft_legacy.internal.repo.snaps.install_snaps")
        )

        # Avoid unnecessary calls to info.
        channel_map = []
        for arch in ("amd64", "i386", "s390x", "arm64", "armhf", "ppc64el"):
            channel_map.append(
                {
                    "channel": {
                        "architecture": arch,
                        "name": "stable",
                        "released-at": "2019-10-15T13:54:06.800280+00:00",
                        "risk": "stable",
                        "track": "latest",
                    },
                    "confinement": "strict",
                    "download": {
                        "deltas": [],
                        "sha3-384": "64d232d6bfa65be14d7f8d84e952d4e372e12021e2c3dbaf70cf2af5e78bf51c4baf9c9107dd6db815064636b781bda6",
                        "size": 57151488,
                        "url": "https://api.snapcraft.io/api/v1/snaps/download/CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6_1223.snap",
                    },
                    "revision": 1223,
                }
            )
        info = {
            "channel-map": channel_map,
            "default-track": None,
            "name": "core20",
            "snap": {
                "name": "core20",
                "publisher": {
                    "display-name": "Canonical",
                    "id": "canonical",
                    "username": "canonical",
                    "validation": "verified",
                },
                "snap-id": "CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6",
            },
            "snap-id": "CSO04Jhav2yK0uz97cr0ipQRyqg0qQL6",
        }
        self.fake_storeapi_get_info = fixtures.MockPatch(
            "snapcraft_legacy.storeapi._snap_api.SnapAPI.get_info",
            return_value=SnapInfo(info),
        )
        self.useFixture(self.fake_storeapi_get_info)

    def test_stable_grade_for_stable_base(self):
        lifecycle.execute(steps.PULL, self.project_config)

        global_state = states.GlobalState.load(filepath=self.global_state_filepath)
        self.assertThat(global_state.get_required_grade(), Equals("stable"))
        self.fake_storeapi_get_info.mock.assert_called_once_with("core20")

    def test_stable_grade_for_non_stable_base(self):
        self.fake_storeapi_get_info.mock.side_effect = SnapNotFoundError(
            snap_name="core20"
        )
        lifecycle.execute(steps.PULL, self.project_config)

        global_state = states.GlobalState.load(filepath=self.global_state_filepath)
        self.assertThat(global_state.get_required_grade(), Equals("devel"))
        self.fake_storeapi_get_info.mock.assert_called_once_with("core20")

    def test_grade_not_queried_for_if_already_set(self):
        # Set the grade
        global_state = states.GlobalState()
        global_state.set_required_grade("devel")
        global_state.save(filepath=self.global_state_filepath)

        lifecycle.execute(steps.PULL, self.project_config)

        self.fake_storeapi_get_info.mock.assert_not_called()


import numpy as np

from common.python.utils import log_utils
from kernel.utils import base_operator

LOGGER = log_utils.get_logger()

def load_data(data_instance):
    X = []
    Y = []
    for iter_key, instant in data_instance:
        weighted_feature = instant.weight * instant.features
        X.append(weighted_feature)
        if instant.label == 1:
            Y.append([1])
        else:
            Y.append([-1])
    X = np.array(X)
    Y = np.array(Y)
    return X, Y

class LogisticGradient(object):

    @staticmethod
    def compute_loss(values, coef, intercept):
        X, Y = load_data(values)
        ywx = np.multiply(-Y.transpose(), X.dot(coef) + intercept).astype(float)
        tot_loss = np.log(1 + np.exp(ywx)).sum()
        return tot_loss

    @staticmethod
    def compute_gradient(values, coef, intercept, fit_intercept):
        X, Y = load_data(values)
        batch_size = len(X)
        if batch_size == 0:
            LOGGER.warning("This partition got 0 data")
            return None
        # [1/(1+e^(-y(wx+b)))-1]*yx
        ywx = -np.multiply(Y.transpose(), X.dot(coef) + intercept).astype(float)
        d = (1.0 / (1 + np.exp(ywx)) - 1).transpose() * Y
        grad_batch = d * X
        if fit_intercept:
            grad_batch = np.c_[grad_batch, d]
        grad = sum(grad_batch)
        return grad

class TaylorLogisticGradient(object):

    @staticmethod
    def compute_gradient(values, coef, intercept, fit_intercept):
        LOGGER.debug("Get in compute_gradient")
        X, Y = load_data(values)
        batch_size = len(X)
        if batch_size == 0:
            return None

        one_d_y = Y.reshape([-1, ])
        d = (0.25 * np.array(base_operator.dot(X, coef) + intercept).transpose() + 0.5 * one_d_y * -1)

        grad_batch = X.transpose() * d
        grad_batch = grad_batch.transpose()
        if fit_intercept:
            grad_batch = np.c_[grad_batch, d]
        grad = sum(grad_batch)
        LOGGER.debug("Finish compute_gradient")
        return grad


from django.shortcuts import get_object_or_404, render
from .models import Product, Brand
from .forms import ProductForm
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
brand = [
    {
        'name': 'vst',
    }
]

def index(request):
    return render(request, "PhoneSaleApp/index.html")

# input: id (param), output: render (request, url, json), JSON: y het model

# chi tiết sản phẩm
def detail(request, product_id):
    pro = Product.objects.get(idProduct = product_id)
    return render(request, "PhoneSaleApp/ProductDetail.html", {"product": pro})

# đăng tải bài đăng mới
def post_product(request):
    if request.method == "GET":
        form = ProductForm()
        context = {"edit": False, "title": "Đăng sản phẩm mới", "button": "Đăng tin"}
        return render(request, "PhoneSaleApp/PostProducts.html", context )
    if request.method == "POST":
        data = {
         "idProduct": request.POST['idProduct'] ,
         "name": request.POST['name'] ,
         "description": request.POST['description'],
         "price": request.POST['price'],
         "numberRemain": request.POST['numberRemain'],
         "avatar": request.FILES['avatar']}
        idBrandProduct = Brand.objects.get(pk=request.POST['brand'])
        pro = Product.objects.create(**data, idBrandProduct = idBrandProduct )
        return render(request, "PhoneSaleApp/index.html")

# update bài đăng
def update_product(request, product_id):
    pro = Product.objects.get(idProduct = product_id)
    if request.method == "GET":
        content = {"edit": True, "title": "Chỉnh sửa bài đăng", "button": "Cập nhập", "product": pro}
        return render(request, "PhoneSaleApp/PostProducts.html", content)
    if request.method == "POST":
        pro.name = request.POST['name']
        pro.description = request.POST['description']
        pro.price = request.POST['price']
        pro.numberRemain = request.POST['numberRemain']
        pro.avatar = request.FILES['avatar']
        pro.idBrandProduct = Brand.objects.get(pk=request.POST['brand'])
        pro.save()
        return render(request, "PhoneSaleApp/index.html")

@csrf_exempt
def delete_product(request, product_id):
    pro = Product.objects.get(idProduct = product_id)
    if request.method == "DELETE":
        pro.delete()
        return JsonResponse({"message":'success'})

# post san pham moi: input: model san pham, output: json{success: true}
# update san pham: input: nhu tren, output nhu tren
# delete: input: id (param), output: json{success: true or false}
# list brand: input: idBrand (param), output: json{model Brand}
# Validation: input: model San Pham, check gia, ten
# gia: >10k, must have, int
# ten san pham: must have >=10 char, unique


import collections

class Solution:
    def minSetSize(self, arr) -> int:
        ## get the occurrence of each character
        mp = collections.Counter(arr)
        ## sort the occurrence and sort by the most frequent element
        ## (alt) mp = [count for _, count in mp.most_common()]
        mp = sorted(list(mp.items()), key=lambda item: item[1], reverse=True)
        target = len(arr)/2
        ## curr stores the current added number, curr_idx stores the number of different elements added on number
        curr, curr_idx = 0, 0
        for num in mp:
            curr += num[1]
            curr_idx += 1
            ## if current number greater than or equal to the half of the length, return the number of different elements
            if curr >= target:
                return curr_idx


from flask import request
from flask_restx import Resource
from backend.main.service.auth_helper import Auth
from backend.main.service.log_service import WriteException
from backend.main.util.dto import AuthDto

api = AuthDto.api
user_auth = AuthDto.user_auth

@api.route('/login')
class UserLogin(Resource):
    """
        User Login Resource
    """

    @api.doc('user login')
    @api.expect(user_auth, validate=True)
    def post(self):
        # get the post data
        try:
            post_data = request.json
            return Auth.login_user(data=post_data)
        except Exception:
            WriteException()
            response_object = {
                'status': 'error',
                'message': 'Algo salio mal, intentalo mas tarde'
            }
            return response_object, 401


from flask import Flask, render_template, request, redirect, url_for
import sqlite3
from flask_sqlalchemy import SQLAlchemy

'''
Red underlines? Install the required packages first:
Open the Terminal in PyCharm (bottom left).

On Windows type:
python -m pip install -r requirements.txt

On MacOS type:
pip3 install -r requirements.txt

This will install the packages from requirements.txt for this project.
'''

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///new-books-collection.db'
db = SQLAlchemy(app)

@app.route('/')
def home():
    all_books = Book.query.all()

    return render_template("index.html",all_books=all_books)

class Book(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(255), nullable=False)
    author = db.Column(db.String(255), nullable=False)
    rating = db.Column(db.Float, nullable=False)

with app.app_context():
    db.create_all()

@app.route("/add", methods=["GET","POST"])
def add():
    if request.method == "POST":
        with app.app_context():
            new_book = Book(title=request.form["title"], author=request.form["author"], rating=request.form["rating"])
            db.session.add(new_book)
            db.session.commit()

        return redirect( url_for('home') )

    return render_template("add.html")

@app.route("/edit/<int:book_id>", methods = ["GET","POST"])
def edit_rating(book_id):
    book = db.get_or_404(Book, book_id)
    if request.method == "POST":
        new_rating = request.form.get("new_rating")
        book.rating = float(new_rating)
        db.session.commit()
        return redirect( url_for("home") )

    return render_template("edit.html",book=book)

@app.route("/delete")
def delete_book():
    book_id = request.args.get("book_id")
    book = db.get_or_404(Book, book_id)

    db.session.delete(book)
    db.session.commit()

    return redirect( url_for("home"))

# Create the database schema within the Flask app context

# Create a new entry in the books table

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


from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken.views import obtain_auth_token
from api import views

router = DefaultRouter()
router.register(r'prog', views.ProgViewSet, basename='prog')
router.register(r'cal', views.CalViewSet, basename='cal')
router.register(r'unlock', views.UnlockViewSet, basename='unlock')
router.register(r'reman/batch', views.RemanBatchViewSet, basename='reman_batch')
router.register(r'reman/checkout', views.RemanCheckOutViewSet, basename='reman_checkout')
router.register(r'reman/repair', views.RemanRepairViewSet, basename='reman_repair')
router.register(r'reman/ecurefbase', views.RemanEcuRefBaseViewSet, basename='reman_ecurefbase')
router.register(r'tools/tc-measure', views.ThermalChamberMeasureViewSet, basename='tools_tc_measure')
router.register(r'tools/bga-time', views.BgaTimeViewSet, basename='tools_bga_time')

app_name = 'api'

urlpatterns = [
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('api-token-auth/', obtain_auth_token, name='token_auth'),
    path('doc/', views.documentation, name='doc'),
    path('nac-license/', views.NacLicenseView.as_view(), name='nac_license')
]


from urllib.request import urlopen
from bs4 import BeautifulSoup
import datetime
import random
import re
import json

random.seed(datetime.datetime.now())

def getLinks(articleUrl):
    try:
        html = urlopen('http://en.wikipedia.org'+articleUrl)
    except:
        return []
    bsObj = BeautifulSoup(html)
    return bsObj.find('div', {'id':'bodyContent'}).find_all('a',
                                                            href=re.compile('^(/wiki/)((?!:).)*$'))

def getHistoryIPs(pageUrl):
    pageUrl = pageUrl.replace('/wiki/', '')
    historyUrl = 'https://en.wikipedia.org/w/index.php?title=' + pageUrl + '&action=history'
    print('history url is: ' + historyUrl)
    try:
        html = urlopen(historyUrl)
    except:
        return set()
    bsObj = BeautifulSoup(html)
    ipAddresses = bsObj.find_all('a', {'class':'mw-anonuserlink'})
    addressList = set()
    for ipAddress in ipAddresses:
        addressList.add(ipAddress.get_text())
    return addressList

def getCountry(ipAddress):
    try:
        response = urlopen('http://freegeoip.net/json/' + ipAddress).read().decode('utf-8')
    except:
        return ''
    responseJson = json.loads(response)
    return responseJson.get('country_code')

if __name__ == '__main__':
    links = getLinks('/wiki/Python_(programming_language)')

    while(len(links) > 0):
        for link in links:
            print('-----------------------------')
            historyIPs = getHistoryIPs(link.attrs['href'])
            for historyIP in historyIPs:
                print(historyIP)
                country = getCountry(historyIP)
                if country != '':
                    print(historyIP + ' is from ' + country)


"""added horse to results

Revision ID: 8555471fb164
Revises: e34e91e9d00d
Create Date: 2019-12-13 09:38:08.700589

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = '8555471fb164'
down_revision = 'e34e91e9d00d'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_foreign_key(None, 'competition_ranking_association', 'rankinglists', ['rankinglist_id'], ['id'])
    op.create_foreign_key(None, 'competition_ranking_association', 'competitions', ['competition_id'], ['id'])
    op.add_column('results', sa.Column('horse_id', sa.Integer(), nullable=False))
    op.create_foreign_key(None, 'results', 'horses', ['horse_id'], ['id'])
    op.create_foreign_key(None, 'results', 'riders', ['rider_id'], ['id'], ondelete='CASCADE')
    op.create_foreign_key(None, 'results', 'tests', ['test_id'], ['id'])
    op.create_foreign_key(None, 'tests', 'competitions', ['competition_id'], ['id'])
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_constraint(None, 'tests', type_='foreignkey')
    op.drop_constraint(None, 'results', type_='foreignkey')
    op.drop_constraint(None, 'results', type_='foreignkey')
    op.drop_constraint(None, 'results', type_='foreignkey')
    op.drop_column('results', 'horse_id')
    op.drop_constraint(None, 'competition_ranking_association', type_='foreignkey')
    op.drop_constraint(None, 'competition_ranking_association', type_='foreignkey')
    # ### end Alembic commands ###


import cv2
import os
import csv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

import keras
import cv2
import re
import pandas as pd
import ntpath
import random

def img_preprocess(img):
    #img = img[60:135,:,:] #Das Bild kann zugeschnitten werden auf einen bestimmten Bereich
    img = cv2.cvtColor(img, cv2.COLOR_RGB2YUV) #colormap für NVIDIA-Model
    #img = cv2.GaussianBlur(img,  (3, 3), 0) #Blur um Bild zu smoothen
    img = cv2.resize(img, (100, 100)) #Auf richtige Größe für Model bringen
    img = img/255 #Bild normalisieren
    return img

print("start")

# print(len(im))
# print(len(im[0]))
# print(len(im[0][0]))
# print(len(im[0][0][0]))

model = keras.models.load_model("model.h5")

print(model.layers[0].input_shape)
print(model.summary())

dirname = os.path.dirname(__file__)
imagepath = dirname + "/daten/img"
images = os.listdir(imagepath)
print(images)
images.sort(key=lambda f: int(re.sub('\D', '', f)))
print(images)
true_data = np.genfromtxt(("daten/data.csv"), delimiter=',')    # alte csv in Array lesen
true_data = np.delete(true_data, 0, axis=0)     # labels entfernen

steering_plot = []
throttle_plot = []

counter = 0
for image in images:
    im = mpimg.imread("daten/img/" + image)

    im = img_preprocess(im)

    # plt.imshow(im)
    # plt.show()

    im = np.expand_dims(im, axis=0)

    model_output = model.predict(im)

    steering_value = model_output[0][0]
    steering_plot.append(steering_value)
    try:
        print("Image:", image, "steering value:", steering_value, ", true value: ", true_data[counter][3])
        throttle_plot.append(true_data[counter][3])
    except IndexError:
        pass
    counter += 1

plt.plot(steering_plot)
plt.plot(throttle_plot)
plt.legend(["model", "true"])
#plt.plot(throttle_plot)
plt.show()

print("end")


import pandas as pd
import sqlite3

conn = sqlite3.connect('parser.sqlite')
cur = conn.cursor()

df = pd.read_excel('test_task.xlsx')

df = df.drop(labels=[0, 1])
df = df.rename(columns={
    'fact': 'data1(Qliq(fact))',
    'Unnamed: 3': 'data2(Qliq(fact))',
    'Unnamed: 4': 'data1(Qoil(fact))',
    'Unnamed: 5': 'data2(Qoil(fact))',
    'forecast': 'data1(Qliq(forecast))',
    'Unnamed: 7': 'data2(Qliq(forecast))',
    'Unnamed: 8': 'data1(Qoil(forecast))',
    'Unnamed: 9': 'data2(Qoil(forecast))'
})

df.to_sql(name='Table1', con=conn, index=False)


from django.shortcuts import render, reverse
import requests
import json
from django.contrib import messages
from calendar import HTMLCalendar
from datetime import datetime
from django.urls import reverse_lazy
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.views import View
from django.http import HttpResponseRedirect
from django.views.generic.list import ListView

from .models import TimeTable, UserProfile, Comment, Course, Friends

from collections import OrderedDict
import copy

# Create your views here.

# Landing Page
# def index(request):
#    return render(request, 'index.html')

def home(request):
   return render(request,'home.html')

def searchClasses(request):
   response_API = requests.get('http://luthers-list.herokuapp.com/api/dept/CS/')
   data = response_API.text
   classes = json.loads(data)
   return render(request, 'searchClasses.html', {'classes': classes})

def searchPage(request):
   return render(request,'searchPage.html')

def classList(request):
   try:
      department = request.POST['department']
   except:
      department = None
      messages.add_message(request, messages.ERROR, 'Please enter subject')   # adds error message banner
      return render(request, 'searchPage.html')
   try:
      catalog_num = request.POST['catalog_num']
   except:
      catalog_num = None
   try:
      days_held = request.POST.getlist('days_held')
   except:
      days_held = None
   try:
      class_type = request.POST['grad_filter']
   except:
      class_type = None
   # edit input data
   days_final = ""
   for each in days_held:
      days_final += each

   try:
      response_API = requests.get('http://luthers-list.herokuapp.com/api/dept/'+department)
      data = response_API.text
      classes = json.loads(data)
   #print(response_API.status_code)
   except:
      messages.add_message(request, messages.ERROR, 'Please enter subject')   # adds error message banner
      return render(request, 'searchPage.html')
   #print(classes[0]['description'])

   # edit meeting date/time info so it's easier to work with
   for i in range(len(classes)):

      meeting_data = ""

      if (len(classes[i]['meetings']) == 0):
         meeting_data = ""
         days = ""
         classes[i]['meetings'] = {'days': "", 'times': "", 'facility_description': ""}

      else:
         meet = classes[i]['meetings'][0]
         # filter for days here
         facility = meet['facility_description']
         if meet['start_time']:

            # reformat start/end times
            datetime_start = datetime.strptime(meet['start_time'].split('-')[0], '%H.%M.%S.%f')
            start_time = datetime_start.strftime("%I:%M%p")   # converts back to string

            datetime_end = datetime.strptime(meet['end_time'].split('-')[0], '%H.%M.%S.%f')
            end_time = datetime_end.strftime("%I:%M%p")   # converts back to string

            # add to meeting data
            meeting_data = start_time + "-" + end_time

         # update data
         classes[i]['meetings'] = {'days' : meet['days'], 'times': meeting_data,'facility_description' : facility}

   # restructure data: dictionary such that each course code is grouped together
   # also filtering data
   all_classes = {}
   for course in classes:
      if not class_type or (class_type == 'both') or (class_type == 'undergrad' and int(course['catalog_number']) < 5000) or (class_type == 'grad' and int(course['catalog_number']) >= 5000):
         if (not catalog_num or course['catalog_number'] == catalog_num) and (not days_final or course['meetings']['days'] == days_final):
            code = course['subject'] + " " + course['catalog_number'] + ": " + course['description']  # this will be the key
            if code in all_classes:
               all_classes[code].append(course)
            else:
               all_classes[code] = [course]
   # adding "no search results found" error
   """
   Found code to redirect to current page as this can happen with browser bars or the search page.
   Title: Redirect To Previous Page Django With Code Examples
   Link: https://www.folkstalk.com/tech/redirect-to-previous-page-django-with-code-examples/
   """
   if len(all_classes) == 0:
      messages.add_message(request, messages.ERROR, 'No search results found!')   # adds error message banner
      return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
      # except:   # in case of bug
      #    messages.add_message(request, messages.ERROR, 'No search results found!')   # adds error message banner
      #    return render(request, 'searchPage.html')

   return render(request, 'classList.html', {'classes': all_classes})

class TimeTableView(LoginRequiredMixin, View):
   def get(self, request):
      profile = UserProfile.objects.get(pk=request.user.id)
      # timetables = TimeTable.objects.get(pk=pk)
      user = profile.user
      timetable = TimeTable.objects.get(author=user)

      my_classes = OrderedDict()   # maintains order
      my_classes['Monday'] = []
      my_classes['Tuesday'] = []
      my_classes['Wednesday'] = []
      my_classes['Thursday'] = []
      my_classes['Friday'] = []
      for each in timetable.courses.all():
         if 'Mo' in each.days:
            my_classes['Monday'].append(each)
         if 'Tu' in each.days:
            my_classes['Tuesday'].append(each)
         if 'We' in each.days:
            my_classes['Wednesday'].append(each)
         if 'Th' in each.days:
            my_classes['Thursday'].append(each)
         if 'Fr' in each.days:
            my_classes['Friday'].append(each)

      # order classes in order of time
      for date in my_classes.keys():
         time_course = []
         for course in my_classes[date]:
            temp = int(course.times.split(':')[0])
            if 'PM' in course.times.split(':')[1] and temp != 12:
               temp += 12
            if len(time_course) == 0:
               time_course.append([temp, course])
            else:
               if temp < time_course[0][0]:   # this would mean it's the earliest
                  time_course.insert(0, [temp, course])
               elif temp > time_course[-1][0]:   # this would mean it's the last one
                  time_course.append([temp, course])
               else:   # means it's somewhere in the middle
                  for i in range(len(time_course)-1):
                     if temp > time_course[i][0] and temp < time_course[i+1][0]:
                        time_course.insert(i+1, [temp, course])
         final_order = []
         for each in time_course:
            final_order.append(each[1])
         my_classes[date] = final_order

      comments = timetable.post_comments.all()

      context = {
         'user' : user,
         'timetable': timetable,
         'courses': my_classes,
         'comments': comments,
      }

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

   def post(self, request):
      """
      Method that posts course information to timetable database; upon completion, should redirect to schedule
      (TODO: later, make method stay on classList page but with some indication that the course was added to the user's schedule)
      """
      profile = UserProfile.objects.get(pk=request.user.id)
      # timetables = TimeTable.objects.get(pk=pk)
      user = profile.user
      timetable = TimeTable.objects.get(author=user)

      if request.method == 'POST':
         # for comment responses/posting
         try:
            comment_post = request.POST['posted_comment']
            if comment_post == "" or comment_post == " ":
               messages.add_message(request, messages.ERROR, 'No comment entered!')   # adds error message banner
            else:
               # create new comment
               new_comment = Comment()
               new_comment.author = user
               new_comment.associated_schedule = timetable
               new_comment.comment_text = comment_post
               # did it get saved?
               new_comment.save()

         except KeyError:   # if not adding a comment
            name = request.POST['course_name']
            section = request.POST['course_section']

            try:   # ----- deleting a course -----
               remove = request.POST['delete_bool']
               timetable.courses.filter(name=name, section=section).delete()
               #to_delete.delete()
               #timetable.save()
            except:   # ----- adding a course -----
               try:
                  topic = request.POST['course_topic']
               except:
                  topic = None
               days = request.POST['days']
               times = request.POST['times']

               # add functionality that checks whether course is compatible with other courses
               does_not_conflict = True
               for each in timetable.courses.all():
                  # first, check for duplicates
                  if name == each.name:
                     if each.topic == "" and topic == None:   # should allow adding when special topic!
                        does_not_conflict = False
                        break

                  # next, check day/time
                  if days == each.days:   # top-down
                     # change time formatting for new class
                     new_times_list = times.split('-')   # splits from e.g. "5:00PM - 6:15PM" to ["5:00", "-", "6:00"]
                     new_times_list = [new_times_list[0], new_times_list[1]]   # keep only times
                     new_times = []
                     for i in new_times_list:
                        new_times.append(datetime.strptime(i, "%H:%S%p").time())

                     # change time formatting for old class
                     other_times_list = each.times.split('-')   # splits from e.g. "5:00PM - 6:15PM" to ["5:00", "-", "6:00"]
                     other_times_list = [other_times_list[0], other_times_list[1]]   # keep only times
                     other_times = []
                     for i in other_times_list:
                        other_times.append(datetime.strptime(i, "%H:%S%p").time())

                     # --- make time comparisons ---
                     # bad case: classes at same time
                     if new_times[0] == other_times[0] and new_times[1] == other_times[1]:
                        does_not_conflict = False
                        break
                     # bad case: overlapping new end to old beginning
                     elif new_times[0] <= other_times[0] and new_times[1] >= other_times[0]:
                        does_not_conflict = False
                        break
                     # another bad case: overlapping new beginning and old end
                     elif new_times[0] <= other_times[1] and new_times[1] >= other_times[1]:
                        does_not_conflict = False
                        break

               if does_not_conflict:
                  new_class = Course(timetable=timetable)
                  new_class.name = name
                  new_class.section = section
                  if topic != None:
                     new_class.topic = topic
                  new_class.component = request.POST['course_component']
                  new_class.units = request.POST['course_units']
                  new_class.instructor = request.POST['course_instructor']
                  new_class.days = days
                  new_class.times = times
                  new_class.location = request.POST['location']

                  new_class.save()

               else:
                  messages.add_message(request, messages.ERROR, 'Class is a duplicate or conflicts with an existing class time.')   # adds error message banner
                  return render(request, 'searchPage.html')   # update this to actually stay on classList

         # create usable course data structure for visualization on page (sort by key Mo/Tu/We/Th/Fr)
         my_classes = OrderedDict()   # maintains order
         my_classes['Monday'] = []
         my_classes['Tuesday'] = []
         my_classes['Wednesday'] = []
         my_classes['Thursday'] = []
         my_classes['Friday'] = []
         for each in timetable.courses.all():
            # debugging
            if 'Mo' in each.days:
               my_classes['Monday'].append(each)
            if 'Tu' in each.days:
               my_classes['Tuesday'].append(each)
            if 'We' in each.days:
               my_classes['Wednesday'].append(each)
            if 'Th' in each.days:
               my_classes['Thursday'].append(each)
            if 'Fr' in each.days:
               my_classes['Friday'].append(each)

         # order classes in order of time
         for date in my_classes.keys():
            time_course = []
            for course in my_classes[date]:
               temp = int(course.times.split(':')[0])
               if 'PM' in course.times.split(':')[1] and temp != 12:
                  temp += 12
               if len(time_course) == 0:
                  time_course.append([temp, course])
               else:
                  if temp < time_course[0][0]:   # this would mean it's the earliest
                     time_course.insert(0, [temp, course])
                  elif temp > time_course[-1][0]:   # this would mean it's the last one
                     time_course.append([temp, course])
                  else:   # means it's somewhere in the middle
                     for i in range(len(time_course)-1):
                        if temp > time_course[i][0] and temp < time_course[i+1][0]:
                           time_course.insert(i+1, [temp, course])
            final_order = []
            for each in time_course:
               final_order.append(each[1])
            my_classes[date] = final_order

         comments = timetable.post_comments.all()

         context = {
            'user' : user,
            'timetable': timetable,
            'courses': my_classes,
            'comments': comments
         }

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

# def scheduler(request):
#    list_of_TimeTables = TimeTable.objects.get(user_id = 1010)
#    return render(request,'schedule.html',
#       {'user_TimeTable':list_of_TimeTables})

#####

def FriendsTimeTableView(request):
   # profile = UserProfile.objects.get(pk=request.user.id)
   # timetables = TimeTable.objects.get(pk=pk)
   # user = profile.user

   if request.method == 'POST':
      # functionality for adding a comment
      current_user = request.user
      friend = request.POST['friend_username']
      # can do this with user.id or userprofile.id
      friend_profile = UserProfile.objects.get(name=friend)
      # print(friend)
      timetable = TimeTable.objects.get(author=friend_profile.user)
      try:
         comment_post = request.POST['posted_comment']
         if comment_post == "" or comment_post == " ":
            messages.add_message(request, messages.ERROR, 'No comment entered!')   # adds error message banner
         else:
            # create new comment
            new_comment = Comment()
            new_comment.author = current_user
            new_comment.associated_schedule = timetable
            new_comment.comment_text = comment_post
            # did it get saved?
            new_comment.save()

      except KeyError:
         new_comment = None   # basically just a throwaway assignment if just getting page; no comment yet

      # timetable = TimeTable.objects.get(author = index)
      # timetable = TimeTable.objects.get(author = friend)

      # need to compare author and friend to get the correct instance of TimeTable. author requires id, but friend is the value of that id.
      # timetables = TimeTable.objects.all()
      # timetable <-- author == friend

      my_classes = OrderedDict()   # maintains order
      my_classes['Monday'] = []
      my_classes['Tuesday'] = []
      my_classes['Wednesday'] = []
      my_classes['Thursday'] = []
      my_classes['Friday'] = []
      for each in timetable.courses.all():
         if 'Mo' in each.days:
            my_classes['Monday'].append(each)
         if 'Tu' in each.days:
            my_classes['Tuesday'].append(each)
         if 'We' in each.days:
            my_classes['Wednesday'].append(each)
         if 'Th' in each.days:
            my_classes['Thursday'].append(each)
         if 'Fr' in each.days:
            my_classes['Friday'].append(each)

      # order classes in order of time
      for date in my_classes.keys():
         time_course = []
         for course in my_classes[date]:
            temp = int(course.times.split(':')[0])
            if 'PM' in course.times.split(':')[1] and temp != 12:
               temp += 12
            if len(time_course) == 0:
               time_course.append([temp, course])
            else:
               if temp < time_course[0][0]:   # this would mean it's the earliest
                  time_course.insert(0, [temp, course])
               elif temp > time_course[-1][0]:   # this would mean it's the last one
                  time_course.append([temp, course])
               else:   # means it's somewhere in the middle
                  for i in range(len(time_course)-1):
                     if temp > time_course[i][0] and temp < time_course[i+1][0]:
                        time_course.insert(i+1, [temp, course])
         final_order = []
         for each in time_course:
            final_order.append(each[1])
         my_classes[date] = final_order

      # get comments on post
      comments = timetable.post_comments.all()

   context = {
      'timetable': timetable,
      'friend': friend,
      'courses': my_classes,
      'comments': comments,
   }

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

#####
def social(request):
   userList = UserProfile.objects.all()
   me = UserProfile.objects.get(pk=request.user.id)
   friendslist = [profile.friend_profile for profile in me.following.all() if profile != me]
   # default filtering
   filters = {'major':'', 'minor':'', 'year':''}
   # make sure we aren't including admin in friending options; throws errors
   real_userList = []
   for profile in userList:
      if not profile.user.is_staff and profile != me and profile not in friendslist:
         real_userList.append(profile)

   if request.method == 'POST':
      user_id = me
      # ---- FOR ADDING A NEW FRIEND -----
      try:
         friends_name = request.POST['friend_search']
         # check for blank user
         if request.POST['friend_search'] == '':
            messages.add_message(request, messages.ERROR, 'You have added all available friends!')   # adds warning banner
            return render(request,'friends.html', {'userList': real_userList, 'friendslist': friendslist, 'me': me, 'filters':filters})

         temp = UserProfile.objects.get(name=friends_name)
         friends_id = str(temp.user_id)
         new_follower = Friends.objects.create(user_id=user_id, friend_profile=temp, friends_id=friends_id, friend_username=friends_name)
         new_follower.save()
         friendslist.append(new_follower.friend_profile)
         real_userList.remove(new_follower.friend_profile)

      # ----- FOR FILTERING RESULTS -----
      except:

         # ----- FOR FILTERING RESULTS -----
         # update filters
         filters['major'] = request.POST['major']
         filters['minor'] = request.POST['minor']
         filters['year'] = request.POST['year']
         # update friendslist to display those filtered
         if filters['major'] == '' and filters['minor'] == '' and filters['year'] == '':
               messages.add_message(request, messages.INFO, 'An empty search will display all friends.')   # adds info message banner
         else:
            templist = copy.deepcopy(friendslist)
            for friend in friendslist:
               if friend.major != None:   # had to do this check to prevent errors
                  if friend.major.lower() != filters['major'].lower() and filters['major'] != '':   # used .lower() to reduce input issues (e.g. someone used lowercase or upper-case)
                     templist.remove(friend)
                     continue
               elif filters['major'] != '':
                  templist.remove(friend)
                  continue
               if friend.minor != None:   # had to do this check to prevent errors
                  if friend.minor.lower() != filters['minor'].lower() and filters['minor'] != '':   # used .lower() to reduce input issues (e.g. someone used lowercase or upper-case)
                     templist.remove(friend)
                     continue
               elif filters['minor'] != '':
                  templist.remove(friend)
                  continue
               if friend.year != filters['year'] and filters['year'] != '':
                  templist.remove(friend)
            friendslist = templist

   return render(request,'friends.html', {'userList': real_userList, 'friendslist': friendslist, 'me': me, 'filters':filters})

def myInfo(request):
   profile = UserProfile.objects.get(user=request.user.id)
   if request.method == 'POST':
      # option for empty input:
      if request.POST['year'] == '' and request.POST['major'] == '' and request.POST['minor'] == '' and request.POST['bio'] == '':
         messages.add_message(request, messages.ERROR, 'Empty input: If updating, please enter items into an input field.')   # adds error message banner
         personal_info = {'year': profile.year, 'major': profile.major, 'minor': profile.minor, 'bio': profile.bio }
         return render(request, 'my_information.html', {'personal_info': personal_info} )

      if request.POST['year'] != "":
         profile.year = request.POST['year']
      if request.POST['major'] != "":
         profile.major = request.POST['major']
      if request.POST['minor'] != "":
         profile.minor = request.POST['minor']
      if request.POST['bio'] != "":
         profile.bio = request.POST['bio']
      profile.save()

   personal_info = {'year': profile.year, 'major': profile.major, 'minor': profile.minor, 'bio': profile.bio }
   return render(request, 'my_information.html', {'personal_info': personal_info} )


# -*- coding: utf-8 -*-
"""
Created on Fri Jan  6 15:09:53 2023

@author: srpv
"""

import math
import torch
import torch.nn as nn
import torch.nn.functional as F

class PrintLayer(torch.nn.Module):
    def __init__(self):
        super(PrintLayer, self).__init__()

    def forward(self, x):
        # Do your print / debug stuff here
        # print(x.shape)
        return x

class CNN(nn.Module):
    def __init__(self,feature_size=64):
        super(CNN, self).__init__()
        self.feature_size = feature_size
        self.dropout=0.05
        self.conv1 = nn.Sequential(
            nn.Conv1d(in_channels=7, out_channels=4, kernel_size=16, bias=False),
            nn.BatchNorm1d(4),
            nn.ReLU(),
            nn.Dropout(self.dropout),
            nn.MaxPool1d(3),
            PrintLayer())

        self.conv2 = nn.Sequential(
            nn.Conv1d(in_channels=4, out_channels=8, kernel_size=16, bias=False),
            nn.BatchNorm1d(8),
            nn.ReLU(),
            nn.Dropout(self.dropout),
            nn.MaxPool1d(3),
            PrintLayer())

        self.conv3 = nn.Sequential(
            nn.Conv1d(in_channels=8, out_channels=16, kernel_size=16, bias=False),
            nn.BatchNorm1d(16),
            nn.ReLU(),
            nn.Dropout(self.dropout),
            nn.MaxPool1d(3),
            PrintLayer())

        self.conv4 = nn.Sequential(
            nn.Conv1d(in_channels=16, out_channels=32, kernel_size=16, bias=False),
            nn.BatchNorm1d(32),
            nn.ReLU(),
            nn.Dropout(self.dropout),
            nn.MaxPool1d(3),
            PrintLayer())

        self.conv5 = nn.Sequential(
            nn.Conv1d(in_channels=32, out_channels=64, kernel_size=16, bias=False),
            nn.BatchNorm1d(64),
            nn.ReLU(),
            # nn.Dropout(self.dropout),
            # nn.MaxPool1d(3),
            torch.nn.AdaptiveAvgPool1d(1),
            PrintLayer())

    def forward(self, x):

        x = self.conv1 (x)
        x = self.conv2 (x)
        x = self.conv3 (x)
        x = self.conv4 (x)
        x = self.conv5 (x)

        x= x.view(x.size(0), -1)

        return x

class LinearNetwork(nn.Module):
    def __init__(self,nb_class,feature):
        super(LinearNetwork, self).__init__()
        self.feature = feature
        self.nb_class=nb_class

        self.fc1=nn.Linear(64, 32)
        self.fc2=nn.Linear(32, 3)

        self.conv1 = nn.Sequential(
            nn.ReLU(),
           )

    def forward(self, x):

        x=self.fc1(x)
        x = self.conv1(x)
        x=self.fc2(x)

        return x


import json

class JsonToCsvScript:
    output_fp = 'converted_nfts_records.csv'

    data = json.loads(open('metadata.json', encoding='utf-8').read())

    csv_headers = [
        "name", "description", "image", "trait_background", "trait_base_character",
        "trait_clothing", "trait_expression", "trait_accessories"
    ]

    def __init__(self):
        self.csv_writer = self.get_csv_writer()
        self.parse_json_files()

    def parse_json_files(self):
        for rec in self.data["collection"]:
            item = {}
            item["name"] = rec['name'].replace('#', 'GGoose ')
            item["description"] = rec['description']
            item["image"] = rec['image']

            for attr in rec['attributes'] or []:
                if attr['trait_type'] == 'Background':
                    item["trait_background"] = attr['value']
                elif attr['trait_type'] == 'Base Character':
                    item["trait_base_character"] = attr['value']
                elif attr['trait_type'] == 'Clothing':
                    item["trait_clothing"] = attr['value']
                elif attr['trait_type'] == 'Expression':
                    item["trait_expression"] = attr['value']
                elif attr['trait_type'] == 'Accessories':
                    item["trait_accessories"] = attr['value']

            self.write_to_csv(item)

    def write_to_csv(self, item):
        row = ','.join('"{}"'.format(item.get(h) or '') for h in self.csv_headers) + '\n'
        self.csv_writer.write(row)
        print("Record inserted into CSV file.")
        print(item)

    def get_csv_writer(self):
        file = open(self.output_fp, mode='w', encoding='utf-8')
        file.write(','.join(h for h in self.csv_headers) + '\n')
        return file

if __name__ == "__main__":
    JsonToCsvScript()


import tornado.ioloop
import os.path

import tornado.web

from blackwidow import config

PARENT_DIR = os.path.abspath(os.path.dirname(__file__))
STATIC_DIR = os.path.join(PARENT_DIR, 'static')
HTML_FILE = os.path.join(STATIC_DIR, 'graph.html')

class MainHandler(tornado.web.RequestHandler):

    def get(self):
        self.render(HTML_FILE)

class DataHandler(tornado.web.RequestHandler):

    def get(self):
        self.write(self.json_data)

application = tornado.web.Application([
    (r"/", MainHandler),
    (r"/json", DataHandler)
], static_path=STATIC_DIR)

def serve(data, port=None):
    """
    Render graph visualization
    """
    DataHandler.json_data = data
    application.listen(port or config.PORT)
    print("Navigate to http://localhost:%d/ to view the package graph" % config.PORT)
    tornado.ioloop.IOLoop.current().start()


# Run this app with `python app.py` and
# visit http://127.0.0.1:8050/ in your web browser.
import dash_bootstrap_components as dbc
import os
import psycopg2
from dash import Dash, callback, html
from whitenoise import WhiteNoise
from components.header_footer import generate_header, generate_footer
from components.figures import (
    generate_overall_handover_status_pie,
    generate_per_subcomplex_handover_status_pie,
    generate_sample_bar_chart,
    generate_table
)

app = Dash(__name__, external_stylesheets=[dbc.themes.FLATLY])

server = app.server
server.wsgi_app = WhiteNoise(server.wsgi_app, root='static/')

DATABASE_URL = os.environ['DATABASE_URL']
if 'postgresql' not in DATABASE_URL:
        DATABASE_URL = DATABASE_URL.replace('postgres', 'postgresql')

conn = psycopg2.connect(DATABASE_URL, sslmode='require')
# conn = psycopg2.connect(DATABASE_URL)

def create_dash_layout(app):
    colors = {
        'background': '#111111',
        'text': '#7FDBFF'
    }

    table_style = {
        'header': {
            'backgroundColor': 'rgb(30, 30, 30)',
            'color': 'white'
        },
        'data': {
            'backgroundColor': 'rgb(50, 50, 50)',
            'color': 'white',
            'whiteSpace': 'normal',
            'height': 'auto',
            'lineHeight': '15px'
        },
        'label': {
            'textAlign': 'center',
            'color': colors['text']
        }
    }

    # Set browser tab title
    app.title = "Cendana Peak Statistics"

    # Header
    header = html.Div(style={'textAlign': 'center', 'color': colors['text']}, children=generate_header())

    # Body
    body = html.Div([
        generate_overall_handover_status_pie(conn, colors),
        generate_per_subcomplex_handover_status_pie(conn, colors),
        generate_table(table_style, conn)
    ])

    # Footer
    footer = html.Div(style={'textAlign': 'center', 'color': colors['text']}, children=generate_footer())

    # Assemble dash layout
    app.layout = html.Div(style={'textAlign': 'center', 'backgroundColor': colors['background']}, children=[header, body, footer])

    return app

create_dash_layout(app)

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


import os
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras import layers
from tensorflow.keras.layers import Dense, Input, InputLayer, Flatten, Conv2D, BatchNormalization, MaxPooling2D, Activation , GlobalAveragePooling2D
from tensorflow.keras.models import Sequential,  Model
import tensorflow.keras.backend as K
import wandb
import tensorflow as tf
from tensorflow import keras
from sklearn import metrics
import pandas as pd
import cv2
from wandb.keras import WandbCallback
import pathlib
import seaborn as sns
from CNN_model import*
from get_data import*
from paths import*

# input image dimensions that we are using for the following task
img_size = (128,128)

'''
Sweep config for the hyperparameter tuning
'''
sweep_config = {
  "name": "Bayesian Sweep",
  "method": "bayes",
  "metric":{
  "name": "val_accuracy", # optimizing wrt to maximizing the validation accuracy
  "goal": "maximize"
  },
  "parameters": {

        "activation":{
            "values": ["relu"]
        },
        "filter_size": {
            "values": [(2,2), (3,3), (4,4)]
        },
        "batch_size": {
            "values": [32, 64]
        },
        "padding": {
            "values": ["same","valid"]
        },
        "data_augmentation": {
            "values": [True, False]
        },
        "optimizer": {
            "values": ["adam", "sgd", "rmsprop"]
        },
        "batch_normalization": {
            "values": [True, False]
        },
        "batchnorm_location": {
            "values": ["After", "Before"]
        },
        "num_filters": {
            "values": [32,64, 128]
        },
        "dense_neurons": {
            "values": [64, 128, 256]
        },
        "dropout_loc": {
            "values": ["conv","dense","all"]
        },
        "dropout": {
            "values": [None, 0.2,0.3]
        },
        "gap": {
            "values": [False,True]
        },
        "filter_multiplier": {
            "values": ["standard","half","double"]
        },
    }
}

'''
Initializing the wandb sweeps for tuning
'''
sweep_id = wandb.sweep(sweep_config,project=project_name, entity=entity_name)

'''
Training function for sweeping and hyperparameter tuning
'''
def train():
    #project name for wandb initialization
    project_name = 'CS6910-Assignment2-PartA_final'
    # model save path location
    model_save_path = "./TrainedModel/"
    img_size=(128,128)
    #config default values for sweeping and values with only one value.
    config_defaults = dict(
            num_hidden_cnn_layer = 5 ,
            activation = 'relu',
            batch_normalization = True,
            batchnorm_location = "After",
            filter_multiplier = "double" ,
            filter_size = (3,3),
            num_filters  = 32,
            dropout = None,
            dropout_loc = "dense",
            pool_size = (2,2),
            padding = 'same',
            dense_neurons = 128,
            num_classes = 10,
            optimizer = 'adam',
            epochs = 7,
            batch_size = 32,
            data_augmentation = False,
            gap = True,
            img_size = img_size
        )

    # Initializing the wandb with project name and entity name
    wandb.init(project = project_name, config = config_defaults,entity=entity_name)
    CONFIG = wandb.config

    # Naming convention fo the wandb runs
    wandb.run.name = "Image_recog" + str(CONFIG.num_hidden_cnn_layer) + "_dn_" + str(CONFIG.dense_neurons) + "_opt_" + CONFIG.optimizer + "_dro_" + str(CONFIG.dropout) + "_bs_"+str(CONFIG.batch_size) + "_fm_" + CONFIG.filter_multiplier + "_bnl_" + CONFIG.batchnorm_location + "_dpl_" + CONFIG.dropout_loc

    with tf.device('/device:GPU:0'):
        # Create object of the CNN model class
        imageRecog = cnnModel(CONFIG.img_size, CONFIG, 10)
        # Build the model
        model = imageRecog.build_cnnmodel()

        # Printing the model summary
        model.summary()

        # Reading the data
        train_generator,validation_generator = get_data(CONFIG.batch_size,CONFIG.data_augmentation,train_data_path)

        # Model compilation
        model.compile(
        optimizer=CONFIG.optimizer,  # Optimizer
        # Loss function to minimize (categorial classification for multiclass classification)
        loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
        # Monitoring accuracy
        metrics=['accuracy'],
        )
        # Model fit for training
        history = model.fit(
                        train_generator,
                        steps_per_epoch = train_generator.samples // CONFIG.batch_size,
                        validation_data = validation_generator,
                        validation_steps = validation_generator.samples // CONFIG.batch_size,
                        epochs = CONFIG.epochs,
                        callbacks=[WandbCallback()]
                        )

        # Save the models in the follwoing path
        model.save(model_save_path+wandb.run.name)
        wandb.finish()
        # Returning the model and the history
        return model, history

wandb.agent(sweep_id, train, count = 30)


import photo1
import photo2
import photo3
import streamlit as st
import json
import requests
from streamlit_lottie import st_lottie
st.set_page_config(page_title='Image Edit and Collage Maker')

st.title("** Image Editing and Collage maker **")
st.markdown("** 19BCE1242 Aritra Basu**")
def load_lottieurl(url: str):
    r = requests.get(url)
    if r.status_code != 200:
        return None
    return r.json()

lottie_hello = load_lottieurl("https://assets8.lottiefiles.com/packages/lf20_cznnfmoz.json")
st_lottie(
    lottie_hello,
    speed=1,
    reverse=False,
    loop=True,
    quality="low", # medium ; high
    renderer="svg", # canvas
    height=None,
    width=None,
    key=None,
)
f1 = st.file_uploader("Upload Your Image ",type=["jpg","png","jpeg"])
PAGES = {

    "Blur your image background": photo1,
    "Black and white image background": photo2,
    "Making your own collage":photo3

}

st.markdown('***')
value = st.selectbox("Select a Functionality", options=list(PAGES.keys()))
page = PAGES[value]

if value == "Blur your image background":
    page.app1(f1)
elif value == "Black and white image background":
    page.app2(f1)
elif value == "Making your own collage":
    page.app3(f1)


#!/usr/bin/python3

import os
import discord
import typing # C'est pour si on veut faire des argument non obligatoire
import asyncio
from datetime import datetime
import datetime as dt
from random import random, choice

from discord.ext import commands

from functions import *

from dotenv import load_dotenv

load_dotenv()

TOKEN = os.environ['DISCORD_TOKEN']
GUILD = os.environ['DISCORD_GUILD']
CHANNEL = int(os.environ['DISCORD_CHANNEL'])

intents = discord.Intents.default()
intents.messages = True
intents.message_content = True

bot = commands.Bot(command_prefix='!', intents=intents)

tgGifs = ["https://tenor.com/view/lotr-ring-no-isildur-lord-of-the-rings-gif-5743603", "https://tenor.com/view/no-bugs-bunny-nope-gif-14359850", "https://tenor.com/view/cdi-super-mario-no-turn-around-gif-13643447", "https://tenor.com/view/ohhh-whoah-gif-14206432", "https://tenor.com/view/antm-americas-next-top-model-miss-j-j-alexander-omg-gif-3720930", "https://tenor.com/view/anime-punch-fight-slam-wall-gif-5012110", "https://tenor.com/view/cheh-sheh-orge-sumerien-gif-20238938", "https://tenor.com/view/cat-cats-cat-reaction-cat-react-cat-what-gif-17596807", "https://tenor.com/view/umm-confused-blinking-okay-white-guy-blinking-gif-7513882", "https://tenor.com/view/pedro-monkey-puppet-meme-awkward-gif-15268759", "https://tenor.com/view/vieux-old-man-gif-20005208", "https://tenor.com/view/ferme-ta-gueule-ta-gueule-ferme-la-ftg-tg-gif-5034362", "https://tenor.com/view/my-hero-acadamia-deku-excited-head-desk-wiggling-gif-5497470"]

alerteSemainePro = ["4:18:30", "5:12:0", "6:18:30"]
alerteDemain = ["0:18:30", "1:18:30", "2:18:30", "3:18:30"]
alerteAujourdhui = ["0:8:0", "1:8:0", "2:8:0", "3:8:0", "4:8:0", "5:8:0"]

# Gestion des bans de la commande
def bannedList(ctx):
    for role in ctx.author.roles:
        if role.id == 885425513865306112:
            return False
    return True

# Coroutine appelé après chaque commandes (permet ici de supprimer le message de commande sauf pour les commandes add, rm et ping)
@bot.after_invoke
async def after_invoke_cmd(ctx):
    if(ctx.command.name not in ["add", "md", "rm", "ping", "extract"]):
        await ctx.message.delete()

# ========================================================
# Test du ping pong
@bot.command(name='ping', help="Répond pong")
async def ping(ctx):
    response = "pong"
    await ctx.send(response)

# ========================================================
# Camioned
@bot.command(name='camioned', help="Un camion qui se baladait sur une toile toile toile")
async def camioned(ctx):
    response = "https://camioned.fr/"
    await ctx.send(response)

# ========================================================
# Gwened
@bot.command(name='gwened', help="Gweno momento")
async def gwened(ctx):
    response = "https://gwened.fr/"
    await ctx.send(response)

# ========================================================
# Amogus
@bot.command(name='amogus', help="sus")
async def amogus(ctx, nb : typing.Optional[int] = 1):
    if nb < 1:
        response = "https://cdn.discordapp.com/attachments/777292703801147402/961635920078077952/reverseamogus.png"
        nb = -nb
    else:
        response = "https://amogus.org/amogus.png"

    if nb > 20:
        nb = 20

    for i in range(0,nb):
        await ctx.send(response)

# ========================================================
# Sugoma
@bot.command(name='sugoma', help="sus")
async def sugoma(ctx, nb : typing.Optional[int] = 1):
    if nb < 1:
        response = "https://cdn.discordapp.com/attachments/777292703801147402/961638400581054475/flipreverseamogus.png"
        nb = -nb
    else:
        response = "https://cdn.discordapp.com/attachments/777292703801147402/961638400874663966/flipamogus.png"

    if nb > 20:
        nb = 20

    for i in range(0,nb):
        await ctx.send(response)

# ========================================================
# Ajouter les devoirs dans le .json des devoirs
@bot.command(
    name='add',
    help="""
    Ajoute des devoirs dans la liste de devoirs
    Il faut préciser :
        - la date au format JJ/MM ou JJ/MM/AA
        - la matière en un mot
        - puis une description de la longueur souhaité""")
async def add(ctx, date: str, matiere: str, *, description):

    date = dateFormating(date)

    if date == None:
        raise commands.BadArgument

    devoirs = getDevoirs()

    toAppend = {"name" : matiere, "value" : description, "date" : date.isoformat()}
    devoirs["fields"].append(toAppend)

    setDevoirs(devoirs)

    date_str = date.strftime("%d/%m/%Y")
    response = f"J'ajoute le devoir de {matiere} pour le {date_str} vous serez prevenus la veille ! \nVous pouvez également voir la liste des devoirs en tapant !devoirs"
    await ctx.send(response)
# Gestion des erreur de la commande add
@add.error
async def add_error(ctx, error):
    if isinstance(error, commands.BadArgument) :
        await ctx.send("Fait attention au format de la date !")
    elif isinstance(error, commands.CheckFailure) :
        await ctx.send("Tu crois pouvoir faire quoi toi ?")
    elif isinstance(error, commands.CommandError) :
        await ctx.send("Ca n'a pas marché dû à une erreur interne, veuillez contacter le développeur ...")
        print(datetime.now().time(), error)
# Gestion des bans de la commande add
add.add_check(bannedList)

# ========================================================
# Ajouter les devoirs dans le .json des devoirs
@bot.command(
    name='md',
    help="""
    Modifie des devoirs dans la liste de devoirs.
    La commande prend obligatoirement en argument l'indice du devoir à modifier.
    Puis soit on utilise les modificateurs précis soit on entre le devoir commme avec la comande add.
    Les modificateur :
        - -d [DATE] : Pour modifier la date
        - -m [MATIERE] : Pour modifier la matière
        - -e [DESCRIPTION] : Pour modifier la description""")
async def md(ctx, indice: int, arg1: typing.Optional[str] = "", arg2: typing.Optional[str] = "", *, description: typing.Optional[str] = ""):
    devoirs = getDevoirs()
    toModify = {}
    response = ""

    try:
        toModify = devoirs["fields"][indice]
    except IndexError:
        raise commands.BadArgument

    if arg1 == "-d":
        # Modification de la date du devoir
        date = dateFormating(arg2)

        if date == None:
            raise commands.BadArgument

        response = "La date à été modifier de **" + datetime.fromisoformat(toModify["date"]).strftime("%d/%m/%Y")

        toModify["date"] = date.isoformat()

        response += "** à la date suivante **" + datetime.fromisoformat(toModify["date"]).strftime("%d/%m/%Y") + "**\n"

    elif arg1 == "-m":
        # Modification de la matière du devoir
        response = "La matière à été modifié de **" + toModify["name"]

        toModify["name"] = arg2

        response += "** à la matière suivante **" + toModify["name"] + "**\n"

    elif arg1 == "-e":
        # Modification de l'explication/description du devoir
        response = "La description à été modifié de **" + toModify["value"]

        toModify["value"] = arg2 + " " + description

        response += "** à la description suivante **" + toModify["value"] + "**\n"

    else:
        # Modifiction de tout
        date = dateFormating(arg1)

        if date == None:
            raise commands.BadArgument

        response = "Le devoir à été modifié de *" + datetime.fromisoformat(toModify["date"]).strftime("%d/%m/%Y") + " : " + toModify["name"] + " : " + toModify["value"]

        toModify["date"] = date.isoformat()
        toModify["name"] = arg2
        toModify["value"] = description

        response += "* au devoir suivant *" + datetime.fromisoformat(toModify["date"]).strftime("%d/%m/%Y") + " : " + toModify["name"] + " : " + toModify["value"] + "*"

    devoirs["fields"][indice] = toModify

    setDevoirs(devoirs)

    response += "Vous pouvez également voir la liste des devoirs en tapant !devoirs"
    await ctx.send(response)
# Gestion des erreur de la commande md
@md.error
async def md_error(ctx, error):
    if isinstance(error, commands.BadArgument) :
        await ctx.send("Fait attention au format de la date ou a l'index du devoir !")
    elif isinstance(error, commands.CheckFailure) :
        await ctx.send("Tu crois pouvoir faire quoi toi ?")
    elif isinstance(error, commands.CommandError) :
        await ctx.send("Ca n'a pas marché dû à une erreur interne, veuillez contacter le développeur ...")
        print(datetime.now().time(), error)
# Gestion des bans de la commande md
md.add_check(bannedList)

# ========================================================
# Supprimer un devoir du fichier .json par son indice
@bot.command(
    help="""
    Supprimer un devoir de la liste par son indice
    Attention l'indice commence à 0, en négatif part de la fin, on est des devs ou pas ?""")
async def rm(ctx, indice: int):

    devoirs = getDevoirs()

    try:
        del(devoirs["fields"][indice])
    except IndexError:
        raise commands.BadArgument

    setDevoirs(devoirs)

    response = f"Je supprime le devoir n°{indice} de la liste ! \nVous pouvez également voir la liste des devoirs en tapant !devoirs"
    await ctx.send(response)
# Gestion des erreur de la commande rm
@rm.error
async def rm_error(ctx, error):
    if isinstance(error, commands.BadArgument) :
        await ctx.send("Cette indice de devoir n'existe pas (ça commence à 0) !")
    elif isinstance(error, commands.CheckFailure) :
        await ctx.send("Tu crois pouvoir faire quoi toi ?")
    elif isinstance(error, commands.CommandError) :
        await ctx.send("Ca n'a pas marché du à une erreur interne, veuillez contacter le développeur ...")
        print(datetime.now().time(), error)
# Gestion des bans de la commande rm
rm.add_check(bannedList)

# ========================================================
# Afficher les devoirs à faire
@bot.command(
    help="""
    Permet d'afficher les devoirs à faire.
    Ils sont trié par date par défaut mais il peuvent être trié par matière avec le modificatieur -m.
    Il est également possible d'afficher que les devoirs d'une matière en précisant la matière derrière le modificateur -m.""")
async def devoirs(ctx, parameter: typing.Optional[str] = "-d", *, description: typing.Optional[str] = "" ):
    devoirsPrets = {}

    if parameter == "-m":
        if description != "":
            devoirsPrets = devoirsParMatiere(matiere=description)
            devoirsPrets["title"] = "Les devoirs en " + description

            if devoirsPrets["fields"] == []:
                devoirsPrets["description"] = "Pas de devoirs en cette matière ! YOUPI !!"
        else:
            devoirsPrets = devoirsParMatiere()

    elif parameter == "-d":
        devoirsPrets = devoirsParDate()
    else:
        raise commands.BadArgument

    miseEnForme = discord.Embed.from_dict(devoirsPrets)
    await ctx.send(embed= miseEnForme)
# Gestion des erreur de la commande devoirs
@devoirs.error
async def devoirs_error(ctx, error):
    if isinstance(error, commands.BadArgument) :
        await ctx.send("Tu as mal écris la commande !")
    elif isinstance(error, commands.CommandError):
        await ctx.send("Ca n'a pas marché du à une erreur interne, veuillez contacter le développeur ...")
        print(datetime.now().time(), error)

# ========================================================
# Tache de vérification régulière
@bot.event
async def my_background_task():
    # guild = discord.utils.get(bot.guilds, name=GUILD)
    # for channel in guild.channels:
    #     if channel.name == "devoirs":
    #         channelFinal = channel
    channelFinal = bot.get_channel(CHANNEL)

    while not bot.is_closed():
        aujourdhui = datetime.now()

        # Suppression des devoirs passés
        if (aujourdhui.hour == 0 and aujourdhui.minute == 1):
            devoirs = getDevoirs()
            modif = False
            cpt = 0
            for devoir in devoirs["fields"]:
                if datetime.fromisoformat(devoir["date"]).date() < aujourdhui.date():
                    del(devoirs["fields"][cpt])
                    modif = True
                cpt += 1

            if modif:
                setDevoirs(devoirs)

        aujourdhuiToTest = str(aujourdhui.weekday()) + ":" + str(aujourdhui.hour) + ":" + str(aujourdhui.minute)

        # Alerte pour le jour même :
        if aujourdhuiToTest in alerteAujourdhui:
            devoirsPrets = {}
            devoirsPrets["title"] = "Voilà les devoirs pour aujourd'hui"

            devoirsPrets = devoirsParDate(laDate=aujourdhui)
            if devoirsPrets["fields"] != []:
                miseEnForme = discord.Embed.from_dict(devoirsPrets)
                if random() < 0.001:
                    await channelFinal.send("@everyone", embed= miseEnForme)
                else:
                    await channelFinal.send("@tout_le_monde", embed= miseEnForme)

        # Alerte des devoirs pour le lendemain :
        elif aujourdhuiToTest in alerteDemain:
            devoirsPrets = {}
            aujourdhui = aujourdhui + dt.timedelta(days=1)
            devoirsPrets["title"] = "Voilà les devoirs pour demain"

            devoirsPrets = devoirsParDate(laDate=aujourdhui)
            if devoirsPrets["fields"] != []:
                miseEnForme = discord.Embed.from_dict(devoirsPrets)
                if random() < 0.001:
                    await channelFinal.send("@everyone", embed= miseEnForme)
                else:
                    await channelFinal.send("@tout_le_monde", embed= miseEnForme)

        # Alerte des devoirs pour le lundi :
        elif aujourdhuiToTest in alerteSemainePro:
            devoirsPrets = {}
            aujourdhui = aujourdhui + dt.timedelta(days= 7 - aujourdhui.weekday())
            devoirsPrets["title"] = "Voilà les devoirs pour la semaine prochaine"

            for i in range(0,4):
                aujourdhui = aujourdhui + dt.timedelta(days=1)
                devoirsPrets += devoirsParDate(laDate=aujourdhui)
            if devoirsPrets["fields"] != []:
                miseEnForme = discord.Embed.from_dict(devoirsPrets)
                if random() < 0.001:
                    await channelFinal.send("@everyone", embed= miseEnForme)
                else:
                    await channelFinal.send("@tout_le_monde", embed= miseEnForme)

        else:
            if random() < 0.00005:
                randomEmoji = [":kissing_heart:", ":flushed:", ":wink:", ":smirk:", ":rolling_eyes:", ":hot_face:", ":yawning_face:", ":face_vomiting:", ":mechanic_tone4:", ":pinching_hand:", ":person_gesturing_no:", ":kiss_mm:", ":couple_mm:", ":frog:", ":full_moon_with_face:", ":sweat_drops:", ":peach:", ":eggplant:", ":brown_square:", ":flag_af:"]
                await channelFinal.send(choice(randomEmoji))

        await asyncio.sleep(60) # task runs every 60 seconds

# ========================================================
# Commande pour process l'image jointe et en extraire le texte
import pytesseract
import re
import requests

def dowloadImage(src, dest):
    response = requests.get(src)
    if not response.ok:
        raise commands.BadArgument(message="Failed to donwload image")

    img_data = response.content
    with open(dest, 'wb') as handler:
        handler.write(img_data)

@bot.hybrid_command(
    help="""
    Permet d'extraire le texte d'une image
    La langue d'interprétation est de base en français mais peut être changé en une autre avec l'argument [LANG].
    Liste des langues dispo : """ + str(pytesseract.get_languages(config='')))
async def extract(ctx, LANG: typing.Optional[str] = "fra", parameter2: typing.Optional[str] = ""):
    if ctx.message.reference:
        if LANG not in pytesseract.get_languages(config=''):
            raise commands.BadArgument("La langue sélectionné n'existe pas (reference)")
        original = await ctx.fetch_message(ctx.message.reference.message_id)

        if len(original.attachments) == 0:
            urlRe = re.search("(?P<url>https?://[^\s]+)", original.content)
            if urlRe is None:
                await ctx.send("Pas d'image dans ce message")
                return

            url = urlRe.group("url")
            if not url.split(".").pop() in ["png", "jpg", "jpeg"] :
                await ctx.send("Le lien ne fait pas référence à une image supporté")
                return

            async with ctx.typing():
                filename = url.split("/").pop()
                pathToImage = "./images/" + filename
                dowloadImage(url, pathToImage)
                text = pytesseract.image_to_string(pathToImage, lang=LANG)
                os.remove(pathToImage)
                await ctx.send("```" + text.strip() + "```")
                return
        elif len(ctx.message.attachments) > 1:
            await ctx.send("Trop d'images dans ce message !")
            return

        if original.attachments[0].content_type in ["image/jpeg", "image/png"]:
            async with ctx.typing():
                pathToImage = "./images/" + original.attachments[0].filename
                await original.attachments[0].save(pathToImage)
                text = pytesseract.image_to_string(pathToImage, lang=LANG)
                os.remove(pathToImage)
                await ctx.send("```" + text.strip() + "```")
                return

    if len(ctx.message.attachments) == 0:
        urlRe = re.search("(?P<url>https?://[^\s]+)", ctx.message.content)
        if urlRe is None :
            await ctx.send("Pas d'image dans ce message")
            return

        url = urlRe.group("url")
        if not url.split(".").pop() in ["png", "jpg", "jpeg"] :
            await ctx.send("Le lien ne fait pas référence à une image supporté")
            return

        splitedMessage = ctx.message.content.split(" ")
        splitedMessage.pop(0)
        lang = "fra"
        if len(splitedMessage) > 1:
            if splitedMessage.index(url):
                lang = splitedMessage[0]
            else:
                lang = splitedMessage[1]

        if lang not in pytesseract.get_languages(config=''):
            print(splitedMessage)
            raise commands.BadArgument("La langue sélectionné n'existe pas (link)")

        async with ctx.typing():
            filename = url.split("/").pop()
            pathToImage = "./images/" + filename
            dowloadImage(url, pathToImage)
            text = pytesseract.image_to_string(pathToImage, lang=lang)
            os.remove(pathToImage)
            await ctx.send("```" + text.strip() + "```")
            return

    if LANG not in pytesseract.get_languages(config=''):
        raise commands.BadArgument("La langue sélectionné n'existe pas (original)")

    elif len(ctx.message.attachments) > 1:
        # plusieurs liens
        # re.findall(r'(https?://[^\s]+)', myString)

        ctx.send("Bro attend le fait d'envoyer plusieurs photos n'est pas encore implémenté !")
        return

    if ctx.message.attachments[0].content_type in ["image/jpeg", "image/png"]:
        async with ctx.typing():
            pathToImage = "./images/" + ctx.message.attachments[0].filename
            await ctx.message.attachments[0].save(pathToImage)
            text = pytesseract.image_to_string(pathToImage, lang=LANG)
            os.remove(pathToImage)
            await ctx.send("```" + text.strip() + "```")
            return

# Gestion des erreur de la commande devoirs
@extract.error
async def devoirs_error(ctx, error):
    if isinstance(error, commands.BadArgument) :
        await ctx.send("Tu as mal écris la commande !\n" + str(error))
    elif isinstance(error, commands.CommandError) :
        await ctx.send("Ca n'a pas marché du à une erreur interne, veuillez contacter le développeur ...")
        print(datetime.now().time(), error)

async def main():
    async with bot:
        bot.loop.create_task(my_background_task())
        await bot.start(TOKEN)

if __name__ == "__main__":
    print(datetime.now().time(), "Let's get started !")
    asyncio.run(main())


import os
import unittest
import pytest
from uuid import uuid4
from tempfile import TemporaryDirectory
from argparse import Namespace
import tarfile
import ppcg_qc_from_sanger.extract_qc as extract_qc
from ppcg_qc_from_sanger.sanger_qc_extractor import SangerQcMetricsExtractor

class PpcgQcFromSangerExtractQcTestCase(unittest.TestCase):

    def setUp(self):
        self.test_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data')

    def write_to_file(self, dir, content, file_name=None):
        if file_name is None:
            test_file = os.path.join(dir, str(uuid4()))
        else:
            test_file = os.path.join(dir, file_name)
        with open(test_file, 'w') as f:
            f.write(content)
        return test_file

    def test_validate_tar_name(self):
        testing_function = SangerQcMetricsExtractor.validate_tar_name
        with pytest.raises(RuntimeError) as exc:
            result = testing_function(os.path.join('x', 'y', 'z', '.tar.gz'))
        self.assertIn('should have ".tar.gz" suffix', str(exc.value))
        with pytest.raises(RuntimeError) as exc:
            result = testing_function(os.path.join('x', 'y', 'z.gz'))
        self.assertIn('should have ".tar.gz" suffix', str(exc.value))

    def test_validate_bas(self):
        testing_function = SangerQcMetricsExtractor.validate_bas

        # test invalid file name
        with pytest.raises(RuntimeError) as exc:
            test = testing_function('test.bam.basss')
        self.assertIn('file test.bam.basss does not exist.', str(exc.value))

        # test valid content
        test_file = os.path.join(self.test_dir, 'test_sample.bam.bas')
        self.assertEqual(testing_function(test_file), None)

        test_content = open(test_file).read()
        with TemporaryDirectory() as temp_dir:

            # test bad header
            test_file_content = 'bas_file_name\n' + test_content
            test_file = self.write_to_file(temp_dir, test_file_content, 'test_1.bam.bas')
            with pytest.raises(RuntimeError) as exc:
                test = testing_function(test_file)
            self.assertIn('invalid BAS header', str(exc.value))

            # test fewer columns in a row
            test_file_content = test_content + '-\ttest_sample\n'
            test_file = self.write_to_file(temp_dir, test_file_content, 'test_2.bam.bas')
            with pytest.raises(RuntimeError) as exc:
                test = testing_function(test_file)
            self.assertIn('invalid row in BAS file', str(exc.value))

    def test_extract_from_sanger(self):
        '''
        testing the whole process
        '''
        testing_function = extract_qc.extract_from_sanger
        with TemporaryDirectory() as temp_dir:
            good_args = Namespace(
                tumour_bas=[os.path.join(self.test_dir, 'tumour_sample.bam.bas')],
                normal_bas=[os.path.join(self.test_dir, 'normal_sample.bam.bas')],
                variant_call_tar=[os.path.join(self.test_dir, 'test.tar.gz')],
                output_tar=os.path.join(temp_dir, 'result.tar.gz'),
                genome_size=3137454505,
                debug=False,
                count_variants=False,
                metadata=[]
            )
            # run the function to have outputs
            self.assertEqual(testing_function(good_args), None)

            # check if the metrics are as expected.
            metrics_file = 'ppcg_sanger_metrics.txt'
            with tarfile.open(good_args.output_tar, 'r:gz') as tar:
                result_files = [a_file.name for a_file in tar.getmembers()]
                tar.extract(metrics_file, path=temp_dir)
            self.assertEqual(
                open(os.path.join(temp_dir, metrics_file), 'r').read(),
                open(os.path.join(self.test_dir, 'expected_metrics.txt')).read()
            )

            # check if expected files are in the tar
            e_genotype_files = \
                SangerQcMetricsExtractor.get_metrics_file_names('tumour_sample', 'normal_sample')[3]
            for a_file in e_genotype_files:
                self.assertTrue(os.path.basename(a_file) in result_files)

            # test wrong genome size type
            # a shallow copy of good_args
            args = Namespace(**vars(good_args))
            args.genome_size = '1'
            with pytest.raises(SystemExit) as exc:
                testing_function(args)
            self.assertEqual(exc.type, SystemExit)

            # test non exist file
            args = Namespace(**vars(good_args))
            args.tumour_bas = 'some should not exist file.file'
            with pytest.raises(SystemExit) as exc:
                testing_function(args)
            self.assertEqual(exc.type, SystemExit)

            # test if variants can be counted correctly
            args = Namespace(**vars(good_args))
            args.count_variants = True
            args.output_tar = os.path.join(temp_dir, 'result_2.tar.gz')
            # run the function to have outputs
            self.assertEqual(testing_function(args), None)
            metrics_file = 'ppcg_sanger_metrics.txt'
            with tarfile.open(args.output_tar, 'r:gz') as tar:
                result_files = [a_file.name for a_file in tar.getmembers()]
                tar.extract(metrics_file, path=temp_dir)
            self.assertEqual(
                open(os.path.join(temp_dir, metrics_file), 'r').read(),
                open(os.path.join(self.test_dir, 'expected_metrics_with_variant_counts.txt')).read()
            )


from colorama import Fore as fo
from colorama import Style as st
blackc = fo.BLACK
dangerc = fo.RED
successc = fo.GREEN
warningc = fo.YELLOW
primaryc = fo.BLUE
infoc = fo.CYAN
r = fo.RESET

def addEntry():
    n = input('Name: ')
    wd = input('Working Directory: ')
    fi = input('File Name: ')
    temp = ""
    temp += '    "{}": {}\n'.format(n,'{')
    temp += '        "working": "{}",\n'.format(wd)
    temp += '        "file": "{}"\n'.format(fi)
    temp += '    }'
    print(temp)
    return temp

def danger(textd):
    print(dangerc+textd+r)

def success(textd):
    print(successc+textd+r)

def warning(textd):
    print(warningc+textd+r)

def info(textd):
    print(infoc+textd+r)

global cfg
print('Welcome to the startup json setup.\n')
print('Please fill in all the informations as they are all compulsory.')

cfg = "{\n"
cfg += addEntry()
#while True:
#    yn = input('Any more startup processes?[Y/N]: ')
#    print('yn: ' + yn)
#    if yn == 'y' or 'Y':
#        print('yes')
#        cfg += ',\n'
#        cfg += addEntry()
#    else:
#        break
#    yn = ''
## Potential Workarounds.
## G:\P\Python Projects\startup\wkar.py

cfg += '\n}'
print(cfg)
jfile = open("autostartup.json", "w")
jfile.write(cfg)
print(jfile)
jfile.close()
exit(0)