from datetime import datetime

import csv
import json

# Открываем файл invertary1.csv и читаем данные
with open('csv/inventory1.csv', 'r', encoding='utf-8') as csv_file:
    csv_reader = csv.reader(csv_file)
    data = []
    errors = []
    # Пропускаем заголовок
    next(csv_reader, None)
    for row in csv_reader:
        try:
            # Пытаемся извлечь данные из строки
            first_column = int(row[0])
            second_column = int(row[1])
            third_column = datetime.strptime(row[2], "%Y-%m-%d %H:%M")
            fourth_column = int(row[3])
            fifth_column = float(row[4])
            sixth_column = float(row[5])
            seventh_column = float(row[6])
            eighth_column = float(row[7])

            # Добавляем данные в список
            data.append({
                "first_column": first_column,
                "second_column": second_column,
                "third_column": third_column.strftime("%Y-%m-%d %H:%M"),
                "fourth_column": fourth_column,
                "fifth_column": fifth_column,
                "sixth_column": sixth_column,
                "seventh_column": seventh_column,
                "eighth_column": eighth_column
            })
        except Exception as e:
            # Если произошла ошибка, записываем предупреждение в лог и продолжаем обработку
            errors.append(f"Ошибка в строке '{','.join(row)}': {str(e)}")

# Преобразуем данные в формат JSON
with open('invertary1.json', 'w', encoding='utf-8') as json_file:
    json.dump(data, json_file, ensure_ascii=False, indent=4)

# Записываем предупреждения в лог
if errors:
    with open('invertary1_error_log.txt', 'w', encoding='utf-8') as log_file:
        log_file.write('\n'.join(errors))
    print("Обнаружены ошибки в файле invertary1.csv. Подробности записаны в файл 'invertary1_error_log.txt'.")
else:
    print("Данные из файла invertary1.csv успешно преобразованы в JSON и сохранены в файле 'invertary1.json'.")


import csv
from collections import defaultdict
from functools import reduce
from itertools import filterfalse, groupby, product
from operator import ior
from typing import Generator

from constance import config
from django.contrib.auth.tokens import default_token_generator
from django.core.mail import EmailMultiAlternatives, get_connection
from django.db import transaction
from django.db.models import Avg, Count, Q
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode

from apps.fair_categories.models import Category, Division, Ethnicity, Subcategory
from apps.judges.models import Judge
from apps.rubrics.models.rubric import QuestionResponse
from fair_scoring_site.logic import get_judging_rubric

from .models import JudgingInstance, Project, Teacher, create_student

def get_rubric_name():
    return config.RUBRIC_NAME

class StudentData:
    def __init__(self, **kwargs):
        self.row_data = kwargs
        self.set_if_contains("first_name", "First Name")
        self.set_if_contains("last_name", "Last Name")
        self.set_if_contains("grade_level", "Grade")
        self.set_if_contains("email", "Email")
        self.set_if_contains("_ethnicity", "Ethnicity")
        self.set_if_contains("_gender", "Gender")
        self.set_if_contains("_teacher", "Teacher")

    def set_if_contains(self, attr: str, label: str):
        for key, value in self.row_data.items():
            if label.lower() in key.lower():
                actual_value = value
                break
        else:
            actual_value = None

        setattr(self, attr, actual_value)

    @property
    def ethnicity(self):
        return Ethnicity.objects.get(short_description=self._ethnicity)

    @property
    def gender(self):
        if self._gender[0].lower() == "m":
            return "M"
        else:
            return "F"

    @property
    def teacher(self):
        return Teacher.objects.get(user__last_name=self._teacher)

class ProjectData:
    STUDENT_FIELDS = (
        "first name",
        "last name",
        "ethnicity",
        "gender",
        "teacher",
        "grade",
        "email",
    )

    def __init__(self, **kwargs):
        self.row_data = kwargs
        print(self.row_data)
        self.title = self.row_data["Title"]
        self.abstract = self.row_data.get("Abstract", "")

    @property
    def category(self):
        if "Category" in self.row_data:
            return self.row_data["Category"]
        else:
            return self.subcategory.category

    @property
    def subcategory(self):
        return Subcategory.objects.get(
            short_description__contains=self.row_data["Subcategory"]
        )

    @property
    def division(self):
        return Division.objects.get(short_description=self.row_data["Division"])

    @property
    def students(self) -> Generator[StudentData, None, None]:
        student_list = [None for x in range(0, 4)]
        for key in filter(self.is_student_field, self.row_data):
            number = self.get_student_number_from_key(key)
            try:
                student_list[number][key] = self.row_data[key]
            except TypeError:
                student_list[number] = {key: self.row_data[key]}
        for student_data in student_list:
            if student_data and next(filter(None, student_data.values()), None):
                yield StudentData(**student_data)

    def is_student_field(self, key):
        for label in self.STUDENT_FIELDS:
            if label in key.lower():
                return True
        else:
            return False

    @staticmethod
    def get_student_number_from_key(key):
        return int(list(filter(str.isdigit, key))[0])

def handle_project_import(file_):
    contents = []
    for chu in file_.chunks():
        contents.append(chu.decode())
    contents = "".join(contents).split("\r\n")

    dialect = csv.Sniffer().sniff(contents[0])
    reader = csv.DictReader(contents[1:], dialect=dialect)

    process_project_import(reader)

@transaction.atomic()
def process_project_import(reader, output_stream=None):

    for row in reader:
        project_data = ProjectData(**row)
        project = Project.create(
            project_data.title,
            project_data.abstract,
            project_data.category,
            project_data.subcategory,
            project_data.division,
            output_stream=output_stream,
        )
        if not project:
            continue

        for student_data in project_data.students:
            create_student(
                student_data.first_name,
                student_data.last_name,
                student_data.ethnicity,
                student_data.gender,
                student_data.grade_level,
                project,
                student_data.teacher,
                output_stream=output_stream,
            )

def assign_judges():
    # 1. Assign judges to new projects
    #    1. Search for projects with fewer than the minimum number of judges.
    #    2. For each project:
    #       1. Determine the number of judges the project needs.
    #       2. Search for judges that can judge the project's category and division, sorted by the number of projects
    #          ascending. Get the number of judges needed for the project.
    #       3. Assign the judges to the project

    # 2. Switch projects from judges that have too many projects
    #    1. Count the number of projects in each category division group, the number of judges that can judge that
    #       category and division, and calculate their quotient.
    #    2. Compute the median and average number of projects assigned to all judges.
    #    3. Compute the max of the median, average and minimum number of projects per judge.
    #    4. Search for judges that have more than this number of projects assigned
    #    5. For each judge:
    #       1. Compute the number of projects needed to bring the judge down to the number computed above
    #       2. Get a list of the projects for this judge that don't have any responses.
    #       3. Sort the projects by the quotient computed in step 1.
    #       4. Loop through each project until the necessary number of projects have been removed or there are no
    #          judges available to take the projects.
    #          1. Search for judges that could be assigned the project and sort by number of projects, filtered by
    #             judges that have fewer than the number computed above.
    #          2. Remove the project from the first judge and assign it to the new judge.

    rubric = get_judging_rubric()
    delete_instances_for_inactive_judges(rubric)
    judge_queryset = Judge.objects.filter(user__is_active=True)
    assign_new_projects(rubric, judge_queryset)
    balance_judges(rubric, judge_queryset)

def create_judging_instance(judge, project, rubric):
    return JudgingInstance.objects.create(judge=judge, project=project, rubric=rubric)

def delete_instances_for_inactive_judges(rubric):
    JudgingInstance.objects.filter(
        judge__user__is_active=False, response__rubric=rubric
    ).delete()

def assign_new_projects(rubric, judge_set):
    project_set = Project.objects.annotate(
        num_judges=Count("judginginstance")
    ).order_by("num_judges")

    judge_set = judge_set.annotate(
        num_projects=Count("judginginstance"),
        num_categories=Count("categories"),
        num_divisions=Count("divisions"),
    ).order_by("num_projects", "num_categories", "num_divisions")

    for project in project_set.filter(num_judges__lt=get_minimum_judges_per_project()):
        num_judges = get_minimum_judges_per_project() - project.num_judges
        judges = judge_set.filter(
            categories=project.category, divisions=project.division
        )

        for judge in judges.all():
            judge_projects = [
                ji.project
                for ji in judge.judginginstance_set.select_related("project").all()
            ]
            if project in judge_projects:
                continue
            else:
                # print('Assigning {0} to {1}'.format(project, judge))
                create_judging_instance(judge, project, rubric)
                num_judges -= 1

                if num_judges <= 0:
                    break

def get_minimum_judges_per_project():
    return config.JUDGES_PER_PROJECT

def get_minimum_projects_per_judge():
    return config.PROJECTS_PER_JUDGE

def balance_judges(rubric, judge_queryset):
    quotients = build_quotient_array(judge_queryset)

    judge_set = judge_queryset.annotate(
        num_projects=Count("judginginstance", distinct=True)
    )
    lower_bound = get_project_balancing_lower_bound(judge_set)

    for judge in judge_set.filter(num_projects__gt=lower_bound).order_by(
        "-num_projects"
    ):
        balance_judge(
            judge,
            rubric,
            judge_set.filter(num_projects__lt=lower_bound).order_by("num_projects"),
            lower_bound,
            quotients,
        )

def build_quotient_array(judge_queryset):
    class Quotient(object):
        def __init__(self, num_projects, num_judges):
            self.num_projects = num_projects
            self.num_judges = num_judges

        @property
        def projects_per_judge(self):
            return self.num_projects / self.num_judges

        def __str__(self):
            return "Projects: {0}; Judges: {1}; Quotient: {2}".format(
                self.num_projects, self.num_judges, self.projects_per_judge
            )

        def __repr__(self):
            return self.__str__()

    proj_counts = {
        (d["category"], d["division"]): d["count"]
        for d in Project.objects.values("category", "division").annotate(
            count=Count("category")
        )
    }
    judge_counts = {
        (d["categories"], d["divisions"]): d["count"]
        for d in judge_queryset.values("categories", "divisions").annotate(
            count=Count("categories")
        )
    }

    quotient_array = defaultdict(dict)
    for cat, div in product(Category.objects.all(), Division.objects.all()):
        try:
            num_projects = proj_counts[(cat.pk, div.pk)]
        except KeyError:
            num_projects = 0

        try:
            num_judges = judge_counts[(cat.pk, div.pk)]
        except KeyError:
            num_judges = 0

        quotient_array[cat][div] = Quotient(num_projects, num_judges)

    return quotient_array

