# flake8: noqa F401
import io
import csv
from datetime import datetime, timedelta, time
from flask import (
    Blueprint,
    render_template,
    request,
    flash,
    redirect,
    url_for,
    send_file,
)
from flask_login import login_required, current_user
from markupsafe import Markup
import sqlalchemy as sa
from flask import current_app as app

from pyecharts import options as opts
from pyecharts.charts import Bar

from app.controllers import create_pagination
from app import models as m, db
from app import forms as f
from app.controllers.graphs import create_bar_graph
from app.logger import log
from app.controllers.jinja_globals import days_active
from app.controllers.date_convert import date_convert

report_blueprint = Blueprint("report", __name__, url_prefix="/report")

@report_blueprint.route("/create", methods=["GET", "POST"])
@login_required
def dashboard():
    exclude = request.args.get("exclude")
    views_filter = request.args.get("views_filter")
    views_filter = views_filter if views_filter and views_filter != "None" else ""
    type_filter = request.args.get("type_filter")
    type_filter = type_filter if type_filter and type_filter != "None" else ""
    make_filter = request.args.get("make_filter")
    make_filter = make_filter if make_filter and make_filter != "None" else ""
    model_filter = request.args.get("model_filter")
    model_filter = model_filter if model_filter and model_filter != "None" else ""
    trim_filter = request.args.get("trim_filter")
    trim_filter = trim_filter if trim_filter and trim_filter != "None" else ""
    price_lower = request.args.get("price_lower")
    price_lower = price_lower if price_lower and price_lower != "None" else ""
    price_sold_lower = request.args.get("price_sold_lower")
    price_sold_lower = (
        price_sold_lower if price_sold_lower and price_sold_lower != "None" else ""
    )
    price_upper = request.args.get("price_upper")
    price_upper = price_upper if price_upper and price_upper != "None" else ""
    price_sold_upper = request.args.get("price_sold_upper")
    price_sold_upper = (
        price_sold_upper if price_sold_upper and price_sold_upper != "None" else ""
    )
    start_date = request.args.get("start_date")
    start_date = start_date if start_date and start_date != "None" else ""
    end_date = request.args.get("end_date")
    end_date = end_date if end_date and end_date != "None" else ""
    date_received = request.args.get("date_received")
    date_received = date_received if date_received and date_received != "None" else ""
    views_options_filter = request.args.get("views_options_filter")
    views_options_filter = (
        views_options_filter
        if views_options_filter and views_options_filter != "None"
        else ""
    )
    download = request.args.get("download")

    query = sa.select(m.Label).where(m.Label.user_id == current_user.id)

    count_query = (
        sa.select(sa.func.count())
        .select_from(m.Label)
        .where(m.Label.user_id == current_user.id)
    )

    if exclude and exclude != "None":
        log(log.INFO, f"Excluding labels: {exclude}")
        exclude_list = exclude.split(",")
        for label_to_exclude in exclude_list:
            query = query.where(m.Label.unique_id != label_to_exclude)
            count_query = count_query.where(m.Label.unique_id != label_to_exclude)

    if not start_date and end_date:
        log(log.INFO, f"Filtering by end_date: {end_date}")
        end_date = datetime.strptime(end_date, "%m/%d/%Y")
        query = query.where(sa.func.DATE(m.Label.date_received) <= end_date)
        count_query = count_query.where(sa.func.DATE(m.Label.date_received) <= end_date)
    elif start_date and not end_date:
        log(log.INFO, f"Filtering by start_date: {start_date}")
        start_date = datetime.strptime(start_date, "%m/%d/%Y")
        query = query.where(sa.func.DATE(m.Label.date_received) >= start_date)
        count_query = count_query.where(
            sa.func.DATE(m.Label.date_received) >= start_date
        )
    elif start_date and end_date:
        log(log.INFO, f"Filtering by start_date: {start_date} and end_date: {end_date}")
        start_date = date_convert(start_date)
        end_date = date_convert(end_date)
        query = query.where(sa.func.DATE(m.Label.date_received) >= start_date)
        count_query = count_query.where(
            sa.func.DATE(m.Label.date_received) >= start_date
        )
        query = query.where(sa.func.DATE(m.Label.date_received) <= end_date)
        count_query = count_query.where(sa.func.DATE(m.Label.date_received) <= end_date)
    elif date_received and date_received != "None":
        log(log.INFO, f"Filtering by date_received: {date_received}")

        date_received = date_convert(date_received)

        query = query.where(sa.func.DATE(m.Label.date_received) == date_received)
        count_query = count_query.where(
            sa.func.DATE(m.Label.date_received) == date_received
        )

    if make_filter and make_filter != "All":
        log(log.INFO, f"Filtering by make: {make_filter}")
        query = query.where(m.Label.make == make_filter)
        count_query = count_query.where(m.Label.make == make_filter)
    if model_filter and model_filter != "All":
        log(log.INFO, f"Filtering by model: {model_filter}")
        query = query.where(m.Label.vehicle_model == model_filter)
        count_query = count_query.where(m.Label.vehicle_model == model_filter)
    if type_filter and type_filter != "All":
        log(log.INFO, f"Filtering by type: {type_filter}")
        query = query.where(m.Label.type_of_vehicle == type_filter)
        count_query = count_query.where(m.Label.type_of_vehicle == type_filter)
    if trim_filter and trim_filter != "All":
        log(log.INFO, f"Filtering by trim: {trim_filter}")
        query = query.where(m.Label.trim == trim_filter)
        count_query = count_query.where(m.Label.trim == trim_filter)
    if price_lower:
        log(log.INFO, f"Filtering by price_lower: {price_lower}")
        query = query.where(m.Label.price >= price_lower)
        count_query = count_query.where(m.Label.price >= price_lower)
    if price_sold_lower:
        log(log.INFO, f"Filtering by price_sold_lower: {price_sold_lower}")
        query = query.where(m.Label.price_sold >= price_sold_lower)
        count_query = count_query.where(m.Label.price_sold >= price_sold_lower)
    if price_upper:
        log(log.INFO, f"Filtering by price_upper: {price_upper}")
        query = query.where(m.Label.price <= price_upper)
        count_query = count_query.where(m.Label.price <= price_upper)
    if price_sold_upper:
        log(log.INFO, f"Filtering by price_sold_upper: {price_sold_upper}")
        query = query.where(m.Label.price_sold <= price_sold_upper)
        count_query = count_query.where(m.Label.price_sold <= price_sold_upper)

    query = query.order_by(m.Label.id.desc())

    if views_options_filter in ["0-10", "10-50", "50-100", "100-1000", "1000-10000"]:
        total_views = sa.func.count(m.LabelView.id).label("total_views")
        log(log.INFO, f"Filtering by views_options_filter: {views_options_filter}")
        query = (
            query.add_columns(total_views)
            .join(m.Label._views)
            .group_by(m.Label.id)
            .having(sa.between(total_views, *views_options_filter.split("-")))
            .order_by(sa.text("total_views DESC"))
        )
        count_query = (
            count_query.add_columns(total_views)
            .join(m.Label._views)
            .group_by(m.Label.id)
            .having(sa.between(total_views, *views_options_filter.split("-")))
        )

    count_query = db.session.scalar(count_query)

    now = datetime.now()

    week_start = now - timedelta(days=now.weekday() + 1)
    week_end = week_start + timedelta(days=6)

    week_dates = [
        (week_start + timedelta(days=i)).strftime("%Y-%m-%d") for i in range(7)
    ]

    view_query = (
        sa.Select(
            sa.func.count(m.LabelView.created_at).label("count"),
            m.LabelView.created_at,
        )
        .join(m.Label)
        .where(
            m.Label.user_id == current_user.id,
            sa.cast(m.LabelView.created_at, sa.Date).between(
                week_start.strftime("%Y-%m-%d"), week_end.strftime("%Y-%m-%d")
            ),
        )
        .group_by(m.LabelView.created_at)
        .order_by(m.LabelView.created_at.asc())
    )

    view_data = db.session.execute(view_query).all()
    graph = create_bar_graph(view_data, week_dates)

    pagination = create_pagination(total=0 if count_query is None else count_query)
    labels = (
        db.session.execute(
            query.offset((pagination.page - 1) * pagination.per_page).limit(
                pagination.per_page
            )
        )
        .scalars()
        .all()
    )
    types = db.session.scalars(
        sa.select(m.Label.type_of_vehicle)
        .where(m.Label.user_id == current_user.id)
        .group_by(m.Label.type_of_vehicle)
    ).all()
    makes = db.session.scalars(
        sa.select(m.Label.make)
        .where(m.Label.user_id == current_user.id)
        .group_by(m.Label.make)
    ).all()
    trims = db.session.scalars(
        sa.select(m.Label.trim)
        .where(m.Label.user_id == current_user.id)
        .group_by(m.Label.trim)
    ).all()
    if make_filter and make_filter != "All":
        log(log.INFO, f"Getting models for make: {make_filter}")
        models = db.session.scalars(
            sa.select(m.Label.vehicle_model)
            .where(m.Label.user_id == current_user.id)
            .where(m.Label.make == make_filter)
            .group_by(m.Label.vehicle_model)
        ).all()
    else:
        log(log.INFO, f"Getting models for all makes")
        models = db.session.scalars(
            sa.select(m.Label.vehicle_model)
            .where(m.Label.user_id == current_user.id)
            .group_by(m.Label.vehicle_model)
        ).all()
    now = datetime.now()
    if download == "true":
        log(log.INFO, f"Downloading report")
        labels = db.session.scalars(query).all()
        with io.StringIO() as proxy:
            writer = csv.writer(proxy)
            row = [
                "sticker_id",
                "name",
                "make",
                "vehicle_model",
                "year",
                "mileage",
                "color",
                "trim",
                "type_of_vehicle",
                "price",
                "date_received",
                "date_deactivated",
                "days_active",
                "url",
                "views",
            ]
            writer.writerow(row)
            for label in labels:
                row = [
                    label.sticker_id,
                    label.name,
                    label.make,
                    label.vehicle_model,
                    label.year,
                    label.mileage,
                    label.color,
                    label.trim,
                    label.type_of_vehicle,
                    label.price,
                    label.date_received,
                    label.date_deactivated,
                    days_active(label.date_received, label.date_deactivated),
                    label.url,
                    label.views,
                ]
                writer.writerow(row)

            # Creating the byteIO object from the StringIO Object
            mem = io.BytesIO()
            mem.write(proxy.getvalue().encode("utf-8"))
            mem.seek(0)

        return send_file(
            mem,
            as_attachment=True,
            download_name=f"report_{current_user.first_name}_{current_user.last_name}_{now.strftime('%Y-%m-%d-%H-%M-%S')}.csv",
            mimetype="text/csv",
            max_age=0,
            last_modified=now,
        )

    return render_template(
        "report/dashboard.html",
        labels=labels,
        makes=makes,
        make_filter=make_filter,
        models=models,
        model_filter=model_filter,
        types=types,
        trims=trims,
        type_filter=type_filter,
        views_filter=views_filter,
        price_lower=price_lower,
        price_upper=price_upper,
        start_date=start_date,
        end_date=end_date,
        date_received=date_received,
        views_options_filter=views_options_filter,
        exclude=exclude,
        page=pagination,
        test_graph=graph,
    )

