## Read sequence file to be examined for motifs ####
file_path = input ("Enter absolute path to the file containing the sequence to be tested:\n")
# Define holder variable for sequence to be read from file:
seq = ""
# Open file containing sequence:
sequence = open (file_path, "r") # read the file
# Read sequence line-by-line and append if not FASTA title:
for line in sequence:
    li = line.strip() # remove trailing spaces and new lines
    if not li.startswith('>'):
        seq = seq + line.strip() # removes all trailing spaces and \n's
sequence.close()
seq = seq.upper()

## Create PSSM from a JASPAR file for motif ####
motif = input ("Enter absolute path to the file containing the jaspar TF motif:\n")
from Bio import motifs
# Open file and read:
with open(motif) as handle:
    m = motifs.read(handle, "jaspar")
# Get relative proportion of nucleotides from test sequence:
A = seq.count("A")/len(seq) # proportion of A
C = seq.count("C")/len(seq) # proportion of C
G = seq.count("G")/len(seq) # proportion of G
T = seq.count("T")/len(seq) # proportion of T
pcounts = {"A":A, "C":C, "G":G, "T":T}
# Generate Position Weight Matrix from jaspar:
pwm = m.counts.normalize(pseudocounts=
{"A":0.6,"C":0.4,"G":0.4,"T":0.6})
# Generate Position-Specific Scoring Matrix for motif Searching
pssm = pwm.log_odds(pcounts)

## Search for instances usine PSSMs ####
thresh = int(input("Enter score threshold:\n")) # Ask for alignment score
from Bio.Seq import Seq
import operator
test_seq = Seq(seq, m.alphabet)
# Forward:
print("MOTIF ALIGNMENT:\nNegative positions denote reverse strand:\n")
for position, score in pssm.search(test_seq, threshold=thresh):
    print("Position %d: score = %5.3f \n Sequence = %s" %(position,score,
    test_seq[position:position+len(pssm.consensus)]))
results = [(position, score, test_seq[position:position+len(pssm.consensus)])
for position,score in pssm.search(test_seq, threshold=1.0)]
results.sort(key = operator.itemgetter(1),reverse=True) # sort the list based on Score

## Create tables and save as csv files ####
csvtable = input ("Enter absolute path and filename of table followed by '.csv':\n")
import csv # import module
# Forward
with open(csvtable, "w") as out:
    csv_out = csv.writer(out)
    csv_out.writerow(['StartPosition','Score','Sequence'])
    #for x in results:
    #    csv_out.writerow(x)
    csv_out.writerows(results)

'''
The negative positions refer to instances of the motif found on
the reverse strand of the test sequence, and follow the Python
convention on negative indices. Therefore, the instance of the motif
at pos is located at test_seq[pos:pos+len(m)] both for positive and
for negative values of pos.You may notice the threshold parameter,
here set arbitrarily to 3.0. This is in log2, so we are now looking only
for words, which are eight times more likely to occur under the motif model
than in the background. The default threshold is 0.0, which selects everything
that looks more like the motif than the background.
'''


# 코드로 실제 이미지 저장하는 법
import requests
import csv

# 변수 선언
movie_img_url = []
movie_codes = []