def get_project_balancing_lower_bound(judge_set):
    median = get_median_projects_per_judge(judge_set)
    # print('Median: ', median)
    minimum = get_minimum_projects_per_judge()
    # print('Minimum: ', minimum)
    average = judge_set.aggregate(avg_projects=Avg("num_projects"))["avg_projects"]
    # print('Average: ', average)
    return max(median, minimum, average)

def get_median_projects_per_judge(judge_set):
    return median_value(judge_set, "num_projects")

def median_value(queryset, term):
    count = queryset.count()
    values = queryset.values_list(term, flat=True).order_by(term)
    if count % 2 == 1:
        return values[int(round(count / 2))]
    else:
        return sum(values[count / 2 - 1 : count / 2 + 1]) / 2.0

def balance_judge(judge, rubric, possible_judges, lower_bound, quotients):
    # print(judge)
    num_to_reassign = judge.num_projects - lower_bound
    cat_Q = reduce(ior, (Q(categories=cat) for cat in judge.categories.all()))
    div_Q = reduce(ior, (Q(divisions=div) for div in judge.divisions.all()))
    # print(num_to_reassign)

    def sort_value(judging_instance):
        project = judging_instance.project
        return quotients[project.category][project.division].projects_per_judge

    instances = sorted(
        get_instances_that_can_be_reassigned(judge, rubric), key=sort_value
    )
    for ji in instances:
        avail_judge = get_available_judge(ji.project, rubric, possible_judges)
        if avail_judge:
            if reassign_project(ji, avail_judge):
                num_to_reassign -= 1

                # for j in possible_judges.filter(cat_Q, div_Q):
                # print(j, j.num_projects)

                if num_to_reassign <= 0:
                    break
                elif not possible_judges.filter(cat_Q, div_Q).exists():
                    break

def get_instances_that_can_be_reassigned(judge, rubric):
    return judge.judginginstance_set.filter(
        response__rubric=rubric, locked=False
    ).select_related("response", "project")

def get_available_judge(project, rubric, possible_judges):
    for judge in possible_judges.filter(
        categories=project.category, divisions=project.division
    ):
        if judge.judginginstance_set.filter(
            project=project, response__rubric=rubric
        ).exists():
            # The judge has already been assigned this project, so continue
            continue
        else:
            return judge
    return None

@transaction.atomic()
def reassign_project(judging_instance, to_judge):
    # print("Reassigning {0} from {1} to {2}".format(judging_instance.project.number, judging_instance.judge, to_judge))
    new_instance = create_judging_instance(
        to_judge, judging_instance.project, judging_instance.response.rubric
    )
    judging_instance.delete()
    return new_instance

def email_teachers(site_name, domain, use_https=False):
    messages = []
    context = {
        "domain": domain,
        "site_name": site_name,
        "protocol": "https" if use_https else "http",
    }
    for teacher in get_teachers():
        context.update(
            {
                "email": teacher.email,
                "uid": urlsafe_base64_encode(force_bytes(teacher.pk)),
                "user": teacher,
                "token": default_token_generator.make_token(teacher),
            }
        )

        subject = render_to_string(
            "fair_projects/email/teacher_signup_subject.txt", context
        )
        # Email subject *must not* contain newlines
        subject = "".join(subject.splitlines())

        body = render_to_string("fair_projects/email/teacher_signup.txt", context)
        html_email = render_to_string(
            "fair_projects/email/teacher_signup.html", context
        )

        email_message = EmailMultiAlternatives(subject, body, to=[teacher.email])
        email_message.attach_alternative(html_email, "text/html")

        messages.append(email_message)

    with get_connection() as connection:
        connection.send_messages(messages)

def get_teachers():
    for teacher in Teacher.objects.select_related("user").all():
        if teacher.user.is_superuser:
            continue

        yield teacher.user

def get_projects_sorted_by_score() -> list:
    def sort_func(project: Project):
        return (
            (project.average_score() * -1, project.num_scores() * -1),
            project.number,
        )

    project_list = list(Project.objects.all())
    project_list.sort(key=sort_func)
    return project_list

def mass_email(
    targets: list, subject_template: str, text_template: str, html_template: str
):
    messages = []
    for email, context in targets:
        subject = render_to_string(subject_template, context)
        # Email subject *must not* contain newlines
        subject = "".join(subject.splitlines())

        body = render_to_string(text_template, context)
        html_email = render_to_string(html_template, context)

        email_message = EmailMultiAlternatives(subject, body, to=[email])
        email_message.attach_alternative(html_email, "text/html")

        messages.append(email_message)

    with get_connection() as connection:
        connection.send_messages(messages)

def get_question_feedback_dict(project: Project) -> dict:
    judging_instances = (
        JudgingInstance.objects.filter(project=project).select_related("response").all()
    )
    rubric_responses = [instance.response for instance in judging_instances]
    question_responses = (
        QuestionResponse.objects.filter(rubric_response__in=rubric_responses)
        .select_related("question")
        .order_by("question__short_description")
        .all()
    )
    question_responses = filter(
        lambda x: x.rubric_response.has_response, question_responses
    )
    question_responses = groupby(
        question_responses, lambda x: x.question.short_description
    )
    question_dict = {
        key: FeedbackQuestion(list(responses)) for key, responses in question_responses
    }

    return question_dict

class FeedbackQuestion:
    def __init__(self, responses):
        self.question = responses[0].question
        self.responses = responses

    def short_description(self):
        return self.question.short_description

    def long_description(self):
        return self.question.long_description

    def description(self):
        return self.question.description()

    def response_list(self):
        return [resp.response for resp in self.responses]

    def response_list_remove_empty(self):
        return list(filter(None, self.response_list()))

    def combined_response_set(self):
        return self._combine_responses(self.response_list())

    @staticmethod
    def _combine_responses(list_to_combine):
        combined_set = set()
        for resp in list_to_combine:
            if not resp:
                continue
            elif hasattr(resp, "__iter__"):
                combined_set.update(resp)
            else:
                combined_set.add(resp)
        return combined_set

    def response_list_external(self):
        return [resp.response_external() for resp in self.responses]

    def response_list_external_remove_empty(self):
        return list(filter(None, self.response_list_external()))

    def combined_response_set_external(self):
        return self._combine_responses(self.response_list_external())

    def score_list(self):
        return [resp.score() for resp in self.responses]

    def score_list_remove_empty(self):
        return list(filter(None, self.score_list()))

    def unweighted_score_list(self):
        return [resp.unweighted_score() for resp in self.responses]

    def average_score(self):
        return self._compute_average(self.score_list())

    def average_score_remove_empty(self):
        return self._compute_average(self.score_list_remove_empty())

    def average_score_unweighted(self):
        return self._compute_average(self.unweighted_score_list())

    @staticmethod
    def _compute_average(scores):
        try:
            return sum(scores) / len(scores)
        except TypeError:
            return None

    def __str__(self):
        return "{0} responses".format(len(self.responses))


from data_preprocessing.kaggle_eyepacs_preprocess import KagglePreprocess
from utils.utils import get_args
from utils.config import process_config
from pathlib import Path
import glob
import os
import cv2 as cv
from concurrent.futures import ProcessPoolExecutor
from multiprocessing import cpu_count
import math

def preprocess_and_write(dest, image_path, class_num, numOfBlurred=1):
    # Create KagglePreprocess instance
    kaggle_preprocessor = KagglePreprocess()
    # read image in color mode
    image = cv.imread(image_path, 1)
    # preprocess image
    new_image = kaggle_preprocessor.preprocess(image, numOfBlurred=numOfBlurred)
    # determite new filepath
    new_image_filepath = os.path.join(dest, str(class_num), os.path.basename(image_path))
    # save new image
    cv.imwrite(new_image_filepath, new_image)

def chunked_worker(input_tuple):
    dest = input_tuple[0]
    img_file_list = input_tuple[1]
    class_num = input_tuple[2]
    numOfBlurred = input_tuple[3]
    [preprocess_and_write(dest, img, class_num, numOfBlurred) for img in img_file_list]
    return 0

def call_multi_executor(images, write_dir, class_num, max_workers=4, numOfBlurred=1):
    with ProcessPoolExecutor(max_workers=max_workers) as executor:
        chunksize = int(math.ceil(len(images) / float(max_workers)))
        for i in range(max_workers):
            images_chuck = images[(chunksize * i) : (chunksize * (i + 1))]
            executor_input_tuple = (write_dir, images_chuck, class_num, numOfBlurred)
            executor.submit(chunked_worker, executor_input_tuple)

def main():
    # capture the config path from the run arguments
    # then process the json configuration file
    try:
        args = get_args()
        config = process_config(args.config, False, False)
    except Exception as e:
        print(e)
        print("missing or invalid arguments")
        exit(0)

    # Classes to search (e.g. if there are 5 folders for each class named by the number of the class, then classes = [0,1,2,3,4])
    classes = config.dataset.classes

    # Directory to read training set
    train_dir = config.dataset.train

    # Directory to read testing set
    test_dir = config.dataset.test

    # How many blurred images
    numOfBlurred = config.preprocessing.numOfBlurred

    # Max multiprocessing workers
    workers = config.multiprocess.workers

    # Directory to write training set
    train_dest = config.dataset.train_dest
    Path(train_dest).mkdir(parents=True, exist_ok=False)

    # Directory to write testing set
    test_dest = config.dataset.test_dest
    Path(test_dest).mkdir(parents=True, exist_ok=False)

    # ####################### #
    # Iterate through classes #
    # ####################### #
    for class_num in classes:
        # ####################### #
        # Preprocess training set #
        # ####################### #
        # Create destination folder for each class
        Path(os.path.join(train_dest,str(class_num))).mkdir(parents=True, exist_ok=False)
        # Determine training images' paths
        train_images = glob.glob(os.path.join(train_dir, str(class_num), '*.jpeg'))
        # Preprocess images on several processors
        call_multi_executor(train_images, train_dest, class_num, max_workers=workers, numOfBlurred=numOfBlurred)

        # ###################### #
        # Preprocess testing set #
        # ###################### #
        # Create destination folder for each class
        Path(os.path.join(test_dest,str(class_num))).mkdir(parents=True, exist_ok=False)
        # Determine testing images' paths
        test_images = glob.glob(os.path.join(test_dir, str(class_num), '*.jpeg'))
        # Iterate through the images
        call_multi_executor(test_images, test_dest, class_num, max_workers=workers, numOfBlurred=numOfBlurred)

if __name__ == '__main__':
    main()


