import datetime
import inspect
import json
import logging
import os
from typing import Any, Callable, Dict, List, Optional, Union

from django.core import serializers
from django.core.exceptions import SuspiciousOperation
from django.db import models
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest, HttpResponseNotFound
from django.shortcuts import redirect, render
from django.views.decorators.csrf import csrf_exempt

from multipoll import slack, utils
from multipoll.forms import FullApprovalVoteForm, FullMultiVoteForm, NameAndSecretForm
from multipoll.models import ApprovalPoll, MultiPoll, PollBase, User

logger = logging.getLogger(__name__)

def check_token(request: HttpRequest) -> Optional[HttpResponse]:
    verifier = os.environ.get("MPOLLS_SLACK_VERIFIER", "")
    if request.method != "POST":
        return HttpResponseBadRequest("400 Request should be of type POST.")
    if "token" in request.POST:
        sent_token = request.POST["token"]
    elif "payload" in request.POST and "token" in json.loads(request.POST["payload"]):
        sent_token = json.loads(request.POST["payload"])["token"]
    else:
        return HttpResponseBadRequest("400 Request is not signed!")
    if verifier != sent_token:
        return HttpResponseBadRequest("400 Request is not signed correctly!")
    return None

def normalize_post(request: HttpRequest) -> None:
    if getattr(request, "POST") is None:
        request.POST = json.loads(request.body)
    logger.info(f'Request to {inspect.stack()[1].function} at '
                + f'{datetime.datetime.utcnow().timestamp():.6f}: {request.POST}')

@csrf_exempt
def server_status(request: HttpRequest) -> HttpResponse:
    return HttpResponse()

@csrf_exempt
def interactive_button(request: HttpRequest) -> HttpResponse:
    normalize_post(request)

    error_code = check_token(request)
    if error_code is not None:
        return error_code
    divider = "_"
    payload = json.loads(request.POST['payload'])
    if payload["callback_id"] == "newOption":
        poll = PollBase.timestamped(payload['state'])
        poll.options.append(payload['submission']['new_option'])
        poll.options = utils.unique_list(poll.options)
        poll.save()
    elif payload['callback_id'] == 'int_vote':
        ts, ind_str = payload['state'].split(divider)
        poll = PollBase.timestamped(ts)
        user = User.find_or_create("@" + payload['user']["name"])
        vote = poll.PartialVoteType.find_or_create(poll=poll, user=user, option=int(ind_str))
        vote.weight = payload['submission']['weight']
        vote.save()
    elif payload['callback_id'] == "options":
        event = payload["actions"][0]
        if event["name"] == "addMore":
            elements: List[Dict[str, Union[bool, str]]] = [{
                "type": "text",
                "label": "New Option",
                "name": "new_option"
            }]
            slack.create_dialog(payload['trigger_id'], "Add an Option",
                                payload['original_message']['ts'], "newOption", elements)
        elif event["name"] == "bool_option":
            poll = PollBase.timestamped(payload['original_message']['ts'])
            voted_index = int(event['value'])
            user = User.find_or_create('@' + payload['user']["name"])
            vote = poll.PartialVoteType.find_or_create(poll=poll, option=voted_index, user=user)
            if vote.weight is None:
                vote.weight = False
            vote.weight = not vote.weight
            vote.save()
        elif event['name'] == "int_option":
            poll = PollBase.timestamped(payload['original_message']['ts'])
            ind = int(event['value'])
            option = poll.options[ind]
            state = f"{payload['original_message']['ts']}{divider}{ind}"
            elements = [{
                "type": "text",
                "subtype": "number",
                "label": option,
                "optional": True,
                "name": "weight"
            }]
            user = User.find_or_create("@" + payload['user']['name'])
            existing = poll.PartialVoteType.objects.filter(poll=poll, user=user, option=ind)
            if existing:
                elements[0]["value"] = existing[0].weight
            slack.create_dialog(payload['trigger_id'], "Respond to Poll:", state, 'int_vote',
                                elements)
    return HttpResponse()

@csrf_exempt
def slash_poll(request: HttpRequest) -> HttpResponse:
    normalize_post(request)

    error_code = check_token(request)
    if error_code is not None:
        return error_code
    channel = request.POST["channel_id"]
    data = request.POST["text"]

    data = data.replace(u'\u201C', '"')
    data = data.replace(u'\u201D', '"')

    items = data.split('"')

    question = items[1]
    options = []
    for i in range(1, len(items) + 1):
        if i % 2 == 0 and i > 2:
            options.append(items[i - 1])
    options = utils.unique_list(options)
    # all data ready for initial message at this point
    logger.debug("Options: %s", options)

    if request.POST["command"] == "/apoll":
        cls = ApprovalPoll
    elif request.POST["command"] == "/mpoll":
        cls = MultiPoll
    else:
        return HttpResponseBadRequest()
    cls.add(channel, question, options)

    return HttpResponse()  # Empty 200 HTTP response, to not display any additional content in Slack

def JsonModelResponse(model: models.Model, status_code: int = 200,  # noqa: N802
                      location: Optional[str] = None,
                      request: Optional[HttpRequest] = None) -> HttpResponse:
    serialized = serializers.serialize('json', [model])
    response = HttpResponse(serialized[1:-1])
    response.status_code = status_code
    if location:
        if request:
            response["Location"] = request.build_absolute_uri(location)
        else:
            response["Location"] = location
    return response

def create_poll(request: HttpRequest) -> HttpResponse:
    if request.method == "POST":
        poll_data = json.loads(request.body)
        if 'timestamp' in poll_data or 'question' not in poll_data or 'options' not in poll_data:
            return HttpResponseBadRequest()
        question = poll_data['question']
        options = poll_data['options']
        channel = poll_data.get('channel', os.environ.get('MPOLLS_DEFAULT_CHANNEL', ''))
        poll_type = poll_data.get('poll_type', 'approval')
        if poll_type == "approval":
            cls = ApprovalPoll
        elif poll_type == "multi":
            cls = MultiPoll
        else:
            return HttpResponseBadRequest()
        poll = cls.add(question=question, options=options, channel=channel)
        poll.save()
        return JsonModelResponse(poll, 201, poll.get_absolute_url())
    else:
        return HttpResponseBadRequest()

def view_poll(request: HttpRequest, poll_timestamp: str) -> HttpResponse:
    if request.method == "GET":
        poll = PollBase.timestamped(poll_timestamp)
        form = NameAndSecretForm()
        return render(request, 'name_and_secret.html',
                      {'form': form, 'poll': poll})
    else:
        return HttpResponseBadRequest()

def view_vote_on_poll_form(request: HttpRequest, poll_timestamp: str) -> HttpResponse:
    logger.info("vote_on_poll: Received a GET request")
    submitted_form = NameAndSecretForm(request.GET)
    if submitted_form.is_valid():
        poll = PollBase.timestamped(poll_timestamp)
        user_name = submitted_form.cleaned_data['user_name']
        user_secret = submitted_form.cleaned_data['user_secret']
        user = User.find_or_create(user_name)
        vote = poll.all_votes.get(user, None)
        if vote is None:
            vote = poll.FullVoteType.find_and_validate_or_create_verified(poll, user,
                                                                          user_secret)
        form = vote.get_form()
        return render(request, "vote_on_poll.html",
                      {'form': form, 'path': request.get_full_path(force_append_slash=True)})
    else:
        return HttpResponseBadRequest()

def add_poll_option(request: HttpRequest, poll_timestamp: str) -> HttpResponse:
    logger.info("vote_on_poll: method is 'addoption'")
    poll = PollBase.timestamped(poll_timestamp)
    option = request.POST['option']
    if option is None:
        return HttpResponseBadRequest()
    else:
        option = option.strip()
        if option in poll.options or len(option) == 0:
            return HttpResponseBadRequest()
        else:
            poll.options.append(option)
            poll.save()
            return redirect(request.POST['next'])

def submit_vote_on_poll(request: HttpRequest, poll_timestamp: str) -> HttpResponse:
    logger.info("vote_on_poll: method is *vote")
    if request.POST['_method'] == 'approvalvote':
        cls = FullApprovalVoteForm
    elif request.POST['_method'] == 'multivote':
        cls = FullMultiVoteForm
    else:
        return HttpResponseBadRequest()
    submitted_form = cls(request.POST)
    if submitted_form.is_valid():
        logger.info("vote_on_poll: submitted_form is_valid")
        if submitted_form.cleaned_data['poll'].timestamp_str == poll_timestamp:
            logger.info("vote_on_poll: submitted_form has correct timestamp")
            poll = submitted_form.cleaned_data['poll']
            submitted_form.save()
            logger.info("vote_on_poll: submitted_form saved")
            return redirect(poll.get_absolute_url() + "results")
        else:
            raise SuspiciousOperation("Poll timestamp did not match what was submitted"
                                      + "in the form.")
    else:
        logger.warning(f"Failed to clean submitted form: {submitted_form.cleaned_data} "
                       + f"had errors {submitted_form.errors}")
        return HttpResponseBadRequest()

def vote_on_poll(request: HttpRequest, poll_timestamp: str) -> HttpResponse:
    logger.info(f"In view controller vote_on_poll({request}, '{poll_timestamp}')")
    if request.method == "GET":
        return view_vote_on_poll_form(request, poll_timestamp)
    elif request.method == 'POST':
        logger.info("vote_on_poll: Received a POST request")
        if request.POST['_method'] == "addoption":
            return add_poll_option(request, poll_timestamp)
        elif request.POST['_method'].endswith('vote'):
            return submit_vote_on_poll(request, poll_timestamp)
        else:
            return HttpResponseBadRequest()
    else:
        return HttpResponseBadRequest()

LIST_SUFFIX = '_list'
RequestHandler = Callable[..., HttpResponse]