@report_blueprint.route("/get_models", methods=["POST"])
@login_required
def get_models():
    make = request.json.get("makeSelected")
    labels = db.session.scalars(
        sa.select(m.Label.vehicle_model)
        .where(m.Label.user_id == current_user.id)
        .where(m.Label.make == make)
        .distinct(m.Label.vehicle_model)
    ).all()
    return {"models": labels}

@report_blueprint.route("/get_label_views_datetime/<unique_id>", methods=["GET"])
@login_required
def get_label_views_datetime(unique_id: str):
    label: m.Label | None = db.session.scalar(
        m.Label.select().where(m.Label.unique_id == unique_id)
    )
    download = request.args.get("download")
    if not label:
        log(log.ERROR, f"Label not found: {unique_id}")
        return {"error": "Label not found"}, 404
    list_views = label.list_views

    if download == "True":
        now = datetime.now()
        log(log.INFO, f"Downloading label views")
        with io.StringIO() as proxy:
            writer = csv.writer(proxy)
            row = [
                "day",
                "time",
                "location",
            ]
            writer.writerow(row)
            for label_view in list_views:
                row = [
                    label_view.day,
                    label_view.time,
                    label.location,
                ]
                writer.writerow(row)

            mem = io.BytesIO()
            mem.write(proxy.getvalue().encode("utf-8"))
            mem.seek(0)
        return send_file(
            mem,
            as_attachment=True,
            download_name=f"label_views_{now.strftime('%Y-%m-%d-%H-%M-%S')}.csv",
            mimetype="text/csv",
            max_age=0,
            last_modified=now,
        )

    return render_template(
        "report/label_views_modal.html",
        list_views=list_views,
        unique_id=label.unique_id,
        location=label.location,
    )

@report_blueprint.route("/all", methods=["GET", "POST"])
@login_required
def all():
    query = (
        m.Label.select()
        .where(m.Label.user_id == current_user.id)
        .where(m.Label.status == m.LabelStatus.active)
        .order_by(m.Label.id)
    )
    count_query = (
        sa.select(sa.func.count())
        .select_from(m.Label)
        .where(m.Label.user_id == current_user.id)
        .where(m.Label.status == m.LabelStatus.active)
    )
    pagination = create_pagination(total=db.session.scalar(count_query))
    return render_template(
        "report/all.html",
        labels=db.session.execute(
            query.offset((pagination.page - 1) * pagination.per_page).limit(
                pagination.per_page
            )
        ).scalars(),
        page=pagination,
    )

@report_blueprint.route("/get_label_views_graph", methods=["GET"])
@login_required
def get_label_views_graph():
    start_date = request.args.get("start_date_graph")
    end_date = request.args.get("end_date_graph")
    label_id = request.args.get("label_id")
    week_dates = None
    if start_date and end_date and label_id:
        where = sa.and_(
            m.LabelView.label_id == label_id,
            m.Label.user_id == current_user.id,
            sa.cast(m.LabelView.created_at, sa.Date).between(
                start_date,
                end_date,
            ),
        )
    elif start_date and end_date and not label_id:
        where = sa.and_(
            m.Label.user_id == current_user.id,
            sa.cast(m.LabelView.created_at, sa.Date).between(
                start_date,
                end_date,
            ),
        )
    elif (not start_date or not end_date) and label_id:
        where = sa.and_(
            m.LabelView.label_id == label_id,
            m.Label.user_id == current_user.id,
        )

    else:
        now = datetime.now()

        week_start = now - timedelta(days=now.weekday() + 1)
        week_end = week_start + timedelta(days=6)

        week_dates = [
            (week_start + timedelta(days=i)).strftime("%Y-%m-%d") for i in range(7)
        ]

        where = sa.and_(
            m.Label.user_id == current_user.id,
            sa.cast(m.LabelView.created_at, sa.Date).between(
                week_start.strftime("%Y-%m-%d"), week_end.strftime("%Y-%m-%d")
            ),
        )

    view_query = (
        sa.Select(
            sa.func.count(m.LabelView.created_at).label("count"),
            m.LabelView.created_at,
        )
        .join(m.Label)
        .where(where)
        .group_by(m.LabelView.created_at)
        .order_by(m.LabelView.created_at.desc())
    )

    view_data = db.session.execute(view_query).all()
    graph = create_bar_graph(view_data, week_dates)

    return render_template("report/graph_report_label.html", graph=graph)

@report_blueprint.route("/get_label_location_views_graph", methods=["GET"])
@login_required
def get_label_location_views_graph():
    start_date = request.args.get("start_date_graph")
    end_date = request.args.get("end_date_graph")
    x_axis_name = "Today"
    if start_date and end_date:
        x_axis_name = f"{start_date} - {end_date}"
        where = sa.and_(
            m.LabelLocation.user_id == current_user.id,
            sa.cast(m.LabelView.created_at, sa.Date).between(
                start_date,
                end_date,
            ),
        )
    else:
        now = datetime.now()
        where = sa.and_(
            m.LabelLocation.user_id == current_user.id,
            sa.cast(m.LabelView.created_at, sa.Date) == now.date(),
        )

    query = (
        sa.Select(m.LabelLocation.name, sa.func.count(m.LabelView.id).label("count"))
        .join(m.Label, m.LabelLocation.id == m.Label.location_id)
        .join(m.LabelView, m.Label.id == m.LabelView.label_id)
        .where(where)
        .group_by(m.LabelLocation.name)
    )
    result = db.session.execute(query).all()

    bar = Bar(init_opts=opts.InitOpts(width="100%", height="300px"))
    bar.set_global_opts(
        yaxis_opts=opts.AxisOpts(name="Views"),
        legend_opts=opts.LegendOpts(pos_right="center", pos_top="top"),
    )
    yaxis = bar.add_xaxis([x_axis_name])
    for data in result:
        location_name, view_count = data
        yaxis.add_yaxis(location_name, [view_count])

    return render_template(
        "report/graph_report_label.html", graph=Markup(bar.render_embed())
    )


"""Core module.
"""
import copy
import hashlib
import os
import shutil

from astropy.table import Table

from astrobucket.config import Config
from astrobucket.xselect import XselectCommander

def open_fits_astable(fits_path: str):
    table = Table.read(fits_path, hdu=1)
    return table

class Client:
    """
    Raises
        TypeError: If `obsid` is not str.
    """
    def __init__(self, fits_path: str, object_name: str,
                 satellite: str, obsid: str, verbose: bool = True,
                 save_cache: bool = True):
        if not isinstance(obsid, str):
            raise TypeError(f"{type(obsid)} is not supported.")

        self.fits_path = fits_path
        self.object_name = object_name
        self.satellite = satellite
        self.obsid = obsid
        self.verbose = verbose

        # self.inputs[1] indicate creation mode (={"curve", "spectrum"}).
        self.inputs = [fits_path, "none", object_name, satellite, obsid]

        self.server = Server(Config.cache_path, verbose, save_cache)

    def clear_cache(self, mode: str, *args):
        inputs = copy.copy(self.inputs)
        inputs[1] = mode
        if mode == "curve":
            dt = args[0]
            energy_range_kev = args[1]
            inputs.extend([dt, energy_range_kev])
        elif mode == "spectrum":
            de = args[0]
            energy_range_kev = args[1]
            inputs.extend([de, energy_range_kev])
        else:
            raise NotImplementedError()
        self.server.clear_cache(*inputs)

    def request_curve(self, dt: float, energy_range_kev: tuple or list,
                      verbose: bool = True):
        inputs = copy.copy(self.inputs)
        inputs[1] = "curve"
        inputs.extend([dt, (energy_range_kev[0], energy_range_kev[1])])
        curve = self.server.request(*inputs)
        return curve

    def request_event(self):
        table = open_fits_astable(self.fits_path)
        return table

    def request_spectrum(self, de: float, energy_range_kev: tuple,
                         verbose: bool = True):
        inputs = copy.copy(self.inputs)
        inputs[1] = "spectum"
        inputs.extend([de, energy_range_kev])
        spectrum = self.server.request(*inputs)
        return spectrum