import matplotlib
import numpy as np
import sys
from collections import defaultdict
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import random
from matplotlib import cm, rc
import pickle

DEALER_RANGE = range(1, 11)
PLAYER_RANGE = range(1, 22)
ACTIONS = (HIT, STICK) = (0, 1)

class State:
    dealercard = random.randint(1,10)
    playersum = random.randint(1,10)

def mse(A, B):
    return np.sum((A - B) ** 2) / np.size(A)

Q_DUMP_BASE_NAME = "Q_dump"
def dump_Q(Q, num_episode):
    filename = ("./{}_episodes_{}.pkl"
              "".format(Q_DUMP_BASE_NAME,num_episode))

    print("dumping Q: ", filename)

    with open(filename, "wb") as f:
        pickle.dump(Q, f)

def create_surf_plot(X, Y, Z, fig_idx=1):
    fig = plt.figure(fig_idx)
    ax = fig.add_subplot(111, projection="3d")
    #print("X,Y,Z:",X,Y,Z)

    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,linewidth=0, antialiased=False)
    #surf = ax.plot_wireframe(X, Y, Z)

    return surf

def plot_V(Q, save=None, fig_idx=0):
    #print("Q value:",Q)
    V = np.max(Q, axis=2)
    X, Y = np.mgrid[DEALER_RANGE,PLAYER_RANGE]

    surf = create_surf_plot(X, Y, V)

    #print("end cread_surf_plot")

    plt.title("V*")
    plt.ylabel('player sum', size=18)
    plt.xlabel('dealer', size=18)

    if save is not None:
        plt.savefig(save, format='pdf', transparent=True)
    else:
        plt.show()

    plt.clf()

def plot_learning_curve(learning_curves, save=None, agent_args={}, fig_idx=2):

    fig = plt.figure(fig_idx)

    plt.title("Mean-squared error vs. 'true' Q values against episode number")
    plt.ylabel(r'$\frac{1}{|S||A|}\sum_{s,a}{(Q(s,a) - Q^{*}(s,a))^2}$', size=18)
    plt.xlabel(r'$episode$', size=18)

    colors = iter(cm.rainbow(np.linspace(0, 1, len(learning_curves))))
    for lmbd, D in learning_curves.items():
        X, Y = zip(*D)
        plt.plot(X, Y, label="lambda={:.1f}".format(lmbd),
                 linewidth=1.0, color=next(colors))

    plt.legend()

    if save is not None:
        plt.savefig(save, format='pdf', transparent=True)
    else:
        plt.show()

    plt.clf()

#draw one card black or red
def Drawcard(current):
    #add black color 2/3 pros;subtract red color 1/3
    if random.randint(1,3) < 3:
        current += random.randint(1,10)
    else:
        current -= random.randint(1,10)
    return current

# action {0: stick, 1: hit}
# return reward and next state
def Step(state,action):
    state_next = State()
    if action == 1:
        state_next.playersum = Drawcard(state.playersum)
        state_next.dealercard = state.dealercard
        if state_next.playersum < 1 or state_next.playersum > 21:
            return "terminal",-1.0
        else:
            return state_next,0
    elif action == 0:#dealer's turn
        dealercardsum = state.dealercard
        while(dealercardsum < 17):
            dealercardsum = Drawcard(dealercardsum)
            if dealercardsum < 1 or dealercardsum > 21:
                return "terminal", 1.0
        if dealercardsum > state.playersum:
            return "terminal", -1.0
        elif dealercardsum < state.playersum:
            return "terminal", 1.0
        else:
            return "terminal", 0.0

# Base on epsilon-policy,number of action and Q value table, return the action.
def Epsilon_greedy_policy(value,counter,state):
    #get the time-varying epsilon, N_0 = 100.0
    #print("state in Policy:",state.dealercard-1,state.playersum-1)
    epsilon = 100.0 / (100.0 + np.sum(counter[state.dealercard-1, state.playersum-1,:],axis=0))
    #the possibility to choose random
    if (random.random() < epsilon):
        action = random.randint(0,1)
    else:#greedy choose
        action = np.argmax(value[state.dealercard-1, state.playersum-1,:])

    return action

# An episode is an array of (state, action, reward) tuples
def Generate_epsiode(value,counter):
    epsiode = []
    # initialize the fisrt State
    state = State()
    #make sure the start state is different every time
    state.dealercard = random.randint(1,10)
    state.playersum = random.randint(1,10)
    totalreward = 0

    while state != "terminal":
        #print("state in Generate_epsiode:",state.dealercard-1,state.playersum-1)
        action = Epsilon_greedy_policy(value,counter,state)
        counter[state.dealercard-1, state.playersum-1,action] += 1
        epsiode.append((state.dealercard, state.playersum,action))
        state,reward= Step(state,action)
        totalreward += reward

    return epsiode,totalreward

# Based on article 5 on-policy  MC Control algorithm-Incremental Implementation


import pytest
from django.urls import reverse
from faker import Faker
from model_bakery import baker
from rest_framework import status

from mycarehub.clients.models import Client
from mycarehub.users.models import GenderChoices

fake = Faker()
pytestmark = pytest.mark.django_db

def test_client_list(user_with_all_permissions, client):
    client.force_login(user_with_all_permissions)
    url = reverse("api:clients-general")
    baker.make(Client)

    response = client.get(
        url,
        content_type="application/json",
        accept="application/json",
    )

    assert response.status_code == status.HTTP_200_OK

    response_data = response.json()
    assert len(response_data) > 0

def test_client_registration(user_with_all_permissions, client):
    client.force_login(user_with_all_permissions)
    url = reverse("api:clients-general")
    org = user_with_all_permissions.organisation
    program = user_with_all_permissions.program

    response = client.post(
        url,
        data={
            "client_id": fake.uuid4(),
            "name": fake.name(),
            "organisation_id": org.id,
            "program_id": program.id,
            "gender": GenderChoices.MALE,
            "date_of_birth": fake.date_of_birth(minimum_age=18),
        },
        content_type="application/json",
        accept="application/json",
    )

    assert response.status_code == status.HTTP_201_CREATED

    response_data = response.json()
    assert response_data["id"] is not None

def test_client_registration_invalid_input(user_with_all_permissions, client):
    client.force_login(user_with_all_permissions)
    url = reverse("api:clients-general")

    response = client.post(
        url,
        data={
            "name": fake.name(),
        },
        content_type="application/json",
        accept="application/json",
    )

    assert response.status_code == status.HTTP_400_BAD_REQUEST

def test_client_remove(user_with_all_permissions, client):
    client.force_login(user_with_all_permissions)
    user = baker.make(Client)
    url = reverse("api:clients-detail", kwargs={"pk": user.pk})
    response = client.delete(
        url,
        content_type="application/json",
        accept="application/json",
    )

    assert response.status_code == status.HTTP_204_NO_CONTENT


from skimage import io
from sklearn.cluster import KMeans
import numpy as np

image = io.imread('scenery.png')
io.imshow(image)
io.show()

rows = image.shape[0]
cols = image.shape[1]
hi = image.shape[2]

print(rows, cols)
clusters = int(input("Enter number of clusters"))

image = (image / 255.0).reshape(rows * cols, 3)
kmeans = KMeans(n_clusters = clusters)
kmeans.fit(image)

compressed_image = kmeans.cluster_centers_[kmeans.labels_]

compressed_image = compressed_image.reshape(rows, cols, hi);

io.imsave('compressed_scenery.png', compressed_image)


import sys
import psutil
import notify2
import time
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QAction
import threading
import images_rc

class MyProcess(QThread):
    def __init__(self, parent = None):
        QThread.__init__(self, parent)
    def run(self):
        while True:
            notify2.init("Battery Alerts")
            battery = psutil.sensors_battery()
            plugged = battery.power_plugged
            percent = str(round(battery.percent))
            msg = ""
            if plugged == False and int(percent) < 80:
                msg = "Charge is only " + percent + "% please charge the laptop now!!!"
                n = notify2.Notification("Battery is too low!", message=msg)
                n.set_urgency(notify2.URGENCY_CRITICAL)
                n.show()
            time.sleep(60)
        return
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
    def __init__(self, icon, parent=None):
        super(SystemTrayIcon, self).__init__(icon, parent)
        menu = QtWidgets.QMenu(parent)

        exitAction= QAction("&Quit", self,triggered=QtWidgets.QApplication.instance().quit)
        exitAction.setIcon(QtGui.QIcon('images/exit.png'))
        exitAction.triggered.connect(parent.close)
        menu.addAction(exitAction)
        self.setContextMenu(menu)

class windows(QtWidgets.QWidget):
    def __init__(self):
        super(windows, self).__init__()
        self.trayicon = SystemTrayIcon(QtGui.QIcon('images/bat.png'), self)
        self.trayicon.show()
        thread1 = MyProcess(self)
        thread1.start()
if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    window = windows()
    window.setWindowTitle("Low Battery Notification")
    QtWidgets.QApplication.setQuitOnLastWindowClosed(False)
    sys.exit(app.exec_())


# Platform: HackerRank
# Problem: https://www.hackerrank.com/challenges/word-order/problem
# Language: Python3
# Difficulty: Moderate

# Enter your code here. Read input from STDIN. Print output to STDOUT
from collections import Counter

if __name__ == "__main__":
    n = int(input())
    words = [input().replace("\n", "") for _ in range(n)]
    print(len(set(words))) # Unique occurences
    print(" ".join(str(i) for i in Counter(words).values())) # Count of each word


# Ex. 8.7 Album
# Create a function called make_album() responsible for building a dictionary representing a music album. The function
# should retrieve the band or artist name and album title. The function's return value should be a dictionary containing
# these two bits of information. Using the prepared function, create three dictionaries representing different albums.
# Display each return value to show that the dictionaries correctly store album information.
# Using the special value None, add an optional parameter to the make_album() function to store the number of songs on
# the album. If the function call contains a value for the number of songs, add it to the album information dictionary.
# Define at least one new function call that also includes the number of songs on the album.

def make_album(artist, title, numer_of_songs=None):
    """Displays album information."""
    album = {'artist': artist, 'title': title}
    if numer_of_songs:
        album['number_of_songs'] = numer_of_songs
    return album

album_1 = make_album('three days grace', 'life starts now', 12)
album_2 = make_album('metallica', 'metallica', 12)
album_3 = make_album('system of a down', 'toxicity')

print(album_1)
print(album_2)
print(album_3)


from django.urls import path

from . import views

app_name = 'medicines'

