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

from __future__ import unicode_literals, absolute_import

import logging
import pickle

from angr import AngrTranslationError
from farnsworth.models import Test, Exploit, RopCache
import rex
import tracer
from simuvex import SimUnsatError

from . import CRSTracerCacheManager
import worker.workers
LOG = worker.workers.LOG.getChild('rex')
LOG.setLevel('DEBUG')

logging.getLogger('rex').setLevel('INFO')

class RexWorker(worker.workers.Worker):

    def __init__(self):
        super(RexWorker, self).__init__()
        self._exploits = None
        self._crash = None
        self._crashing_test = None
        self._needs_retrace = False

    @staticmethod
    def _get_pov_score(exploit):
        return exploit.test_binary(enable_randomness=True, times=10).count(True) / 10.0

    def _save_exploit(self, exploit, crashing_test):
        LOG.info("Adding %s type %d", exploit.method_name, exploit.cgc_type)
        type_name = 'type%d' % exploit.cgc_type

        exploit = Exploit.create(cs=self._cs, job=self._job, pov_type=type_name,
                                 method=exploit.method_name, blob=exploit.dump_binary(),
                                 c_code=exploit.dump_c(), crash=crashing_test)

        return exploit

    def craft_leaks(self, crash):
        if not crash.leakable():
            LOG.error("Attempted to leak from a crash which cannot be leveraged for leaking")
            return

        try:
            for flag_leak in crash.point_to_flag():
                LOG.debug("Dumping possible leaking input to tests")
                test, created = Test.get_or_create(cs=self._cs, job=self._job, blob=flag_leak)
                if created:
                    LOG.debug("New flag leaking test id %d", test.id)
        except rex.CannotExploit:
            LOG.warning("Crash was leakable but was unable to point read at flag page")

    def forge_ahead(self, crashing_test, crash):
        while crash.explorable():
            # simultaneously explore and dump the new input into a file
            crash.explore("/tmp/new-testcase")

            # upload the new testcase
            Test.get_or_create(cs=self._cs, job=self._job, blob=open("/tmp/new-testcase").read())

            crashing_test.explored = True
            crashing_test.save()

            # dump a point-to-flag input if it's leakable
            if crash.leakable:
                self.craft_leaks(crash)

        return crash

    def exploit_crash(self, crashing_test, crash):
        e_pairs = []
        for exploit in crash.yield_exploits():
            e_pairs.append((exploit, self._save_exploit(exploit, crashing_test)))

        crashing_test.exploited = True
        crashing_test.save()

        # safety loop, make sure we don't throw-away working exploits because of memory issues
        for exploit, e_db in e_pairs:
            e_db.reliability = 0.1 if exploit.test_binary() else 0.0
            e_db.save()

        # do this in a seperate loop to make sure we don't kill the worker before adding exploits
        for exploit, e_db in e_pairs:
            e_db.reliability = self._get_pov_score(exploit)
            e_db.save()

        # do we need to retrace without atoi hookups?
        if all([e.reliability == 0 for _, e in e_pairs]) and self._needs_retrace:
            self._needs_retrace = False

            self.tracer_cache = CRSTracerCacheManager(atoi_flag=False)
            self.tracer_cache.cs = self._cs
            tracer.tracer.GlobalCacheManager = self.tracer_cache

            LOG.warning("Exploit had 0 reliability with formated atoi info, rerunning without atoi info")
            self._run_rex()

    def _get_atoi_infos(self):
        """Run rex on the crashing testcase."""

        # Hook up atoi stuff
        atoi_infos = worker.workers.AtoiManager.get_atoi_info(self._cs.symbols)
        if len(atoi_infos) > 0:
            self._needs_retrace = True
            self.tracer_cache = CRSTracerCacheManager(atoi_flag=True)
            self.tracer_cache.cs = self._cs
            tracer.tracer.GlobalCacheManager = self.tracer_cache
            for a in atoi_infos:
                LOG.info("hooking %#x, %s", a.addr, a.func_name)
            LOG.info("Hooked up %d atoi infos", len(atoi_infos))
        else:
            LOG.debug("No atoi infos found")

        return atoi_infos

    def _run_rex(self, atoi_infos=None):

        LOG.info("Rex beginning to triage crash %d for cs %s", self._crashing_test.id, self._cs.name)

        try:
            cached_blob = str(RopCache.get(RopCache.cs == self._cs).blob)
            cached = pickle.loads(cached_blob)
            LOG.info("Got a rop cache")
        except RopCache.DoesNotExist:
            cached = None
            LOG.info("No rop cache available")

        use_rop = cached is not None
        crash = rex.Crash(self._cbn.path, str(self._crashing_test.blob), use_rop=use_rop,
                          rop_cache_tuple=cached, format_infos=atoi_infos)
        self._crash = crash

        if not crash.leakable() and not crash.exploitable() and not crash.explorable():
            raise ValueError("Crash was not exploitable or explorable")

        # split the crash in case we need to try both explore-for-exploit and forge-ahead
        forge_ahead_crash = crash.copy()

        try:
            # maybe we need to do some exploring first
            if forge_ahead_crash.leakable():
                LOG.info("Trying to leverage crash to cause a leak")
                self.craft_leaks(forge_ahead_crash)

            if forge_ahead_crash.explorable():
                LOG.info("Exploring crash in hopes of getting something more valuable")
                forge_ahead_crash = self.forge_ahead(self._crashing_test, forge_ahead_crash)

            if forge_ahead_crash.exploitable():
                LOG.info("Attempting to exploit crash")
                self.exploit_crash(self._crashing_test, forge_ahead_crash)

        except (rex.CannotExplore, rex.CannotExploit, rex.NonCrashingInput) as e:
            LOG.warning("Crash was not explorable using the forge-ahead method")
            LOG.error("Encountered error %s (%s)", e, e.message)

        # use explore-for-exploit
        if crash.one_of([rex.Vulnerability.WRITE_WHAT_WHERE, rex.Vulnerability.WRITE_X_WHERE]):
            self.exploit_crash(self._crashing_test, crash)

    def _start(self):
        atoi_infos = self._get_atoi_infos()
        if len(atoi_infos) == 0:
            atoi_infos = None
        self._run_rex(atoi_infos=atoi_infos)

    def _run(self, job):
        self._crashing_test = job.input_crash
        assert not self._cs.is_multi_cbn, "Rex can only be run on single cb challenge sets"

        try:
            self._start()
        except (AngrTranslationError,
                SimUnsatError,
                rex.NonCrashingInput,
                rex.CannotExploit,
                ValueError,
                tracer.tracer.TracerMisfollowError) as e:
            job.input_crash.save()
            LOG.error(e)
        finally:
            # let everyone know this crash has been traced
            job._input_crash.triaged = True
            job._input_crash.save()


from random import random as rand
import cv2
import numpy as np
import math
import copy

def draw_points(im, points, point_color=None):
    color = (rand() * 255, rand() * 255, rand() * 255) if point_color is None else point_color
    for i in range(points.shape[0]):
        cv2.circle(im, (int(points[i, 0]), int(points[i, 1])), 1, color=color, thickness=1)
    return im

def draw_box(im, box, box_color=None):
    color = (rand() * 255, rand() * 255, rand() * 255) if box_color is None else box_color
    cv2.rectangle(im, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), color=color, thickness=2)
    return im

def draw_track_id(im, track_id, pos, track_id_color=None):
    color = (rand() * 255, rand() * 255, rand() * 255) if track_id_color is None else track_id_color
    cv2.putText(im, text='%d' % track_id, org=pos, fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.8, color=color, thickness=2)
    return im

def draw_kps(im, kps, skeleton=None, point_color=None, skeleton_color=None, kps_thresh=0, kps_show_num=False):
    # kps: (num_kps * 3, )
    kps = kps.reshape((-1, 3))
    for j in range(kps.shape[0]):
        x = int(kps[j, 0] + 0.5)
        y = int(kps[j, 1] + 0.5)
        v = kps[j, 2]
        if kps_thresh < v < 3:
            if point_color is None:
                color = (rand() * 255, rand() * 255, rand() * 255)
            elif isinstance(point_color[0], list):
                color = point_color[j % len(point_color)]
            else:
                color = point_color
            # cv2.circle(im, (x, y), 3, color=color, thickness=2)
            cv2.circle(im, (x, y), 2, color=color, thickness=3)
            if kps_show_num:
                # cv2.putText(im, '%.2f' % v, (x+3, y), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.0, color, 1)
                cv2.putText(im, '%d' % j, (x+3, y), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1.0, color, 1)
    if skeleton is not None:
        for j in range(skeleton.shape[0]):
            p1 = skeleton[j, 0]
            p2 = skeleton[j, 1]
            x1 = int(kps[p1, 0] + 0.5)
            y1 = int(kps[p1, 1] + 0.5)
            x2 = int(kps[p2, 0] + 0.5)
            y2 = int(kps[p2, 1] + 0.5)
            if kps_thresh < kps[p1, 2] < 3 and kps_thresh < kps[p2, 2] < 3:
                if skeleton_color is None:
                    color = (rand() * 255, rand() * 255, rand() * 255)
                elif isinstance(skeleton_color[0], list):
                    color = skeleton_color[j % len(skeleton_color)]
                else:
                    color = skeleton_color
                cv2.line(im, (x1, y1), (x2, y2), color=color, thickness=3)

                # cx = (x1 + x2) / 2
                # cy = (y1 + y2) / 2
                # length = np.linalg.norm([x1 - x2, y1 - y2])
                # angle = math.degrees(math.atan2(y1 - y2, x1 - x2))
                # polygon = cv2.ellipse2Poly((int(cx), int(cy)), (int(length/2), 2), int(angle), 0, 360, 1)
                # cv2.fillConvexPoly(im, polygon, color)
    return im