def query_dict_to_kwonlyargs(handler: RequestHandler) \
        -> RequestHandler:
    _, _, varkw, _, kwonlyargs, _, _ = inspect.getfullargspec(handler)

    def wrapped(request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
        query_dict = request.GET or request.POST
        if query_dict is not None:
            kwnames = kwonlyargs
            if varkw is not None:
                kwnames += request.GET.keys()
            for kwname in kwnames:
                if kwname in query_dict:
                    if kwname.endswith(LIST_SUFFIX):
                        kwargs[kwname] = query_dict.getlist(kwname[:-len(LIST_SUFFIX)])
                    else:
                        kwargs[kwname] = query_dict.get(kwname)
        return handler(request, *args, **kwargs)
    return wrapped

@query_dict_to_kwonlyargs
def poll_results(request: HttpRequest, poll_timestamp: str, *,
                 system: Optional[str] = None) -> HttpResponse:
    if request.method == "GET":
        poll = PollBase.timestamped(poll_timestamp)
        system = system or poll.default_system
        return render(request, "poll_results.html",
                      {'poll': poll, 'system': system})
    else:
        return HttpResponseBadRequest()

@query_dict_to_kwonlyargs
def poll_results_visualization(request: HttpRequest, poll_timestamp: str, *,
                               system: Optional[str] = None) -> HttpResponse:
    if request.method == "GET":
        poll = PollBase.timestamped(poll_timestamp)
        system = system or poll.default_system
        visualization = poll.visualized_results(system)
        if visualization is None:
            return HttpResponseNotFound()
        else:
            response = HttpResponse()
            response.write(visualization)
            response["Content-Type"] = "text/html"
            return response
    else:
        return HttpResponseBadRequest()


import requests
import json
def next1f():
    url = "https://fdo.rocketlaunch.live/json/launches/next/5"

    response = requests.get(url)
    data = response.json()
    next1 = (data["result"][0]["launch_description"])
    return next1
#print(data["result"][0]["name"])
#print(data["result"][0]["vehicle"]["name"])
#print(data["result"][0]["provider"]["name"])
def next5f():
    url = "https://fdo.rocketlaunch.live/json/launches/next/5"

    response = requests.get(url)
    data = response.json()
    next1 = (data["result"][0]["launch_description"])
    next2 = (data["result"][1]["launch_description"])
    next3 = (data["result"][2]["launch_description"])
    next4 = (data["result"][3]["launch_description"])
    next5 = (data["result"][4]["launch_description"])
    First = "First"

    next5l = ("**First:** " + next1 + "\n" + "**Second:** " + next2 + "\n" "**Third:** " +
              next3 + "\n" + "**Fourth:** " + next4 + "\n" "**Fifth:** " + next5 + "\n")
    return next5l


import heapq

n, m = map(int, input().split())
priority = [[] for i in range(n+1)]

indegree = [0 for i in range(n+1)]

for i in range(1, m+1):
    A, B = map(int, input().split())
    priority[A].append(B)
    indegree[B] += 1

result = []

for i in range(1, n+1):
    if indegree[i] == 0:
        heapq.heappush(result, i)

while result:
    popped = heapq.heappop(result)
    print(popped)
    for j in priority[popped]:
        indegree[j] -= 1
        if indegree[j] == 0:
            heapq.heappush(result, j)


from .base import FunctionalTest
import time
from selenium.common.exceptions import WebDriverException
from datetime import datetime, date
from django.contrib.auth.models import User
# from selenium.webdriver.firefox.webdriver import WebDriver
# from selenium.webdriver.common.keys import Keys
# import unittest
# import os

# StaticLiveServerTestCase -> serve static files during test, spin up development server for test, creates and deletes test database without interfering with production database
class TestNewObjectSubmission(FunctionalTest):

	# User makes a submission and observes on objectList
	def test_1_new_userToDo_UserNote__NoteDescription_submission(self):
		User.objects.create_user('admin', 'admin@testuser.com', 'adminTest')

		# Webpage startup
		self.selenium.get( ('%s%s' % (self.live_server_url, '/')) )
		self.wait_for_(lambda: self.find_object_by_id("loginHeader", "Welcome to Marindec."))
		self.insert_Login(
			"admin",
			"adminTest",
			)

		self.wait_for_(lambda: self.find_object_by_id("updateItem", "ajax loaded."))

		self.insert_UserToDo(
			"Test New User To Do",
			"In Progress",
			failure=False,
			)

		self.selenium.find_element_by_id('refreshObjectList').click()
		self.wait_for_(lambda: self.find_object_by_id("UserToDo_subject", "Test New User To Do"))

		time.sleep(5)

		self.selenium.execute_script("window.scrollTo(0, document.body.scrollHeight);")
		# User inserts a new usernote
		self.selenium.find_element_by_id('UserToDo_subject').click()
		self.wait_for_(lambda: self.find_object_by_id("addUserNote_Toggle", "Insert a task"))
		self.selenium.find_element_by_id('addUserNote_Toggle').click()

		self.insert_UserNote(
			"Test New User Note",
			"In Progress",
			# datetime.strftime(date.today(), '%Y-%m-%d'),
			failure=False,
			)
		time.sleep(5)
		self.selenium.execute_script("window.scrollTo(0, document.body.scrollHeight);")

		self.selenium.find_element_by_id('refreshObjectList').click()
		time.sleep(5)
		self.selenium.find_element_by_id('UserToDo_subject').click()
		time.sleep(1)	# Allow for animation
		self.wait_for_(lambda: self.find_object_by_id("userNote_subject", "Test New User Note"))

		# User inserts a new note description
		self.selenium.find_element_by_id('userNote_subject').click()
		time.sleep(1)	# Allow for animation
		self.selenium.find_element_by_id('addNoteDescription_Toggle').click()
		self.insert_NoteDescription(
			"Test New Note Description",
			"In Progress",
			)
		time.sleep(5)
		self.selenium.find_element_by_id('refreshObjectList').click()
		time.sleep(5)
		self.selenium.find_element_by_id('UserToDo_subject').click()
		time.sleep(1)	# Allow for animation
		self.selenium.find_element_by_id('userNote_subject').click()
		time.sleep(1)	# Allow for animation
		self.wait_for_(lambda: self.find_object_by_id("noteDescription_1", "Test New Note Description"))

		# user clicks on edit objective to being making changes to UserToDO
		self.selenium.find_element_by_id('editUserToDo_Toggle').click()

		# Edit objective.
		self.elementID_wait("editUserToDo_heading")

		self.edit_UserToDo(
			"Edited New User To Do",
			"Completed",
			)
		self.selenium.find_element_by_id('refreshObjectList').click()
		self.wait_for_(lambda: self.find_object_by_id("UserToDo_subject", "Edited New User To Do"))
		print("TEST: test_new_userToDo_submission -> complete")

		# # User decides to make changes to userNote
		# self.selenium.find_element_by_id('UserToDo_subject').click()
		# time.sleep(1)	# Allow for animation
		# self.wait_for_(lambda: self.find_object_by_id("addUserNote_Toggle", "Insert a task"))
		# self.selenium.find_element_by_id('editUserNote_Toggle').click()
		# self.wait_for_(lambda: self.find_object_by_id("editUserNote_heading", "Edit this secondary objective"))
		# self.wait_for_(lambda: self.find_object_by_id("editUserNote_taskNote", "Test New User Note"))
		# self.selenium.execute_script("window.scrollTo(0, 1200)")
		# time.sleep(1)
		# self.edit_UserNote(
		# 	"Edited New User To Do",
		# 	"Completed",
		# 	)

		# # User decides to change a note description
		# self.selenium.find_element_by_id('refreshObjectList').click()
		# time.sleep(1)	# Allow for animation
		# self.selenium.find_element_by_id('UserToDo_subject').click()
		# time.sleep(1)	# Allow for animation
		# self.selenium.find_element_by_id('userNote_subject').click()
		# time.sleep(1)	# Allow for animation
		# self.selenium.find_element_by_id('editNoteDescription_Toggle').click()
		# self.edit_NoteDescription(
		# 	"Test New Note Description",
		# 	"In Progress",
		# 	)
		# self.selenium.execute_script("window.scrollTo(0, 1200)")
		# time.sleep(1)

		print("\ndef:test_1_new_userToDo_UserNote__NoteDescription_submission -> complete\n")

		return True


def load_matrix(filename):
    """
    pre: `filename` est un nom de fichier
    post: retourne une matrice rectangulaire M x N dont le contenu est donné
        dans le fichier `filename`.

    le format du fichier est :
        première ligne : le nombre de lignes M
        deuxième ligne : le nombre de colonnes N
        lignes suivantes : une ligne par élément au format "I,J VAL"
            où 0 <= I < M et 0 <= J < N
            et VAL est le réel en ligne I et colonne J de la matrice

    Les éléments non repris dans le fichier sont initialisés à 0.0.

    En cas d'erreur (exception d'entrée/sortie, fichier non lisible,
    mauvais format) retourne None.
    """
    with open(filename, "r") as f:
        try:
            n_row = int(f.readline())
            n_column = int(f.readline())
            matrix = []

            for i in range(n_row):
                matrix.append([])
                for j in range(n_column):
                    matrix[i].append(0.0)

            for line in f.readlines():
                info = line.split()
                number = info[1]
                i,j = info[0].split(",")
                matrix[int(i)][int(j)] = number
            return matrix
        except Exception:
            return None

# TESTS
f = open("mat.txt", "w")
f.write("""\
3
3
0,0 10
1,1 20
0,2 30
""")
f.close()
print(load_matrix("mat.txt"))


from PyQt6.QtCore import QTimer

from UM.Application import Application
from UM.Logger import Logger
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.Math.Vector import Vector
from UM.Scene.Selection import Selection
from UM.Scene.SceneNodeSettings import SceneNodeSettings

from cura.Scene.ConvexHullDecorator import ConvexHullDecorator

from cura.Operations import PlatformPhysicsOperation
from cura.Scene import ZOffsetDecorator

import random  # used for list shuffling

class PlatformPhysics:
    def __init__(self, controller, volume):
        super().__init__()
        self._controller = controller
        self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
        self._controller.toolOperationStarted.connect(self._onToolOperationStarted)
        self._controller.toolOperationStopped.connect(self._onToolOperationStopped)
        self._build_volume = volume
        self._enabled = True

        self._change_timer = QTimer()
        self._change_timer.setInterval(100)
        self._change_timer.setSingleShot(True)
        self._change_timer.timeout.connect(self._onChangeTimerFinished)
        self._move_factor = 1.1  # By how much should we multiply overlap to calculate a new spot?
        self._max_overlap_checks = 10  # How many times should we try to find a new spot per tick?
        self._minimum_gap = 2  # It is a minimum distance (in mm) between two models, applicable for small models

        Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", False)
        Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", True)

    def _onSceneChanged(self, source):
        if not source.callDecoration("isSliceable"):
            return

        self._change_timer.start()

    def _onChangeTimerFinished(self):
        if not self._enabled:
            return

        app_instance = Application.getInstance()
        app_preferences = app_instance.getPreferences()
        app_automatic_drop_down = app_preferences.getValue("physics/automatic_drop_down")
        app_automatic_push_free = app_preferences.getValue("physics/automatic_push_free")

        root = self._controller.getScene().getRoot()
        build_volume = app_instance.getBuildVolume()
        build_volume.updateNodeBoundaryCheck()

        # Keep a list of nodes that are moving. We use this so that we don't move two intersecting objects in the
        # same direction.
        transformed_nodes = []

        nodes = list(BreadthFirstIterator(root))

        # Only check nodes inside build area.
        nodes = [node for node in nodes if (hasattr(node, "_outside_buildarea") and not node._outside_buildarea)]

        # We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
        # By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
        random.shuffle(nodes)
        for node in nodes:
            if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None:
                continue

            bbox = node.getBoundingBox()

            # Move it downwards if bottom is above platform
            move_vector = Vector()

            if node.getSetting(SceneNodeSettings.AutoDropDown, app_automatic_drop_down) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled(): #If an object is grouped, don't move it down
                z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
                move_vector = move_vector.set(y = -bbox.bottom + z_offset)

            # If there is no convex hull for the node, start calculating it and continue.
            if not node.getDecorator(ConvexHullDecorator) and not node.callDecoration("isNonPrintingMesh") and node.callDecoration("getLayerData") is None:
                node.addDecorator(ConvexHullDecorator())

            # only push away objects if this node is a printing mesh
            if not node.callDecoration("isNonPrintingMesh") and app_automatic_push_free:
                # Do not move locked nodes
                if node.getSetting(SceneNodeSettings.LockPosition):
                    continue

                # Check for collisions between convex hulls
                for other_node in BreadthFirstIterator(root):
                    # Ignore root, ourselves and anything that is not a normal SceneNode.
                    if other_node is root or not issubclass(type(other_node), SceneNode) or other_node is node or other_node.callDecoration("getBuildPlateNumber") != node.callDecoration("getBuildPlateNumber"):
                        continue

                    # Ignore collisions of a group with it's own children
                    if other_node in node.getAllChildren() or node in other_node.getAllChildren():
                        continue

                    # Ignore collisions within a group
                    if other_node.getParent() and node.getParent() and (other_node.getParent().callDecoration("isGroup") is not None or node.getParent().callDecoration("isGroup") is not None):
                        continue

                    # Ignore nodes that do not have the right properties set.
                    if not other_node.callDecoration("getConvexHull") or not other_node.getBoundingBox():
                        continue

                    if other_node in transformed_nodes:
                        continue  # Other node is already moving, wait for next pass.

                    if other_node.callDecoration("isNonPrintingMesh"):
                        continue

                    overlap = (0, 0)  # Start loop with no overlap
                    current_overlap_checks = 0
                    # Continue to check the overlap until we no longer find one.
                    while overlap and current_overlap_checks < self._max_overlap_checks:
                        current_overlap_checks += 1
                        head_hull = node.callDecoration("getConvexHullHead")
                        if head_hull:  # One at a time intersection.
                            overlap = head_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_node.callDecoration("getConvexHull"))
                            if not overlap:
                                other_head_hull = other_node.callDecoration("getConvexHullHead")
                                if other_head_hull:
                                    overlap = node.callDecoration("getConvexHull").translate(move_vector.x, move_vector.z).intersectsPolygon(other_head_hull)
                                    if overlap:
                                        # Moving ensured that overlap was still there. Try anew!
                                        move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
                                                                      z = move_vector.z + overlap[1] * self._move_factor)
                            else:
                                # Moving ensured that overlap was still there. Try anew!
                                move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
                                                              z = move_vector.z + overlap[1] * self._move_factor)
                        else:
                            own_convex_hull = node.callDecoration("getConvexHull")
                            other_convex_hull = other_node.callDecoration("getConvexHull")
                            if own_convex_hull and other_convex_hull:
                                overlap = own_convex_hull.translate(move_vector.x, move_vector.z).intersectsPolygon(other_convex_hull)
                                if overlap:  # Moving ensured that overlap was still there. Try anew!
                                    temp_move_vector = move_vector.set(x = move_vector.x + overlap[0] * self._move_factor,
                                                                       z = move_vector.z + overlap[1] * self._move_factor)

                                    # if the distance between two models less than 2mm then try to find a new factor
                                    if abs(temp_move_vector.x - overlap[0]) < self._minimum_gap and abs(temp_move_vector.y - overlap[1]) < self._minimum_gap:
                                        temp_x_factor = (abs(overlap[0]) + self._minimum_gap) / overlap[0] if overlap[0] != 0 else 0 # find x move_factor, like (3.4 + 2) / 3.4 = 1.58
                                        temp_y_factor = (abs(overlap[1]) + self._minimum_gap) / overlap[1] if overlap[1] != 0 else 0 # find y move_factor

                                        temp_scale_factor = temp_x_factor if abs(temp_x_factor) > abs(temp_y_factor) else temp_y_factor

                                        move_vector = move_vector.set(x = move_vector.x + overlap[0] * temp_scale_factor,
                                                                      z = move_vector.z + overlap[1] * temp_scale_factor)
                                    else:
                                        move_vector = temp_move_vector
                            else:
                                # This can happen in some cases if the object is not yet done with being loaded.
                                # Simply waiting for the next tick seems to resolve this correctly.
                                overlap = None

            if not Vector.Null.equals(move_vector, epsilon = 1e-5):
                transformed_nodes.append(node)
                op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
                op.push()

        # After moving, we have to evaluate the boundary checks for nodes
        build_volume.updateNodeBoundaryCheck()

    def _onToolOperationStarted(self, tool):
        self._enabled = False

    def _onToolOperationStopped(self, tool):
        # Selection tool should not trigger an update.
        if tool.getPluginId() == "SelectionTool":
            return

        if tool.getPluginId() == "TranslateTool":
            for node in Selection.getAllSelectedObjects():
                if node.getBoundingBox() and node.getBoundingBox().bottom < 0:
                    if not node.getDecorator(ZOffsetDecorator.ZOffsetDecorator):
                        node.addDecorator(ZOffsetDecorator.ZOffsetDecorator())

                    node.callDecoration("setZOffset", node.getBoundingBox().bottom)
                else:
                    if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator):
                        node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)

        self._enabled = True
        self._onChangeTimerFinished()