urlpatterns = [
    path('', views.ListCreateView.as_view(), name='list'),
    path('<pk>/', views.EditView.as_view(), name='detail'),
    path('<pk>/delete/', views.DeleteView.as_view(), name='delete'),
]


from __future__ import print_function

import numpy as np
import scipy.ndimage as simage
import astropy.io.fits as fits
import astropy.stats as astats
import math as mt
from .instrument import Instrument
#import astropysics.ccd as ccd
import photutils as pu
#import skimage as skim
#from skimage.transform import hough_circle
#from skimage.util import img_as_ubyte
from . import darkbias
from . import flatfield
#from image_registration.register_images import register_images
#from skimage.feature import peak_local_max, canny
import matplotlib.pyplot as plt
import matplotlib.colors as cols
from astropy.convolution import interpolate_replace_nans, Gaussian2DKernel
#import skimage.transform as tf
import pickle
import os
import datetime
from .__init__ import __version__ #hack, replace later

#print(__version__)
eso_fits_keywords = ["ORIGIN",
                     "DATE",
                     "TELESCOP",
                     "INSTRUME",
                     "OBJECT",
                     "RA",
                     "DEC",
                     "EQUINOX",
                     "RADECSYS",
                     #EXPTIME
                     #MJD-OBS
                     #DATE-OBS
                     #UTC
                     #LST
                     "ESO DPR CATG",
                     "ESO DPR TECH",
                     "ESO DPR TYPE",
                     "ESO INS COMB ICOR",
                     "ESO INS COMB IFLT",
                     "ESO INS COMB POLA",
                     "ESO INS COMB VCOR",
                     "ESO INS DATE",
                     "ESO INS1 FILT ID",
                     "ESO INS1 FILT NAME",
                     "ESO INS1 FILT NO",
                     "ESO INS1 ID",
                     "ESO INS1 MODE",
                     "ESO INS1 OPTI1 ID",
                     "ESO INS1 OPTI1 NAME",
                     "ESO INS1 OPTI1 NO",
                     "ESO INS1 OPTI1 TYPE",
                     "ESO INS1 OPTI2 ID",
                     "ESO INS1 OPTI2 NAME",
                     "ESO INS1 OPTI2 NO",
                     "ESO INS1 OPTI2 TYPE",
                     "ESO OBS ID",
                     "ESO OBS NAME",
                     "ESO OBS NTPL",
                     "ESO OBS PROG ID",
                     "ESO OBS START",
                     "ESO SEQ ARM",
                     "ESO SEQ CORO CPI_ND",
                     "ESO SEQ CORO DATE",
                     "ESO SEQ CORO XC",
                     "ESO SEQ CORO YC",
                     "ESO TEL ALT",
                     "ESO TEL AMBI RHUM",
                     "ESO TEL AMBI TAU0",
                     "ESO TEL AMBI TEMP",
                     "ESO TEL AMBI WINDDIR",
                     "ESO TEL AMBI WINDSP",
                     "ESO TEL AZ",
                     "ESO TEL DATE",
                     "ESO TEL DID",
                     "ESO TEL GEOELEV",
                     "ESO TEL GEOLAT",
                     "ESO TEL GEOLON",
                     "ESO TEL IA FWHM",
                     "ESO TEL IA FWHMLIN",
                     "ESO TEL IA FWHMLINOBS",
                     "ESO TEL ID",
                     "ESO TEL MOON DEC",
                     "ESO TEL MOON RA",
                     "ESO TEL OPER",
                     "ESO TEL TARG ALPHA",
                     "ESO TEL TARG COORDTYPE",
                     "ESO TEL TARG DELTA",
                     "ESO TEL TARG EPOCH",
                     "ESO TEL TARG EPOCHSYSTEM",
                     "ESO TEL TARG EQUINOX",
                     "ESO TEL TARG PARALLAX",
                     "ESO TEL TARG PMA",
                     "ESO TEL TARG PMD",
                     "ESO TEL TARG RADVEL",
                     "ESO TEL TH M1 TEMP",
                     "ESO TEL TRAK STATUS",
                     "ESO TPL DID",
                     "ESO TPL EXPNO",
                     "ESO TPL ID",
                     "ESO TPL NAME",
                     "ESO TPL NEXP",
                     "ESO TPL PRESEQ",
                     "ESO TPL START",
                     "ESO TPL VERSION",
                     "PIXSCAL"
                     #ARCFILE

                     ]

#need a list of filters, conoragraphs, etc
class Irdis(Instrument):
    def __init__(self, observation,#,scifiles=None,badpixfile=None,skyfiles=None,
                 #flatfiles=None,darkfiles=None,mode=None,optics=None,
                 options=None, interProd=False,prefix="", **kwargs):
        self.__version__ = __version__
        self.science=observation.obs_main
        self.datadir=observation.datadir
        self.mode=observation.obs_type
        self.prefix=prefix
        self.darks=observation.cals['IRD_DARK']
        if 'CLI' in self.mode:
            self.flats=observation.cals['IRD_CLI_FLAT']
            try:
                self.sky=observation.cals['IRD_SCI_CLI_SKY']  #or does this need to be 'IRD_SKY_BG_RAW'? #Sky
            except KeyError:
                try:
                    self.sky=observation.cals['IRD_SKY_BG_RAW']  #or does this need to be 'IRD_SKY_BG_RAW'? #Sky
                except KeyError:
                    print("No sky frame found. Please check your association tree contains all required calibrations")
                    print("Do not continue with reduction!")
                    #return
        elif 'DBI' in self.mode:
            self.flats=observation.cals['IRD_DBI_FLAT']
            try:
                self.sky=observation.cals['IRD_SCI_CLI_SKY']  #or does this need to be 'IRD_SKY_BG_RAW'? #Sky
            except KeyError:
                try:
                    self.sky=observation.cals['IRD_SKY_BG_RAW']  #or does this need to be 'IRD_SKY_BG_RAW'? #Sky
                except KeyError:
                    print("No sky frame found. Please check your association tree contains all required calibrations")
                    print("Do not continue with reduction!")
                    #return

        try:
            self.flux=observation.cals['IRD_FLUX_CALIB_CORO_RAW'] #flux
        except KeyError:
            self.flux=None #flux observations were not taken (e.g. this may be a reference psf)
#        self.scifiles=scifiles
#        self.badpixfile=badpixfile
#        self.skyfiles=skyfiles
#        self.flatfiles=flatfiles
#        self.flatcals
#        self.darkfiles=darkfiles
#        self.mode=mode
#        self.optics=optics
        self.options=options
        self.interProd=interProd #write out intermediate products? (master dark, etc)
        #calibration angles
        self.pupilOffset=-135.99 #Pupil offset angle
        self.tn=-1.764 #True North offset
        #astrometric calibration numbers - probably won't use these and just say that pipeline is not suitable for high-precision astrometry
        self.plateScale=12.251 #IRDIS plate scale (after distortion correction) of irdis detector
        self.Anamorph=1.0062 #anamophic distortion multiplier for Y direction of detector
        self.logfile = open(str(datetime.datetime.now()).split(' ')[0]+"_"+prefix+"_precision.log",'wb+')

    def __repr__(self):
        return "<IRDIS mode: %s science data: %s sky: %s flux: %s flats: %s darks: %s options: %s>" % (self.mode, self.science, self.sky, self.flux, self.flats, self.darks)

    def __str__(self):
        return "IRDIS mode: %s science data: %s sky: %s flux: %s flats: %s darks: %s options: %s" % (self.mode, self.science, self.sky, self.flux, self.flats, self.darks, self.options)

    def findSources(self,sourcefinder,data,window,guess,median,interact=True,**kwargs):
        sources=sourcefinder.find_stars(data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
                                              np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median)
        sources.sort('flux')
        if interact:
            sources.pprint(max_lines=-1)
            plt.imshow(data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
                            np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median,
                       origin='lower')
            plt.show(block=False)
            try:
                a=raw_input('What is the ID of the source at the centre of rotation?\n')
            except NameError:
                a=input('What is the ID of the source at the centre of rotation?\n')
            plt.close()
            if int(a) < 0:
                sources,new_window=self.findSources(sourcefinder,data,int(1.5*window),guess,median)
            else:
                b=(sources['id'] == int(a))
                return sources[:][b],window
        return sources,window#sources

    def findcentre(self,data,guess,interact=True,window=60,**kwargs):
        print(data.shape,guess)
        print(np.int(guess[0]))
        print(np.int(np.ceil(guess[1])))
        #help(np.int(np.ceil(guess[1])) + window)
        #help(data)
        mean,median,std=astats.sigma_clipped_stats(data,sigma=3.0)
        sourcefinders=pu.DAOStarFinder( #data[500:550,450:500] - median, # assumes datacube #[500:550,450:500]
                           fwhm = 2.0,
                           threshold=std#,
                           #sharplo=0.3,
                           #sharphi=0.5,
                           #roundhi=0.3,
                           #roundlo=-0.3
                           )
        #sources
        #b=
        self.central,new_window=self.findSources(sourcefinders,data,window,guess,median,interact)
#        sources.sort('flux')#'peak') #take brightest source
        #try making this interactive?
        #if interact:
#            print sources
        #    sources.pprint(max_lines=-1)
        #    plt.imshow(data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
        #                    np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median)
        #    plt.show(block=False)
            #try:
        #    a=raw_input('What is the ID of the source at the centre of rotation?\n')
            #except ValueError:
        #    if int(a) < 0:
        #        sources=self.findSources(sourcefinders,data,int(1.5*window),guess,median)
        #        sources.pprint(max_lines=-1)
        #        plt.imshow(data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
        #                        np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median)
        #        plt.show(block=False)
                #try:
        #        a=raw_input('What is the ID of the source at the centre of rotation?\n')
                #            print a,sources.dtype
        #    b=(sources['id'] == int(a))
#            print b
#            print sources[b]
            #try:
                #self.central.append(sources[:][b])
            #except:
        #self.central=sources[:][b]
        #    plt.close()
        #try:
        #    self.central=sources[:][-1]
        #except:
        #    self.central=sources
#        self.central=central
        #self.sources=sources
        #return central,sources
        #print
        self.centre=np.array([self.central['xcentroid'].data+(np.int(guess[1])-new_window),self.central['ycentroid'].data+(np.int(guess[0])-new_window)])