class Creator:
    """Create request `astropy.table`.
    """
    def _create_curve(self):
        xsel_commander = XselectCommander()
        xsel_commander.create_curve(*self.inputs)

    def _create_spectrum(self):
        raise NotImplementedError("Comming soon...")
        # TODO: create spectrum.
        # de = self.inputs[-2]
        # energy_range = self.inputs[-1]
        spectrum = None
        return spectrum

    def create(self, *inputs):
        self.inputs = inputs
        self.mode = inputs[1]  # mode = {"curve", "spectrum"}
        if self.mode == "curve":
            self._create_curve()
        elif self.mode == "spectrum":
            self._create_spectrum()
        fits_path = os.path.join(Config.tmp_path, "xselect_tmp.fits")
        return fits_path

class Namer:
    """Name class.

    Raises
        TypeError: if inputs have other types exept to `int`, `float`, `str`,
            `list`, and `tuple`.
    """
    def _convert_float(self, value: float):
        if int(value) == value:
            return self._convert_int(int(value))
        word = str(value).rjust(10, "0")
        word = word.replace(".", "p")
        return word

    def _convert_int(self, value: int):
        word = str(value).rjust(10, "0")
        return word

    def _convert_multiple(self, value: list or tuple):
        words = [self._convert_single(v) for v in value]
        words = "-".join(words)
        return words

    def _convert_single(self, value: float or int or str):
        if isinstance(value, float):
            word = self._convert_float(value)
        elif isinstance(value, int):
            word = self._convert_int(value)
        elif isinstance(value, str):
            word = self._convert_str(value)
        elif isinstance(value, (list, tuple)):
            word = self._convert_multiple(value)
        return word

    def _convert_str(self, value: str):
        word = str(value)  # Copy instance.
        word = value.lower()
        word = word.replace(" ", "")
        return word

    def get_name(self, *inputs):
        word_list = []
        for t in inputs:
            if isinstance(t, (float, int, str)):
                word = self._convert_single(t)
            elif isinstance(t, (list, tuple)):
                word = self._convert_multiple(t)
            else:
                raise TypeError(f"{type(t)} is not supported.")
            word_list.append(word)
        fullname = "_".join(word_list)
        return fullname

class Server:
    """Server.

    If cache exists, return that. If not, inputs are passed to
    Creator instance.
    """
    def __init__(self, cache_path: str, verbose: bool = True,
                 save_cache: bool = True):
        self.cache_path = cache_path
        self.verbose = verbose
        self.save_cache = save_cache

    def _check_cache(self, filename: str):
        search_path = os.path.join(self.cache_path, filename)
        return os.path.exists(search_path)

    def _convert2hash(self, target: object):
        target_hash = hashlib.md5(target.encode()).hexdigest()
        return target_hash

    def _get_eventhash(self, event_path: str):
        """Get event hash by reading event file.
        """
        hash_ = hashlib.md5()
        with open(event_path, 'rb') as f:
            while True:
                chunk = f.read(2048 * hash_.block_size)
                if len(chunk) == 0:
                    break
                hash_.update(chunk)
        event_hash = hash_.hexdigest()
        return event_hash

    def clear_cache(self, *inputs):
        basename = Namer().get_name(*inputs[1:])
        filename_hash = self._convert2hash(basename)
        fits_path = os.path.join(self.cache_path, filename_hash)
        if os.path.exists(fits_path):
            os.remove(fits_path)

    def request(self, *inputs):

        # Use hash from combined hash of filename and event_hash to
        # ensure that the event file is the same as previous one.
        basename = Namer().get_name(*inputs[1:])
        filename_hash = self._convert2hash(basename)
        event_hash = self._get_eventhash(inputs[0])
        reference_hash = self._convert2hash(filename_hash + event_hash)

        exist = self._check_cache(reference_hash)
        fits_path = os.path.join(self.cache_path, reference_hash)
        if not exist:
            tmp_fits_path = Creator().create(*inputs)
            if self.save_cache:
                shutil.copy(tmp_fits_path, fits_path)
                fits_path = tmp_fits_path
        else:
            if self.verbose:
                print(f"use cache for {basename}")
        table = open_fits_astable(fits_path)

        return table


from django.shortcuts import render
from django.views import generic
from django.urls import reverse_lazy
from .forms import UserCreateForm
from .forms import CommentUpdateForm
from .forms import SearchForm
from .forms import FingerprintCreateForm
from .models import LabAttendanceTb
from .models import LabFingerprintTb
from .models import LabTips
from django.db.models import Q
import random
import json
from django.db.models.signals import post_save
from django.dispatch import receiver

from datetime import date,timedelta

# Create your views here.
# どのhtmlで出力するかの指定
# 出席情報画面
class AttendanceListView(generic.ListView):
    model = LabAttendanceTb
    template_name = 'attendance/attendance_list.html'

    def get_context_data(self, **kwargs):
        model_list = LabAttendanceTb.objects.all()

        tips_list = LabTips.objects.all()
        tips_size = tips_list.count()
        random_num = random.randint(1, tips_size)

        query = LabTips.objects.get(pk = random_num)

        context = {
            'labattendancetb_list': model_list,
            'image_name': "img/" + query.image,
            'text': query.sentence,
        }
        return context

# ユーザ登録画面
class UserCreateView(generic.CreateView):
    model = LabAttendanceTb
    form_class = UserCreateForm
    template_name = 'attendance/user_create.html'
    # ユーザ作成成功時のリダイレクト先
    success_url = reverse_lazy('attendance:attendance_list')

# 指紋登録画面
class FingerprintCreateView(generic.CreateView):
    model = LabFingerprintTb
    form_class = FingerprintCreateForm
    template_name = 'attendance/fingerprint_create.html'
    # ユーザ作成成功時のリダイレクト先
    success_url = reverse_lazy('attendance:attendance_list')

# コメント編集画面
class CommentUpdateView(generic.UpdateView):
    model = LabAttendanceTb
    form_class = CommentUpdateForm
    template_name = 'attendance/comment_update.html'
    # ユーザ作成成功時のリダイレクト先
    success_url = reverse_lazy('attendance:attendance_list')

# 検索画面
class SearchView(generic.ListView):
    template_name = 'attendance/search.html'
    model = LabAttendanceTb

    paginate_by = 5

    def post(self, request, *args, **kwargs):
        form_value = [
            self.request.POST.get('user_id', None),
            self.request.POST.get('user_name', None),
            self.request.POST.get('status', None),
        ]
        request.session['form_value'] = form_value
        # 検索時にページネーションに関連したエラーを防ぐ
        self.request.GET = self.request.GET.copy()
        self.request.GET.clear()
        return self.get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # sessionに値がある場合、その値をセットする。（ページングしてもform値が変わらないように）
        user_id = ''
        user_name = ''
        status = ''

        if 'form_value' in self.request.session:
            form_value = self.request.session['form_value']
            user_id = form_value[0]
            user_name = form_value[1]
            status = form_value[2]
        default_data = {'user_id': user_id,
                        'user_name': user_name,
                        'status': status,
                        }
        test_form = SearchForm(initial=default_data) # 検索フォーム
        context['test_form'] = test_form
        return context

    def get_queryset(self):
        # sessionに値がある場合、その値でクエリ発行する。
        if 'form_value' in self.request.session:
            form_value = self.request.session['form_value']
            user_id = form_value[0]
            user_name = form_value[1]
            status = form_value[2]
            # 検索条件
            condition_user_id = Q()
            condition_user_name = Q()
            condition_status = Q()
            if len(user_id) != 0 and user_id[0]:
                condition_user_id = Q(user_id__contains=user_id)
            if len(user_name) != 0 and user_name[0]:
                condition_user_name = Q(user_name__icontains=user_name)
            if len(status) != 0 and status[0]:
                condition_status = Q(status__icontains=status)
            return LabAttendanceTb.objects.select_related().filter(condition_user_id & condition_user_name & condition_status )
        else:
            # 何も返さない
            return LabAttendanceTb.objects.none()


from .models import PriceOfTicket
from django.db import transaction
import requests
import traceback
from datetime import datetime, timedelta

class ParserData:

    def __init__(self):
        self.headers = {
            'Content-Type': 'application/json'
        }
        self.respons = []
        self.data_by_date = {}

    def start_parse(self, url):
        responce = self.get_data(url)
        self.sort_by_date(responce)
        self.parse_data()

    def check_url(self, dict_check):
        response = self.get_data(dict_check["url"])
        self.cheking_data(response, dict_check["id"])

    def cheking_data(self, data, id):
        obj = PriceOfTicket.objects.get(pk=id)
        obj.flights_checked = data.get('flights_checked')
        obj.flights_invalid = data.get('flights_invalid')
        obj.price_change = data.get('price_change')
        obj.save()

    def get_data(self, url):
        try:
            response = requests.get(url=url, headers=self.headers)
            if response.status_code == 404:
                return
            if response.status_code != 200:
                raise ValueError('Request to {} responded with status {}'.format(url, response.status_code))
            else:
                return response.json()
        except Exception:
            raise Exception('Error in getting html\n' + str(traceback.format_exc()))

    def sort_by_date(self, response):
        data = response['data']
        for i in data:
            date = str(datetime.utcfromtimestamp(i['dTime']).strftime('%Y-%m-%d'))  # .strftime('%Y-%m-%d %H:%M:%S')
            if date in self.data_by_date:
                self.data_by_date[date].append(i)
            else:
                self.data_by_date[date] = []
                self.data_by_date[date].append(i)

    def parse_data(self):
        for k, v in self.data_by_date.items():
            seq_price = [x['price'] for x in v]
            min_price = min(seq_price)
            v = [x for x in v if x['price'] == min_price]
            rows_for_ins = []
            with transaction.atomic():
                for i in v:
                    PriceOfTicket.objects.filter(id_in_api=i["id"]).delete()
                    pot = PriceOfTicket(id_in_api=i["id"],
                                      date=k,
                                      city_from=i["cityFrom"],
                                      city_to=i["cityTo"],
                                      price=i["price"],
                                      booking_token=i["booking_token"])
                    rows_for_ins.append(pot)

                PriceOfTicket.objects.bulk_create(rows_for_ins)