import sqlite3
import logging
from variables import schema
from string import Template
from utilities import func_name
from os.path import isfile, isdir, join
from PIL import Image
from io import BytesIO

def connect_database(config, logger, **kwargs):
    logger = logging.getLogger(func_name())
    logger.debug(kwargs)

    database = config.database

    if not isfile(database):
        logger.warning("Use create database instead")
        return False
    connection = sqlite3.connect(database)
    sqlite_select_Query = "select sqlite_version();"
    cursor = connection.cursor()
    cursor.execute(sqlite_select_Query)
    record = cursor.fetchall()

    logger.debug("SQLite Database Version is: %s ", record)
    return connection

def create_table(logger, table_name, table_schema, connection, **kwargs):
    logger = logging.getLogger(func_name())
    logger.debug(table_name, table_schema, kwargs)

    cursor = connection.cursor()

    field_list = ""
    sql_template = Template("""CREATE TABLE  '${table_name}' (\n${field_list});""")
    for field, field_type in table_schema.items():
        field_list += "\t"
        field_list += " \t\t".join([field, field_type])
        field_list += ",\n"
    sql_create = sql_template.substitute(table_name=table_name, field_list=field_list[:-2])
    logger.debug(sql_create)
    cursor.execute(sql_create)

    cursor.close()

def create_database(config, logger, schema_list, **kwargs):
    """
    Create a database if none exists

    """
    database = config.database
    logger = logging.getLogger(func_name())
    logger.debug(database, schema_list, kwargs)

    connection = sqlite3.connect(database)
    sqlite_select_Query = "select sqlite_version();"
    cursor = connection.cursor()
    cursor.execute(sqlite_select_Query)
    record = cursor.fetchall()
    logger.info("Creating Database {}".format(database))
    logger.debug("SQLite Database Version is: ", record)

    # Put a list of tables from Globals to create schema
    cursor.execute("PRAGMA journal_mode=WAL;")
    logger.debug("Modifying database for WAL access")
    # Create all Schemas if new
    for schema in schema_list:
        table_name = list(schema.keys())[0]
        table_schema = schema[table_name]

        logger.debug('creating table: ', table_name)

        create_table(logger, table_name, table_schema, connection)

    cursor.close()
    connection.close()

def create_table(logger, table_name, table_schema, connection, **kwargs):
    logger = logging.getLogger(func_name())
    logger.debug(table_name, table_schema, kwargs)

    cursor = connection.cursor()

    field_list = ""
    sql_template = Template("""CREATE TABLE  '${table_name}' (\n${field_list});""")
    for field, field_type in table_schema.items():
        field_list += "\t"
        field_list += " \t\t".join([field, field_type])
        field_list += ",\n"
    sql_create = sql_template.substitute(table_name=table_name, field_list=field_list[:-2])
    logger.debug(sql_create)
    cursor.execute(sql_create)

    cursor.close()

def insert_into_db(logger, connection, table, record, **kwargs):
    """
    record is a dictionary
    """
    logger.debug('record filename {}'.format(record['filename_full']))
    logger.info('Writing record to table %s',table)
    logger = logging.getLogger(func_name())
    logger.debug(table, record, **kwargs)
    column_names = list()
    values = list()

    if not connection:
        logger.warning("Connection not valid")
        return False

    cursor = connection.cursor()
    sql_template = Template("""INSERT INTO ${table} (${columns}) VALUES (${values});""")
    column_names = ",".join(list(record.keys()))
    logger.debug(column_names)
    data_values = tuple(record.values())
    num_columns = len(list(record.keys()))
    values = ",".join([' ?'] * num_columns)
    sql_insert = sql_template.substitute(table=table, columns=column_names, values=values)
    logger.debug('columns_names %s', column_names)
    logger.debug("data values %s", data_values)
    logger.debug(sql_insert)
    logger.debug('columns_names',column_names)
    cursor.execute(sql_insert, data_values)
    connection.commit()

    return cursor.lastrowid

def insertImage(logger, connection, table_name, filename, name, image):
    print('inserting image into table {}'.format(table_name))
    try:
        sqlite_insert_blob_query = """ INSERT INTO {table_name}
                                  (filename, userid, headshot_image) VALUES (?, ?, ?)""".format(
            table_name=table_name)

        cursor = connection.cursor()
        # Convert data into tuple format
        data_tuple = (filename, name, image)
        cursor.execute(sqlite_insert_blob_query, data_tuple)
        connection.commit()
        print("Image and information {info} inserted successfully as a BLOB into a table {table_name}".format(info=name,
                                                                                table_name=table_name))

    except sqlite3.Error as error:
        print("Failed to insert blob data into sqlite table", error)

def get_named_faces(logger,connection,table_name):
    named_faces = dict()
    logger = logging.getLogger(func_name())
    logger.debug("get named faces from table %s", table_name)
    cursor = connection.cursor()
    sql_template = Template("""select * from  ${table} order by user_id;""")
    sql = sql_template.substitute(table_name=table_name)
    cursor.execute(sql)
    records = cursor.fetchall()
    for record in records:
        pass


n = int(input())

avg = 0
maxscore = 0

aa = list(map(int, input().split()))
maxscore = max(aa)

for i in range(n) :
    aa[i] = (aa[i] / maxscore) * 100
    avg += aa[i]

avg = avg / n
print(format(avg, ".2f"))


import sys
import numpy as np