with open('movie_naver.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        movie_img_url.append(row['이미지URL']) # 인터넷 상의 이미지파일 리스터 저장
        movie_codes.append(row['영화 대표코드'])

# 요청 -> 파일 저장
for url, movieCd in zip(movie_img_url, movie_codes):
    with open(f'images/{movieCd}.jpg', 'wb') as f: # wb : 바이너리 파일을 쓰겠다.
        response = requests.get(url)
        f.write(response.content) # 텍스트형식(json, html, xml....)이 아닌 형식을 받을 때는 .content


"""
В этом модуле лежат различные наборы представлений.

Разные view интернет-магазина: по товарам, заказам и т.д.
"""

from django.shortcuts import render, redirect, reverse, get_object_or_404
from django.contrib.auth.models import Group
from django.http import HttpResponse, HttpRequest, HttpResponseRedirect, JsonResponse
from timeit import default_timer
from django.core.cache import cache
from django.urls import reverse_lazy
from django.views.generic import TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin
from rest_framework.viewsets import ModelViewSet
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema, OpenApiResponse
import logging

from .forms import ProductForm, OrdersForm, GroupForm
from .mixins import LogoutIfNotStaffMixin
from .models import Product, Order, ProductImage
from django.views import View
from .serializers import ProductSerialiser, OrderSerialiser

logger = logging.getLogger(__name__)

@extend_schema(description="Product views CRUD")
class ProductViewSet(ModelViewSet):
    """
    Набор представлений для действий над Product
    Полный CRUD для сущностей товара
    """
    queryset = Product.objects.all()
    serializer_class = ProductSerialiser
    filter_backends = [
        SearchFilter,
        DjangoFilterBackend,
        OrderingFilter,
    ]
    search_fields = ["name", "description"]
    filterset_fields = [
        "name",
        "description",
        "price",
        "discount",
        "archived",
    ]
    ordering_fields = [
        "name",
        "price",
        "discount",
    ]

    @extend_schema(
        summary="Get one product by ID",
        description="Retrieves **product**, returns 404 if not found",
        responses={
            200: ProductSerialiser,
            404: OpenApiResponse(description="Empty response, product by id not found"),
        }
    )
    def retrieve(self, request, *args, **kwargs):
        return super().retrieve(*args, **kwargs)

class OrderViewSet(ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = OrderSerialiser
    filter_backends = [
        SearchFilter,
        DjangoFilterBackend,
        OrderingFilter,
    ]
    search_fields = ["user", "products"]
    filterset_fields = [
        "delivery_address",
        "promocode",
        "created_at",
        "user",
        "products",
    ]
    ordering_fields = [
        "created_at",
        "user",
        "delivery_address",
    ]

class ShopIndexView(View):
    def get(self, request: HttpRequest) -> HttpResponse:
        products = [
            ('Laptop', 1999),
            ('Desktop', 2999),
            ('Smartphone', 999)
        ]
        context = {
            "time_running": default_timer(),
            "products": products,
            "items": 1,
        }
        return render(request, 'shopapp/shop-index.html', context=context)

class GroupsListView(View):
    def get(self, request: HttpRequest) -> HttpResponse:
        context = {
            "form": GroupForm(),
            "groups": Group.objects.prefetch_related('permissions').all(),
        }
        return render(request, 'shopapp/groups-list.html', context=context)

    def post(self, request: HttpRequest):
        form = GroupForm(request.POST)
        if form.is_valid():
            form.save()
        return redirect(request.path)

class ProductDetailsView(DetailView):
    template_name = "shopapp/product_details.html"
    # model = Product
    queryset = Product.objects.prefetch_related("images")
    context_object_name = "product"

    # def get(self, request: HttpRequest, pk: int) -> HttpResponse:
    #     product = get_object_or_404(Product, pk=pk)
    #     context = {
    #         "product": product,
    #     }
    #     return render(request, 'shopapp/products-details.html', context=context)

class ProductsListView(ListView):
    template_name = "shopapp/products-list.html"
    # model = Product
    context_object_name = "products"
    queryset = Product.objects.filter(archived=False)

# def products_list(request: HttpRequest):
#     context = {
#         "products": Product.objects.all(),
#     }
#     return render(request, 'shopapp/products-list.html', context=context)

class ProductCreateView(UserPassesTestMixin, CreateView):
    def test_func(self):
        # return self.request.user.groups.filter(name="secret-group").exists()
        return self.request.user.is_superuser

    model = Product
    fields = "name", "price", "description", "discount", "preview"
    success_url = reverse_lazy("shopapp:products_list")

# def create_product(request: HttpRequest) -> HttpResponse:
#     if request.method == "POST":
#         form = ProductForm(request.POST)
#         if form.is_valid():
#             # name = form.cleaned_data["name"]
#             # price = form.cleaned_data["price"]
#             form.save()
#             url = reverse("shopapp:products_list")
#             return redirect(url)
#     else:
#         form = ProductForm()
#     context = {
#         "form": form,
#     }
#     return render(request, "shopapp/create-product.html", context=context)

class ProductUpdateView(UpdateView):
    model = Product
    # fields = "name", "price", "description", "discount", "preview"
    form_class = ProductForm
    template_name_suffix = "_update_form"

    def get_success_url(self):
        return reverse(
            "shopapp:product_details",
            kwargs={"pk": self.object.pk},
        )

    def form_valid(self, form):
        response = super().form_valid(form)
        for image in form.files.getlist("images"):
            ProductImage.objects.create(product=self.object, image=image)
        return response

class ProductDeleteView(DeleteView):
    model = Product
    success_url = reverse_lazy("shopapp:products_list")

    def form_valid(self, form):
        success_url = self.get_success_url()
        self.object.archived = True
        self.object.save()
        return HttpResponseRedirect(success_url)

class OrdersListView(LoginRequiredMixin, ListView):
    queryset = (
        Order.objects
        .select_related("user")
        .prefetch_related("products")
    )

# def orders_list(request: HttpRequest):
#     context = {
#         "orders": Order.objects.select_related("user").prefetch_related("products").all(),
#     }
#     return render(request, 'shopapp/orders-list.html', context=context)

class OrderDetailView(PermissionRequiredMixin, DetailView):
    # permission_required = "view_order"
    permission_required = "shopapp.view_order"
    queryset = (
        Order.objects
        .select_related("user")
        .prefetch_related("products")
    )

class OrderCreateView(CreateView):
    model = Order
    fields = "user", "products", "promocode", "delivery_address"
    success_url = reverse_lazy("shopapp:order_list")
    logger.info(f'Создан заказ {fields}')

# def create_order(request: HttpRequest) -> HttpResponse:
#     if request.method == "POST":
#         form = OrdersForm(request.POST)
#         if form.is_valid():
#             form.save()
#             url = reverse("shopapp:order_list")
#             return redirect(url)
#     else:
#         form = OrdersForm()
#     context = {
#         "form": form,
#     }
#     return render(request, "shopapp/create-order.html", context=context)

class OrderUpdateView(UpdateView):
    model = Order
    fields = "user", "products"
    template_name_suffix = "_update_form"

    def get_success_url(self):
        return reverse(
            "shopapp:order_details",
            kwargs={"pk": self.object.pk},
        )

class OrderDeleteView(DeleteView):
    model = Order
    success_url = reverse_lazy("shopapp:order_list")

class ProductsDataExportView(View):
    def get(self, request: HttpRequest) -> JsonResponse:
        products = Product.objects.order_by("pk").all()
        products_data = [
            {
                "pk": product.pk,
                "name": product.name,
                "price": product.price,
                "archived": product.archived,
            }
            for product in products
        ]
        return JsonResponse({"products": products_data})

class OrderDataExportView(PermissionRequiredMixin, LogoutIfNotStaffMixin, View):
    permission_required = 'is_staff'

    def get(self, request: HttpRequest) -> JsonResponse:
        orders = Order.objects.order_by("pk").all()
        orders_data = [
            {
                "user": order.user.pk,
                "products": order.products.pk,
                "pk": order.pk,
                "promocode": order.promocode,
                "delivery_address": order.delivery_address,
            }
            for order in orders
        ]
        return JsonResponse({"orders": orders_data})


import rclpy
from rclpy.context import Context
from rclpy.node import Node
from geometry_msgs.msg import PoseArray, Pose, PoseStamped, TransformStamped
from std_msgs.msg import String
from typing import List
from pytransform3d import transformations as pt
from pytransform3d import rotations as pr
import numpy as np
import pycolmap
import trimesh
from pathlib import Path
import pickle
from sensor_msgs.msg import PointCloud2, PointField
from viewpoint_planner import ViewpointPlanner, PlannerModes
from viewpoint_planning.viewpoint import Camera
from std_msgs.msg import ColorRGBA, Header, Bool

from rclpy.parameter import Parameter

class ViewpointPlanningNode(Node):
    def __init__(self) -> None:
        super().__init__("viewpoint_planner")
        print('Hi from the viewpoint planner.')

        self.declare_parameter("home_directory", "/home")
        home_directory = self.get_parameter(
            'home_directory').get_parameter_value().string_value

        self.declare_parameter("map_name", "map-00195")
        map_name = self.get_parameter(
            'map_name').get_parameter_value().string_value
        environment = map_name.split(sep="-")[-1]

        self.declare_parameter(
            "cam_string", "PINHOLE 1280 720 609.5238037109375 610.1694946289062 640 360")
        cam_string = self.get_parameter(
            'cam_string').get_parameter_value().string_value

        self.declare_parameter(
            "mode_string", "trf_clf")
        mode_string = self.get_parameter(
            'mode_string').get_parameter_value().string_value

        self.declare_parameter(
            "planning_topic_name", "planning_poses")
        planning_topic_name = self.get_parameter(
            'planning_topic_name').get_parameter_value().string_value

        self.declare_parameter("occlusion", False)
        occlusion = self.get_parameter(
            'occlusion').get_parameter_value().bool_value

        self.declare_parameter("num_viewpoint_samples", 100)
        num_viewpoint_samples = self.get_parameter(
            'num_viewpoint_samples').get_parameter_value().integer_value

        self.plan_poses_sub = self.create_subscription(
            PoseArray, planning_topic_name, self.plan_poses_callback, 10)

        self.plan_single_pose_sub = self.create_subscription(TransformStamped, "plan_viewpoint", self.plan_viewpoint_callback, 10)
        self.viewpoint_result_map_pub = self.create_publisher(PoseStamped, "plan_viewpoint_result_map", 10)
        self.viewpoint_result_loc_cam_pub = self.create_publisher(PoseStamped, "plan_viewpoint_result_loc_cam", 10)
        self.planner_loc_pub = self.create_publisher(PoseStamped, "planner_loc", 10)
        self.mode_sub = self.create_subscription(String, "planner_mode", self.planner_mode_callback, 10)

        self.result_pose_publisher_map = self.create_publisher(
            PoseArray, 'viewpoint_poses_map', 10)

        self.result_pose_publisher_base = self.create_publisher(
            PoseArray, 'viewpoint_poses_base', 10)

        home_dir = Path(home_directory)
        environment_data = home_dir / \
            ('viewpoint_planning/data/' + environment)
        model_dir = home_dir / "viewpoint_planning/data/models"

        _, c_width, c_height, cfx, cfy, cx, cy = cam_string.split()
        camera = Camera(width=int(c_width),
                        height=int(c_height),
                        fx=float(cfx),
                        fy=float(cfy),
                        cx=float(cx),
                        cy=float(cy))

        reconstruction_dir = str(
            home_dir
        ) + f"/Hierarchical-Localization/outputs/{environment}/reconstruction"

        reconstruction = pycolmap.Reconstruction(reconstruction_dir)

        self.pc_publisher = self.create_publisher(PointCloud2, 'planning_pc', 10)

        self.landmark_list = list(reconstruction.points3D.keys())
        self.pcd_points = np.zeros((len(self.landmark_list), 3))

        for idx, landmark in enumerate(self.landmark_list):
            self.pcd_points[idx] = np.array(
                reconstruction.points3D[landmark].xyz)
        self.pointcloud_msg = self.point_cloud(points=self.pcd_points, parent_frame="map")
        self.pc_publisher.publish(self.pointcloud_msg)

        if occlusion:
            scene: trimesh.Trimesh = trimesh.load(
                str(environment_data) + f"/{environment}_mesh.ply")
        else:
            scene = None

        file = open(environment_data / "pose_dict.pkl", 'rb')
        pose_dict = pickle.load(file)
        file.close()

        file = open(environment_data / "landmark_dict.pkl", 'rb')
        landmark_dict = pickle.load(file)
        file.close()

        file = open(environment_data / "min_max.pkl", 'rb')
        min_max_dict = pickle.load(file)
        file.close()
        min_max_viewing_angles = min_max_dict["angles"]
        min_max_viewing_distances = min_max_dict["distances"]

        try:
            file = open(environment_data / "dino_3_landmark_dict.pkl", 'rb')
            dino_dict = pickle.load(file)
            file.close()
        except:
            print("ERROR")

        planner_mode = PlannerModes(mode_string)

        self.planner = ViewpointPlanner(
            pc_publisher = self.pc_publisher,
            mode=planner_mode,
            occlusion=occlusion,
            num_samples=num_viewpoint_samples,
            reconstruction=reconstruction,
            rc_scene=scene, camera=camera,
            landmark_dict=landmark_dict,
            dino_dict=dino_dict,
            model_dir=str(model_dir),
            min_max_viewing_angles=min_max_viewing_angles,
            min_max_viewing_distances=min_max_viewing_distances)

        self.T_zforward_zup = pt.transform_from(
            np.array([[0.0, -1.0, 0.0], [0.0, 0.0, -1.0], [1.0, 0.0,
                                                           0.0]]),
            np.array([0, 0.0, 0.0]))
        self.T_zup_zforward = np.linalg.inv(self.T_zforward_zup)

        self.mode_publisher = self.create_publisher(String, 'current_planner_mode', 10)
        timer_period = 0.5
        self.timer = self.create_timer(timer_period, self.timer_callback)

    def point_cloud(self, points, parent_frame):
        """ Creates a point cloud message.
        Args:
            points: Nx3 array of xyz positions.
            parent_frame: frame in which the point cloud is defined
        Returns:
            sensor_msgs/PointCloud2 message
        Code source:
            https://gist.github.com/pgorczak/5c717baa44479fa064eb8d33ea4587e0
        """
        ros_dtype = PointField.FLOAT32
        dtype = np.float32
        itemsize = np.dtype(dtype).itemsize  # A 32-bit float takes 4 bytes.

        data = points.astype(dtype).tobytes()
        fields = [PointField(
            name=n, offset=i * itemsize, datatype=ros_dtype, count=1)
            for i, n in enumerate('xyz')]
        header = Header(frame_id=parent_frame)

        return PointCloud2(
            header=header,
            height=1,
            width=points.shape[0],
            is_dense=False,
            is_bigendian=False,
            fields=fields,
            # Every point consists of three float32s.
            point_step=(itemsize * 3),
            row_step=(itemsize * 3 * points.shape[0]),
            data=data
        )

    def timer_callback(self):
        msg = String()
        msg.data = self.planner.mode.value
        self.mode_publisher.publish(msg)

    def plan_viewpoint_callback(self, msg: TransformStamped):
        translation = np.array([
            msg.transform.translation.x,
            msg.transform.translation.y,
            msg.transform.translation.z
        ])
        rotation = np.array([
            msg.transform.rotation.w,
            msg.transform.rotation.x,
            msg.transform.rotation.y,
            msg.transform.rotation.z,
        ])
        print(translation)

        planner_pose = PoseStamped()
        planner_pose.header.frame_id = "map"
        planner_pose.header.stamp = self.get_clock().now().to_msg()

        planner_pose.pose.position.x = msg.transform.translation.x
        planner_pose.pose.position.y = msg.transform.translation.y
        planner_pose.pose.position.z = msg.transform.translation.z

        planner_pose.pose.orientation.x = msg.transform.rotation.x
        planner_pose.pose.orientation.y = msg.transform.rotation.y
        planner_pose.pose.orientation.z = msg.transform.rotation.z
        planner_pose.pose.orientation.w = msg.transform.rotation.w

        self.planner_loc_pub.publish(planner_pose)

        pq = np.concatenate([translation, rotation])
        transformation_matrix = pt.invert_transform(pt.transform_from_pq(pq))
        planning_poses = [transformation_matrix]

        viewpoint_dict = self.planner.plan_viewpoints(planning_poses)

        viewpoint_poses_map = []
        viewpoint_poses_base = []

        viewpoint_poses_map_d = []
        viewpoint_poses_base_d = []

        for result in viewpoint_dict.keys():
            T_cam_map = viewpoint_dict[result]["T_cam_map"]
            T_map_cam = np.linalg.inv(self.T_zup_zforward @ T_cam_map)

            T_cam_base = viewpoint_dict[result]["T_cam_base"]
            T_base_cam = np.linalg.inv(self.T_zup_zforward @ T_cam_base)

            viewpoint_poses_map.append(self.transform_to_pose_stamped(T_map_cam, "map"))
            viewpoint_poses_base.append(self.transform_to_pose_stamped(T_base_cam, "hand"))

            viewpoint_poses_map_d.append(self.transform_to_pose(T_map_cam))
            viewpoint_poses_base_d.append(self.transform_to_pose(T_base_cam))
            # print(pt.pq_from_transform(T_base_cam))
            # print(pr.euler_from_quaternion(pt.pq_from_transform(T_base_cam)[3:], 2,1,0, False))
        self.viewpoint_result_map_pub.publish(viewpoint_poses_map[0])
        self.viewpoint_result_loc_cam_pub.publish(viewpoint_poses_base[0])

        result_pose_array_map = self.create_pose_array(viewpoint_poses_map_d)
        result_pose_array_base = self.create_pose_array(viewpoint_poses_base_d)
        self.result_pose_publisher_map.publish(result_pose_array_map)
        self.result_pose_publisher_base.publish(result_pose_array_base)

    def plan_poses_callback(self, msg):
        # Convert each pose in the received request to a 4x4 transformation matrix

        T_cam_base_orig = np.array(
            [[0.0, -1.0, 0.0, 0.0],
             [0.0, 0.0, -1.0, 0.0],
             [1.0, 0.0, 0.0, 0.0],
             [0.0, 0.0, 0.0, 1.0]])
        planning_poses = []
        for pose in msg.poses:

            translation = np.array([
                -pose.position.x,
                -pose.position.y,
                -pose.position.z
            ])
            rotation = np.array([
                pose.orientation.w,
                pose.orientation.x,
                pose.orientation.y,
                pose.orientation.z,

            ])
            pq = np.concatenate([translation, rotation])
            transformation_matrix = pt.transform_from_pq(pq)
            planning_poses.append(transformation_matrix)

        viewpoint_dict = self.planner.plan_viewpoints(planning_poses)

        viewpoint_poses_map = []
        viewpoint_poses_base = []
        for result in viewpoint_dict.keys():
            T_cam_map = viewpoint_dict[result]["T_cam_map"]
            T_map_cam = np.linalg.inv(self.T_zup_zforward @ T_cam_map)

            T_cam_base = viewpoint_dict[result]["T_cam_base"]
            T_base_cam = np.linalg.inv(self.T_zup_zforward @ T_cam_base)

            viewpoint_poses_map.append(self.transform_to_pose(T_map_cam))
            viewpoint_poses_base.append(self.transform_to_pose(T_base_cam))

        result_pose_array_map = self.create_pose_array(viewpoint_poses_map)
        result_pose_array_base = self.create_pose_array(viewpoint_poses_base)

        self.result_pose_publisher_map.publish(result_pose_array_map)
        self.result_pose_publisher_base.publish(result_pose_array_base)

    def planner_mode_callback(self, msg: String):
        self.planner.change_mode(msg.data)
        print(f"Planner mode changed to {msg.data}")

    def transform_to_pose(self, transformation_matrix):
        pq = pt.pq_from_transform(transformation_matrix)
        pose = Pose()
        pose.position.x = pq[0]
        pose.position.y = pq[1]
        pose.position.z = pq[2]

        pose.orientation.x = pq[4]
        pose.orientation.y = pq[5]
        pose.orientation.z = pq[6]
        pose.orientation.w = pq[3]
        return pose

    def transform_to_pose_stamped(self, transformation_matrix, frame):
        pq = pt.pq_from_transform(transformation_matrix)
        pose = PoseStamped()
        pose.header.frame_id = frame
        pose.header.stamp = self.get_clock().now().to_msg()
        pose.pose.position.x = pq[0]
        pose.pose.position.y = pq[1]
        pose.pose.position.z = pq[2]

        pose.pose.orientation.x = pq[4]
        pose.pose.orientation.y = pq[5]
        pose.pose.orientation.z = pq[6]
        pose.pose.orientation.w = pq[3]
        return pose

    def rotation_matrix_to_quaternion(self, rotation_matrix):
        qw = np.sqrt(
            1 + rotation_matrix[0, 0] + rotation_matrix[1, 1] + rotation_matrix[2, 2]) / 2
        qx = (rotation_matrix[2, 1] - rotation_matrix[1, 2]) / (4 * qw)
        qy = (rotation_matrix[0, 2] - rotation_matrix[2, 0]) / (4 * qw)
        qz = (rotation_matrix[1, 0] - rotation_matrix[0, 1]) / (4 * qw)
        return [qx, qy, qz, qw]

    def create_pose_array(self, poses):
        pose_array = PoseArray()
        pose_array.header.frame_id = 'map'  # Set the frame ID for the PoseArray
        pose_array.poses = poses
        return pose_array

def main(args=None):
    rclpy.init(args=args)
    print('Hi from learned_viewpoint_planning.')

    viewpoint_planner = ViewpointPlanningNode()

    rclpy.spin(viewpoint_planner)

    viewpoint_planner.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()


"""
Module to implement a plugin that ensures that all Unordered List Items
start at the beginning of the line.
"""
from typing import List, cast

from pymarkdown.general.parser_helper import ParserHelper
from pymarkdown.plugin_manager.plugin_details import PluginDetails
from pymarkdown.plugin_manager.plugin_scan_context import PluginScanContext
from pymarkdown.plugin_manager.rule_plugin import RulePlugin
from pymarkdown.tokens.block_quote_markdown_token import BlockQuoteMarkdownToken
from pymarkdown.tokens.list_start_markdown_token import ListStartMarkdownToken
from pymarkdown.tokens.markdown_token import MarkdownToken

class RuleMd006(RulePlugin):
    """
    Class to implement a plugin that ensures that all Unordered List Items
    start at the beginning of the line.
    """

    def __init__(self) -> None:
        super().__init__()
        self.__token_stack: List[MarkdownToken] = []

    def get_details(self) -> PluginDetails:
        """
        Get the details for the plugin.
        """
        return PluginDetails(
            plugin_name="ul-start-left",
            plugin_id="MD006",
            plugin_enabled_by_default=False,
            plugin_description="Consider starting bulleted lists at the beginning of the line",
            plugin_version="0.5.0",
            plugin_interface_version=1,
            plugin_url="https://github.com/jackdewinter/pymarkdown/blob/main/docs/rules/rule_md006.md",
        )

    def starting_new_file(self) -> None:
        """
        Event that the a new file to be scanned is starting.
        """
        self.__token_stack = []

    def __calculate_expected_indent(self) -> int:
        expected_indent = 0
        if len(self.__token_stack) > 1:
            if self.__token_stack[-2].is_block_quote_start:
                block_quote_token = cast(
                    BlockQuoteMarkdownToken, self.__token_stack[-2]
                )
                assert block_quote_token.bleading_spaces is not None
                split_spaces = block_quote_token.bleading_spaces.split(
                    ParserHelper.newline_character
                )
                expected_indent = len(split_spaces[0]) + (
                    block_quote_token.column_number - 1
                )
            else:
                list_token = cast(ListStartMarkdownToken, self.__token_stack[-2])
                expected_indent = list_token.indent_level
        return expected_indent

    def next_token(self, context: PluginScanContext, token: MarkdownToken) -> None:
        """
        Event that a new token is being processed.
        """
        if token.is_list_start or token.is_block_quote_start:
            self.__token_stack.append(token)
            if token.is_unordered_list_start:
                expected_indent = self.__calculate_expected_indent()
                if token.column_number != (1 + expected_indent):
                    self.report_next_token_error(context, token)
        elif token.is_list_end or token.is_block_quote_end:
            del self.__token_stack[-1]
        elif token.is_new_list_item:
            if self.__token_stack[-1].is_unordered_list_start:
                expected_indent = self.__calculate_expected_indent()
                if token.column_number != (1 + expected_indent):
                    self.report_next_token_error(context, token)


from itertools import product as pd

h, w, k = map(int, input().split())
c = [list(input()) for _ in range(h)]

ans = 0
for i, j in pd(range(1 << h), range(1 << w)):
    temp = 0
    for x, y in pd(range(h), range(w)):
        if 1 << x & i and 1 << y & j:
            if c[x][y] == "#":
                temp += 1
    ans += temp == k
print(ans)


# -*- coding: utf-8 -*-
# snapshottest: v1 - https://goo.gl/zC4yUc
from __future__ import unicode_literals

from snapshottest import Snapshot

snapshots = Snapshot()

snapshots['CategoryTestCase::test_can_fetch_all_categories 1'] = {
    'data': {
        'categoryList': {
            'edges': [
                {
                    'node': {
                        'description': 'For people who want to be happy.',
                        'featuredImage': 'https://cdn.eleganttheme.com/1',
                        'id': 'Q2F0ZWdvcnlOb2RlOjI3',
                        'name': 'Swimming Meetup 1'
                    }
                },
                {
                    'node': {
                        'description': 'For people who want to be happy.',
                        'featuredImage': 'https://cdn.eleganttheme.com/2',
                        'id': 'Q2F0ZWdvcnlOb2RlOjI4',
                        'name': 'Swimming Meetup 2'
                    }
                },
                {
                    'node': {
                        'description': 'For people who want to be happy.',
                        'featuredImage': 'https://cdn.eleganttheme.com/3',
                        'id': 'Q2F0ZWdvcnlOb2RlOjI5',
                        'name': 'Swimming Meetup 3'
                    }
                },
                {
                    'node': {
                        'description': 'For people who want to be happy.',
                        'featuredImage': 'https://cdn.eleganttheme.com/4',
                        'id': 'Q2F0ZWdvcnlOb2RlOjMw',
                        'name': 'Swimming Meetup 4'
                    }
                },
                {
                    'node': {
                        'description': 'For people who want to be happy.',
                        'featuredImage': 'https://cdn.eleganttheme.com/5',
                        'id': 'Q2F0ZWdvcnlOb2RlOjMx',
                        'name': 'Swimming Meetup 5'
                    }
                }
            ]
        }
    }
}

snapshots['CategoryTestCase::test_can_fetch_single_category 1'] = {
    'data': {
        'category': {
            'description': 'For people who want to be happy.',
            'featuredImage': 'https://cdn.eleganttheme.com/5',
            'id': 'Q2F0ZWdvcnlOb2RlOjM2',
            'name': 'Swimming Meetup 5'
        }
    }
}


import logging
import os

# Logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

if not logger.hasHandlers():
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)
    ch.setFormatter(logging.Formatter(
        '%(levelname)s: %(name)s - %(message)s'
    ))
    logger.addHandler(ch)

def create_new_logger(new_logger, name):
    name = filename_to_loggingname(name)
    new_logger.setLevel(logging.INFO)
    ch = logging.StreamHandler()
    ch.setLevel(logging.INFO)
    ch.setFormatter(logging.Formatter(
        '%(levelname)s: {} - %(message)s'.format(name)
    ))
    new_logger.addHandler(ch)
    return new_logger

def filename_to_loggingname(filename):
    # assumption is that asr_standardized_combined occurs 2x in path e.g. .../asr_standardized_combined/asr_standardized_combined/standardize/standardize_nbtale12.py
    package_name = 'asr_standardized_combined'
    # get everything after the first package name
    filename = os.path.normpath(filename)
    return '.'.join([part for part in filename[filename.index(package_name) + len(package_name):].strip('.py').split(os.sep) if part])


from flask import jsonify, make_response, request
import sqlalchemy
import models
from flask import Blueprint
person_bp = Blueprint('person', __name__)

@person_bp.route("/person")
def get_all_person():
    person_list = models.Person.query.all()
    return jsonify([models.row2dict(person) for person in person_list])

@person_bp.route("/person/<person_name>")
def get_person_by_name(person_name):
    # id is a primary key, so we'll have max 1 result row
    person = models.Person.query.filter_by(name=person_name).first()
    if person:
        return jsonify(models.row2dict(person))
    else:
        return make_response(jsonify({"code": 404, "msg": "Cannot find this person name."}), 404)

@person_bp.route("/person/<int:person_id>")
def get_person(person_id):
    # id is a primary key, so we'll have max 1 result row
    person = models.Person.query.filter_by(id=person_id).first()
    if person:
        return jsonify(models.row2dict(person))
    else:
        return make_response(jsonify({"code": 404, "msg": "Cannot find this person id."}), 404)

@person_bp.route("/person", methods={"PUT"})
def create_person():
    # get the name first, if no name then fail
    name = request.form.get("name")
    if not name:
        return make_response(jsonify({"code": 403,
                                      "msg": "Cannot put person. Missing mandatory fields."}), 403)
    person_id = request.form.get("id")
    if not person_id:
        p = models.Person(name=name)
    else:
        p = models.Person(id=person_id, name=name)

    models.db.session.add(p)
    try:
        models.db.session.commit()
    except sqlalchemy.exc.SQLAlchemyError as e:
        error = "Cannot put person. "
        print(person_bp.config.get("DEBUG"))
        if person_bp.config.get("DEBUG"):
            error += str(e)
        return make_response(jsonify({"code": 404, "msg": error}), 404)
    return jsonify({"code": 200, "msg": "success"})

@person_bp.route("/person/update", methods={"PUT"})
def update_person():
    # get the movie name first, if no movie name then fail
    person_name = request.form.get("name")
    person_id = request.form.get("id")
    if not person_id:
        return make_response(jsonify({"code": 403,
                                      "msg": "Cannot update person. Missing mandatory fields."}), 403)

    person = models.Person.query.filter_by(id=person_id).first()
    if not person:
        return make_response(jsonify({"code": 404, "msg": "Cannot find this person id."}), 404)

    person.name = person_name

    try:
        models.db.session.commit()
    except sqlalchemy.exc.SQLAlchemyError as e:
        error = "Cannot update person. "
        print(person_bp.config.get("DEBUG"))
        if person_bp.config.get("DEBUG"):
            error += str(e)
        return make_response(jsonify({"code": 404, "msg": error}), 404)
    return jsonify({"code": 200, "msg": "success"})

@person_bp.route("/person/delete", methods={"PUT"})
def delete_person():
    person_id = request.form.get("person_id")
    # id is a primary key, so we'll have max 1 result row
    person = models.Person.query.filter_by(id=person_id).first()
    if person:
        models.db.session.delete(person)
        try:
            models.db.session.commit()
        except sqlalchemy.exc.SQLAlchemyError as e:
            error = "Cannot delete person. "
            print(person_bp.config.get("DEBUG"))
            if person_bp.config.get("DEBUG"):
                error += str(e)
            return make_response(jsonify({"code": 404, "msg": error}), 404)
        return jsonify({"code": 200, "msg": "person is successfully deleted"})
    else:
        return make_response(jsonify({"code": 404, "msg": "Cannot find this person id."}), 404)


# Exercícios LISTA DE TAREFAS
import os
import json

tarefas = []
apagados = []

def ler(tarefas):
    temporarios = []
    try:
        with open('lista_de_tarefas.json', 'r', encoding='utf8') as file:
            temporarios = json.load(file)
        if tarefas != []:
            while True:
                resposta = input('Deseja adicionar os itens carregados aos itens existentes na lista? [S/N]').upper()
                if resposta not in 'SsNn':
                    print('RESPOSTA INVÁLIDA')
                    print()
                else:
                    break
            if resposta == 'N':
                for c in range(len(tarefas)):
                    tarefas.pop()
        for temporario in temporarios:
            tarefas.append(temporario)
        return tarefas

    except FileNotFoundError:
        print('Nenhum Arquivo .json encontrado para carregar.')

def salvar(tarefas):
    with open('lista_de_tarefas.json', 'w', encoding='utf8') as file:
        json.dump(tarefas, file,ensure_ascii=False, indent=2)

def adicionar(tarefas, acao):
    if acao == 'sair':
        return
    tarefas.append(acao)
    print(f'Tarefa {acao} adicionada na lista de tarefas.')

def listar(tarefas):
    print()
    if not tarefas:
        try:
            with open('lista_de_tarefas.json', 'r', encoding='utf8') as file:
                tarefas = json.load(file)
        except FileNotFoundError:
            print('LISTA DE TAREFAS ESTÁ VAZIA')
            print()
            return
    print('-'*13)
    print(f'{"   TAREFAS"}')
    print('-'*13)
    for tarefa in tarefas:
        print(f'- {tarefa}')
    print()

def desfazer(tarefas):
    print()
    if not tarefas:
        print('-' * 27)
        print('Nada mais para ser desfeito'.upper())
        print('-' * 27)
        return

    ultimo = tarefas[-1]
    apagados.append(ultimo)
    print(f'Tarefa {ultimo} removida da lista de tarefas.')
    tarefas.pop()
    print()

def refazer(tarefas, apagados):
    if not apagados:
        print('-' * 21)
        print('Nada para ser refeito'.upper())
        print('-' * 21)
        return
    tarefas.append(apagados[-1])
    print(f'Tarefa {apagados[-1]} retornada a lista de tarefas.')
    apagados.pop(-1)
    print()

while True:
    print()
    print('Comandos: listar, desfazer, refazer, sair(para sair), ler, salvar.', )
    acao = input('Digite uma tarefa ou um comando:').lower().strip()
    print()
    if acao == 'sair':
        break
    comandos = {
        'listar' : lambda : listar(tarefas),
        'desfazer' : lambda : desfazer(tarefas),
        'refazer' : lambda : refazer(tarefas, apagados),
        'listar' : lambda : listar(tarefas),
        'clear' : lambda : os.system('cls'),
        'adicionar' : lambda : adicionar(tarefas, acao),
        'salvar' : lambda : salvar(tarefas),
        'ler' : lambda : ler(tarefas),

    }

    comando = comandos.get(acao) if comandos.get(acao) is not None else comandos['adicionar']
    comando()


# coding=utf-8
"""
@Time : 2020/6/9 17:49
@Author: zhangqian
"""

import asyncio
import json
from os import makedirs
from os.path import exists

from pyppeteer import launch
import logging
from pyppeteer.errors import TimeoutError

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s')
# INDEX_URL = 'https://dynamic5.scrape.cuiqingcai.com/api/book/?limit=18&offset={offset}'
INDEX_URL = 'https://dynamic2.scrape.cuiqingcai.com/page/{page}'
DETAIL_URL = 'https://dynamic5.scrape.cuiqingcai.com/api/book/{id}'
MAX_PAGE = 3
PAGE_SIZE = 18
WINDOW_WIDTH, WINDOW_HEIGHT = 1366, 768
HEADLESS = False
browser, tab = None, None
TIMEOUT = 15
HEADLESS = True
RESULTS_DIR = 'results'
exists(RESULTS_DIR) or makedirs(RESULTS_DIR)

async def init():
    '''
    根据selector判断该页面元素是否可操作
    :return:
    '''
    global browser, tab
    browser = await launch(headless=HEADLESS,
                           args=['--disable-infobars',
                                 f'--window-size={WINDOW_WIDTH},{WINDOW_HEIGHT}'])
    tab = await browser.newPage()
    await tab.setViewport({'width': WINDOW_WIDTH, 'height': WINDOW_HEIGHT})

async def scrape_page(url, selector):
    '''
    根据selector判断该页面元素是否可操作
    :param url:
    :param selector:
    :return:
    '''
    logging.info('scrape page %s', url)
    try:
        await tab.goto(url)
        await tab.waitForSelector(selector, options={'timeout': TIMEOUT * 1000})  # 会出现timeout 15000ms exceeds
        # await asyncio.wait([tab.waitForNavigation(), tab.querySelector(selector)])
    except TimeoutError:
        logging.error('error occurred while scraping %s', url, exc_info=True)

async def scrape_index(page):
    '''
    根据页码生成的列表url、元素选择器判断是否可操作
    :param page:
    :return:
    '''
    url = INDEX_URL.format(page=page)
    await scrape_page(url, '.item .name')

async def parse_index():
    '''
    解析列表页，返回详情页链接
    :return:
    '''
    return await tab.querySelectorAllEval('.item .name', 'nodes => nodes.map(node => node.href)')

async def scrape_detail(url):
    '''
    判断详情页是否可操作
    :param url:
    :return:
    '''
    await scrape_page(url, 'h2')

async def parse_detail():
    '''
    解析详情页，返回json
    :return:
    '''
    url = tab.url
    name = await tab.querySelectorEval('.m-b-sm', 'node => node.innerText')
    categories = await tab.querySelectorAllEval('.categories button span', 'nodes => nodes.map(node => node.innerText)')
    score = await tab.querySelectorEval('.score', 'node => node.innerText')
    cover = await tab.querySelectorEval('.cover', 'node => node.src')
    drama = await tab.querySelectorEval('.drama p', 'node => node.innerText')
    return {
        'url': url,
        'name': name,
        'score': score,
        'categories': categories,
        'cover': cover,
        'drama': drama
    }

async def save_data(data):
    name = data.get('name')
    data_path = f'{RESULTS_DIR}/{name}.json'
    json.dump(data, open(data_path, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)

async def main():
    await init()
    try:
        for page in range(1, MAX_PAGE+1):
            await scrape_index(page)
            detail_urls = await parse_index()
            logging.info('detailUrls %s', detail_urls)
            for detail_url in detail_urls:
                await scrape_detail(detail_url)
                res = await parse_detail()
                logging.info('data : %s', res)
                await save_data(res)
                logging.info('save data.')
    finally:
        await browser.close()

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())


from collections import Counter, OrderedDict, defaultdict
from finedial.utils.logging.logger_helper import logger
from torchtext.vocab import Vocab

def load_vocab(vocab_path, special_tokens=[], placeholder_tokens=0, enable_duplication=False, reset_unk=None):
    """
     创建词表，
        Args:
            vocab_path: 需要给定的是已经排序好，确定好词表的文件，这里仅增加特殊符号
            special_tokens: 哪些特殊符号
            placeholder_tokens: 哪些需要创建的特殊符号，以及对应的最大数量。
            enable_duplication: 多个词表之间是否允许重复
    """
    counter = Counter()
    assert vocab_path is not None
    if isinstance(vocab_path, str):
        with open(vocab_path, 'r+', encoding='utf-8') as fin:
            vocabs = [x.strip('\r\n') for x in fin.readlines()]
            assert len(vocabs) == len(set(vocabs))
    elif isinstance(vocab_path, list):
        vocabs = []
        vocab_set = set()
        for sub_vocab_path in vocab_path:
            with open(sub_vocab_path, 'r+', encoding='utf-8') as fin:
                sub_vocabs = [x.strip('\r\n') for x in fin.readlines()]
                if not enable_duplication:
                    assert len(vocab_set - set(sub_vocabs)) == 0
                    assert len(set(sub_vocabs)) == len(sub_vocabs)
                vocabs += sub_vocabs
    else:
        raise NotImplementedError()

    vocabs += ['<%s_%d>' % ('dmc', x) for x in range(placeholder_tokens)]
    vocab_size = len(vocabs)
    for idx, token in enumerate(vocabs):
        counter[token] = vocab_size - idx

    specials = list(OrderedDict.fromkeys(tok for tok in special_tokens if tok is not None))
    vocab = Vocab(counter, specials=specials)
    if reset_unk is None:
        return vocab
    # 增加
    unk_index = vocab.stoi[reset_unk]
    new_stoi = defaultdict(lambda :unk_index)
    for k, v in vocab.stoi.items():
        new_stoi[k] = v
    vocab.stoi = new_stoi
    return vocab

def load_vocab_from_list(vocabs, sp_tokens=None):
    """
     创建词表，
        Args:
            vocab: 已经确定好的词表
    """
    counter = Counter()
    vocab_size = len(vocabs)
    vocabs = list(vocabs)
    if sp_tokens is not None:
        vocab_set = set(vocabs)
        vocab_dict = dict()
        for word in vocabs:
            vocab_dict[word] = len(vocab_dict)
        unused_id = 0
        res = ''
        for sp_token in sp_tokens:
            if sp_token not in vocab_set:
                unused_id += 1
                uid = '[unused%d]' % unused_id
                assert uid in vocab_dict, 'unused id is not enough : %s, vocablist=%s' % (uid, str(vocab_dict))
                vocabs[vocab_dict[uid]] = sp_token
                vocab_dict[sp_token] = unused_id
                res += '%s->%s ' % (uid, sp_token)
                vocab_set.add(sp_token)
        logger.info('[SP_TOKEN MAP] %s' % res)
    for idx, token in enumerate(vocabs):
        counter[token] = vocab_size - idx
    return Vocab(counter, specials=[])


from distutils import dist
from io import StringIO
from json import dumps
from pkg_resources import DistributionNotFound, get_distribution

from fastapi.responses import HTMLResponse
from jinja2 import Template

from microcosm_fastapi.templates.landing import template

def configure_landing(graph):  # noqa: C901
    def get_properties_and_version():
        """
        Parse the properties from the package information
        """
        try:
            distribution = get_distribution(graph.metadata.name)
            metadata_str = distribution.get_metadata(distribution.PKG_INFO)
            package_info = dist.DistributionMetadata()
            package_info.read_pkg_file(StringIO(metadata_str))
            return package_info
        except DistributionNotFound:
            return None

    def iter_endpoints(graph, match_func):
        for route in graph.app.routes:
            if match_func(route.path):
                yield route

    def get_swagger_versions():
        """
        Finds all swagger conventions that are bound to the graph

        """
        versions = []

        def is_swagger_endpoint(path):
            """
            Defines a condition to determine which endpoints are swagger type

            """
            return graph.config.swagger_convention.name in path

        for route in iter_endpoints(graph, is_swagger_endpoint):
            # route comes in as /api/v2/swagger
            # so we split to get this -> ['', 'api', 'v2', 'swagger']
            # and then get the version value from the array
            versions.append(route.path.split("/")[2])

        return versions

    def pretty_dict(dict_):
        return dumps(dict_, sort_keys=True, indent=2, separators=(",", ": "))

    def get_env_file_commands(config, conf_key, conf_string=None):
        if conf_string is None:
            conf_string = []
        for key, value in config.items():
            if isinstance(value, dict):
                get_env_file_commands(value, "{}__{}".format(conf_key, key), conf_string)
            else:
                conf_string.append(
                    "export {}__{}='{}'".format(conf_key.upper(), key.upper(), value)
                )
        return conf_string

    def get_links(swagger_versions, properties):
        # add links set in config
        links = {
            key: value
            for (key, value) in graph.config.landing_convention.get("links", {}).items()
        }

        # add links for each swagger version
        for swagger_version in swagger_versions:
            links["swagger {}".format(swagger_version)] = "api/{}/swagger".format(swagger_version)

        # add link to home page
        if hasattr(properties, "url"):
            links["home page"] = properties.url

        return links

    @graph.app.get("/")
    async def render_landing_page():
        """
        Render landing page

        """
        config = graph.config_convention.to_dict()
        env = get_env_file_commands(config, graph.metadata.name)

        health = await graph.health_convention.to_object()
        health = health.dict()

        properties = get_properties_and_version()
        swagger_versions = get_swagger_versions()

        html = Template(template).render(
            config=pretty_dict(config),
            description=properties.description if properties else None,
            env=env,
            health=pretty_dict(health),
            links=get_links(swagger_versions, properties),
            service_name=graph.metadata.name,
            version=getattr(properties, "version", None),
        )

        return HTMLResponse(html)


import os
import logging
from osgeo import gdalconst
from osgeo import ogr
from osgeo import osr

from .version import __program__

class OgrDatasource:
    def __init__(self, translation, source_proj4=None, source_epsg=None, gisorder=False, \
                       source_encoding='utf-8'):
        self.logger = logging.getLogger(__program__)
        self.datasource = None
        self.is_database_source = False
        self.query = None
        self.translation = translation
        self.source_proj4 = source_proj4
        self.source_epsg = source_epsg
        self.gisorder = gisorder
        self.source_encoding = source_encoding

    def open_datasource(self, ogrpath, prefer_mem_copy=True):
        full_ogrpath = None

        # database source ?
        if ogrpath.startswith('PG:'):
            self.is_database_source = True
            full_ogrpath = ogrpath
        else:
            # unsupported access method ?
            ogr_unsupported = [ "vsimem", "vsistdout" ]
            has_unsup = [ m for m in ogr_unsupported if m in ogrpath.split('/') ]
            if has_unsup:
                self.logger.error("Unsupported OGR access method(s) found: %s.", \
                                  ', '.join(has_unsup))

            # using ogr access methods ?
            ogr_accessmethods = [ "vsicurl", "vsicurl_streaming", "vsisubfile", "vsistdin" ]
            if any([ m in ogrpath.split('/') for m in ogr_accessmethods ]):
                full_ogrpath = ogrpath
            else:
                filename = ogrpath

                # filter out file access method if present
                ogr_filemethods = [ "/vsisparse/", "/vsigzip/", "/vsitar/", "/vsizip/" ]
                for fm in ogr_filemethods:
                    if ogrpath.find(fm) == 0:
                        filename = ogrpath[len(fm):]
                        break

                if not os.path.exists(filename):
                    self.logger.error("The file '%s' does not exist.", filename)
                elif ogrpath == filename:
                    if filename.endswith('.tar') or \
                       filename.endswith('.tgz') or \
                       filename.endswith('.tar.gz'):
                        full_ogrpath = '/vsitar/' + filename
                    elif filename.endswith('.gz'):
                        full_ogrpath = '/vsigzip/' + filename
                    elif filename.endswith('.zip'):
                        full_ogrpath = '/vsizip/' + filename
                    else:
                        full_ogrpath = filename
                else:
                    full_ogrpath = filename

        if full_ogrpath:
            file_datasource = None
            if not self.is_database_source and prefer_mem_copy:
                file_datasource = ogr.Open(full_ogrpath, gdalconst.GA_ReadOnly)
            else:
                self.datasource = ogr.Open(full_ogrpath, gdalconst.GA_ReadOnly)

            if self.is_database_source and not self.datasource:
                self.logger.error("OGR failed to open connection to %s.", full_ogrpath)
            elif not self.is_database_source and not self.datasource and not file_datasource:
                self.logger.error("OGR failed to open '%s', format may be unsupported.", \
                                  full_ogrpath)
            elif not self.is_database_source and file_datasource and prefer_mem_copy:
                mem_driver = ogr.GetDriverByName('Memory')
                self.datasource = mem_driver.CopyDataSource(file_datasource, 'memoryCopy')

    def set_query(self, query):
        self.query = query

    def __get_source_reprojection_func(self, layer):
        layer_spatial_ref = layer.GetSpatialRef()

        spatial_ref = None
        if self.source_proj4:
            spatial_ref = osr.SpatialReference()
            if self.gisorder:
                spatial_ref.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
            spatial_ref.ImportFromProj4(self.source_proj4)
        elif self.source_epsg:
            spatial_ref = osr.SpatialReference()
            if self.gisorder:
                spatial_ref.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
            spatial_ref.ImportFromEPSG(self.source_epsg)
        elif layer_spatial_ref:
            spatial_ref = layer_spatial_ref
            self.logger.info("Detected projection metadata:\n%s", str(layer_spatial_ref))
        else:
            self.logger.info("Layer has no projection metadata, falling back to EPSG:4326")
            if not self.gisorder:
                spatial_ref = osr.SpatialReference()
                spatial_ref.ImportFromEPSG(4326)

        # No source proj specified yet? Then default to do no reprojection.
        # Some python magic: skip reprojection altogether by using a dummy
        # lamdba funcion. Otherwise, the lambda will be a call to the OGR
        # reprojection stuff.
        reproject = lambda geometry: None

        if spatial_ref:
            # Destionation projection will *always* be EPSG:4326, WGS84 lat-lon
            dest_spatial_ref = osr.SpatialReference()
            dest_spatial_ref.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
            dest_spatial_ref.ImportFromEPSG(4326)
            coord_trans = osr.CoordinateTransformation(spatial_ref, dest_spatial_ref)
            reproject = lambda geometry: geometry.Transform(coord_trans)

        return reproject

    def get_layer_count(self):
        if self.is_database_source:
            return 1
        else:
            return self.datasource.GetLayerCount()

    def get_layer(self, index):
        layer = None
        if self.is_database_source:
            if self.query:
                # TODO: avoid executing the query more than once
                layer = self.datasource.ExecuteSQL(self.query)
                layer.ResetReading()
            else:
                self.logger.error("Query must be set first when the datasource is a database.")
        else:
            layer = self.datasource.GetLayer(index)
            layer.ResetReading()

        filteredlayer = self.translation.filter_layer(layer)
        return (filteredlayer, self.__get_source_reprojection_func(filteredlayer))


import subprocess
from pathlib import Path
from joblib import Parallel, delayed

gpu_script = Path("./gpus.py")

cmdline = f"cd {gpu_script.parent.absolute()}; pipenv run python3 {gpu_script.absolute()}"
print(cmdline)

def check_host(host: str):
    print("Checking", host)
    proc = subprocess.run(["ssh", host, cmdline], capture_output=True, encoding="UTF-8")

    print(host, ":", proc.stdout) #, proc.stderr)

hosts = ["hyperion", "hyperion3", "turing1", "turing2", "turing3", "turing4", "hyperturing1", "hyperturing2"]

Parallel(n_jobs=8, backend="threading")(
             map(delayed(check_host), hosts))


"""
* 이진 검색
정렬된 nums를 입력받아 이진 검색으로 target에 해당하는 인덱스를 찾아라.
Input: nums = [-1, 0, 3, 5, 9, 12], target = 9
Output: 4
"""
import bisect
from typing import List

class Solution:
    # 이진 검색 모듈
    def search(self, nums: List[int], target: int) -> int:
        index = bisect.bisect_left(nums, target)

        if index < len(nums) and nums[index] == target:
            return index
        else:
            return -1

if __name__ == '__main__':
    nums = [-1, 0, 3, 5, 9, 12]
    target = 9
    print(Solution().search(nums, target))


"""
Matplotlib based plotting utilities
"""
import math
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import art3d
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d.proj3d import proj_transform
from mpl_toolkits.mplot3d import Axes3D

from utils.angle import rot_mat_2d

def plot_covariance_ellipse(x, y, cov, chi2=3.0, color="-r", ax=None):
    """
    This function plots an ellipse that represents a covariance matrix. The ellipse is centered at (x, y) and its shape, size and rotation are determined by the covariance matrix.

    Parameters:
    x : (float) The x-coordinate of the center of the ellipse.
    y : (float) The y-coordinate of the center of the ellipse.
    cov : (numpy.ndarray) A 2x2 covariance matrix that determines the shape, size, and rotation of the ellipse.
    chi2 : (float, optional) A scalar value that scales the ellipse size. This value is typically set based on chi-squared distribution quantiles to achieve certain confidence levels (e.g., 3.0 corresponds to ~95% confidence for a 2D Gaussian). Defaults to 3.0.
    color : (str, optional) The color and line style of the ellipse plot, following matplotlib conventions. Defaults to "-r" (a red solid line).
    ax : (matplotlib.axes.Axes, optional) The Axes object to draw the ellipse on. If None (default), a new figure and axes are created.

    Returns:
    None. This function plots the covariance ellipse on the specified axes.
    """
    eig_val, eig_vec = np.linalg.eig(cov)

    if eig_val[0] >= eig_val[1]:
        big_ind = 0
        small_ind = 1
    else:
        big_ind = 1
        small_ind = 0
    a = math.sqrt(chi2 * eig_val[big_ind])
    b = math.sqrt(chi2 * eig_val[small_ind])
    angle = math.atan2(eig_vec[1, big_ind], eig_vec[0, big_ind])
    plot_ellipse(x, y, a, b, angle, color=color, ax=ax)

def plot_ellipse(x, y, a, b, angle, color="-r", ax=None, **kwargs):
    """
    This function plots an ellipse based on the given parameters.

    Parameters
    ----------
    x : (float) The x-coordinate of the center of the ellipse.
    y : (float) The y-coordinate of the center of the ellipse.
    a : (float) The length of the semi-major axis of the ellipse.
    b : (float) The length of the semi-minor axis of the ellipse.
    angle : (float) The rotation angle of the ellipse, in radians.
    color : (str, optional) The color and line style of the ellipse plot, following matplotlib conventions. Defaults to "-r" (a red solid line).
    ax : (matplotlib.axes.Axes, optional) The Axes object to draw the ellipse on. If None (default), a new figure and axes are created.
    **kwargs: Additional keyword arguments to pass to plt.plot or ax.plot.

    Returns
    ---------
    None. This function plots the ellipse based on the specified parameters.
    """

    t = np.arange(0, 2 * math.pi + 0.1, 0.1)
    px = [a * math.cos(it) for it in t]
    py = [b * math.sin(it) for it in t]
    fx = rot_mat_2d(angle) @ (np.array([px, py]))
    px = np.array(fx[0, :] + x).flatten()
    py = np.array(fx[1, :] + y).flatten()
    if ax is None:
        plt.plot(px, py, color, **kwargs)
    else:
        ax.plot(px, py, color, **kwargs)

def plot_arrow(x, y, yaw, arrow_length=1.0,
               origin_point_plot_style="xr",
               head_width=0.1, fc="r", ec="k", **kwargs):
    """
    Plot an arrow or arrows based on 2D state (x, y, yaw)

    All optional settings of matplotlib.pyplot.arrow can be used.
    - matplotlib.pyplot.arrow:
    https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.arrow.html

    Parameters
    ----------
    x : a float or array_like
        a value or a list of arrow origin x position.
    y : a float or array_like
        a value or a list of arrow origin y position.
    yaw : a float or array_like
        a value or a list of arrow yaw angle (orientation).
    arrow_length : a float (optional)
        arrow length. default is 1.0
    origin_point_plot_style : str (optional)
        origin point plot style. If None, not plotting.
    head_width : a float (optional)
        arrow head width. default is 0.1
    fc : string (optional)
        face color
    ec : string (optional)
        edge color
    """
    if not isinstance(x, float):
        for (i_x, i_y, i_yaw) in zip(x, y, yaw):
            plot_arrow(i_x, i_y, i_yaw, head_width=head_width,
                       fc=fc, ec=ec, **kwargs)
    else:
        plt.arrow(x, y,
                  arrow_length * math.cos(yaw),
                  arrow_length * math.sin(yaw),
                  head_width=head_width,
                  fc=fc, ec=ec,
                  **kwargs)
        if origin_point_plot_style is not None:
            plt.plot(x, y, origin_point_plot_style)

def plot_curvature(x_list, y_list, heading_list, curvature,
                   k=0.01, c="-c", label="Curvature"):
    """
    Plot curvature on 2D path. This plot is a line from the original path,
    the lateral distance from the original path shows curvature magnitude.
    Left turning shows right side plot, right turning shows left side plot.
    For straight path, the curvature plot will be on the path, because
    curvature is 0 on the straight path.

    Parameters
    ----------
    x_list : array_like
        x position list of the path
    y_list : array_like
        y position list of the path
    heading_list : array_like
        heading list of the path
    curvature : array_like
        curvature list of the path
    k : float
        curvature scale factor to calculate distance from the original path
    c : string
        color of the plot
    label : string
        label of the plot
    """
    cx = [x + d * k * np.cos(yaw - np.pi / 2.0) for x, y, yaw, d in
          zip(x_list, y_list, heading_list, curvature)]
    cy = [y + d * k * np.sin(yaw - np.pi / 2.0) for x, y, yaw, d in
          zip(x_list, y_list, heading_list, curvature)]

    plt.plot(cx, cy, c, label=label)
    for ix, iy, icx, icy in zip(x_list, y_list, cx, cy):
        plt.plot([ix, icx], [iy, icy], c)

class Arrow3D(FancyArrowPatch):

    def __init__(self, x, y, z, dx, dy, dz, *args, **kwargs):
        super().__init__((0, 0), (0, 0), *args, **kwargs)
        self._xyz = (x, y, z)
        self._dxdydz = (dx, dy, dz)

    def draw(self, renderer):
        x1, y1, z1 = self._xyz
        dx, dy, dz = self._dxdydz
        x2, y2, z2 = (x1 + dx, y1 + dy, z1 + dz)

        xs, ys, zs = proj_transform((x1, x2), (y1, y2), (z1, z2), self.axes.M)
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
        super().draw(renderer)

    def do_3d_projection(self, renderer=None):
        x1, y1, z1 = self._xyz
        dx, dy, dz = self._dxdydz
        x2, y2, z2 = (x1 + dx, y1 + dy, z1 + dz)

        xs, ys, zs = proj_transform((x1, x2), (y1, y2), (z1, z2), self.axes.M)
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))

        return np.min(zs)