def create_urls():
    from_to = [
        {'from': "ALA", "to": "TSE"},
        {'from': "TSE", "to": "ALA"},
        {'from': "ALA", "to": "MOW"},
        {'from': "MOW", "to": "ALA"},
        {'from': "ALA", "to": "CIT"},
        {'from': "CIT", "to": "ALA"},
        {'from': "TSE", "to": "MOW"},
        {'from': "MOW", "to": "TSE"},
        {'from': "TSE", "to": "LED"},
        {'from': "LED", "to": "RSE"},
    ]
    date_now = datetime.now().strftime("%d/%m/%Y")
    now_30 = (datetime.now() + timedelta(30)).strftime("%d/%m/%Y")
    urls = [
        f'https://api.skypicker.com/flights?fly_from={i["from"]}&fly_to={i["to"]}&date_from={date_now}&date_to={now_30}&partner=picky'
        for i in from_to]
    return urls

def check_urls():
    urls = []
    objs = PriceOfTicket.objects.all()
    for i in objs:
        url = f'https://booking-api.skypicker.com/api/v0.1/check_flights?v=2&booking_token={i.booking_token}' \
              '&bnum=1' \
              '&pnum=1' \
              '&affily=picky_{market}' \
              '&currency=EUR&' \
              'adults=1' \
              '&children=0' \
              '&infants=0'
        urls.append({"url": url, "id": i.id})
    return urls


# -*- coding: utf-8 -*-
import os
import xmltodict
import json
import xml.etree.ElementTree as ET
from utils.fileUtil import append_json, write_json

def remove_xml_special_chars(d):
    result = {}
    for key, value in d.items():
        if isinstance(value, dict):
            value = remove_xml_special_chars(value)
        elif isinstance(value, list):
            value = [remove_xml_special_chars(x) if isinstance(x, dict) else x for x in value]

        # 去掉其中的命名空间
        if ':' in key:
            new_key = key[key.index(':') + 1:]
            result[new_key] = value
        elif ('@' in key) or ('#' in key):
            new_key = key.replace('#', '').replace('@', '')
            result[new_key] = value
    return result

# 定义xml转json的函数
def xmltojson(xmlstr):
    # parse是的xml解析器
    xmlparse = xmltodict.parse(xmlstr)
    parse_dict = remove_xml_special_chars(xmlparse)
    # print(parse_dict)
    # json库dumps()是将dict转化成json格式，loads()是将json转化成dict格式。
    # dumps()方法的ident=1，格式化json
    jsonstr = json.dumps(parse_dict, ensure_ascii=False)
    return jsonstr

def readXml(filepath, loop_xpath, ns):
    '''read xml by elementTree
    input: xml filepath
    output: xml linelist to csv'''

    try:
        # prase to tree
        tree = ET.parse(filepath)
    except:
        print('xml损坏无法解析：', filepath)
        return None

    # loop_xpath
    root = tree.getroot()
    nodes = root.findall(loop_xpath, ns)
    # print(list(nodes))
    return [ET.tostring(node, encoding='utf-8', method='xml') for node in nodes]

def parse_xml_part(xml_ele_str):
    return xmltojson(xml_ele_str)

def handle_one_xml(xml_path):
    xml_name = os.path.basename(xml_path)
    xml_name_noext = os.path.splitext(xml_name)[0]
    # 读取xml
    nodes = readXml(xml_path, loop_xpath, ns)
    first_time = True
    for node in nodes:
        # 将该node转为json
        json_str = parse_xml_part(node)
        json_file = '%s/%s.json' % (json_dir, xml_name_noext)
        # 第一次覆盖写入，以后append进去
        if first_time:
            write_json(json_str, json_file)
            first_time = False
        else:
            append_json(json_str, json_file)

if __name__ == '__main__':
    # xml文件中一个里面有500个项目数据，需要先拆分开，然后使用xmltodict转为json，并保存下来
    # 配置
    xml_dir = r'F:\全球项目库数据\280_xml_3'
    json_dir = r'F:\全球项目库数据\json_all'
    ns = {'istic': 'http://matadata.istic.ac.cn/elements/2019',
          'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
          'xsd': 'http://www.w3.org/2001/XMLSchema'}
    loop_xpath = './istic:ProjectData/istic:Project'

    for base_dir, dir_names, xml_names in os.walk(xml_dir):
        for xml_name in xml_names:
            xml_path = os.path.join(base_dir, xml_name)
            handle_one_xml(xml_path)


import pandas as pd

def solution(info, query):
    answer = []

    lang_list = []
    stack_list = []
    career_list = []
    food_list = []
    score_list = []
    for inf in info :
        lang, stack, career, food, score = inf.split(' ')
        score = int(score)
        lang_list.append(lang)
        stack_list.append(stack)
        career_list.append(career)
        food_list.append(food)
        score_list.append(score)

    info_df = pd.DataFrame(data = {'언어' : lang_list,
                              '스택' : stack_list,
                              '경력' : career_list,
                              '소울푸드' : food_list,
                              '점수' : score_list})

    for q in query :
        lang, stack, career, food_score = q.split('and')
        lang = lang.strip()
        stack = stack.strip()
        career = career.strip()
        food_score = food_score.strip()
        food = food_score.split(' ')[0]
        score = int(food_score.split(' ')[1])

        new_df = info_df[info_df['점수'] >= score]

        if lang == '-' :
            pass
        else :
            new_df = new_df[new_df['언어'] == lang]

        if stack == '-' :
            pass
        else :
            new_df = new_df[new_df['스택'] == stack]

        if career == '-' :
            pass
        else :
            new_df = new_df[new_df['경력'] == career]

        if food == '-' :
            pass
        else :
            new_df = new_df[new_df['소울푸드'] == food]

        answer.append(len(new_df))
    return answer

# 시간초과
import pandas as pd

def solution(info, query):
    answer = []

    dataframe = pd.DataFrame()
    languages, stacks, careers, foods, scores = [], [], [], [], []
    for information in info: # O(50000)
        language, stack, career, food, score = information.split()
        languages.append(language)
        stacks.append(stack)
        careers.append(career)
        foods.append(food)
        scores.append(int(score))

    dataframe['언어'] = languages
    dataframe['직군'] = stacks
    dataframe['경력'] = careers
    dataframe['푸드'] = foods
    dataframe['점수'] = scores

    for q in query: # O(100000)
        language, stack, career, food_score = q.split('and')
        food, score = food_score.split()

        if language.strip() == '-': language = ''
        if stack.strip() == '-': stack = ''
        if career.strip() == '-': career = ''
        if food.strip() == '-': food = ''
        if score.strip() == '-': score = ''

        d_l = dataframe[dataframe['언어'] == language.strip()] if language else dataframe
        d_s = d_l[d_l['직군'] == stack.strip()] if stack else d_l
        d_c = d_s[d_s['경력'] == career.strip()] if career else d_s
        d_f = d_c[d_c['푸드'] == food.strip()] if food else d_c
        d_ss = d_f[d_f['점수'] >= int(score.strip())] if score else d_f
        answer.append(len(d_ss))
    return answer

# 시간초과
from itertools import product, combinations
import numpy as np

def solution(info, query):
    answer = []

    languages = ['cpp', 'java', 'python']
    stacks = ['backend', 'frontend']
    careers = ['junior', 'senior']
    foods = ['chicken', 'pizza']

    combination_dict = {'empty': []}
    for prod in list(product(languages, stacks, careers, foods)):
        for i in range(1, 5):
            for comb in combinations(prod, i):
                combination_dict[comb] = []

    for information in info:
        language, stack, career, food, score = information.split()
        combination_dict['empty'].append(score)
        for i in range(1, 5):
            for comb in combinations([language, stack, career, food], i):
                combination_dict[comb].append(score)

    for q in query:
        language, stack, career, food_score = q.split(' and ')
        food, score = food_score.split()

        name = []
        if language != '-': name.append(language)
        if stack != '-': name.append(stack)
        if career != '-': name.append(career)
        if food != '-': name.append(food)
        name = tuple(name)

        if not name:
            name = 'empty'

        check_score = combination_dict[name]

        check_score = combination_dict[name]
        check_score = list(map(int, check_score))
        check_score = np.array(check_score)
        count = len(check_score[check_score >= int(score)])

        answer.append(count)

        # count = 0
        # cnt = [1 if int(s) >= int(score) else 0 for s in check_score ]
        # answer.append(sum(cnt))
        # for s in check_score:
        #     if int(s) >= int(score):
        #         count += 1
        # answer.append(count)
    return answer

# 통과
from itertools import product, combinations

from typing import List

def binary_search(check_score: List, score: int) -> int:
    if len(check_score) == 0:
        return 0

    start, end = 0, len(check_score)-1

    min_idx = len(check_score)
    while start <= end:
        mid = (start + end) // 2

        if check_score[mid] >= score:
            end = mid-1
            min_idx = min(min_idx, mid)
        else:
            start = mid+1
    return len(check_score) - min_idx

def solution(info, query):
    answer = []

    languages = ['cpp', 'java', 'python']
    stacks = ['backend', 'frontend']
    careers = ['junior', 'senior']
    foods = ['chicken', 'pizza']

    combination_dict = {'empty': []}
    for prod in list(product(languages, stacks, careers, foods)):
        for i in range(1, 5):
            for comb in combinations(prod, i):
                combination_dict[comb] = []

    for information in info:
        language, stack, career, food, score = information.split()
        combination_dict['empty'].append(int(score))
        for i in range(1, 5):
            for comb in combinations([language, stack, career, food], i):
                combination_dict[comb].append(int(score))

    for key in combination_dict.keys():
        combination_dict[key].sort()

    for q in query:
        language, stack, career, food_score = q.split(' and ')
        food, score = food_score.split()

        name = []
        if language != '-': name.append(language)
        if stack != '-': name.append(stack)
        if career != '-': name.append(career)
        if food != '-': name.append(food)
        name = tuple(name)

        if not name:
            name = 'empty'

        check_score = combination_dict[name]

        count = binary_search(check_score, int(score))
        answer.append(count)

    return answer