sys.path.append('../mover_library/')

from mover_library.utils import compute_occ_vec, set_robot_config, remove_drawn_configs, \
    draw_configs, clean_pose_data, draw_robot_at_conf, \
    check_collision_except, two_arm_pick_object, two_arm_place_object, pick_distance, place_distance
from mover_library.samplers import sample_pick, sample_grasp_parameters, sample_ir, sample_ir_multiple_regions
from mover_library.operator_utils.grasp_utils import solveTwoArmIKs, compute_two_arm_grasp

class PickGenerator(object):
    def __init__(self, problem_env):
        self.problem_env = problem_env
        self.env = problem_env.env
        self.robot = self.env.GetRobots()[0]

    def predict(self, obj, region, n_iter):
        raise NotImplementedError

    def compute_grasp_config(self, obj, pick_base_pose, grasp_params):
        set_robot_config(pick_base_pose, self.robot)
        #if self.env.CheckCollision(self.robot):
        #    return None
        grasps = compute_two_arm_grasp(depth_portion=grasp_params[2],
                                       height_portion=grasp_params[1],
                                       theta=grasp_params[0],
                                       obj=obj,
                                       robot=self.robot)

        g_config = solveTwoArmIKs(self.env, self.robot, obj, grasps)
        return g_config

    def compute_grasp_action(self, obj, region, n_iter, pick_base_pose=None):
        grasp_params = None
        g_config = None

        #print 'Sampling pick'
        for iter in range(n_iter):
            # sample pick parameters
            if True:#pick_base_pose is None:
                with self.robot:
                    pick_base_pose = sample_ir(obj, self.robot, self.env, region, 1)
            if pick_base_pose is None:
                continue
                #return {'operator_name': 'two_arm_pick', 'base_pose': None, 'grasp_params': None, 'g_config': None}
            theta, height_portion, depth_portion = sample_grasp_parameters()

            grasp_params = np.array([theta[0], height_portion[0], depth_portion[0]])

            # compute if parameters are feasible
            g_config = self.compute_g_config(obj, pick_base_pose, grasp_params)
            if g_config is not None:
                pick_action = {'operator_name': 'two_arm_pick', 'base_pose': pick_base_pose,
                               'grasp_params': grasp_params, 'g_config': g_config}
                return pick_action
        #print "Sampling pick failed"
        #import pdb;pdb.set_trace()
        pick_action = {'operator_name': 'two_arm_pick', 'base_pose': None, 'grasp_params': None, 'g_config': None}
        return pick_action

    def compute_g_config(self, obj, pick_base_pose, grasp_params):
        with self.robot:
            g_config = self.compute_grasp_config(obj, pick_base_pose, grasp_params)
            if g_config is not None:
                pick_action = {'operator_name': 'two_arm_pick', 'base_pose': pick_base_pose,
                               'grasp_params': grasp_params, 'g_config': g_config}
                if self.problem_env.name == 'convbelt':
                    two_arm_pick_object(obj, pick_action)
                    set_robot_config(self.problem_env.init_base_conf, self.robot)
                    if not self.env.CheckCollision(self.robot):
                        two_arm_place_object(pick_action)
                        set_robot_config(self.problem_env.init_base_conf, self.robot)
                        #print "Sampling pick succeeded"
                        return g_config
                    else:
                        two_arm_place_object(pick_action)
                        set_robot_config(self.problem_env.init_base_conf, self.robot)
                elif self.problem_env.name == 'mover':
                    #print "Sampling mover pick succeeded"
                    return g_config
                else:
                    two_arm_pick_object(obj, pick_action)
                    if not self.env.CheckCollision(self.robot):
                        two_arm_place_object(pick_action)
                        #print "Sampling pick succeeded"
                        return g_config
                    else:
                        two_arm_place_object(pick_action)
            else:
                return None


# -*- coding: utf-8 -*-
"""
Created on Sat Nov 22 11:16:00 2019

@author: youko
"""
import os
import sys
import re
import datetime
import time
import pickle
from nltk.stem import PorterStemmer
import math
import json
from build import *
from query import *

######################### query expansion using pseudo relevance feedback algorithm
# here, we are using single term index

def topdoc_list(retrieved_):
    ''' given the retrieved top docs with tuples, return a list of top doc DOCNOS
    '''
    res = []
    for item in retrieved_:
        DOCNO,score = item
        res.append(DOCNO)
    return res

#################### TODO: should we sort the top_docs first????
def get_doc_length(collections,index_,top_docs):
    '''
    given top docs, return the term list of each docs
    need to be adjusted to make it run faster; index compressing
    '''
    doc_dict = {}
    indexer = Indexer('stops.txt')
    for f in collections:
        file = './trec_files/'+ f
        coll = open(file)
        doc = ""
        i = 0
        for line in coll:
            if '</DOC>' not in line:
                doc+=' '
                doc+=line
            else:
                # reach the end of one document
                # pass this document
                mydoc = doc
                doc = ""
                d = indexer.strip_text(mydoc)
                if d['DOCNO'] in top_docs:

                    doc_dict[d['DOCNO']] = {}
                    if index_ == 'single':
                        indexer.single_term_index(mydoc)
                        term_list = indexer.single_term
                    if index_ == 'stem':
                        indexer.stem_index(mydoc)
                        term_list = indexer.stemmed
                    if index_ == 'positional':
                        indexer.positional_index(mydoc)
                        term_list = indexer.term_positions
                    if index_ == 'phrase':
                        indexer.phrase_index(mydoc)
                        term_list = indexer.phrases
                    for tpl in term_list:
                        lexi,info = tpl
                        if index_ == 'positional':
                            doc_dict[d['DOCNO']][lexi] = info['pos']
                        else:
                            doc_dict[d['DOCNO']][lexi] = info['tf']

    return doc_dict

class Expander:
    '''for both expansion and reduction
    '''
    def __init__(self,lexicons,stop_word_path,index_):
        '''lexicons: specify the lexicon list you are gonna use
        '''
        self.stop_word_path = stop_word_path
        self.stop_words = self._set_of_stopwords(stop_word_path)
        self.doc_len = load_doc_length(index_)
        #self.doc_term = self.get_doc_length(collections,index_,)
        #self.N = len(self.doc_len)
        self.lexicons = lexicons
        self.index = index_
        #self.top_docs = []
        self.ranker = self.set_ranker()
        self.collections = os.listdir('./trec_files/')

    def set_ranker(self):
        #doc_len = load_doc_length(self.index)
        ranker = Ranker(self.lexicons,self.doc_len,self.stop_word_path)
        return ranker

    def _set_of_stopwords(self, path):
        '''
        create set of words from stop-words file
        :param path: path to stop-word file
        :return: set of stop-words
        '''
        if not os.path.exists(path):
            return set()
        with open(path) as f:
            return set((line.strip() for line in f.readlines()))

    def sorting_weight(self,doc_term,term,criteria):
        '''function to compute n*idf, which is our sorting criteria
        TODO: implement several sorting criteria to see the different effects
        '''
        # compute idf
        #from query import load_doc_length,Ranker
        #doc_len = load_doc_length(self.index)
        #ranker = Ranker(self.lexicons,self.doc_len,self.stop_word_path)
        # load doc_length file
        # top_docs =
        #doc_term = get_doc_length(collections,self.index,)

        if term not in self.lexicons:
            return 0
        else:
            N = len(self.doc_len)
            pl = self.ranker.get_postinglist(term,self.index)
            df = len(pl)
            # compute idf
            idf = math.log10(N/df)

            df = 0
            n = 0
            f = 0
            for DOCNO,all_terms in doc_term.items():
                if term in doc_term[DOCNO]:
                    # compute number of docs in relevant set that haves term
                    f += doc_term[DOCNO][term]
                    n += 1

            # compute idf
            if criteria == 'number':
                return n*idf
            if criteria == 'frequency':
                return f*idf

    def topterm_list(self,q,t,criteria,df_threshold,top_docs):
        '''
        for a given q, and a given relevant doc set,
        we want to get the top terms from the top docs
        df_threshold will prevent adding terms that are too rare in some cases
        '''
        all_terms = {}
        res = []
        # create top doc list
        #top_docs = topdoc_list(retrieved_)
        doc_term = get_doc_length(self.collections,self.index,top_docs)
        query_terms = preprocess_query(q,self.index)
        # we want to exclude the terms that are already in the query
        for docno,term_dict in doc_term.items():
            for term,tf in term_dict.items():
                if term not in all_terms and term not in query_terms:
                    all_terms[term] = [self.sorting_weight(doc_term,term,criteria),len(self.ranker.get_postinglist(term,self.index))]

        sorted_tw = sorted(all_terms.items(),key=lambda kv: kv[1][0],reverse = True)
        #top_terms_weight = sorted(all_terms.items(),key=lambda kv: kv[1],reverse = True)[:t]
        for term,w_df in sorted_tw:
            if w_df[1]>df_threshold:
                res.append({term:w_df})
        if len(res)>=t:
            return res[:t]
        else:
            return res

    def expand_query(self,q,t,criteria,df_threshold,top_docs):
        '''
        for a given query and based on a relevant doc set, we want to expand it
        then use the new query q' to do retrieving again
        '''
        #res = []
        q_terms = preprocess_query(q,self.index)
        #retrieved = retrieve_docs(self.lexicons,self.doc_len,q,n,self.index,metric)
        added_terms = self.topterm_list(q,t,criteria,df_threshold,top_docs)
        # add terms to q_terms
        for ele in added_terms:
            for key, value in ele.items():
                q_terms.append(key)
        new_q = ' '.join(q_terms)
        return new_q