def _arrow3D(ax, x, y, z, dx, dy, dz, *args, **kwargs):
    '''Add an 3d arrow to an `Axes3D` instance.'''
    arrow = Arrow3D(x, y, z, dx, dy, dz, *args, **kwargs)
    ax.add_artist(arrow)

def plot_3d_vector_arrow(ax, p1, p2):
    setattr(Axes3D, 'arrow3D', _arrow3D)
    ax.arrow3D(p1[0], p1[1], p1[2],
               p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2],
               mutation_scale=20,
               arrowstyle="-|>",
               )

def plot_triangle(p1, p2, p3, ax):
    ax.add_collection3d(art3d.Poly3DCollection([[p1, p2, p3]], color='b'))

def set_equal_3d_axis(ax, x_lims, y_lims, z_lims):
    """Helper function to set equal axis

    Args:
        ax (Axes3DSubplot): matplotlib 3D axis, created by
        `ax = fig.add_subplot(projection='3d')`
        x_lims (np.array): array containing min and max value of x
        y_lims (np.array): array containing min and max value of y
        z_lims (np.array): array containing min and max value of z
    """
    x_lims = np.asarray(x_lims)
    y_lims = np.asarray(y_lims)
    z_lims = np.asarray(z_lims)
    # compute max required range
    max_range = np.array([x_lims.max() - x_lims.min(),
                          y_lims.max() - y_lims.min(),
                          z_lims.max() - z_lims.min()]).max() / 2.0
    # compute mid-point along each axis
    mid_x = (x_lims.max() + x_lims.min()) * 0.5
    mid_y = (y_lims.max() + y_lims.min()) * 0.5
    mid_z = (z_lims.max() + z_lims.min()) * 0.5

    # set limits to axis
    ax.set_xlim(mid_x - max_range, mid_x + max_range)
    ax.set_ylim(mid_y - max_range, mid_y + max_range)
    ax.set_zlim(mid_z - max_range, mid_z + max_range)