import os
import re
import datetime
import importlib

from tornado.web import HTTPError
from traitlets import Dict

from multicontents.multi_versions_file_checkpoints import MultiVersionsFileCheckpoints

try:
    from jupyter_server.services.contents.manager import ContentsManager
except ImportError:
    from notebook.services.contents.manager import ContentsManager

DUMMY_CREATED_DATE = datetime.datetime.fromtimestamp(86400)

def build_base_model(
    type_,
    path,
    writable=True,
    last_modified=None,
    created=None,
    content=None,
    format=None,
    mimetype=None,
):
    return {
        "name": path.rstrip("/").rsplit("/", 1)[-1],
        "path": path,
        "writable": writable,
        "last_modified": last_modified or DUMMY_CREATED_DATE,
        "created": created or DUMMY_CREATED_DATE,
        "content": content,
        "mimetype": mimetype,
        "format": format,
        "type": type_,
    }

class WrapperManager(object):
    def __init__(self, proxy_path, manager_class, manager_kwargs):
        self.proxy_path = proxy_path
        if isinstance(manager_class, str):
            module_name, cls_name = manager_class.rsplit(".", 1)
            manager_class = getattr(importlib.import_module(module_name), cls_name)
        self.manager = manager_class(**manager_kwargs)

    def is_parent_directory_of(self, path):
        path = path.strip("/")
        proxy_folders = self.proxy_path.split("/") if self.proxy_path != "" else []
        path_folders = path.lstrip("/").split("/")
        return len(path_folders) >= len(proxy_folders) and "/".join(
            proxy_folders
        ) == "/".join(path_folders[: len(proxy_folders)])

    def is_sub_directory_of(self, path):
        path = path.strip("/")
        proxy_parent = ("/" + self.proxy_path).rsplit("/", 1)[0]
        return (
            proxy_parent.lstrip("/") == path.lstrip("/")
            and path.lstrip("/") != self.proxy_path
        )

    def to_actual_path(self, path):
        path = path.strip("/")
        if re.match(f"^{re.escape(self.proxy_path)}$", path):
            return ""
        return re.sub(f"^{re.escape(self.proxy_path)}/", r"/", path).strip("/")

    def to_proxy_path(self, actual_path):
        actual_path = actual_path.strip("/")
        return os.path.join(self.proxy_path, actual_path).strip("/")

    def get(self, path, *args, **kwargs):
        result = self.manager.get(self.to_actual_path(path), *args, **kwargs)
        if result.get("path", None):
            result["path"] = self.to_proxy_path(result["path"])
        if result.get("content", None) and self.dir_exists(path):
            result["content"] = [
                dict(
                    list(model.items()) + [("path", self.to_proxy_path(model["path"]))]
                )
                for model in result["content"]
            ]
        return result

    def save(self, model, path):
        return self.manager.save(model, self.to_actual_path(path))

    def delete_file(self, path):
        return self.manager.delete_file(self.to_actual_path(path))

    def file_exists(self, path=None):
        return self.manager.file_exists(self.to_actual_path(path))

    def dir_exists(self, path):
        return self.manager.dir_exists(self.to_actual_path(path))

    def is_hidden(self, path):
        return self.manager.is_hidden(self.to_actual_path(path))

    def rename_file(self, old_path, new_path):
        self.manager.rename_file(
            self.to_actual_path(old_path), self.to_actual_path(new_path)
        )

class MultiContentsManager(ContentsManager):

    managers = Dict(help="the path to manager_class settings").tag(config=True)

    def __init__(self, *args, **kwargs):
        super(MultiContentsManager, self).__init__(*args, **kwargs)
        self._managers = [
            WrapperManager(path.lstrip("/"), config["manager_class"], config["kwargs"])
            for path, config in self.managers.items()
        ]
        # path are searched based on the depth, so that we will always match
        # to the closest one first
        self._managers.sort(
            key=lambda manager: (
                manager.proxy_path == "",  # non root matched first
                -len(manager.proxy_path.split("/")),  # match deeper folder first
                -len(
                    manager.proxy_path.rsplit("/", 1)[-1]
                ),  # match longest directory name first
            )
        )

    def get_manager(self, path):
        for manager in self._managers:
            if manager.is_parent_directory_of(path):
                return manager
        raise HTTPError(404, f"Manager not found for path: '{path}'")

    def get(self, path, *args, **kwargs):
        try:
            manager = self.get_manager(path)
            current = manager.get(path, *args, **kwargs)
            is_dir = manager.dir_exists(path)
        except HTTPError as e:
            # if root is not configured, we build a virtual directory to list all
            # the defined path
            if path == "/" or path == "":  # jupyterlab use "/", but classic use ""
                current = build_base_model(
                    type_="directory",
                    path="/",
                    format="json",
                    content=[] if kwargs.get("content", None) else None,
                )
                is_dir = True
            else:
                raise e

        # add virtual directory
        if kwargs.get("content", None) and is_dir:
            extra = [
                build_base_model(
                    type_="directory", path=other_manager.to_proxy_path("")
                )
                for other_manager in self._managers
                if other_manager.is_sub_directory_of(path)
            ]
            current["content"] += extra
        return current

    def rename_file(self, old_path, new_path):
        old_manager = self.get_manager(old_path)
        new_manager = self.get_manager(new_path)

        # avoid renaming on virtual folder
        if (
            old_manager.to_actual_path(old_path) == ""
            or new_manager.to_actual_path(new_path) == ""
        ):
            raise HTTPError(400, reason="You cannot rename the virtual directory")

        if old_manager == new_manager:
            old_manager.rename_file(old_path, new_path)
        else:
            model = old_manager.get(old_path)
            new_manager.save(model, new_path)
            if self.dir_exists(old_path):
                for model in self.get(old_path)["content"]:
                    self.rename_file(
                        os.path.join(old_path, model["name"]),
                        os.path.join(new_path, model["name"]),
                    )
            old_manager.delete_file(old_path)

    def save(self, model, path):
        return self.get_manager(path).save(model, path)

    def delete_file(self, path):
        return self.get_manager(path).delete_file(path)

    def file_exists(self, path=None):
        return self.get_manager(path).file_exists(path)

    def dir_exists(self, path):
        if path == "":
            return True
        return self.get_manager(path).dir_exists(path)

    def is_hidden(self, path):
        if path == "":
            return False
        return self.get_manager(path).is_hidden(path)

    def _checkpoints_class_default(self):
        return MultiVersionsFileCheckpoints


from django.urls import path
from cities import views

app_name = 'cities'

urlpatterns = [
    # path('', views.home, name='home'),
    path('', views.CityListView.as_view(), name='home'),
    path('detail/<int:pk>/', views.CityDetailView.as_view(), name='detail'),
    path('update/<int:pk>/', views.CityUpdateView.as_view(), name='update'),
    path('delete/<int:pk>/', views.CityDeleteView.as_view(), name='delete'),
    path('add', views.CityCreateView.as_view(), name='create'),
]


import time
from selenium.webdriver.common.keys import Keys
from Config.config import TestData
from Pages.BasePages import BasePage
from selenium.webdriver.common.by import By

class ProfilePage(BasePage):

    CHANGE_INFO = (By.ID, "js--edit-personal")
    NAME = (By.XPATH,'//input[@class="form-control personal p-3 name"]')
    SAVE_BUTTON = (By.ID, "personalInfo")

    def __init__(self, driver):
        super().__init__(driver)
        self.driver.get(TestData.PROFILE_URL)

    def get_profile_page_title(self, title):
        return self.get_title(title)
    def do_change_info(self, name):
        self.do_click(self.CHANGE_INFO)
        self.do_send_keys(self.NAME, name)
        self.do_click(self.SAVE_BUTTON)


from pathlib import Path
from http import HTTPStatus

from flask import Blueprint, current_app, jsonify, request
from flask_babel import gettext as _

from reforis.foris_controller_api.utils import validate_json, APIError

# pylint: disable=invalid-name
blueprint = Blueprint(
    'Nextcloud',
    __name__,
    url_prefix='/nextcloud/api',
)

BASE_DIR = Path(__file__).parent

# pylint: disable=invalid-name
nextcloud = {
    'blueprint': blueprint,
    # Define {python_module_name}/js/app.min.js
    # See https://gitlab.labs.nic.cz/turris/reforis/reforis-distutils/blob/master/reforis_distutils/__init__.py#L11
    'js_app_path': 'reforis_nextcloud/js/app.min.js',
    'translations_path': BASE_DIR / 'translations',
}

@blueprint.route('/nextcloud', methods=['GET'])
def get_status():
    return jsonify(current_app.backend.perform('nextcloud', 'get_status'))

@blueprint.route('/nextcloud', methods=['POST'])
def configure_nextcloud():
    validate_json(request.json)

    response = current_app.backend.perform(
        'nextcloud', 'configure_nextcloud', request.json
    )
    if response.get('result') is not True:
        raise APIError(
            _('Cannot configure Nextcloud'), HTTPStatus.INTERNAL_SERVER_ERROR
        )

    return jsonify(response), HTTPStatus.ACCEPTED


import datetime
import time
from typing import Dict

from .request import BookingMethod, VenueAvailability, search_availability

_MAIL_FORMAT = """
<!DOCTYPE html>
<html>
<body>
{body}
</body>
</html>
"""
_NEW_AVAILABILITY_FORMAT = """Date: {date}
{availability}
"""