#        pass
        #how on earth do I do this? try finding the coronagraph?
        #in case of ALC look for central spot using photutils
        #else use scikit-image to find circles for CLC
 #       tempimg=img_as_byte(frame)
 #       edges=canny(tempimg)
 #       hough_radii=1 #needs to depend on coronagraph choice
 #       hough_res=hough_circle(edges,hough_radii)
        #now need to use info to align both cubes
        #return centres of circles

    def splitchannels(self,data,**kwargs):
        #call this after dark/flat/sky correction and centre finding but before anything else - will probably end up most used...
        return data[:,:,0:1024],data[:,:,1024:2048]

    def derotate(self,data,angle,**kwargs):
        """ Function to derotate images. Assumes images are already centred """
        #derotate
        return simage.interpolation.rotate(data,angle,reshape=False)

    def CI(self,**kwargs): #test on VY CMa
        print("Combining images for CI")
        self.finalNoDerot=np.mean(self.medianNoDerot,axis=0) #take median of all images at each pixel
        #self.finalvarNoDerot=np.mean(self.varNoDerot,axis=0)         #small number approximation -
        self.finalvarNoDerot=(np.mean(self.varNoDerot,axis=0) / #variance on mean = mean of variances / N
                              (self.varNoDerot.shape[0]))#(2*self.varNoDerot.shape[0]))          #or alternatively
                                                                     #uncertainty on mean = mean of uncertainties / sqrt(N)
        #need to fix uncertainty tracking...current version should underestimate variances, only alteratives (apart from MC) appear to overestimate them
        if self.rot=='PUPIL':
            self.finalDerot=np.mean(self.medianDerot,axis=0) #take median of all derotated images at each pixel
            #self.finalVarDerot=np.mean(self.varDerot,axis=0)         #small number approximation -
            self.finalVarDerot=(np.mean(self.varDerot,axis=0) / #variance on mean = mean of variances / N
                                  (self.varDerot.shape[0]))          #or alternatively
        return

    def SDI(self,**kwargs): #test on GD50, VY CMa
        self.CI()
        print("Combining images for SDI")
        self.SDINoDerot=np.mean(self.medianNoDerot,axis=0) #produces L- and R- channel images
        self.SDINoDerot=self.SDINoDerot[1]-self.SDINoDerot[0] #check which way round this is supposed to be! and scaling!

        self.varSDINoDerot=np.mean(self.varNoDerot,axis=0) / self.varNoDerot.shape[0]
        self.varSDINoDerot=np.sum(self.varSDINoDerot, axis=0)

        if self.rot=='PUPIL':
            self.SDIDerot=np.mean(self.medianDerot,axis=0)
            self.SDIDerot=self.SDIDerot[1]-self.SDIDerot[0]
            self.varSDIDerot=np.mean(self.varDerot,axis=0) / self.varDerot.shape[0]
            self.varSDIDerot=np.sum(self.varSDIDerot,axis=0)
        return

    def ADI(self,**kwargs): #test on GD50
        """ This method perfoms classical ADI by taking the median non-derotated frame and subtracting it from each non-derotated frame. It then derotates all frames and collapses the whole cube """
        self.medianADI=np.array([])
        self.varADI=np.array([])
        isci=0
        for f in self.scifiles:
            #read data
            data,header=self.readdata(f)
            data=self.badpixcorrect(data)
            data=self.skysub(data,self.mastersky)
            #undither data
            data=simage.interpolation.shift(data,[header['HIERARCH ESO INS1 DITH POSX'], #check sign
                                                  header['HIERARCH ESO INS1 DITH POSY'] #of shifts
                                                  ]
                                            )
            #split channels and align
            datal,datar=self.splitchannels(data)
            #Centres were found before by CI algorithm, so shift each cube
            datal=simage.interpolation.shift(datal,
                                             np.array([0,
                                                       self.shiftl[isci][1][0],
                                                       self.shiftl[isci][0][0]
                                             ])
            )
            datar=simage.interpolation.shift(datar,
                                             np.array([0,
                                                       self.shiftr[isci][1][0],
                                                       self.shiftr[isci][0][0]
                                             ])
            )
            #subtract speckle image (non-derotated median frames)
            datal=datal-self.finalNoDerot
            datar=datar-self.finalNoDerot
            #derotate channels
            #then calculate rotation as a function of time
            self.parang=[header['HIERARCH ESO TEL PARANG START'],header['HIERARCH ESO TEL PARANG START']]
            self.pdelt=(self.parang[1]-self.parang[0])/data.shape[0]
            for i in range(data.shape[0]):
                angle=-1.*self.parang[0]-self.parangInit + (i+0.5)*self.pdelt #rotation angle at centre of exposure relative to beginning of entire sequence - add absolute rotations as well!
                    #then derotate each frame of each half of the detector
                datal[i,:,:]=self.derotate(datal[i,:,:],angle)

            #then calculate rotation as a function of time
            self.parang=[header['HIERARCH ESO TEL PARANG START'],header['HIERARCH ESO TEL PARANG START']]
            self.pdelt=(self.parang[1]-self.parang[0])/data.shape[0]
            for i in range(data.shape[0]):
                angle=-1.*self.parang[0]-self.parangInit + (i+0.5)*self.pdelt #rotation angle at centre of exposure relative to beginning of entire sequence - add absolute rotations as well!
                    #then derotate each frame of each half of the detector
                datar[i,:,:]=self.derotate(datar[i,:,:],angle)
            #now build ADI medians for each dither position
            try:
                self.medianADI=np.r_[self.medianADI,
                                     [np.nanmedian(datal,axis=0),np.nanmedian(datar,axis=0)]
                ]
                self.varADI=np.r_[self.varADI,
                                  [(np.pi/(2.*datal.shape[0]))*(np.std(datal,axis=0))**2,
                                   (np.pi/(2.*datar.shape[0]))*(np.std(datar,axis=0))**2
                                  ]
                ]
            except:
                self.medianADI=np.array([np.nanmedian(datal,axis=0),np.nanmedian(datar,axis=0)])
                self.varADI = np.array(
                                       [
                                           (np.pi/(2.*datal.shape[0]))*(np.std(datal,axis=0))**2,
                                           (np.pi/(2.*datar.shape[0]))*(np.std(datar,axis=0))**2
                                        ]
                                       )
            isci+=1
        #average all frames ('cADI')
        self.finalADI=np.mean(self.medianADI,axis=0) #produces L- and R- channel images and combines
        #self.finalADI=np.mean(self.finalADI,axis=0) #combine both channels
        #self.finalVarADI=np.mean(self.varADI,axis=0)         #small number approximation -
        self.finalVarADI=(np.mean(self.varADI,axis=0) / #variance on mean = mean of variances / N
                            (self.varADI.shape[0]))

        if mode=='SDI':
            self.finalSADI=np.mean(self.medianSADI[0:-1:2,:,:],axis=0) - np.mean(self.medianSADI[1::2,:,:],axis=0)    #produces L- and R- channel images and subtracts them
            #self.finalSADI=self.finalSADI[1]-self.finalSADI[0]#
            self.finalVarSADI=np.mean(self.varSADI,axis=0)    #small number approximation -
            self.finalVarSADI=np.sum(self.finalVarSADI,axis=0)#variance on mean = mean of variances / N
        pass

    def LOCI(self,**kwargs):
        raise NotImplementedError("LOCI is not implemented yet.")#        pass

    def DPI(self,**kwargs): #test on HR 3090
        self.CI()

        #split L and R channels into O- and E-rays respectively
        self.MeanOray=np.mean(self.medianNoDerot[:,0,:,:],axis=0) #add an additional axis for DPI observations, so that it contains [+Q, -Q, +U, -U] or as many as are available
        self.MeanEray=np.mean(self.medianNoDerot[:,1,:,:],axis=0)# self.splitchannels()

        #calculate Stokes parameter(s) the old fashioned way
        #concatenate channels and collapse for I
        self.I=self.MeanOray + self.MeanEray

        #O - E for Q/U
        self.pol=self.MeanOray - self.MeanEray #this all needs updating to enable it to process an entire DPI observation, correctly interpreting what combinations of +/- Q/U to do

        #if double difference, do +Q - -Q

        #compute fractional pol

        #do ratio method too

        pass

    def makesky(self,**kwargs):
        print(self.sky)
        if len(self.sky.obs_main) == 1:
            f=self.sky.datadir+self.sky.obs_main[0][:][1]+'.fits'
            data,header=self.readdata(f)
            data=self.badpixcorrect(data)
            self.skyframes=data
        else:
            for f in self.sky.obs_main[0][:][1]:
                f=self.sky.datadir+f+'.fits'
                data,header=self.readdata(f)
                data=self.badpixcorrect(data)
                self.skyframes=np.r_[self.skyframes,data]
        #now median combine all sky frames
        if (len(self.skyframes.shape) == 3):
            self.mastersky=np.nanmedian(self.skyframes,axis=0)
            self.skyvar=(np.pi/(2.*self.skyframes.shape[0]))*(np.std(self.skyframes,axis=0))**2
            self.skyfiles=None
        else:
            self.mastersky=self.skyframes
            self.skyvar=self.mastersky
        pass

    def reduce(self,**kwargs):
        self.status=0
        if self.darks is not None:
            self.masterdark,self.darkvar,self.RON=darkbias.makemasterdark(self.darks,**kwargs)
        else:
            self.masterdark=None

        if self.flats is not None:
            self.masterflat,self.flatvar,self.badpixmap=flatfield.makemasterflat(self.flats,**kwargs)#,self.masterdark,**kwargs)
        else:
            self.masterflat=None
        if self.sky is not None:
            self.makesky()
        if self.flux is not None:
            self.sciFlux()
            #exit()

        #print np.sum(np.isnan(self.mastersky))
        self.medianNoDerot=np.array([])
        self.medianDerot=np.array([])
        self.varNoDerot=np.array([])
        self.varDerot=np.array([])
        self.headers=[]#np.array([])
        isci=-1
        print(self.science[0][1])
        #exit()
        self.centrel=[]
        self.centrer=[]
        self.shiftl=[]
        self.shiftr=[]
        for f in self.science:
            isci+=1
            f=self.datadir+f[1]+'.fits'
            #read data
            data,header=self.readdata(f)
            #print data
            if isci==0:
                #pull important info out of header from first science file
                self.rot=header['HIERARCH ESO INS4 COMB ROT']
                self.parangInit=header['HIERARCH ESO TEL PARANG START']
                self.optics={'filt': [header['HIERARCH ESO INS1 FILT NO'],header['HIERARCH ESO INS1 FILT ID'],header['HIERARCH ESO INS1 FILT NAME']],'opti':[header['HIERARCH ESO INS1 OPTI2 NO'],header['HIERARCH ESO INS1 OPTI2 ID'],header['HIERARCH ESO INS1 OPTI2 NAME']],'stop': [header['HIERARCH ESO INS1 OPTI1 NO'],header['HIERARCH ESO INS1 OPTI1 ID'],header['HIERARCH ESO INS1 OPTI1 NAME']]}
                #coros and stops could be in IRDIS (INS1) or in CPI (INS4)
                pass
            #intermediate processing
            data=self.badpixcorrect(data)
            #print data
            #print np.sum(np.isfinite(data))
            data=self.skysub(data,self.mastersky)
            #print data
            #print np.sum(np.isfinite(data))
            mask=np.logical_not(np.isfinite(data))
            data[mask]=np.nan
            if (len(data.shape) == 3): #datacube
                for i in range(data.shape[0]):
                    data[i,:,:] = interpolate_replace_nans(data[i,:,:],Gaussian2DKernel(stddev=1))
            else:
                data[:,:] = interpolate_replace_nans(data[:,:],Gaussian2DKernel(stddev=1))
            #split channels and align
            datal,datar=self.splitchannels(data)

            #----------------------------NOW THINGS ARE DIFFERENT DEPENDING ON METHOD!!--------------------------
            #Undithering data:
            try:
                self.medianNoDerot=np.r_[self.medianNoDerot,
                                         [simage.interpolation.shift(np.nanmedian(datal,axis=0),
                                                                     #[0,
                                                                     [header['HIERARCH ESO INS1 DITH POSX'],
                                                                      header['HIERARCH ESO INS1 DITH POSY']
                                                                     ]
                                         ),
                                          simage.interpolation.shift(np.nanmedian(datar,axis=0),
                                                                     #[0,
                                                                     [header['HIERARCH ESO INS1 DITH POSX'],
                                                                      header['HIERARCH ESO INS1 DITH POSY']])
                                         ]
                                        ] #make sure the sign is right here (by inspection!!)
                self.varNoDerot=np.r_[self.varNoDerot,
                                      [simage.interpolation.shift((np.pi/(2.*datal.shape[0]))*(np.std(datal,axis=0))**2,
                                                                  #[0,
                                                                  [header['HIERARCH ESO INS1 DITH POSX'],
                                                                   header['HIERARCH ESO INS1 DITH POSY']]),
                                       simage.interpolation.shift((np.pi/(2.*datar.shape[0]))*(np.std(datar,axis=0))**2,
                                                                  #[0,
                                                                  [header['HIERARCH ESO INS1 DITH POSX'],
                                                                   header['HIERARCH ESO INS1 DITH POSY']])
                                      ]
                                     ]
            except:
                self.medianNoDerot=np.array(
                                         [simage.interpolation.shift(np.nanmedian(datal,axis=0),
                                                                     #[0,
                                                                     [header['HIERARCH ESO INS1 DITH POSX'],
                                                                      header['HIERARCH ESO INS1 DITH POSY']
                                                                     ]
                                         ),
                                          simage.interpolation.shift(np.nanmedian(datar,axis=0),
                                                                     #[0,
                                                                     [header['HIERARCH ESO INS1 DITH POSX'],
                                                                      header['HIERARCH ESO INS1 DITH POSY']])
                                         ]
                                        ) #make sure the sign is right here (by inspection!!)
                self.varNoDerot=np.array(
                                      [simage.interpolation.shift((np.pi/(2.*datal.shape[0]))*(np.std(datal,axis=0))**2,
                                                                  #[0,
                                                                   [header['HIERARCH ESO INS1 DITH POSX'],
                                                                   header['HIERARCH ESO INS1 DITH POSY']]),
                                       simage.interpolation.shift((np.pi/(2.*datar.shape[0]))*(np.std(datar,axis=0))**2,
                                                                 # [0,
                                                                  [header['HIERARCH ESO INS1 DITH POSX'],
                                                                   header['HIERARCH ESO INS1 DITH POSY']])
                                      ]
                                     )

            #plt.imshow(self.medianNoDerot[0,:,:])
            print(np.max(self.medianNoDerot))
            #plt.show()
            #exit()
            self.headers.append(header)
            #print header
            print(self.medianNoDerot.shape)
            #if isci == 0:
            centreGuess=[header['HIERARCH ESO SEQ CORO XC'],header['HIERARCH ESO SEQ CORO YC']]
            self.findcentre(self.medianNoDerot[isci*2],centreGuess,interact=True)
            self.centrel.append(self.centre)#[self.central['xcentroid'],self.central['ycentroid']]
            #centreGuess.append([header['HIERARCH ESO SEQ CORO XC'],header['HIERARCH ESO SEQ CORO YC']])
            self.findcentre(self.medianNoDerot[isci*2+1],centreGuess,interact=True)
            self.centrer.append(self.centre)#[self.central['xcentroid'],self.central['ycentroid']]
            print(self.centrel[isci],self.centrer[isci])
            self.shiftl.append(np.array(511 - self.centrel[isci]))
            self.shiftr.append(np.array(511 - self.centrer[isci]))
            print(self.shiftl[isci],self.shiftl[isci][0],self.shiftl[isci][1][0])
            #tform=tf.SimilarityTransform(scale=1,rotation=0,translation=(self.shiftl[isci][1],self.shiftl[isci][0]))
            self.medianNoDerot[isci*2]=simage.interpolation.shift(self.medianNoDerot[isci*2],np.array([self.shiftl[isci][1][0],self.shiftl[isci][0][0]]))#tf.warp(self.medianNoDerot[isci*2 -1],tform)# [yshift, xshift]
            self.medianNoDerot[isci*2+1]=simage.interpolation.shift(self.medianNoDerot[isci*2 + 1],np.array([self.shiftr[isci][1][0],self.shiftr[isci][0][0]]))
            self.varNoDerot[isci*2]=simage.interpolation.shift(self.varNoDerot[isci*2],np.array([self.shiftl[isci][1][0],self.shiftl[isci][0][0]]))#tf.warp(self.medianNoDerot[isci*2 -1],tform)# [yshift, xshift]
            self.varNoDerot[isci*2+1]=simage.interpolation.shift(self.varNoDerot[isci*2 + 1],np.array([self.shiftr[isci][1][0],self.shiftr[isci][0][0]]))
            print(isci*2,isci*2+1)
            temp=self.medianNoDerot[isci*2]+self.medianNoDerot[isci*2+1]

            #now derotate cube if pupil stabilised
            if self.rot=='PUPIL':
                #first find centre of rotation

                #then calculate rotation as a function of time
                self.parang=[header['HIERARCH ESO TEL PARANG START'],header['HIERARCH ESO TEL PARANG START']]
                self.pdelt=(self.parang[1]-self.parang[0])/data.shape[0]
                #centre cube:
                datal=simage.interpolation.shift(datal,
                                                np.array(
                                                    [
                                                        0,
                                                        self.shiftl[isci][1][0],
                                                        self.shiftl[isci][0][0]
                                                    ]
                                                 )
                                                )
                #shift data to common reference frame
                for i in range(data.shape[0]):
                    angle=-1.*self.parang[0] + (i+0.5)*self.pdelt + self.pupilOffset + self.tn #rotation angle at centre of exposure relative to beginning of entire sequence - add absolute rotations as well! ##-self.parangInit is not required
                    #then derotate each frame of each half of the detector
                    datal[i,:,:]=self.derotate(datal[i,:,:],angle) #simage.interpolation.rotate(datal[i,:,:],angle,reshape=False) #somehow I must be able to pass in the centre of rotation...I guess I could also shift it so that it is centred correctly first.
                #then calculate rotation as a function of time
                self.parang=[header['HIERARCH ESO TEL PARANG START'],header['HIERARCH ESO TEL PARANG START']]
                self.pdelt=(self.parang[1]-self.parang[0])/data.shape[0]
                datar=simage.interpolation.shift(datar,
                                                np.array(
                                                    [
                                                        0,
                                                        self.shiftr[isci][1][0],
                                                        self.shiftr[isci][0][0]
                                                    ]
                                                 )
                                                )
                for i in range(data.shape[0]):
                    angle=-1.*self.parang[0] + (i+0.5)*self.pdelt + self.pupilOffset + self.tn #rotation angle at centre of exposure relative to beginning of entire sequence - add absolute rotations as well! ##-self.parangInit is not required
                    #then derotate each frame of each half of the detector
                    datar[i,:,:]=self.derotate(datar[i,:,:],angle)
                try:
                    self.medianDerot=np.r_[self.medianDerot,
                                           [np.nanmedian(datal,axis=0),
                                            np.nanmedian(datar,axis=0)]
                                          ]

                    self.varDerot=np.r_[self.varDerot,
                                        [(np.pi/(2.*datal.shape[0]))*(np.std(datal,axis=0))**2,
                                         (np.pi/(2.*datar.shape[0]))*(np.std(datar,axis=0))**2]
                                        ]
                except:
                    self.medianDerot=np.array([np.nanmedian(datal,axis=0),
                                               np.nanmedian(datar,axis=0)
                                                 ]
                                              )
                    self.varDerot=np.array(
                                           [(np.pi/(2.*datal.shape[0]))*(np.std(datal,axis=0))**2,
                                            (np.pi/(2.*datar.shape[0]))*(np.std(datar,axis=0))**2]
                                          )

        if self.mode=='IRD_SCI_CLI_OBJ':#'CI':
            self.CI()
        elif self.mode=='DPI':
            self.DPI()
        elif self.mode=='IRD_SCI_DBI_OBJ':
            self.SDI()
        else:
            print('IRDIS mode not recognised')

        self.writeFinalProducts()
        return self.status

    def writeFinalProducts(self,**kwargs):
        """ Write out final data reduction products to single multi-extension fits file and to separate files """
        hdu=fits.PrimaryHDU()
        for key in eso_fits_keywords: #add important keywords from observed data
            hdu.header.append((key,self.headers[0][key]))
        hdu.header.append(("Pipeline","precision"))
        hdu.header.append(("PipeAuth","P. Scicluna"))
        hdu.header.append(("PipeVers",__version__))
        if self.flux is not None:
            hdu.header.append(("Flux factor",self.flux.flux,"Divide images by this amount to convert to contrast"))
        else:
            hdu.header.append(("Flux factor",1,"No flux frames observed, no conversion necessary"))
        #hdu.header.append(("COMMENT",self.__str__().encode("ascii"))) #full list of files and associations used to produce this dataset - fix in future versions to produce a more useful list which can be used to reconstruct the processing without the association tree ... fix later...
        hdulist=fits.HDUList(hdu)
        """ CI outputs are always required because it always gets done  """
        hdu=fits.ImageHDU(self.finalNoDerot,name="Image (No Derotation)")
        hdulist.append(hdu)
        #How should this be structured?
        #if self.mode=='IRD_SCI_CLI_OBJ':#'CI':
            #CI - required outputs, finalNoDerot,finalDerot,ADI,fluxcal,photcal, uncertainty frames
        hdu=fits.ImageHDU(self.finalvarNoDerot, name="variance (no derotation)")
        hdulist.append(hdu)
        if self.rot=='PUPIL':
            #Derotated images
            hdulist.append(fits.ImageHDU(self.finalDerot,name="Image (derotated)"))
            hdulist.append(fits.ImageHDU(self.finalVarDerot, name="variance (derotated)"))
            #pass
        elif self.mode=='DPI':
            """ Special outputs just for DPI """
            pass
        elif self.mode=='IRD_SCI_DBI_OBJ':
            """ Special outputs just for DBI """
            hdulist.append(self.SDINoDerot, name='SDI')
            hdulist.append(self.varSDINoDerot, name='var SDI')
            if self.rot=='PUPIL':
                hdulist.append(self.SDIDerot, name='SDI derotated')
                hdulist.append(self.varSDIDerot, name='var SDI derotated')
            pass
        logtime = str(datetime.datetime.now()).replace(" ","_")
        hdulist.writeto(self.prefix+"_"+logtime+"_prod.fits")
        pass

    def writeInterProd(self,**kwargs):
        """ Write out intermediate products """
        #What intermediate products are required?
        #Master dark + unc
        #Master flat + unc
        #Bad-pixel map
        #Dark/flat corrected cubes?
        #Bad-pixel corrected cubes?
        #Derotated cubes?
        #Collapsed/aligned cubes?
        #Other calibrations (Flux frames, phot.cals. etc) after calibration
        #Try to make this flexible where you pass info in and it gets turned into a fits file
        #hdulist.writeto(self.outfile+"_interprod.fits")
        pass

    def sciFlux(self,**kwargs):
        '''
        Take non-coronographic observation to compute contrast and facilitate flux calibration
        '''
        #read flux file and calibrate it
        filename=self.flux.datadir+self.flux.obs_main[0][:][1]+".fits"
        fluxframes,fluxhdr=self.readdata(filename)

        #scale for ND filters #and exposure time
        filt=fluxhdr['HIERARCH ESO INS COMB IFLT'].split('_')[1].strip(' ') #self.optics['filt'][2].split('_')[1].strip(' ')#
        ND=fluxhdr['HIERARCH ESO INS4 FILT2 NAME'].split('_')[1].strip(' ')
        print(ND)
        ND=np.int(np.float64(ND))
        #fluxframes=fluxframes * 10**(ND) #very approximate, try to get the ND transmission curves.
        #Scrape filter curves from https://www.eso.org/sci/facilities/paranal/instruments/sphere/inst/filters/*.dat
        #then construct look-up table with approximate throughput of each filter/ND combination
        #read in lookup table
        path=os.path.abspath(__file__)
        print(os.path.dirname(path))
        with open(os.path.dirname(path)+"/IRDIS_filter_throughputs.pkl","rb") as f:
            tab=pickle.load(f, encoding='latin1', fix_imports=True)
            tp=tab[filt][ND]
            print(tp)
            fluxframes=fluxframes / tp
        #extract point-source counts and peak counts for target
        #check for multiple frames:
        if len(fluxframes.shape) == 3:
            masterflux=np.median(fluxframes,axis=0)
        else:
            masterflux=fluxframes

        mean,median,std=astats.sigma_clipped_stats(masterflux,sigma=3.0)
        sourcefinders=pu.DAOStarFinder( #data[500:550,450:500] - median, # assumes datacube #[500:550,450:500]
                           fwhm = 2.0,
                           threshold=std#,
                           #sharplo=0.3,
                           #sharphi=0.5,
                           #roundhi=0.3,
                           #roundlo=-0.3
                           )
        #self.findsources(sourcefinders,masterflux,100
        sources=sourcefinders.find_stars(masterflux[400:600,400:600] - median#data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,#daofind(data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
                                         #     np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median)
        )
        sources.sort('flux')
        sources.pprint(max_lines=-1)
        peakl=sources[-1]['peak']
        sources=sourcefinders.find_stars(masterflux[400:600,1350:1550] - median#data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,#daofind(data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
                                         #     np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median)
        )
        sources.sort('flux')
        sources.pprint(max_lines=-1)
        peakr=sources[-1]['peak']
        peak=0.5*(peakl+peakr)
        #print peak
        self.flux.flux=peak
        #plt.imshow(masterflux[400:600,1350:1550] - median,#data[np.int(guess[0])-window:np.int(np.ceil(guess[0]))+window,
                   #         np.int(guess[1])-window:np.int(np.ceil(guess[1]))+window] - median,
        #               origin='lower')
        #plt.show()

    def photCal(self,**kwargs):
        '''
        Perform photometric calibration with standard star
        '''
        pass

    def readdata(self,filename,**kwargs):
        #print filename

        hdu=fits.open(filename)
        cube=hdu[0].data #extract data itself
        exptime=hdu[0].header['EXPTIME']
        #then extract important header info ? (might have already done this before, not sure about architecture yet)
        cube=cube/exptime #?
        if self.masterdark is not None:
            cube=cube-self.masterdark
        if self.masterflat is not None:
            cube=cube/self.masterflat
        header=hdu[0].header
        extra='??'
        hdu.close()
        return cube,header#,extra

    def output(self,**kwargs):
        self.outfile=(self.headers[0]['HIERARCH ESO OBS NAME'] + '_' +
                      self.optics['filt'][2] + '_' +
                      self.headers[0]['HIERARCH ESO DET SEQ1 DIT'] + '_' +
                      self.headers[0]['HIERARCH ESO OBS START'] +
                      '.fits')
        print('Writing reduced data to file ',self.outfile)
        if self.interProd: #write intermediate products too
            pass
        fits.writeto(self.outfile ,self.finalNoDerot,self.outheader)
        fits.update(self.outfile , self.finalvarNoDerot,'var CI')
        if self.rot=='PUPIL':
            fits.update(self.outfile , self.finalDerot, 'CI derotated')
            fits.update(self.outfile , self.finalvarDerot, 'var CI derotated')
            fits.update(self.outfile , self.finalADI, 'Classical ADI')
            fits.update(self.outfile , self.finalvarADI, 'var Classical ADI')
        if self.mode=='SDI':
            fits.update(self.outfile , self.SDINoDerot, 'SDI')
            fits.update(self.outfile , self.varSDINoDerot, 'var SDI')
            if self.rot=='PUPIL':
                fits.update(self.outfile , self.SDIDerot, 'SDI derotated')
                fits.update(self.outfile , self.varSDIDerot, 'var SDI derotated')
                fits.update(self.outfile , self.finalSADI, 'SADI')
                fits.update(self.outfile , self.finalvarSADI, 'var SADI')
        if self.mode=='DPI':
            pass