if __name__ == '__main__':
    plot_ellipse(0, 0, 1, 2, np.deg2rad(15))
    plt.axis('equal')
    plt.show()


import argparse
import gcal
import datetime
import pytz
import os
import sys
import json

def setup():
    pass

def print_schedule(events,from_datetime,to_datetime):
    print(f"{'Calendar':=<60}")
    events = [e for e in events if e["from"] >= from_datetime and e["to"] <= to_datetime]
    for event in events:
        print(f'{event["name"]:<40}: {event["from"].strftime("%I:%M%p"):<8} - {event["to"].strftime("%I:%M%p"):<8}')
    print(f"{'':=<60}")
    td_seconds = sum_time_ranges(events)
    total_seconds = td_seconds.total_seconds()
    minutes = total_seconds / 60
    hours = total_seconds / 3600
    print(f"Total hours of scheduled events: {hours}")
    worktime_info = worktimes()
    workday_hours_abs = diff_times(worktime_info["from"], worktime_info["to"])
    print(f'{workday_hours_abs.total_seconds() / 3600} hr workday from {worktime_info["from"].strftime("%I:%M%p")} to {worktime_info["to"].strftime("%I:%M%p")}')
    timez = pytz.timezone('America/New_York')
    datetime_now = timez.localize(datetime.datetime.now())
    from_time = max(datetime_now.time(), worktime_info["from"])
    total_work_time = diff_times(from_time, worktime_info["to"])
    available_time = total_work_time - td_seconds
    # bug, what if you're already in your lunch break!
    print(f'Available Hours: {available_time.total_seconds() / 3600}')
    if (datetime_now.time() < worktime_info["from"]):
        print(f'Hours Until Work: {diff_times(datetime_now.time(), worktime_info["from"]).total_seconds() / 3600}')
    return events