class Reducer:
    def __init__(self,lexicons,stop_word_path,index_):
        self.lexicons = lexicons
        self.stop_word_path = stop_word_path
        self.index = index_
        self.doc_len = load_doc_length(index_)
        self.ranker = self.set_ranker()

    def set_ranker(self):
        #doc_len = load_doc_length(self.index)
        ranker = Ranker(self.lexicons,self.doc_len,self.stop_word_path)
        return ranker

    def _set_of_stopwords(self, path):
        '''
        create set of words from stop-words file
        :param path: path to stop-word file
        :return: set of stop-words
        '''
        if not os.path.exists(path):
            return set()
        with open(path) as f:
            return set((line.strip() for line in f.readlines()))

    def common_reducer(self,q,threshold):
        '''given a unpreprocessed query, we want to get the reduced query based on
        a given threshold;
        will return a new query
        note that, it is not relying on the irrelevant set and relevant set
        '''
        res = []
        narr_ = preprocess_query(q,self.index)
        thre_dict = {}
        for term in narr_:
            if term not in thre_dict:
                thre_dict[term] = self.ranker.compute_weight(term,narr_,self.index)
        # sort the dict
        sorted_thre = sorted(thre_dict.items(),key = lambda kv:kv[1],reverse = True)
        # get the amount of the terms we are going to use here
        term_amount = int(threshold*len(set(narr_)))
        temp = sorted_thre[:term_amount]
        for t_w in temp:
            term,weight = t_w
            res.append(term)

        return ' '.join(res)

    def rocchio_reducer(self,q,threshold,top_docs_narr):
        '''given a query(in our case, use the narratives), and given a relevant set(retrieved)
        reduce the query based on some threshold set for the query length
        '''
        # extract documents using original narrative

        #retrieved_ = retrieve_docs(lexicons,single_len,q,index_,'BM25')
        narr_terms = preprocess_query(q,self.index)
        #top_docs_narr = topdoc_list(retrieved_)
        irrelevant_docs = []
        for term in narr_terms:

            pl = self.ranker.get_postinglist(term,self.index)
            for docno,tf in pl.items():
                if docno not in top_docs_narr:
                    # compute the term 'tf*idf'
                    irrelevant_docs.append(docno)
        # compute the term 'tf*idf'
        irre_size = len(irrelevant_docs)
        term_irre = {}
        for term in list(set(narr_terms)):
            n_irre = 0
            tf = 0
            pl = self.ranker.get_postinglist(term,self.index)
            for docno,t_f in pl.items():
                if docno in irrelevant_docs:
                    tf += t_f
                    n_irre += 1

            term_irre[term] = n_irre*math.log10(irre_size/len(pl))
        # sort the term_irre
        sorted_irre = sorted(term_irre.items(),key = lambda kv:kv[1], reverse = False)
        # based on threshold , removing terms that got high weight in irrelevant doc set
        all_terms = []
        for item in sorted_irre:
            term,weight = item
            all_terms.append(term)
        term_amount = int(len(set(narr_terms))*threshold)
        res = all_terms[:term_amount]
        return ' '.join(res)


from io import BytesIO
from time import time

import pybase16384 as pybs

pybs.is_64bits()
with open("input.pcm", "rb") as f:
    data = f.read()

st = time()
for i in range(10):
    pybs.encode_file(BytesIO(data), open("output2.pcm", "wb"), True, len(data) // 7)
print(f"耗时： {time() - st}")


alphabet = "abcdefghijklmnopqrstuvwxyz"
prefix = "vikeCTF"

ciphertext = input("text to decrypt:\n")

def decrypt(text, key):
	plaintext = ""
	for i, c in enumerate(text):
		if not c.isalpha():
			plaintext += c
			continue

		offset = alphabet.find(c.lower())
		rotation = key[i % len(key)]

		result = alphabet[(offset + rotation) % len(alphabet)]
		if c.islower():
			plaintext += result
		else:
			plaintext += result.upper()

	return plaintext

key = []
while len(key) < len("vikeCTF"):
	for i in range(27):
		if i == 26:
			print("no solution :(")
			exit(1)
		key.append(i)
		plaintext = decrypt(ciphertext[:len(key)], key)
		if prefix.startswith(plaintext):
			break
		key.pop()

print("key:", *map(lambda x: (26-x), key))
print("plaintext:")
print(decrypt(ciphertext, key))


from collections import OrderedDict
from braindecode.datautil.signalproc import exponential_running_standardize
from braindecode.datautil.trial_segment import create_signal_target_from_raw_mne
import logging
import numpy as np
from braindecode.datasets.bbci import BBCIDataset
from braindecode.datautil.signalproc import highpass_cnt
from braindecode.mne_ext.signalproc import mne_apply, resample_cnt
import h5py
import os

log = logging.getLogger(__name__)
log.setLevel('INFO')
logging.basicConfig(level=logging.INFO)

def main():
    data_dir = '/home/no316758/data/high-gamma-dataset/data'
    data_dir = '/Users/sebas/code/_eeg_data/high-gamma-dataset/data'
    output_dir = os.path.abspath(
        os.path.join(os.path.dirname(__file__), '../..',
                     'data/hgd_processed_low_cut_4hz'))

    # Check ouput dir exists and possibly create it
    parent_output_dir = os.path.abspath(os.path.join(output_dir, os.pardir))
    assert os.path.exists(parent_output_dir), \
        "Parent directory of given output directory does not exist"
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # Get file paths:
    #   subject_ids: list of indices in range [1, ..., 14]
    subject_ids = [x for x in range(1, 15)]

    train_data_paths = [data_dir + f"/train/{subject_id}.mat" for subject_id in
                        subject_ids]
    test_data_paths = [data_dir + f"/test/{subject_id}.mat" for subject_id in
                       subject_ids]

    # Process and save data
    low_cut_hz = 4
    debug = False
    save_processed_high_gamma_datatset(train_data_paths, test_data_paths,
                                       output_dir, low_cut_hz, debug)

def save_processed_high_gamma_datatset(train_filenames, test_filenames,
                                       output_dir, low_cut_hz, debug=False):
    for train_filename, test_filename in zip(train_filenames, test_filenames):
        log.info("Processing data...")
        full_train_set = process_bbci_data(train_filename,
                                           low_cut_hz=low_cut_hz,
                                           debug=debug)
        test_set = process_bbci_data(test_filename, low_cut_hz=low_cut_hz,
                                     debug=debug)
        subject_id = train_filename.split('/')[-1].split('.')[0]
        log.info("Saving processed data...")
        with h5py.File(f'{output_dir}/{subject_id}_train.h5', 'w') as h5file:
            h5file.create_dataset(f'{subject_id}_train_X',
                                  data=list(full_train_set.X))
            h5file.create_dataset(f'{subject_id}_train_y',
                                  data=list(full_train_set.y))
        with h5py.File(f'{output_dir}/{subject_id}_test.h5', 'w') as h5file:
            h5file.create_dataset(f'{subject_id}_test_X', data=list(test_set.X))
            h5file.create_dataset(f'{subject_id}_test_y', data=list(test_set.y))
        log.info(f"Done processing data subject {subject_id}\n")

def process_bbci_data(filename, low_cut_hz, debug=False):
    """
    As taken from: https://github.com/robintibor/high-gamma-dataset
    :param filename: data from subject (train or test)
    :param low_cut_hz: 0 or 4
    :param debug:
    :return: SignalAndTarget
    """
    load_sensor_names = None
    if debug:
        load_sensor_names = ['C3', 'C4', 'C2']

    # We loaded all sensors to always get same cleaning
    #   results independent of sensor selection
    # There is an inbuilt heuristic that tries to use
    #   only EEG channels and that definitely
    #   works for datasets in our paper
    loader = BBCIDataset(filename, load_sensor_names=load_sensor_names)

    log.info("Loading raw data...")
    cnt = loader.load()

    # Cleaning: First find all trials that have absolute microvolt values
    # larger than +- 800 inside them and remember them for removal later
    log.info("Cutting trials...")

    marker_def = OrderedDict([('Right Hand', [1]), ('Left Hand', [2],),
                              ('Rest', [3]), ('Feet', [4])])
    clean_ival = [0, 4000]

    set_for_cleaning = create_signal_target_from_raw_mne(cnt, marker_def,
                                                         clean_ival)

    clean_trial_mask = np.max(np.abs(set_for_cleaning.X), axis=(1, 2)) < 800

    log.info("Clean trials: {:3d}  of {:3d} ({:5.1f}%)".format(
        np.sum(clean_trial_mask),
        len(set_for_cleaning.X),
        np.mean(clean_trial_mask) * 100))

    # now pick only sensors with C in their name
    # as they cover motor cortex
    C_sensors = ['FC5', 'FC1', 'FC2', 'FC6', 'C3', 'C4', 'CP5',
                 'CP1', 'CP2', 'CP6', 'FC3', 'FCz', 'FC4', 'C5', 'C1', 'C2',
                 'C6',
                 'CP3', 'CPz', 'CP4', 'FFC5h', 'FFC3h', 'FFC4h', 'FFC6h',
                 'FCC5h',
                 'FCC3h', 'FCC4h', 'FCC6h', 'CCP5h', 'CCP3h', 'CCP4h', 'CCP6h',
                 'CPP5h',
                 'CPP3h', 'CPP4h', 'CPP6h', 'FFC1h', 'FFC2h', 'FCC1h', 'FCC2h',
                 'CCP1h',
                 'CCP2h', 'CPP1h', 'CPP2h']
    if debug:
        C_sensors = load_sensor_names
    cnt = cnt.pick_channels(C_sensors)

    # Further preprocessings as descibed in paper
    log.info("Resampling...")
    cnt = resample_cnt(cnt, 250.0)
    log.info("Highpassing...")
    cnt = mne_apply(
        lambda a: highpass_cnt(
            a, low_cut_hz, cnt.info['sfreq'], filt_order=3, axis=1),
        cnt)
    log.info("Standardizing...")
    cnt = mne_apply(
        lambda a: exponential_running_standardize(a.T, factor_new=1e-3,
                                                  init_block_size=1000,
                                                  eps=1e-4).T,
        cnt)

    # Trial interval, start at -500 already,
    # since improved decoding for networks
    ival = [-500, 4000]

    dataset = create_signal_target_from_raw_mne(cnt, marker_def, ival)
    dataset.X = dataset.X[clean_trial_mask]
    dataset.y = dataset.y[clean_trial_mask]
    return dataset

if __name__ == '__main__':
    main()


# 2016-03-26   230 tests, 64 ms
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        if not head: return None
        n, p1, p2 = 0, head, head
        # p1 goes to the last node
        while p1.next: n, p1 = n + 1, p1.next
        if k % (n + 1) == 0: return head
        # p2 goes to the k place
        for i in xrange(n - k % (n + 1)): p2 = p2.next
        # find new head
        new_head, p2.next, p1.next = p2.next, None, head
        return new_head


import os
import random

import pygame

from data.base_modifier import BaseModifier
from data.colors import Colors

class Fortifier(BaseModifier):
    def __init__(self, game):
        self.name = "fortifier"
        self.game = game
        self.block_positions = self.get_block_positions()
        self.image = pygame.image.load(os.path.join("resources", "fortifier.png"))

    def set_icon_location(self):
        possible_locations = list(
            set(self.game.board_coordinates)
            - set(self.game.snake.body)
            - set(self.block_positions)
        )
        self.position = random.choice(possible_locations)
        x, y = self.position
        self.coordinates = (x * self.game.block_size, y * self.game.block_size)

    def get_block_positions(self):
        top_positions = [(i, 0) for i in range(20)]
        right_positions = [(19, i) for i in range(20)]
        bottom_positions = [(i, 19) for i in range(20)]
        left_positions = [(0, i) for i in range(20)]
        return [*top_positions, *right_positions, *bottom_positions, *left_positions]

    def check_block_hit(self):
        for block in self.block_positions:
            if self.game.snake.overlaps(block, head_only=True):
                self.game.end()

    def hide(self):
        self.position = []
        self.coordinates = []

    def draw(self):
        if self.coordinates:
            self.game.game_surface.blit(self.image, self.coordinates)

    def draw_blocks(self):
        for x, y in self.block_positions:
            rect = pygame.Rect(
                x * self.game.block_size,
                y * self.game.block_size,
                self.game.block_size,
                self.game.block_size,
            )
            pygame.draw.rect(self.game.game_surface, Colors.BLUE, rect, 0)


# https://www.codewars.com/kata/517abf86da9663f1d2000003

def to_camel_case(text):
    # Complete the method/function so that it converts dash/underscore delimited words into camel casing.
    # The first word within the output should be capitalized only if the original word was capitalized
    # (known as Upper Camel Case, also often referred to as Pascal case).

    new_text = ""
    separated = False
    for i in range(0, len(text)):
        if (text[i] == "-" or text[i] == "_"):
            separated = True
        else:
            if separated:
                separated = False
                new_text += text[i].upper()
            else:
                new_text += text[i]
    return new_text


import pandas as pd
import requests

API_KEY = 'Bearer e3920e0f60c88136aa66dca3bbfbae7f-bb9c32f4d0ab0fc0106137b0467a4394'

HEADERS = {
    'Content-Type': 'application/json',
    'Authorization': API_KEY
}

# format: Currency1_Currency2
INSTRUMENT = 'EUR_USD'

# e.g. 'S5', 'M15', 'H1', 'D', 'W', 'M'
# https://developer.oanda.com/rest-live-v20/instrument-df/ for full options
GRANULARITY = 'M30'

# format: '2016-06-01T15:00:00.000000000Z'
# leave None if using COUNT
#FROM_DATE = '2020-01-01T15:00:00.000000000Z'

# format: '2016-10-17T15:00:00.000000000Z'
# leave None for present time
#TO_DATE = '2020-05-01T15:00:00.000000000Z'

# (1 - 5000) must be in quotes e.g. '100'
# leave None if using dates, else fill with number of past candlesticks you want up to present time
COUNT = None

# 'practice' or 'trade'
ACCOUNT_TYPE = 'practice'

def export_ba_data():
    try:
        r = requests.get("https://api-fx{}.oanda.com/v3/instruments/{}/candles?price=BA".format(
            ACCOUNT_TYPE, INSTRUMENT), headers=HEADERS, params=PARAMS).json()

        df = pd.DataFrame(([candle['time'], candle['ask']['o'], candle['ask']['h'], candle['ask']['l'], candle['ask']['c'], candle['volume']] for candle in r['candles']),
                          columns=['Time', 'Open', 'High', 'Low', 'Close', 'Volume'])
        print(FROM_DATE)
        print(TO_DATE)
        # df.to_csv('ask_data.csv', index=False)
        return df
    except:
        print('request failed, likely that candlestick count is out of range (max=50000)')

#####################################
from_year = 2020
from_month = 1
to_year = 2021
to_month = 1
#####################################
first_time = 1

for y in range(from_year, to_year+1):
    if ((y == to_year) and (y == from_year)):
        m_range_min = from_month
        m_range_max = to_month-1
    elif(y == from_year):
        m_range_min = from_month
        m_range_max = 12
    elif(y == to_year):
        m_range_min = 1
        m_range_max = to_month-1
    else:
        m_range_min = 1
        m_range_max = 12

    for m in range(m_range_min, m_range_max+1):
        m1 = m
        m2 = m+1
        if(m1 >= 10):
            FROM_DATE = str(y)+'-'+str(m1)+'-01T15:00:00.000000000Z'
        else:
            FROM_DATE = str(y)+'-0'+str(m1)+'-01T15:00:00.000000000Z'
        if(m2 >= 10):
            if(m2 == 13):
                TO_DATE = str(y+1)+'-0'+str(1)+'-01T15:00:00.000000000Z'
            else:
                TO_DATE = str(y)+'-'+str(m2)+'-01T15:00:00.000000000Z'
        else:
            TO_DATE = str(y)+'-0'+str(m2)+'-01T15:00:00.000000000Z'
            #TO_DATE = '2020-05-01T15:00:00.000000000Z'
        PARAMS = {
            'from': FROM_DATE,
            'to': TO_DATE,
            'count': COUNT,
            'granularity': GRANULARITY
        }
        # print(FROM_DATE)
        # print(TO_DATE)
        if(first_time):
            df = export_ba_data()
            first_time = 0
        else:
            df_aux = export_ba_data()
            df = df.append(df_aux)

df.to_csv('ask_data.csv', index=False)
print('bid/ask data exported to "ask_data.csv"')


import openpyxl

# 打开excel文件,获取工作簿对象
wb = openpyxl.load_workbook('example.xlsx')
ws = wb.active  # 当前活跃的表单

col_range = ws['B:C']
row_range = ws[2:6]

# for col in col_range:  # 打印BC两列单元格中的值内容
#     for cell in col:
#         print(cell.value)

# for row in row_range:  # 打印 2-5行中所有单元格中的值
#     for cell in row:
#         print(cell.value)
#
for row in ws.iter_rows(min_row=1, max_row=2, max_col=3):  # 打印1-2行，1-3列中的内容
    for cell in row:
        print(cell.value)

3_简历/3_python操作excel/1_获取excel/5_遍历行和列中单元格的值　.py

5_遍历行和列中单元格的值　.py


#!/usr/bin/python3
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-

import apt
import apt_pkg
import hashlib
import mock
import os
import unittest
import shutil
import tempfile
import json

from DistUpgrade.DistUpgradeQuirks import DistUpgradeQuirks

CURDIR = os.path.dirname(os.path.abspath(__file__))

class MockController(object):
    def __init__(self):
        self._view = None

class MockConfig(object):
    pass

class MockPopenSnap():
    def __init__(self, cmd, universal_newlines=True,
                 stdout=None):
        self.command = cmd

    def communicate(self):
        if self.command[1] == "list":
            return []
        snap_name = self.command[2]
        if snap_name == 'gnome-logs':
            # Package to refresh
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gnome-calculator
snap-id:      1234
tracking:     stable/ubuntu-19.04
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
installed:   3.32.1             (406) 4MB -
"""]
        elif "gnome-characters" in snap_name:
            # Package installed but not tracking the release channel
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gnome-characters
snap-id:      1234
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
installed:   3.32.1             (406) 4MB -
"""]
        elif "gtk-common-themes" in snap_name:
            # Package installed but missing/invalid snap id
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gtk-common-themes
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
"""]
        else:
            return ["""