#        fits.update( , self.badpixmap, 'bad pixel map')
        pass

class IrdisLSS(Irdis):
    pass


import pytest
import json
from pageObjects.register_page import RegisterPage
from testCases.teardown_conf import TeardownConf
from testCases.conftest import SetupConf
from pageObjects.main_page import *
from utilities.random_string import random_string_generator

class TestRegister(SetupConf,TeardownConf):
    def testSuccessfullyRegisteredWithMandatoryFields(self, teardown):
        print("Success: Register only filling mandatory fields")
        self.givenConfig("Chrome")
        #input("HERE...")
        #self.driver.execute_script("window.localStorage.setItem('{}', {})".format('__paypal_storage__', json.dumps('{"id":"uid_1a761fcfcb_mtq6mti6ntu","__session__":{"guid":"uid_17e112ae1d_mtq6mti6ntu","created":1690985575521}}')))

        self.main_page = MainPage(self.driver)
        self.main_page.open_register_page()

        self.register_page = RegisterPage(self.driver)

        random_string = random_string_generator()
        self.register_page.fill_username_field(random_string)
        self.register_page.fill_firstName_field(random_string)
        self.register_page.fill_lastName_field(random_string)
        self.register_page.fill_email_field(random_string+"@email.com")
        self.register_page.select_country_field('Brazil')
        self.register_page.fill_password_field(random_string+"&!#$")
        self.register_page.click_on_correct_icon()
        self.register_page.click_on_register()
        input()
        assert 1 == 1


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