def sum_time_ranges(events):
    import functools
    return functools.reduce(lambda x, y: x + (y["to"] - y["from"]), events, datetime.timedelta())

def worktimes():
    return {
        "from": datetime.time(hour=10, minute=0),
        "to": datetime.time(hour=17, minute=0)
    }

def bar_chart(from_dt, to_dt, events):
    seconds = (to_dt - from_dt).total_seconds()
    minutes = seconds / 60
    min_blocks = minutes // 15
    min_block_symbol = " "
    print(f"{' ':<{min_blocks}}")

def diff_times(from_time, to_time):
    return datetime.datetime.combine(datetime.date.min, to_time) - datetime.datetime.combine(datetime.date.min, from_time)

def events_from_google():
    event_filters = [
        "Eng Hold: Cut production branch",
        "[Optional] Daily Dose of Team Time (DDOTT)"
    ]
    mapped_events = [
        {
            "name": event["summary"],
            "from": datetime.datetime.fromisoformat(event["start"]["dateTime"]),
            "to": datetime.datetime.fromisoformat(event["end"]["dateTime"])
        } for event in gcal.all_events()
    ]
    return [e for e in mapped_events if e["name"] not in event_filters]

def time_range(context):
    if context == "work":
        eastern = pytz.timezone('America/New_York')
        worktime_info = worktimes()
        today = datetime.datetime.today()
        datetime_now = eastern.localize(datetime.datetime.now())
        from_time = eastern.localize(datetime.datetime(
            today.year,
            today.month,
            today.day,
            worktime_info["from"].hour,
            worktime_info["from"].minute
        ))
        from_time = max(datetime_now, from_time)
        to = datetime.datetime(
            today.year,
            today.month,
            today.day,
            worktime_info["to"].hour,
            worktime_info["to"].minute
        )
        return (from_time, eastern.localize(to))
    else:
        return today_remaining_range()