def _send_mail(
    email: str,
    new_availabilities: Dict[datetime.datetime, VenueAvailability],
) -> None:
    availabilities_str = "\n".join(
        _NEW_AVAILABILITY_FORMAT.format(
            date=date.strftime("%d/%m/%Y"),
            availability=availability.to_html(),
        )
        for date, availability in new_availabilities.items()
    )
    body = _MAIL_FORMAT.format(body=availabilities_str)
    print(body)

def poll_venue(
    email: str,
    start_date: datetime.datetime,
    table_size: int,
    interval: int,
    venue_id: str,
):
    found_availabilities: Dict[int, VenueAvailability] = dict()
    while True:
        new_availabilities: Dict[
            datetime.datetime,
            VenueAvailability,
        ] = dict()
        for day_delta in range(7):
            date = start_date + datetime.timedelta(days=day_delta)
            availability = search_availability(
                table_size=table_size,
                date=date,
                venue=venue_id,
            )

            if availability.method == BookingMethod.DISABLED:
                print(
                    "[-] No booking options for ",
                    f"{date.strftime('%d/%m/%Y')}",
                )
                continue

            current_found_availability = found_availabilities.get(day_delta)
            if (
                current_found_availability is None
                or current_found_availability != availability
            ):
                found_availabilities[day_delta] = availability
                new_availabilities[date] = availability
            else:
                print(
                    "[-] Skipping known booking options for "
                    f"{date.strftime('%d/%m/%Y')}",
                )

        if len(new_availabilities) > 0:
            _send_mail(email, new_availabilities)

        time.sleep(interval * 60)


"""
Algorithm:
----------
A3C algorithm.

Reference:
----------
Tensorlayer: https://github.com/tensorlayer/tensorlayer/blob/master/examples/reinforcement_learning/tutorial_A3C.py
MorvanZhou's tutorial: https://morvanzhou.github.io/tutorials/

Environment:
------------
CartPole-v0
CartPole-v1
#MountainCar-v0

Prerequisites:
--------------
tensorflow 2
gym

"""

"""
Algorithm:
----------
A3C algorithm. This code can be used to continuous action space game by
modifying function self.sample_action.

Reference:
----------
Tensorlayer: https://github.com/tensorlayer/tensorlayer/blob/master/examples/reinforcement_learning/tutorial_A3C.py
MorvanZhou's tutorial: https://morvanzhou.github.io/tutorials/

Environment:
------------
CartPole-v0
CartPole-v1
#MountainCar-v0

Prerequisites:
--------------
tensorflow 2
gym

"""

import tensorflow as tf
from tensorflow.keras.layers import Dense,Input
import numpy as np
import gym
import threading
import multiprocessing
import matplotlib.pyplot as plt

ENV_NAME = 'CartPole-v1'
N_LAYERS = [96]
LR_CRITIC = 1e-2
LR_ACTOR = 1e-3
N_STEPS = np.inf # default: 10
GAMMA = 0.99
ENTROPY_BETA=0.01
MAX_GLOBAL_EPISODES = 1500
NUM_WORKERS = multiprocessing.cpu_count()
RENDER = False
SEED = 116

class ActorCritic(object):
    def __init__(self, state_dim, action_num):
        self.state_dim=state_dim
        self.action_num=action_num

        self.actor=self.build_net(N_LAYERS, self.action_num)
        self.critic=self.build_net(N_LAYERS,1)

    def build_net(self, n_layers, output_size):
        kernel_init = tf.random_uniform_initializer(0, 0.01)
        bias_init = tf.constant_initializer(0.01)
        inputs=Input(shape=[self.state_dim,])
        for i in range(len(n_layers)):
            if i==0:
                x=Dense(n_layers[i],activation=tf.nn.leaky_relu,kernel_initializer=kernel_init,bias_initializer=bias_init)(inputs)
            else:
                x=Dense(n_layers[i],activation=tf.nn.leaky_relu,kernel_initializer=kernel_init,bias_initializer=bias_init)(x)
        y=Dense(output_size,activation=None,kernel_initializer=kernel_init,bias_initializer=bias_init)(x)
        return tf.keras.Model(inputs=inputs,outputs=y)

    def sample_action(self,observation):
        # shape: (state_dim,) => (1, state_dim)
        observation = observation[np.newaxis, :]
        # shape: (1, action_num)
        logits = self.actor(observation)
        probs = tf.nn.softmax(logits)
        # np scalar
        action = np.random.choice(np.arange(self.action_num), p=probs.numpy()[0])
        return action

    def update_global(self,observations,actions,n_step_returns,master):
        """update critic"""
        with tf.GradientTape() as tape:
            # shape: (batch, 1)
            vs=self.critic(observations)
            advantages=n_step_returns-vs
            # tensor scalar
            critic_loss=tf.math.reduce_mean(tf.math.square(advantages))
        critic_grad=tape.gradient(critic_loss,self.critic.trainable_variables)
        master.share_critic_optimizer.apply_gradients(zip(critic_grad,master.share_ACnet.critic.trainable_variables))

        """update actor"""
        with tf.GradientTape() as tape:
            # shape (batch, action_num)
            logits = self.actor(observations)
            prob = tf.nn.softmax(logits)
            # shape (batch, 1)
            log_prob = tf.math.reduce_sum(tf.math.log(prob+1e-10) * tf.one_hot(actions, depth=self.action_num), axis=1)
            # entropy to encourage exploration, output shape: (batch,1)
            entropy = -tf.math.reduce_sum(prob*tf.math.log(prob+1e-10),axis=1)
            # loss
            actor_loss=tf.reduce_mean(-advantages*log_prob-ENTROPY_BETA*entropy)
        actor_grad=tape.gradient(actor_loss,self.actor.trainable_variables)
        master.share_actor_optimizer.apply_gradients(zip(actor_grad,master.share_ACnet.actor.trainable_variables))

    def pull_global(self,master):
        for l_p, g_p in zip(self.critic.trainable_weights, master.share_ACnet.critic.trainable_weights):
            l_p.assign(g_p)
        for l_p, g_p in zip(self.actor.trainable_weights, master.share_ACnet.actor.trainable_weights):
            l_p.assign(g_p)

class Worker(object):
    def __init__(self,work_name,state_dim,action_num):
        self.work_name=work_name
        self.env=gym.make(ENV_NAME)
        self.local_AC=ActorCritic(state_dim,action_num)

    def work(self,master):
        while not COORD.should_stop() and master.global_episodes<MAX_GLOBAL_EPISODES:
            observation_buffer, action_buffer, reward_buffer = [], [], []
            ob=self.env.reset()
            ob = ob.astype(np.float32)
            ep_r=0
            while True:
                if RENDER and self.work_name == 'Worker_0' and master.global_episodes>MAX_GLOBAL_EPISODES/2:
                    self.env.render()

                ac = self.local_AC.sample_action(ob)
                ob_, rew, done, _ = self.env.step(ac)
                ob_=ob_.astype(np.float32)

                ep_r += rew
                observation_buffer.append(ob)
                action_buffer.append(ac)
                reward_buffer.append(rew)

                if len(reward_buffer)==N_STEPS or done:
                    if done:
                        v_ = 0.
                    else:
                        v_ = self.local_AC.critic(ob_[np.newaxis,:])[0,0] # (1,1) => scalar
                        v_ = v_.numpy()

                    n_step_returns = []
                    for r in reward_buffer[::-1]:
                        v_ = r+ GAMMA * v_
                        n_step_returns.append(v_)
                    n_step_returns.reverse()

                    # list => Tensor (batch, dim)
                    observation_buffer=tf.convert_to_tensor(np.vstack(observation_buffer),dtype=tf.float32)
                    #action_buffer=tf.convert_to_tensor(np.vstack(action_buffer),dtype=tf.float32)
                    n_step_returns=tf.convert_to_tensor(np.vstack(n_step_returns),dtype=tf.float32)

                    # update global networks
                    self.local_AC.update_global(observation_buffer,action_buffer,n_step_returns,master)
                    observation_buffer,action_buffer,reward_buffer=[],[],[]

                    # update local network
                    self.local_AC.pull_global(master)
                ob = ob_
                if done:
                    print("Training | {}, Episode:{}/{} | Episode Reward: {:.1f}".format(
                        self.work_name,master.global_episodes,MAX_GLOBAL_EPISODES,ep_r))
                    master.global_episodes += 1
                    master.global_episode_rewards.append(ep_r)
                    break

class Master(object):
    def __init__(self,state_dim,action_num):
        self.share_ACnet=ActorCritic(state_dim=state_dim,action_num=action_num)
        self.share_actor_optimizer=tf.optimizers.Adam(learning_rate=LR_ACTOR)
        self.share_critic_optimizer=tf.optimizers.Adam(learning_rate=LR_CRITIC)
        self.global_episodes=0
        self.global_episode_rewards=[]

if __name__=="__main__":
    # reproducible
    np.random.seed(SEED)
    tf.random.set_seed(SEED)

    """get env parameters"""
    env=gym.make(ENV_NAME)
    state_dim = env.observation_space.shape[0]
    action_num = env.action_space.n
    env.close()

    """create a global actor critic"""
    master = Master(state_dim=state_dim,action_num=action_num)

    """Threading"""
    workers=[]
    for i in range(NUM_WORKERS):
        i_name='Worker_%i' % i
        workers.append(Worker(work_name=i_name,state_dim=state_dim,action_num=action_num))
    COORD=tf.train.Coordinator()
    workers_threads=[]
    for worker in workers:
        job = lambda : worker.work(master)
        t=threading.Thread(target=job)
        t.start()
        workers_threads.append(t)
    COORD.join(workers_threads)

    plt.figure()
    plt.plot(master.global_episode_rewards)
    plt.xlabel('episodes')
    plt.ylabel('total reward per episode')
    plt.show()


import CoreNetwork.CoreNetworkModel as cn
import CoreNetwork.ModelParameters as mp
import CoreNetwork.Optimizers as asop
import tensorflow as tf
import json
import numpy as np