import numpy as np
import pandas as pd
from sklearn.mixture import GaussianMixture
import matplotlib as mpl
import matplotlib.colors
import matplotlib.pyplot as plt
from sklearn.metrics.pairwise import pairwise_distances_argmin

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

iris_feature = '花萼长度', '花萼宽度', '花瓣长度', '花瓣宽度'

def expand(a, b, rate=0.05):
    d = (b - a) * rate
    return a-d, b+d

if __name__ == '__main__':
    path = '..\\..\\9.Regression\\iris.data'
    data = pd.read_csv(path, header=None)
    x_prime = data[np.arange(4)]
    y = pd.Categorical(data[4]).codes

    n_components = 3
    feature_pairs = [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]
    plt.figure(figsize=(8, 6), facecolor='w')
    for k, pair in enumerate(feature_pairs, start=1):
        x = x_prime[pair]
        m = np.array([np.mean(x[y == i], axis=0) for i in range(3)])  # 均值的实际值
        print('实际均值 = \n', m)

        gmm = GaussianMixture(n_components=n_components, covariance_type='full', random_state=0)
        gmm.fit(x)
        print('预测均值 = \n', gmm.means_)
        print('预测方差 = \n', gmm.covariances_)
        y_hat = gmm.predict(x)
        order = pairwise_distances_argmin(m, gmm.means_, axis=1, metric='euclidean')
        print('顺序：\t', order)

        n_sample = y.size
        n_types = 3
        change = np.empty((n_types, n_sample), dtype=np.bool)
        for i in range(n_types):
            change[i] = y_hat == order[i]
        for i in range(n_types):
            y_hat[change[i]] = i
        acc = '准确率：%.2f%%' % (100*np.mean(y_hat == y))
        print(acc)

        cm_light = mpl.colors.ListedColormap(['#FF8080', '#77E0A0', '#A0A0FF'])
        cm_dark = mpl.colors.ListedColormap(['r', 'g', '#6060FF'])
        x1_min, x2_min = x.min()
        x1_max, x2_max = x.max()
        x1_min, x1_max = expand(x1_min, x1_max)
        x2_min, x2_max = expand(x2_min, x2_max)
        x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]
        grid_test = np.stack((x1.flat, x2.flat), axis=1)
        grid_hat = gmm.predict(grid_test)

        change = np.empty((n_types, grid_hat.size), dtype=np.bool)
        for i in range(n_types):
            change[i] = grid_hat == order[i]
        for i in range(n_types):
            grid_hat[change[i]] = i

        grid_hat = grid_hat.reshape(x1.shape)
        plt.subplot(2, 3, k)
        plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
        plt.scatter(x[pair[0]], x[pair[1]], s=20, c=y, marker='o', cmap=cm_dark, edgecolors='k')
        xx = 0.95 * x1_min + 0.05 * x1_max
        yy = 0.1 * x2_min + 0.9 * x2_max
        plt.text(xx, yy, acc, fontsize=10)
        plt.xlim((x1_min, x1_max))
        plt.ylim((x2_min, x2_max))
        plt.xlabel(iris_feature[pair[0]], fontsize=11)
        plt.ylabel(iris_feature[pair[1]], fontsize=11)
        plt.grid(b=True, ls=':', color='#606060')
    plt.suptitle('EM算法无监督分类鸢尾花数据', fontsize=14)
    plt.tight_layout(1, rect=(0, 0, 1, 0.95))
    plt.show()