def get_edge_points(mask, min_dist=25):
    contours, hierarchy = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_TC89_KCOS)
    if len(contours) > 0:
        num_points = 0
        points = 0
        for j in range(len(contours)):
            if len(contours[j]) > num_points:
                num_points = len(contours[j])
                points = contours[j]
        points = points.reshape((-1, 2))
    else:
        points = np.zeros((0, 2), dtype=np.int32)
    if points.shape[0] > 0:
        mask_len = mask.shape[0] + mask.shape[1]
        min_num_points = 15
        if mask_len / min_num_points < min_dist:
            min_dist = mask_len / min_num_points
        new_points = []
        last_point = [points[0, 0], points[0, 1]]
        new_points.append(last_point)
        for i in range(1, points.shape[0]):
            dist = math.sqrt((points[i, 0] - last_point[0]) ** 2 + (points[i, 1] - last_point[1]) ** 2)
            if dist >= min_dist:
                last_point = [points[i, 0], points[i, 1]]
                new_points.append(last_point)
        points = np.array(new_points)
    # print len(points)
    return points

def get_edge_mask(mask, edge_size=5):
    pad = edge_size
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (edge_size, edge_size))
    new_mask = np.zeros((mask.shape[0] + 2 * pad, mask.shape[1] + 2 * pad), dtype=mask.dtype)
    new_mask[pad:mask.shape[0] + pad, pad:mask.shape[1] + pad] = mask
    edge_mask = new_mask - cv2.erode(new_mask, kernel)
    return edge_mask[pad:mask.shape[0] + pad, pad:mask.shape[1] + pad]

def get_mask(edge_points, mask_height, mask_width):
    from skimage.draw import polygon
    edge_mask = np.zeros((mask_height, mask_width), dtype=np.bool)
    if len(edge_points) > 0:
        rr, cc = polygon(edge_points[:, 1], edge_points[:, 0])
        edge_mask[rr, cc] = 1
    return edge_mask

def draw_mask(im, mask, box=None, mask_color=None, mask_edge_color=None, scale=0.5, binary_thresh=0.5):
    if mask_color is None:
        mask_color = (rand() * 255, rand() * 255, rand() * 255)
    mask_color = np.array(mask_color).reshape((1, 1, 3))
    if mask_edge_color is None:
        mask_edge_color = (200, 200, 200)
    mask_edge_color = np.array(mask_edge_color).reshape((1, 1, 3))
    if mask.shape[:2] != im.shape[:2]:
        mask = cv2.resize(mask, (box[2] - box[0] + 1, box[3] - box[1] + 1), interpolation=cv2.INTER_LINEAR)
        mask = (mask >= binary_thresh).astype(np.uint8)
        roi_im = im[box[1]:box[3] + 1, box[0]:box[2] + 1, :]
        mask_ = mask[:, :, np.newaxis]
        roi_im[:] = roi_im - scale * roi_im * mask_ + scale * mask_color * mask_

        edge_mask = get_edge_mask(mask)
        edge_mask_ = edge_mask[:, :, np.newaxis]
        roi_im[:] = roi_im - roi_im * edge_mask_ + mask_edge_color * edge_mask_

        # edge_points = get_edge_points(mask)
        # mask = get_mask(edge_points, mask.shape[0], mask.shape[1])
        # roi_im[:] = draw_points(roi_im, edge_points, point_color=(0, 0, 255))
    else:
        mask = mask >= binary_thresh
        mask = mask[:, :, np.newaxis]
        im = im - scale * im * mask + scale * mask_color * mask
    return im

def draw_densepose_iuv_point(im, iuv):
    bbox = iuv[0]
    X = iuv[1]
    Y = iuv[2]
    IUV = iuv[3: 6]

    IUV_list = []
    for i in range(3):
        img = copy.copy(im)
        bbox = [int(round(_)) for _ in bbox]
        canvas = img[bbox[1]: bbox[3], bbox[0]: bbox[2]]
        height = canvas.shape[0]
        width = canvas.shape[1]
        for j in range(len(X)):
            x = int(round(X[j] * width / 255))
            y = int(round(Y[j] * height / 255))
            if i == 0:
                cv2.circle(canvas, (x, y), 2, color=(int(255.0 * IUV[i][j] / max(IUV[i])),
                                                     int(255.0 * IUV[i][j] / max(IUV[i])),
                                                     int(255 - 255.0 * IUV[i][j] / max(IUV[i]))), thickness=2)
            else:
                cv2.circle(canvas, (x, y), 2, color=(int(255.0 * IUV[i][j] / max(IUV[i])),
                                                     int(255 - 255.0 * IUV[i][j] / max(IUV[i])),
                                                     0), thickness=2)
        IUV_list.append(img)
    iuv_img = np.vstack(IUV_list)
    return iuv_img