def today_full_range():
    today = datetime.datetime.today()
    day_begin = datetime.datetime(year=today.year, month=today.month, day=today.day, hour=0, second=0, tzinfo=pytz.timezone('EST'))
    day_end = day_begin.replace(hour=23, minute=59, second=59, microsecond=999999)
    return (day_begin, day_end)

def today_remaining_range():
    today = datetime.datetime.today()
    day_begin = datetime.datetime(year=today.year, month=today.month, day=today.day, hour=0, second=0, tzinfo=pytz.timezone('America/New_York'))
    now = datetime.datetime.now(pytz.timezone('America/New_York'))
    day_end = day_begin.replace(hour=23, minute=59, second=59, microsecond=999999)
    bedtime = datetime.datetime(year=today.year, month=today.month, day=today.day, hour=22, second=0, tzinfo=pytz.timezone('America/New_York'))
    return (now, bedtime)

def hours_remaining(range_start, range_end, events, unscheduled_blocks=[]):
    print(f"Day end: {range_end}")
    total = range_end - range_start
    scheduled_blocks = [e['to'] - e['from'] for e in events]
    total_scheduled = sum(scheduled_blocks, datetime.timedelta())
    print(f"Total scheduled: {total_scheduled}")
    total_remaining = total - total_scheduled
    print(f"Remaining: {total_remaining}")
    pomodoro_size = datetime.timedelta(minutes=30)
    print(f"Number of pomodoros: {total_remaining / pomodoro_size}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Get time info.')
    subparsers = parser.add_subparsers(help='commands', dest="subparser_name")

    englog_parser = subparsers.add_parser('elog', help="Engineering log")
    englog_parser.add_argument('-n', '--new', action='store_true', help='New Log')
    englog_parser.add_argument('-o', '--open', action='store_true', help='New Log')

    event_parser = subparsers.add_parser('events', help='List contents')
    event_parser.add_argument('-l', '--ls', action='store_true', help='List events')
    event_parser.add_argument('--local', action='store_true', help='List events')
    event_parser.add_argument('-n', '--new', action='store', help='New Event')
    event_parser.add_argument('-c', '--clear', action='store_true', help='Clear all events')
    event_parser.add_argument('-e', '--end', action='store', type=int, help='End Event')
    event_parser.add_argument('-t', '--type', action='store', help='Event Type')
    parser.add_argument('-r', '--range', help="time range. i.e: today, week", dest='range')
    event_parser.add_argument('context', help="Context. i.e work, all")
    args = parser.parse_args()

    if args.subparser_name == "elog":
        if args.new:
            now = datetime.datetime.now(pytz.timezone('America/New_York'))
            file_name = f"englogs/{now.strftime('%Y-%m-%d')}.md"
            if os.path.exists(file_name):
                print("File already exists! Use open.")
                sys.exit()
            with open(f"{file_name}", "w") as f:
                f.write("top 3:\n*\n*\n*\npostnotes:\n")
        if args.open:
            now = datetime.datetime.now(pytz.timezone('America/New_York'))
            file_name = f"englogs/{now.strftime('%Y-%m-%d')}.md"
            os.system(f"vim {file_name}")
        sys.exit()

    if args.new:
        if args.type == "sw":
            import uuid
            with open("local-events.json", "r+") as f:
                curr = json.loads(f.read())
                curr.append({
                    "name": args.new,
                    "from": datetime.datetime.utcnow().isoformat(),
                    "to": ""
                })
                with open("local-events.json", "w+") as fwrite:
                    fwrite.write(json.dumps(curr))
        sys.exit()

    if args.end == 0 or args.end:
        print(f"Editing {args.end}")
        with open("local-events.json", "r+") as f:
            curr = json.loads(f.read())
            for index, event in enumerate(curr):
                if index == args.end:
                    event['to'] = datetime.datetime.utcnow().isoformat()
            with open("local-events.json", "w+") as fwrite:
                fwrite.write(json.dumps(curr))
        sys.exit()

    if args.clear:
        print("clearing events")
        sys.exit()

    if args.ls:
        if args.local:
            print("Listing local events only")
            with open("local-events.json", "r") as f:
                results = json.loads(f.read())
                for index, event in enumerate(results):
                    print(f'{index} - {event["name"]}: {event["from"]} - {event["to"]}')
        else:
            today = datetime.datetime.today()
            tz = pytz.timezone('America/New_York')
            recurring_local_events = [
                {
                    "name": "Lunch",
                    "from": tz.localize(datetime.datetime(today.year, today.month, today.day, 12)),
                    "to": tz.localize(datetime.datetime(today.year, today.month, today.day, 13)),
                }
            ]
            start, end = time_range(args.context)
            all_events = recurring_local_events + events_from_google()
            all_events = sorted(all_events, key=lambda x: x["from"])
            print_schedule(all_events, start, end)
        sys.exit()


#CONFIG
import re
import pytz
from datetime import *
LOCAL_TIMEZONE = pytz.timezone("Australia/Perth")
SLOT_LENGTH_MINUTES = 30

DAYS = [  'Monday',
          'Tuesday',
          'Wednesday',
          'Thursday',
          'Friday',
          'Saturday',
          'Sunday']

from html.parser import HTMLParser

class HtmlResolver(HTMLParser):
    def __init__(self):
        super().__init__()
        self.result=""

    def handle_starttag(self, tag, attrs):
        pass

    def handle_endtag(self, tag):
        pass

    def handle_data(self, data):
        self.result+=data

def resolve_html(html_frag):
    oldtext = ""
    text = html_frag
    while text!=oldtext: #keep resolving HTML til no change
        oldtext = text
        res = HtmlResolver()
        res.feed(text)
        text = res.result
    return text

def normalise(string):
    string = resolve_html(string)
    string = resolve_html(string)
    string = string.replace("\r",'')
    string = string.replace("\xa0", " ")

    string = re.sub(r"\n\s*\n", "\n", string)

    return string.strip()

def strip_titles(string):
    return re.sub(r"\b(mr|mrs|dr|ms|mx)\b\s*","",string, flags=re.I)

def load_list(csl):
    ldlst=[]
    if type(csl) is list:
        ldlst=csl
    else:
        ldlst = str.split(csl, ',')

    ldlst=[normalise(ll).strip().replace("\n", " ") for ll in ldlst]
    return [ll for ll in ldlst if len(ll)>0]

def parse_datetime(datetime_str):
    if type(datetime_str) is datetime:
        return datetime_str

    import dateutil.parser

    raw = dateutil.parser.parse(datetime_str)
    return raw.astimezone(LOCAL_TIMEZONE)

class session(object):
    def __init__(self, id,
                 start_time_str,end_time_str,
                 title,tags_str,people_str,
                 venues_str,description):
        self.id = int(id)
        self.start = parse_datetime(start_time_str)
        self.end = parse_datetime(end_time_str)
        self.title = normalise(title)
        self.tags = set(load_list(tags_str))
        self.people = list(map(strip_titles, load_list(people_str)))
        self.venues = set(load_list(venues_str))
        self.description = normalise(description)

    @property
    def day(self):
        week_days   = DAYS
        daynum = self.start.weekday()
        return week_days[daynum]

    @property
    def start_time(self):
        return self.start.strftime("%H:%M")

    @property
    def end_time(self):
        return self.end.strftime("%H:%M")

    @property
    def duration(self):
        return self.end - self.start

    def __str__(self):
        str(self.__dict__)

def load_sessions_csv(csvpath):
    import csv
    sessions = []
    with open(csvpath, 'r') as csvfile:
        con_csv = csv.reader(csvfile)
        next(con_csv) #Skip heading
        sessions = [session(*row) for row in con_csv]
    return sessions


from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='home'),
    path('schedule/<int:year>', views.schedule, name='scheduleyear'),
    path('submitpick/<pickid>', views.submitpick),
    path('league/create', views.createleague),
    path('league/<int:leagueid>', views.league)
]