class KModelSelector(object):

    def __init__(self):
        self._configs = self._getconfigs()
        self._learning_rate = 0.01
        self._optimizers = self._getOptimizers()
        self._epochs = 5
        self._minibatchsize = 200

    def _getOptimizers(self):
        opts = [
            tf.train.GradientDescentOptimizer(learning_rate=self._learning_rate),
            asop.ASGradientDescentOptimizer(base_learning_rate=self._learning_rate),
            tf.train.RMSPropOptimizer(learning_rate=self._learning_rate),
            asop.ASRMSPropOptimizer(base_learning_rate=self._learning_rate),
            tf.train.AdamOptimizer(learning_rate=self._learning_rate),
            tf.train.MomentumOptimizer(learning_rate=self._learning_rate, momentum=.9),
            tf.train.MomentumOptimizer(learning_rate=self._learning_rate, momentum=.9, use_nesterov=True),
            tf.train.AdagradOptimizer(learning_rate=self._learning_rate)
        ]
        opt_names = ['SGD',
                     'SGD+AS',
                     'RMSProp',
                     'RMSProp+AS',
                     'ADAM',
                     'SGD+M',
                     'SGD+NM',
                     'Adagrad'
                     ]
        return zip(opts,opt_names)

    def _getconfigs(self):
        fpath = "D:\\BecomingADS\\KerasTFLab\\KModelSelector\\ModelSelectionConfig.json"
        with open(fpath) as f:
            _configs = json.load(f)
            return _configs

    def GetExperiments(self,Tag):
        tagconfigs = self._configs
        tagfns = tagconfigs[Tag]
        return tagfns

    def RunExperiments(self,Tag, X, Y, features, num_classes):
        tagf = self.GetExperiments(Tag)
        for l in tagf:
            getattr(KModelSelector,l)(self, X, Y, features, num_classes)

    def _train(self, modelparameters, X, Y):
        losses = []
        for optimizer, optimizername in (self._optimizers):
            init1 = tf.global_variables_initializer()
            with tf.Session() as sess:
                sess.run(init1)
                network = cn.CoreNetwork(modelparameters)
                loss = network.train(sess, X, Y, self._epochs, optimizer, self._minibatchsize, optimizername)
                losses.append(loss)
            tf.reset_default_graph()

        return losses

    def BuildLogisticRegressionModel(self,X,Y,features,num_classes):
        model_p = mp.ModelParameters(input_feature_count=features, layers=[], activations=[], outputclasses=num_classes)
        losses = self._train(model_p,X,Y)
        return losses

    def BuildANNModel2Layers(self,X,Y,features,num_classes):
        model_p = mp.ModelParameters(input_feature_count=features, layers=[20, 5], activations=["relu", "relu"],
                                     outputclasses=num_classes)
        losses = self._train(model_p, X, Y)
        return losses

    def BuildANNModel3Layers(self,X,Y,features,num_classes):
        model_p = mp.ModelParameters(input_feature_count=features, layers=[20, 5, 10], activations=["relu", "relu","relu"],
                                     outputclasses=num_classes)
        losses = self._train(model_p, X, Y)
        return losses

    def BuildConvNet1(self,X,Y,features,num_classes):
        return "return Convnet 1"

    def BuildConvNet2(self,X,Y,features,num_classes):
        return "return Convnet 2"


"""Defines the URL patterns for the pizzas app"""

from django.urls import path

from . import views

app_name = 'pizzas'
urlpatterns = [
    path('', views.index, name="index"), # Home page
    path('pizzas/', views.pizzas, name='pizzas'), # Page that shows all pizzas
    path('pizzas/<int:pizza_id>/', views.toppings, name='toppings'), # Page that show all toppings for a pizza
]


#!/usr/bin/env python

import sys
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde

df = pd.read_table(sys.argv[1])

fpkm = df["FPKM"]
density = gaussian_kde(fpkm)
xs = np.linspace(0,140, 1000)
density.covariance_factor = lambda : .25
density._compute_covariance()

plt.figure()
plt.title("FPKM density plot of SRR07893")
plt.plot(xs, density(xs))
plt.ylabel("Density")
plt.xlabel("FPKM")
#plt.hexbin(df["FPKM"] +1, df2["FPKM"]+1) #gives density of points as well
plt.savefig("densityplot.png")
plt.close()


"""
utils.py - module to implement utils for BiLSTM-CRF
"""

# import dependencies
import os
import tensorflow as tf
import numpy as np
import pandas as pd
from sklearn.utils import shuffle
from tensorflow.keras.utils import Sequence, to_categorical
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization

def process_text(input, word_table, training = True):
	"""
	Function process_text to clean text before Training process:
		- lowercase
		- tokenize

	--Notice--
		Punctuation stripping is not done here the dgiven dataset is clean. Also, punctuation is also considered as features as well.
	Inputs:
		- input : Tensor
			A single text line of sequence of words-tags
		- word_table : Tensorflow table lookup
			Table lookup to convert word to index
		- training : Boolean
			Inference: return tokens and encoded tokens
			Training: return encodedo tokens
	Outputs:
		- input : Tensor
			Tensor of shape [sequence_length]
	"""
	print(input)
	# lowercase string
	input = tf.strings.lower(input)
	print(input)
	# tokenize
	tokens = tf.strings.split(input)
	print(tokens)
	# convert string to integer
	output = word_table.lookup(tokens)

	if training:
		return output
	else:
		return tokens, output

def process_target(inputs, tag_table):
	"""
	Function process_target to clean/process target for Training process:
		- tokenize
		- convert to full categoricals
	Inputs:
		- inputs : tensor
			A single text line of sequences of words-tags
		- tag_table : Tensor lookup table
			Table lookup to convert tag to index
	Outputs:
		- input: tensor
			Tensor of shape [sequence_length, n_tags]
	"""

	# tokenize
	inputs = tf.strings.split(inputs)

	# convert string to integer
	inputs = tag_table.lookup(inputs)

	# expand targets to number of tags
	inputs = tf.one_hot(inputs, depth = tf.cast(tag_table.size(), dtype = tf.int32), dtype = tf.int64)
	return inputs

class SentenceGetter(Sequence):
	"""
	Inheritted class from tf.keras.utils.Sequence class to efficiently load
	data to Tensorflow/Keras model
	"""
	def __init__(self, data, words, tags, maxlen, batch_size = 16, shuffle = False):
		"""
		__init__ - initializer for SentenceGetter class
		Inputs:
			- data : String or Pandas DataFrame object
				Path string to file or dataframe object
			- words : set
				Set of distinct words
			- tags : set
				Set of distinct tags
		"""

		if isinstance(data, str):
			# load data from Pandas file path
			data = pd.read_csv(data, encoding = 'latin1')
		elif isinstance(data, pd.DataFrame):
			# load data from Pandas DataFrame
			data = data
		else:
			raise Exception('Data is None or not found')
		self.word2dix = {w : i + 1 for i, w in enumerate(words)}
		self.tag2dix = {t : i for i, t in enumerate(tags)}
		self.n_tags = len(tags)
		self.batch_size = batch_size
		self.shuffle = shuffle
		self.maxlen = maxlen
		n_sent = 1
		self.grouped = data.groupby('Sentence #').apply(self.agg_func)\
			.reset_index().rename(columns = {0 : 'sentence'})['sentence']
		self.sentences = [s for s in self.grouped]

	def agg_func(self, input):
		"""
		agg_func - function to group words/tags of sentences together
		"""
		print(input)
		return [(w, p, t) for w, p, t in zip(input['Word'].values.tolist(),
			input['POS'].values.tolist(), input['Tag'].values.tolist())]

	def pad_sentences(self, input):
		input = [[self.word2dix[w[0]] for w in s] for s in input]
		return pad_sequences(maxlen = self.maxlen, sequences = input, padding = 'post', value = 0)

	def generate_labels(self, input):
		input = [[self.tag2dix[w[2]] for w in s] for s in input]
		input = pad_sequences(maxlen = self.maxlen, sequences = input, padding = 'post', value = self.tag2dix['O'])

		return np.array([to_categorical(x, num_classes = self.n_tags) for x in input])
	def __len__(self):
		"""
		__len__ - function to compute length of SentenceGetter
		"""
		return int(self.grouped.shape[0] // self.batch_size)

	def __getitem__(self, index):
		if index == 0 and self.shuffle:
		# shuffle dataset for every iteration
			self.grouped = shuffle(self.grouped).reset_index()['sentence']

		# get batch of data
		sentences = self.grouped[index * self.batch_size : (index + 1) * self.batch_size]

		# generate sentences and labels
		labels = self.generate_labels(sentences)
		sentences = self.pad_sentences(sentences)

		return sentences, labels


#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为：“对于有根树 T 的两个结点 p、q，最近公共祖先表示为一个结点 x，满足 x 是 p、q 的祖先且 x 的深度尽可能大（一个节点也可以是它自己的祖先）。”

例如，给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4]

示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

示例 2:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。

说明:

所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。