name:      test-snap
summary:   Test Snap
publisher: Canonical
license:   unset
description: Some description
commands:
  - gnome-calculator
snap-id:      1234
refresh-date: 2019-04-11
channels:
  stable:    3.32.1  2019-04-10 (406) 4MB -
  candidate: 3.32.2  2019-06-26 (433) 4MB -
  beta:      3.33.89 2019-08-06 (459) 4MB -
  edge:      3.33.90 2019-08-06 (460) 4MB -
"""]

def mock_urlopen_snap(req):
    result = """{{
  "error-list": [],
  "results": [
    {{
      "effective-channel": "stable",
      "instance-key": "test",
      "name": "{name}",
      "released-at": "2019-04-10T18:54:15.717357+00:00",
      "result": "download",
      "snap": {{
        "created-at": "2019-04-09T17:09:29.941588+00:00",
        "download": {{
          "deltas": [],
          "size": {size},
          "url": "SNAPURL"
        }},
        "license": "GPL-3.0+",
        "name": "{name}",
        "prices": {{ }},
        "publisher": {{
          "display-name": "Canonical",
          "id": "canonical",
          "username": "canonical",
          "validation": "verified"
        }},
        "revision": 406,
        "snap-id": "{snap_id}",
        "summary": "GNOME Calculator",
        "title": "GNOME Calculator",
        "type": "app",
        "version": "3.32.1"
      }},
      "snap-id": "{snap_id}"
    }}
  ]
}}
"""
    test_snaps = {
        '1': ("gnome-calculator", 4218880),
        '2': ("test-snap", 2000000)
    }
    json_data = json.loads(req.data)
    snap_id = json_data['actions'][0]['snap-id']
    name = test_snaps[snap_id][0]
    size = test_snaps[snap_id][1]
    response_mock = mock.Mock()
    response_mock.read.return_value = result.format(
        name=name, snap_id=snap_id, size=size)
    return response_mock

def make_mock_pkg(name, is_installed, candidate_rec=""):
    mock_pkg = mock.Mock()
    mock_pkg.name = name
    mock_pkg.is_installed = is_installed
    mock_pkg.marked_install = False
    if candidate_rec:
        mock_pkg.candidate = mock.Mock()
        mock_pkg.candidate.record = candidate_rec
    return mock_pkg

class TestPatches(unittest.TestCase):

    orig_chdir = ''

    def setUp(self):
        # To patch, we need to be in the same directory as the patched files
        self.orig_chdir = os.getcwd()
        os.chdir(CURDIR)

    def tearDown(self):
        os.chdir(self.orig_chdir)

    def _verify_result_checksums(self):
        """ helper for test_patch to verify that we get the expected result """
        # simple case is foo
        patchdir = CURDIR + "/patchdir/"
        with open(patchdir + "foo") as f:
            self.assertFalse("Hello" in f.read())
        with open(patchdir + "foo_orig") as f:
            self.assertTrue("Hello" in f.read())
        md5 = hashlib.md5()
        with open(patchdir + "foo", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "52f83ff6877e42f613bcd2444c22528c")
        # more complex example fstab
        md5 = hashlib.md5()
        with open(patchdir + "fstab", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "c56d2d038afb651920c83106ec8dfd09")
        # most complex example
        md5 = hashlib.md5()
        with open(patchdir + "pycompile", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "97c07a02e5951cf68cb3f86534f6f917")
        # with ".\n"
        md5 = hashlib.md5()
        with open(patchdir + "dotdot", "rb") as patch:
            md5.update(patch.read())
        self.assertEqual(md5.hexdigest(), "cddc4be46bedd91db15ddb9f7ddfa804")
        # test that incorrect md5sum after patching rejects the patch
        with open(patchdir + "fail") as f1, open(patchdir + "fail_orig") as f2:
            self.assertEqual(f1.read(),
                             f2.read())

    def test_patch(self):
        q = DistUpgradeQuirks(MockController(), MockConfig)
        # create patch environment
        patchdir = CURDIR + "/patchdir/"
        shutil.copy(patchdir + "foo_orig", patchdir + "foo")
        shutil.copy(patchdir + "fstab_orig", patchdir + "fstab")
        shutil.copy(patchdir + "pycompile_orig", patchdir + "pycompile")
        shutil.copy(patchdir + "dotdot_orig", patchdir + "dotdot")
        shutil.copy(patchdir + "fail_orig", patchdir + "fail")
        # apply patches
        q._applyPatches(patchdir=patchdir)
        self._verify_result_checksums()
        # now apply patches again and ensure we don't patch twice
        q._applyPatches(patchdir=patchdir)
        self._verify_result_checksums()

    def test_patch_lowlevel(self):
        # test lowlevel too
        from DistUpgrade.DistUpgradePatcher import patch, PatchError
        self.assertRaises(PatchError, patch, CURDIR + "/patchdir/fail",
                          CURDIR + "/patchdir/patchdir_fail."
                          "ed04abbc6ee688ee7908c9dbb4b9e0a2."
                          "deadbeefdeadbeefdeadbeff",
                          "deadbeefdeadbeefdeadbeff")

class TestQuirks(unittest.TestCase):

    orig_recommends = ''
    orig_status = ''

    def setUp(self):
        self.orig_recommends = apt_pkg.config.get("APT::Install-Recommends")
        self.orig_status = apt_pkg.config.get("Dir::state::status")

    def tearDown(self):
        apt_pkg.config.set("APT::Install-Recommends", self.orig_recommends)
        apt_pkg.config.set("Dir::state::status", self.orig_status)

    def test_enable_recommends_during_upgrade(self):
        controller = mock.Mock()

        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        # server mode
        apt_pkg.config.set("APT::Install-Recommends", "0")
        controller.serverMode = True
        self.assertFalse(apt_pkg.config.find_b("APT::Install-Recommends"))
        q.ensure_recommends_are_installed_on_desktops()
        self.assertFalse(apt_pkg.config.find_b("APT::Install-Recommends"))
        # desktop mode
        apt_pkg.config.set("APT::Install-Recommends", "0")
        controller.serverMode = False
        self.assertFalse(apt_pkg.config.find_b("APT::Install-Recommends"))
        q.ensure_recommends_are_installed_on_desktops()
        self.assertTrue(apt_pkg.config.find_b("APT::Install-Recommends"))

    def test_parse_from_modaliases_header(self):
        pkgrec = {
            "Package": "foo",
            "Modaliases": "modules1(pci:v00001002d00006700sv*sd*bc03sc*i*, "
                          "pci:v00001002d00006701sv*sd*bc03sc*i*), "
                          "module2(pci:v00001002d00006702sv*sd*bc03sc*i*, "
                          "pci:v00001001d00006702sv*sd*bc03sc*i*)"
        }
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        self.assertEqual(q._parse_modaliases_from_pkg_header({}), [])
        self.assertEqual(q._parse_modaliases_from_pkg_header(pkgrec),
                         [("modules1",
                           ["pci:v00001002d00006700sv*sd*bc03sc*i*",
                            "pci:v00001002d00006701sv*sd*bc03sc*i*"]),
                          ("module2",
                           ["pci:v00001002d00006702sv*sd*bc03sc*i*",
                            "pci:v00001001d00006702sv*sd*bc03sc*i*"])])

    def disabled__as_fglrx_is_gone_testFglrx(self):
        mock_lspci_good = set(['1002:9990'])
        mock_lspci_bad = set(['8086:ac56'])
        config = mock.Mock()
        cache = apt.Cache()
        controller = mock.Mock()
        controller.cache = cache
        q = DistUpgradeQuirks(controller, config)
        if q.arch not in ['i386', 'amd64']:
            return self.skipTest("Not on an arch with fglrx package")
        self.assertTrue(q._supportInModaliases("fglrx", mock_lspci_good))
        self.assertFalse(q._supportInModaliases("fglrx", mock_lspci_bad))

    def test_screensaver_poke(self):
        # fake nothing is installed
        empty_status = tempfile.NamedTemporaryFile()
        apt_pkg.config.set("Dir::state::status", empty_status.name)

        # create quirks class
        controller = mock.Mock()
        config = mock.Mock()
        quirks = DistUpgradeQuirks(controller, config)
        quirks._pokeScreensaver()
        res = quirks._stopPokeScreensaver()
        res  # pyflakes

    def test_get_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-3.19-24-generic",
                is_installed=True,
                candidate_rec={"Source": "linux"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-generic")

    def test_get_lpae_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-4.2.0-16-generic-lpae",
                is_installed=True,
                candidate_rec={"Source": "linux"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-generic-lpae")

    def test_get_lowlatency_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-4.2.0-16-lowlatency",
                is_installed=True,
                candidate_rec={"Source": "linux"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-lowlatency")

    def test_get_lts_linux_metapackage(self):
        q = DistUpgradeQuirks(mock.Mock(), mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="linux-image-3.13.0-24-generic",
                is_installed=True,
                candidate_rec={"Source": "linux-lts-quantal"},
            ),
        ])
        pkgname = q._get_linux_metapackage(mock_cache, headers=False)
        self.assertEqual(pkgname, "linux-generic-lts-quantal")

    def test_ros_installed_warning(self):
        ros_packages = (
            "ros-melodic-catkin",
            "ros-noetic-rosboost-cfg",
            "ros-foxy-rosclean",
            "ros-kinetic-ros-environment",
            "ros-dashing-ros-workspace")
        for package_name in ros_packages:
            mock_controller = mock.Mock()
            mock_question = mock_controller._view.askYesNoQuestion
            mock_question.return_value = True

            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            mock_cache = set([
                make_mock_pkg(
                    name=package_name,
                    is_installed=True,
                ),
            ])
            q._test_and_warn_if_ros_installed(mock_cache)
            mock_question.assert_called_once_with(mock.ANY, mock.ANY)
            self.assertFalse(len(mock_controller.abort.mock_calls))

            mock_controller.reset_mock()
            mock_question.reset_mock()
            mock_question.return_value = False

            mock_cache = set([
                make_mock_pkg(
                    name=package_name,
                    is_installed=True,
                ),
            ])
            q._test_and_warn_if_ros_installed(mock_cache)
            mock_question.assert_called_once_with(mock.ANY, mock.ANY)
            mock_controller.abort.assert_called_once_with()

    def test_ros_not_installed_no_warning(self):
        mock_controller = mock.Mock()
        mock_question = mock_controller._view.askYesNoQuestion
        mock_question.return_value = False

        q = DistUpgradeQuirks(mock_controller, mock.Mock())
        mock_cache = set([
            make_mock_pkg(
                name="ros-melodic-catkin",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-noetic-rosboost-cfg",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-foxy-rosclean",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-kinetic-ros-environment",
                is_installed=False,
            ),
            make_mock_pkg(
                name="ros-dashing-ros-workspace",
                is_installed=False,
            ),
        ])
        q._test_and_warn_if_ros_installed(mock_cache)
        self.assertFalse(len(mock_question.mock_calls))
        self.assertFalse(len(mock_controller.abort.mock_calls))

    @mock.patch('os.path.exists')
    def test_aufs_fail(self, mock_exists):
        mock_exists.return_value = True
        mock_controller = mock.Mock()

        q = DistUpgradeQuirks(mock_controller, mock.Mock())

        q._test_and_fail_on_aufs()
        self.assertTrue(len(mock_controller.abort.mock_calls))

    def test_replace_fkms_overlay_no_config(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            mock_controller = mock.Mock()

            q = DistUpgradeQuirks(mock_controller, mock.Mock())

            q._replace_fkms_overlay(boot_dir)
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))

    def test_replace_fkms_overlay_no_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            demo_config = """\