from base.configurations.element import Element
from base.configurations.interactions import Interactions
from base.configurations.waits import Waits
from base.configurations.exception import HomePageNotLoadedException

class BasePage:

    def __init__(self, session):
        self.session = session
        self.driver = session.driver
        self.logger = session.logger
        self.action = Interactions(self.session)
        self.waits = Waits(self.session)

    def navigate_to_home_page_from_content(self):
        if not self.action.is_element_displayed(self.events_search_form):
            self.action.click(self.booking_home_logo)
            if not self.action.is_element_displayed(self.events_search_form, timeout=20):
                raise HomePageNotLoadedException('Failed to navigate to home page from content.')
        self.logger.info("Home page successfully loaded.")

    @property
    def booking_home_logo(self): return Element(self.session, ("CSS_SELECTOR", "#top #logo_no_globe_new_logo"))
    @property
    def events_search_form(self): return Element(self.session, ("CSS_SELECTOR", ".js-ds-layout-events-search-form"))


from manimlib.imports import *
import itertools

class WTF(Scene):
    CONFIG = {
        "plane_kwargs": {
            "color": RED_B
        },
    }

    testE = None
    testEArrow = None
    testF = None

    D = 3.0
    FST = 5.0

    def construct(self):
        # Plane
        plane = NumberPlane(**self.plane_kwargs)
        plane.add(plane.get_axis_labels())
        self.add(plane)
        # Left E
        e_left = self.Positron("-")
        e_left_text = TexMobject("-4Q")
        e_left.move_to(self.D * LEFT)
        e_left_text.next_to(e_left, UP)
        # Origin E
        origin = self.Positron("+")
        # origin.scale(0.25)
        origin_text = TexMobject("Q")
        origin_text.next_to(origin, UP)
        # Brace
        left_group = VGroup(e_left, e_left_text, origin)
        left_brace = Brace(left_group)
        left_brace_text = left_brace.get_tex("L=-" + str(self.D))

        # Brace
        right = Dot(self.D * RIGHT, radius=0.2)
        right_group = VGroup(origin, right)
        right_brace = Brace(right_group)
        right_text = right_brace.get_tex("L=" + str(self.D))

        self.testE = self.Positron("+")
        self.testE.move_to(self.FST * LEFT)
        # self.testE.scale(0.25)
        self.testEArrow = Arrow(color=YELLOW, stroke_width=2)
        self.testEArrow.move_to(self.FST * LEFT)

        self.testF = TexMobject("0", color=RED)
        self.testF.move_to(self.FST * LEFT)

        self.play(
            FadeIn(e_left),
            Write(e_left_text),
            FadeIn(origin),
            Write(origin_text),
            Write(left_brace_text),
            GrowFromCenter(left_brace),
            Write(right_text),
            GrowFromCenter(right_brace),
            FadeIn(self.testE),
            FadeIn(self.testEArrow),
            FadeIn(self.testF))

        i = -self.FST
        while i < self.FST:
            f = self.calculate_f(i)
            new_f = TexMobject("E=" + format(f) + "N/c", color=YELLOW)
            new_f.move_to(X_AXIS * i + 1.3 * UP)
            new_f.scale(0.8)
            new_arrow = Arrow(color=YELLOW, stroke_width=2)
            new_arrow.move_to(X_AXIS * i + 0.5 * UP)
            new_arrow.set_length(sign(f) * 0.8)
            self.play(ApplyMethod(self.testE.move_to, i * X_AXIS),
                      Transform(self.testEArrow, new_arrow),
                      Transform(self.testF, new_f)
                      )
            i = i + 0.5

    def calculate_f(self, d):
        if d == .0 or d == -.0:
            d = 0.001
        r = d + self.D
        if r == .0 or r == -.0:
            r = 0.001
        f1 = -4.0 / (r ** 2) * sign(r)
        f2 = 1.0 / (d ** 2.0) * sign(d)
        return 9.0 * 1E9 * (f1 + f2)

    class Positron(Circle):
        CONFIG = {
            "radius": 0.2,
            "stroke_width": 2,
            "color": RED,
            "fill_color": RED,
            "fill_opacity": 0.8,
        }

        def __init__(self, text, **kwargs):
            Circle.__init__(self, **kwargs)
            plus = TexMobject(text)
            plus.scale(0.7)
            plus.move_to(self)
            self.add(plus)

def sign(n):
    if n == .0:
        return 1.0
    else:
        return n / abs(n)

def format(s):
    raw = "%e" % s
    r = raw.split('e')
    if float(s) == 0:
        return "0.0"
    return r[0] + "Q\\times10^{" + ''.join(list(itertools.dropwhile(lambda x: x == '0', r[1][1:]))) + "}"


#python3

def sort_chars(s):
	n = len(s)
	order = [0] * n
	chars = ('$', 'A', 'C', 'G', 'T')
	count = {}
	for char in chars:
		count[char] = 0
	for i in range(n):
		count[s[i]] += 1
	for j in range(1, len(chars)):
		count[chars[j]] += count[chars[j - 1]]
	for i in reversed(range(n)):
		c = s[i]
		count[c] -= 1
		order[count[c]] = i
	return order

def compute_char_classes(s, order):
	n = len(s)
	class_ = [0] * n
	class_[order[0]] = 0
	for i in range(1, n):
		if s[order[i]] != s[order[i - 1]]:
			class_[order[i]] = class_[order[i - 1]] + 1
		else:
			class_[order[i]] = class_[order[i - 1]]
	return class_

def sort_doubled(s, l, order, class_):
	n = len(s)
	count = [0] * n
	new_order = [0] * n
	for i in range(n):
		count[class_[i]] += 1
	for j in range(1, n):
		count[j] += count[j - 1]
	for i in reversed(range(n)):
		start = (order[i] - l + n) % n
		cl = class_[start]
		count[cl] -= 1
		new_order[count[cl]] = start
	return new_order

def update_classes(new_order, class_, l):
	n = len(new_order)
	new_class = [0] * n
	new_class[new_order[0]] = 0
	for i in range(1, n):
		cur = new_order[i]
		prev = new_order[i - 1]
		mid = (cur + l) % n
		mid_prev = (prev + l) % n
		if class_[cur] != class_[prev] or \
			class_[mid] != class_[mid_prev]:
			new_class[cur] = new_class[prev] + 1
		else:
			new_class[cur] = new_class[prev]
	return new_class

def build_suffix_array(s):
	n = len(s)
	order = sort_chars(s)
	class_ = compute_char_classes(s, order)
	l = 1
	while l < n:
		order = sort_doubled(s, l, order, class_)
		class_ = update_classes(order, class_, l)
		l *= 2
	return order

if __name__ == '__main__':
	s = input()
	# s = 'AACGATAGCGGTAGA$'
	print(*build_suffix_array(s))


import os

from azure.cognitiveservices.vision.computervision import ComputerVisionClient
from azure.cognitiveservices.vision.computervision.models import OperationStatusCodes, ImageDescription
from msrest.authentication import CognitiveServicesCredentials

import pymongo

# Clé de Azure Cognitive Services - Computer Vision
VISION_SUBSCRIPTION_KEY = os.environ["VISION_KEY"]
# Point d'accès à Azure Compute Services - Computer Vision
VISION_ENDPOINT = os.environ["VISION_ENDPOINT"]

# Récupération de la chaîne de connection
CONNECTION_STRING = os.environ["COSMOS_CONNECTION_STRING"]
# Nom de la base de données
DB_NAME = "azcogimagedescdb1"
# Nom de la collection
COLLECTION_NAME = "desciptions"

# Url de l'image à analyser
remote_image_url = "https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/landmark.jpg"

"""
===========================================================
 1. Analyse the image sent through URL
===========================================================
"""
# Récupération du client Computer Vsision
print("===== Description de l'image =====")
computer_vision_client = ComputerVisionClient(VISION_ENDPOINT, CognitiveServicesCredentials(VISION_SUBSCRIPTION_KEY))
# Call the API with the remote image url
description:ImageDescription = computer_vision_client.describe_image(remote_image_url)
print("Descriptions in the remote image")
if (len(description.captions) == 0):
    print("No captions detected !!")
else:
    for caption in description.captions:
        print("'{}' with confidence {:.2f}".format(caption.text, caption.confidence))
print("===== Fin de la description de l'image =====")

"""
===========================================================
 2. Store the image description into Cosmos DB collection
===========================================================
"""
# Enregsitrement de la description dans Cosmos DB
print("===== Enregistrement de la description dans Cosmos DB =====")
# Récupération du client MongoDB
client = pymongo.MongoClient(CONNECTION_STRING)
# Obtenir la base de données
db = client[DB_NAME]
# Obtenir la collection
collection = db[COLLECTION_NAME]

# Création de l'objet ImageDescription
image_description = {
    "url": remote_image_url,
    "description": description.captions[0].text
}
# Insertion de la description dans la base de données
result = collection.update_one({"url": image_description["url"]}, {"$set": image_description}, upsert=True)
print("Insertion du document (url={}) avec l'id: {}".format(image_description["url"], result.upserted_id))
print("===== Fin de l'insertion du document =====")