#a script that downloads cracked games from STEAMRIP / GOG.

import requests
from bs4 import BeautifulSoup
import re
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from webdriver_manager.chrome import ChromeDriverManager
from time import sleep
import webbrowser
from constants import *

def main():

  def search_in_gog(game_name = None, page = 1):

    game_name = game_name.replace(' ', '-').lower()

    response = requests.get(f'{gog_list}{game_name}/{page}{gog_addon}')
    soup = BeautifulSoup(response.content, 'html.parser')
    game_html_line = soup.find_all('a', {'class': 'block'})

    if len(game_html_line) > 1:

      for i, game in enumerate(game_html_line):

        title = game.text
        title = re.sub(r'\s*Last Update.*', '', title).strip()
        print(f'{i+1}. {title}')

        if (i+1) % 28 == 0:

          question = input('Do you want to continue to the next page? Answer with y / n. ')

          if question == 'y':

            print(f'question = {question}')
            page += 1
            search_in_gog(game_name, page)

          else:
            break

      question = int(input('\nYou have multiple options, please pick the one you want: \nif the game you want is not in the list type \'999\':\n')) - 1

      if question == 998:
        game_url = search_in_steamrip(game_name)

        return game_url

      elif question >= len(game_html_line):
        question = int(input('\nThe number you chose was not in the list, Please choose again: \n')) - 1

      href_value = game_html_line[question].get('href')
      game_url = f'https://gog-games.com{href_value}'

      return game_url

    elif len(game_html_line) == 0:
      game_url = search_in_steamrip(game_name)

      return game_url

    href_value = game_html_line[0].get('href')
    game_url = f'https://gog-games.com{href_value}'

    return game_url

  def search_in_steamrip(game_name = None):

    if game_name == None:
      game_name = input('Please input the game\'s name: \n')

    game_name = game_name.replace(' ', '-').lower()

    response = requests.get(gamelist1)
    soup = BeautifulSoup(response.content, 'html.parser')
    game_html_line = soup.find_all('a', href=re.compile(game_name))

    if len(game_html_line) > 1:
      i = 0

      for i, game in enumerate(game_html_line):
        title = game.text
        print(f'{i+1}. {title}')

      question = int(input('\nYou have multiple options, please pick the one you want: ')) - 1

      if question >= len(game_html_line):
          question = int(input('\nThe number you chose was not in the list, Please choose again: \n')) - 1

      href_value = game_html_line[question].get('href')
      game_url = f'https://webcache.googleusercontent.com/search?q=cache:https://steamrip.com{href_value}'

      return game_url

    elif len(game_html_line) == 0:
      print('Couldn\'t find the game you asked for, Please try again.')

      return None

    href_value = game_html_line[0].get('href')
    game_url = f'https://webcache.googleusercontent.com/search?q=cache:https://steamrip.com{href_value}'

    return game_url

  def find_and_download(game_url):

    if game_url == None:
      return None

    response = requests.get(game_url)
    soup = BeautifulSoup(response.content, 'html.parser')

    if game_url.find('steamrip.com') > 0:
      download_html_line = soup.find('a', class_="shortc-button medium purple")

      if download_html_line == None:
        index_cash = game_url.find('cache:') + 6
        actual_url = game_url[index_cash:]

        print('Failed to find the link to the download in ' + actual_url)
        return None

      url = download_html_line.get('href')[2:]
      formatted_url = f'https://{url}'
      webbrowser.open(formatted_url)

    else:
      driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
      driver.get(game_url)
      driver.find_element(By.CLASS_NAME, "g-recaptcha").click()
      wait = WebDriverWait(driver, 50)
      wait.until(ec.visibility_of_element_located((By.XPATH, '//*[@id="game-details"]/div/div[2]/div[1]/div[1]')))
      html = driver.page_source
      download_link = re.search(r'(filecrypt\.cc\/Container\/\w+)', html)

      if download_link:
        formatted_url = f'https://{download_link.group(1)}'
        driver.get(formatted_url)
        wait.until(ec.visibility_of_element_located((By.XPATH, '//*[@id="cnl_btn"]')))
        driver.find_element(By.XPATH, '//*[@id="cnl_btn"]').click()
        sleep(55)

      else:
        download_link = re.search(r'(?:title=")(https:\/\/1fichier\..*)(?:" href)', html)
        if download_link:
          formatted_url = f'https://{download_link.group(1)}'

  game_name = input('Please input the game\'s name: \n')

  find_and_download(search_in_gog(game_name))

if __name__ == '__main__':
  main()


import os
from datetime import datetime
from app.exceptions import *

class Post:
    def __init__(self, subject, body, username) -> None:
        """
        Construct a Post

        Args:
            subject: post subject
            body   : post body
        """
        self.subject = subject
        self.body = body
        self.date = datetime.now()
        self.owner = username

    def __lt__(self, other):
         """
         Define less than to sort posts according to post date
         """
         return self.date < other.date

    def show_post(self):
        """
        Show the post
        """
        print("-----------------------------")
        print("Subject: {}".format(self.subject))
        print("-------- ")
        print(self.body)

class AddPost:
    def __init__(self, username, authorizor, authenticator) -> None:
        """
        Create Adapter to add posts

        Args:
            username: namd of the user who will add the post
            authorizor: authorizor will manage permissions
            authenticator: authenticator will manage users
        """
        self.username = username
        self.authorizor = authorizor
        self.authenticator = authenticator

    def post(self):
        """
        Create Post and check if the post added successfully

        Raises:
            NotLoggedInError: If the user isn't logged in
            PermissionError : If permission doesn't exists
        """
        os.system("clear")
        subject = input("Enter the subject: ")
        body    = input("Enter post body  : ")
        post    = Post(subject, body, self.username)

        try:
            self.authorizor.check_permission("add post", self.username)
            self.authenticator.users[self.username].posts.append(post)
            os.system("clear")
            print("-----------------------------")
            print("Your post added successfully")
            print("-----------------------------")

        except NotLoggedInError:
            os.system("clear")
            print("---------------------------------")
            print("You should login first")
            print("---------------------------------")

        except PermissionError:
            os.system("clear")
            print("-----------------------------------------")
            print("You don't have the permission to add post")
            print("-----------------------------------------")


# Add the root path of the dmrgpy library
import os ; import sys ; sys.path.append(os.getcwd()+'/../../src')

import numpy as np
from dmrgpy import spinchain

n = 20 # number of sites in your chain
spins = ["S=1" for i in range(n)] # create the sites
sc = spinchain.Spin_Chain(spins) # create the chain
#sc.itensor_version = "julia"

# now define the Hamiltonian
h = 0
for i in range(n-1):
    h = h + sc.Sx[i]*sc.Sx[i+1] # add exchange
    h = h + sc.Sy[i]*sc.Sy[i+1] # add exchange
    h = h + sc.Sz[i]*sc.Sz[i+1] # add exchange
for i in range(n-1):
    h = h + -1.1*sc.Sz[i]*sc.Sz[i] # add single ion anisotropy
sc.maxm = 20
sc.kpmmaxm = sc.maxm
sc.set_hamiltonian(sum(sc.Sx)) ; wf = sc.get_gs()
sc.set_hamiltonian(h) # and initialize the Hamiltonian
wf0 = sc.get_gs(wf0=wf)
# setup some parameters