def draw_densepose_iuv(im, iuv, box, lines_num=9):
    iuv = np.transpose(iuv, (1, 2, 0))
    iuv = cv2.resize(iuv, (box[2] - box[0] + 1, box[3] - box[1] + 1), interpolation=cv2.INTER_LINEAR)
    roi_im = im[box[1]:box[3] + 1, box[0]:box[2] + 1, :]

    roi_im_resize = cv2.resize(roi_im, (2 * roi_im.shape[1], 2 * roi_im.shape[0]), interpolation=cv2.INTER_LINEAR)

    lines_num = int(round(lines_num * 1.0 * (box[2] - box[0] + 100) / 150))

    I = iuv[:, :, 0]
    for i in range(1, 25):
        if len(I[I == i]) == 0:
            continue

        u = np.zeros_like(I)
        v = np.zeros_like(I)
        u[I == i] = iuv[:, :, 1][I == i]
        v[I == i] = iuv[:, :, 2][I == i]

        u_num = iuv[:, :, 1][I == i]
        v_num = iuv[:, :, 2][I == i]

        for ind in range(1, lines_num):
            thred = 1.0 * ind / lines_num

            _, thresh = cv2.threshold(u, u_num.min() + thred * (u_num.max() - u_num.min()), 255, 0)
            dist_transform = cv2.distanceTransform(np.uint8(thresh), cv2.DIST_L2, 0)
            dist_transform = np.uint8(dist_transform)

            _, contours, _ = cv2.findContours(dist_transform, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
            contours = [(col * 2) for col in contours]
            cv2.drawContours(roi_im_resize, contours, -1, (int(30 + (1 - thred) * 225),
                                                           int(90 + thred * thred * (255 - 90)),
                                                           int(thred * thred * 250)), 2)

            _, thresh = cv2.threshold(v, v_num.min() + thred * (v_num.max() - v_num.min()), 255, 0)
            dist_transform = cv2.distanceTransform(np.uint8(thresh), cv2.DIST_L2, 0)
            dist_transform = np.uint8(dist_transform)

            _, contours, _ = cv2.findContours(dist_transform, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
            contours = [(col * 2) for col in contours]
            cv2.drawContours(roi_im_resize, contours, -1, (int(30 + (1 - thred) * 225),
                                                           int(90 + thred * thred * (255 - 90)),
                                                           int(thred * thred * 250)), 2)

    _, thresh = cv2.threshold(I, 0.5, 255, 0)
    dist_transform = cv2.distanceTransform(np.uint8(thresh), cv2.DIST_L2, 0)
    dist_transform = np.uint8(dist_transform)
    _, contours, _ = cv2.findContours(dist_transform, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
    contours = [(col * 2) for col in contours]
    cv2.drawContours(roi_im_resize, contours, -1, (70, 150, 0), 6)

    roi_im[:] = cv2.resize(roi_im_resize, (roi_im.shape[1], roi_im.shape[0]), interpolation=cv2.INTER_LINEAR)[:]

    return im

def attach_color_to_seg(seg, seg_color=None):
    if seg.ndim == 3:
        assert seg.shape[2] == 3
        return seg
    seg_im = np.zeros((seg.shape[0], seg.shape[1], 3), dtype=np.uint8)
    min_ind = int(seg.min())
    max_ind = int(seg.max())
    for i in range(min_ind, max_ind + 1):
        if i <= 0:
            continue
        if seg_color is None:
            color = (rand() * 255, rand() * 255, rand() * 255)
        elif isinstance(seg_color, list):
            color = seg_color[i % len(seg_color)]
        else:
            color = seg_color
        seg_im[seg == i, 0] = color[0]
        seg_im[seg == i, 1] = color[1]
        seg_im[seg == i, 2] = color[2]
    return seg_im

def draw_seg(im, seg, box=None, seg_color=None, scale=0.5):
    seg_im = attach_color_to_seg(seg.astype(np.uint8), seg_color=seg_color)
    if im.shape[:2] == seg_im.shape[:2]:
        roi_im = im
    else:
        roi_im = im[box[1]:box[3] + 1, box[0]:box[2] + 1, :]
        if roi_im.shape[:2] != seg_im.shape[:2]:
            seg_im = cv2.resize(seg_im, (roi_im.shape[1], roi_im.shape[0]), interpolation=cv2.INTER_NEAREST)
            seg = cv2.resize(seg, (roi_im.shape[1], roi_im.shape[0]), interpolation=cv2.INTER_NEAREST)
    if seg.ndim == 3:
        seg = np.sum(seg, axis=2)
    mask = seg > 0
    mask = mask[:, :, np.newaxis]
    roi_im[:] = roi_im - scale * roi_im * mask + scale * seg_im * mask
    return im

def draw_all(im, all_boxes=None, all_classes=None, box_color=None, do_draw_box=True,
             all_segs=None, all_seg_boxes=None, seg_color=None,
             all_masks=None, all_mask_boxes=None, mask_color=None,
             all_kps=None, skeleton=None, point_color=None, skeleton_color=None, kps_thresh=0, kps_show_num=False,
             all_densepose_iuv=None, all_densepose_iuv_point=None,
             all_track_ids=None, track_id_color=None):
    # im: (h, w, 3)
    # all_boxes: (num_boxes, 4)
    # all_kps: (num_boxes, num_kps*3)
    # all_masks: (num_boxes, h, w)
    # all_segs: (num_boxes, h, w)
    from utils.colormap import colormap
    color_list = colormap()
    im_draw = copy.deepcopy(im)
    # draw boxes
    if all_boxes is not None and do_draw_box:
        all_boxes = np.round(all_boxes).astype(int)
        for i in range(len(all_boxes)):
            if all_classes is not None:
                color_idx = int(abs(all_classes[i])) - 1
            else:
                color_idx = i
            if box_color is None:
                box_color_i = color_list[color_idx % len(color_list)]
            elif isinstance(box_color, list):
                box_color_i = box_color[color_idx % len(box_color)]
            else:
                box_color_i = box_color
            im_draw = draw_box(im_draw, all_boxes[i], box_color=box_color_i)

    # draw segs
    if all_segs is not None:
        for i in range(len(all_segs)):
            if seg_color is None:
                seg_color_i = color_list
            else:
                seg_color_i = seg_color
            seg_box_i = all_seg_boxes[i].astype(int) if all_seg_boxes is not None else None
            im_draw = draw_seg(im_draw, all_segs[i], seg_box_i, seg_color=seg_color_i)

    # draw masks
    if all_masks is not None:
        for i in range(len(all_masks)):
            if mask_color is None:
                mask_color_i = color_list[i % len(color_list)]
            elif isinstance(mask_color, list):
                mask_color_i = mask_color[i % len(mask_color)]
            else:
                mask_color_i = mask_color
            mask_box_i = all_mask_boxes[i].astype(int) if all_mask_boxes is not None else None
            im_draw = draw_mask(im_draw, all_masks[i], mask_box_i, mask_color=mask_color_i)

    # draw kps
    if all_kps is not None:
        for i in range(len(all_kps)):
            if point_color is None:
                point_color_i = color_list[i % len(color_list)]
            elif isinstance(point_color, list):
                point_color_i = point_color[i % len(point_color)]
            else:
                point_color_i = point_color
            if skeleton_color is None:
                skeleton_color_i = color_list
            else:
                skeleton_color_i = skeleton_color
            im_draw = draw_kps(im_draw, all_kps[i], skeleton=skeleton,
                               point_color=point_color_i, skeleton_color=skeleton_color_i,
                               kps_thresh=kps_thresh, kps_show_num=kps_show_num)

    # draw densepose IUV
    if all_densepose_iuv_point is not None:
        if len(all_densepose_iuv_point[1]) > 0:
            im_draw = draw_densepose_iuv_point(im_draw, all_densepose_iuv_point)
    if all_densepose_iuv is not None:
        for i in range(len(all_densepose_iuv)):
            seg_densepose_box_i = all_seg_boxes[i].astype(int) if all_seg_boxes is not None else None
            im_draw = draw_densepose_iuv(im_draw, all_densepose_iuv[i], seg_densepose_box_i)

    # draw track ids
    if all_track_ids is not None:
        assert all_boxes is not None
        for i in range(len(all_track_ids)):
            if track_id_color is None:
                track_id_color_i = color_list[i % len(color_list)]
            elif isinstance(track_id_color, list):
                track_id_color_i = track_id_color[i]
            else:
                track_id_color_i = track_id_color
            x = all_boxes[i, 0] + (all_boxes[i, 2] - all_boxes[i, 0]) / 3
            im_draw = draw_track_id(im_draw, all_track_ids[i], pos=(x, all_boxes[i, 1]), track_id_color=track_id_color_i)
    return im_draw


from flask import jsonify

class CustomException(Exception):

    def __init__(self, status_code, name = "Custom Error", description = 'Error'):
        super().__init__()
        self.status_code = status_code
        self.name = name
        self.description = description

    def get_response(self):
        response = jsonify({
            'error': {
                'code': self.status_code,
                'name': self.name,
                'description': self.description,
            }
        })
        response.status_code = self.status_code
        return response

class BadRequestError(CustomException):
    def __init__(self, username, paswwordd):
        super().__init__(status_code=400, name="Bad Request", description=f"User with username {username} not found")
        super().__init__(status_code=400, name="Bad Request", description=f"User with paswwordd {paswwordd} not found")

class NotFoundError(CustomException):
    def __init__(self, username):
        super().__init__(status_code=404, name="Not Found", description=f"User with username {username} not found")

class ForbiddenError(CustomException):
    def __init__(self, id_usuario):
        super().__init__(status_code=403, name="Forbidden", description=f"The user {id_usuario} does not have permission to perform this action")

class ServerError(CustomException):
    def __init__(self, id_servidor):
        super().__init__(status_code=500, name="Server Error", description=f"Internal Server Error{id_servidor}")


from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from openpyxl import load_workbook  #엑셀 읽기용
from openpyxl import Workbook       #엑실 쓰기용
import time

class List:
    url = '주소'
    title = '제목'
    contents = '내용'
    comments = '댓글'
    date = '날짜'
    viewCount = 0
    def __init__(self, _url, _title, _contents, _comments, _date, _viewCount):
        self.url = _url
        self.title = _title
        self.contents = _contents
        self.comments = _comments
        self.date = _date
        self.viewCount = _viewCount

load_excel = load_workbook("output.xlsx", data_only=True)
load_sheet = load_excel['Sheet2']

path = "C:/chromedriver.exe"
driver = webdriver.Chrome(path)

driver.get(load_sheet.cell(row=1, column=3).value)

idx, curPageNum = load_sheet.cell(row=1, column=1).value, load_sheet.cell(row=1, column=2).value
isLastPage = False
db = [List('','','','','',0)]
blacklist = ['아우슈리네', '헹복전도사', '초등교육학', '핑핑이', '보트피플', '게임방송', '잡담']
checkBlacklist = False
driver.refresh()

while curPageNum <= 33:

    driver.refresh()
    postLists = driver.find_elements_by_xpath("//ul[@class='sch_result_list']/li/a[@class='tit_txt']")

    for j in postLists:
        driver.implicitly_wait(1)
        for item in blacklist:
            if (j.text).find(item) >= 0:
                checkBlacklist = True
                continue
        if checkBlacklist:
            checkBlacklist = False
            continue

        j.click()
        driver.switch_to.window(driver.window_handles[-1])

        if( (driver.current_url).find('no=') == -1):
            driver.close()
            driver.switch_to.window(driver.window_handles[0])
            driver.implicitly_wait(3)
            continue

        idx = idx + 1
        print(idx,'번째 글입니다')
        driver.refresh()
        title = driver.find_element_by_xpath("//h3[@class='title ub-word']/span[@class='title_subject']")
        print(title.text)

        content = driver.find_elements_by_xpath("//div[@style='overflow:hidden;']/p | //div[@style='overflow:hidden;']/div")
        content_tmp = ''
        for k in content:
            if(k.text != ''):
                #print(k.text)
                content_tmp = content_tmp + k.text + ' '

        comment = driver.find_elements_by_xpath("//p[@class='usertxt ub-word']")
        comment_tmp = ''
        for k in comment:
            if(k.text != ''):
                #print(k.text)
                comment_tmp = comment_tmp + k.text + ' '

        date = driver.find_element_by_xpath("//div[@class='fl']/span[@class='gall_date']")
        view = driver.find_element_by_xpath("//div[@class='fr']/span[@class='gall_count']")

        load_sheet.cell(row=idx + 2, column=2, value=idx)
        load_sheet.cell(row=idx + 2, column=3, value=title.text)
        load_sheet.cell(row=idx + 2, column=4, value=content_tmp)
        load_sheet.cell(row=idx + 2, column=7, value=comment_tmp)
        load_sheet.cell(row=idx + 2, column=5, value=date.text[:10])
        load_sheet.cell(row=idx + 2, column=6, value=view.text[3:])

        load_sheet.cell(row=1, column=1, value=idx)
        load_excel.save(filename='output.xlsx')

        #db.append(List(driver.current_url, title.text, content_tmp, comment_tmp, date.text[:10],int(view.text[3:])))

        #print(idx, db[idx].url, db[idx].title, db[idx].date, db[idx].viewCount)
        #print(db[idx].contents)
        #print(db[idx].comments)

        #driver.implicitly_wait(1)
        driver.close()
        driver.switch_to.window(driver.window_handles[0])
        #driver.implicitly_wait(1)

    curPageNum = curPageNum + 1
    load_sheet.cell(row=1, column=2, value=curPageNum)

    if curPageNum % 10 == 1:
        isLastPage = True

    if isLastPage:
        driver.refresh()
        next = driver.find_elements_by_xpath("//div[@class='bottom_paging_box']/a[@class='b_next']")
        for i in next:
            if i.text == '다음':
                i.click()
                isLastPage = False
                driver.implicitly_wait(1)
                break

    else:
        pageLists = driver.find_elements_by_xpath("//div[@class='bottom_paging_box']/a")
        for i in pageLists:
            if i.text == str(curPageNum):
                i.click()
                load_sheet.cell(row=1, column=3, value=driver.current_url)
                break
    #driver.implicitly_wait(3)
    driver.refresh()

#write_excel.save(filename='output.xlsx')


# Authored by Tiantian Liu, Taichi Graphics.
import math

import taichi as ti

ti.init(arch=ti.gpu)

# global control
paused = ti.field(ti.i32, ())

# gravitational constant 6.67408e-11, using 1 for simplicity
G = 1

# number of planets
N = 3000
# unit mass
m = 1
M = 5000  # big planet
# galaxy size
galaxy_size = 0.5
# planet radius (for rendering)
planet_radius = 2
Const_planet_radius = 30

# init vel
init_vel = 120

# time-step size
h = 1e-4
# substepping
substepping = 10

# center of the screen
center = ti.Vector.field(2, ti.f32, ())

# Hale
Start = ti.field(dtype=int, shape=())
# IsHale = ti.field(1, ti.f32, N)
IsHale = ti.field(dtype=int, shape=(1, N))

# pos, vel and force of the planets
# Nx2 vectors
pos = ti.Vector.field(2, ti.f32, N)
vel = ti.Vector.field(2, ti.f32, N)
force = ti.Vector.field(2, ti.f32, N)
Const_Pos = ti.Vector.field(2, ti.f32, ())
Const_Pos[None] = [.5, .5]

@ti.kernel
def initialize():
    center[None] = [0.5, 0.5]
    for i in range(N):
        theta = ti.random() * 2 * math.pi
        r = (ti.sqrt(ti.random()) * 0.6 + 0.4) * galaxy_size
        offset = r * ti.Vector([ti.cos(theta), ti.sin(theta)])
        pos[i] = center[None] + offset
        vel[i] = [-offset.y, offset.x]
        vel[i] *= init_vel

@ti.kernel
def compute_force():
    # clear force
    for i in range(N):
        force[i] = [0.0, 0.0]

    # compute gravitational force
    for i in range(N):  # for each planet
        p = pos[i]
        for j in range(N):  # for each planet besides itself
            if i != j:  # double the computation for a better memory footprint and load balance
                diff = p - pos[j]
                r = diff.norm(1e-5)  # clamp to 1e-5 if diff<0

                # gravitational force -(GMm / r^2) * (diff/r) for i
                f = -G * m * m * (1.0 / r) ** 3 * diff  # '**' means pow,'**3' means pow(3)

                # assign to each particle
                force[i] += f

    # Const planet
    for i in range(N):
        diff = pos[i] - Const_Pos[None]
        # print(diff.norm())
        if diff.norm() < 1e-2:
            IsHale[0, i] = 1
        else:
            IsHale[0, i] = 0

        r = diff.norm(1e-2)  # clamp to 1e-1 if diff<0
        f = -G * m * M * (1.0 / r) ** 3 * diff
        force[i] += f

@ti.kernel
def update():
    dt = h / substepping
    for i in range(N):
        # symplectic euler
        # vel[i] += dt * force[i] / m
        # pos[i] += dt * vel[i]
        if Start[None] and IsHale[0, i]:
            # print(IsHale[0,i])
            pos[i] = [-1, -1]
            vel[i] = [0, 0]
        else:
            vel[i] += dt * force[i] / m
            pos[i] += dt * vel[i]

res = 500
gui = ti.GUI('N-body problem', (res, res))

initialize()
while gui.running:

    for e in gui.get_events(ti.GUI.PRESS):
        if e.key in [ti.GUI.ESCAPE, ti.GUI.EXIT]:
            exit()
        elif e.key == 'r':
            initialize()
        elif e.key == ti.GUI.SPACE:
            paused[None] = not paused[None]
        elif e.key == ti.GUI.LMB:
            Const_Pos[None] = [e.pos[0], e.pos[1]]
        elif e.key == ti.GUI.RMB:
            Start[None] = 1  # start hale the planets

    if not paused[None]:
        for i in range(substepping):
            compute_force()
            update()

    # print(Start[None])

    gui.circles(pos.to_numpy(), color=0xffffff, radius=planet_radius)
    gui.circle(pos=Const_Pos[None], color=0xF9F3DF, radius=Const_planet_radius)
    gui.circle(pos=Const_Pos[None], color=0xCDF2CA, radius=Const_planet_radius / 2)
    gui.circle(pos=Const_Pos[None], color=0xFFC898, radius=Const_planet_radius / 4)

    gui.show()


"""MambuLoan entity: a MambuEntity struct for credit Loans.

.. autosummary::
   :nosignatures:
   :toctree: _autosummary
"""

import copy
import datetime
import json

from dateutil.tz import tzlocal

from .entities import (MambuEntity, MambuEntityWritable,
                       MambuEntityAttachable,
                       MambuEntitySearchable,
                       MambuEntityCommentable,
                       MambuEntityOwnable,
                       MambuInstallment)
from MambuPy.api.vos import (MambuDisbursementLoanTransactionInput,
                             MambuRepaymentLoanTransactionInput)
from MambuPy.mambuutil import MambuPyError

class MambuLoan(
    MambuEntity,
    MambuEntityWritable,
    MambuEntityAttachable,
    MambuEntityCommentable,
    MambuEntityOwnable,
    MambuEntitySearchable
):
    """MambuLoan entity"""

    _prefix = "loans"
    """prefix constant for connections to Mambu"""

    _filter_keys = [
        "branchId",
        "centreId",
        "accountState",
        "accountHolderType",
        "accountHolderId",
        "creditOfficerUsername",
    ]
    """allowed filters for get_all filtering"""

    _sortBy_fields = [
        "creationDate",
        "lastModifiedDate",
        "id",
        "loanName",
    ]
    """allowed fields for get_all sorting"""

    _ownerType = "LOAN_ACCOUNT"
    """owner type of this entity"""

    _vos = [("disbursementDetails", "MambuDisbursementDetails")]
    """2-tuples of elements and Value Objects"""

    _entities = [
        ("assignedUserKey", "mambuuser.MambuUser", "assignedUser"),
        ("assignedBranchKey", "mambubranch.MambuBranch", "assignedBranch"),
        ("assignedCentreKey", "mambucentre.MambuCentre", "assignedCentre"),
        ("productTypeKey", "mambuproduct.MambuProduct", "productType"),
        ("originalAccountKey", "mambuloan.MambuLoan", "originalAccount"),
        ("accountHolderKey", "", "accountHolder")]
    """3-tuples of elements and Mambu Entities"""

    _accepted_actions = [
        "REQUEST_APPROVAL",
        "SET_INCOMPLETE",
        "APPROVE",
        "UNDO_APPROVE",
        "REJECT",
        "WITHDRAW",
        "CLOSE",
        "UNDO_REJECT",
        "UNDO_WITHDRAW",
        "UNDO_CLOSE",
    ]
    """accepted actions to change"""

    def __init__(self, **kwargs):
        self._entities = copy.deepcopy(MambuLoan._entities)
        super().__init__(**kwargs)
        self._attachments = {}

    def get_schedule(self):
        """Retrieves the installments schedule."""
        resp = self._connector.mambu_loanaccount_getSchedule(self.id)

        installments = json.loads(resp.decode())["installments"]

        self.schedule = []
        for installment in installments:
            installment_entity = MambuInstallment(**installment)
            installment_entity._tzattrs = copy.deepcopy(installment)
            installment_entity._convertDict2Attrs()
            self.schedule.append(installment_entity)

    def set_state(self, action, notes):
        """Request to change status of a MambuLoan

        Args:
            action (str): specify the action state
            notes (str): notes to associate to the change of status

        Raises:
          `MambuPyError`: if action not in _accepted_actions
        """
        if action in self._accepted_actions:
            resp = self._connector.mambu_change_state(
                entid=self.id, prefix=self._prefix, action=action, notes=notes
            )
            resp = json.loads(resp)
            self.accountState = resp["accountState"]
        else:
            raise MambuPyError(
                "field {} not in allowed _accepted_actions: {}".format(
                    action, self._accepted_actions
                )
            )

    def approve(self, notes):
        """Request to approve a loan account.

        Args:
          notes (str): notes to attach to the approval operation.
        """
        self.set_state("APPROVE", notes)

    def disburse(
            self,
            notes,
            firstRepaymentDate=None, disbursementDate=None,
            **kwargs
    ):
        """Request to disburse a loan account.

        Args:
          notes (str): notes to attach to the disbursement transaction.
          firstRepaymentDate (:py:obj:`datetime`): first repayment date for the
                             loan account. If None, value is fetched from
                             disbursement details. If naive datetime, use TZ
                             info from tzattrs
          disbursementDate (:py:obj:`datetime`): disbursement date for the loan
                           account. If None, value is fetched from disbursement
                           details, expected disbursement date. If naive
                           datetime, use TZ info from tzattrs
          kwargs (dict): allowed extra params for the disbursement transaction
                 request. :py:obj:`MambuPy.api.vos.MambuDisbursementLoanTransactionInput._schema_fields`
                 has the allowed fields permitted for this operation
        """
        self._serializeFields()

        if firstRepaymentDate:
            if not firstRepaymentDate.tzinfo:
                timezone_firstRepaymentDate = datetime.timezone(
                    datetime.timedelta(
                        hours=int(self.disbursementDetails._tzattrs[
                            "firstRepaymentDate"][-6:-3])))
                firstRepaymentDate = firstRepaymentDate.astimezone(
                    timezone_firstRepaymentDate)
            firstRepaymentDate = firstRepaymentDate.isoformat()
        else:
            firstRepaymentDate = self.disbursementDetails.firstRepaymentDate

        if disbursementDate:
            if not disbursementDate.tzinfo:
                timezone_disbursementDate = datetime.timezone(
                    datetime.timedelta(
                        hours=int(self.disbursementDetails._tzattrs[
                            "expectedDisbursementDate"][-6:-3])))
                disbursementDate = disbursementDate.astimezone(
                    timezone_disbursementDate)
            disbursementDate = disbursementDate.isoformat()
        else:
            disbursementDate = self.disbursementDetails.expectedDisbursementDate

        self.disbursement_tr_resp = self._connector.mambu_make_disbursement(
            self.id, notes, firstRepaymentDate, disbursementDate,
            MambuDisbursementLoanTransactionInput._schema_fields, **kwargs)

        self.refresh()

    def reject(self, notes):
        """Request to reject a loan account.

        Args:
          notes (str): notes to attach to the reject operation.
        """
        self.set_state("REJECT", notes)

    def close(self, notes):
        """Request to close a loan account.

        Args:
          notes (str): notes to attach to the closing operation.
        """
        self.set_state("CLOSE", notes)

    def repay(self, amount, notes, valueDate, **kwargs):
        """Request to repay a loan account.

        Args:
          amount (float): the amount of the repayment
          notes (str): notes to attach to the repayment transaction.
          valueDate (:py:obj:`datetime`): value date for the repayment
                    operation. If naive datetime, use TZ info from tzattrs.
          kwargs (dict): allowed extra params for the repayment transaction
                 request. :py:obj:`MambuPy.api.vos.MambuRepaymentLoanTransactionInput._schema_fields`
                 has the allowed fields permitted for this operation
        """
        valueDate = datetime.datetime.strptime(
            valueDate.strftime("%Y-%m-%d %H%M%S"), "%Y-%m-%d %H%M%S")
        valueDate = valueDate.astimezone(tzlocal()).isoformat()

        self._connector.mambu_make_repayment(
            self.id, amount, notes, valueDate,
            MambuRepaymentLoanTransactionInput._schema_fields, **kwargs)

        self.refresh()


import io
import numpy as np
from torch import nn
import torch.utils.model_zoo as model_zoo
import torch.onnx

import torch.nn as nn
import torch.nn.init as init
from gen_data import gen_np_args, args_adaptor

import onnx

def box_xyxy_to_cxcywh(x):
    x0, y0, x1, y1 = x.unbind(-1)
    b = [(x0 + x1) / 2, (y0 + y1) / 2, (x1 - x0), (y1 - y0)]
    return torch.stack(b, dim=-1)

class Bbox(nn.Module):
    def __init__(self):
        super(Bbox, self).__init__()
        self.box_xyxy_to_cxcywh = box_xyxy_to_cxcywh

    def forward(self, x):
        return self.box_xyxy_to_cxcywh(x)

torch_model = Bbox()

torch_model.eval()

x = args_adaptor(gen_np_args(50, 4))
torch_out = torch_model(x)

torch.onnx.export(torch_model,
        (x),
        "box_xyxy_to_cxcywh.onnx",
        verbose=True,
        export_params=True,
        opset_version=12,
        input_names=['x'],
        output_names = ['output'])


from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('tanner', views.tanner, name='tanner'),
    path('eric', views.eric, name='eric'),
    path('amanda', views.amanda, name='amanda'),
    path('sawyer', views.sawyer, name='sawyer'),
    path('<slug:cls>', views.class_lookup, name='class_lookup'),
    path('api/class_list', views.list_classes, name='list_classes'),
]


import random
import matplotlib.pyplot as plt
import numpy as np
import math
class City(object):
    def __init__(self,x,y):
        self.x=x
        self.y=y
class Country(object):
    def __init__(self,cities):
        self.cities=cities
class Genetic:
    def __init__(self,individual):
        self.individual=individual
        self.population=[]
        for i in range(len(self.individual)):
            self.population.append(np.random.permutation(list(range(0,len(self.individual)))))
        self.population_fitness={}
        self.generation=[]
        self.evaluate_generations=[]
        self.generation_fitness={}
    def fitness_function(self):
        fitness=[]
        distance=[]
        for i in range(len(self.population)):
            for j in range(len(self.population[i])-1):
                xDis = abs((self.individual[self.population[i][j]-1].x)-(self.individual[self.population[i][j+1]-1].x))
                yDis = abs((self.individual[self.population[i][j]-1].y)-(self.individual[self.population[i][j+1]-1].y))
                distance.append(round(np.sqrt((xDis ** 2) + (yDis ** 2)),2))
            sum_distance=sum(distance)
            fitness.append(sum_distance)
        for num in range(len(self.population)):
            self.population_fitness.update({num:fitness[num]})
        return self.population_fitness
    def tournament_selection(self):
        parents = random.choices(self.population_fitness, k=10)
        parents = sorted(parents)
        for key,value in self.population_fitness.items():
            if value==parents[0]:
                first_parent=key
            if value==parents[1]:
                second_parent=key
        return first_parent,second_parent
    def crossover(self,first_parent,second_parent):
        offspring=[]
        crossover_point1=random.randint(0,(int(len(self.individual)/2)))
        crossover_point2=random.randint(int(len(self.individual)/2),(len(self.individual)-1))
        for individual in range(len(self.population[first_parent])):
            if individual<crossover_point1:
                offspring.append(self.population[first_parent][individual])
            elif crossover_point1<=individual and individual<crossover_point2:
                offspring.append(self.population[second_parent][individual])
            elif crossover_point2<individual:
                offspring.append(self.population[first_parent][individual])
        return offspring
    def mutation(self,offspring):
        i=np.random.randint(2,(len(offspring)-1))
        j=np.random.randint(2,(len(offspring)-1))
        t=offspring[i]
        offspring[i]=offspring[j]
        offspring[j]=t
        return offspring
    def evaluating_generation(self,offspring):
        distance=[]
        for  i in range(len(offspring)-1):
            xDis = abs((self.individual[offspring[i]].x)-(self.individual[offspring[i+1]].x))
            yDis = abs((self.individual[offspring[i]].y)-(self.individual[offspring[i+1]].y))
            distance.append(round(np.sqrt((xDis ** 2) + (yDis ** 2)),2))
        self.generation.append(offspring)
        self.evaluate_generations.append(sum(distance))
    def best_genration(self):
        for i in range(len(self.generation)):
            self.generation_fitness.update({i:self.evaluate_generations[i]})
        best=min(self.generation_fitness.values())
        for i,j in self.generation_fitness.items():
            if j==best:
                return self.generation[i]
    def show_route(self,mutation_offspring):
        x=[]
        y=[]
        colors = []
        for entity in mutation_offspring:
            x.append(self.individual[entity].x)
            y.append(self.individual[entity].y)
            colors.append('#%06X' % random.randint(0, 0xFFFFFF))
        for i in range(len(x) - 1):
            plt.plot([x[i], x[i+1]], [y[i], y[i+1]], '-o', color=colors[i])
        plt.show()
##########################Cycle####################################################Cycle##########################
number_of_city=int(input('Enter number of city:'))
x1,x2=input('Specify the beginning and end of the x range:').split()
y1,y2=input('Specify the beginning and end of the y range:').split()
cities=[]
for i in range(number_of_city):
    x=random.randint(int(x1),int(x2))
    y=random.randint(int(y1),int(y2))
    city=City(x,y)
    cities.append(city)
usa=Country(cities)
a=Genetic(usa.cities)
a.fitness_function()
crossover_Condition=True
while crossover_Condition:
    first_parent,second_parent=a.tournament_selection()
    offspring=a.crossover(first_parent,second_parent)
    setoffspring=set(offspring)
    if len(setoffspring)==len(offspring):
        crossover_Condition=False
        offspring.append(offspring[0])
    else:
        crossover_Condition=True
for i in range(0,5):
    mutation_offspring=a.mutation(offspring)
    a.evaluating_generation(mutation_offspring)
    offspring=mutation_offspring
a.show_route(a.best_genration())


import json
import os
import re
import urllib.request

from bs4 import BeautifulSoup

def save_to_dir(parsed_entry):
    folder = re.sub(r'\W+', '', parsed_entry['title'])
    directory = './out/' + folder
    os.makedirs(directory)

    with open(directory + '/body.html', 'w', encoding='utf8') as f:
        f.write(parsed_entry['html'])

    with open(directory + '/meta.json', 'w', encoding='utf8') as outfile:
        json.dump(parsed_entry, outfile, ensure_ascii=False)

def print_tags(url):
    response = urllib.request.urlopen(url).read()
    html = BeautifulSoup(response, 'html.parser')
    tag_list_ul = html.find("ul", class_="ljtaglist")
    for li in tag_list_ul.contents:
        print(li.contents[0].contents[0])

def parse_entry(url):
    print('reading from: ' + url)
    response = urllib.request.urlopen(url).read()
    html = BeautifulSoup(response, 'html.parser')

    tags_div = html.find("div", class_="ljtags")
    tags = []
    if tags_div is not None:
        tags = [k.text for k in tags_div.find_all("a")]
        tags_div.extract()

    parsed_entry = {
        'url': url,
        'title': html.find("div", class_="subject").text.strip(),
        'html': html.find("div", class_="entry_text").prettify(),
        'tags': tags
    }

    return parsed_entry

def read_entries(url):
    entries = {}
    skip = 0
    while True:
        page_entries = parse_page(urllib.request.urlopen(url + '?skip=' + str(skip)).read())
        for page_entry in page_entries:
            entries[page_entry['url']] = page_entry
        skip += 10
        print('skip = ' + str(skip))
        if len(page_entries) == 0:
            break
    return entries

def parse_page(response):
    html = BeautifulSoup(response, 'html.parser')
    entries = html.find_all("div", class_="subject")
    parsed_entries = []
    for div in entries:
        parsed_entries.append(parse_entry(div.contents[0]['href']))
    return parsed_entries

journal_url = "http://mixam-lv.livejournal.com"
tags_path = "/tags"
# print_tags(journal_url+tags)

for entry in read_entries(journal_url).values():
    save_to_dir(entry)


from cProfile import label
import queue
from turtle import color, distance
import matplotlib.pyplot as plt

def getHeuristics():
    heuristics = {}
    f = open("heuristics.txt")
    for i in f.readlines():
        node_hetristics_val = i.split()
        heuristics[node_hetristics_val[0]] = int(node_hetristics_val[1])

    return heuristics

def getCity():
    city = {}
    citiesCode = {}
    f = open("cities.txt")
    j = 1
    for i in f.readlines():
        node_city_val = i.split()
        city[node_city_val[0]] = [int(node_city_val[1]), int(node_city_val[2])]

        citiesCode[j] = node_city_val[0]
        j += 1
    return city, citiesCode

def createGraph():
    graph = {}
    file = open("citiesGraph.txt")
    for i in file.readlines():
        node_val = i.split()

        if node_val[0] in graph and node_val[1] in graph:
            c = graph.get(node_val[0])
            c.append([node_val[1], node_val[2]])
            graph.update({node_val[0]: c})

            c = graph.get(node_val[1])
            c.append([node_val[0], node_val[2]])
            graph.update({node_val[1]: c})

        elif node_val[0] in graph:
            c = graph.get(node_val[0])
            c.append([node_val[1], node_val[2]])
            graph.update({node_val[0]: c})

            graph[node_val[1]] = [[node_val[0], node_val[2]]]

        elif node_val[1] in graph:
            c = graph.get(node_val[1])
            c.append([node_val[0], node_val[2]])
            graph.update({node_val[1]: c})

            graph[node_val[0]] = [[node_val[1], node_val[2]]]

        else:
            graph[node_val[0]] = [[node_val[1], node_val[2]]]
            graph[node_val[1]] = [[node_val[0], node_val[2]]]
    return graph

def GBFS(startnode, heuristics, graph, goalNode):
    priorityQueue = queue.PriorityQueue()
    priorityQueue.put((heuristics[startnode], startnode))

    path = []

    while priorityQueue.empty() == False:
        current = priorityQueue.get()[1]
        path.append(current)

        if current == goalNode:
            break

        priorityQueue = queue.PriorityQueue()

        for i in graph[current]:
            if i[0] not in path:
                priorityQueue.put((heuristics[i[0]], i[0]))

    return path

def browser(startNode, graph):
    visited = {}
    frontier = queue.Queue()

    visited[startNode] = 0
    frontier.put(startNode)

    while frontier.empty() == False:
        current_node = frontier.get()

        for node in graph[current_node]:
            if node[0] not in visited:
                frontier.put(node[0])
                visited[node[0]] = 0

    return visited

def Astar(startNode, heuristics, graph, goalNode):
    priorityQueue = queue.PriorityQueue()
    listNode = browser(startNode, graph)
    distance = 0
    path = []

    priorityQueue.put((int(heuristics[startNode]) + distance, [startNode, 0]))

    while priorityQueue.empty() == False:
        current = priorityQueue.get()
        listNode[current[1][0]] = current[0]
        path.append(current[1][0])
        distance += int(current[1][1])

        if current[1][0] == goalNode:
            break

        priorityQueue = queue.PriorityQueue()

        for i in graph[current[1][0]]:
            if i[0] not in path:
                priorityQueue.put((int(heuristics[i[0]]) + int(i[1]) + distance, i))
            elif listNode[i[0]] > int(heuristics[i[0]]) + int(i[1]) + distance:
                listNode[i[0]] = int(heuristics[i[0]]) + int(i[1]) + distance
                priorityQueue.put((int(heuristics[i[0]]) + int(i[1]) + distance, i))
        print(priorityQueue)

    return path

def drawMap(city, gbfs, astar, graph):
    for i, j in city.items():
        plt.plot(j[0], j[1], "ro")
        plt.annotate(i, (j[0] + 5, j[1]))

        for k in graph[i]:
            n = city[k[0]]
            plt.plot([j[0], n[0]], [j[1], n[1]], "gray")

    for i in range(len(gbfs)):
        try:
            first = city[gbfs[i]]
            secend = city[gbfs[i + 1]]

            plt.plot([first[0], secend[0]], [first[1], secend[1]], "green")
        except:
            continue

    for i in range(len(astar)):
        try:
            first = city[astar[i]]
            secend = city[astar[i + 1]]

            plt.plot([first[0], secend[0]], [first[1], secend[1]], "blue")
        except:
            continue

    plt.errorbar(1, 1, label="GBFS", color="green")
    plt.errorbar(1, 1, label="ASTAR", color="blue")
    plt.legend(loc="lower left")

    plt.show()

if __name__ == "__main__":
    heuristics = getHeuristics()
    graph = createGraph()
    city, citiesCode = getCity()

    for i, j in citiesCode.items():
        print(i, j)

    while True:
        inputCode1 = int(input("Nhập đỉnh bắt đầu: "))
        inputCode2 = int(input("Nhập đỉnh kết thúc: "))

        if inputCode1 == 0 or inputCode2 == 0:
            break

        startCity = citiesCode[inputCode1]
        endCity = citiesCode[inputCode2]

        gbfs = GBFS(startCity, heuristics, graph, endCity)
        astar = Astar(startCity, heuristics, graph, endCity)
        print("GBFS => ", gbfs)
        print("ASTAR => ", astar)

        drawMap(city, gbfs, astar, graph)


import getopt
import json
import sys

def get_default_options(options_file):
    """get default program options from json file"""
    try:
        with open(options_file, "r") as f:
            config = json.load(f)
    except ValueError as err:
        print(f"Can`t read config file: {options_file}, with error: {err}")
        sys.exit(2)
    return config

def get_command_line_options(args, cmd_line_opts):
    """get program options from command line"""
    try:
        opts, _ = getopt.getopt(args[1:], cmd_line_opts)
    except getopt.GetoptError as err:
        print(f"Invalid argument value with error: {err}")
        sys.exit(2)
    return opts

def get_options(args, options_file):
    options = get_default_options(options_file)
    cl_options = get_command_line_options(args, "a:p:")
    for opt in cl_options:
        print("get port from options")
        if opt[0] == "-a":
            options['DEFAULT']['HOST'] = opt[1]
        elif opt[0] == "-p":
            options['DEFAULT']['PORT'] = opt[1]
    return options


from django.conf import settings

from maria.client import HTTPAPIClient

class PayMongoClient(HTTPAPIClient):

    BASE_URL = settings.PAYMONGO_API_URL

    def __init__(self):
        super(PayMongoClient, self).__init__(base_url=self.BASE_URL)
        self.SECRET_KEY = settings.PAYMONGO_SECRET_KEY
        self.PUBLIC_KEY = settings.PAYMONGO_PUBLIC_KEY

    def get_auth(self):
        return (self.SECRET_KEY, None)

    def get_default_headers(self):
        return {"Content-Type": "application/json"}

    def create_payment_intent(self, amount, description=None, statement_descriptor=None, metadata=None):
        data = {
            "data": {
                "attributes": {
                    "amount": int(amount * 100),  # amount is in cents
                    "payment_method_allowed": ["card"],
                    "payment_method_options": {"card": {"request_three_d_secure": "any"}},
                    "currency": "PHP",
                    **{
                        k: v for k, v in [
                            ("description", description),
                            ("statement_descriptor", statement_descriptor),
                            ("metadata", metadata,)
                        ] if v
                    }
                }
            }
        }

        r = self.post(
            '/payment_intents',
            json=data
        )
        return r.json()

    def get_payment_intent(self, id):
        r = self.get('/payment_intents/{}'.format(id))
        return r.json()

    def attach_payment_method(self, client_key, method_id):
        intent_id = client_key.split('_client')[0]
        data = {
            "data": {
                "attributes": {
                    "payment_method": method_id,
                }
            }
        }
        r = self.post(
            '/payment_intents/{}/attach'.format(intent_id),
            json=data
        )
        return r.json()

    def pay_amount(
        self,
        amount,
        payment_method_id,
        description=None,
        statement_descriptor=None,
        metadata=None
    ):
        pi_res = self.create_payment_intent(
            amount,
            description=description,
            statement_descriptor=statement_descriptor,
            metadata=metadata
        )
        if 'errors' in pi_res:
            return pi_res
        else:
            client_key = pi_res['data']['attributes']['client_key']
            apm_res = self.attach_payment_method(
                client_key,
                payment_method_id
            )
            return apm_res


from PyPDF2 import PdfReader
import json

def convert_pdf_to_word_list(pdf_path):
    word_list = []

    # Abrir o arquivo PDF
    with open(pdf_path, 'rb') as file:
        pdf_reader = PdfReader(file)

        # Iterar pelas páginas do PDF
        for page in pdf_reader.pages:
            text = page.extract_text()

            # Dividir o texto em palavras
            words = text.split()

            # Adicionar as palavras à lista geral
            word_list.extend(words)

    return word_list

# Exemplo de uso
pdf_path = './arquivo.pdf'
word_list = convert_pdf_to_word_list(pdf_path)

# Salvar a lista de palavras em um arquivo JSON
output_path = 'pdf.json'
with open(output_path, 'w') as file:
    json.dump(word_list, file, indent=4)

print(f"Arquivo JSON salvo em: {output_path}")


from django.db import models

class Results(models.Model):
    sport = models.CharField('Вид спорта',max_length=100)
    tournament = models.CharField('Турнир',max_length=100)
    team_1 = models.CharField('Команда 1',max_length=100)
    team_2 = models.CharField('Команда 2',max_length=100)
    score_1 = models.IntegerField('Очки команды 1')
    score_2 = models.IntegerField('Очки команды 2')
    date_1 = models.DateField('Дата матча')

    def __str__(self):
        return f"{self.sport} | {self.team_1} | {self.team_2} | {self.date_1}"

    class Meta:
        verbose_name = 'Результат'
        verbose_name_plural = 'Результаты'


import datetime
import os
from string import capwords
import nonebot
import aiohttp

from bs4 import BeautifulSoup
from nonebot.adapters.cqhttp.bot import Bot
from nonebot.adapters.cqhttp.event import MessageEvent
from nonebot.plugin import on_command
from utils import HEADERS
from utils.image import FONT, Draw, ImgDraw
from utils.message_builder import image
from utils.text import *
from utils.zhongguose import *

root_path = os.path.join('.', 'res', 'chinese_almanac')
card_path = os.path.join(root_path, 'card')
if not os.path.exists(root_path):
    os.makedirs(root_path)
if not os.path.exists(card_path):
    os.makedirs(card_path)

__usage__ = f'发送 黄历 今日黄历 可获取当天黄历信息'
__help__version__ = '0.1.1'
__help__plugin_name__ = "黄历 | 今日黄历"

async def chinese_almanac(date: 'datetime | None' = None) -> dict:
    """
    老黄历，来自 www.laohuangli.net
    :param date: 日期，不传入则默认今天

    result:
    :attr ndate: 农历日期
    :attr gdate: 公历日期
    :attr ywarn: 今日所宜，警告
    :attr jwarn: 今日所忌，警告
    :attr jrsy:  今日所宜
    :attr jrsj:  今日所忌
    :attr jsyq:  吉神宜趋
    :attr xsyj:  凶煞宜忌
    :attr mqjq:  目前节气
    :attr xgjq:  下个节气
    :attr csw:   财神位 [x, f, c] 喜神，福神，财神
    :attr yygs:  阴阳贵神 [yang, yin] 阳贵神 阴贵神
    """
    result = {
        'ndate': '',
        'gdate': '',
        'ywarn': '',
        'jwarn': '',
        'jrsy':  '',
        'jrsj':  '',
        'jsyq':  '',
        'xsyj':  '',
        'mqjq':  '',
        'xgjq':  '',
        'csw': {'x': '', 'f': '', 'c': ''},
        'yygs': {'yang': '', 'yin': ''}
    }
    payload = date.__format__('%Y/%Y-%m-%d.html') if date is not None else ''
    async with aiohttp.ClientSession() as c:
        r = await c.get(
            'https://www.laohuangli.net/' + payload,
            headers=HEADERS
        )
        soup = BeautifulSoup((await r.text()), features='lxml')
    table = soup.select_one(
        '.cate-box.mt-10 .title-table-index.table-border-box table')
    bg_table = table.select_one('.middle-rowspan')
    result['ndate'] = space_multiple_to_one(
        bg_table.select_one('.p-relative').text)
    date2 = space_multiple_to_one(
        bg_table.select_one('.page-btn-box span').text)
    result['gdate'] = space_multiple_to_one(bg_table.select_one(
        '.middle-rowspan p:first-child').text)
    # 【日值岁破 大事勿用】
    tf3 = table.select('.table-three-div', limit=2)
    appropriates = []
    for i in tf3[0].select('.t-center span'):
        appropriates.append(delete_space(i.text))
    result['jrsy'] = appropriates
    w = tf3[0].select_one('.t-center')
    [i.decompose() for i in w('span')]
    result['ywarn'] = space_multiple_to_one(w.text)

    taboos = []
    for i in tf3[1].select('.t-center span'):
        taboos.append(delete_space(i.text))
    result['jrsj'] = taboos
    w = tf3[1].select_one('.t-center')
    [i.decompose() for i in w('span')]
    result['jwarn'] = space_multiple_to_one(w.text)

    tf5 = table.select('.table-five-div', limit=2)
    jsyq = ''
    for i in tf5[0].select('.t-center span'):
        jsyq += delete_space(i.text)
    result['jsyq'] = jsyq
    xsyj = ''
    for i in tf5[1].select('.t-center span'):
        xsyj += delete_space(i.text)
    result['xsyj'] = xsyj

    jq = table.select_one('.text-p').select('td')
    result['mqjq'] = jq[0].text
    result['xgjq'] = jq[1].text

    e = soup.select('.table-box2 .img-box .flex-1.t-center')
    for i in e:
        for j in i('strong'):
            j.decompose()
    csw = e[0].select('li')
    result['csw']['x'] = delete_space(csw[0].text)
    result['csw']['f'] = delete_space(csw[1].text)
    result['csw']['c'] = delete_space(csw[2].text)
    yygs = e[1].select('li')
    result['yygs']['yang'] = delete_space(yygs[0].text)
    result['yygs']['yin'] = delete_space(yygs[1].text)
    return result

async def make_almanac(date: 'datetime | None' = None) -> str:
    """
    构建黄历图片并返回路径
    """
    date = date or datetime.datetime.now()
    out_path = os.path.join(
        card_path,
        date.__format__('%Y-%m-%d')+'.jpg'
    )
    data = (await chinese_almanac(date))
    bg = Draw.make_bg(1200, 1500)
    draw = ImgDraw(bg)
    await draw.init()
    await draw.openfont(FONT)
    draw.pos = (0, 30)

    await draw.putTextCenter('今日黄历', 1200, 0, 30, fontsize=100, fill=MANJIANGHONG)
    await draw.putTextCenter(data['gdate'], 1200, 0, 10, fontsize=32)
    await draw.putTextCenter(data['ndate'], 1200, 0, 30, fontsize=32)
    tmp = draw.y
    await draw.putTextCenter('宜', 600, 0, 20, fontsize=72, fill=YANHONG)
    await draw.putTextCenter(data['ywarn'], 600, 0, fontsize=32, fill=SHANCHAHONG)
    await draw.putTextCenter(linefeed(data['jrsy'], 15), 600, 0, 30, fontsize=32)
    maxy = draw.y
    draw.pos = (600, tmp)
    await draw.putTextCenter('忌', 600, 0, 20, fontsize=72, fill=YANHONG)
    await draw.putTextCenter(data['jwarn'], 600, 0, fontsize=32, fill=SHANCHAHONG)
    await draw.putTextCenter(linefeed(data['jrsj'], 15), 600, 0, 30, fontsize=32)
    draw.pos = (0, max(maxy, draw.y))

    tmp = draw.y
    await draw.putTextCenter('吉神宜趋', 600, 0, 20, fontsize=72, fill=YANHONG)
    await draw.putTextCenter(linefeed(data['jsyq'], 15), 600, 0, 30, fontsize=32)
    maxy = draw.y
    draw.pos = (600, tmp)
    await draw.putTextCenter('凶煞宜忌', 600, 0, 20, fontsize=72, fill=YANHONG)
    await draw.putTextCenter(linefeed(data['xsyj'], 15), 600, 0, 50, fontsize=32)

    draw.pos = (0, max(maxy, draw.y))
    await draw.putTextCenter('节    气', 1200, 0, 40, fontsize=72, fill=YANHONG)
    draw.x = 50
    await draw.putTextCenter(data['mqjq'], 500, -1, fontsize=32)
    draw.x = 550
    await draw.putTextCenter('==>', 100, -1, fontsize=32)
    draw.x = 650
    await draw.putTextCenter(data['xgjq'], 500, 0, 50, fontsize=32)

    draw.x = 0
    await draw.putTextCenter('财神位', 1200, 0, 30, fontsize=72, fill=YANHONG)
    await draw.putTextCenter(
        (
            '喜神', data['csw']['x'], '',
            '福神', data['csw']['f'], '',
            '财神', data['csw']['c']
        ), 1200, 0, 50, fontsize=50
    )
    draw.x = 0
    await draw.putTextCenter('阴阳贵神', 1200, 0, 30, fontsize=72, fill=YANHONG)
    await draw.putTextCenter(
        (
            '阳贵神', data['yygs']['yang'], '',
            '阴贵神', data['yygs']['yin']
        ), 1200, 0, 50, fontsize=50
    )

    draw.x = 800
    await draw.putText('临时版面 Sakuyark@2021', fill=(196, 196, 196))
    await draw.save(out_path)
    return os.path.abspath(out_path)

ca = on_command(
    '今日黄历', aliases={'黄历'},
    priority=2
)

@ca.handle()
async def _(bot: Bot, event: MessageEvent):
    path = (await make_almanac())
    await bot.send(event, image(path), at_sender=True)


import os
import psycopg2
import random
import sqlite3
import telebot
import time

types_dict = {
    0: 'Отжимания',
    10: 'Бег',
    20: 'Пресс'
}
push_ups = {
    1: 'Узким хватом',
    2: 'Средним хватом',
    3: 'Широким хватом',
    4: 'Задние',
}

def get_key(my_dict, val):
    for key, value in my_dict.items():
        if val == value:
            return key
    return None

keyboard_basic = telebot.types.ReplyKeyboardMarkup(True)
keyboard_activity = telebot.types.ReplyKeyboardMarkup(True, True)
keyboard_push_ups = telebot.types.ReplyKeyboardMarkup(True, True)
keyboard_basic.row('Внести данные', 'График')
for key in types_dict:
    keyboard_activity.add(types_dict[key])
for key in push_ups:
    keyboard_push_ups.add(push_ups[key])

DATABASE_URL = os.environ['DATABASE_URL']
token = os.environ.get('token', None)
bot = telebot.TeleBot(token)

@bot.message_handler(commands=['start'])
def start_message(message):
    bot.send_message(message.chat.id, 'Бот для статистики упражнений', reply_markup=keyboard_basic)

@bot.message_handler(content_types=['text'])
def send_text(message):
    chat_id = message.chat.id
    if message.text.lower() == 'привет':
        bot.send_message(chat_id, 'Приветствую тебя, мой ,белый хозяин!')
    elif message.text.lower() == 'внести данные':
        bot.send_message(chat_id, 'Выберите упражнение', reply_markup=keyboard_activity)
        bot.register_next_step_handler(message, choose_type)
    elif message.text.lower() == 'график':
        connection = psycopg2.connect(DATABASE_URL, sslmode='require')
        cursor = connection.cursor()
        try:
            cursor.execute(
                "SELECT type, result, date FROM measurements WHERE chat_id = %s ORDER BY date;"
                % chat_id
            )
        except:
            pass
        data = cursor.fetchall()
        for measurement in data:
            res = 'type: ' + str(measurement[0]) + ', result: ' + measurement[1] + ', date: ' + measurement[2]
            bot.send_message(chat_id, res, reply_markup=keyboard_basic)
        connection.close()

def choose_type(message):
    if message.text == types_dict[0]:
        bot.send_message(message.chat.id, 'Выберите тип отжимания', reply_markup=keyboard_push_ups)
        bot.register_next_step_handler(message, choose_type)
    else:
        bot.send_message(message.chat.id, 'Введите результаты тренировки')
        global activity_type
        activity_type = get_key(types_dict, message.text)
        if activity_type is None:
            activity_type = get_key(push_ups, message.text)
        # print(message, activity_type)
        bot.register_next_step_handler(message, enter_data)

def enter_data(message):
    conn = psycopg2.connect(DATABASE_URL, sslmode='require')
    cursor = conn.cursor()
    global activity_type
    try:
        cursor.execute(
            "INSERT INTO measurements (chat_id, type, result, date) VALUES (%s, %i, %s, %s)"
            % (message.chat.id, activity_type, message.text, time.strftime("%Y-%m-%d", time.gmtime()))
        )
        conn.commit()
    except Exception as exc:
        print(exc)
        bot.send_message(message.chat.id, 'Произошла какая-то ошибка', reply_markup=keyboard_basic)
    else:
        bot.send_message(message.chat.id, 'Данные успешно записаны!', reply_markup=keyboard_basic)
    conn.close()

# Executing
while True:
    try:
        bot.polling(none_stop=True)

    except Exception as e:
        print(e)
        time.sleep(15)


from flask import request
from flasgger.utils import swag_from
from flask import Blueprint

from usersServiceApp.core.report_logic import validate_and_create_report, get_reports_info, \
    validate_and_update_report_status, get_report_status_dataset
from usersServiceApp.errors.usersException import usersException
from flask import jsonify

bp_report = Blueprint('report', __name__, url_prefix='/report/')

@bp_report.route("/", methods=['POST'])
@swag_from(methods=['POST'])
def new_report():
    """
    Register a new report
    The form has to be complete.
    ---
    tags:
      - report
    consumes:
      - application/json
    parameters:
      - name: body
        in: body
        required: true
        schema:
            required:
              - id_report_type
              - id_user_reported
              - id_user_reported_by
            properties:
              id_report_type:
                type: integer
                description: id_report_type
              id_user_reported:
                type: integer
                description: id_user_reported
              id_user_reported_by:
                type: integer
                description: id_user_reported_by
              other_text:
                type: String
                description: text for other report
    responses:
      200:
        description: A successful profile creation
        schema:
          properties:
              id:
                type: integer
                description: Unique identifier of the created report
    """
    try:
        post_data = request.get_json()
        validate_and_create_report(post_data)
    except usersException as e:
        return jsonify({'Error': e.message}), e.error_code
    return jsonify(
        {'Status': "Report Created"}), 200

@bp_report.route("/<int:user_id>", methods=['GET'])
@swag_from(methods=['GET'])
def get_user_if_registered(user_id):
    """
    Get user if registered
    ---
    tags:
      - report
    parameters:
      - in: path
        name: user_id
        type: integer
        required: true
    responses:
      200:
        description: A single user info if registered
        schema:
          properties:
              id:
                type: integer
                description: Unique identifier of the created user
              first_name:
                type: string
                description: first name of the created user
    """
    try:
        _reports = get_reports_info(user_id)
    except usersException as e:
        return jsonify({'Error': e.message}), e.error_code
    return jsonify(_reports), 200

@bp_report.route("/<int:report_id>", methods=['PUT'])
@swag_from(methods=['PUT'])
def update_report(report_id):
    """
    update status report
    The form has to be complete.
    ---
    tags:
      - report
    consumes:
      - application/json
    parameters:
      - in: path
        name: report_id
        type: integer
        required: true
      - name: body
        in: body
        required: true
        schema:
            required:
              - is_pending
            properties:
              is_pending:
                type: boolean
                description: is_pending
    responses:
      200:
        description: A successful profile creation
        schema:
          properties:
              id:
                type: integer
                description: Unique identifier of the updated report
    """
    try:
        post_data = request.get_json()
        validate_and_update_report_status(report_id, post_data['is_pending'])
    except usersException as e:
        return jsonify({'Error': e.message}), e.error_code
    return jsonify(
        {'Status': "Report Updated"}), 200

@bp_report.route("/dataset", methods=['GET'])
@swag_from(methods=['GET'])
def get_report_dataset():
    """
    Get dataset
    ---
    tags:
      - report
    responses:
      200:
        description: A single user info if registered
        schema:
          properties:
              id:
                type: integer
                description: Unique identifier of the created user
    """
    try:
        _reports = get_report_status_dataset()
    except usersException as e:
        return jsonify({'Error': e.message}), e.error_code
    return jsonify(_reports), 200


#User function Template for python3

from typing import List

class Solution:
    def numberOfEnclaves(self, grid: List[List[int]]) -> int:
        if not grid:
            return 0

        def dfs(row, col):
            stack = [(row, col)]
            count = 0

            while stack:
                r, c = stack.pop()
                if (
                    r < 0
                    or r >= len(grid)
                    or c < 0
                    or c >= len(grid[0])
                    or grid[r][c] == 0
                ):
                    continue

                grid[r][c] = 0  # Mark the cell as visited
                count += 1

                # Add adjacent cells to the stack
                stack.append((r - 1, c))
                stack.append((r + 1, c))
                stack.append((r, c - 1))
                stack.append((r, c + 1))

            return count

        # Start DFS from the boundary land cells
        for row in range(len(grid)):
            if grid[row][0] == 1:
                dfs(row, 0)
            if grid[row][len(grid[0]) - 1] == 1:
                dfs(row, len(grid[0]) - 1)

        for col in range(len(grid[0])):
            if grid[0][col] == 1:
                dfs(0, col)
            if grid[len(grid) - 1][col] == 1:
                dfs(len(grid) - 1, col)

        # Count the remaining land cells (those not connected to the boundary)
        enclave_count = sum(row.count(1) for row in grid)

        return enclave_count

#{
 # Driver Code Starts
#Initial Template for Python 3

if __name__ == "__main__":
    for _ in range(int(input())):
        n, m = map(int,input().strip().split())
        grid = []
        for i in range(n):
            grid.append([int(i) for i in input().strip().split()])

        obj=Solution()
        print(obj.numberOfEnclaves(grid))
# } Driver Code Ends

GFG/Problem of the day/Number Of Enclaves.py


"""Provides a UPNP discovery method that mimics Hue hubs."""
import threading
import socket
import logging
import select

from aiohttp import web

from homeassistant import core
from homeassistant.components.http import HomeAssistantView
from .utility import *

_LOGGER = logging.getLogger(__name__)

class DescriptionXmlView(HomeAssistantView):
    """Handles requests for the description.xml file."""

    url = '/description.xml'
    name = 'description:xml'
    requires_auth = False

    def __init__(self, config):
        """Initialize the instance of the view."""
        self.config = config

    @core.callback
    def get(self, request):
        """Handle a GET request."""
        xml_template = """<?xml version="1.0" encoding="UTF-8" ?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://{0}:{1}/</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
<friendlyName>HASS Bridge ({0})</friendlyName>
<manufacturer>Royal Philips Electronics</manufacturer>
<manufacturerURL>http://www.philips.com</manufacturerURL>
<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>
<modelName>Philips hue bridge 2015</modelName>
<modelNumber>BSB002</modelNumber>
<modelURL>http://www.meethue.com</modelURL>
<serialNumber>{2}</serialNumber>
<UDN>uuid:01234567-89ab-cdef-0123-{2}</UDN>
</device>
</root>
"""

        resp_text = xml_template.format(
            self.config.advertise_ip, self.config.advertise_port,get_mac_address_noformat())

        return web.Response(text=resp_text, content_type='text/xml')

class UPNPResponderThread(threading.Thread):
    """Handle responding to UPNP/SSDP discovery requests."""

    _interrupted = False

    def __init__(self, host_ip_addr, listen_port, upnp_bind_multicast,
                 advertise_ip, advertise_port):
        """Initialize the class."""
        threading.Thread.__init__(self)

        self.host_ip_addr = host_ip_addr
        self.listen_port = listen_port
        self.upnp_bind_multicast = upnp_bind_multicast

        # Note that the double newline at the end of
        # this string is required per the SSDP spec
        resp_template = """HTTP/1.1 200 OK
CACHE-CONTROL: max-age=60
EXT:
LOCATION: http://{0}:{1}/description.xml
SERVER: HomeAssistant/0.6.5, UPnP/1.0, IpBridge/0.1
hue-bridgeid: {2}
ST: upnp:rootdevice
USN: uuid:01234567-89ab-cdef-0123-{3}::upnp:rootdevice

"""

        self.upnp_response = resp_template.format(
            advertise_ip, advertise_port, get_bridgeid(),get_mac_address_noformat()).replace("\n", "\r\n") \
                                         .encode('utf-8')

    def run(self):
        """Run the server."""
        # Listen for UDP port 1900 packets sent to SSDP multicast address
        ssdp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        ssdp_socket.setblocking(False)

        # Required for receiving multicast
        ssdp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        ssdp_socket.setsockopt(
            socket.SOL_IP,
            socket.IP_MULTICAST_IF,
            socket.inet_aton(self.host_ip_addr))

        ssdp_socket.setsockopt(
            socket.SOL_IP,
            socket.IP_ADD_MEMBERSHIP,
            socket.inet_aton("239.255.255.250") +
            socket.inet_aton(self.host_ip_addr))

        if self.upnp_bind_multicast:
            ssdp_socket.bind(("", 1900))
        else:
            ssdp_socket.bind((self.host_ip_addr, 1900))

        while True:
            if self._interrupted:
                clean_socket_close(ssdp_socket)
                return

            try:
                read, _, _ = select.select(
                    [ssdp_socket], [],
                    [ssdp_socket], 2)

                if ssdp_socket in read:
                    data, addr = ssdp_socket.recvfrom(1024)
                else:
                    # most likely the timeout, so check for interrupt
                    continue
            except socket.error as ex:
                if self._interrupted:
                    clean_socket_close(ssdp_socket)
                    return

                _LOGGER.error("UPNP Responder socket exception occurred: %s",
                              ex.__str__)
                # without the following continue, a second exception occurs
                # because the data object has not been initialized
                continue

            if "M-SEARCH" in data.decode('utf-8', errors='ignore'):
                # SSDP M-SEARCH method received, respond to it with our info
                resp_socket = socket.socket(
                    socket.AF_INET, socket.SOCK_DGRAM)

                resp_socket.sendto(self.upnp_response, addr)
                resp_socket.close()

    def stop(self):
        """Stop the server."""
        # Request for server
        self._interrupted = True
        self.join()

def clean_socket_close(sock):
    """Close a socket connection and logs its closure."""
    _LOGGER.info("UPNP responder shutting down.")

    sock.close()


from unittest import mock

import pytest

from pyda import data

def test__PropertyUpdateResponse__init__fails():
    with pytest.raises(
        AssertionError, match='"header" and "exception" '
        'are mutually exclusive arguments',
    ):
        data.PropertyUpdateResponse(
            query=mock.MagicMock(),
            header=mock.MagicMock(),
            exception=data.PropertyAccessError("Test error"),
        )

def test__PropertyUpdateResponse__header_succeeds():
    header = mock.MagicMock()
    resp = data.PropertyUpdateResponse(
        query=mock.MagicMock(),
        header=header,
    )
    assert resp.header is header

def test__PropertyUpdateResponse__header_fails():
    exc = data.PropertyAccessError("Test error")
    resp = data.PropertyUpdateResponse(
        query=mock.MagicMock(),
        exception=exc,
    )
    assert resp.exception is exc
    with pytest.raises(data.PropertyAccessError, match="Test error"):
        resp.header

@pytest.mark.parametrize(
    "kwargs,expected_str", [
        (
                {"header": "HEADER_OUTPUT", "query": "QUERY_OUTPUT"},
                "-- PropertyUpdateResponse from QUERY_OUTPUT --\n\n"
                "HEADER_OUTPUT",
        ),
        (
                {
                    "exception": data.PropertyAccessError("Test error"),
                    "query": "QUERY_OUTPUT",
                },
                "-- PropertyUpdateResponse from QUERY_OUTPUT --\n\n"
                "Exception occurred: Test error",
        ),
    ],
)
def test__PropertyUpdateResponse__str__(kwargs, expected_str):
    resp = data.PropertyUpdateResponse(**kwargs)
    assert str(resp) == expected_str