# This is a demo boot config
[pi4]
max_framebuffers=2
[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(demo_config)

            mock_controller = mock.Mock()

            q = DistUpgradeQuirks(mock_controller, mock.Mock())

            q._replace_fkms_overlay(boot_dir)
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == demo_config)

    def test_replace_fkms_overlay_with_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            demo_config = """\
# This is a demo boot config
[pi4]
max_framebuffers=2
[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel
dtoverlay=vc4-fkms-v3d,cma-256
start_x=1
gpu_mem=256
"""
            expected_config = """\
# This is a demo boot config
[pi4]
max_framebuffers=2
[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel
# changed by do-release-upgrade (LP: #1923673)
#dtoverlay=vc4-fkms-v3d,cma-256
dtoverlay=vc4-kms-v3d,cma-256
# disabled by do-release-upgrade (LP: #1923673)
#start_x=1
# disabled by do-release-upgrade (LP: #1923673)
#gpu_mem=256
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(demo_config)

            mock_controller = mock.Mock()

            q = DistUpgradeQuirks(mock_controller, mock.Mock())

            q._replace_fkms_overlay(boot_dir)
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == expected_config)

    def test_remove_uboot_no_config(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))

    def test_remove_uboot_no_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            native_config = """\
# This is a demo boot config with a comment at the start that should not
# be removed

[pi4]
max_framebuffers=2

[all]
arm_64bit=1
kernel=vmlinuz
initramfs initrd.img followkernel

# This is a user-added include that should not be merged
include custom.txt
"""
            custom_config = """\
# This is the custom included configuration file

hdmi_group=1
hdmi_mode=4
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(native_config)
            with open(os.path.join(boot_dir, 'custom.txt'), 'w') as f:
                f.write(custom_config)

            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'custom.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == native_config)
            with open(os.path.join(boot_dir, 'custom.txt')) as f:
                self.assertTrue(f.read() == custom_config)

    def test_remove_uboot_with_changes(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            config_txt = """\
# This is a warning that you should not edit this file. The upgrade should
# remove this comment

[pi4]
# This is a comment that should be included
kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi2]
kernel=uboot_rpi_2.bin

[pi3]
kernel=uboot_rpi_3.bin

[all]
arm_64bit=1
device_tree_address=0x3000000
include syscfg.txt
include usercfg.txt
dtoverlay=vc4-fkms-v3d,cma-256
include custom.txt
"""
            usercfg_txt = """\
# Another chunk of warning text that should be skipped
"""
            syscfg_txt = """\
# Yet more warnings to exclude
dtparam=audio=on
dtparam=spi=on
enable_uart=1
"""
            custom_txt = """\
# This is a user-added file that should be left alone by the upgrade
[gpio4=1]
kernel=custom
"""
            expected_config_txt = """\

[pi4]
# This is a comment that should be included
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi2]
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_2.bin

[pi3]
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_3.bin

[all]
# added by do-release-upgrade (LP: #1936401)
kernel=vmlinuz
initramfs initrd.img followkernel
arm_64bit=1
# commented by do-release-upgrade (LP: #1936401)
#device_tree_address=0x3000000
# merged from syscfg.txt by do-release-upgrade (LP: #1936401)
dtparam=audio=on
dtparam=spi=on
enable_uart=1
# merged from usercfg.txt by do-release-upgrade (LP: #1936401)
dtoverlay=vc4-fkms-v3d,cma-256
include custom.txt
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(config_txt)
            with open(os.path.join(boot_dir, 'syscfg.txt'), 'w') as f:
                f.write(syscfg_txt)
            with open(os.path.join(boot_dir, 'usercfg.txt'), 'w') as f:
                f.write(usercfg_txt)
            with open(os.path.join(boot_dir, 'custom.txt'), 'w') as f:
                f.write(custom_txt)

            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'syscfg.txt.distUpgrade')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'usercfg.txt.distUpgrade')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt')))
            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'custom.txt')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'syscfg.txt')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'usercfg.txt')))
            self.assertFalse(os.path.exists(os.path.join(
                boot_dir, 'custom.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == expected_config_txt)
            with open(os.path.join(boot_dir, 'custom.txt')) as f:
                self.assertTrue(f.read() == custom_txt)

    def test_remove_uboot_no_all_section(self):
        with tempfile.TemporaryDirectory() as boot_dir:
            config_txt = """\
arm_64bit=1
device_tree_address=0x3000000

[pi4]
# This is a comment that should be included
kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi3]
kernel=uboot_rpi_3.bin
"""
            expected_config_txt = """\