# now define the operator for which you want the distribution
M = (1/(2*n))*sum([sc.Sz[i]*(-1)**i for i in range(len(sc.Sz))])
import time
t0 = time.time()
x,y = sc.get_distribution(X=M,delta=5e-2) # compute a distribution
t1 = time.time()
print("Time KPM",t1-t0)
from dmrgpy import distribution
x1,y1 = distribution.get_distribution_maxent(sc,X=M,n=6) # compute a distribution
t2 = time.time()
print("Time max ent",t2-t1)
#x1,y1 = sc.get_distribution(X=M,delta=1e-1,mode="ED") # compute a distribution

# plot the result and save it in a file
print("Integral KPM=",np.trapz(y.real,dx=x[1]-x[0]))
print("Integral Max ent=",np.trapz(y1.real,dx=x1[1]-x1[0]))
import matplotlib.pyplot as plt
np.savetxt("DISTRIBUTION.OUT",np.array([x,y.real]).T)
plt.plot(x,y.real,marker="o",label="KPM") # correlator using DMRG
plt.plot(x1,y1.real,marker="o",label="Max ent") # correlator using DMRG
plt.xlabel("magnetization")
plt.ylabel("distribution")
plt.legend()
plt.show()


from sklearn.base import clone
from itertools import  combinations
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

'''
序列后向选择算法（Sequence Backward Selection)
    用作特征选择
'''
class SBS():
    def __init__(self,estimator,k_features,
                 scoring=accuracy_score,
                 test_size=0.25,
                 random_state=1):
        self.scoring = scoring
        self.estimator = clone(estimator)
        self.k_features = k_features
        self.test_size = test_size
        self.random_state = random_state

    def fit(self,X,y):
        X_train,X_test,y_train,y_test=\
                train_test_split(X,y,test_size=self.test_size,random_state=self.random_state)
        dim = X_train.shape[1]#当前特征数
        self.indices_ = tuple(range(dim))
        self.subsets_ = [self.indices_]#子特征数
        score = self._calc_score(X_train,y_train,X_test,y_test,self.indices_)
        self.scores_ = [score]#获取初始分值
        while dim>self.k_features:
            scores = []
            subsets = []
            for p in combinations(self.indices_,r=dim-1):#对当前特征数进行特征数-1的排列组合，获取到子序列
                score = self._calc_score(X_train,y_train,
                                         X_test,y_test,p)
                scores.append(score)
                subsets.append(p)
            best = np.argmax(scores)
            self.indices_ = subsets[best] #获取到当前子序列中分值最高的特征值子序列
            self.subsets_.append(self.indices_)#获取当前数量分值最高的子序列
            dim -= 1
            self.scores_.append(scores[best])#获取当前最好的分值

        self.k_score_ = self.scores_[-1]#获取分值最高的分数
        return self

    def transform(self,X):
        return X[:,self.indices_]

    def _calc_score(self,X_train,y_train,X_test,y_test,indices):
        self.estimator.fit(X_train[:,indices],y_train)#通过给定的机器学习算法，训练模型
        y_pred = self.estimator.predict(X_test[:,indices])#通过测试集得到预测结果
        score = self.scoring(y_test,y_pred)#获取到预测分值
        return score


"""
Created on Sun Oct  4 12:47:45 2020

@author: Marc
"""
# Importing the libraries
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Loading the data
data = pd.read_csv('College_Data.csv')

# Plot (just for visualization)
sns.lmplot(x = 'Outstate', y = 'F.Undergrad', data = data, hue = 'Private',
           fit_reg = False)
plt.savefig('outstate_f-undergrad.png')

# Outstate VS Private Visualization
sns.set_style('darkgrid')
g = sns.FacetGrid(data, hue = 'Private', palette = 'coolwarm')
g.map(plt.hist, 'Outstate', bins = 20, alpha = 0.7)
plt.savefig('outstate_private.png')

# Grad. Rate VS Private Visualization
g = sns.FacetGrid(data, hue = 'Private', palette = 'coolwarm')
g.map(plt.hist, 'Grad.Rate', bins = 20, alpha = 0.7)
plt.savefig('grad-rate_private.png')

# In the plot we saw there was a school with a grad. rate > 100
school = data[data['Grad.Rate'] > 100]
# We need to change it at 100 (so it makes sense)
data['Grad.Rate']['Cazenovia College'] = 100

# K MEANS
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters = 2)
kmeans.fit(data.drop(['Private', 'Unnamed: 0'], axis = 1))

# New dataframe (only for visualization)
d = {'Name': data['Unnamed: 0'],
     'Private': data['Private'],
     'Cluster': kmeans.labels_}
new_df = pd.DataFrame(d)
def check(df):
    if df['Private'] == 'Yes' and df['Cluster'] == 1:
        return 'YES'
    if df['Private'] == 'No' and df['Cluster'] == 0:
        return 'YES'
    return 'NO'
new_df['Same'] = new_df.apply(check, axis = 1)

# Final plot (only for visualization)
sns.countplot(x = 'Same', data = new_df)
plt.xlabel('K Means Clusters & Real Clusters')
plt.savefig('kmeans_results.png')

# Evaluation
# We can do this because we had labeled data
# In a real world project, you will use K Means Algorithm when
# you won't have labeled data
def conversion(x):
    if x == 'Yes':
        return 1
    return 0
from sklearn.metrics import confusion_matrix,classification_report
data['Cluster'] = data['Private'].apply(conversion)
print('------------------------------------------------------')
print('-----CONFUSION MATRIX---------------------------------')
print(confusion_matrix(data['Cluster'], kmeans.labels_))
print('------------------------------------------------------')
print('-----CLASSIFICATION REPORT----------------------------')
print(classification_report(data['Cluster'], kmeans.labels_))


"""
制作目标数据集
"""
import os
import cv2
import random
import numpy as np
import shutil
import math

def gen_box(s, r):
    """
    在的图像上随机生成一个 大小为s, 纵横比为r的框
    :param s:
    :param r:
    :return:
    """
    # 随机获取一个中心坐标
    center_x = round(random.uniform(0.2, 0.8), 2)
    center_y = round(random.uniform(0.2, 0.8), 2)
    w = np.sqrt(s/r)
    h = np.sqrt(s*r)
    # 左上角和右下角的坐标分别是
    x1, y1 = max(0, center_x - w/2), max(0, center_y - h/2)
    x2, y2 = min(1, center_x + w/2), min(1, center_y + h/2)
    return x1, y1, x2, y2

def intersection(box1, box2):
    """
    计算box1, box2 的交集
    :param box1:
    :param box2:
    :return:
    """
    # 交集
    inter_x1 = max(box1[0], box2[0])
    inter_y1 = max(box1[1], box2[1])
    inter_x2 = min(box1[2], box2[2])
    inter_y2 = min(box1[3], box2[3])

    # 交集
    inter_area = max(inter_y2 - inter_y1, 0) * max(inter_x2 - inter_x1, 0)
    return inter_area

def iou(box1, box2):
    """
    计算box1 和 box2 的iou
    :param box1:
    :param box2:
    :return:
    """
    inter_area = intersection(box1, box2)
    box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
    box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
    # 并集
    union_area = box2_area + box1_area - inter_area

    return inter_area / union_area

def select_target_imgs(s_list, r_list, n, threshold=0.8):
    """
    从图像上随机选取指定数量的符合要求的目标框
    :param s_list:  可供选择的 s的列表
    :param r_list:  可供选择的r的列表
    :param n:       要选取的目标框数量
    :param threshold:生成的目标框和之前的目标框的阀值不能大于threshold
    :return: n 个目标框
    """
    box = {}
    while len(box) != n:
        s = random.uniform(s_list[0], s_list[1])
        r = random.uniform(r_list[0], r_list[1])
        gen_target = gen_box(s, r)
        # 对于太小的, 要重新生成
        if (gen_target[2] - gen_target[0]) < 0.05 or \
            (gen_target[3] - gen_target[1]) < 0.05:
            continue

        # 对于生成的框, 和已有的目标框太相似, 也要去除
        is_in = False
        for k, target in box.items():
            # 获取交并比
            iou_val = iou(gen_target, target)
            if iou_val > threshold:
                is_in = True
                break
        if is_in:
            continue
        # 存入box
        box[len(box)+1] = gen_target
    return box

def gen_anno(img_base_path, origin_num, anno_base_path='../annot', target_s=(0.1, 0.3), target_r=(0.5, 2), per_target_num=6, split_rate=(0.8, 0.8)):
    """
    生成标注文本, 并且分割成训练集,验证集, 测试集
    :param img_base_path:   图片文件夹
    :param origin_num:      获取原始图片数量
    :param target_s:        生成的目标框大小
    :param target_r:        生成的目标框纵横比
    :param per_target_num:  每张原始图片生成目标框数量
    :return:
    """
    # 选取指定数量的原始图片
    origin_path = os.path.join(img_base_path, 'origin')
    target_path = os.path.join(img_base_path, 'target')
    train_anno_name = os.path.join(anno_base_path, 'train.txt')
    val_anno_name = os.path.join(anno_base_path, 'val.txt')
    test_anno_name = os.path.join(anno_base_path, 'test.txt')
    # 删除目标图像
    if os.path.exists(target_path):
        shutil.rmtree(target_path)
    os.mkdir(target_path)
    # 删除标注文件夹
    if os.path.exists(anno_base_path):
        shutil.rmtree(anno_base_path)
    os.mkdir(anno_base_path)

    all_origins = os.listdir(origin_path)
    select_origins = all_origins[:origin_num]

    data = []
    for img_suffix in select_origins:
        img_name = img_suffix.split('.')[0].strip()
        img_path = os.path.join(origin_path, img_suffix)
        img = cv2.imread(img_path)
        h, w = img.shape[:2]
        # 随机选择指定个目标框
        target_points = select_target_imgs(target_s, target_r, per_target_num)

        for ind, point in target_points.items():
            anno = []
            x1, y1, x2, y2 = (point * np.array([w, h, w, h])).astype(int)
            target = img[y1: y2, x1: x2]
            # cv2.imshow('10', img)
            # cv2.waitKey(0)
            # cv2.imshow('11', target)
            # cv2.waitKey(0)
            # random_trans = random.uniform(0.7, 1.3)
            # print(random_trans)
            # target = cv2.resize(target, None, fx=random_trans, fy=random_trans)
            # cv2.imshow('12', target)
            # cv2.waitKey(0)
            # cv2.destroyAllWindows()
            target_name = os.path.join(target_path, '{}_{}.jpg'.format(img_name, ind))
            cv2.imwrite(target_name, target)
            anno.append(target_name)
            anno.append(img_path)
            anno.append(",".join(['{:.2f}'.format(item) for item in point]))
            # 保存一个样本
            data.append(','.join(anno))

    total_num = len(data)
    train_val_ind = math.floor(split_rate[0] * total_num)
    train_ind = math.floor(split_rate[1] * train_val_ind)
    train_data = data[:train_ind]
    val_data = data[train_ind: train_val_ind]
    test_data = data[train_val_ind:]

    # 将所有的样本保存到文件中
    with open(train_anno_name, 'w') as f:
        f.write('\n'.join(train_data))
    with open(val_anno_name, 'w') as f:
        f.write('\n'.join(val_data))
    with open(test_anno_name, 'w') as f:
        f.write('\n'.join(test_data))

if __name__ == '__main__':
    gen_anno('../imgs', 20)
    print('over')


import pygame
import sys

if __name__ == '__main__':
    pygame.init()
    running = True
    try:
        data = [int(line) for line in sys.stdin]
        size = width, height = data[0], data[1]
        screen = pygame.display.set_mode(size)
    except Exception:
        print('Неправильный формат ввода')
        running = False

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
        pygame.draw.line(screen, (255, 255, 255), (0, 0), (width, height), width=5)
        pygame.draw.line(screen, (255, 255, 255), (0, height), (width, 0), width=5)
        pygame.display.flip()
    pygame.quit()