"""

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        # 如果为空，后者两者其中有一个相等，那么就就返回，因为本身就可能就是 根节点
        if not root or root == p or root == q:
            return root
        # 如果判断其是否为左右子树
        l = self.lowestCommonAncestor(root.left, p, q)
        r = self.lowestCommonAncestor(root.right, p, q)
        # 如果左子树
        if not l:
            return r
        if not r:
            return l
        return root

from typing import Optional

class Solution1:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 这种情况处理的是 非结构化的 树结构同步

        # 1. 分别获取 root >>> ndoe 的path
        # 2. 双指针 从 根节点 判断共同的 数值，然后找到不相同的上一个 node 就是最近的公共节点。
        p_path = self.dfs(root,p,[])
        q_path = self.dfs(root,q,[])

        if p in q_path and p not in q_path:
            return p
        elif p not in q_path and p in q_path:
            return q
        else:
            num = min(len(q_path),len(p_path))
            res = root
            for i in range(1,num):
                if p_path[i]==q_path[i]:
                    res=p_path[i]
            return res

    # 找到root>>>node 的path
    def dfs(self,root:Optional[TreeNode],node:TreeNode,path:list[TreeNode]) -> list[TreeNode]:
        if root is None and node not in path:
            return []
        if node in path:
            return path

        path.append(root)

        return self.dfs(root.left,node,path[:]) or self.dfs(root.right,node,path[:])

算法分析和归类/树/二叉树的最近公共祖先.py

二叉树的最近公共祖先.py


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

import base64
import urllib2
import json
import time
import sys
import syslog
import subprocess
import zlib
import bz2
import os
from hashlib import md5
from Crypto.Cipher import AES
from Crypto import Random

hostname = ''
apikey = ''
secret = ''

url_format = '\nT\x9d$\xd5\xbac\x9fnC\x7f\xe8\x96;\xa7\xe5\x7f\xc5[\x01a\x1d\x8e\xe1u\x8eY\xb0\x9d\x84M1\xe8O\x8a\xaf\xa8 \x08\x9a\x07\xfd,\x1e\xf3\xe1\x0b\xe1\xe8\x18\xd6+Y\xfd\x18bycd\x14\x12\\\x86"'
payload = '\xe7\x83\xfcEU9\x125_A#\xc3\x18r&\xe3dk\x8aE\x14\xe5\x9c,7\xcc\xd2M\x0cM\xfa\t7)\xef\x1an;<\x16\xd2?\x83\x8b\xd8\x16\x9fy/a\x0b\xf9cC\xfa\x06\xb8\xc8f\x81=\x842\x0cRsL\xf4v\xc7\x83\xa6\xb5d\x94\xb3u\xae\xd8\xec\xd5\xc3%\xa9\xda\xda:\xdb\xf9-*\xf8\x17\x82\x90\x93'
syslog.openlog(ident='ddns_updater')
dprint = syslog.syslog

def encrypt_text(key, text):
    IV = ''
    for i in range(16):
        IV += chr(int(i))
    encryptor = AES.new(key, AES.MODE_CBC, IV)
    return encryptor.encrypt(text + ' ' * (16 - len(text)%16))

def decrypt_text(text):
    IV = ''
    for i in range(16):
        IV += chr(int(i))
    key = 'BZh91AY&SYA\x11\xb4i\x00\x00\t\xdc\xfc\xc0\x1b\x80L\x02\x00\x00\x082D\x00\x13\x10\x04\x00\x14\x00\x82\x00\x17L\x00 \x001\x8c\x00\x13\x00\x010\xc7\xa9\xa6\x86\x8fDhhy4\xca\x18N\x94\x15\x94\x06\xc1\x13\x97\x00K\xf475\xd0\xadT\xaa\x19 \xb33\x07\xe2\xeeH\xa7\n\x12\x08"6\x8d '

    decryptor = AES.new(base64.b64decode(zlib.decompress(bz2.decompress(key))), AES.MODE_CBC, IV)
    return decryptor.decrypt(text)

def derive_key_and_iv(password, salt, key_length, iv_length):
    d = d_i = ''
    while len(d) < key_length + iv_length:
        d_i = md5(d_i + password + salt).digest()
        d += d_i
    return d[:key_length], d[key_length:key_length+iv_length]

def get_domain_ip():
    global url_format
    url = decrypt_text(url_format).format(hostname)
    headers = {'Authorization': 'sso-key {}:{}'.format(apikey, secret),
               'Accept': 'application/json'}

    request = urllib2.Request(url, headers=headers)
    response = urllib2.urlopen(request)
    if response.getcode() == 200:
        json_data = json.load(response)
        return json_data[0]['data'] if json_data else ''
    else:
        dprint('err. domain resp code: {}'.format(response.getcode()))
        return ''

def get_public_ip():
    request = urllib2.Request('http://ipv4.icanhazip.com/')
    response = urllib2.urlopen(request)
    pubIP = str(response.read())
    if response.getcode() == 200:
        return pubIP.strip()
    else:
        dprint('err. public resp code: {}'.format(response.getcode()))
        dprint('retrying with different website...')
        request = urllib2.Request('http://ipinfo.io/json')
        response = urllib2.urlopen(request)
        json_data = json.load(response)
        return json_data['ip']

def update_domain_record(pubIP):
    global url_format
    data = json.dumps([{"data": pubIP, "ttl": 3600, "name": hostname, "type": "A"}])
    url = decrypt_text(url_format).format(hostname)
    headers = {'Authorization': 'sso-key {}:{}'.format(apikey, secret),
               'Content-Type': 'application/json',
               'Accept': 'application/json'}
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    req = urllib2.Request(url, headers=headers, data=data.encode('utf-8'))
    req.get_method = lambda:"PUT"
    response = opener.open(req)
    return response.getcode()

def main():
    global apikey, secret, hostname, payload
    # exit code. 1: invalid key, 2. no info file, 3: invalid hash, 4: invalid id, 5: no internet
    if not os.path.isfile('.info.txt'):
        if len(sys.argv) == 3:
            dprint('generating new information file...')
            key, _, _ = decrypt_text(payload).split(':')
            if key != sys.argv[2]:
                dprint('invalid key')
                sys.exit(1)

            hostname = sys.argv[1]
            p = subprocess.Popen('grep Serial /proc/cpuinfo'.split(), stdout=subprocess.PIPE)
            uniq_id = p.communicate()[0].split(':')[1].strip()
            text= ':'.join([hostname, uniq_id, md5(hostname + ':' + uniq_id).hexdigest()])
            enc_data = encrypt_text(sys.argv[2], text)
            with open('.info.txt', 'w') as f:
                f.write(encrypt_text(sys.argv[2], text))
                f.flush()
            dprint('new .info.txt file generated.')
        else:
            dprint('cannot find information file...')
            sys.exit(2)
        sys.exit(0)

    with open('.info.txt', 'rb') as f:
        enc_data = ''.join(f.readlines())

    hostname, uniq_id, hashvalue = decrypt_text(enc_data).split(':')

    if md5(hostname + ':' + uniq_id).hexdigest().strip() != hashvalue.strip():
        dprint('incorrect hash value - original: {}, calcualted: {}'.format(hashvalue.strip(),
                                          md5(hostname + ':' + uniq_id).hexdigest().strip()))
        sys.exit(3)

    dec_payload = decrypt_text(payload).split(':')
    key, apikey, secret = dec_payload

    try:
        p = subprocess.Popen('grep Serial /proc/cpuinfo'.split(), stdout=subprocess.PIPE)
        stdout, stderr = p.communicate()
    except:
        stdout = ''

    if not uniq_id.strip() in stdout:
        dprint('not approved Opi id - original: {}, current: {}'.format(uniq_id, stdout.split(':')[1]))
        sys.exit(4)

    try:
        domainIP = get_domain_ip()
        pubIP = get_public_ip()
        if domainIP != pubIP:
            dprint('updating domain ip addr...')
            ret = update_domain_record(pubIP)
            dprint('updating domain ret: {}'.format(ret))
        else:
            dprint('domain ip same as public ip...')
    except Exception as e:
        dprint('err: {}. no internet conn...'.format(e))
        sys.exit(5)

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-
"""
First application with pyQtGraph / Spyder in PyQt5 graphical QMainWindow

Author : Julien VILLEMEJANE
Laboratoire d Enseignement Experimental - Institut d Optique Graduate School
Created on Sat Jan 28 20:34:05 2023

@author: julien.villemejane
@see https://www.pythonguis.com/tutorials/plotting-pyqtgraph/
@see https://www.aranacorp.com/fr/afficher-un-signal-dans-pyqt-avec-pyqtgraph/
"""

from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (
    QApplication, QDialog, QMainWindow, QMessageBox, QWidget
)
from PyQt5.uic import loadUi

import sys
import numpy as np

SAMPLES = 10

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__(parent=None)
        loadUi("IHM_PyQtGraph_v1_inPyQt.ui", self)
        self.refreshBt.clicked.connect(self.refreshGraph)

        self.plotWidget = pg.PlotWidget()
        self.mainLayout.addWidget(self.plotWidget)

        self.x = np.linspace(0, SAMPLES, SAMPLES)
        self.data = np.random.random_sample(size=SAMPLES)

        self.plotWidget.setBackground('w')
        self.plotWidget.setYRange(0, 1, padding=0)

        self.pen = pg.mkPen(color=(255, 0, 0), width=5)
        self.plot1 = self.plotWidget.plot(self.x, self.data, pen=self.pen)

    def refreshGraph(self):
        print("refresh")
        self.plotWidget.removeItem(self.plot1)
        self.data = np.random.random_sample(size=SAMPLES)
        self.plot1 = self.plotWidget.plot(self.x, self.data, pen=self.pen)

    def closeEvent(self, event):
        QApplication.quit()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


from django.http import response
from django.test import TestCase
from django.urls import reverse
from django.db.models import QuerySet
from points.models import Points
from .factories import PointsFactory

class PointsListTestCase(TestCase):
    def test_open_list_success(self):
        point_1 = PointsFactory(name='Cool place', description='Visit any time')
        point_2 = PointsFactory()

        url = reverse('points-list')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        points = response.context.get('points')
        self.assertIsInstance(points, QuerySet)

        self.assertEqual('Location - 1', points[1].location)
        self.assertEqual(points[0].description, 'Visit any time')

class PointsCreateTestCase(TestCase):
    def test_create_place_success(self):
        url = reverse('create-points')
        data = {
            'name': "Issyk-Kul",
            'location': "Kara-Kol region",
            'description': "Lake in KG"
        }
        response = self.client.post(url, data)
        points = Points.objects.last()
        self.assertEqual(points.name, "Issyk-Kul")