arm_64bit=1
# commented by do-release-upgrade (LP: #1936401)
#device_tree_address=0x3000000

[pi4]
# This is a comment that should be included
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_4.bin
max_framebuffers=2

[pi3]
# commented by do-release-upgrade (LP: #1936401)
#kernel=uboot_rpi_3.bin
# added by do-release-upgrade (LP: #1936401)
[all]
kernel=vmlinuz
initramfs initrd.img followkernel
"""
            with open(os.path.join(boot_dir, 'config.txt'), 'w') as f:
                f.write(config_txt)

            mock_controller = mock.Mock()
            q = DistUpgradeQuirks(mock_controller, mock.Mock())
            q._remove_uboot_on_rpi(boot_dir)

            self.assertTrue(os.path.exists(os.path.join(
                boot_dir, 'config.txt.distUpgrade')))
            with open(os.path.join(boot_dir, 'config.txt')) as f:
                self.assertTrue(f.read() == expected_config_txt)

class TestSnapQuirks(unittest.TestCase):

    def test_get_from_and_to_version(self):
        # Prepare the state for testing
        controller = mock.Mock()
        controller.fromDist = 'disco'
        controller.toDist = 'eoan'
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        # Call method under test
        q._get_from_and_to_version()
        self.assertEqual(q._from_version, '19.04')
        self.assertEqual(q._to_version, '19.10')

    @mock.patch("subprocess.Popen", MockPopenSnap)
    def test_prepare_snap_replacement_data(self):
        # Prepare the state for testing
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        q._from_version = "19.04"
        q._to_version = "19.10"
        # Call method under test

        controller.cache = {
            'ubuntu-desktop':
                make_mock_pkg(
                    name="ubuntu-desktop",
                    is_installed=True),
            'core18':
                make_mock_pkg(
                    name="core18",
                    is_installed=True),
            'firefox':
                make_mock_pkg(
                    name="firefox",
                    is_installed=True),
            'gnome-3-28-1804':
                make_mock_pkg(
                    name="gnome-3-28-1804",
                    is_installed=True),
            'gtk-common-themes':
                make_mock_pkg(
                    name="gtk-common-themes",
                    is_installed=True),
            'gnome-calculator':
                make_mock_pkg(
                    name="gnome-calculator",
                    is_installed=True),
            'gnome-characters':
                make_mock_pkg(
                    name="gnome-characters",
                    is_installed=False),
            'gnome-logs':
                make_mock_pkg(
                    name="gnome-logs",
                    is_installed=False),
            'gnome-software':
                make_mock_pkg(
                    name="gnome-software",
                    is_installed=True),
            'snap-not-tracked':
                make_mock_pkg(
                    name="snap-not-tracked",
                    is_installed=True),
        }

        q._prepare_snap_replacement_data()
        # Check if the right snaps have been detected as installed and
        # needing refresh and which ones need installation
        self.maxDiff = None
        self.assertDictEqual(
            q._snap_list,
            {'core20': {
                'channel': 'stable',
                'command': 'install',
                'deb': None, 'snap-id': '1234'},
             'firefox': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': 'firefox',
                'snap-id': '1234'},
             'gnome-3-34-1804': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': None, 'snap-id': '1234'},
             'gnome-3-38-2004': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': None, 'snap-id': '1234'},
             'gnome-logs': {
                'command': 'remove'},
             'snap-store': {
                'channel': 'stable/ubuntu-19.10',
                'command': 'install',
                'deb': 'gnome-software',
                'snap-id': '1234'}})

    def test_is_deb2snap_metapkg_installed(self):
        # Prepare the state for testing
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        q._from_version = "19.04"
        q._to_version = "19.10"
        controller.cache = {
            'ubuntu-desktop':
                make_mock_pkg(
                    name="ubuntu-desktop",
                    is_installed=True)
        }

        testdata = [
            # (input, expected output)
            ({}, False),
            ({'metapkg': None}, False),
            ({'metapkg': 'ubuntu-desktop'}, True),
            ({'metapkg': 'kubuntu-desktop'}, False),
            ({'metapkg': ['kubuntu-desktop', 'ubuntu-desktop']}, True),
            ({'metapkg': ['kubuntu-desktop', 'lubuntu-desktop']}, False),
        ]

        for data in testdata:
            self.assertEqual(q._is_deb2snap_metapkg_installed(data[0]),
                             data[1],
                             'Expected {1} for input {0}'.format(*data))

    @mock.patch("DistUpgrade.DistUpgradeQuirks.get_arch")
    @mock.patch("urllib.request.urlopen")
    def test_calculate_snap_size_requirements(self, urlopen, arch):
        # Prepare the state for testing
        arch.return_value = 'amd64'
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        # We mock out _prepare_snap_replacement_data(), as this is tested
        # separately.
        q._prepare_snap_replacement_data = mock.Mock()
        q._snap_list = {
            'test-snap': {'command': 'install',
                          'deb': None, 'snap-id': '2',
                          'channel': 'stable/ubuntu-19.10'},
            'gnome-calculator': {'command': 'install',
                                 'deb': 'gnome-calculator',
                                 'snap-id': '1',
                                 'channel': 'stable/ubuntu-19.10'},
            'gnome-system-monitor': {'command': 'refresh',
                                     'channel': 'stable/ubuntu-19.10'}
        }
        q._to_version = "19.10"
        # Mock out urlopen in such a way that we get a mocked response based
        # on the parameters given but also allow us to check call arguments
        # etc.
        urlopen.side_effect = mock_urlopen_snap
        # Call method under test
        q._calculateSnapSizeRequirements()
        # Check if the size was calculated correctly
        self.assertEqual(q.extra_snap_space, 6218880)
        # Check if we only sent queries for the two command: install snaps
        self.assertEqual(urlopen.call_count, 2)
        # Make sure each call had the right headers and parameters
        for call in urlopen.call_args_list:
            req = call[0][0]
            self.assertIn(b"stable/ubuntu-19.10", req.data)
            self.assertDictEqual(
                req.headers,
                {'Snap-device-series': '16',
                 'Content-type': 'application/json',
                 'Snap-device-architecture': 'amd64'})

    @mock.patch("subprocess.run")
    def test_replace_debs_and_snaps(self, run_mock):
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)
        q._snap_list = {
            'core18': {'command': 'refresh',
                       'channel': 'stable'},
            'gnome-3-28-1804': {'command': 'refresh',
                                'channel': 'stable/ubuntu-19.10'},
            'gtk-common-themes': {'command': 'refresh',
                                  'channel': 'stable/ubuntu-19.10'},
            'gnome-calculator': {'command': 'remove'},
            'gnome-characters': {'command': 'remove'},
            'gnome-logs': {'command': 'install',
                           'deb': 'gnome-logs',
                           'snap-id': '1234',
                           'channel': 'stable/ubuntu-19.10'},
            'gnome-system-monitor': {'command': 'install',
                                     'deb': 'gnome-system-monitor',
                                     'snap-id': '1234',
                                     'channel': 'stable/ubuntu-19.10'},
            'snap-store': {'command': 'install',
                           'deb': 'gnome-software',
                           'snap-id': '1234',
                           'channel': 'stable/ubuntu-19.10'}
        }
        q._to_version = "19.10"
        q._replaceDebsAndSnaps()
        # Make sure all snaps have been handled
        self.assertEqual(run_mock.call_count, 8)
        snaps_refreshed = {}
        snaps_installed = {}
        snaps_removed = []
        # Check if all the snaps that needed to be installed were installed
        # and those that needed a refresh - refreshed
        # At the same time, let's check that all the snaps were acted upon
        # while using the correct channel and branch
        for call in run_mock.call_args_list:
            args = call[0][0]
            if args[1] == 'refresh':
                snaps_refreshed[args[4]] = args[3]
            elif args[1] == 'install':
                snaps_installed[args[4]] = args[3]
            elif args[1] == 'remove':
                snaps_removed.append(args[2])
        self.assertDictEqual(
            snaps_refreshed,
            {'core18': 'stable',
             'gnome-3-28-1804': 'stable/ubuntu-19.10',
             'gtk-common-themes': 'stable/ubuntu-19.10'})
        self.assertDictEqual(
            snaps_installed,
            {'gnome-logs': 'stable/ubuntu-19.10',
             'gnome-system-monitor': 'stable/ubuntu-19.10',
             'snap-store': 'stable/ubuntu-19.10'})
        self.assertListEqual(
            snaps_removed,
            ['gnome-calculator',
             'gnome-characters'])
        # Make sure we marked the replaced ones for removal
        # Here we only check if the right number of 'packages' has been
        # added to the forced_obsoletes list - not all of those packages are
        # actual deb packages that will have to be removed during the upgrade
        self.assertEqual(controller.forced_obsoletes.append.call_count, 3)

    @mock.patch("builtins.open", new_callable=mock.mock_open,
                read_data="""\
processor       : 0
cpu             : POWER8 (raw), altivec supported
clock           : 3491.000000MHz
revision        : 2.0 (pvr 004d 0200)

processor       : 1
cpu             : POWER8 (raw), altivec supported
clock           : 3491.000000MHz
revision        : 2.0 (pvr 004d 0200)

timebase        : 512000000
platform        : PowerNV
model           : 8001-22C
machine         : PowerNV 8001-22C
firmware        : OPAL
MMU             : Hash
""")
    @mock.patch("DistUpgrade.DistUpgradeQuirks.get_arch",
                return_value="ppc64el")
    def test_power8_fail(self, arch, mock_file):
        controller = mock.Mock()
        config = mock.Mock()
        q = DistUpgradeQuirks(controller, config)

        q._test_and_fail_on_power8()
        self.assertTrue(len(controller.abort.mock_calls))

        mock_file.assert_called_with("/proc/cpuinfo")

if __name__ == "__main__":
    import logging
    logging.basicConfig(level=logging.DEBUG)
    unittest.main()